Merge branch 'master' into modal_dialogs_async

This commit is contained in:
vladest 2017-09-16 12:30:07 +02:00
commit 5b033e021a
52 changed files with 295 additions and 263 deletions

View file

@ -354,15 +354,16 @@ void Agent::scriptRequestFinished() {
void Agent::executeScript() {
_scriptEngine = std::unique_ptr<ScriptEngine>(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload));
_scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload);
_scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine.get());
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine);
// setup an Avatar for the script to use
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
connect(_scriptEngine.get(), SIGNAL(update(float)), scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection);
connect(_scriptEngine.data(), SIGNAL(update(float)),
scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection);
scriptedAvatar->setForceFaceTrackerConnected(true);
// call model URL setters with empty URLs so our avatar, if user, will have the default models

View file

@ -88,7 +88,7 @@ private:
void encodeFrameOfZeros(QByteArray& encodedZeros);
void computeLoudness(const QByteArray* decodedBuffer, QSharedPointer<ScriptableAvatar>);
std::unique_ptr<ScriptEngine> _scriptEngine;
ScriptEnginePointer _scriptEngine;
EntityEditPacketSender _entityEditSender;
EntityTreeHeadlessViewer _entityViewer;

View file

@ -415,8 +415,7 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) {
void EntityScriptServer::resetEntitiesScriptEngine() {
auto engineName = QString("about:Entities %1").arg(++_entitiesScriptEngineCount);
auto newEngine = QSharedPointer<ScriptEngine>(new ScriptEngine(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName),
&ScriptEngine::deleteLater);
auto newEngine = scriptEngineFactory(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName);
auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor);
newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);
@ -437,11 +436,14 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
newEngine->runInThread();
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngine.data());
auto newEngineSP = qSharedPointerCast<EntitiesScriptEngineProvider>(newEngine);
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngineSP);
disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS);
disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated,
this, &EntityScriptServer::updateEntityPPS);
_entitiesScriptEngine.swap(newEngine);
connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS);
connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated,
this, &EntityScriptServer::updateEntityPPS);
}

View file

@ -72,7 +72,7 @@ private:
bool _shuttingDown { false };
static int _entitiesScriptEngineCount;
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
ScriptEnginePointer _entitiesScriptEngine;
EntityEditPacketSender _entityEditSender;
EntityTreeHeadlessViewer _entityViewer;

View file

@ -137,48 +137,11 @@ Item {
}
}
}
// Left gray MouseArea
MouseArea {
anchors.left: parent.left;
anchors.right: textContainer.left;
anchors.top: textContainer.top;
anchors.bottom: textContainer.bottom;
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
letterbox.visible = false
}
}
// Right gray MouseArea
MouseArea {
anchors.left: textContainer.left;
anchors.right: parent.left;
anchors.top: textContainer.top;
anchors.bottom: textContainer.bottom;
acceptedButtons: Qt.LeftButton
onClicked: {
letterbox.visible = false
}
}
// Top gray MouseArea
MouseArea {
anchors.left: parent.left;
anchors.right: parent.right;
anchors.top: parent.top;
anchors.bottom: textContainer.top;
acceptedButtons: Qt.LeftButton
onClicked: {
letterbox.visible = false
}
}
// Bottom gray MouseArea
MouseArea {
anchors.left: parent.left;
anchors.right: parent.right;
anchors.top: textContainer.bottom;
anchors.bottom: parent.bottom;
acceptedButtons: Qt.LeftButton
onClicked: {
letterbox.visible = false
letterbox.visible = false;
}
}
}

View file

@ -387,9 +387,9 @@ ScrollingWindow {
readOnly: true
Connections {
target: treeView
target: treeView.selection
onCurrentIndexChanged: {
var path = scriptsModel.data(treeView.currentIndex, 0x100)
var path = scriptsModel.data(treeView.selection.currentIndex, 0x100)
if (path) {
selectedScript.text = path
} else {

View file

@ -416,9 +416,9 @@ Rectangle {
readOnly: true
Connections {
target: treeView
target: treeView.selection
onCurrentIndexChanged: {
var path = scriptsModel.data(treeView.currentIndex, 0x100)
var path = scriptsModel.data(treeView.selection.currentIndex, 0x100)
if (path) {
selectedScript.text = path
} else {

View file

@ -963,7 +963,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
scriptEngines->registerScriptInitializer([this](ScriptEngine* engine){
scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){
registerScriptEngineWithApplicationServices(engine);
});
@ -5209,7 +5209,7 @@ void Application::update(float deltaTime) {
}
}
avatarManager->postUpdate(deltaTime);
avatarManager->postUpdate(deltaTime, getMain3DScene());
{
PROFILE_RANGE_EX(app, "PreRenderLambdas", 0xffff0000, (uint64_t)0);
@ -5930,7 +5930,7 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer
void Application::packetSent(quint64 length) {
}
void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) {
void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) {
scriptEngine->setEmitScriptUpdatesFunction([this]() {
SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer);
@ -5965,29 +5965,31 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface();
scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable);
connect(scriptEngine, &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater);
connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater);
scriptEngine->registerGlobalObject("Overlays", &_overlays);
qScriptRegisterMetaType(scriptEngine, OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue);
qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue,
qScriptRegisterMetaType(scriptEngine.data(), OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue);
qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue,
RayToOverlayIntersectionResultFromScriptValue);
scriptEngine->registerGlobalObject("OffscreenFlags", DependencyManager::get<OffscreenUi>()->getFlags());
scriptEngine->registerGlobalObject("Desktop", DependencyManager::get<DesktopScriptingInterface>().data());
qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue<ToolbarProxy>, wrapperFromScriptValue<ToolbarProxy>);
qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue<ToolbarButtonProxy>, wrapperFromScriptValue<ToolbarButtonProxy>);
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<ToolbarProxy>, wrapperFromScriptValue<ToolbarProxy>);
qScriptRegisterMetaType(scriptEngine.data(),
wrapperToScriptValue<ToolbarButtonProxy>, wrapperFromScriptValue<ToolbarButtonProxy>);
scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue<TabletProxy>, wrapperFromScriptValue<TabletProxy>);
qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue<TabletButtonProxy>, wrapperFromScriptValue<TabletButtonProxy>);
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<TabletProxy>, wrapperFromScriptValue<TabletProxy>);
qScriptRegisterMetaType(scriptEngine.data(),
wrapperToScriptValue<TabletButtonProxy>, wrapperFromScriptValue<TabletButtonProxy>);
scriptEngine->registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
DependencyManager::get<TabletScriptingInterface>().data()->setToolbarScriptingInterface(DependencyManager::get<ToolbarScriptingInterface>().data());
auto toolbarScriptingInterface = DependencyManager::get<ToolbarScriptingInterface>().data();
DependencyManager::get<TabletScriptingInterface>().data()->setToolbarScriptingInterface(toolbarScriptingInterface);
scriptEngine->registerGlobalObject("Window", DependencyManager::get<WindowScriptingInterface>().data());
qScriptRegisterMetaType(scriptEngine, CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue);
qScriptRegisterMetaType(scriptEngine.data(), CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue);
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
LocationScriptingInterface::locationSetter, "Window");
// register `location` on the global object.
@ -6019,7 +6021,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface);
scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance());
qScriptRegisterMetaType(scriptEngine, DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
qScriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
scriptEngine->registerGlobalObject("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
@ -6047,11 +6049,11 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>().data());
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine, steamClient.get()));
scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine.data(), steamClient.get()));
}
auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
scriptEngine->registerGlobalObject("Controller", scriptingInterface.data());
UserInputMapper::registerControllerTypes(scriptEngine);
UserInputMapper::registerControllerTypes(scriptEngine.data());
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
scriptEngine->registerGlobalObject("Recording", recordingInterface.data());
@ -6062,14 +6064,19 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue);
qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue);
// connect this script engines printedMessage signal to the global ScriptEngines these various messages
connect(scriptEngine, &ScriptEngine::printedMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onPrintedMessage);
connect(scriptEngine, &ScriptEngine::errorMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onErrorMessage);
connect(scriptEngine, &ScriptEngine::warningMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onWarningMessage);
connect(scriptEngine, &ScriptEngine::infoMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onInfoMessage);
connect(scriptEngine, &ScriptEngine::clearDebugWindow, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onClearDebugWindow);
connect(scriptEngine.data(), &ScriptEngine::printedMessage,
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onPrintedMessage);
connect(scriptEngine.data(), &ScriptEngine::errorMessage,
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onErrorMessage);
connect(scriptEngine.data(), &ScriptEngine::warningMessage,
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onWarningMessage);
connect(scriptEngine.data(), &ScriptEngine::infoMessage,
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onInfoMessage);
connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow,
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onClearDebugWindow);
}

