More progress on getting values in and out of scripts.

This commit is contained in:
Andrzej Kapolka 2013-12-17 13:44:56 -08:00
parent 07ed688a8a
commit d535d3b115
5 changed files with 102 additions and 17 deletions

View file

@ -30,6 +30,8 @@ void MetavoxelSystem::init() {
_pointScaleLocation = _program.uniformLocation("pointScale");
}
AttributeRegistry::getInstance()->configureScriptEngine(&_scriptEngine);
MetavoxelPath p1;
p1 += 7;
p1 += 7;
@ -41,6 +43,13 @@ void MetavoxelSystem::init() {
QScriptValue guideFunction = _scriptEngine.evaluate(
"(function(visitation) { "
" var attributes = visitation.visitor.getAttributes();"
" var colorIndex = attributes.indexOf(AttributeRegistry.colorAttribute);"
" var normalIndex = attributes.indexOf(AttributeRegistry.normalAttribute);"
" for (var i = 0; i < attributes.length; i++) {"
" print(attributes[i].getName() + ' ');"
" }"
" print('\\n');"
" visitation.visitor.visit(visitation.info);"
"})");
_data.setAttributeValue(MetavoxelPath(), AttributeValue(AttributeRegistry::getInstance()->getGuideAttribute(),

View file

@ -6,6 +6,8 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <QScriptEngine>
#include "AttributeRegistry.h"
#include "MetavoxelData.h"
@ -17,6 +19,14 @@ AttributeRegistry::AttributeRegistry() :
_normalAttribute(registerAttribute(new QRgbAttribute("normal", qRgb(0, 127, 0)))) {
}
void AttributeRegistry::configureScriptEngine(QScriptEngine* engine) {
QScriptValue registry = engine->newObject();
registry.setProperty("colorAttribute", engine->newQObject(_colorAttribute.data()));
registry.setProperty("normalAttribute", engine->newQObject(_normalAttribute.data()));
registry.setProperty("getAttribute", engine->newFunction(getAttribute, 1));
engine->globalObject().setProperty("AttributeRegistry", registry);
}
AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute) {
AttributePointer& pointer = _attributes[attribute->getName()];
if (!pointer) {
@ -25,6 +35,11 @@ AttributePointer AttributeRegistry::registerAttribute(AttributePointer attribute
return pointer;
}
QScriptValue AttributeRegistry::getAttribute(QScriptContext* context, QScriptEngine* engine) {
return engine->newQObject(_instance.getAttribute(context->argument(0).toString()).data(), QScriptEngine::QtOwnership,
QScriptEngine::PreferExistingWrapperObject);
}
AttributeValue::AttributeValue(const AttributePointer& attribute) :
_attribute(attribute), _value(attribute ? attribute->getDefaultValue() : NULL) {
}
@ -76,7 +91,8 @@ OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other)
}
}
Attribute::Attribute(const QString& name) : _name(name) {
Attribute::Attribute(const QString& name) {
setObjectName(name);
}
Attribute::~Attribute() {
@ -106,6 +122,10 @@ bool QRgbAttribute::merge(void*& parent, void* children[]) const {
return allChildrenEqual;
}
void* QRgbAttribute::createFromScript(const QScriptValue& value, QScriptEngine* engine) const {
return encodeInline((QRgb)value.toUInt32());
}
PolymorphicData::~PolymorphicData() {
}

View file

@ -12,12 +12,17 @@
#include <QColor>
#include <QExplicitlySharedDataPointer>
#include <QHash>
#include <QObject>
#include <QSharedData>
#include <QSharedPointer>
#include <QString>
#include "Bitstream.h"
class QScriptContext;
class QScriptEngine;
class QScriptValue;
class Attribute;
typedef QSharedPointer<Attribute> AttributePointer;
@ -31,6 +36,9 @@ public:
AttributeRegistry();
/// Configures the supplied script engine with the global AttributeRegistry property.
void configureScriptEngine(QScriptEngine* engine);
/// Registers an attribute with the system. The registry assumes ownership of the object.
/// \return either the pointer passed as an argument, if the attribute wasn't already registered, or the existing
/// attribute
@ -55,6 +63,8 @@ public:
private:
static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine);
static AttributeRegistry _instance;
QHash<QString, AttributePointer> _attributes;
@ -114,15 +124,17 @@ public:
};
/// Represents a registered attribute.
class Attribute {
class Attribute : public QObject {
Q_OBJECT
public:
static const int MERGE_COUNT = 8;
Attribute(const QString& name);
virtual ~Attribute();
const QString& getName() const { return _name; }
Q_INVOKABLE QString getName() const { return objectName(); }
void* create() const { return create(getDefaultValue()); }
virtual void* create(void* copy) const = 0;
@ -139,9 +151,7 @@ public:
virtual void* getDefaultValue() const = 0;
private:
QString _name;
virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return create(); }
};
/// A simple attribute class that stores its values inline.
@ -193,6 +203,8 @@ public:
QRgbAttribute(const QString& name, QRgb defaultValue = QRgb());
virtual bool merge(void*& parent, void* children[]) const;
virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const;
};
/// An attribute class that stores pointers to its values.

