mirror of
https://github.com/overte-org/overte.git
synced 2025-04-26 01:36:20 +02:00
Merge branch 'master' of https://github.com/amerhifi/hifi
This commit is contained in:
commit
a6d03bb140
45 changed files with 662 additions and 102 deletions
|
@ -17,7 +17,6 @@
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|
||||||
#include <EntityTree.h>
|
#include <EntityTree.h>
|
||||||
#include <SimpleEntitySimulation.h>
|
|
||||||
#include <ResourceCache.h>
|
#include <ResourceCache.h>
|
||||||
#include <ScriptCache.h>
|
#include <ScriptCache.h>
|
||||||
#include <EntityEditFilters.h>
|
#include <EntityEditFilters.h>
|
||||||
|
@ -36,7 +35,7 @@ const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo";
|
||||||
|
|
||||||
EntityServer::EntityServer(ReceivedMessage& message) :
|
EntityServer::EntityServer(ReceivedMessage& message) :
|
||||||
OctreeServer(message),
|
OctreeServer(message),
|
||||||
_entitySimulation(NULL),
|
_entitySimulation(nullptr),
|
||||||
_dynamicDomainVerificationTimer(this)
|
_dynamicDomainVerificationTimer(this)
|
||||||
{
|
{
|
||||||
DependencyManager::set<ResourceManager>();
|
DependencyManager::set<ResourceManager>();
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "EntityItem.h"
|
#include <EntityItem.h>
|
||||||
|
#include <EntityTree.h>
|
||||||
|
#include <SimpleEntitySimulation.h>
|
||||||
|
|
||||||
#include "EntityServerConsts.h"
|
#include "EntityServerConsts.h"
|
||||||
#include "EntityTree.h"
|
|
||||||
|
|
||||||
/// Handles assignments of type EntityServer - sending entities to various clients.
|
/// Handles assignments of type EntityServer - sending entities to various clients.
|
||||||
|
|
||||||
|
@ -27,9 +29,6 @@ struct ViewerSendingStats {
|
||||||
quint64 lastEdited;
|
quint64 lastEdited;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleEntitySimulation;
|
|
||||||
using SimpleEntitySimulationPointer = std::shared_ptr<SimpleEntitySimulation>;
|
|
||||||
|
|
||||||
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
|
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -301,10 +301,17 @@ void EntityScriptServer::run() {
|
||||||
|
|
||||||
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
||||||
|
|
||||||
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
auto treePtr = _entityViewer.getTree();
|
||||||
|
DependencyManager::set<AssignmentParentFinder>(treePtr);
|
||||||
|
|
||||||
|
if (!_entitySimulation) {
|
||||||
|
SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() };
|
||||||
|
simpleSimulation->setEntityTree(treePtr);
|
||||||
|
treePtr->setSimulation(simpleSimulation);
|
||||||
|
_entitySimulation = simpleSimulation;
|
||||||
|
}
|
||||||
|
|
||||||
auto tree = _entityViewer.getTree().get();
|
auto tree = treePtr.get();
|
||||||
connect(tree, &EntityTree::deletingEntity, this, &EntityScriptServer::deletingEntity, Qt::QueuedConnection);
|
connect(tree, &EntityTree::deletingEntity, this, &EntityScriptServer::deletingEntity, Qt::QueuedConnection);
|
||||||
connect(tree, &EntityTree::addingEntity, this, &EntityScriptServer::addingEntity, Qt::QueuedConnection);
|
connect(tree, &EntityTree::addingEntity, this, &EntityScriptServer::addingEntity, Qt::QueuedConnection);
|
||||||
connect(tree, &EntityTree::entityServerScriptChanging, this, &EntityScriptServer::entityServerScriptChanging, Qt::QueuedConnection);
|
connect(tree, &EntityTree::entityServerScriptChanging, this, &EntityScriptServer::entityServerScriptChanging, Qt::QueuedConnection);
|
||||||
|
@ -451,6 +458,7 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
|
||||||
|
|
||||||
connect(newEngine.data(), &ScriptEngine::update, this, [this] {
|
connect(newEngine.data(), &ScriptEngine::update, this, [this] {
|
||||||
_entityViewer.queryOctree();
|
_entityViewer.queryOctree();
|
||||||
|
_entityViewer.getTree()->preUpdate();
|
||||||
_entityViewer.getTree()->update();
|
_entityViewer.getTree()->update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <EntityEditPacketSender.h>
|
#include <EntityEditPacketSender.h>
|
||||||
#include <plugins/CodecPlugin.h>
|
#include <plugins/CodecPlugin.h>
|
||||||
#include <ScriptEngine.h>
|
#include <ScriptEngine.h>
|
||||||
|
#include <SimpleEntitySimulation.h>
|
||||||
#include <ThreadedAssignment.h>
|
#include <ThreadedAssignment.h>
|
||||||
#include "../entities/EntityTreeHeadlessViewer.h"
|
#include "../entities/EntityTreeHeadlessViewer.h"
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ private:
|
||||||
|
|
||||||
static int _entitiesScriptEngineCount;
|
static int _entitiesScriptEngineCount;
|
||||||
ScriptEnginePointer _entitiesScriptEngine;
|
ScriptEnginePointer _entitiesScriptEngine;
|
||||||
|
SimpleEntitySimulationPointer _entitySimulation;
|
||||||
EntityEditPacketSender _entityEditSender;
|
EntityEditPacketSender _entityEditSender;
|
||||||
EntityTreeHeadlessViewer _entityViewer;
|
EntityTreeHeadlessViewer _entityViewer;
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
||||||
set(BUILD_ORGANIZATION "High Fidelity")
|
set(BUILD_ORGANIZATION "High Fidelity")
|
||||||
set(HIGH_FIDELITY_PROTOCOL "hifi")
|
set(HIGH_FIDELITY_PROTOCOL "hifi")
|
||||||
set(HIGH_FIDELITY_APP_PROTOCOL "hifiapp")
|
set(HIGH_FIDELITY_APP_PROTOCOL "hifiapp")
|
||||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
set(INTERFACE_BUNDLE_NAME "interface")
|
||||||
set(INTERFACE_ICON_PREFIX "interface")
|
set(INTERFACE_ICON_PREFIX "interface")
|
||||||
|
|
||||||
# add definition for this release type
|
# add definition for this release type
|
||||||
|
@ -61,7 +61,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
||||||
set(PR_BUILD 1)
|
set(PR_BUILD 1)
|
||||||
set(BUILD_VERSION "PR${RELEASE_NUMBER}")
|
set(BUILD_VERSION "PR${RELEASE_NUMBER}")
|
||||||
set(BUILD_ORGANIZATION "High Fidelity - PR${RELEASE_NUMBER}")
|
set(BUILD_ORGANIZATION "High Fidelity - PR${RELEASE_NUMBER}")
|
||||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
set(INTERFACE_BUNDLE_NAME "interface")
|
||||||
set(INTERFACE_ICON_PREFIX "interface-beta")
|
set(INTERFACE_ICON_PREFIX "interface-beta")
|
||||||
|
|
||||||
# add definition for this release type
|
# add definition for this release type
|
||||||
|
@ -70,7 +70,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
||||||
set(DEV_BUILD 1)
|
set(DEV_BUILD 1)
|
||||||
set(BUILD_VERSION "dev")
|
set(BUILD_VERSION "dev")
|
||||||
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
|
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
|
||||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
set(INTERFACE_BUNDLE_NAME "interface")
|
||||||
set(INTERFACE_ICON_PREFIX "interface-beta")
|
set(INTERFACE_ICON_PREFIX "interface-beta")
|
||||||
|
|
||||||
# add definition for this release type
|
# add definition for this release type
|
||||||
|
|
20
interface/interface.entitlements
Normal file
20
interface/interface.entitlements
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>high-fidelity.hifi</string>
|
||||||
|
</array>
|
||||||
|
<key>com.apple.security.cs.allow-jit</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.device.audio-input</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.server</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -512,13 +512,13 @@ void OtherAvatar::handleChangedAvatarEntityData() {
|
||||||
entity->setParentID(NULL_ID);
|
entity->setParentID(NULL_ID);
|
||||||
entity->setParentID(oldParentID);
|
entity->setParentID(oldParentID);
|
||||||
|
|
||||||
if (entity->stillHasMyGrabAction()) {
|
if (entity->stillHasMyGrab()) {
|
||||||
// For this case: we want to ignore transform+velocities coming from authoritative OtherAvatar
|
// For this case: we want to ignore transform+velocities coming from authoritative OtherAvatar
|
||||||
// because the MyAvatar is grabbing and we expect the local grab state
|
// because the MyAvatar is grabbing and we expect the local grab state
|
||||||
// to have enough information to prevent simulation drift.
|
// to have enough information to prevent simulation drift.
|
||||||
//
|
//
|
||||||
// Clever readers might realize this could cause problems. For example,
|
// Clever readers might realize this could cause problems. For example,
|
||||||
// if an ignored OtherAvagtar were to simultanously grab the object then there would be
|
// if an ignored OtherAvatar were to simultanously grab the object then there would be
|
||||||
// a noticeable discrepancy between participants in the distributed physics simulation,
|
// a noticeable discrepancy between participants in the distributed physics simulation,
|
||||||
// however the difference would be stable and would not drift.
|
// however the difference would be stable and would not drift.
|
||||||
properties.clearTransformOrVelocityChanges();
|
properties.clearTransformOrVelocityChanges();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QtCore/QProcess>
|
#include <QtCore/QProcess>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
#include <QSharedMemory>
|
#include <QSharedMemory>
|
||||||
|
@ -117,21 +118,27 @@ int main(int argc, const char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString applicationPath;
|
QString applicationPath;
|
||||||
|
// A temporary application instance is needed to get the location of the running executable
|
||||||
|
// Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV)
|
||||||
|
// If we wanted to avoid the QCoreApplication, we would need to write our own
|
||||||
|
// cross-platform implementation.
|
||||||
{
|
{
|
||||||
// A temporary application instance is needed to get the location of the running executable
|
|
||||||
// Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV)
|
|
||||||
// If we wanted to avoid the QCoreApplication, we would need to write our own
|
|
||||||
// cross-platform implementation.
|
|
||||||
QCoreApplication tempApp(argc, const_cast<char**>(argv));
|
QCoreApplication tempApp(argc, const_cast<char**>(argv));
|
||||||
|
#ifdef Q_OS_OSX
|
||||||
|
if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/../../../config.json")) {
|
||||||
|
applicationPath = QCoreApplication::applicationDirPath() + "/../../../";
|
||||||
|
} else {
|
||||||
|
applicationPath = QCoreApplication::applicationDirPath();
|
||||||
|
}
|
||||||
|
#else
|
||||||
applicationPath = QCoreApplication::applicationDirPath();
|
applicationPath = QCoreApplication::applicationDirPath();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString APPLICATION_CONFIG_FILENAME = "config.json";
|
static const QString APPLICATION_CONFIG_FILENAME = "config.json";
|
||||||
QDir applicationDir(applicationPath);
|
QDir applicationDir(applicationPath);
|
||||||
QString configFileName = applicationDir.filePath(APPLICATION_CONFIG_FILENAME);
|
QString configFileName = applicationDir.filePath(APPLICATION_CONFIG_FILENAME);
|
||||||
QFile configFile(configFileName);
|
QFile configFile(configFileName);
|
||||||
QString launcherPath;
|
QString launcherPath;
|
||||||
|
|
||||||
if (configFile.exists()) {
|
if (configFile.exists()) {
|
||||||
if (!configFile.open(QIODevice::ReadOnly)) {
|
if (!configFile.open(QIODevice::ReadOnly)) {
|
||||||
qWarning() << "Found application config, but could not open it";
|
qWarning() << "Found application config, but could not open it";
|
||||||
|
|
|
@ -118,7 +118,7 @@ void AnimStats::updateStats(bool force) {
|
||||||
|
|
||||||
auto prevIter = _prevDebugAlphaMap.find(key);
|
auto prevIter = _prevDebugAlphaMap.find(key);
|
||||||
if (prevIter != _prevDebugAlphaMap.end()) {
|
if (prevIter != _prevDebugAlphaMap.end()) {
|
||||||
float prevAlpha = std::get<0>(iter.second);
|
float prevAlpha = std::get<0>(prevIter->second);
|
||||||
if (prevAlpha != alpha) {
|
if (prevAlpha != alpha) {
|
||||||
// change detected: reset timer
|
// change detected: reset timer
|
||||||
_animAlphaValueChangedTimers[key] = now;
|
_animAlphaValueChangedTimers[key] = now;
|
||||||
|
|
|
@ -126,7 +126,10 @@ add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD
|
||||||
|
|
||||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||||
COMMAND updater
|
COMMAND updater
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/updater" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources/")
|
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/updater" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/MacOS/"
|
||||||
|
# Older versions of Launcher put updater in `/Contents/Resources/updater`.
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E chdir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources" ln -sf ../MacOS/updater updater
|
||||||
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
TARGETS HQLauncher
|
TARGETS HQLauncher
|
||||||
|
|
10
launchers/darwin/HQ Launcher.entitlements
Normal file
10
launchers/darwin/HQ Launcher.entitlements
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>high-fidelity.hifi</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -50,6 +50,8 @@
|
||||||
repeats: YES];
|
repeats: YES];
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
|
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||||
|
NSString* appPath = [sharedLauncher getAppPath];
|
||||||
NSString *destinationFileName = downloadTask.originalRequest.URL.lastPathComponent;
|
NSString *destinationFileName = downloadTask.originalRequest.URL.lastPathComponent;
|
||||||
NSString* finalFilePath = [[[Launcher sharedLauncher] getAppPath] stringByAppendingPathComponent:destinationFileName];
|
NSString* finalFilePath = [[[Launcher sharedLauncher] getAppPath] stringByAppendingPathComponent:destinationFileName];
|
||||||
NSURL *destinationURL = [NSURL URLWithString: [finalFilePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]] relativeToURL: [NSURL URLWithString:@"file://"]];
|
NSURL *destinationURL = [NSURL URLWithString: [finalFilePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]] relativeToURL: [NSURL URLWithString:@"file://"]];
|
||||||
|
@ -59,7 +61,12 @@
|
||||||
}
|
}
|
||||||
[fileManager moveItemAtURL:location toURL:destinationURL error:&error];
|
[fileManager moveItemAtURL:location toURL:destinationURL error:&error];
|
||||||
|
|
||||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
NSURL *oldInterfaceURL = [NSURL URLWithString: [[appPath stringByAppendingString:@"interface.app"] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]] relativeToURL: [NSURL URLWithString:@"file://"]];
|
||||||
|
|
||||||
|
if([fileManager fileExistsAtPath:[oldInterfaceURL path]])
|
||||||
|
{
|
||||||
|
[fileManager removeItemAtURL:oldInterfaceURL error:nil];
|
||||||
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
NSLog(@"Download Interface: failed to move file to destination -> error: %@", error);
|
NSLog(@"Download Interface: failed to move file to destination -> error: %@", error);
|
||||||
|
@ -68,7 +75,6 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[sharedLauncher setDownloadFilename:destinationFileName];
|
[sharedLauncher setDownloadFilename:destinationFileName];
|
||||||
NSString* appPath = [sharedLauncher getAppPath];
|
|
||||||
NSString* downloadFileName = [sharedLauncher getDownloadFilename];
|
NSString* downloadFileName = [sharedLauncher getDownloadFilename];
|
||||||
|
|
||||||
NSLog(@"extract interface zip");
|
NSLog(@"extract interface zip");
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
@interface DownloadLauncher : NSObject<NSURLSessionDataDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLDownloadDelegate> {
|
@interface DownloadLauncher : NSObject<NSURLSessionDataDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLDownloadDelegate> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property (readonly) bool didBecomeDownloadTask;
|
||||||
|
|
||||||
- (void) downloadLauncher:(NSString*) launcherUrl;
|
- (void) downloadLauncher:(NSString*) launcherUrl;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -8,6 +8,13 @@ static const NSString *kIOError = @"IOError";
|
||||||
|
|
||||||
@implementation DownloadLauncher
|
@implementation DownloadLauncher
|
||||||
|
|
||||||
|
-(id)init {
|
||||||
|
if ((self = [super init]) != nil) {
|
||||||
|
_didBecomeDownloadTask = false;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) downloadLauncher:(NSString*)launcherUrl {
|
- (void) downloadLauncher:(NSString*)launcherUrl {
|
||||||
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:launcherUrl]
|
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:launcherUrl]
|
||||||
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||||
|
@ -16,8 +23,8 @@ static const NSString *kIOError = @"IOError";
|
||||||
|
|
||||||
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
|
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||||
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
|
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
|
||||||
NSURLSessionDownloadTask *downloadTask = [defaultSession downloadTaskWithRequest:request];
|
NSURLSessionDataTask *task = [defaultSession dataTaskWithRequest:request];
|
||||||
[downloadTask resume];
|
[task resume];
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
|
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
|
||||||
|
@ -45,6 +52,25 @@ static const NSString *kIOError = @"IOError";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
|
||||||
|
didReceiveResponse:(NSURLResponse *)response
|
||||||
|
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
|
||||||
|
{
|
||||||
|
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||||
|
NSURLSessionResponseDisposition disposition = NSURLSessionResponseBecomeDownload;
|
||||||
|
if (httpResponse.statusCode != 200) {
|
||||||
|
NSLog(@"expected statusCode 200, got %ld", (long)httpResponse.statusCode);
|
||||||
|
disposition = NSURLSessionResponseCancel;
|
||||||
|
}
|
||||||
|
completionHandler(disposition);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
|
||||||
|
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||||
|
{
|
||||||
|
_didBecomeDownloadTask = true;
|
||||||
|
}
|
||||||
|
|
||||||
-(void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didFinishDownloadingToURL:(NSURL*)location {
|
-(void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didFinishDownloadingToURL:(NSURL*)location {
|
||||||
NSLog(@"Did finish downloading to url");
|
NSLog(@"Did finish downloading to url");
|
||||||
@try {
|
@try {
|
||||||
|
@ -95,9 +121,14 @@ static const NSString *kIOError = @"IOError";
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)URLSession:(NSURLSession*)session task:(NSURLSessionTask*)task didCompleteWithError:(NSError*)error {
|
- (void)URLSession:(NSURLSession*)session task:(NSURLSessionTask*)task didCompleteWithError:(NSError*)error {
|
||||||
NSLog(@"completed; error: %@", error);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
if (_didBecomeDownloadTask && [task class] == [NSURLSessionDataTask class]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSLog(@"couldn't complete download: %@", error);
|
||||||
[[Launcher sharedLauncher] displayErrorPage];
|
[[Launcher sharedLauncher] displayErrorPage];
|
||||||
|
} else {
|
||||||
|
NSLog(@"finished downloading Launcher");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -383,6 +383,13 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
|
||||||
|
|
||||||
[self updateLatestBuildInfo];
|
[self updateLatestBuildInfo];
|
||||||
|
|
||||||
|
NSString *kLauncherUrl = @"LAUNCHER_URL";
|
||||||
|
NSString *envLauncherUrl = [[NSProcessInfo processInfo] environment][kLauncherUrl];
|
||||||
|
if (envLauncherUrl != nil) {
|
||||||
|
NSLog(@"Using launcherUrl from environment: %@ = %@", kLauncherUrl, envLauncherUrl);
|
||||||
|
launcherUrl = envLauncherUrl;
|
||||||
|
}
|
||||||
|
|
||||||
NSDictionary* launcherArguments = [LauncherCommandlineArgs arguments];
|
NSDictionary* launcherArguments = [LauncherCommandlineArgs arguments];
|
||||||
if (newLauncherAvailable && ![launcherArguments valueForKey: @"--noUpdate"]) {
|
if (newLauncherAvailable && ![launcherArguments valueForKey: @"--noUpdate"]) {
|
||||||
[self.downloadLauncher downloadLauncher: launcherUrl];
|
[self.downloadLauncher downloadLauncher: launcherUrl];
|
||||||
|
@ -460,11 +467,36 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
|
||||||
|
|
||||||
-(void)runAutoupdater
|
-(void)runAutoupdater
|
||||||
{
|
{
|
||||||
NSTask* task = [[NSTask alloc] init];
|
NSException *exception;
|
||||||
|
bool launched = false;
|
||||||
NSString* newLauncher = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent: @"HQ Launcher.app"];
|
NSString* newLauncher = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent: @"HQ Launcher.app"];
|
||||||
task.launchPath = [newLauncher stringByAppendingString:@"/Contents/Resources/updater"];
|
|
||||||
task.arguments = @[[[NSBundle mainBundle] bundlePath], newLauncher];
|
// Older versions of Launcher put updater in `/Contents/Resources/updater`.
|
||||||
[task launch];
|
for (NSString *bundlePath in @[@"/Contents/MacOS/updater",
|
||||||
|
@"/Contents/Resources/updater",
|
||||||
|
]) {
|
||||||
|
NSTask* task = [[NSTask alloc] init];
|
||||||
|
task.launchPath = [newLauncher stringByAppendingString: bundlePath];
|
||||||
|
task.arguments = @[[[NSBundle mainBundle] bundlePath], newLauncher];
|
||||||
|
|
||||||
|
NSLog(@"launching updater: %@ %@", task.launchPath, task.arguments);
|
||||||
|
|
||||||
|
@try {
|
||||||
|
[task launch];
|
||||||
|
}
|
||||||
|
@catch (NSException *e) {
|
||||||
|
NSLog(@"couldn't launch updater: %@, %@", e.name, e.reason);
|
||||||
|
exception = e;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
launched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!launched) {
|
||||||
|
@throw exception;
|
||||||
|
}
|
||||||
|
|
||||||
[NSApp terminate:self];
|
[NSApp terminate:self];
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,19 +14,32 @@
|
||||||
return sharedSettings;
|
return sharedSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString*) getOldFilePath {
|
||||||
|
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||||
|
NSString* appPath = [sharedLauncher getAppPath];
|
||||||
|
NSString* filePath = [appPath stringByAppendingString:@"interface.app/Contents/MacOS/"];
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString*) getFilePath
|
- (NSString*) getFilePath
|
||||||
{
|
{
|
||||||
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
Launcher* sharedLauncher = [Launcher sharedLauncher];
|
||||||
NSString* appPath = [sharedLauncher getAppPath];
|
NSString* appPath = [sharedLauncher getAppPath];
|
||||||
NSString* filePath = [appPath stringByAppendingString:@"interface.app/Contents/MacOS/"];
|
return appPath;
|
||||||
|
|
||||||
return filePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) readDataFromJsonFile
|
- (void) readDataFromJsonFile
|
||||||
{
|
{
|
||||||
|
NSString* oldPath = [self getOldFilePath];
|
||||||
|
NSString* fileAtOldPath = [oldPath stringByAppendingString:@"config.json"];
|
||||||
NSString* filePath = [self getFilePath];
|
NSString* filePath = [self getFilePath];
|
||||||
NSString* fileAtPath = [filePath stringByAppendingString:@"config.json"];
|
NSString* fileAtPath = [filePath stringByAppendingString:@"config.json"];
|
||||||
|
|
||||||
|
if ([[NSFileManager defaultManager] fileExistsAtPath:fileAtOldPath] && ![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
|
||||||
|
BOOL success = [[NSFileManager defaultManager] moveItemAtPath:fileAtOldPath toPath:fileAtPath error:nil];
|
||||||
|
NSLog(@"move config to new location -> status: %@", success ? @"SUCCESS" : @"FAILED");
|
||||||
|
}
|
||||||
|
|
||||||
if ([[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
|
if ([[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
|
||||||
NSString* jsonString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding];
|
NSString* jsonString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding];
|
||||||
NSError * err;
|
NSError * err;
|
||||||
|
@ -34,7 +47,6 @@
|
||||||
NSDictionary * json;
|
NSDictionary * json;
|
||||||
if (data != nil) {
|
if (data != nil) {
|
||||||
json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
|
json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
|
||||||
|
|
||||||
self.loggedIn = [[json valueForKey:@"loggedIn"] boolValue];
|
self.loggedIn = [[json valueForKey:@"loggedIn"] boolValue];
|
||||||
self.build = [[json valueForKey:@"build_version"] integerValue];
|
self.build = [[json valueForKey:@"build_version"] integerValue];
|
||||||
self.launcher = [json valueForKey:@"luancherPath"];
|
self.launcher = [json valueForKey:@"luancherPath"];
|
||||||
|
|
148
libraries/animation/src/AnimBlendDirectional.cpp
Normal file
148
libraries/animation/src/AnimBlendDirectional.cpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
//
|
||||||
|
// AnimBlendDirectional.cpp
|
||||||
|
//
|
||||||
|
// Created by Anthony J. Thibault on Augest 30 2019.
|
||||||
|
// Copyright (c) 2019 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AnimBlendDirectional.h"
|
||||||
|
#include "GLMHelpers.h"
|
||||||
|
#include "AnimationLogging.h"
|
||||||
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
|
AnimBlendDirectional::AnimBlendDirectional(const QString& id, glm::vec3 alpha, const QString& centerId,
|
||||||
|
const QString& upId, const QString& downId, const QString& leftId, const QString& rightId,
|
||||||
|
const QString& upLeftId, const QString& upRightId, const QString& downLeftId, const QString& downRightId) :
|
||||||
|
AnimNode(AnimNode::Type::BlendDirectional, id),
|
||||||
|
_alpha(alpha),
|
||||||
|
_centerId(centerId),
|
||||||
|
_upId(upId),
|
||||||
|
_downId(downId),
|
||||||
|
_leftId(leftId),
|
||||||
|
_rightId(rightId),
|
||||||
|
_upLeftId(upLeftId),
|
||||||
|
_upRightId(upRightId),
|
||||||
|
_downLeftId(downLeftId),
|
||||||
|
_downRightId(downRightId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimBlendDirectional::~AnimBlendDirectional() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnimPoseVec& AnimBlendDirectional::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) {
|
||||||
|
|
||||||
|
// lookupRaw don't transform the vector.
|
||||||
|
_alpha = animVars.lookupRaw(_alphaVar, _alpha);
|
||||||
|
float parentDebugAlpha = context.getDebugAlpha(_id);
|
||||||
|
|
||||||
|
if (_children.size() == 9) {
|
||||||
|
|
||||||
|
// try to keep the order the same as quadrants, for _childIndices.
|
||||||
|
// +---+---+
|
||||||
|
// | 1 | 0 |
|
||||||
|
// +---+---+
|
||||||
|
// | 2 | 3 |
|
||||||
|
// +---+---+
|
||||||
|
|
||||||
|
std::array<int, 4> indices;
|
||||||
|
glm::vec2 alpha = _alpha;
|
||||||
|
if (_alpha.x > 0.0f) {
|
||||||
|
if (_alpha.y > 0.0f) {
|
||||||
|
// quadrant 0
|
||||||
|
indices = {{_childIndices[0][2], _childIndices[0][1], _childIndices[1][1], _childIndices[1][2]}};
|
||||||
|
} else {
|
||||||
|
// quadrant 3
|
||||||
|
indices = {{_childIndices[1][2], _childIndices[1][1], _childIndices[2][1], _childIndices[2][2]}};
|
||||||
|
// shift alpha up so both alpha.x and alpha.y are in the (0, 1) range.
|
||||||
|
alpha.y += 1.0f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_alpha.y > 0.0f) {
|
||||||
|
// quadrant 1
|
||||||
|
indices = {{_childIndices[0][1], _childIndices[0][0], _childIndices[1][0], _childIndices[1][1]}};
|
||||||
|
// shift alpha right so both alpha.x and alpha.y are in the (0, 1) range.
|
||||||
|
alpha.x += 1.0f;
|
||||||
|
} else {
|
||||||
|
// quadrant 2
|
||||||
|
indices = {{_childIndices[1][1], _childIndices[1][0], _childIndices[2][0], _childIndices[2][1]}};
|
||||||
|
// shift alpha up and right so both alpha.x and alpha.y are in the (0, 1) range.
|
||||||
|
alpha.x += 1.0f;
|
||||||
|
alpha.y += 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::array<float, 4> alphas = {{
|
||||||
|
alpha.x * alpha.y,
|
||||||
|
(1.0f - alpha.x) * alpha.y,
|
||||||
|
(1.0f - alpha.x) * (1.0f - alpha.y),
|
||||||
|
alpha.x * (1.0f - alpha.y)
|
||||||
|
}};
|
||||||
|
|
||||||
|
// evaluate children
|
||||||
|
std::array<AnimPoseVec, 4> poseVecs;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
poseVecs[i] = _children[indices[i]]->evaluate(animVars, context, dt, triggersOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
// blend children
|
||||||
|
size_t minSize = INT_MAX;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (poseVecs[i].size() < minSize) {
|
||||||
|
minSize = poseVecs[i].size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_poses.resize(minSize);
|
||||||
|
blend4(minSize, &poseVecs[0][0], &poseVecs[1][0], &poseVecs[2][0], &poseVecs[3][0], &alphas[0], &_poses[0]);
|
||||||
|
|
||||||
|
// animation stack debug stats
|
||||||
|
for (int i = 0; i < 9; i++) {
|
||||||
|
context.setDebugAlpha(_children[i]->getID(), 0.0f, _children[i]->getType());
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
context.setDebugAlpha(_children[indices[i]]->getID(), alphas[i] * parentDebugAlpha, _children[indices[i]]->getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (auto&& pose : _poses) {
|
||||||
|
pose = AnimPose::identity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _poses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for AnimDebugDraw rendering
|
||||||
|
const AnimPoseVec& AnimBlendDirectional::getPosesInternal() const {
|
||||||
|
return _poses;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AnimBlendDirectional::lookupChildIds() {
|
||||||
|
_childIndices[0][0] = findChildIndexByName(_upLeftId);
|
||||||
|
_childIndices[0][1] = findChildIndexByName(_upId);
|
||||||
|
_childIndices[0][2] = findChildIndexByName(_upRightId);
|
||||||
|
|
||||||
|
_childIndices[1][0] = findChildIndexByName(_leftId);
|
||||||
|
_childIndices[1][1] = findChildIndexByName(_centerId);
|
||||||
|
_childIndices[1][2] = findChildIndexByName(_rightId);
|
||||||
|
|
||||||
|
_childIndices[2][0] = findChildIndexByName(_downLeftId);
|
||||||
|
_childIndices[2][1] = findChildIndexByName(_downId);
|
||||||
|
_childIndices[2][2] = findChildIndexByName(_downRightId);
|
||||||
|
|
||||||
|
// manditory children
|
||||||
|
// TODO: currently all are manditory.
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
if (_childIndices[i][j] == -1) {
|
||||||
|
qDebug(animation) << "Error in AnimBlendDirectional::lookupChildIds() could not find child[" << i << "," << j << "]";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
59
libraries/animation/src/AnimBlendDirectional.h
Normal file
59
libraries/animation/src/AnimBlendDirectional.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// AnimBlendDirectonal.h
|
||||||
|
//
|
||||||
|
// Created by Anthony J. Thibault on Augest 30 2019.
|
||||||
|
// Copyright (c) 2019 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_AnimBlendDirectional_h
|
||||||
|
#define hifi_AnimBlendDirectional_h
|
||||||
|
|
||||||
|
#include "AnimNode.h"
|
||||||
|
|
||||||
|
// blend between up to nine AnimNodes.
|
||||||
|
|
||||||
|
class AnimBlendDirectional : public AnimNode {
|
||||||
|
public:
|
||||||
|
friend class AnimTests;
|
||||||
|
|
||||||
|
AnimBlendDirectional(const QString& id, glm::vec3 alpha, const QString& centerId,
|
||||||
|
const QString& upId, const QString& downId, const QString& leftId, const QString& rightId,
|
||||||
|
const QString& upLeftId, const QString& upRightId, const QString& downLeftId, const QString& downRightId);
|
||||||
|
virtual ~AnimBlendDirectional() override;
|
||||||
|
|
||||||
|
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override;
|
||||||
|
|
||||||
|
void setAlphaVar(const QString& alphaVar) { _alphaVar = alphaVar; }
|
||||||
|
|
||||||
|
bool lookupChildIds();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// for AnimDebugDraw rendering
|
||||||
|
virtual const AnimPoseVec& getPosesInternal() const override;
|
||||||
|
|
||||||
|
AnimPoseVec _poses;
|
||||||
|
|
||||||
|
glm::vec3 _alpha;
|
||||||
|
QString _centerId;
|
||||||
|
QString _upId;
|
||||||
|
QString _downId;
|
||||||
|
QString _leftId;
|
||||||
|
QString _rightId;
|
||||||
|
QString _upLeftId;
|
||||||
|
QString _upRightId;
|
||||||
|
QString _downLeftId;
|
||||||
|
QString _downRightId;
|
||||||
|
|
||||||
|
QString _alphaVar;
|
||||||
|
|
||||||
|
int _childIndices[3][3];
|
||||||
|
|
||||||
|
// no copies
|
||||||
|
AnimBlendDirectional(const AnimBlendDirectional&) = delete;
|
||||||
|
AnimBlendDirectional& operator=(const AnimBlendDirectional&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AnimBlendDirectional_h
|
|
@ -110,11 +110,9 @@ void AnimBlendLinear::evaluateAndBlendChildren(const AnimVariantMap& animVars, c
|
||||||
// copy translation and scale from nextPoses
|
// copy translation and scale from nextPoses
|
||||||
AnimPose pose = nextPoses[i];
|
AnimPose pose = nextPoses[i];
|
||||||
|
|
||||||
int parentIndex = _skeleton->getParentIndex((int)i);
|
// convert from a rotation that happens in the absolute space of the joint
|
||||||
if (parentIndex >= 0) {
|
// into a rotation that happens in the relative space of the joint.
|
||||||
// but transform nextPoses rot into absPrev parent frame.
|
pose.rot() = glm::inverse(absPrev[i].rot()) * pose.rot() * absPrev[i].rot();
|
||||||
pose.rot() = glm::inverse(absPrev[parentIndex].rot()) * pose.rot() * absPrev[parentIndex].rot();
|
|
||||||
}
|
|
||||||
|
|
||||||
relOffsetPoses.push_back(pose);
|
relOffsetPoses.push_back(pose);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ static void bakeRelativeDeltaAnim(std::vector<AnimPoseVec>& anim, const AnimPose
|
||||||
// for each joint in animPoses
|
// for each joint in animPoses
|
||||||
for (size_t i = 0; i < animPoses.size(); ++i) {
|
for (size_t i = 0; i < animPoses.size(); ++i) {
|
||||||
// convert this relative AnimPose into a delta animation.
|
// convert this relative AnimPose into a delta animation.
|
||||||
animPoses[i] = animPoses[i] * invBasePoses[i];
|
animPoses[i] = invBasePoses[i] * animPoses[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,13 +80,11 @@ void bakeAbsoluteDeltaAnim(std::vector<AnimPoseVec>& anim, const AnimPoseVec& ba
|
||||||
for (size_t i = 0; i < animPoses.size(); ++i) {
|
for (size_t i = 0; i < animPoses.size(); ++i) {
|
||||||
|
|
||||||
// scale and translation are relative frame
|
// scale and translation are relative frame
|
||||||
animPoses[i] = animPoses[i] * invBasePoses[i];
|
animPoses[i] = invBasePoses[i] * animPoses[i];
|
||||||
|
|
||||||
// but transform the rotation delta into the absolute frame.
|
// convert from a rotation that happens in the relative space of the joint
|
||||||
int parentIndex = skeleton->getParentIndex((int)i);
|
// into a rotation that happens in the absolute space of the joint.
|
||||||
if (parentIndex >= 0) {
|
animPoses[i].rot() = absBasePoses[i].rot() * animPoses[i].rot() * glm::inverse(absBasePoses[i].rot());
|
||||||
animPoses[i].rot() = absBasePoses[parentIndex].rot() * animPoses[i].rot() * glm::inverse(absBasePoses[parentIndex].rot());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ enum class AnimNodeType {
|
||||||
TwoBoneIK,
|
TwoBoneIK,
|
||||||
SplineIK,
|
SplineIK,
|
||||||
PoleVectorConstraint,
|
PoleVectorConstraint,
|
||||||
|
BlendDirectional,
|
||||||
NumTypes
|
NumTypes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,15 @@ public:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int findChildIndexByName(const QString& id) {
|
||||||
|
for (size_t i = 0; i < _children.size(); ++i) {
|
||||||
|
if (_children[i]->getID() == id) {
|
||||||
|
return (int)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
const AnimPoseVec& getPoses() const { return getPosesInternal(); }
|
const AnimPoseVec& getPoses() const { return getPosesInternal(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "AnimTwoBoneIK.h"
|
#include "AnimTwoBoneIK.h"
|
||||||
#include "AnimSplineIK.h"
|
#include "AnimSplineIK.h"
|
||||||
#include "AnimPoleVectorConstraint.h"
|
#include "AnimPoleVectorConstraint.h"
|
||||||
|
#include "AnimBlendDirectional.h"
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
using NodeLoaderFunc = AnimNode::Pointer (*)(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
using NodeLoaderFunc = AnimNode::Pointer (*)(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
@ -47,6 +48,7 @@ static AnimNode::Pointer loadDefaultPoseNode(const QJsonObject& jsonObj, const Q
|
||||||
static AnimNode::Pointer loadTwoBoneIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
static AnimNode::Pointer loadTwoBoneIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
static AnimNode::Pointer loadSplineIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
static AnimNode::Pointer loadSplineIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
static AnimNode::Pointer loadPoleVectorConstraintNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
static AnimNode::Pointer loadPoleVectorConstraintNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
static AnimNode::Pointer loadBlendDirectionalNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
|
||||||
static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f;
|
static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f;
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f;
|
||||||
static bool processDoNothing(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { return true; }
|
static bool processDoNothing(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { return true; }
|
||||||
bool processStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
bool processStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
bool processRandomSwitchStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
bool processRandomSwitchStateMachineNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
bool processBlendDirectionalNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||||
|
|
||||||
static const char* animNodeTypeToString(AnimNode::Type type) {
|
static const char* animNodeTypeToString(AnimNode::Type type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -70,6 +73,7 @@ static const char* animNodeTypeToString(AnimNode::Type type) {
|
||||||
case AnimNode::Type::TwoBoneIK: return "twoBoneIK";
|
case AnimNode::Type::TwoBoneIK: return "twoBoneIK";
|
||||||
case AnimNode::Type::SplineIK: return "splineIK";
|
case AnimNode::Type::SplineIK: return "splineIK";
|
||||||
case AnimNode::Type::PoleVectorConstraint: return "poleVectorConstraint";
|
case AnimNode::Type::PoleVectorConstraint: return "poleVectorConstraint";
|
||||||
|
case AnimNode::Type::BlendDirectional: return "blendDirectional";
|
||||||
case AnimNode::Type::NumTypes: return nullptr;
|
case AnimNode::Type::NumTypes: return nullptr;
|
||||||
};
|
};
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -211,6 +215,7 @@ static NodeLoaderFunc animNodeTypeToLoaderFunc(AnimNode::Type type) {
|
||||||
case AnimNode::Type::TwoBoneIK: return loadTwoBoneIKNode;
|
case AnimNode::Type::TwoBoneIK: return loadTwoBoneIKNode;
|
||||||
case AnimNode::Type::SplineIK: return loadSplineIKNode;
|
case AnimNode::Type::SplineIK: return loadSplineIKNode;
|
||||||
case AnimNode::Type::PoleVectorConstraint: return loadPoleVectorConstraintNode;
|
case AnimNode::Type::PoleVectorConstraint: return loadPoleVectorConstraintNode;
|
||||||
|
case AnimNode::Type::BlendDirectional: return loadBlendDirectionalNode;
|
||||||
case AnimNode::Type::NumTypes: return nullptr;
|
case AnimNode::Type::NumTypes: return nullptr;
|
||||||
};
|
};
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -230,6 +235,7 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) {
|
||||||
case AnimNode::Type::TwoBoneIK: return processDoNothing;
|
case AnimNode::Type::TwoBoneIK: return processDoNothing;
|
||||||
case AnimNode::Type::SplineIK: return processDoNothing;
|
case AnimNode::Type::SplineIK: return processDoNothing;
|
||||||
case AnimNode::Type::PoleVectorConstraint: return processDoNothing;
|
case AnimNode::Type::PoleVectorConstraint: return processDoNothing;
|
||||||
|
case AnimNode::Type::BlendDirectional: return processBlendDirectionalNode;
|
||||||
case AnimNode::Type::NumTypes: return nullptr;
|
case AnimNode::Type::NumTypes: return nullptr;
|
||||||
};
|
};
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -402,7 +408,6 @@ static AnimNode::Pointer loadClipNode(const QJsonObject& jsonObj, const QString&
|
||||||
auto tempUrl = QUrl(url);
|
auto tempUrl = QUrl(url);
|
||||||
tempUrl = jsonUrl.resolved(tempUrl);
|
tempUrl = jsonUrl.resolved(tempUrl);
|
||||||
|
|
||||||
// AJT:
|
|
||||||
AnimBlendType blendTypeEnum = AnimBlendType_Normal; // default value
|
AnimBlendType blendTypeEnum = AnimBlendType_Normal; // default value
|
||||||
if (!blendType.isEmpty()) {
|
if (!blendType.isEmpty()) {
|
||||||
blendTypeEnum = stringToAnimBlendType(blendType);
|
blendTypeEnum = stringToAnimBlendType(blendType);
|
||||||
|
@ -772,6 +777,32 @@ static AnimNode::Pointer loadPoleVectorConstraintNode(const QJsonObject& jsonObj
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AnimNode::Pointer loadBlendDirectionalNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) {
|
||||||
|
|
||||||
|
READ_VEC3(alpha, jsonObj, id, jsonUrl, nullptr);
|
||||||
|
READ_OPTIONAL_STRING(alphaVar, jsonObj);
|
||||||
|
|
||||||
|
READ_OPTIONAL_STRING(centerId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(upId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(downId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(leftId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(rightId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(upLeftId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(upRightId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(downLeftId, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(downRightId, jsonObj);
|
||||||
|
|
||||||
|
auto node = std::make_shared<AnimBlendDirectional>(id, alpha, centerId,
|
||||||
|
upId, downId, leftId, rightId,
|
||||||
|
upLeftId, upRightId, downLeftId, downRightId);
|
||||||
|
|
||||||
|
if (!alphaVar.isEmpty()) {
|
||||||
|
node->setAlphaVar(alphaVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
void buildChildMap(std::map<QString, int>& map, AnimNode::Pointer node) {
|
void buildChildMap(std::map<QString, int>& map, AnimNode::Pointer node) {
|
||||||
for (int i = 0; i < (int)node->getChildCount(); ++i) {
|
for (int i = 0; i < (int)node->getChildCount(); ++i) {
|
||||||
map.insert(std::pair<QString, int>(node->getChild(i)->getID(), i));
|
map.insert(std::pair<QString, int>(node->getChild(i)->getID(), i));
|
||||||
|
@ -1042,7 +1073,12 @@ bool processRandomSwitchStateMachineNode(AnimNode::Pointer node, const QJsonObje
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool processBlendDirectionalNode(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& nodeId, const QUrl& jsonUrl) {
|
||||||
|
auto blendNode = std::static_pointer_cast<AnimBlendDirectional>(node);
|
||||||
|
assert(blendNode);
|
||||||
|
|
||||||
|
return blendNode->lookupChildIds();
|
||||||
|
}
|
||||||
|
|
||||||
AnimNodeLoader::AnimNodeLoader(const QUrl& url) :
|
AnimNodeLoader::AnimNodeLoader(const QUrl& url) :
|
||||||
_url(url)
|
_url(url)
|
||||||
|
|
|
@ -26,6 +26,31 @@ void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void blend3(size_t numPoses, const AnimPose* a, const AnimPose* b, const AnimPose* c, float* alphas, AnimPose* result) {
|
||||||
|
for (size_t i = 0; i < numPoses; i++) {
|
||||||
|
const AnimPose& aPose = a[i];
|
||||||
|
const AnimPose& bPose = b[i];
|
||||||
|
const AnimPose& cPose = c[i];
|
||||||
|
|
||||||
|
result[i].scale() = alphas[0] * aPose.scale() + alphas[1] * bPose.scale() + alphas[2] * cPose.scale();
|
||||||
|
result[i].rot() = safeLinearCombine3(aPose.rot(), bPose.rot(), cPose.rot(), alphas);
|
||||||
|
result[i].trans() = alphas[0] * aPose.trans() + alphas[1] * bPose.trans() + alphas[2] * cPose.trans();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void blend4(size_t numPoses, const AnimPose* a, const AnimPose* b, const AnimPose* c, const AnimPose* d, float* alphas, AnimPose* result) {
|
||||||
|
for (size_t i = 0; i < numPoses; i++) {
|
||||||
|
const AnimPose& aPose = a[i];
|
||||||
|
const AnimPose& bPose = b[i];
|
||||||
|
const AnimPose& cPose = c[i];
|
||||||
|
const AnimPose& dPose = d[i];
|
||||||
|
|
||||||
|
result[i].scale() = alphas[0] * aPose.scale() + alphas[1] * bPose.scale() + alphas[2] * cPose.scale() + alphas[3] * dPose.scale();
|
||||||
|
result[i].rot() = safeLinearCombine4(aPose.rot(), bPose.rot(), cPose.rot(), dPose.rot(), alphas);
|
||||||
|
result[i].trans() = alphas[0] * aPose.trans() + alphas[1] * bPose.trans() + alphas[2] * cPose.trans() + alphas[3] * dPose.trans();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// additive blend
|
// additive blend
|
||||||
void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result) {
|
void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result) {
|
||||||
|
|
||||||
|
@ -43,8 +68,7 @@ void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha
|
||||||
delta = -delta;
|
delta = -delta;
|
||||||
}
|
}
|
||||||
delta = glm::lerp(identity, delta, alpha);
|
delta = glm::lerp(identity, delta, alpha);
|
||||||
result[i].rot() = glm::normalize(delta * aPose.rot());
|
result[i].rot() = glm::normalize(aPose.rot() * delta);
|
||||||
|
|
||||||
result[i].trans() = aPose.trans() + (alpha * bPose.trans());
|
result[i].trans() = aPose.trans() + (alpha * bPose.trans());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
// this is where the magic happens
|
// this is where the magic happens
|
||||||
void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
|
void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
|
||||||
|
|
||||||
|
// blend between three sets of poses
|
||||||
|
void blend3(size_t numPoses, const AnimPose* a, const AnimPose* b, const AnimPose* c, float* alphas, AnimPose* result);
|
||||||
|
|
||||||
|
// blend between four sets of poses
|
||||||
|
void blend4(size_t numPoses, const AnimPose* a, const AnimPose* b, const AnimPose* c, const AnimPose* d, float* alphas, AnimPose* result);
|
||||||
|
|
||||||
// additive blending
|
// additive blending
|
||||||
void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
|
void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
|
||||||
|
|
||||||
|
@ -34,6 +40,41 @@ inline glm::quat safeLerp(const glm::quat& a, const glm::quat& b, float alpha) {
|
||||||
return glm::normalize(glm::lerp(a, bTemp, alpha));
|
return glm::normalize(glm::lerp(a, bTemp, alpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline glm::quat safeLinearCombine3(const glm::quat& a, const glm::quat& b, const glm::quat& c, float* alphas) {
|
||||||
|
// adjust signs for b & c if necessary
|
||||||
|
glm::quat bTemp = b;
|
||||||
|
float dot = glm::dot(a, bTemp);
|
||||||
|
if (dot < 0.0f) {
|
||||||
|
bTemp = -bTemp;
|
||||||
|
}
|
||||||
|
glm::quat cTemp = c;
|
||||||
|
dot = glm::dot(a, cTemp);
|
||||||
|
if (dot < 0.0f) {
|
||||||
|
cTemp = -cTemp;
|
||||||
|
}
|
||||||
|
return glm::normalize(alphas[0] * a + alphas[1] * bTemp + alphas[2] * cTemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline glm::quat safeLinearCombine4(const glm::quat& a, const glm::quat& b, const glm::quat& c, const glm::quat& d, float* alphas) {
|
||||||
|
// adjust signs for b, c & d if necessary
|
||||||
|
glm::quat bTemp = b;
|
||||||
|
float dot = glm::dot(a, bTemp);
|
||||||
|
if (dot < 0.0f) {
|
||||||
|
bTemp = -bTemp;
|
||||||
|
}
|
||||||
|
glm::quat cTemp = c;
|
||||||
|
dot = glm::dot(a, cTemp);
|
||||||
|
if (dot < 0.0f) {
|
||||||
|
cTemp = -cTemp;
|
||||||
|
}
|
||||||
|
glm::quat dTemp = d;
|
||||||
|
dot = glm::dot(a, dTemp);
|
||||||
|
if (dot < 0.0f) {
|
||||||
|
dTemp = -dTemp;
|
||||||
|
}
|
||||||
|
return glm::normalize(alphas[0] * a + alphas[1] * bTemp + alphas[2] * cTemp + alphas[3] * dTemp);
|
||||||
|
}
|
||||||
|
|
||||||
AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone);
|
AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone);
|
||||||
|
|
||||||
// This will attempt to determine the proper body facing of a characters body
|
// This will attempt to determine the proper body facing of a characters body
|
||||||
|
|
|
@ -141,32 +141,26 @@ std::map<QString, QString> AnimVariantMap::toDebugMap() const {
|
||||||
break;
|
break;
|
||||||
case AnimVariant::Type::Vec3: {
|
case AnimVariant::Type::Vec3: {
|
||||||
// To prevent filling up debug stats, don't show vec3 values
|
// To prevent filling up debug stats, don't show vec3 values
|
||||||
/*
|
|
||||||
glm::vec3 value = pair.second.getVec3();
|
glm::vec3 value = pair.second.getVec3();
|
||||||
result[pair.first] = QString("(%1, %2, %3)").
|
result[pair.first] = QString("(%1, %2, %3)").
|
||||||
arg(QString::number(value.x, 'f', 3)).
|
arg(QString::number(value.x, 'f', 3)).
|
||||||
arg(QString::number(value.y, 'f', 3)).
|
arg(QString::number(value.y, 'f', 3)).
|
||||||
arg(QString::number(value.z, 'f', 3));
|
arg(QString::number(value.z, 'f', 3));
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AnimVariant::Type::Quat: {
|
case AnimVariant::Type::Quat: {
|
||||||
// To prevent filling up the anim stats, don't show quat values
|
// To prevent filling up the anim stats, don't show quat values
|
||||||
/*
|
|
||||||
glm::quat value = pair.second.getQuat();
|
glm::quat value = pair.second.getQuat();
|
||||||
result[pair.first] = QString("(%1, %2, %3, %4)").
|
result[pair.first] = QString("(%1, %2, %3, %4)").
|
||||||
arg(QString::number(value.x, 'f', 3)).
|
arg(QString::number(value.x, 'f', 3)).
|
||||||
arg(QString::number(value.y, 'f', 3)).
|
arg(QString::number(value.y, 'f', 3)).
|
||||||
arg(QString::number(value.z, 'f', 3)).
|
arg(QString::number(value.z, 'f', 3)).
|
||||||
arg(QString::number(value.w, 'f', 3));
|
arg(QString::number(value.w, 'f', 3));
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AnimVariant::Type::String:
|
case AnimVariant::Type::String:
|
||||||
// To prevent filling up anim stats, don't show string values
|
// To prevent filling up anim stats, don't show string values
|
||||||
/*
|
|
||||||
result[pair.first] = pair.second.getString();
|
result[pair.first] = pair.second.getString();
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// invalid AnimVariant::Type
|
// invalid AnimVariant::Type
|
||||||
|
|
|
@ -171,6 +171,8 @@ void ClientTraitsHandler::processTraitOverride(QSharedPointer<ReceivedMessage> m
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AJT: DON'T CHECK THIS IN, disable model URL overrides.
|
||||||
|
/*
|
||||||
// only accept an override if this is for a trait type we override
|
// only accept an override if this is for a trait type we override
|
||||||
// and the version matches what we last sent for skeleton
|
// and the version matches what we last sent for skeleton
|
||||||
if (traitType == AvatarTraits::SkeletonModelURL
|
if (traitType == AvatarTraits::SkeletonModelURL
|
||||||
|
@ -192,6 +194,7 @@ void ClientTraitsHandler::processTraitOverride(QSharedPointer<ReceivedMessage> m
|
||||||
} else {
|
} else {
|
||||||
message->seek(message->getPosition() + traitBinarySize);
|
message->seek(message->getPosition() + traitBinarySize);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -798,7 +798,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
auto lastEdited = lastEditedFromBufferAdjusted;
|
auto lastEdited = lastEditedFromBufferAdjusted;
|
||||||
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
|
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
|
||||||
// calculate hasGrab once outside the lambda rather than calling it every time inside
|
// calculate hasGrab once outside the lambda rather than calling it every time inside
|
||||||
bool hasGrab = stillHasGrabAction();
|
bool hasGrab = stillHasGrab();
|
||||||
auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection, hasGrab](quint64 updatedTimestamp, bool valueChanged) {
|
auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection, hasGrab](quint64 updatedTimestamp, bool valueChanged) {
|
||||||
if (hasGrab) {
|
if (hasGrab) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1444,7 +1444,7 @@ void EntityItem::getTransformAndVelocityProperties(EntityItemProperties& propert
|
||||||
|
|
||||||
void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
|
void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
|
||||||
uint8_t newPriority = glm::max(priority, _scriptSimulationPriority);
|
uint8_t newPriority = glm::max(priority, _scriptSimulationPriority);
|
||||||
if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasMyGrabAction()) {
|
if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasMyGrab()) {
|
||||||
newPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
newPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
||||||
}
|
}
|
||||||
if (newPriority != _scriptSimulationPriority) {
|
if (newPriority != _scriptSimulationPriority) {
|
||||||
|
@ -1457,7 +1457,7 @@ void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
|
||||||
void EntityItem::clearScriptSimulationPriority() {
|
void EntityItem::clearScriptSimulationPriority() {
|
||||||
// DO NOT markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) here, because this
|
// DO NOT markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) here, because this
|
||||||
// is only ever called from the code that actually handles the dirty flags, and it knows best.
|
// is only ever called from the code that actually handles the dirty flags, and it knows best.
|
||||||
_scriptSimulationPriority = stillHasMyGrabAction() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
|
_scriptSimulationPriority = stillHasMyGrab() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::setPendingOwnershipPriority(uint8_t priority) {
|
void EntityItem::setPendingOwnershipPriority(uint8_t priority) {
|
||||||
|
@ -2204,7 +2204,7 @@ void EntityItem::enableNoBootstrap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::disableNoBootstrap() {
|
void EntityItem::disableNoBootstrap() {
|
||||||
if (!stillHasMyGrabAction()) {
|
if (!stillHasMyGrab()) {
|
||||||
_flags &= ~Simulation::SPECIAL_FLAG_NO_BOOTSTRAPPING;
|
_flags &= ~Simulation::SPECIAL_FLAG_NO_BOOTSTRAPPING;
|
||||||
_flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
_flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||||
|
|
||||||
|
@ -2290,33 +2290,25 @@ bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& a
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityItem::stillHasGrabAction() const {
|
bool EntityItem::stillHasGrab() const {
|
||||||
return !_grabActions.empty();
|
return !(_grabs.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
// retutrns 'true' if there exists an action that returns 'true' for EntityActionInterface::isMine()
|
// returns 'true' if there exists an action that returns 'true' for EntityActionInterface::isMine()
|
||||||
// (e.g. the action belongs to the MyAvatar instance)
|
// (e.g. the action belongs to the MyAvatar instance)
|
||||||
bool EntityItem::stillHasMyGrabAction() const {
|
bool EntityItem::stillHasMyGrab() const {
|
||||||
QList<EntityDynamicPointer> holdActions = getActionsOfType(DYNAMIC_TYPE_HOLD);
|
bool foundGrab = false;
|
||||||
QList<EntityDynamicPointer>::const_iterator i = holdActions.begin();
|
if (!_grabs.empty()) {
|
||||||
while (i != holdActions.end()) {
|
_grabsLock.withReadLock([&] {
|
||||||
EntityDynamicPointer action = *i;
|
foreach (const GrabPointer &grab, _grabs) {
|
||||||
if (action->isMine()) {
|
if (grab->getOwnerID() == Physics::getSessionUUID()) {
|
||||||
return true;
|
foundGrab = true;
|
||||||
}
|
break;
|
||||||
i++;
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
QList<EntityDynamicPointer> farGrabActions = getActionsOfType(DYNAMIC_TYPE_FAR_GRAB);
|
return foundGrab;
|
||||||
i = farGrabActions.begin();
|
|
||||||
while (i != farGrabActions.end()) {
|
|
||||||
EntityDynamicPointer action = *i;
|
|
||||||
if (action->isMine()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation) {
|
bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation) {
|
||||||
|
|
|
@ -569,7 +569,7 @@ public:
|
||||||
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
|
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
|
||||||
static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
|
static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
|
||||||
|
|
||||||
bool stillHasMyGrabAction() const;
|
bool stillHasMyGrab() const;
|
||||||
|
|
||||||
bool needsRenderUpdate() const { return resultWithReadLock<bool>([&] { return _needsRenderUpdate; }); }
|
bool needsRenderUpdate() const { return resultWithReadLock<bool>([&] { return _needsRenderUpdate; }); }
|
||||||
void setNeedsRenderUpdate(bool needsRenderUpdate) { withWriteLock([&] { _needsRenderUpdate = needsRenderUpdate; }); }
|
void setNeedsRenderUpdate(bool needsRenderUpdate) { withWriteLock([&] { _needsRenderUpdate = needsRenderUpdate; }); }
|
||||||
|
@ -585,7 +585,7 @@ protected:
|
||||||
void setSimulated(bool simulated) { _simulated = simulated; }
|
void setSimulated(bool simulated) { _simulated = simulated; }
|
||||||
|
|
||||||
const QByteArray getDynamicDataInternal() const;
|
const QByteArray getDynamicDataInternal() const;
|
||||||
bool stillHasGrabAction() const;
|
bool stillHasGrab() const;
|
||||||
void setDynamicDataInternal(QByteArray dynamicData);
|
void setDynamicDataInternal(QByteArray dynamicData);
|
||||||
|
|
||||||
virtual void dimensionsChanged() override;
|
virtual void dimensionsChanged() override;
|
||||||
|
|
|
@ -2246,8 +2246,8 @@ void EntityTree::preUpdate() {
|
||||||
void EntityTree::update(bool simulate) {
|
void EntityTree::update(bool simulate) {
|
||||||
PROFILE_RANGE(simulation_physics, "UpdateTree");
|
PROFILE_RANGE(simulation_physics, "UpdateTree");
|
||||||
PerformanceTimer perfTimer("updateTree");
|
PerformanceTimer perfTimer("updateTree");
|
||||||
withWriteLock([&] {
|
if (simulate && _simulation) {
|
||||||
if (simulate && _simulation) {
|
withWriteLock([&] {
|
||||||
_simulation->updateEntities();
|
_simulation->updateEntities();
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(simulation_physics, "Deletes");
|
PROFILE_RANGE(simulation_physics, "Deletes");
|
||||||
|
@ -2265,8 +2265,8 @@ void EntityTree::update(bool simulate) {
|
||||||
deleteEntities(idsToDelete, true);
|
deleteEntities(idsToDelete, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 EntityTree::getAdjustedConsiderSince(quint64 sinceTime) {
|
quint64 EntityTree::getAdjustedConsiderSince(quint64 sinceTime) {
|
||||||
|
|
|
@ -111,7 +111,7 @@ vec3 fetchNormalMap(vec2 uv) {
|
||||||
// unpack normal, swizzle to get into hifi tangent space with Y axis pointing out
|
// unpack normal, swizzle to get into hifi tangent space with Y axis pointing out
|
||||||
vec2 t = 2.0 * (texture(normalMap, uv, TAA_TEXTURE_LOD_BIAS).rg - vec2(0.5, 0.5));
|
vec2 t = 2.0 * (texture(normalMap, uv, TAA_TEXTURE_LOD_BIAS).rg - vec2(0.5, 0.5));
|
||||||
vec2 t2 = t*t;
|
vec2 t2 = t*t;
|
||||||
return vec3(t.x, sqrt(1.0 - t2.x - t2.y), t.y);
|
return vec3(t.x, sqrt(max(0.0, 1.0 - t2.x - t2.y)), t.y);
|
||||||
}
|
}
|
||||||
<@endif@>
|
<@endif@>
|
||||||
|
|
||||||
|
|
|
@ -274,6 +274,7 @@ enum class EntityVersion : PacketVersion {
|
||||||
TextUnlit,
|
TextUnlit,
|
||||||
ShadowBiasAndDistance,
|
ShadowBiasAndDistance,
|
||||||
TextEntityFonts,
|
TextEntityFonts,
|
||||||
|
ScriptServerKinematicMotion,
|
||||||
|
|
||||||
// Add new versions above here
|
// Add new versions above here
|
||||||
NUM_PACKET_TYPE,
|
NUM_PACKET_TYPE,
|
||||||
|
|
|
@ -740,7 +740,8 @@ bool EntityMotionState::shouldSendBid() const {
|
||||||
&& (_region == workload::Region::R1)
|
&& (_region == workload::Region::R1)
|
||||||
&& _ownershipState != EntityMotionState::OwnershipState::Unownable
|
&& _ownershipState != EntityMotionState::OwnershipState::Unownable
|
||||||
&& glm::max(glm::max(VOLUNTEER_SIMULATION_PRIORITY, _bumpedPriority), _entity->getScriptSimulationPriority()) >= _entity->getSimulationPriority()
|
&& glm::max(glm::max(VOLUNTEER_SIMULATION_PRIORITY, _bumpedPriority), _entity->getScriptSimulationPriority()) >= _entity->getSimulationPriority()
|
||||||
&& !_entity->getLocked();
|
&& !_entity->getLocked()
|
||||||
|
&& (!_body->isStaticOrKinematicObject() || _entity->stillHasMyGrab());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::setRigidBody(btRigidBody* body) {
|
void EntityMotionState::setRigidBody(btRigidBody* body) {
|
||||||
|
|
|
@ -291,6 +291,10 @@ void OffscreenSurface::setMaxFps(uint8_t maxFps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenSurface::load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) {
|
void OffscreenSurface::load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) {
|
||||||
|
loadFromQml(qmlSource, parent, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OffscreenSurface::loadFromQml(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) {
|
||||||
loadInternal(qmlSource, false, parent, [callback](QQmlContext* context, QQuickItem* newItem) {
|
loadInternal(qmlSource, false, parent, [callback](QQmlContext* context, QQuickItem* newItem) {
|
||||||
QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem));
|
QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem));
|
||||||
});
|
});
|
||||||
|
|
|
@ -111,6 +111,7 @@ signals:
|
||||||
void rootItemCreated(QQuickItem* rootContext);
|
void rootItemCreated(QQuickItem* rootContext);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void loadFromQml(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback);
|
||||||
bool eventFilter(QObject* originalDestination, QEvent* event) override;
|
bool eventFilter(QObject* originalDestination, QEvent* event) override;
|
||||||
bool filterEnabled(QObject* originalDestination, QEvent* event) const;
|
bool filterEnabled(QObject* originalDestination, QEvent* event) const;
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
#include <QtScriptTools/QScriptEngineDebugger>
|
#include <QtScriptTools/QScriptEngineDebugger>
|
||||||
|
|
||||||
|
#include <shared/LocalFileAccessGate.h>
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <AudioConstants.h>
|
#include <AudioConstants.h>
|
||||||
#include <AudioEffectOptions.h>
|
#include <AudioEffectOptions.h>
|
||||||
|
@ -1123,6 +1124,12 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::run() {
|
void ScriptEngine::run() {
|
||||||
|
if (QThread::currentThread() != qApp->thread() && _context == Context::CLIENT_SCRIPT) {
|
||||||
|
// Flag that we're allowed to access local HTML files on UI created from C++ calls on this thread
|
||||||
|
// (because we're a client script)
|
||||||
|
hifi::scripting::setLocalAccessSafeThread(true);
|
||||||
|
}
|
||||||
|
|
||||||
auto filenameParts = _fileNameString.split("/");
|
auto filenameParts = _fileNameString.split("/");
|
||||||
auto name = filenameParts.size() > 0 ? filenameParts[filenameParts.size() - 1] : "unknown";
|
auto name = filenameParts.size() > 0 ? filenameParts[filenameParts.size() - 1] : "unknown";
|
||||||
PROFILE_SET_THREAD_NAME("Script: " + name);
|
PROFILE_SET_THREAD_NAME("Script: " + name);
|
||||||
|
@ -1300,6 +1307,9 @@ void ScriptEngine::run() {
|
||||||
|
|
||||||
emit finished(_fileNameString, qSharedPointerCast<ScriptEngine>(sharedFromThis()));
|
emit finished(_fileNameString, qSharedPointerCast<ScriptEngine>(sharedFromThis()));
|
||||||
|
|
||||||
|
// Don't leave our local-file-access flag laying around, reset it to false when the scriptengine
|
||||||
|
// thread is finished
|
||||||
|
hifi::scripting::setLocalAccessSafeThread(false);
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
emit runningStateChanged();
|
emit runningStateChanged();
|
||||||
emit doneRunning();
|
emit doneRunning();
|
||||||
|
|
21
libraries/shared/src/shared/LocalFileAccessGate.cpp
Normal file
21
libraries/shared/src/shared/LocalFileAccessGate.cpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2019/09/05
|
||||||
|
// Copyright 2013-2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "LocalFileAccessGate.h"
|
||||||
|
|
||||||
|
#include <QtCore/QThreadStorage>
|
||||||
|
|
||||||
|
static QThreadStorage<bool> localAccessSafe;
|
||||||
|
|
||||||
|
void hifi::scripting::setLocalAccessSafeThread(bool safe) {
|
||||||
|
localAccessSafe.setLocalData(safe);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hifi::scripting::isLocalAccessSafeThread() {
|
||||||
|
return localAccessSafe.hasLocalData() && localAccessSafe.localData();
|
||||||
|
}
|
21
libraries/shared/src/shared/LocalFileAccessGate.h
Normal file
21
libraries/shared/src/shared/LocalFileAccessGate.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2019/09/05
|
||||||
|
// Copyright 2013-2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_LocalFileAccessGate_h
|
||||||
|
#define hifi_LocalFileAccessGate_h
|
||||||
|
|
||||||
|
namespace hifi { namespace scripting {
|
||||||
|
|
||||||
|
void setLocalAccessSafeThread(bool safe = true);
|
||||||
|
|
||||||
|
bool isLocalAccessSafeThread();
|
||||||
|
|
||||||
|
}} // namespace hifi::scripting
|
||||||
|
|
||||||
|
#endif
|
|
@ -42,6 +42,7 @@
|
||||||
#include <NetworkAccessManager.h>
|
#include <NetworkAccessManager.h>
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <AudioClient.h>
|
#include <AudioClient.h>
|
||||||
|
#include <shared/LocalFileAccessGate.h>
|
||||||
|
|
||||||
#include <gl/OffscreenGLCanvas.h>
|
#include <gl/OffscreenGLCanvas.h>
|
||||||
#include <gl/GLHelpers.h>
|
#include <gl/GLHelpers.h>
|
||||||
|
@ -814,4 +815,24 @@ void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OffscreenQmlSurface::loadFromQml(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) {
|
||||||
|
auto objectCallback = [callback](QQmlContext* context, QQuickItem* newItem) {
|
||||||
|
QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (hifi::scripting::isLocalAccessSafeThread()) {
|
||||||
|
// If this is a
|
||||||
|
auto contextCallback = [callback](QQmlContext* context) {
|
||||||
|
ContextAwareProfile::restrictContext(context, false);
|
||||||
|
#if !defined(Q_OS_ANDROID)
|
||||||
|
FileTypeProfile::registerWithContext(context);
|
||||||
|
HFWebEngineProfile::registerWithContext(context);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
loadInternal(qmlSource, true, parent, objectCallback, contextCallback);
|
||||||
|
} else {
|
||||||
|
loadInternal(qmlSource, false, parent, objectCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "OffscreenQmlSurface.moc"
|
#include "OffscreenQmlSurface.moc"
|
||||||
|
|
|
@ -61,6 +61,7 @@ public slots:
|
||||||
void sendToQml(const QVariant& message);
|
void sendToQml(const QVariant& message);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void loadFromQml(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) override;
|
||||||
void clearFocusItem();
|
void clearFocusItem();
|
||||||
void setFocusText(bool newFocusText);
|
void setFocusText(bool newFocusText);
|
||||||
void initializeEngine(QQmlEngine* engine) override;
|
void initializeEngine(QQmlEngine* engine) override;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <QtQml/QQmlProperty>
|
#include <QtQml/QQmlProperty>
|
||||||
|
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
|
#include <shared/LocalFileAccessGate.h>
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
|
@ -637,11 +638,22 @@ void TabletProxy::returnToPreviousApp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) {
|
void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) {
|
||||||
|
// Capture whether the current script thread is allowed to load local HTML content,
|
||||||
|
// pass the information along to the real function
|
||||||
|
bool localSafeContext = hifi::scripting::isLocalAccessSafeThread();
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "loadQMLSource", Q_ARG(QVariant, path), Q_ARG(bool, resizable));
|
QMetaObject::invokeMethod(this, "loadQMLSourceImpl", Q_ARG(QVariant, path), Q_ARG(bool, resizable), Q_ARG(bool, localSafeContext));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
loadQMLSourceImpl(path, resizable, localSafeContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabletProxy::loadQMLSourceImpl(const QVariant& path, bool resizable, bool localSafeContext) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
qCWarning(uiLogging) << __FUNCTION__ << "may not be called directly by scripts";
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
QObject* root = nullptr;
|
QObject* root = nullptr;
|
||||||
if (!_toolbarMode && _qmlTabletRoot) {
|
if (!_toolbarMode && _qmlTabletRoot) {
|
||||||
root = _qmlTabletRoot;
|
root = _qmlTabletRoot;
|
||||||
|
@ -650,7 +662,14 @@ void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root) {
|
if (root) {
|
||||||
|
// BUGZ-1398: tablet access to local HTML files from client scripts
|
||||||
|
// Here we TEMPORARILY mark the main thread as allowed to load local file content,
|
||||||
|
// because the thread that originally made the call is so marked.
|
||||||
|
if (localSafeContext) {
|
||||||
|
hifi::scripting::setLocalAccessSafeThread(true);
|
||||||
|
}
|
||||||
QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path));
|
QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path));
|
||||||
|
hifi::scripting::setLocalAccessSafeThread(false);
|
||||||
_state = State::QML;
|
_state = State::QML;
|
||||||
_currentPathLoaded = path;
|
_currentPathLoaded = path;
|
||||||
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||||
|
|
|
@ -291,6 +291,13 @@ public:
|
||||||
* to have it not resizable.
|
* to have it not resizable.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void loadQMLSource(const QVariant& path, bool resizable = false);
|
Q_INVOKABLE void loadQMLSource(const QVariant& path, bool resizable = false);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Internal function, do not call from scripts
|
||||||
|
* @function TabletProxy#loadQMLSourceImpl
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void loadQMLSourceImpl(const QVariant& path, bool resizable, bool localSafeContext);
|
||||||
|
|
||||||
// FIXME: This currently relies on a script initializing the tablet (hence the bool denoting success);
|
// FIXME: This currently relies on a script initializing the tablet (hence the bool denoting success);
|
||||||
// it should be initialized internally so it cannot fail
|
// it should be initialized internally so it cannot fail
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,6 @@ function pruneOldAvimojis() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function maybeClearTimeoutDelete() {
|
function maybeClearTimeoutDelete() {
|
||||||
if (defaultTimeout) {
|
if (defaultTimeout) {
|
||||||
Script.clearTimeout(defaultTimeout);
|
Script.clearTimeout(defaultTimeout);
|
||||||
|
@ -157,6 +156,7 @@ function handleSelectedEmoji(emojiFilename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function onDomainChanged() {
|
function onDomainChanged() {
|
||||||
resetEmojis();
|
resetEmojis();
|
||||||
}
|
}
|
||||||
|
@ -167,6 +167,14 @@ function onScaleChanged() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onAddingWearable(id) {
|
||||||
|
var props = Entities.getEntityProperties(id, ["name"]);
|
||||||
|
if (props.name.toLowerCase().indexOf("avimoji") > -1) {
|
||||||
|
Entities.deleteEntity(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
// *************************************
|
// *************************************
|
||||||
// END ui_handlers
|
// END ui_handlers
|
||||||
|
@ -179,7 +187,13 @@ function onScaleChanged() {
|
||||||
|
|
||||||
|
|
||||||
// what happens when we need to add an emoji over a user
|
// what happens when we need to add an emoji over a user
|
||||||
|
var firstEmojiMadeOnStartup = false;
|
||||||
function addEmoji(emojiFilename) {
|
function addEmoji(emojiFilename) {
|
||||||
|
if (!firstEmojiMadeOnStartup) {
|
||||||
|
firstEmojiMadeOnStartup = true;
|
||||||
|
Entities.addingWearable.disconnect(onAddingWearable);
|
||||||
|
}
|
||||||
|
|
||||||
if (currentEmoji) {
|
if (currentEmoji) {
|
||||||
resetEmojis();
|
resetEmojis();
|
||||||
}
|
}
|
||||||
|
@ -418,6 +432,7 @@ function startup() {
|
||||||
Script.scriptEnding.connect(unload);
|
Script.scriptEnding.connect(unload);
|
||||||
Window.domainChanged.connect(onDomainChanged);
|
Window.domainChanged.connect(onDomainChanged);
|
||||||
MyAvatar.scaleChanged.connect(onScaleChanged);
|
MyAvatar.scaleChanged.connect(onScaleChanged);
|
||||||
|
Entities.addingWearable.connect(onAddingWearable);
|
||||||
signalsConnected = true;
|
signalsConnected = true;
|
||||||
|
|
||||||
function AviMoji() {
|
function AviMoji() {
|
||||||
|
@ -457,6 +472,10 @@ function unload() {
|
||||||
if (signalsConnected) {
|
if (signalsConnected) {
|
||||||
Window.domainChanged.disconnect(onDomainChanged);
|
Window.domainChanged.disconnect(onDomainChanged);
|
||||||
MyAvatar.scaleChanged.disconnect(onScaleChanged);
|
MyAvatar.scaleChanged.disconnect(onScaleChanged);
|
||||||
|
if (!firstEmojiMadeOnStartup) {
|
||||||
|
Entities.addingWearable.disconnect(onAddingWearable);
|
||||||
|
}
|
||||||
|
|
||||||
signalsConnected = false;
|
signalsConnected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,7 +543,7 @@ function onDisplayModeChanged(isHMDMode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var emojiAPI = Script.require("./emojiApp/simplifiedEmoji.js");
|
var emojiAPI = Script.require("./emojiApp/simplifiedEmoji.js?" + Date.now());
|
||||||
var keyPressSignalsConnected = false;
|
var keyPressSignalsConnected = false;
|
||||||
var emojiCodeMap;
|
var emojiCodeMap;
|
||||||
var customEmojiCodeMap;
|
var customEmojiCodeMap;
|
||||||
|
|
|
@ -584,7 +584,7 @@ function restoreLODSettings() {
|
||||||
|
|
||||||
|
|
||||||
var nametag = Script.require("./simplifiedNametag/simplifiedNametag.js?" + Date.now());
|
var nametag = Script.require("./simplifiedNametag/simplifiedNametag.js?" + Date.now());
|
||||||
var si = Script.require("./simplifiedStatusIndicator/simplifiedStatusIndicator.js?" + Date.now())
|
var si = Script.require("./simplifiedStatusIndicator/simplifiedStatusIndicator.js?" + Date.now());
|
||||||
var emote = Script.require("../simplifiedEmote/simplifiedEmote.js?" + Date.now());
|
var emote = Script.require("../simplifiedEmote/simplifiedEmote.js?" + Date.now());
|
||||||
var oldShowAudioTools;
|
var oldShowAudioTools;
|
||||||
var oldShowBubbleTools;
|
var oldShowBubbleTools;
|
||||||
|
|
Loading…
Reference in a new issue