Merge branch 'master' into tweak_sit_pose

This commit is contained in:
dooglife@gmail.com 2019-08-23 14:21:09 -07:00
commit e8492beb4a
24 changed files with 468 additions and 268 deletions

View file

@ -186,15 +186,6 @@ Rectangle {
backgroundOnColor: "#E3E3E3";
checked: muted;
onClicked: {
if (pushToTalk && !checked) {
// disable push to talk if unmuting
if (bar.currentIndex === 0) {
AudioScriptingInterface.pushToTalkDesktop = false;
}
else {
AudioScriptingInterface.pushToTalkHMD = false;
}
}
if (bar.currentIndex === 0) {
AudioScriptingInterface.mutedDesktop = checked;
}

View file

@ -5863,8 +5863,13 @@ bool MyAvatar::endReaction(QString reactionName) {
int reactionIndex = beginEndReactionNameToIndex(reactionName);
if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_BEGIN_END_REACTIONS) {
std::lock_guard<std::mutex> guard(_reactionLock);
_reactionEnabledRefCounts[reactionIndex]--;
return true;
if (_reactionEnabledRefCounts[reactionIndex] > 0) {
_reactionEnabledRefCounts[reactionIndex]--;
return true;
} else {
_reactionEnabledRefCounts[reactionIndex] = 0;
return false;
}
}
return false;
}

View file

@ -101,6 +101,10 @@ void Audio::setMutedDesktop(bool isMuted) {
}
}
});
if (!isMuted && _settingsLoaded) {
// Disable Push-To-Talk if muted is changed to false. Settings also need to be loaded.
setPTTDesktop(isMuted);
}
if (changed) {
if (!isHMD) {
emit mutedChanged(isMuted);
@ -128,6 +132,10 @@ void Audio::setMutedHMD(bool isMuted) {
}
}
});
if (!isMuted && _settingsLoaded) {
// Disable Push-To-Talk if muted is changed to false. Settings also need to be loaded.
setPTTHMD(isMuted);
}
if (changed) {
if (isHMD) {
emit mutedChanged(isMuted);
@ -187,9 +195,9 @@ void Audio::setPTTDesktop(bool enabled) {
_pttDesktop = enabled;
}
});
if (enabled || _settingsLoaded) {
if (enabled && _settingsLoaded) {
// Set to default behavior (muted for Desktop) on Push-To-Talk disable or when enabled. Settings also need to be loaded.
setMutedDesktop(true);
setMutedDesktop(enabled);
}
if (changed) {
emit pushToTalkChanged(enabled);
@ -211,7 +219,7 @@ void Audio::setPTTHMD(bool enabled) {
_pttHMD = enabled;
}
});
if (enabled || _settingsLoaded) {
if (enabled && _settingsLoaded) {
// Set to default behavior (unmuted for HMD) on Push-To-Talk disable or muted for when PTT is enabled.
setMutedHMD(enabled);
}

View file

@ -22,7 +22,10 @@
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
CGFloat prog = (float)totalBytesWritten/totalBytesExpectedToWrite;
NSLog(@"interface downloaded %d%%", (int)(100.0*prog));
if ((int)(100.0 * prog) != (int)self.progressPercentage) {
NSLog(@"interface downloaded %d%%", (int)(100.0*prog));
}
self.progressPercentage = (100.0 * prog);
[[Launcher sharedLauncher] updateProgressIndicator];

View file

@ -1,31 +1,20 @@
#import "LatestBuildRequest.h"
#import "Launcher.h"
#import "Settings.h"
#import "Interface.h"
@implementation LatestBuildRequest
- (NSInteger) getCurrentVersion {
NSInteger currentVersion;
@try {
NSString* interfaceAppPath = [[Launcher.sharedLauncher getAppPath] stringByAppendingString:@"interface.app"];
NSError* error = nil;
Interface* interface = [[Interface alloc] initWith:interfaceAppPath];
currentVersion = [interface getVersion:&error];
if (currentVersion == 0 && error != nil) {
NSLog(@"can't get version from interface, falling back to settings: %@", error);
currentVersion = [Settings.sharedSettings latestBuildVersion];
}
} @catch (NSException *exception) {
NSLog(@"an exception was thrown: %@", exception);
currentVersion = [Settings.sharedSettings latestBuildVersion];
}
return currentVersion;
}
- (void) requestLatestBuildInfo {
NSString* buildsURL = [[[NSProcessInfo processInfo] environment] objectForKey:@"HQ_LAUNCHER_BUILDS_URL"];
if ([buildsURL length] == 0) {
buildsURL = @"https://thunder.highfidelity.com/builds/api/tags/latest?format=json";
}
NSLog(@"Making request for builds to: %@", buildsURL);
NSMutableURLRequest* request = [NSMutableURLRequest new];
[request setURL:[NSURL URLWithString:@"https://thunder.highfidelity.com/builds/api/tags/latest?format=json"]];
[request setURL:[NSURL URLWithString:buildsURL]];
[request setHTTPMethod:@"GET"];
[request setValue:@USER_AGENT_STRING forHTTPHeaderField:@"User-Agent"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
@ -39,7 +28,7 @@
NSLog(@"Latest Build Request Response: %ld", [ne statusCode]);
Launcher* sharedLauncher = [Launcher sharedLauncher];
if ([ne statusCode] == 500) {
if (error || [ne statusCode] == 500) {
dispatch_async(dispatch_get_main_queue(), ^{
[sharedLauncher displayErrorPage];
});
@ -60,36 +49,26 @@
NSFileManager* fileManager = [NSFileManager defaultManager];
NSArray* values = [json valueForKey:@"results"];
NSDictionary* launcherValues = [json valueForKey:@"launcher"];
NSDictionary* value = [values objectAtIndex:0];
NSString* defaultBuildTag = [json valueForKey:@"default_tag"];
NSString* launcherVersion = [launcherValues valueForKey:@"version"];
NSString* launcherUrl = [[launcherValues valueForKey:@"mac"] valueForKey:@"url"];
NSString* buildNumber = [value valueForKey:@"latest_version"];
NSDictionary* installers = [value objectForKey:@"installers"];
NSDictionary* macInstallerObject = [installers objectForKey:@"mac"];
NSString* macInstallerUrl = [macInstallerObject valueForKey:@"zip_url"];
BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]];
dispatch_async(dispatch_get_main_queue(), ^{
NSInteger currentVersion = [self getCurrentVersion];
NSInteger currentLauncherVersion = atoi(LAUNCHER_BUILD_VERSION);
NSLog(@"Latest Build Request -> current launcher version %ld", currentLauncherVersion);
NSLog(@"Latest Build Request -> latest launcher version %ld", launcherVersion.integerValue);
NSLog(@"Latest Build Request -> launcher url %@", launcherUrl);
NSLog(@"Latest Build Request -> does build directory exist: %@", appDirectoryExist ? @"TRUE" : @"FALSE");
NSLog(@"Latest Build Request -> current version: %ld", currentVersion);
NSLog(@"Latest Build Request -> latest version: %ld", buildNumber.integerValue);
NSLog(@"Latest Build Request -> mac url: %@", macInstallerUrl);
BOOL latestVersionAvailable = (currentVersion != buildNumber.integerValue);
BOOL latestLauncherVersionAvailable = (currentLauncherVersion != launcherVersion.integerValue);
[[Settings sharedSettings] buildVersion:buildNumber.integerValue];
BOOL shouldDownloadInterface = (latestVersionAvailable || !appDirectoryExist);
NSLog(@"Latest Build Request -> SHOULD DOWNLOAD: %@", shouldDownloadInterface ? @"TRUE" : @"FALSE");
[sharedLauncher shouldDownloadLatestBuild:shouldDownloadInterface :macInstallerUrl
:latestLauncherVersionAvailable :launcherUrl];
[sharedLauncher shouldDownloadLatestBuild:values
:defaultBuildTag
:latestLauncherVersionAvailable
:launcherUrl];
});
}];

View file

@ -55,6 +55,8 @@ struct LatestBuildInfo {
@property (nonatomic) BOOL waitingForInterfaceToTerminate;
@property (nonatomic) BOOL shouldDownloadInterface;
@property (nonatomic) BOOL latestBuildRequestFinished;
@property (nonatomic, assign) NSArray* latestBuilds;
@property (nonatomic, assign) NSString* defaultBuildTag;
@property (nonatomic, assign) NSTimer* updateProgressIndicatorTimer;
@property (nonatomic, assign, readwrite) ProcessState processState;
@property (nonatomic, assign, readwrite) LoginError loginError;
@ -70,6 +72,7 @@ struct LatestBuildInfo {
- (void) domainContentDownloadFinished;
- (void) domainScriptsDownloadFinished;
- (void) setDomainURLInfo:(NSString*) aDomainURL :(NSString*) aDomainContentUrl :(NSString*) aDomainScriptsUrl;
- (void) setOrganizationBuildTag:(NSString*) organizationBuildTag;
- (void) organizationRequestFinished:(BOOL) aOriginzationAccepted;
- (BOOL) loginShouldSetErrorState;
- (void) displayErrorPage;
@ -81,7 +84,9 @@ struct LatestBuildInfo {
- (void) setCurrentProcessState:(ProcessState) aProcessState;
- (void) setLoginErrorState:(LoginError) aLoginError;
- (LoginError) getLoginErrorState;
- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl :(BOOL) newLauncherAvailable :(NSString*) launcherUrl;
- (void) updateLatestBuildInfo;
- (void) shouldDownloadLatestBuild:(NSArray*) latestBuilds :(NSString*) defaultBuildTag :(BOOL) newLauncherAvailable :(NSString*) launcherUrl;
- (void) tryDownloadLatestBuild:(BOOL)progressScreenAlreadyDisplayed;
- (void) interfaceFinishedDownloading;
- (NSString*) getDownloadPathForContentAndScripts;
- (void) launchInterface;
@ -97,11 +102,9 @@ struct LatestBuildInfo {
- (NSString*) getDownloadFilename;
- (void) startUpdateProgressIndicatorTimer;
- (void) endUpdateProgressIndicatorTimer;
- (BOOL) isLoadedIn;
- (BOOL) isLoggedIn;
- (NSString*) getAppPath;
- (void) updateProgressIndicator;
- (void) setLatestBuildInfo:(struct LatestBuildInfo) latestBuildInfo;
- (struct LatestBuildInfo) getLatestBuildInfo;
+ (id) sharedLauncher;
@end

View file

@ -8,6 +8,7 @@
#import "ErrorViewController.h"
#import "Settings.h"
#import "NSTask+NSTaskExecveAdditions.h"
#import "Interface.h"
@interface Launcher ()
@ -241,7 +242,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
return self.waitingForInterfaceToTerminate;
}
- (BOOL) isLoadedIn
- (BOOL) isLoggedIn
{
return [[Settings sharedSettings] isLoggedIn];
}
@ -255,6 +256,11 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
[[Settings sharedSettings] setDomainUrl:aDomainURL];
}
- (void) setOrganizationBuildTag:(NSString*) organizationBuildTag;
{
[[Settings sharedSettings] setOrganizationBuildTag:organizationBuildTag];
}
- (NSString*) getAppPath
{
return [self getDownloadPathForContentAndScripts];
@ -275,13 +281,26 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
self.displayName = aDiplayName;
}
- (NSInteger) getCurrentVersion {
NSInteger currentVersion;
@try {
NSString* interfaceAppPath = [[self getAppPath] stringByAppendingString:@"interface.app"];
NSError* error = nil;
Interface* interface = [[Interface alloc] initWith:interfaceAppPath];
currentVersion = [interface getVersion:&error];
if (currentVersion == 0 && error != nil) {
NSLog(@"can't get version from interface: %@", error);
}
} @catch (NSException *exception) {
NSLog(@"an exception was thrown while getting current interface version: %@", exception);
currentVersion = 0;
}
return currentVersion;
}
- (void) domainContentDownloadFinished
{
if (self.shouldDownloadInterface) {
[self.downloadInterface downloadInterface: self.interfaceDownloadUrl];
return;
}
[self interfaceFinishedDownloading];
[self tryDownloadLatestBuild:TRUE];
}
- (void) domainScriptsDownloadFinished
@ -337,6 +356,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
{
self.credentialsAccepted = aOriginzationAccepted;
if (aOriginzationAccepted) {
[self updateLatestBuildInfo];
[self.credentialsRequest confirmCredentials:self.username : self.password];
} else {
LoginScreen* loginScreen = [[LoginScreen alloc] initWithNibName:@"LoginScreen" bundle:nil];
@ -349,42 +369,26 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
return YES;
}
- (struct LatestBuildInfo) getLatestBuildInfo
{
return self.buildInfo;
}
- (void) setLatestBuildInfo:(struct LatestBuildInfo) latestBuildInfo
{
self.buildInfo = latestBuildInfo;
}
-(void) showLoginScreen
{
LoginScreen* loginScreen = [[LoginScreen alloc] initWithNibName:@"LoginScreen" bundle:nil];
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: loginScreen];
}
- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl :(BOOL) newLauncherAvailable :(NSString*) launcherUrl
- (void) shouldDownloadLatestBuild:(NSArray*) latestBuilds :(NSString*) defaultBuildTag :(BOOL) newLauncherAvailable :(NSString*) launcherUrl
{
self.latestBuilds = [[NSArray alloc] initWithArray:latestBuilds copyItems:true];
self.defaultBuildTag = defaultBuildTag;
[self updateLatestBuildInfo];
NSDictionary* launcherArguments = [LauncherCommandlineArgs arguments];
if (newLauncherAvailable && ![launcherArguments valueForKey: @"--noUpdate"]) {
[self.downloadLauncher downloadLauncher: launcherUrl];
} else {
self.shouldDownloadInterface = shouldDownload;
self.interfaceDownloadUrl = downloadUrl;
self.latestBuildRequestFinished = TRUE;
if ([self isLoadedIn]) {
Launcher* sharedLauncher = [Launcher sharedLauncher];
[sharedLauncher setCurrentProcessState:CHECKING_UPDATE];
if (shouldDownload) {
ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil];
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen];
[self startUpdateProgressIndicatorTimer];
[self.downloadInterface downloadInterface: downloadUrl];
return;
}
[self interfaceFinishedDownloading];
if ([self isLoggedIn]) {
[self tryDownloadLatestBuild:FALSE];
} else {
[[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE];
[self showLoginScreen];
@ -392,6 +396,67 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
}
}
// The latest builds are always retrieved on application start because they contain not only
// the latest interface builds, but also the latest launcher builds, which are required to know if
// we need to self-update first. The interface builds are categorized by build tag, and we may
// not know at application start which build tag we should be using. There are 2 scenarios where
// we call this function to determine our build tag and the correct build:
//
// 1. If we are logged in, we will have our build tag and can immediately get the correct build
// after receiving the builds.
// 2. If we are not logged in, we need to wait until we have logged in and received the org
// metadata for the user. The latest build info also needs to be updated _before_ downloading
// the content set cache because the progress bar value depends on it.
//
- (void) updateLatestBuildInfo {
NSLog(@"Updating latest build info");
NSInteger currentVersion = [self getCurrentVersion];
NSInteger latestVersion = 0;
Launcher* sharedLauncher = [Launcher sharedLauncher];
[sharedLauncher setCurrentProcessState:CHECKING_UPDATE];
BOOL newVersionAvailable = false;
NSString* url = @"";
NSString* buildTag = [[Settings sharedSettings] organizationBuildTag];
if ([buildTag length] == 0) {
buildTag = self.defaultBuildTag;
}
for (NSDictionary* build in self.latestBuilds) {
NSString* name = [build valueForKey:@"name"];
NSLog(@"Checking %@", name);
if ([name isEqual:buildTag]) {
url = [[[build objectForKey:@"installers"] objectForKey:@"mac"] valueForKey:@"zip_url"];
NSString* thisLatestVersion = [build valueForKey:@"latest_version"];
latestVersion = thisLatestVersion.integerValue;
newVersionAvailable = currentVersion != latestVersion;
NSLog(@"Using %@, %ld", name, latestVersion);
break;
}
}
self.shouldDownloadInterface = newVersionAvailable;
self.interfaceDownloadUrl = url;
NSLog(@"Updating latest build info, currentVersion=%ld, latestVersion=%ld, %@ %@",
currentVersion, latestVersion, (self.shouldDownloadInterface ? @"Yes" : @"No"), self.interfaceDownloadUrl);
}
- (void) tryDownloadLatestBuild:(BOOL)progressScreenAlreadyDisplayed
{
if (self.shouldDownloadInterface) {
if (!progressScreenAlreadyDisplayed) {
ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil];
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen];
[self startUpdateProgressIndicatorTimer];
}
[self.downloadInterface downloadInterface: self.interfaceDownloadUrl];
return;
}
[self interfaceFinishedDownloading];
}
-(void)runAutoupdater
{
NSTask* task = [[NSTask alloc] init];

View file

@ -2,6 +2,7 @@
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonHMAC.h>
#import "Launcher.h"
#import "Settings.h"
static NSString* const organizationURL = @"https://orgs.highfidelity.com/organizations/";
@ -76,11 +77,16 @@ static NSString* const organizationURL = @"https://orgs.highfidelity.com/organiz
}
NSString* domainURL = [json valueForKey:@"domain"];
NSString* contentSetURL = [json valueForKey:@"content_set_url"];
NSString* buildTag = [json valueForKey:@"build_tag"];
if (buildTag == nil) {
buildTag = @"";
}
if (domainURL != nil && contentSetURL != nil) {
NSLog(@"Organization: getting org file successful");
[sharedLauncher setDomainURLInfo:[json valueForKey:@"domain"] :[json valueForKey:@"content_set_url"] :nil];
[sharedLauncher setLoginErrorState: NONE];
[[Settings sharedSettings] setOrganizationBuildTag:buildTag];
[sharedLauncher organizationRequestFinished:TRUE];
} else {
NSLog(@"Organization: Either domainURL: %@ or contentSetURL: %@ json entries are invalid", domainURL, contentSetURL);

View file

@ -7,6 +7,7 @@
@property (nonatomic, assign) BOOL loggedIn;
@property (nonatomic, assign) NSString* domain;
@property (nonatomic, assign) NSString* launcher;
@property (nonatomic, assign) NSString* _organizationBuildTag;
- (NSInteger) latestBuildVersion;
- (BOOL) isLoggedIn;
- (void) login:(BOOL)aLoggedIn;
@ -15,6 +16,8 @@
- (NSString*) getLaucnherPath;
- (void) setDomainUrl:(NSString*) aDomainUrl;
- (NSString*) getDomainUrl;
- (void) setOrganizationBuildTag:(NSString*) aOrganizationBuildTag;
- (NSString*) organizationBuildTag;
- (void) save;
+ (id) sharedSettings;
@end

View file

@ -32,13 +32,18 @@
NSError * err;
NSData *data =[jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary * json;
if(data!=nil){
if (data != nil) {
json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
self.loggedIn = [[json valueForKey:@"loggedIn"] boolValue];
self.build = [[json valueForKey:@"build_version"] integerValue];
self.launcher = [json valueForKey:@"luancherPath"];
self.domain = [json valueForKey:@"domain"];
self.organizationBuildTag = [json valueForKey:@"organizationBuildTag"];
if ([self.organizationBuildTag length] == 0) {
self.organizationBuildTag = @"";
}
return;
}
}
@ -53,7 +58,9 @@
[NSString stringWithFormat:@"%ld", self.build], @"build_version",
self.loggedIn ? @"TRUE" : @"FALSE", @"loggedIn",
self.domain, @"domain",
self.launcher, @"launcherPath", nil];
self.launcher, @"launcherPath",
self.organizationBuildTag, @"organizationBuildTag",
nil];
NSError * err;
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:json options:0 error:&err];
NSString * jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
@ -114,6 +121,16 @@
return self.domain;
}
- (void) setOrganizationBuildTag:(NSString*) aOrganizationBuildTag
{
self._organizationBuildTag = aOrganizationBuildTag;
}
- (NSString*) organizationBuildTag
{
return self._organizationBuildTag;
}
- (NSString*) getLaucnherPath
{
return self.launcher;

View file

@ -36,6 +36,7 @@ void LauncherManager::init(BOOL allowUpdate, ContinueActionOnStart continueActio
}
addToLog(_T("Launcher is running version: " + _launcherVersion));
addToLog(_T("Getting most recent builds"));
_isInstalled = isApplicationInstalled(_currentVersion, _domainURL, _contentURL, _loggedIn, _organizationBuildTag);
getMostRecentBuilds(_latestLauncherURL, _latestLauncherVersion, _latestApplicationURL, _latestVersion);
}
@ -260,14 +261,14 @@ BOOL LauncherManager::deleteShortcuts() {
}
BOOL LauncherManager::isApplicationInstalled(CString& version, CString& domain,
CString& content, bool& loggedIn) {
CString& content, bool& loggedIn, CString& organizationBuildTag) {
CString applicationDir;
getAndCreatePaths(PathType::Launcher_Directory, applicationDir);
CString applicationPath = applicationDir + "interface\\interface.exe";
BOOL isInstalled = PathFileExistsW(applicationPath);
BOOL configFileExist = PathFileExistsW(applicationDir + _T("interface\\config.json"));
if (configFileExist) {
LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn);
LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn, organizationBuildTag);
return isInstalled && status == LauncherUtils::ResponseError::NoError;
}
return FALSE;
@ -326,7 +327,6 @@ BOOL LauncherManager::getInstalledVersion(const CString& path, CString& version)
return success;
}
HWND LauncherManager::launchApplication() {
CString installDir;
LauncherManager::getAndCreatePaths(PathType::Interface_Directory, installDir);
@ -368,6 +368,7 @@ BOOL LauncherManager::createConfigJSON() {
config["launcherPath"] = LauncherUtils::cStringToStd(applicationPath);
config["version"] = LauncherUtils::cStringToStd(_latestVersion);
config["domain"] = LauncherUtils::cStringToStd(_domainURL);
config["organizationBuildTag"] = LauncherUtils::cStringToStd(_organizationBuildTag);
CString content;
getAndCreatePaths(PathType::Content_Directory, content);
config["content"] = LauncherUtils::cStringToStd(content);
@ -377,7 +378,7 @@ BOOL LauncherManager::createConfigJSON() {
}
LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain,
CString& content, bool& loggedIn) {
CString& content, bool& loggedIn, CString& organizationBuildTag) {
CString configPath;
getAndCreatePaths(PathType::Interface_Directory, configPath);
configPath += "\\config.json";
@ -394,6 +395,13 @@ LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, C
version = config["version"].asCString();
domain = config["domain"].asCString();
content = config["content"].asCString();
if (config["organizationBuildTag"].isString()) {
organizationBuildTag = config["organizationBuildTag"].asCString();
} else {
organizationBuildTag = "";
}
configFile.close();
return LauncherUtils::ResponseError::NoError;
}
@ -401,12 +409,43 @@ LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, C
return LauncherUtils::ResponseError::ParsingJSON;
}
bool findBuildInResponse(const Json::Value& json, const CString& tag, CString& interfaceUrlOut, CString& interfaceVersionOut) {
if (json["results"].isArray()) {
auto& results = json["results"];
int count = results.size();
for (int i = 0; i < count; i++) {
if (results[i].isObject()) {
Json::Value result = results[i];
if (result["name"].asCString() == tag) {
if (result["latest_version"].isInt()) {
std::string version = std::to_string(result["latest_version"].asInt());
interfaceVersionOut = CString(version.c_str());
} else {
return false;
}
if (result["installers"].isObject() &&
result["installers"]["windows"].isObject() &&
result["installers"]["windows"]["zip_url"].isString()) {
interfaceUrlOut = result["installers"]["windows"]["zip_url"].asCString();
} else {
return false;
}
return true;
}
}
}
}
return false;
}
LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString& hash) {
CString contentTypeJson = L"content-type:application/json";
CString response;
CString url = _T("/organizations/") + hash + _T(".json");
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(getHttpUserAgent(),
L"orgs.highfidelity.com", url,
true, L"orgs.highfidelity.com", url,
contentTypeJson, CStringA(),
response, false);
if (error != LauncherUtils::ResponseError::NoError) {
@ -417,6 +456,13 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString
if (json["content_set_url"].isString() && json["domain"].isString()) {
_contentURL = json["content_set_url"].asCString();
_domainURL = json["domain"].asCString();
_organizationBuildTag = json.get("build_tag", "").asCString();
auto buildTag = _organizationBuildTag.IsEmpty() ? _defaultBuildTag : _organizationBuildTag;
if (!findBuildInResponse(_latestBuilds, buildTag, _latestApplicationURL, _latestVersion)) {
return LauncherUtils::ResponseError::ParsingJSON;
}
return LauncherUtils::ResponseError::NoError;
}
}
@ -429,8 +475,12 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun
std::function<void(CString, int)> httpCallback = [&](CString response, int err) {
LauncherUtils::ResponseError error = LauncherUtils::ResponseError(err);
if (error == LauncherUtils::ResponseError::NoError) {
Json::Value json;
Json::Value& json = _latestBuilds;
if (LauncherUtils::parseJSON(response, json)) {
_defaultBuildTag = json.get("default_tag", "").asCString();
auto buildTag = _organizationBuildTag.IsEmpty() ? _defaultBuildTag : _organizationBuildTag;
addToLog(_T("Build tag is: ") + buildTag);
if (json["launcher"].isObject()) {
if (json["launcher"]["windows"].isObject() && json["launcher"]["windows"]["url"].isString()) {
launcherUrlOut = json["launcher"]["windows"]["url"].asCString();
@ -440,41 +490,50 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun
launcherVersionOut = CString(version.c_str());
}
}
int count = json["count"].isInt() ? json["count"].asInt() : 0;
if (count > 0 && json["results"].isArray()) {
for (int i = 0; i < count; i++) {
if (json["results"][i].isObject()) {
Json::Value result = json["results"][i];
if (result["latest_version"].isInt()) {
std::string version = std::to_string(result["latest_version"].asInt());
interfaceVersionOut = CString(version.c_str());
}
if (result["installers"].isObject() &&
result["installers"]["windows"].isObject() &&
result["installers"]["windows"]["zip_url"].isString()) {
interfaceUrlOut = result["installers"]["windows"]["zip_url"].asCString();
}
}
}
if (launcherUrlOut.IsEmpty() || launcherVersionOut.IsEmpty()) {
error = LauncherUtils::ResponseError::ParsingJSON;
}
if (launcherUrlOut.IsEmpty() || launcherVersionOut.IsEmpty() || interfaceUrlOut.IsEmpty() || interfaceVersionOut.IsEmpty()) {
if (!findBuildInResponse(json, buildTag, _latestApplicationURL, _latestVersion)) {
addToLog(_T("Failed to find build"));
error = LauncherUtils::ResponseError::ParsingJSON;
}
}
}
onMostRecentBuildsReceived(response, error);
};
bool useHTTPS{ true };
CString domainName;
if (domainName.GetEnvironmentVariable(L"HQ_LAUNCHER_BUILDS_DOMAIN")) {
addToLog(_T("Using overridden builds domain: ") + domainName);
useHTTPS = false;
} else {
domainName = L"thunder.highfidelity.com";
}
CString pathName;
if (pathName.GetEnvironmentVariable(L"HQ_LAUNCHER_BUILDS_PATH")) {
addToLog(_T("Using overridden builds path: ") + pathName);
useHTTPS = false;
} else {
pathName = L"/builds/api/tags/latest?format=json";
}
LauncherUtils::httpCallOnThread(getHttpUserAgent(),
L"thunder.highfidelity.com",
L"/builds/api/tags/latest?format=json",
useHTTPS,
domainName,
pathName,
contentTypeJson, CStringA(), false, httpCallback);
}
void LauncherManager::onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error) {
if (error == LauncherUtils::ResponseError::NoError) {
addToLog(_T("Latest launcher version: ") + _latestLauncherVersion);
CString currentVersion;
BOOL isInstalled = (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn);
CString currentVersion = _currentVersion;
BOOL isInstalled = _isInstalled && _loggedIn;
bool newInterfaceVersion = _latestVersion.Compare(currentVersion) != 0;
bool newLauncherVersion = _latestLauncherVersion.Compare(_launcherVersion) != 0 && _updateLauncherAllowed;
if (newLauncherVersion) {
@ -511,7 +570,7 @@ void LauncherManager::onMostRecentBuildsReceived(const CString& response, Launch
_shouldWait = FALSE;
} else {
_hasFailed = true;
setFailed(true);
CString msg;
msg.Format(_T("Getting most recent builds has failed with error: %d"), error);
addToLog(msg);
@ -531,6 +590,7 @@ LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const
CString contentTypeText = L"content-type:application/x-www-form-urlencoded";
CString response;
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(getHttpUserAgent(),
true,
L"metaverse.highfidelity.com",
L"/oauth/token",
contentTypeText, post,
@ -611,7 +671,7 @@ BOOL LauncherManager::extractApplication() {
onZipExtracted((ProcessType)type, size);
} else {
addToLog(_T("Error decompressing application zip file."));
_hasFailed = true;
setFailed(true);
}
};
std::function<void(float)> onProgress = [&](float progress) {
@ -688,7 +748,7 @@ BOOL LauncherManager::installContent() {
}
else {
addToLog(_T("Error decompressing content zip file."));
_hasFailed = true;
setFailed(true);
}
};
std::function<void(float)> onProgress = [&](float progress) {
@ -728,7 +788,7 @@ BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString
} else {
addToLog(_T("Error downloading application."));
}
_hasFailed = true;
setFailed(true);
}
};
std::function<void(float)> onProgress = [&, type](float progress) {

View file

@ -76,7 +76,7 @@ public:
BOOL getAndCreatePaths(PathType type, CString& outPath);
BOOL getInstalledVersion(const CString& path, CString& version);
BOOL isApplicationInstalled(CString& version, CString& domain,
CString& content, bool& loggedIn);
CString& content, bool& loggedIn, CString& organizationBuildTag);
LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password);
void getMostRecentBuilds(CString& launcherUrlOut,
CString& launcherVersionOut,
@ -84,7 +84,7 @@ public:
CString& interfaceVersionOut);
LauncherUtils::ResponseError readOrganizationJSON(const CString& hash);
LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain,
CString& content, bool& loggedIn);
CString& content, bool& loggedIn, CString& organizationBuildTag);
BOOL createConfigJSON();
BOOL createApplicationRegistryKeys(int size);
BOOL deleteApplicationRegistryKeys();
@ -139,10 +139,12 @@ public:
private:
ProcessType _currentProcess { ProcessType::DownloadApplication };
void onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error);
CString _latestApplicationURL;
CString _latestVersion;
CString _latestLauncherURL;
CString _latestLauncherVersion;
CString _contentURL;
CString _domainURL;
CString _version;
@ -152,6 +154,8 @@ private:
CString _contentZipPath;
CString _launcherVersion;
CString _tempLauncherPath;
CString _currentVersion;
bool _isInstalled{ false };
bool _loggedIn { false };
bool _hasFailed { false };
BOOL _shouldUpdate { FALSE };
@ -171,4 +175,7 @@ private:
float _progressOffset { 0.0f };
float _progress { 0.0f };
CStdioFile _logFile;
Json::Value _latestBuilds;
CString _defaultBuildTag;
CString _organizationBuildTag;
};