View file

@ -185,31 +185,67 @@ void DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
}
}
QScriptValue ScriptedMetavoxelGuide::getAttributes(QScriptContext* context, QScriptEngine* engine) {
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
const QVector<AttributePointer>& attributes = guide->_visitation->visitor.getAttributes();
QScriptValue attributesValue = engine->newArray(attributes.size());
for (int i = 0; i < attributes.size(); i++) {
attributesValue.setProperty(i, engine->newQObject(attributes.at(i).data(), QScriptEngine::QtOwnership,
QScriptEngine::PreferExistingWrapperObject));
}
return attributesValue;
}
QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) {
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
MetavoxelInfo info;
// start with the basics, including inherited attribute values
QScriptValue infoValue = context->argument(0);
QScriptValue minimumValue = infoValue.property(guide->_minimumHandle);
info.minimum = glm::vec3(minimumValue.property(0).toNumber(), minimumValue.property(1).toNumber(),
minimumValue.property(2).toNumber());
info.size = infoValue.property(guide->_sizeHandle).toNumber();
info.isLeaf = infoValue.property(guide->_isLeafHandle).toBool();
QScriptValue minimum = infoValue.property(guide->_minimumHandle);
MetavoxelInfo info = {
glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()),
infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.attributeValues,
infoValue.property(guide->_isLeafHandle).toBool() };
return guide->_visitor->visit(info);
// extract and convert the values provided by the script
QScriptValue attributeValues = infoValue.property(guide->_attributeValuesHandle);
const QVector<AttributePointer>& attributes = guide->_visitation->visitor.getAttributes();
for (int i = 0; i < attributes.size(); i++) {
QScriptValue attributeValue = attributeValues.property(i);
if (attributeValue.isValid()) {
info.attributeValues[i] = AttributeValue(attributes.at(i),
attributes.at(i)->createFromScript(attributeValue, engine));
}
}
QScriptValue result = guide->_visitation->visitor.visit(info);
// destroy any created values
for (int i = 0; i < attributes.size(); i++) {
if (attributeValues.property(i).isValid()) {
info.attributeValues[i].getAttribute()->destroy(info.attributeValues[i].getValue());
}
}
return result;
}
ScriptedMetavoxelGuide::ScriptedMetavoxelGuide(const QScriptValue& guideFunction) :
_guideFunction(guideFunction),
_minimumHandle(guideFunction.engine()->toStringHandle("minimum")),
_sizeHandle(guideFunction.engine()->toStringHandle("size")),
_attributeValuesHandle(guideFunction.engine()->toStringHandle("attributeValues")),
_isLeafHandle(guideFunction.engine()->toStringHandle("isLeaf")),
_getAttributesFunction(guideFunction.engine()->newFunction(getAttributes, 0)),
_visitFunction(guideFunction.engine()->newFunction(visit, 1)),
_info(guideFunction.engine()->newObject()),
_minimum(guideFunction.engine()->newArray(3)) {
_arguments.append(guideFunction.engine()->newObject());
QScriptValue visitor = guideFunction.engine()->newObject();
visitor.setProperty("getAttributes", _getAttributesFunction);
visitor.setProperty("visit", _visitFunction);
_arguments[0].setProperty("visitor", visitor);
_arguments[0].setProperty("info", _info);
@ -221,14 +257,19 @@ PolymorphicData* ScriptedMetavoxelGuide::clone() const {
}
void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
_visitFunction.setData(_guideFunction.engine()->newVariant(QVariant::fromValue<void*>(this)));
QScriptValue data = _guideFunction.engine()->newVariant(QVariant::fromValue<void*>(this));
_getAttributesFunction.setData(data);
_visitFunction.setData(data);
_minimum.setProperty(0, visitation.info.minimum.x);
_minimum.setProperty(1, visitation.info.minimum.y);
_minimum.setProperty(2, visitation.info.minimum.z);
_info.setProperty(_sizeHandle, visitation.info.size);
_info.setProperty(_isLeafHandle, visitation.info.isLeaf);
_visitor = &visitation.visitor;
_visitation = &visitation;
_guideFunction.call(QScriptValue(), _arguments);
if (_guideFunction.engine()->hasUncaughtException()) {
qDebug() << "Script error: " << _guideFunction.engine()->uncaughtException().toString() << "\n";
}
}
bool MetavoxelVisitation::allNodesLeaves() const {

View file

@ -156,18 +156,21 @@ public:
private:
static QScriptValue getAttributes(QScriptContext* context, QScriptEngine* engine);
static QScriptValue visit(QScriptContext* context, QScriptEngine* engine);
QScriptValue _guideFunction;
QScriptString _minimumHandle;
QScriptString _sizeHandle;
QScriptString _attributeValuesHandle;
QScriptString _isLeafHandle;
QScriptValueList _arguments;
QScriptValue _getAttributesFunction;
QScriptValue _visitFunction;
QScriptValue _info;
QScriptValue _minimum;
MetavoxelVisitor* _visitor;
MetavoxelVisitation* _visitation;
};
/// Contains the state associated with a visit to a metavoxel system.