View file

@ -218,7 +218,7 @@ public:
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) override;
virtual void registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) override;
virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const override { copyDisplayViewFrustum(viewOut); }
virtual QThread* getMainThread() override { return thread(); }

View file

@ -259,12 +259,12 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
simulateAvatarFades(deltaTime);
}
void AvatarManager::postUpdate(float deltaTime) {
void AvatarManager::postUpdate(float deltaTime, const render::ScenePointer& scene) {
auto hashCopy = getHashCopy();
AvatarHash::iterator avatarIterator = hashCopy.begin();
for (avatarIterator = hashCopy.begin(); avatarIterator != hashCopy.end(); avatarIterator++) {
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
avatar->postUpdate(deltaTime);
avatar->postUpdate(deltaTime, scene);
}
}

View file

@ -55,7 +55,7 @@ public:
void updateMyAvatar(float deltaTime);
void updateOtherAvatars(float deltaTime);
void postUpdate(float deltaTime);
void postUpdate(float deltaTime, const render::ScenePointer& scene);
void clearOtherAvatars();
void deleteAllAvatars();

View file

@ -262,7 +262,7 @@ void MyAvatar::setDominantHand(const QString& hand) {
}
}
void MyAvatar::registerMetaTypes(QScriptEngine* engine) {
void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) {
QScriptValue value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
engine->globalObject().setProperty("MyAvatar", value);
@ -273,8 +273,8 @@ void MyAvatar::registerMetaTypes(QScriptEngine* engine) {
}
engine->globalObject().setProperty("DriveKeys", driveKeys);
qScriptRegisterMetaType(engine, audioListenModeToScriptValue, audioListenModeFromScriptValue);
qScriptRegisterMetaType(engine, driveKeysToScriptValue, driveKeysFromScriptValue);
qScriptRegisterMetaType(engine.data(), audioListenModeToScriptValue, audioListenModeFromScriptValue);
qScriptRegisterMetaType(engine.data(), driveKeysToScriptValue, driveKeysFromScriptValue);
}
void MyAvatar::setOrientationVar(const QVariant& newOrientationVar) {
@ -1814,11 +1814,11 @@ void MyAvatar::destroyAnimGraph() {
_skeletonModel->getRig().destroyAnimGraph();
}
void MyAvatar::postUpdate(float deltaTime) {
void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
Avatar::postUpdate(deltaTime);
Avatar::postUpdate(deltaTime, scene);
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars() && _skeletonModel->initWhenReady(qApp->getMain3DScene())) {
if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode()) {
initHeadBones();
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();

View file

@ -19,6 +19,7 @@
#include <SettingHandle.h>
#include <Rig.h>
#include <Sound.h>
#include <ScriptEngine.h>
#include <controllers/Pose.h>
#include <controllers/Actions.h>
@ -169,7 +170,7 @@ public:
~MyAvatar();
void instantiableAvatar() override {};
void registerMetaTypes(QScriptEngine* engine);
void registerMetaTypes(ScriptEnginePointer engine);
virtual void simulateAttachments(float deltaTime) override;
@ -196,7 +197,7 @@ public:
Q_INVOKABLE void clearIKJointLimitHistory(); // thread-safe
void update(float deltaTime);
virtual void postUpdate(float deltaTime) override;
virtual void postUpdate(float deltaTime, const render::ScenePointer& scene) override;
void preDisplaySide(RenderArgs* renderArgs);
const glm::mat4& getHMDSensorMatrix() const { return _hmdSensorMatrix; }

View file

@ -61,7 +61,7 @@ void _writeLines(const QString& filename, const QList<QString>& lines) {
QTextStream(&file) << json;
}
JSConsole::JSConsole(QWidget* parent, const QSharedPointer<ScriptEngine>& scriptEngine) :
JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) :
QWidget(parent),
_ui(new Ui::Console),
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
@ -97,7 +97,7 @@ JSConsole::~JSConsole() {
delete _ui;
}
void JSConsole::setScriptEngine(const QSharedPointer<ScriptEngine>& scriptEngine) {
void JSConsole::setScriptEngine(const ScriptEnginePointer& scriptEngine) {
if (_scriptEngine == scriptEngine && scriptEngine != NULL) {
return;
}
@ -111,7 +111,7 @@ void JSConsole::setScriptEngine(const QSharedPointer<ScriptEngine>& scriptEngin
// if scriptEngine is NULL then create one and keep track of it using _ownScriptEngine
if (scriptEngine.isNull()) {
_scriptEngine = QSharedPointer<ScriptEngine>(DependencyManager::get<ScriptEngines>()->loadScript(_consoleFileName, false), &QObject::deleteLater);
_scriptEngine = DependencyManager::get<ScriptEngines>()->loadScript(_consoleFileName, false);
} else {
_scriptEngine = scriptEngine;
}

View file

@ -30,10 +30,10 @@ const int CONSOLE_HEIGHT = 200;
class JSConsole : public QWidget {
Q_OBJECT
public:
JSConsole(QWidget* parent, const QSharedPointer<ScriptEngine>& scriptEngine = QSharedPointer<ScriptEngine>());
JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine = ScriptEnginePointer());
~JSConsole();
void setScriptEngine(const QSharedPointer<ScriptEngine>& scriptEngine = QSharedPointer<ScriptEngine>());
void setScriptEngine(const ScriptEnginePointer& scriptEngine = ScriptEnginePointer());
void clear();
public slots:
@ -66,7 +66,7 @@ private:
QString _savedHistoryFilename;
QList<QString> _commandHistory;
QString _rootCommand;
QSharedPointer<ScriptEngine> _scriptEngine;
ScriptEnginePointer _scriptEngine;
static const QString _consoleFileName;
};

View file

@ -24,7 +24,7 @@ TestingDialog::TestingDialog(QWidget* parent) :
_console->setFixedHeight(TESTING_CONSOLE_HEIGHT);
auto _engines = DependencyManager::get<ScriptEngines>();
_engine.reset(_engines->loadScript(qApp->applicationDirPath() + testRunnerRelativePath));
_engine = _engines->loadScript(qApp->applicationDirPath() + testRunnerRelativePath);
_console->setScriptEngine(_engine);
connect(_engine.data(), &ScriptEngine::finished, this, &TestingDialog::onTestingFinished);
}

View file

@ -29,7 +29,7 @@ public:
private:
std::unique_ptr<JSConsole> _console;
QSharedPointer<ScriptEngine> _engine;
ScriptEnginePointer _engine;
};
#endif

View file

@ -256,15 +256,46 @@ bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3
void Base3DOverlay::locationChanged(bool tellPhysics) {
SpatiallyNestable::locationChanged(tellPhysics);
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
transaction.updateItem(itemID);
scene->enqueueTransaction(transaction);
}
// Force the actual update of the render transform through the notify call
notifyRenderTransformChange();
}
void Base3DOverlay::parentDeleted() {
qApp->getOverlays().deleteOverlay(getOverlayID());
}
void Base3DOverlay::update(float duration) {
// In Base3DOverlay, if its location or bound changed, the renderTrasnformDirty flag is true.
// then the correct transform used for rendering is computed in the update transaction and assigned.
// TODO: Fix the value to be computed in main thread now and passed by value to the render item.
// This is the simplest fix for the web overlay of the tablet for now
if (_renderTransformDirty) {
_renderTransformDirty = false;
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
transaction.updateItem<Overlay>(itemID, [](Overlay& data) {
auto overlay3D = dynamic_cast<Base3DOverlay*>(&data);
if (overlay3D) {
auto latestTransform = overlay3D->evalRenderTransform();
overlay3D->setRenderTransform(latestTransform);
}
});
scene->enqueueTransaction(transaction);
}
}
}
void Base3DOverlay::notifyRenderTransformChange() const {
_renderTransformDirty = true;
}
Transform Base3DOverlay::evalRenderTransform() const {
return getTransform();
}
void Base3DOverlay::setRenderTransform(const Transform& transform) {
_renderTransform = transform;
}