View file

@ -181,7 +181,7 @@ BOOL LauncherUtils::deleteRegistryKey(const CString& registryPath) {
}
LauncherUtils::ResponseError LauncherUtils::makeHTTPCall(const CString& callerName,
const CString& mainUrl, const CString& dirUrl,
bool useHTTPS, const CString& mainUrl, const CString& dirUrl,
const CString& contentType, CStringA& postData,
CString& response, bool isPost = false) {
@ -190,12 +190,12 @@ LauncherUtils::ResponseError LauncherUtils::makeHTTPCall(const CString& callerNa
if (!hopen) {
return ResponseError::Open;
}
HINTERNET hconnect = WinHttpConnect(hopen, mainUrl, INTERNET_DEFAULT_HTTPS_PORT, 0);
HINTERNET hconnect = WinHttpConnect(hopen, mainUrl, useHTTPS ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0);
if (!hconnect) {
return ResponseError::Connect;
}
HINTERNET hrequest = WinHttpOpenRequest(hconnect, isPost ? L"POST" : L"GET", dirUrl,
NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, useHTTPS ? WINHTTP_FLAG_SECURE : 0);
if (!hrequest) {
return ResponseError::OpenRequest;
}
@ -497,7 +497,7 @@ DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) {
DWORD WINAPI LauncherUtils::httpThread(LPVOID lpParameter) {
HttpThreadData& data = *((HttpThreadData*)lpParameter);
CString response;
auto error = LauncherUtils::makeHTTPCall(data._callerName, data._mainUrl, data._dirUrl,
auto error = LauncherUtils::makeHTTPCall(data._callerName, data._useHTTPS, data._mainUrl, data._dirUrl,
data._contentType, data._postData, response, data._isPost);
data._callback(response, error);
return 0;
@ -552,12 +552,13 @@ BOOL LauncherUtils::deleteDirectoryOnThread(const CString& dirPath, std::functio
return FALSE;
}
BOOL LauncherUtils::httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl,
BOOL LauncherUtils::httpCallOnThread(const CString& callerName, bool useHTTPS, const CString& mainUrl, const CString& dirUrl,
const CString& contentType, CStringA& postData, bool isPost,
std::function<void(CString, int)> callback) {
DWORD myThreadID;
HttpThreadData* httpThreadData = new HttpThreadData();
httpThreadData->_callerName = callerName;
httpThreadData->_useHTTPS = useHTTPS;
httpThreadData->_mainUrl = mainUrl;
httpThreadData->_dirUrl = dirUrl;
httpThreadData->_contentType = contentType;

View file

@ -120,6 +120,7 @@ public:
struct HttpThreadData {
CString _callerName;
bool _useHTTPS;
CString _mainUrl;
CString _dirUrl;
CString _contentType;
@ -137,7 +138,7 @@ public:
};
static BOOL parseJSON(const CString& jsonTxt, Json::Value& jsonObject);
static ResponseError makeHTTPCall(const CString& callerName, const CString& mainUrl,
static ResponseError makeHTTPCall(const CString& callerName, bool useHTTPS, const CString& mainUrl,
const CString& dirUrl, const CString& contentType,
CStringA& postData, CString& response, bool isPost);
static std::string cStringToStd(CString cstring);
@ -163,7 +164,7 @@ public:
std::function<void(int, bool)> callback,
std::function<void(float)> progressCallback);
static BOOL deleteDirectoryOnThread(const CString& dirPath, std::function<void(bool)> callback);
static BOOL httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl,
static BOOL httpCallOnThread(const CString& callerName, bool useHTTPS, const CString& mainUrl, const CString& dirUrl,
const CString& contentType, CStringA& postData, bool isPost,
std::function<void(CString, int)> callback);

View file

@ -101,7 +101,7 @@ protected:
virtual void doRender(RenderArgs* args) = 0;
virtual bool isFading() const { return _isFading; }
void updateModelTransformAndBound();
virtual void updateModelTransformAndBound();
virtual bool isTransparent() const { return _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f : false; }
inline bool isValidRenderItem() const { return _renderItemID != Item::INVALID_ITEM_ID; }
@ -124,7 +124,6 @@ signals:
protected:
template<typename T>
std::shared_ptr<T> asTypedEntity() { return std::static_pointer_cast<T>(_entity); }
static void makeStatusGetters(const EntityItemPointer& entity, Item::Status::Getters& statusGetters);
const Transform& getModelTransform() const;
@ -153,7 +152,6 @@ protected:
quint64 _created;
private:
// The base class relies on comparing the model transform to the entity transform in order
// to trigger an update, so the member must not be visible to derived classes as a modifiable
// transform

View file

@ -41,23 +41,55 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
}
}
void PolyLineEntityRenderer::buildPipelines() {
// FIXME: opaque pipelines
void PolyLineEntityRenderer::updateModelTransformAndBound() {
bool success = false;
auto newModelTransform = _entity->getTransformToCenter(success);
if (success) {
_modelTransform = newModelTransform;
auto lineEntity = std::static_pointer_cast<PolyLineEntityItem>(_entity);
AABox bound;
lineEntity->computeTightLocalBoundingBox(bound);
bound.transform(newModelTransform);
_bound = bound;
}
}
bool PolyLineEntityRenderer::isTransparent() const {
return _glow || (_textureLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha());
}
void PolyLineEntityRenderer::buildPipelines() {
static const std::vector<std::pair<render::Args::RenderMethod, bool>> keys = {
{ render::Args::DEFERRED, false }, { render::Args::DEFERRED, true }, { render::Args::FORWARD, false }, { render::Args::FORWARD, true },
};
for (auto& key : keys) {
gpu::ShaderPointer program = gpu::Shader::createProgram(key.first == render::Args::DEFERRED ? shader::entities_renderer::program::paintStroke : shader::entities_renderer::program::paintStroke_forward);
gpu::ShaderPointer program;
render::Args::RenderMethod renderMethod = key.first;
bool transparent = key.second;
if (renderMethod == render::Args::DEFERRED) {
if (transparent) {
program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke_translucent);
} else {
program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke);
}
} else { // render::Args::FORWARD
program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke_forward);
}
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setCullMode(gpu::State::CullMode::CULL_NONE);
state->setDepthTest(true, !key.second, gpu::LESS_EQUAL);
PrepareStencil::testMask(*state);
state->setDepthTest(true, !transparent, gpu::LESS_EQUAL);
if (transparent) {
PrepareStencil::testMask(*state);
} else {
PrepareStencil::testMaskDrawShape(*state);
}
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
state->setBlendFunction(transparent, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_pipelines[key] = gpu::Pipeline::create(program, state);
@ -65,11 +97,16 @@ void PolyLineEntityRenderer::buildPipelines() {
}
ItemKey PolyLineEntityRenderer::getKey() {
return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
return isTransparent() ?
ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()) :
ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
}
ShapeKey PolyLineEntityRenderer::getShapeKey() {
auto builder = ShapeKey::Builder().withOwnPipeline().withTranslucent().withoutCullFace();
auto builder = ShapeKey::Builder().withOwnPipeline().withoutCullFace();
if (isTransparent()) {
builder.withTranslucent();
}
if (_primitiveMode == PrimitiveMode::LINES) {
builder.withWireframe();
}
@ -294,7 +331,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
buildPipelines();
}
batch.setPipeline(_pipelines[{args->_renderMethod, _glow}]);
batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);
batch.setModelTransform(transform);
batch.setResourceTexture(0, texture);
batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * numVertices), 0);