View file

@ -52,6 +52,10 @@ public:
virtual AABox getBounds() const override = 0;
void update(float deltatime) override;
void notifyRenderTransformChange() const;
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
@ -67,12 +71,18 @@ protected:
virtual void locationChanged(bool tellPhysics = true) override;
virtual void parentDeleted() override;
mutable Transform _renderTransform;
virtual Transform evalRenderTransform() const;
virtual void setRenderTransform(const Transform& transform);
const Transform& getRenderTransform() const { return _renderTransform; }
float _lineWidth;
bool _isSolid;
bool _isDashedLine;
bool _ignoreRayIntersection;
bool _drawInFront;
bool _isGrabbable { false };
mutable bool _renderTransformDirty{ true };
QString _name;
};

View file

@ -85,6 +85,7 @@ void Circle3DOverlay::render(RenderArgs* args) {
}
// FIXME: THe line width of _lineWidth is not supported anymore, we ll need a workaround
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
auto transform = getTransform();
transform.postScale(glm::vec3(getDimensions(), 1.0f));

View file

@ -54,6 +54,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
// TODO: handle registration point??
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
glm::vec3 position = getPosition();
glm::vec3 dimensions = getDimensions();
glm::quat rotation = getRotation();

View file

@ -79,6 +79,7 @@ void Grid3DOverlay::render(RenderArgs* args) {
position += glm::vec3(cameraPosition.x, 0.0f, cameraPosition.z);
}
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
Transform transform;
transform.setRotation(getRotation());
transform.setScale(glm::vec3(getDimensions(), 1.0f));

View file

@ -117,6 +117,7 @@ void Image3DOverlay::render(RenderArgs* args) {
xColor color = getColor();
float alpha = getAlpha();
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
Transform transform = getTransform();
bool transformChanged = applyTransformTo(transform, true);
// If the transform is not modified, setting the transform to

View file

@ -132,6 +132,7 @@ void Line3DOverlay::render(RenderArgs* args) {
glm::vec4 colorv4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
auto batch = args->_batch;
if (batch) {
// FIXME Start using the _renderTransform instead of calling for Transform and start and end from here, do the custom things needed in evalRenderTransform()
batch->setModelTransform(Transform());
glm::vec3 start = getStart();
glm::vec3 end = getEnd();

View file

@ -281,6 +281,7 @@ ModelOverlay* ModelOverlay::createClone() const {
void ModelOverlay::locationChanged(bool tellPhysics) {
Base3DOverlay::locationChanged(tellPhysics);
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
if (_model && _model->isActive()) {
_model->setRotation(getRotation());
_model->setTranslation(getPosition());

View file

@ -66,3 +66,11 @@ bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
// FIXME - face and surfaceNormal not being returned
return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), getDimensions(), distance);
}
Transform Planar3DOverlay::evalRenderTransform() const {
auto transform = getTransform();
if (glm::length2(getDimensions()) != 1.0f) {
transform.postScale(vec3(getDimensions(), 1.0f));
}
return transform;
}

View file

@ -32,7 +32,9 @@ public:
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal) override;
Transform evalRenderTransform() const override;
protected:
glm::vec2 _dimensions;
};

View file

@ -66,6 +66,7 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
auto batch = args->_batch;
if (batch) {
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
Transform transform;
transform.setTranslation(position);
transform.setRotation(rotation);

View file

@ -33,6 +33,7 @@ void Shape3DOverlay::render(RenderArgs* args) {
const float MAX_COLOR = 255.0f;
glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
// TODO: handle registration point??
glm::vec3 position = getPosition();
glm::vec3 dimensions = getDimensions();

View file

@ -39,6 +39,7 @@ void Sphere3DOverlay::render(RenderArgs* args) {
auto batch = args->_batch;
if (batch) {
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
Transform transform = getTransform();
transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE);
batch->setModelTransform(transform);

View file

@ -96,6 +96,7 @@ void Text3DOverlay::render(RenderArgs* args) {
Q_ASSERT(args->_batch);
auto& batch = *args->_batch;
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
Transform transform = getTransform();
applyTransformTo(transform, true);
setTransform(transform);

View file

@ -184,6 +184,7 @@ void Web3DOverlay::update(float deltatime) {
// update globalPosition
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
}
Parent::update(deltatime);
}
QString Web3DOverlay::pickURL() {
@ -306,19 +307,6 @@ void Web3DOverlay::render(RenderArgs* args) {
vec2 halfSize = getSize() / 2.0f;
vec4 color(toGlm(getColor()), getAlpha());
Transform transform = getTransform();
// FIXME: applyTransformTo causes tablet overlay to detach from tablet entity.
// Perhaps rather than deleting the following code it should be run only if isFacingAvatar() is true?
/*
applyTransformTo(transform, true);
setTransform(transform);
*/
if (glm::length2(getDimensions()) != 1.0f) {
transform.postScale(vec3(getDimensions(), 1.0f));
}
if (!_texture) {
_texture = gpu::Texture::createExternal(OffscreenQmlSurface::getDiscardLambda());
_texture->setSource(__FUNCTION__);
@ -332,7 +320,8 @@ void Web3DOverlay::render(RenderArgs* args) {
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
batch.setResourceTexture(0, _texture);
batch.setModelTransform(transform);
batch.setModelTransform(getRenderTransform());
auto geometryCache = DependencyManager::get<GeometryCache>();
if (color.a < OPAQUE_ALPHA_THRESHOLD) {
geometryCache->bindWebBrowserProgram(batch, true);

View file

@ -19,8 +19,10 @@ class OffscreenQmlSurface;
class Web3DOverlay : public Billboard3DOverlay {
Q_OBJECT
using Parent = Billboard3DOverlay;
public:
static const QString QML;
static QString const TYPE;
virtual QString getType() const override { return TYPE; }

View file

@ -553,7 +553,7 @@ void Avatar::updateRenderItem(render::Transaction& transaction) {
}
}
void Avatar::postUpdate(float deltaTime) {
void Avatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
if (isMyAvatar() ? showMyLookAtVectors : showOtherLookAtVectors) {
const float EYE_RAY_LENGTH = 10.0;
@ -577,6 +577,8 @@ void Avatar::postUpdate(float deltaTime) {
DebugDraw::getInstance().drawRay(rightEyePosition, rightEyePosition + rightEyeRotation * Vectors::UNIT_Z * EYE_RAY_LENGTH, RED);
}
}
fixupModelsInScene(scene);
}
void Avatar::render(RenderArgs* renderArgs) {
@ -648,10 +650,6 @@ void Avatar::render(RenderArgs* renderArgs) {
return;
}
if (!isMyAvatar()) {
fixupModelsInScene(renderArgs->_scene);
}
if (showCollisionShapes && shouldRenderHead(renderArgs) && _skeletonModel->isRenderable()) {
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
const float BOUNDING_SHAPE_ALPHA = 0.7f;

View file

@ -98,7 +98,7 @@ public:
void updateRenderItem(render::Transaction& transaction);
virtual void postUpdate(float deltaTime);
virtual void postUpdate(float deltaTime, const render::ScenePointer& scene);
//setters
void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; }

View file

@ -70,45 +70,21 @@ EntityRendererPointer EntityTreeRenderer::renderableForEntityId(const EntityItem
return itr->second;
}
render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& id) const {
auto renderable = renderableForEntityId(id);
return renderable ? renderable->getRenderItemID() : render::Item::INVALID_ITEM_ID;
render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& id) const {
auto renderable = renderableForEntityId(id);
return renderable ? renderable->getRenderItemID() : render::Item::INVALID_ITEM_ID;
}
int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
void entitiesScriptEngineDeleter(ScriptEngine* engine) {
class WaitRunnable : public QRunnable {
public:
WaitRunnable(ScriptEngine* engine) : _engine(engine) {}
virtual void run() override {
_engine->waitTillDoneRunning();
_engine->deleteLater();
}
private:
ScriptEngine* _engine;
};
// Wait for the scripting thread from the thread pool to avoid hanging the main thread
auto threadPool = QThreadPool::globalInstance();
if (threadPool) {
threadPool->start(new WaitRunnable(engine));
} else {
delete engine;
}
}
void EntityTreeRenderer::resetEntitiesScriptEngine() {
// Keep a ref to oldEngine until newEngine is ready so EntityScriptingInterface has something to use
auto oldEngine = _entitiesScriptEngine;
auto newEngine = new ScriptEngine(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
_entitiesScriptEngine = QSharedPointer<ScriptEngine>(newEngine, entitiesScriptEngineDeleter);
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine.data());
_entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
_entitiesScriptEngine->runInThread();
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(_entitiesScriptEngine.data());
auto entitiesScriptEngineProvider = qSharedPointerCast<EntitiesScriptEngineProvider>(_entitiesScriptEngine);
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(entitiesScriptEngineProvider);
}
void EntityTreeRenderer::clear() {

View file

@ -181,7 +181,7 @@ private:
QVector<EntityItemID> _currentEntitiesInside;
bool _wantScripts;
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
ScriptEnginePointer _entitiesScriptEngine;
void playEntityCollisionSound(const EntityItemPointer& entity, const Collision& collision);

View file

@ -121,14 +121,19 @@ bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP
}
void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
static const QUrl DEFAULT_POLYLINE_TEXTURE = QUrl(PathUtils::resourcesPath() + "images/paintStroke.png");
QUrl entityTextures = DEFAULT_POLYLINE_TEXTURE;
if (entity->texturesChanged()) {
entity->resetTexturesChanged();
auto textures = entity->getTextures();
QString path = textures.isEmpty() ? PathUtils::resourcesPath() + "images/paintStroke.png" : textures;
if (!_texture || _lastTextures != path) {
_texture = DependencyManager::get<TextureCache>()->getTexture(QUrl(path));
if (!textures.isEmpty()) {
entityTextures = QUrl(textures);
}
}
if (!_texture || _texture->getURL() != entityTextures) {
_texture = DependencyManager::get<TextureCache>()->getTexture(entityTextures);
}
}
void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
@ -140,6 +145,10 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
auto normalsChanged = entity->normalsChanged();
entity->resetPolyLineChanged();
_polylineTransform = Transform();
_polylineTransform.setTranslation(entity->getPosition());
_polylineTransform.setRotation(entity->getRotation());
if (pointsChanged) {
_lastPoints = entity->getLinePoints();
}
@ -217,13 +226,13 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
batch.setModelTransform(Transform{ _modelTransform }.setScale(vec3(1)));
batch.setModelTransform(_polylineTransform);
batch.setUniformBuffer(PAINTSTROKE_UNIFORM_SLOT, _uniformBuffer);
if (_texture->isLoaded()) {
if (_texture && _texture->isLoaded()) {
batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, _texture->getGPUTexture());
} else {
batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, nullptr);
batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, DependencyManager::get<TextureCache>()->getWhiteTexture());
}
batch.setInputFormat(polylineFormat);

View file

@ -47,6 +47,7 @@ protected:
void updateGeometry(const std::vector<Vertex>& vertices);
static std::vector<Vertex> updateVertices(const QVector<glm::vec3>& points, const QVector<glm::vec3>& normals, const QVector<float>& strokeWidths);
Transform _polylineTransform;
QVector<glm::vec3> _lastPoints;
QVector<glm::vec3> _lastNormals;
QVector<float> _lastStrokeWidths;
@ -54,7 +55,6 @@ protected:
gpu::BufferView _uniformBuffer;
uint32_t _numVertices { 0 };
bool _empty{ true };
QString _lastTextures;
NetworkTexturePointer _texture;
};

View file

@ -539,7 +539,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
}
}
void EntityScriptingInterface::setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine) {
void EntityScriptingInterface::setEntitiesScriptEngine(QSharedPointer<EntitiesScriptEngineProvider> engine) {
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
_entitiesScriptEngine = engine;
}
@ -749,7 +749,7 @@ bool EntityPropertyMetadataRequest::script(EntityItemID entityID, QScriptValue h
request->deleteLater();
});
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
entityScriptingInterface->withEntitiesScriptEngine([&](EntitiesScriptEngineProvider* entitiesScriptEngine) {
entityScriptingInterface->withEntitiesScriptEngine([&](QSharedPointer<EntitiesScriptEngineProvider> entitiesScriptEngine) {
if (entitiesScriptEngine) {
request->setFuture(entitiesScriptEngine->getLocalEntityScriptDetails(entityID));
}

View file

@ -99,7 +99,7 @@ public:
void setEntityTree(EntityTreePointer modelTree);
EntityTreePointer getEntityTree() { return _entityTree; }
void setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine);
void setEntitiesScriptEngine(QSharedPointer<EntitiesScriptEngineProvider> engine);
float calculateCost(float mass, float oldVelocity, float newVelocity);
void resetActivityTracking();
@ -405,7 +405,7 @@ signals:
void webEventReceived(const EntityItemID& entityItemID, const QVariant& message);
protected:
void withEntitiesScriptEngine(std::function<void(EntitiesScriptEngineProvider*)> function) {
void withEntitiesScriptEngine(std::function<void(QSharedPointer<EntitiesScriptEngineProvider>)> function) {
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
function(_entitiesScriptEngine);
};
@ -427,7 +427,7 @@ private:
EntityTreePointer _entityTree;
std::recursive_mutex _entitiesScriptEngineLock;
EntitiesScriptEngineProvider* _entitiesScriptEngine { nullptr };
QSharedPointer<EntitiesScriptEngineProvider> _entitiesScriptEngine;
bool _bidOnSimulationOwnership { false };
float _currentAvatarEnergy = { FLT_MAX };

View file

@ -12,13 +12,13 @@
#ifndef hifi_AbstractScriptingServicesInterface_h
#define hifi_AbstractScriptingServicesInterface_h
class ScriptEngine;
#include <BaseScriptEngine.h>
/// Interface provided by Application to other objects that need access to scripting services of the application
class AbstractScriptingServicesInterface {
public:
/// Registers application specific services with a script engine.
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) = 0;
virtual void registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) = 0;
};

View file

@ -14,6 +14,7 @@
#include <QtCore/QObject>
#include <BaseScriptEngine.h>
#include <DependencyManager.h>
#include <recording/ClipCache.h>
#include <recording/Forward.h>
@ -28,7 +29,7 @@ class RecordingScriptingInterface : public QObject, public Dependency {
public:
RecordingScriptingInterface();
void setScriptEngine(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
void setScriptEngine(QSharedPointer<BaseScriptEngine> scriptEngine) { _scriptEngine = scriptEngine; }
public slots:
void loadRecording(const QString& url, QScriptValue callback = QScriptValue());
@ -85,7 +86,7 @@ protected:
Flag _useSkeletonModel { false };
recording::ClipPointer _lastClip;
QScriptEngine* _scriptEngine;
QSharedPointer<BaseScriptEngine> _scriptEngine;
QSet<recording::NetworkClipLoaderPointer> _clipLoaders;
};

View file

@ -153,6 +153,15 @@ QString ScriptEngine::logException(const QScriptValue& exception) {
return message;
}
ScriptEnginePointer scriptEngineFactory(ScriptEngine::Context context,
const QString& scriptContents,
const QString& fileNameString) {
ScriptEngine* engine = new ScriptEngine(context, scriptContents, fileNameString);
ScriptEnginePointer engineSP = ScriptEnginePointer(engine);
DependencyManager::get<ScriptEngines>()->addScriptEngine(qSharedPointerCast<ScriptEngine>(engineSP));
return engineSP;
}
int ScriptEngine::processLevelMaxRetries { ScriptRequest::MAX_RETRIES };
ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const QString& fileNameString) :
BaseScriptEngine(),
@ -160,10 +169,10 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const
_scriptContents(scriptContents),
_timerFunctionMap(),
_fileNameString(fileNameString),
_arrayBufferClass(new ArrayBufferClass(this))
_arrayBufferClass(new ArrayBufferClass(this)),
// don't delete `ScriptEngines` until all `ScriptEngine`s are gone
_scriptEngines(DependencyManager::get<ScriptEngines>())
{
DependencyManager::get<ScriptEngines>()->addScriptEngine(this);
connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {
if (hasUncaughtException()) {
// the engine's uncaughtException() seems to produce much better stack traces here
@ -208,22 +217,9 @@ QString ScriptEngine::getContext() const {
}
ScriptEngine::~ScriptEngine() {
// FIXME: are these scriptInfoMessage/scriptWarningMessage segfaulting anybody else at app shutdown?
#if !defined(Q_OS_LINUX)
scriptInfoMessage("Script Engine shutting down:" + getFilename());
#else
qCDebug(scriptengine) << "~ScriptEngine()" << this;
#endif
auto scriptEngines = DependencyManager::get<ScriptEngines>();
if (scriptEngines) {
scriptEngines->removeScriptEngine(this);
} else {
#if !defined(Q_OS_LINUX)
scriptWarningMessage("Script destroyed after ScriptEngines!");
#else
qCWarning(scriptengine) << ("Script destroyed after ScriptEngines!");
#endif
scriptEngines->removeScriptEngine(qSharedPointerCast<ScriptEngine>(sharedFromThis()));
}
}
@ -294,7 +290,7 @@ void ScriptEngine::runDebuggable() {
stopAllTimers(); // make sure all our timers are stopped if the script is ending
emit scriptEnding();
emit finished(_fileNameString, this);
emit finished(_fileNameString, qSharedPointerCast<ScriptEngine>(sharedFromThis()));
_isRunning = false;
emit runningStateChanged();
@ -503,7 +499,8 @@ static void animVarMapFromScriptValue(const QScriptValue& value, AnimVariantMap&
parameters.animVariantMapFromScriptValue(value);
}
// ... while these two are not. But none of the four are ever used.
static QScriptValue resultHandlerToScriptValue(QScriptEngine* engine, const AnimVariantResultHandler& resultHandler) {
static QScriptValue resultHandlerToScriptValue(QScriptEngine* engine,
const AnimVariantResultHandler& resultHandler) {
qCCritical(scriptengine) << "Attempt to marshall result handler to javascript";
assert(false);
return QScriptValue();
@ -516,7 +513,8 @@ static void resultHandlerFromScriptValue(const QScriptValue& value, AnimVariantR
// Templated qScriptRegisterMetaType fails to compile with raw pointers
using ScriptableResourceRawPtr = ScriptableResource*;
static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine, const ScriptableResourceRawPtr& resource) {
static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine,
const ScriptableResourceRawPtr& resource) {
// The first script to encounter this resource will track its memory.
// In this way, it will be more likely to GC.
// This fails in the case that the resource is used across many scripts, but
@ -539,11 +537,11 @@ static void scriptableResourceFromScriptValue(const QScriptValue& value, Scripta
resource = static_cast<ScriptableResourceRawPtr>(value.toQObject());
}
static QScriptValue createScriptableResourcePrototype(QScriptEngine* engine) {
static QScriptValue createScriptableResourcePrototype(ScriptEnginePointer engine) {
auto prototype = engine->newObject();
// Expose enum State to JS/QML via properties
QObject* state = new QObject(engine);
QObject* state = new QObject(engine.data());
state->setObjectName("ResourceState");
auto metaEnum = QMetaEnum::fromType<ScriptableResource::State>();
for (int i = 0; i < metaEnum.keyCount(); ++i) {
@ -693,7 +691,7 @@ void ScriptEngine::init() {
qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue);
// Scriptable cache access
auto resourcePrototype = createScriptableResourcePrototype(this);
auto resourcePrototype = createScriptableResourcePrototype(qSharedPointerCast<ScriptEngine>(sharedFromThis()));
globalObject().setProperty("Resource", resourcePrototype);
setDefaultPrototype(qMetaTypeId<ScriptableResource*>(), resourcePrototype);
qScriptRegisterMetaType(this, scriptableResourceToScriptValue, scriptableResourceFromScriptValue);
@ -1178,7 +1176,7 @@ void ScriptEngine::run() {
}
}
emit finished(_fileNameString, this);
emit finished(_fileNameString, qSharedPointerCast<ScriptEngine>(sharedFromThis()));
_isRunning = false;
emit runningStateChanged();

View file

@ -53,6 +53,8 @@ static const int SCRIPT_FPS = 60;
static const int DEFAULT_MAX_ENTITY_PPS = 9000;
static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900;
class ScriptEngines;
class CallbackData {
public:
QScriptValue function;
@ -242,7 +244,7 @@ signals:
void errorLoadingScript(const QString& scriptFilename);
void update(float deltaTime);
void scriptEnding();
void finished(const QString& fileNameString, ScriptEngine* engine);
void finished(const QString& fileNameString, ScriptEnginePointer);
void cleanupMenuItem(const QString& menuItemString);
void printedMessage(const QString& message, const QString& scriptName);
void errorMessage(const QString& message, const QString& scriptName);
@ -328,6 +330,12 @@ protected:
static const QString _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS;
Setting::Handle<bool> _enableExtendedJSExceptions { _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS, true };
QSharedPointer<ScriptEngines> _scriptEngines;
};
ScriptEnginePointer scriptEngineFactory(ScriptEngine::Context context,
const QString& scriptContents,
const QString& fileNameString);
#endif // hifi_ScriptEngine_h

View file

@ -137,16 +137,14 @@ void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) {
_scriptInitializers.push_back(initializer);
}
void ScriptEngines::addScriptEngine(ScriptEngine* engine) {
if (_isStopped) {
engine->deleteLater();
} else {
void ScriptEngines::addScriptEngine(ScriptEnginePointer engine) {
if (!_isStopped) {
QMutexLocker locker(&_allScriptsMutex);
_allKnownScriptEngines.insert(engine);
}
}
void ScriptEngines::removeScriptEngine(ScriptEngine* engine) {
void ScriptEngines::removeScriptEngine(ScriptEnginePointer engine) {
// If we're not already in the middle of stopping all scripts, then we should remove ourselves
// from the list of running scripts. We don't do this if we're in the process of stopping all scripts
// because that method removes scripts from its list as it iterates them
@ -161,9 +159,9 @@ void ScriptEngines::shutdownScripting() {
QMutexLocker locker(&_allScriptsMutex);
qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size();
QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);
QMutableSetIterator<ScriptEnginePointer> i(_allKnownScriptEngines);
while (i.hasNext()) {
ScriptEngine* scriptEngine = i.next();
ScriptEnginePointer scriptEngine = i.next();
QString scriptName = scriptEngine->getFilename();
// NOTE: typically all script engines are running. But there's at least one known exception to this, the
@ -187,12 +185,9 @@ void ScriptEngines::shutdownScripting() {
qCDebug(scriptengine) << "waiting on script:" << scriptName;
scriptEngine->waitTillDoneRunning();
qCDebug(scriptengine) << "done waiting on script:" << scriptName;
scriptEngine->deleteLater();
// Once the script is stopped, we can remove it from our set
i.remove();
}
// Once the script is stopped, we can remove it from our set
i.remove();
}
qCDebug(scriptengine) << "DONE Stopping all scripts....";
}
@ -369,9 +364,9 @@ void ScriptEngines::stopAllScripts(bool restart) {
_isReloading = true;
}
for (QHash<QUrl, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
for (QHash<QUrl, ScriptEnginePointer>::const_iterator it = _scriptEnginesHash.constBegin();
it != _scriptEnginesHash.constEnd(); it++) {
ScriptEngine *scriptEngine = it.value();
ScriptEnginePointer scriptEngine = it.value();
// skip already stopped scripts
if (scriptEngine->isFinished() || scriptEngine->isStopping()) {
continue;
@ -417,11 +412,12 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) {
QReadLocker lock(&_scriptEnginesHashLock);
if (_scriptEnginesHash.contains(scriptURL)) {
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURL];
ScriptEnginePointer scriptEngine = _scriptEnginesHash[scriptURL];
if (restart) {
auto scriptCache = DependencyManager::get<ScriptCache>();
scriptCache->deleteScript(scriptURL);
connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) {
connect(scriptEngine.data(), &ScriptEngine::finished,
this, [this](QString scriptName, ScriptEnginePointer engine) {
reloadScript(scriptName);
});
}
@ -449,11 +445,11 @@ void ScriptEngines::reloadAllScripts() {
stopAllScripts(true);
}
ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor,
ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor,
bool activateMainWindow, bool reload) {
if (thread() != QThread::currentThread()) {
ScriptEngine* result { nullptr };
BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptEngine*, result),
ScriptEnginePointer result { nullptr };
BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptEnginePointer, result),
Q_ARG(QUrl, scriptFilename),
Q_ARG(bool, isUserLoaded),
Q_ARG(bool, loadScriptFromEditor),
@ -479,19 +475,16 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL
return scriptEngine;
}
scriptEngine = new ScriptEngine(_context, NO_SCRIPT, "about:" + scriptFilename.fileName());
scriptEngine = ScriptEnginePointer(new ScriptEngine(_context, NO_SCRIPT, "about:" + scriptFilename.fileName()));
addScriptEngine(scriptEngine);
scriptEngine->setUserLoaded(isUserLoaded);
connect(scriptEngine, &ScriptEngine::doneRunning, this, [scriptEngine] {
scriptEngine->deleteLater();
}, Qt::QueuedConnection);
if (scriptFilename.isEmpty() || !scriptUrl.isValid()) {
launchScriptEngine(scriptEngine);
} else {
// connect to the appropriate signals of this script engine
connect(scriptEngine, &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded);
connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError);
connect(scriptEngine.data(), &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded);
connect(scriptEngine.data(), &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError);
// get the script engine object to load the script at the designated script URL
scriptEngine->loadURL(scriptUrl, reload);
@ -500,8 +493,8 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL
return scriptEngine;
}
ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) {
ScriptEngine* result = nullptr;
ScriptEnginePointer ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) {
ScriptEnginePointer result;
{
QReadLocker lock(&_scriptEnginesHashLock);
const QUrl scriptURL = normalizeScriptURL(rawScriptURL);
@ -516,7 +509,8 @@ ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) {
// FIXME - change to new version of ScriptCache loading notification
void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) {
UserActivityLogger::getInstance().loadedScript(rawScriptURL);
ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender());
QSharedPointer<BaseScriptEngine> baseScriptEngine = qobject_cast<ScriptEngine*>(sender())->sharedFromThis();
ScriptEnginePointer scriptEngine = qSharedPointerCast<ScriptEngine>(baseScriptEngine);
launchScriptEngine(scriptEngine);
@ -532,12 +526,12 @@ void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) {
emit scriptCountChanged();
}
void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) {
connect(scriptEngine, &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection);
connect(scriptEngine, &ScriptEngine::loadScript, [&](const QString& scriptName, bool userLoaded) {
void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) {
connect(scriptEngine.data(), &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection);
connect(scriptEngine.data(), &ScriptEngine::loadScript, [&](const QString& scriptName, bool userLoaded) {
loadScript(scriptName, userLoaded);
});
connect(scriptEngine, &ScriptEngine::reloadScript, [&](const QString& scriptName, bool userLoaded) {
connect(scriptEngine.data(), &ScriptEngine::reloadScript, [&](const QString& scriptName, bool userLoaded) {
loadScript(scriptName, userLoaded, false, false, true);
});
@ -558,7 +552,7 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) {
}
}
void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine* engine) {
void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEnginePointer engine) {
bool removed = false;
{
QWriteLocker lock(&_scriptEnginesHashLock);

View file

@ -33,7 +33,7 @@ class ScriptEngines : public QObject, public Dependency {
Q_PROPERTY(ScriptsModelFilter* scriptsModelFilter READ scriptsModelFilter CONSTANT)
public:
using ScriptInitializer = std::function<void(ScriptEngine*)>;
using ScriptInitializer = std::function<void(ScriptEnginePointer)>;
ScriptEngines(ScriptEngine::Context context);
void registerScriptInitializer(ScriptInitializer initializer);
@ -45,7 +45,7 @@ public:
void loadDefaultScripts();
void setScriptsLocation(const QString& scriptsLocation);
QStringList getRunningScripts();
ScriptEngine* getScriptEngine(const QUrl& scriptHash);
ScriptEnginePointer getScriptEngine(const QUrl& scriptHash);
ScriptsModel* scriptsModel() { return &_scriptsModel; };
ScriptsModelFilter* scriptsModelFilter() { return &_scriptsModelFilter; };
@ -53,7 +53,7 @@ public:
QString getDefaultScriptsLocation() const;
Q_INVOKABLE void loadOneScript(const QString& scriptFilename);
Q_INVOKABLE ScriptEngine* loadScript(const QUrl& scriptFilename = QString(),
Q_INVOKABLE ScriptEnginePointer loadScript(const QUrl& scriptFilename = QString(),
bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false);
Q_INVOKABLE bool stopScript(const QString& scriptHash, bool restart = false);
@ -72,6 +72,8 @@ public:
void shutdownScripting();
bool isStopped() const { return _isStopped; }
void addScriptEngine(ScriptEnginePointer);
signals:
void scriptCountChanged();
void scriptsReloading();
@ -92,22 +94,21 @@ public slots:
void onClearDebugWindow();
protected slots:
void onScriptFinished(const QString& fileNameString, ScriptEngine* engine);
void onScriptFinished(const QString& fileNameString, ScriptEnginePointer engine);
protected:
friend class ScriptEngine;
void reloadScript(const QString& scriptName) { loadScript(scriptName, true, false, false, true); }
void addScriptEngine(ScriptEngine* engine);
void removeScriptEngine(ScriptEngine* engine);
void removeScriptEngine(ScriptEnginePointer);
void onScriptEngineLoaded(const QString& scriptFilename);
void onScriptEngineError(const QString& scriptFilename);
void launchScriptEngine(ScriptEngine* engine);
void launchScriptEngine(ScriptEnginePointer);
ScriptEngine::Context _context;
QReadWriteLock _scriptEnginesHashLock;
QHash<QUrl, ScriptEngine*> _scriptEnginesHash;
QSet<ScriptEngine*> _allKnownScriptEngines;
QHash<QUrl, ScriptEnginePointer> _scriptEnginesHash;
QSet<ScriptEnginePointer> _allKnownScriptEngines;
QMutex _allScriptsMutex;
std::list<ScriptInitializer> _scriptInitializers;
mutable Setting::Handle<QString> _scriptsLocationHandle;

View file

@ -16,6 +16,9 @@
#include <QtCore/QDebug>
#include <QtScript/QScriptEngine>
class ScriptEngine;
using ScriptEnginePointer = QSharedPointer<ScriptEngine>;
// common base class for extending QScriptEngine itself
class BaseScriptEngine : public QScriptEngine, public QEnableSharedFromThis<BaseScriptEngine> {
Q_OBJECT

View file

@ -89,9 +89,9 @@ var coatButton = new ToggleButtonBuddy(buttonPositionX, buttonPositionY, BUTTON_
var HAT_ATTACHMENT = {
modelURL: "https://s3.amazonaws.com/hifi-public/tony/cowboy-hat.fbx",
jointName: "Head",
translation: {"x": 0, "y": 0.2, "z": 0},
translation: {"x": 0, "y": 0.25, "z": 0.03},
rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
scale: 1,
scale: 0.052,
isSoft: false
};

View file

@ -1,4 +1,4 @@
<!--
<!--
// entityProperties.html
//
// Created by Ryan Huffman on 13 Nov 2014
@ -136,17 +136,21 @@
<fieldset class="column" id="group-cloneable-group" style="display:none;">
<legend class="sub-section-header">
<span>Cloneable Settings</span>
<span>Cloneable Settings</span>
</legend>
<fieldset class="minor">
<div><label>Clone Lifetime</label><input type="number" data-user-data-type="cloneLifetime" id="property-cloneable-lifetime"></div>
<div><label>Clone Lifetime</label><input type="number" data-user-data-type="cloneLifetime" id="property-cloneable-lifetime"></div>
</fieldset>
<fieldset class="minor">
<div><label>Clone Limit </label><input type="number" data-user-data-type="cloneLimit" id="property-cloneable-limit"></div>
<div><label>Clone Limit</label><input type="number" data-user-data-type="cloneLimit" id="property-cloneable-limit"></div>
</fieldset>
<div class="property checkbox">
<input type="checkbox" id="property-cloneable-dynamic">
<label for="property-cloneable-dynamic">Clone Dynamic</label>
<input type="checkbox" id="property-cloneable-dynamic">
<label for="property-cloneable-dynamic">Clone Dynamic</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-cloneable-avatarEntity">
<label for="property-cloneable-avatarEntity">Clone Avatar Entity</label>
</div>
</fieldset>
</div>

View file

@ -554,6 +554,7 @@ function loaded() {
var elCloneable = document.getElementById("property-cloneable");
var elCloneableDynamic = document.getElementById("property-cloneable-dynamic");
var elCloneableAvatarEntity = document.getElementById("property-cloneable-avatarEntity");
var elCloneableGroup = document.getElementById("group-cloneable-group");
var elCloneableLifetime = document.getElementById("property-cloneable-lifetime");
var elCloneableLimit = document.getElementById("property-cloneable-limit");
@ -844,25 +845,29 @@ function loaded() {
parsedUserData = JSON.parse(properties.userData);
if ("grabbableKey" in parsedUserData) {
if ("grabbable" in parsedUserData["grabbableKey"]) {
elGrabbable.checked = parsedUserData["grabbableKey"].grabbable;
var grabbableData = parsedUserData["grabbableKey"];
if ("grabbable" in grabbableData) {
elGrabbable.checked = grabbableData.grabbable;
}
if ("wantsTrigger" in parsedUserData["grabbableKey"]) {
elWantsTrigger.checked = parsedUserData["grabbableKey"].wantsTrigger;
if ("wantsTrigger" in grabbableData) {
elWantsTrigger.checked = grabbableData.wantsTrigger;
}
if ("ignoreIK" in parsedUserData["grabbableKey"]) {
elIgnoreIK.checked = parsedUserData["grabbableKey"].ignoreIK;
if ("ignoreIK" in grabbableData) {
elIgnoreIK.checked = grabbableData.ignoreIK;
}
if ("cloneable" in parsedUserData["grabbableKey"]) {
elCloneable.checked = parsedUserData["grabbableKey"].cloneable;
if ("cloneable" in grabbableData) {
elCloneable.checked = grabbableData.cloneable;
elCloneableGroup.style.display = elCloneable.checked ? "block": "none";
elCloneableDynamic.checked = parsedUserData["grabbableKey"].cloneDynamic ? parsedUserData["grabbableKey"].cloneDynamic : properties.dynamic;
elCloneableDynamic.checked = grabbableData.cloneDynamic ? grabbableData.cloneDynamic : properties.dynamic;
if (elCloneable.checked) {
if ("cloneLifetime" in parsedUserData["grabbableKey"]) {
elCloneableLifetime.value = parsedUserData["grabbableKey"].cloneLifetime ? parsedUserData["grabbableKey"].cloneLifetime : 300;
if ("cloneLifetime" in grabbableData) {
elCloneableLifetime.value = grabbableData.cloneLifetime ? grabbableData.cloneLifetime : 300;
}
if ("cloneLimit" in parsedUserData["grabbableKey"]) {
elCloneableLimit.value = parsedUserData["grabbableKey"].cloneLimit ? parsedUserData["grabbableKey"].cloneLimit : 0;
if ("cloneLimit" in grabbableData) {
elCloneableLimit.value = grabbableData.cloneLimit ? grabbableData.cloneLimit : 0;
}
if ("cloneAvatarEntity" in grabbableData) {
elCloneableAvatarEntity.checked = grabbableData.cloneAvatarEntity ? grabbableData.cloneAvatarEntity : false;
}
}
}
@ -1114,9 +1119,14 @@ function loaded() {
}
userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, properties.dynamic);
});
elCloneableDynamic.addEventListener('change', function (event){
elCloneableDynamic.addEventListener('change', function(event) {
userDataChanger("grabbableKey", "cloneDynamic", event.target, elUserData, -1);
});
elCloneableAvatarEntity.addEventListener('change', function(event) {
userDataChanger("grabbableKey", "cloneAvatarEntity", event.target, elUserData, -1);
});
elCloneable.addEventListener('change', function (event) {
var checked = event.target.checked;
if (checked) {
@ -1124,6 +1134,7 @@ function loaded() {
cloneLifetime: elCloneableLifetime,
cloneLimit: elCloneableLimit,
cloneDynamic: elCloneableDynamic,
cloneAvatarEntity: elCloneableAvatarEntity,
cloneable: event.target,
grabbable: null
}, elUserData, {});
@ -1134,6 +1145,7 @@ function loaded() {
cloneLifetime: null,
cloneLimit: null,
cloneDynamic: null,
cloneAvatarEntity: null,
cloneable: false
}, elUserData, {});
elCloneableGroup.style.display = "none";

View file

@ -72,6 +72,7 @@ cloneEntity = function(props, worldEntityProps) {
var lifetime = grabInfo.cloneLifetime ? grabInfo.cloneLifetime : 300;
var dynamic = grabInfo.cloneDynamic ? grabInfo.cloneDynamic : false;
var triggerable = grabInfo.triggerable ? grabInfo.triggerable : false;
var avatarEntity = grabInfo.cloneAvatarEntity ? grabInfo.cloneAvatarEntity : false;
var cUserData = Object.assign({}, JSON.parse(cloneableProps.userData));
var cProperties = Object.assign({}, cloneableProps);
@ -80,6 +81,7 @@ cloneEntity = function(props, worldEntityProps) {
delete cUserData.grabbableKey.cloneable;
delete cUserData.grabbableKey.cloneDynamic;
delete cUserData.grabbableKey.cloneLimit;
delete cUserData.grabbableKey.cloneAvatarEntity;
delete cProperties.id;
@ -90,6 +92,6 @@ cloneEntity = function(props, worldEntityProps) {
cProperties.lifetime = lifetime;
cProperties.userData = JSON.stringify(cUserData);
var cloneID = Entities.addEntity(cProperties);
var cloneID = Entities.addEntity(cProperties, avatarEntity);
return cloneID;
};