View file

@ -25,8 +25,9 @@ class PolyLineEntityRenderer : public TypedEntityRenderer<PolyLineEntityItem> {
public:
PolyLineEntityRenderer(const EntityItemPointer& entity);
// FIXME: shouldn't always be transparent: take into account texture and glow
virtual bool isTransparent() const override { return true; }
void updateModelTransformAndBound() override;
virtual bool isTransparent() const override;
protected:
virtual bool needsRenderUpdate() const override;

View file

@ -1 +1 @@
DEFINES forward
DEFINES translucent:f forward

View file

@ -34,7 +34,11 @@ void main(void) {
texel.a *= mix(1.0, pow(1.0 - min(1.0, abs(_distanceFromCenter)), 10.0), _polylineData.faceCameraGlow.y);
<@if not HIFI_USE_FORWARD@>
packDeferredFragmentTranslucent((2.0 * float(gl_FrontFacing) - 1.0) * _normalWS, texel.a, texel.rgb, DEFAULT_ROUGHNESS);
<@if HIFI_USE_TRANSLUCENT@>
packDeferredFragmentTranslucent((2.0 * float(gl_FrontFacing) - 1.0) * _normalWS, texel.a, texel.rgb, DEFAULT_ROUGHNESS);
<@else@>
packDeferredFragmentUnlit((2.0 * float(gl_FrontFacing) - 1.0) * _normalWS, texel.a, texel.rgb);
<@endif@>
<@else@>
_fragColor0 = texel;
<@endif@>

View file

@ -14,6 +14,7 @@
#include <QDebug>
#include <ByteCountCoding.h>
#include <Extents.h>
#include "EntitiesLogging.h"
#include "EntityItemProperties.h"
@ -85,7 +86,7 @@ void PolyLineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
_points = points;
_pointsChanged = true;
});
computeAndUpdateDimensionsAndPosition();
computeAndUpdateDimensions();
}
void PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths) {
@ -93,7 +94,7 @@ void PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths) {
_widths = strokeWidths;
_widthsChanged = true;
});
computeAndUpdateDimensionsAndPosition();
computeAndUpdateDimensions();
}
void PolyLineEntityItem::setNormals(const QVector<glm::vec3>& normals) {
@ -110,7 +111,7 @@ void PolyLineEntityItem::setStrokeColors(const QVector<glm::vec3>& strokeColors)
});
}
void PolyLineEntityItem::computeAndUpdateDimensionsAndPosition() {
void PolyLineEntityItem::computeAndUpdateDimensions() {
QVector<glm::vec3> points;
QVector<float> widths;
@ -129,6 +130,32 @@ void PolyLineEntityItem::computeAndUpdateDimensionsAndPosition() {
setScaledDimensions(2.0f * (maxHalfDim + maxWidth));
}
void PolyLineEntityItem::computeTightLocalBoundingBox(AABox& localBox) const {
QVector<glm::vec3> points;
QVector<float> widths;
withReadLock([&] {
points = _points;
widths = _widths;
});
if (points.size() > 0) {
Extents extents;
float maxWidth = DEFAULT_LINE_WIDTH;
for (int i = 0; i < points.length(); i++) {
extents.addPoint(points[i]);
if (i < widths.size()) {
maxWidth = glm::max(maxWidth, widths[i]);
}
}
extents.addPoint(extents.minimum - maxWidth * Vectors::ONE);
extents.addPoint(extents.maximum + maxWidth * Vectors::ONE);
localBox.setBox(extents.minimum, extents.maximum - extents.minimum);
} else {
localBox.setBox(glm::vec3(-0.5f * DEFAULT_LINE_WIDTH), glm::vec3(DEFAULT_LINE_WIDTH));
}
}
int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
@ -267,4 +294,4 @@ void PolyLineEntityItem::setFaceCamera(bool faceCamera) {
_needsRenderUpdate = _faceCamera != faceCamera;
_faceCamera = faceCamera;
});
}
}

View file

@ -15,7 +15,7 @@
#include "EntityItem.h"
class PolyLineEntityItem : public EntityItem {
public:
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
PolyLineEntityItem(const EntityItemID& entityItemID);
@ -90,10 +90,12 @@ class PolyLineEntityItem : public EntityItem {
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
void computeTightLocalBoundingBox(AABox& box) const;
virtual void debugDump() const override;
private:
void computeAndUpdateDimensionsAndPosition();
void computeAndUpdateDimensions();
protected:
glm::u8vec3 _color;
QVector<glm::vec3> _points;

View file

@ -60,74 +60,108 @@ void PrepareJointsTask::configure(const Config& config) {
_passthrough = config.passthrough;
}
void PrepareJointsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) {
const auto& jointsIn = input.get0();
auto& jointsOut = output.edit0();
std::vector<QString> jointNames;
if (_passthrough) {
jointsOut = jointsIn;
} else {
const auto& mapping = input.get1();
auto& jointRotationOffsets = output.edit1();
auto& jointIndices = output.edit2();
bool newJointRot = false;
static const QString JOINT_ROTATION_OFFSET2_FIELD = "jointRotationOffset2";
QVariantHash fstHashMap = mapping;
if (fstHashMap.contains(JOINT_ROTATION_OFFSET2_FIELD)) {
newJointRot = true;
} else {
newJointRot = false;
}
bool newJointRot = fstHashMap.contains(JOINT_ROTATION_OFFSET2_FIELD);
// Get joint renames
auto jointNameMapping = getJointNameMapping(mapping);
QMap<QString, QString> jointNameMapping = getJointNameMapping(mapping);
// Apply joint metadata from FST file mappings
for (const auto& jointIn : jointsIn) {
for (const hfm::Joint& jointIn : jointsIn) {
jointsOut.push_back(jointIn);
auto& jointOut = jointsOut.back();
hfm::Joint& jointOut = jointsOut.back();
if (!newJointRot) {
auto jointNameMapKey = jointNameMapping.key(jointIn.name);
// Offset rotations are referenced by the new joint's names
// We need to assign new joint's names now, before the offsets are read.
QString jointNameMapKey = jointNameMapping.key(jointIn.name);
if (jointNameMapping.contains(jointNameMapKey)) {
jointOut.name = jointNameMapKey;
}
}
jointIndices.insert(jointOut.name, (int)jointsOut.size());
jointNames.push_back(jointOut.name);
}
// Get joint rotation offsets from FST file mappings
auto offsets = getJointRotationOffsets(mapping);
QMap<QString, glm::quat> offsets = getJointRotationOffsets(mapping);
for (auto itr = offsets.begin(); itr != offsets.end(); itr++) {
QString jointName = itr.key();
int jointIndex = jointIndices.value(jointName) - 1;
if (jointIndex >= 0) {
glm::quat rotationOffset = itr.value();
jointRotationOffsets.insert(jointIndex, rotationOffset);
qCDebug(model_baker) << "Joint Rotation Offset added to Rig._jointRotationOffsets : " << " jointName: " << jointName << " jointIndex: " << jointIndex << " rotation offset: " << rotationOffset;
auto jointToOffset = std::find_if(jointsOut.begin(), jointsOut.end(), [jointName](const hfm::Joint& joint) {
return (joint.name == jointName && joint.isSkeletonJoint);
});
if (jointToOffset != jointsOut.end()) {
// In case there are named duplicates we'll assign the offset rotation to the first skeleton joint that matches the name.
int jointIndex = (int)distance(jointsOut.begin(), jointToOffset);
if (jointIndex >= 0) {
glm::quat rotationOffset = itr.value();
jointRotationOffsets.insert(jointIndex, rotationOffset);
qCDebug(model_baker) << "Joint Rotation Offset added to Rig._jointRotationOffsets : " << " jointName: " << jointName << " jointIndex: " << jointIndex << " rotation offset: " << rotationOffset;
break;
}
}
}
if (newJointRot) {
for (auto& jointOut : jointsOut) {
auto jointNameMapKey = jointNameMapping.key(jointOut.name);
int mappedIndex = jointIndices.value(jointOut.name);
// Offset rotations are referenced using the original joint's names
// We need to apply new names now, once we have read the offsets
for (size_t i = 0; i < jointsOut.size(); i++) {
hfm::Joint& jointOut = jointsOut[i];
QString jointNameMapKey = jointNameMapping.key(jointOut.name);
if (jointNameMapping.contains(jointNameMapKey)) {
// delete and replace with hifi name
jointIndices.remove(jointOut.name);
jointOut.name = jointNameMapKey;
jointIndices.insert(jointOut.name, mappedIndex);
} else {
// nothing mapped to this fbx joint name
if (jointNameMapping.contains(jointOut.name)) {
// but the name is in the list of hifi names is mapped to a different joint
int extraIndex = jointIndices.value(jointOut.name);
jointIndices.remove(jointOut.name);
jointOut.name = "";
jointIndices.insert(jointOut.name, extraIndex);
}
jointNames[i] = jointNameMapKey;
}
}
}
const QString APPEND_DUPLICATE_JOINT = "_joint";
const QString APPEND_DUPLICATE_MESH = "_mesh";
// resolve duplicates and set jointIndices
auto& jointIndices = output.edit2();
for (size_t i = 0; i < jointsOut.size(); i++) {
hfm::Joint& jointOut = jointsOut[i];
if (jointIndices.contains(jointOut.name)) {
int duplicatedJointIndex = jointIndices[jointOut.name] - 1;
if (duplicatedJointIndex >= 0) {
auto& duplicatedJoint = jointsOut[duplicatedJointIndex];
bool areBothJoints = jointOut.isSkeletonJoint && duplicatedJoint.isSkeletonJoint;
QString existJointName = jointOut.name;
QString appendName;
if (areBothJoints) {
appendName = APPEND_DUPLICATE_JOINT;
qCWarning(model_baker) << "Duplicated skeleton joints found: " << existJointName;
} else {
appendName = APPEND_DUPLICATE_MESH;
qCDebug(model_baker) << "Duplicated joints found. Renaming the mesh joint: " << existJointName;
}
QString newName = existJointName + appendName;
// Make sure the new name is unique
int duplicateIndex = 0;
while (jointIndices.contains(newName)) {
newName = existJointName + appendName + QString::number(++duplicateIndex);
}
// Find and rename the mesh joint
if (!jointOut.isSkeletonJoint) {
jointOut.name = newName;
} else {
jointIndices.remove(jointOut.name);
jointIndices.insert(newName, duplicatedJointIndex);
}
}
}
jointIndices.insert(jointOut.name, (int)(i + 1));
}
}
}

View file

@ -52,7 +52,8 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, float r
}
void packDeferredFragmentUnlit(vec3 normal, float alpha, vec3 color) {
if (alpha < 1.0) {
// to reduce texel flickering for floating point error we discard when alpha is "almost one"
if (alpha < 0.999999) {
discard;
}
_fragColor0 = vec4(color, packUnlit());

View file

@ -40,9 +40,9 @@ body
letter-spacing: 0.5px;
}
#main p {
line-height: 24px;
margin-bottom: 24px;
p {
font-size: 0.95rem;
line-height: 20px;
}
section
@ -118,30 +118,17 @@ h5, .container-overview .subsection-title
**************************** Table styles **************************
********************************************************************/
table
{
width: 100%;
background-color: #fff;
table {
border-collapse: collapse;
border-spacing: 0;
border: solid #d8e1d9 1px;
text-align: left;
overflow: auto;
font-size: 0.9rem;
line-height: 1.5;
border: solid #d8e1d9 1px;
margin-bottom: 1.5rem;
width: 100%
}
table > thead {
thead {
border-color: #d8e1d9;
background: #d8e1d9;
font-weight: 400;
}
table th, table td {
padding: 0.5rem;
border-left: 1px solid #d8e1d9;
font-size: .95em;
background:#d8e1d9;
text-align: left;
}
table tr {
@ -152,6 +139,23 @@ table tr:nth-child(even) {
background-color: #f8f8f8;
}
td {
border: solid #c7cccb 1px;
}
article table thead tr th, article table tbody tr td, article table tbody tr td p {
font-size: .89rem;
line-height: 20px;
}
article table thead tr th, article table tbody tr td {
padding: 0.5rem;
}
article table tbody tr td ul li {
font-size: .89rem;
}
/*******************************************************************
****************************** Link styles *************************
********************************************************************/
@ -169,21 +173,15 @@ a, a:hover, a:active, a:visited {
********************************************************************/
article ul {
margin-bottom: 1.7em;
margin-bottom: 1em;
}
article li {
font-size: .95rem;
line-height: 20px;
padding-bottom: 5px;
}
.readme ul {
font-size: 0.95rem;
line-height: 24px;
margin-bottom: 24px;
}
/*******************************************************************
********************** Navigation sidebar styles *******************
********************************************************************/
@ -388,20 +386,16 @@ tt, code, kbd, samp {
font-size: 0.9rem;
}
img {
display: block;
max-width: 100%;
margin: auto;
}
p, ul, ol, blockquote {
ul, ol, blockquote {
margin-bottom: 1em;
}
.class-description {
font-size: 130%;
line-height: 140%;
@ -423,7 +417,6 @@ header {
padding: 0px 4px;
}
.apiLinks
{
display: block;
@ -529,7 +522,6 @@ header {
.code-caption {
font-style: italic;
font-size: 107%;
margin: 0;
}
@ -696,51 +688,6 @@ span.param-type, .params td .param-type, .param-type dd {
z-index: 1;
}
/********************************************************************
**************************** Mobile styles **************************
*********************************************************************/
@media only screen and (min-width: 320px) and (max-width: 680px) {
body {
overflow-x: hidden;
}
nav {
background: #FFF;
width: 250px;
height: 100%;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: -250px;
z-index: 3;
padding: 0 10px;
transition: left 0.2s;
}
.navicon-button {
display: inline-block;
position: fixed;
top: 1.5em;
right: 0;
z-index: 2;
}
#main {
width: 100%;
min-width: 360px;
}
#main section {
padding: 0;
}
footer {
margin-left: 0;
}
}
/** Add a '#' to static members */
[data-type="member"] a::before {
content: '#';