mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-29 22:22:54 +02:00
Merge branch 'master' into Sitting_emote_variants
This commit is contained in:
commit
b5d2675a05
49 changed files with 1283 additions and 1041 deletions
|
@ -33,7 +33,7 @@ MixerAvatar::MixerAvatar() {
|
||||||
_challengeTimer.setSingleShot(true);
|
_challengeTimer.setSingleShot(true);
|
||||||
_challengeTimer.setInterval(CHALLENGE_TIMEOUT_MS);
|
_challengeTimer.setInterval(CHALLENGE_TIMEOUT_MS);
|
||||||
|
|
||||||
_challengeTimer.callOnTimeout([this]() {
|
_challengeTimer.callOnTimeout(this, [this]() {
|
||||||
if (_verifyState == challengeClient) {
|
if (_verifyState == challengeClient) {
|
||||||
_pendingEvent = false;
|
_pendingEvent = false;
|
||||||
_verifyState = verificationFailed;
|
_verifyState = verificationFailed;
|
||||||
|
|
|
@ -15,9 +15,11 @@ macro(TARGET_WEBRTC)
|
||||||
# select_library_configurations(WEBRTC)
|
# select_library_configurations(WEBRTC)
|
||||||
else()
|
else()
|
||||||
set(WEBRTC_INCLUDE_DIRS "${VCPKG_INSTALL_ROOT}/include/webrtc")
|
set(WEBRTC_INCLUDE_DIRS "${VCPKG_INSTALL_ROOT}/include/webrtc")
|
||||||
find_library(WEBRTC_LIBRARY NAMES webrtc PATHS ${VCPKG_INSTALL_ROOT}/lib/ NO_DEFAULT_PATH)
|
|
||||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${WEBRTC_INCLUDE_DIRS})
|
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${WEBRTC_INCLUDE_DIRS})
|
||||||
target_link_libraries(${TARGET_NAME} ${WEBRTC_LIBRARY})
|
find_library(WEBRTC_LIBRARY_RELEASE webrtc PATHS ${VCPKG_INSTALL_ROOT}/lib NO_DEFAULT_PATH)
|
||||||
|
find_library(WEBRTC_LIBRARY_DEBUG webrtc PATHS ${VCPKG_INSTALL_ROOT}/debug/lib NO_DEFAULT_PATH)
|
||||||
|
select_library_configurations(WEBRTC)
|
||||||
|
target_link_libraries(${TARGET_NAME} ${WEBRTC_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,7 @@ if (APPLE)
|
||||||
# configure CMake to use a custom Info.plist
|
# configure CMake to use a custom Info.plist
|
||||||
set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)
|
set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)
|
||||||
|
|
||||||
|
set(MACOSX_BUNDLE_BUNDLE_NAME "High Fidelity")
|
||||||
if (PRODUCTION_BUILD)
|
if (PRODUCTION_BUILD)
|
||||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface)
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface)
|
||||||
else ()
|
else ()
|
||||||
|
|
|
@ -136,17 +136,17 @@ Flickable {
|
||||||
Layout.preferredHeight: 18
|
Layout.preferredHeight: 18
|
||||||
Layout.preferredWidth: parent.width
|
Layout.preferredWidth: parent.width
|
||||||
labelTextOn: "Show Emote UI"
|
labelTextOn: "Show Emote UI"
|
||||||
checked: Settings.getValue("simplifiedUI/emoteIndicatorVisible", true)
|
checked: Settings.getValue("simplifiedUI/allowEmoteDrawerExpansion", true)
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var currentSetting = Settings.getValue("simplifiedUI/emoteIndicatorVisible", true);
|
var currentSetting = Settings.getValue("simplifiedUI/allowEmoteDrawerExpansion", true);
|
||||||
Settings.setValue("simplifiedUI/emoteIndicatorVisible", !currentSetting);
|
Settings.setValue("simplifiedUI/allowEmoteDrawerExpansion", !currentSetting);
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: Settings
|
target: Settings
|
||||||
|
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
if (setting === "simplifiedUI/emoteIndicatorVisible") {
|
if (setting === "simplifiedUI/allowEmoteDrawerExpansion") {
|
||||||
emoteSwitch.checked = value;
|
emoteSwitch.checked = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,7 @@ class MyAvatar : public Avatar {
|
||||||
*
|
*
|
||||||
* @property {Vec3} qmlPosition - A synonym for <code>position</code> for use by QML.
|
* @property {Vec3} qmlPosition - A synonym for <code>position</code> for use by QML.
|
||||||
*
|
*
|
||||||
|
* @property {Vec3} feetPosition - The position of the avatar's feet.
|
||||||
* @property {boolean} shouldRenderLocally=true - If <code>true</code> then your avatar is rendered for you in Interface,
|
* @property {boolean} shouldRenderLocally=true - If <code>true</code> then your avatar is rendered for you in Interface,
|
||||||
* otherwise it is not rendered for you (but it is still rendered for other users).
|
* otherwise it is not rendered for you (but it is still rendered for other users).
|
||||||
* @property {Vec3} motorVelocity=Vec3.ZERO - The target velocity of your avatar to be achieved by a scripted motor.
|
* @property {Vec3} motorVelocity=Vec3.ZERO - The target velocity of your avatar to be achieved by a scripted motor.
|
||||||
|
@ -340,6 +341,7 @@ class MyAvatar : public Avatar {
|
||||||
Q_PROPERTY(QVector3D qmlPosition READ getQmlPosition)
|
Q_PROPERTY(QVector3D qmlPosition READ getQmlPosition)
|
||||||
QVector3D getQmlPosition() { auto p = getWorldPosition(); return QVector3D(p.x, p.y, p.z); }
|
QVector3D getQmlPosition() { auto p = getWorldPosition(); return QVector3D(p.x, p.y, p.z); }
|
||||||
|
|
||||||
|
Q_PROPERTY(glm::vec3 feetPosition READ getWorldFeetPosition WRITE goToFeetLocation)
|
||||||
Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally)
|
Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally)
|
||||||
Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity)
|
Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity)
|
||||||
Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale)
|
Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale)
|
||||||
|
@ -1938,9 +1940,8 @@ public slots:
|
||||||
* @param {boolean} [shouldFaceLocation=false] - Set to <code>true</code> to position the avatar a short distance away from
|
* @param {boolean} [shouldFaceLocation=false] - Set to <code>true</code> to position the avatar a short distance away from
|
||||||
* the new position and orientate the avatar to face the position.
|
* the new position and orientate the avatar to face the position.
|
||||||
*/
|
*/
|
||||||
void goToFeetLocation(const glm::vec3& newPosition,
|
void goToFeetLocation(const glm::vec3& newPosition, bool hasOrientation = false,
|
||||||
bool hasOrientation, const glm::quat& newOrientation,
|
const glm::quat& newOrientation = glm::quat(), bool shouldFaceLocation = false);
|
||||||
bool shouldFaceLocation);
|
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Moves the avatar to a new position and/or orientation in the domain.
|
* Moves the avatar to a new position and/or orientation in the domain.
|
||||||
|
|
|
@ -337,10 +337,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
eyeParams.modelTranslation = getTranslation();
|
eyeParams.modelTranslation = getTranslation();
|
||||||
eyeParams.leftEyeJointIndex = _rig.indexOfJoint("LeftEye");
|
eyeParams.leftEyeJointIndex = _rig.indexOfJoint("LeftEye");
|
||||||
eyeParams.rightEyeJointIndex = _rig.indexOfJoint("RightEye");
|
eyeParams.rightEyeJointIndex = _rig.indexOfJoint("RightEye");
|
||||||
|
_rig.updateFromEyeParameters(eyeParams);
|
||||||
if (_owningAvatar->getHasProceduralEyeFaceMovement()) {
|
|
||||||
_rig.updateFromEyeParameters(eyeParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateFingers();
|
updateFingers();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#import "DownloadLauncher.h"
|
#import "DownloadLauncher.h"
|
||||||
#import "Launcher.h"
|
#import "Launcher.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
static const __int32_t kMinLauncherSize = 250000; // 308kb is our smallest launcher
|
||||||
|
static const NSString *kIOError = @"IOError";
|
||||||
|
|
||||||
@implementation DownloadLauncher
|
@implementation DownloadLauncher
|
||||||
|
|
||||||
|
@ -22,8 +26,38 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(void)validateHQLauncherZipAt:(NSURL *)location {
|
||||||
|
// Does the file look like a valid HQLauncher ZIP?
|
||||||
|
struct stat lStat;
|
||||||
|
const char *cStrLocation = location.fileSystemRepresentation;
|
||||||
|
if (stat(cStrLocation, &lStat) != 0) {
|
||||||
|
NSLog(@"couldn't stat download file: %s", cStrLocation);
|
||||||
|
@throw [NSException exceptionWithName:(NSString *)kIOError
|
||||||
|
reason:@"couldn't stat download file"
|
||||||
|
userInfo:nil];
|
||||||
|
}
|
||||||
|
if (lStat.st_size <= kMinLauncherSize) {
|
||||||
|
NSLog(@"download is too small: %s is %lld bytes, should be at least %d bytes",
|
||||||
|
cStrLocation, lStat.st_size, kMinLauncherSize);
|
||||||
|
@throw [NSException exceptionWithName:(NSString *)kIOError
|
||||||
|
reason:@"download is too small"
|
||||||
|
userInfo:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
-(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 {
|
||||||
|
[self validateHQLauncherZipAt:location];
|
||||||
|
}
|
||||||
|
@catch (NSException *exc) {
|
||||||
|
if ([exc.name isEqualToString:(NSString *)kIOError]) {
|
||||||
|
[[Launcher sharedLauncher] displayErrorPage];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@throw;
|
||||||
|
}
|
||||||
|
|
||||||
NSError* error = nil;
|
NSError* error = nil;
|
||||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||||
NSString* destinationFileName = downloadTask.originalRequest.URL.lastPathComponent;
|
NSString* destinationFileName = downloadTask.originalRequest.URL.lastPathComponent;
|
||||||
|
|
|
@ -21,15 +21,39 @@ int main(int argc, char const* argv[]) {
|
||||||
for (int index = 0; index < argc; index++) {
|
for (int index = 0; index < argc; index++) {
|
||||||
NSLog(@"argv at index %d = %s", index, argv[index]);
|
NSLog(@"argv at index %d = %s", index, argv[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
|
||||||
NSString* oldLauncher = [NSString stringWithUTF8String:argv[1]];
|
NSString* oldLauncher = [NSString stringWithUTF8String:argv[1]];
|
||||||
NSString* newLauncher = [NSString stringWithUTF8String:argv[2]];
|
NSString* newLauncher = [NSString stringWithUTF8String:argv[2]];
|
||||||
NSURL* destinationUrl = [UpdaterHelper NSStringToNSURL:newLauncher];
|
NSURL* destinationUrl = [UpdaterHelper NSStringToNSURL:newLauncher];
|
||||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||||
[fileManager replaceItemAtURL:[UpdaterHelper NSStringToNSURL:oldLauncher] withItemAtURL:[UpdaterHelper NSStringToNSURL:newLauncher] backupItemName:nil options:NSFileManagerItemReplacementUsingNewMetadataOnly resultingItemURL:&destinationUrl error:nil];
|
[fileManager replaceItemAtURL:[UpdaterHelper NSStringToNSURL:oldLauncher]
|
||||||
|
withItemAtURL:[UpdaterHelper NSStringToNSURL:newLauncher]
|
||||||
|
backupItemName:nil
|
||||||
|
options:NSFileManagerItemReplacementUsingNewMetadataOnly
|
||||||
|
resultingItemURL:&destinationUrl
|
||||||
|
error:&error];
|
||||||
|
if (error != nil) {
|
||||||
|
NSLog(@"couldn't update launcher: %@", error);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
|
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
|
||||||
NSURL* applicationURL = [UpdaterHelper NSStringToNSURL: [oldLauncher stringByAppendingString: @"/Contents/MacOS/HQ Launcher"]];
|
NSURL* applicationURL = [UpdaterHelper NSStringToNSURL: [oldLauncher stringByAppendingString: @"/Contents/MacOS/HQ Launcher"]];
|
||||||
NSArray* arguments =@[];
|
NSArray* arguments =@[];
|
||||||
NSLog(@"Launcher agruments: %@", arguments);
|
NSLog(@"Launcher agruments: %@", arguments);
|
||||||
[workspace launchApplicationAtURL:applicationURL options:NSWorkspaceLaunchNewInstance configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:nil];
|
|
||||||
|
NSDictionary *configuration = [NSDictionary dictionaryWithObject:arguments
|
||||||
|
forKey:NSWorkspaceLaunchConfigurationArguments];
|
||||||
|
[workspace launchApplicationAtURL:applicationURL
|
||||||
|
options:NSWorkspaceLaunchNewInstance
|
||||||
|
configuration:configuration
|
||||||
|
error:&error];
|
||||||
|
if (error != nil) {
|
||||||
|
NSLog(@"couldn't start launcher: %@", error);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "LauncherApp.h"
|
#include "LauncherApp.h"
|
||||||
#include "LauncherDlg.h"
|
#include "LauncherDlg.h"
|
||||||
|
|
||||||
|
#include <propsys.h>
|
||||||
|
#include <propkey.h>
|
||||||
#include <d2d1.h>
|
#include <d2d1.h>
|
||||||
#pragma comment(lib, "d2d1")
|
#pragma comment(lib, "d2d1")
|
||||||
|
|
||||||
|
@ -84,7 +86,7 @@ END_MESSAGE_MAP()
|
||||||
|
|
||||||
BOOL CLauncherDlg::OnInitDialog() {
|
BOOL CLauncherDlg::OnInitDialog() {
|
||||||
CDialog::OnInitDialog();
|
CDialog::OnInitDialog();
|
||||||
|
MarkWindowAsUnpinnable();
|
||||||
SetIcon(m_hIcon, TRUE); // Set big icon
|
SetIcon(m_hIcon, TRUE); // Set big icon
|
||||||
SetIcon(m_hIcon, FALSE); // Set small icon
|
SetIcon(m_hIcon, FALSE); // Set small icon
|
||||||
|
|
||||||
|
@ -129,6 +131,19 @@ BOOL CLauncherDlg::OnInitDialog() {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CLauncherDlg::MarkWindowAsUnpinnable() {
|
||||||
|
HWND hwnd = AfxGetMainWnd()->m_hWnd;
|
||||||
|
IPropertyStore* pps;
|
||||||
|
HRESULT hr = SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&pps));
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
PROPVARIANT var;
|
||||||
|
var.vt = VT_BOOL;
|
||||||
|
var.boolVal = VARIANT_TRUE;
|
||||||
|
hr = pps->SetValue(PKEY_AppUserModel_PreventPinning, var);
|
||||||
|
pps->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
POINT CLauncherDlg::getMouseCoords(MSG* pMsg) {
|
POINT CLauncherDlg::getMouseCoords(MSG* pMsg) {
|
||||||
POINT pos;
|
POINT pos;
|
||||||
pos.x = (int)(short)LOWORD(pMsg->lParam);
|
pos.x = (int)(short)LOWORD(pMsg->lParam);
|
||||||
|
|
|
@ -59,6 +59,7 @@ protected:
|
||||||
BOOL getTextFormat(int ResID, TextFormat& formatOut);
|
BOOL getTextFormat(int ResID, TextFormat& formatOut);
|
||||||
void showWindows(std::vector<CStatic*> windows, bool show);
|
void showWindows(std::vector<CStatic*> windows, bool show);
|
||||||
POINT getMouseCoords(MSG* pMsg);
|
POINT getMouseCoords(MSG* pMsg);
|
||||||
|
void MarkWindowAsUnpinnable();
|
||||||
|
|
||||||
|
|
||||||
bool _isConsoleRunning { false };
|
bool _isConsoleRunning { false };
|
||||||
|
|
|
@ -14,9 +14,10 @@
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
#include "AnimClip.h"
|
#include "AnimClip.h"
|
||||||
|
|
||||||
AnimBlendLinear::AnimBlendLinear(const QString& id, float alpha) :
|
AnimBlendLinear::AnimBlendLinear(const QString& id, float alpha, AnimBlendType blendType) :
|
||||||
AnimNode(AnimNode::Type::BlendLinear, id),
|
AnimNode(AnimNode::Type::BlendLinear, id),
|
||||||
_alpha(alpha) {
|
_alpha(alpha),
|
||||||
|
_blendType(blendType) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +37,19 @@ const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, con
|
||||||
} else if (_children.size() == 1) {
|
} else if (_children.size() == 1) {
|
||||||
_poses = _children[0]->evaluate(animVars, context, dt, triggersOut);
|
_poses = _children[0]->evaluate(animVars, context, dt, triggersOut);
|
||||||
context.setDebugAlpha(_children[0]->getID(), parentDebugAlpha, _children[0]->getType());
|
context.setDebugAlpha(_children[0]->getID(), parentDebugAlpha, _children[0]->getType());
|
||||||
|
} else if (_children.size() == 2 && _blendType != AnimBlendType_Normal) {
|
||||||
|
// special case for additive blending
|
||||||
|
float alpha = glm::clamp(_alpha, 0.0f, 1.0f);
|
||||||
|
const size_t prevPoseIndex = 0;
|
||||||
|
const size_t nextPoseIndex = 1;
|
||||||
|
evaluateAndBlendChildren(animVars, context, triggersOut, alpha, prevPoseIndex, nextPoseIndex, dt);
|
||||||
|
|
||||||
|
// for animation stack debugging
|
||||||
|
float weight2 = alpha;
|
||||||
|
float weight1 = 1.0f - weight2;
|
||||||
|
context.setDebugAlpha(_children[prevPoseIndex]->getID(), weight1 * parentDebugAlpha, _children[prevPoseIndex]->getType());
|
||||||
|
context.setDebugAlpha(_children[nextPoseIndex]->getID(), weight2 * parentDebugAlpha, _children[nextPoseIndex]->getType());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
float clampedAlpha = glm::clamp(_alpha, 0.0f, (float)(_children.size() - 1));
|
float clampedAlpha = glm::clamp(_alpha, 0.0f, (float)(_children.size() - 1));
|
||||||
size_t prevPoseIndex = glm::floor(clampedAlpha);
|
size_t prevPoseIndex = glm::floor(clampedAlpha);
|
||||||
|
@ -79,7 +93,35 @@ void AnimBlendLinear::evaluateAndBlendChildren(const AnimVariantMap& animVars, c
|
||||||
if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) {
|
if (prevPoses.size() > 0 && prevPoses.size() == nextPoses.size()) {
|
||||||
_poses.resize(prevPoses.size());
|
_poses.resize(prevPoses.size());
|
||||||
|
|
||||||
::blend(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]);
|
if (_blendType == AnimBlendType_Normal) {
|
||||||
|
::blend(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]);
|
||||||
|
} else if (_blendType == AnimBlendType_AddRelative) {
|
||||||
|
::blendAdd(_poses.size(), &prevPoses[0], &nextPoses[0], alpha, &_poses[0]);
|
||||||
|
} else if (_blendType == AnimBlendType_AddAbsolute) {
|
||||||
|
// convert prev from relative to absolute
|
||||||
|
AnimPoseVec absPrev = prevPoses;
|
||||||
|
_skeleton->convertRelativePosesToAbsolute(absPrev);
|
||||||
|
|
||||||
|
// rotate the offset rotations from next into the parent relative frame of each joint.
|
||||||
|
AnimPoseVec relOffsetPoses;
|
||||||
|
relOffsetPoses.reserve(nextPoses.size());
|
||||||
|
for (size_t i = 0; i < nextPoses.size(); ++i) {
|
||||||
|
|
||||||
|
// copy translation and scale from nextPoses
|
||||||
|
AnimPose pose = nextPoses[i];
|
||||||
|
|
||||||
|
int parentIndex = _skeleton->getParentIndex((int)i);
|
||||||
|
if (parentIndex >= 0) {
|
||||||
|
// but transform nextPoses rot into absPrev parent frame.
|
||||||
|
pose.rot() = glm::inverse(absPrev[parentIndex].rot()) * pose.rot() * absPrev[parentIndex].rot();
|
||||||
|
}
|
||||||
|
|
||||||
|
relOffsetPoses.push_back(pose);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then blend
|
||||||
|
::blendAdd(_poses.size(), &prevPoses[0], &relOffsetPoses[0], alpha, &_poses[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class AnimBlendLinear : public AnimNode {
|
||||||
public:
|
public:
|
||||||
friend class AnimTests;
|
friend class AnimTests;
|
||||||
|
|
||||||
AnimBlendLinear(const QString& id, float alpha);
|
AnimBlendLinear(const QString& id, float alpha, AnimBlendType blendType);
|
||||||
virtual ~AnimBlendLinear() override;
|
virtual ~AnimBlendLinear() override;
|
||||||
|
|
||||||
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override;
|
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override;
|
||||||
|
@ -44,6 +44,7 @@ protected:
|
||||||
AnimPoseVec _poses;
|
AnimPoseVec _poses;
|
||||||
|
|
||||||
float _alpha;
|
float _alpha;
|
||||||
|
AnimBlendType _blendType;
|
||||||
|
|
||||||
QString _alphaVar;
|
QString _alphaVar;
|
||||||
|
|
||||||
|
|
|
@ -16,100 +16,6 @@
|
||||||
#include "AnimationLogging.h"
|
#include "AnimationLogging.h"
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
|
|
||||||
AnimClip::AnimClip(const QString& id, const QString& url, float startFrame, float endFrame, float timeScale, bool loopFlag, bool mirrorFlag) :
|
|
||||||
AnimNode(AnimNode::Type::Clip, id),
|
|
||||||
_startFrame(startFrame),
|
|
||||||
_endFrame(endFrame),
|
|
||||||
_timeScale(timeScale),
|
|
||||||
_loopFlag(loopFlag),
|
|
||||||
_mirrorFlag(mirrorFlag),
|
|
||||||
_frame(startFrame)
|
|
||||||
{
|
|
||||||
loadURL(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimClip::~AnimClip() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const AnimPoseVec& AnimClip::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) {
|
|
||||||
|
|
||||||
// lookup parameters from animVars, using current instance variables as defaults.
|
|
||||||
_startFrame = animVars.lookup(_startFrameVar, _startFrame);
|
|
||||||
_endFrame = animVars.lookup(_endFrameVar, _endFrame);
|
|
||||||
_timeScale = animVars.lookup(_timeScaleVar, _timeScale);
|
|
||||||
_loopFlag = animVars.lookup(_loopFlagVar, _loopFlag);
|
|
||||||
_mirrorFlag = animVars.lookup(_mirrorFlagVar, _mirrorFlag);
|
|
||||||
float frame = animVars.lookup(_frameVar, _frame);
|
|
||||||
|
|
||||||
_frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame, dt, _loopFlag, _id, triggersOut);
|
|
||||||
|
|
||||||
// poll network anim to see if it's finished loading yet.
|
|
||||||
if (_networkAnim && _networkAnim->isLoaded() && _skeleton) {
|
|
||||||
// loading is complete, copy animation frames from network animation, then throw it away.
|
|
||||||
copyFromNetworkAnim();
|
|
||||||
_networkAnim.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_anim.size()) {
|
|
||||||
|
|
||||||
// lazy creation of mirrored animation frames.
|
|
||||||
if (_mirrorFlag && _anim.size() != _mirrorAnim.size()) {
|
|
||||||
buildMirrorAnim();
|
|
||||||
}
|
|
||||||
|
|
||||||
int prevIndex = (int)glm::floor(_frame);
|
|
||||||
int nextIndex;
|
|
||||||
if (_loopFlag && _frame >= _endFrame) {
|
|
||||||
nextIndex = (int)glm::ceil(_startFrame);
|
|
||||||
} else {
|
|
||||||
nextIndex = (int)glm::ceil(_frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
// It can be quite possible for the user to set _startFrame and _endFrame to
|
|
||||||
// values before or past valid ranges. We clamp the frames here.
|
|
||||||
int frameCount = (int)_anim.size();
|
|
||||||
prevIndex = std::min(std::max(0, prevIndex), frameCount - 1);
|
|
||||||
nextIndex = std::min(std::max(0, nextIndex), frameCount - 1);
|
|
||||||
|
|
||||||
const AnimPoseVec& prevFrame = _mirrorFlag ? _mirrorAnim[prevIndex] : _anim[prevIndex];
|
|
||||||
const AnimPoseVec& nextFrame = _mirrorFlag ? _mirrorAnim[nextIndex] : _anim[nextIndex];
|
|
||||||
float alpha = glm::fract(_frame);
|
|
||||||
|
|
||||||
::blend(_poses.size(), &prevFrame[0], &nextFrame[0], alpha, &_poses[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
processOutputJoints(triggersOut);
|
|
||||||
|
|
||||||
return _poses;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimClip::loadURL(const QString& url) {
|
|
||||||
auto animCache = DependencyManager::get<AnimationCache>();
|
|
||||||
_networkAnim = animCache->getAnimation(url);
|
|
||||||
_url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimClip::setCurrentFrameInternal(float frame) {
|
|
||||||
// because dt is 0, we should not encounter any triggers
|
|
||||||
const float dt = 0.0f;
|
|
||||||
AnimVariantMap triggers;
|
|
||||||
_frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame + _startFrame, dt, _loopFlag, _id, triggers);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<int> buildJointIndexMap(const AnimSkeleton& dstSkeleton, const AnimSkeleton& srcSkeleton) {
|
|
||||||
std::vector<int> jointIndexMap;
|
|
||||||
int srcJointCount = srcSkeleton.getNumJoints();
|
|
||||||
jointIndexMap.reserve(srcJointCount);
|
|
||||||
for (int srcJointIndex = 0; srcJointIndex < srcJointCount; srcJointIndex++) {
|
|
||||||
QString srcJointName = srcSkeleton.getJointName(srcJointIndex);
|
|
||||||
int dstJointIndex = dstSkeleton.nameToJointIndex(srcJointName);
|
|
||||||
jointIndexMap.push_back(dstJointIndex);
|
|
||||||
}
|
|
||||||
return jointIndexMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_CUSTOM_ASSERT
|
#ifdef USE_CUSTOM_ASSERT
|
||||||
#undef ASSERT
|
#undef ASSERT
|
||||||
#define ASSERT(x) \
|
#define ASSERT(x) \
|
||||||
|
@ -123,12 +29,73 @@ static std::vector<int> buildJointIndexMap(const AnimSkeleton& dstSkeleton, cons
|
||||||
#define ASSERT assert
|
#define ASSERT assert
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void AnimClip::copyFromNetworkAnim() {
|
static std::vector<int> buildJointIndexMap(const AnimSkeleton& dstSkeleton, const AnimSkeleton& srcSkeleton) {
|
||||||
assert(_networkAnim && _networkAnim->isLoaded() && _skeleton);
|
std::vector<int> jointIndexMap;
|
||||||
_anim.clear();
|
int srcJointCount = srcSkeleton.getNumJoints();
|
||||||
|
jointIndexMap.reserve(srcJointCount);
|
||||||
|
for (int srcJointIndex = 0; srcJointIndex < srcJointCount; srcJointIndex++) {
|
||||||
|
QString srcJointName = srcSkeleton.getJointName(srcJointIndex);
|
||||||
|
int dstJointIndex = dstSkeleton.nameToJointIndex(srcJointName);
|
||||||
|
jointIndexMap.push_back(dstJointIndex);
|
||||||
|
}
|
||||||
|
return jointIndexMap;
|
||||||
|
}
|
||||||
|
|
||||||
auto avatarSkeleton = getSkeleton();
|
static void bakeRelativeDeltaAnim(std::vector<AnimPoseVec>& anim, const AnimPoseVec& basePoses) {
|
||||||
const HFMModel& animModel = _networkAnim->getHFMModel();
|
|
||||||
|
// invert all the basePoses
|
||||||
|
AnimPoseVec invBasePoses = basePoses;
|
||||||
|
for (auto&& invBasePose : invBasePoses) {
|
||||||
|
invBasePose = invBasePose.inverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each frame of the animation
|
||||||
|
for (auto&& animPoses : anim) {
|
||||||
|
ASSERT(animPoses.size() == basePoses.size());
|
||||||
|
|
||||||
|
// for each joint in animPoses
|
||||||
|
for (size_t i = 0; i < animPoses.size(); ++i) {
|
||||||
|
// convert this relative AnimPose into a delta animation.
|
||||||
|
animPoses[i] = animPoses[i] * invBasePoses[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bakeAbsoluteDeltaAnim(std::vector<AnimPoseVec>& anim, const AnimPoseVec& basePoses, AnimSkeleton::ConstPointer skeleton) {
|
||||||
|
|
||||||
|
// invert all the basePoses
|
||||||
|
AnimPoseVec invBasePoses = basePoses;
|
||||||
|
for (auto&& invBasePose : invBasePoses) {
|
||||||
|
invBasePose = invBasePose.inverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimPoseVec absBasePoses = basePoses;
|
||||||
|
skeleton->convertRelativePosesToAbsolute(absBasePoses);
|
||||||
|
|
||||||
|
// for each frame of the animation
|
||||||
|
for (auto&& animPoses : anim) {
|
||||||
|
ASSERT(animPoses.size() == basePoses.size());
|
||||||
|
|
||||||
|
// for each joint in animPoses
|
||||||
|
for (size_t i = 0; i < animPoses.size(); ++i) {
|
||||||
|
|
||||||
|
// scale and translation are relative frame
|
||||||
|
animPoses[i] = animPoses[i] * invBasePoses[i];
|
||||||
|
|
||||||
|
// but transform the rotation delta into the absolute frame.
|
||||||
|
int parentIndex = skeleton->getParentIndex((int)i);
|
||||||
|
if (parentIndex >= 0) {
|
||||||
|
animPoses[i].rot() = absBasePoses[parentIndex].rot() * animPoses[i].rot() * glm::inverse(absBasePoses[parentIndex].rot());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<AnimPoseVec> copyAndRetargetFromNetworkAnim(AnimationPointer networkAnim, AnimSkeleton::ConstPointer avatarSkeleton) {
|
||||||
|
ASSERT(networkAnim && networkAnim->isLoaded() && avatarSkeleton);
|
||||||
|
std::vector<AnimPoseVec> anim;
|
||||||
|
|
||||||
|
const HFMModel& animModel = networkAnim->getHFMModel();
|
||||||
AnimSkeleton animSkeleton(animModel);
|
AnimSkeleton animSkeleton(animModel);
|
||||||
const int animJointCount = animSkeleton.getNumJoints();
|
const int animJointCount = animSkeleton.getNumJoints();
|
||||||
const int avatarJointCount = avatarSkeleton->getNumJoints();
|
const int avatarJointCount = avatarSkeleton->getNumJoints();
|
||||||
|
@ -137,7 +104,7 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
std::vector<int> avatarToAnimJointIndexMap = buildJointIndexMap(animSkeleton, *avatarSkeleton);
|
std::vector<int> avatarToAnimJointIndexMap = buildJointIndexMap(animSkeleton, *avatarSkeleton);
|
||||||
|
|
||||||
const int animFrameCount = animModel.animationFrames.size();
|
const int animFrameCount = animModel.animationFrames.size();
|
||||||
_anim.resize(animFrameCount);
|
anim.resize(animFrameCount);
|
||||||
|
|
||||||
// find the size scale factor for translation in the animation.
|
// find the size scale factor for translation in the animation.
|
||||||
float boneLengthScale = 1.0f;
|
float boneLengthScale = 1.0f;
|
||||||
|
@ -223,8 +190,8 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
// convert avatar rotations into relative frame
|
// convert avatar rotations into relative frame
|
||||||
avatarSkeleton->convertAbsoluteRotationsToRelative(avatarRotations);
|
avatarSkeleton->convertAbsoluteRotationsToRelative(avatarRotations);
|
||||||
|
|
||||||
ASSERT(frame >= 0 && frame < (int)_anim.size());
|
ASSERT(frame >= 0 && frame < (int)anim.size());
|
||||||
_anim[frame].reserve(avatarJointCount);
|
anim[frame].reserve(avatarJointCount);
|
||||||
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
||||||
const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex);
|
const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex);
|
||||||
|
|
||||||
|
@ -251,14 +218,129 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
|
|
||||||
// build the final pose
|
// build the final pose
|
||||||
ASSERT(avatarJointIndex >= 0 && avatarJointIndex < (int)avatarRotations.size());
|
ASSERT(avatarJointIndex >= 0 && avatarJointIndex < (int)avatarRotations.size());
|
||||||
_anim[frame].push_back(AnimPose(relativeScale, avatarRotations[avatarJointIndex], relativeTranslation));
|
anim[frame].push_back(AnimPose(relativeScale, avatarRotations[avatarJointIndex], relativeTranslation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mirrorAnim will be re-built on demand, if needed.
|
return anim;
|
||||||
_mirrorAnim.clear();
|
}
|
||||||
|
|
||||||
_poses.resize(avatarJointCount);
|
AnimClip::AnimClip(const QString& id, const QString& url, float startFrame, float endFrame, float timeScale, bool loopFlag, bool mirrorFlag,
|
||||||
|
AnimBlendType blendType, const QString& baseURL, float baseFrame) :
|
||||||
|
AnimNode(AnimNode::Type::Clip, id),
|
||||||
|
_startFrame(startFrame),
|
||||||
|
_endFrame(endFrame),
|
||||||
|
_timeScale(timeScale),
|
||||||
|
_loopFlag(loopFlag),
|
||||||
|
_mirrorFlag(mirrorFlag),
|
||||||
|
_frame(startFrame),
|
||||||
|
_blendType(blendType),
|
||||||
|
_baseFrame(baseFrame)
|
||||||
|
{
|
||||||
|
loadURL(url);
|
||||||
|
|
||||||
|
if (blendType != AnimBlendType_Normal) {
|
||||||
|
auto animCache = DependencyManager::get<AnimationCache>();
|
||||||
|
_baseNetworkAnim = animCache->getAnimation(baseURL);
|
||||||
|
_baseURL = baseURL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimClip::~AnimClip() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnimPoseVec& AnimClip::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) {
|
||||||
|
|
||||||
|
// lookup parameters from animVars, using current instance variables as defaults.
|
||||||
|
_startFrame = animVars.lookup(_startFrameVar, _startFrame);
|
||||||
|
_endFrame = animVars.lookup(_endFrameVar, _endFrame);
|
||||||
|
_timeScale = animVars.lookup(_timeScaleVar, _timeScale);
|
||||||
|
_loopFlag = animVars.lookup(_loopFlagVar, _loopFlag);
|
||||||
|
_mirrorFlag = animVars.lookup(_mirrorFlagVar, _mirrorFlag);
|
||||||
|
float frame = animVars.lookup(_frameVar, _frame);
|
||||||
|
|
||||||
|
_frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame, dt, _loopFlag, _id, triggersOut);
|
||||||
|
|
||||||
|
// poll network anim to see if it's finished loading yet.
|
||||||
|
if (_blendType == AnimBlendType_Normal) {
|
||||||
|
if (_networkAnim && _networkAnim->isLoaded() && _skeleton) {
|
||||||
|
// loading is complete, copy & retarget animation.
|
||||||
|
_anim = copyAndRetargetFromNetworkAnim(_networkAnim, _skeleton);
|
||||||
|
|
||||||
|
// we no longer need the actual animation resource anymore.
|
||||||
|
_networkAnim.reset();
|
||||||
|
|
||||||
|
// mirrorAnim will be re-built on demand, if needed.
|
||||||
|
_mirrorAnim.clear();
|
||||||
|
|
||||||
|
_poses.resize(_skeleton->getNumJoints());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// an additive blend type
|
||||||
|
if (_networkAnim && _networkAnim->isLoaded() && _baseNetworkAnim && _baseNetworkAnim->isLoaded() && _skeleton) {
|
||||||
|
// loading is complete, copy & retarget animation.
|
||||||
|
_anim = copyAndRetargetFromNetworkAnim(_networkAnim, _skeleton);
|
||||||
|
|
||||||
|
// we no longer need the actual animation resource anymore.
|
||||||
|
_networkAnim.reset();
|
||||||
|
|
||||||
|
// mirrorAnim will be re-built on demand, if needed.
|
||||||
|
// TODO: handle mirrored relative animations.
|
||||||
|
_mirrorAnim.clear();
|
||||||
|
|
||||||
|
_poses.resize(_skeleton->getNumJoints());
|
||||||
|
|
||||||
|
// copy & retarget baseAnim!
|
||||||
|
auto baseAnim = copyAndRetargetFromNetworkAnim(_baseNetworkAnim, _skeleton);
|
||||||
|
|
||||||
|
if (_blendType == AnimBlendType_AddAbsolute) {
|
||||||
|
bakeAbsoluteDeltaAnim(_anim, baseAnim[(int)_baseFrame], _skeleton);
|
||||||
|
} else {
|
||||||
|
// AnimBlendType_AddRelative
|
||||||
|
bakeRelativeDeltaAnim(_anim, baseAnim[(int)_baseFrame]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_anim.size()) {
|
||||||
|
|
||||||
|
// lazy creation of mirrored animation frames.
|
||||||
|
if (_mirrorFlag && _anim.size() != _mirrorAnim.size()) {
|
||||||
|
buildMirrorAnim();
|
||||||
|
}
|
||||||
|
|
||||||
|
int prevIndex = (int)glm::floor(_frame);
|
||||||
|
int nextIndex;
|
||||||
|
if (_loopFlag && _frame >= _endFrame) {
|
||||||
|
nextIndex = (int)glm::ceil(_startFrame);
|
||||||
|
} else {
|
||||||
|
nextIndex = (int)glm::ceil(_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
// It can be quite possible for the user to set _startFrame and _endFrame to
|
||||||
|
// values before or past valid ranges. We clamp the frames here.
|
||||||
|
int frameCount = (int)_anim.size();
|
||||||
|
prevIndex = std::min(std::max(0, prevIndex), frameCount - 1);
|
||||||
|
nextIndex = std::min(std::max(0, nextIndex), frameCount - 1);
|
||||||
|
|
||||||
|
const AnimPoseVec& prevFrame = _mirrorFlag ? _mirrorAnim[prevIndex] : _anim[prevIndex];
|
||||||
|
const AnimPoseVec& nextFrame = _mirrorFlag ? _mirrorAnim[nextIndex] : _anim[nextIndex];
|
||||||
|
float alpha = glm::fract(_frame);
|
||||||
|
|
||||||
|
::blend(_poses.size(), &prevFrame[0], &nextFrame[0], alpha, &_poses[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
processOutputJoints(triggersOut);
|
||||||
|
|
||||||
|
return _poses;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimClip::setCurrentFrameInternal(float frame) {
|
||||||
|
// because dt is 0, we should not encounter any triggers
|
||||||
|
const float dt = 0.0f;
|
||||||
|
AnimVariantMap triggers;
|
||||||
|
_frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame + _startFrame, dt, _loopFlag, _id, triggers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimClip::buildMirrorAnim() {
|
void AnimClip::buildMirrorAnim() {
|
||||||
|
@ -275,3 +357,9 @@ void AnimClip::buildMirrorAnim() {
|
||||||
const AnimPoseVec& AnimClip::getPosesInternal() const {
|
const AnimPoseVec& AnimClip::getPosesInternal() const {
|
||||||
return _poses;
|
return _poses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimClip::loadURL(const QString& url) {
|
||||||
|
auto animCache = DependencyManager::get<AnimationCache>();
|
||||||
|
_networkAnim = animCache->getAnimation(url);
|
||||||
|
_url = url;
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,8 @@ class AnimClip : public AnimNode {
|
||||||
public:
|
public:
|
||||||
friend class AnimTests;
|
friend class AnimTests;
|
||||||
|
|
||||||
AnimClip(const QString& id, const QString& url, float startFrame, float endFrame, float timeScale, bool loopFlag, bool mirrorFlag);
|
AnimClip(const QString& id, const QString& url, float startFrame, float endFrame, float timeScale, bool loopFlag, bool mirrorFlag,
|
||||||
|
AnimBlendType blendType, const QString& baseURL, float baseFrame);
|
||||||
virtual ~AnimClip() override;
|
virtual ~AnimClip() override;
|
||||||
|
|
||||||
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override;
|
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override;
|
||||||
|
@ -52,19 +53,20 @@ public:
|
||||||
void setMirrorFlag(bool mirrorFlag) { _mirrorFlag = mirrorFlag; }
|
void setMirrorFlag(bool mirrorFlag) { _mirrorFlag = mirrorFlag; }
|
||||||
|
|
||||||
float getFrame() const { return _frame; }
|
float getFrame() const { return _frame; }
|
||||||
|
|
||||||
void loadURL(const QString& url);
|
void loadURL(const QString& url);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void setCurrentFrameInternal(float frame) override;
|
virtual void setCurrentFrameInternal(float frame) override;
|
||||||
|
|
||||||
void copyFromNetworkAnim();
|
|
||||||
void buildMirrorAnim();
|
void buildMirrorAnim();
|
||||||
|
|
||||||
// for AnimDebugDraw rendering
|
// for AnimDebugDraw rendering
|
||||||
virtual const AnimPoseVec& getPosesInternal() const override;
|
virtual const AnimPoseVec& getPosesInternal() const override;
|
||||||
|
|
||||||
AnimationPointer _networkAnim;
|
AnimationPointer _networkAnim;
|
||||||
|
AnimationPointer _baseNetworkAnim;
|
||||||
|
|
||||||
AnimPoseVec _poses;
|
AnimPoseVec _poses;
|
||||||
|
|
||||||
// _anim[frame][joint]
|
// _anim[frame][joint]
|
||||||
|
@ -78,6 +80,9 @@ protected:
|
||||||
bool _loopFlag;
|
bool _loopFlag;
|
||||||
bool _mirrorFlag;
|
bool _mirrorFlag;
|
||||||
float _frame;
|
float _frame;
|
||||||
|
AnimBlendType _blendType;
|
||||||
|
QString _baseURL;
|
||||||
|
float _baseFrame;
|
||||||
|
|
||||||
QString _startFrameVar;
|
QString _startFrameVar;
|
||||||
QString _endFrameVar;
|
QString _endFrameVar;
|
||||||
|
|
|
@ -34,6 +34,13 @@ enum class AnimNodeType {
|
||||||
NumTypes
|
NumTypes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AnimBlendType {
|
||||||
|
AnimBlendType_Normal,
|
||||||
|
AnimBlendType_AddRelative,
|
||||||
|
AnimBlendType_AddAbsolute,
|
||||||
|
AnimBlendType_NumTypes
|
||||||
|
};
|
||||||
|
|
||||||
class AnimContext {
|
class AnimContext {
|
||||||
public:
|
public:
|
||||||
AnimContext() {}
|
AnimContext() {}
|
||||||
|
|
|
@ -161,6 +161,19 @@ static EasingType stringToEasingType(const QString& str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AnimBlendType stringToAnimBlendType(const QString& str) {
|
||||||
|
if (str == "normal") {
|
||||||
|
return AnimBlendType_Normal;
|
||||||
|
} else if (str == "addRelative") {
|
||||||
|
return AnimBlendType_AddRelative;
|
||||||
|
} else if (str == "addAbsolute") {
|
||||||
|
return AnimBlendType_AddAbsolute;
|
||||||
|
} else {
|
||||||
|
return AnimBlendType_NumTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char* animManipulatorJointVarTypeToString(AnimManipulator::JointVar::Type type) {
|
static const char* animManipulatorJointVarTypeToString(AnimManipulator::JointVar::Type type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AnimManipulator::JointVar::Type::Absolute: return "absolute";
|
case AnimManipulator::JointVar::Type::Absolute: return "absolute";
|
||||||
|
@ -374,6 +387,9 @@ static AnimNode::Pointer loadClipNode(const QJsonObject& jsonObj, const QString&
|
||||||
READ_FLOAT(timeScale, jsonObj, id, jsonUrl, nullptr);
|
READ_FLOAT(timeScale, jsonObj, id, jsonUrl, nullptr);
|
||||||
READ_BOOL(loopFlag, jsonObj, id, jsonUrl, nullptr);
|
READ_BOOL(loopFlag, jsonObj, id, jsonUrl, nullptr);
|
||||||
READ_OPTIONAL_BOOL(mirrorFlag, jsonObj, false);
|
READ_OPTIONAL_BOOL(mirrorFlag, jsonObj, false);
|
||||||
|
READ_OPTIONAL_STRING(blendType, jsonObj);
|
||||||
|
READ_OPTIONAL_STRING(baseURL, jsonObj);
|
||||||
|
READ_OPTIONAL_FLOAT(baseFrame, jsonObj, 0.0f);
|
||||||
|
|
||||||
READ_OPTIONAL_STRING(startFrameVar, jsonObj);
|
READ_OPTIONAL_STRING(startFrameVar, jsonObj);
|
||||||
READ_OPTIONAL_STRING(endFrameVar, jsonObj);
|
READ_OPTIONAL_STRING(endFrameVar, jsonObj);
|
||||||
|
@ -381,11 +397,22 @@ static AnimNode::Pointer loadClipNode(const QJsonObject& jsonObj, const QString&
|
||||||
READ_OPTIONAL_STRING(loopFlagVar, jsonObj);
|
READ_OPTIONAL_STRING(loopFlagVar, jsonObj);
|
||||||
READ_OPTIONAL_STRING(mirrorFlagVar, jsonObj);
|
READ_OPTIONAL_STRING(mirrorFlagVar, jsonObj);
|
||||||
|
|
||||||
|
|
||||||
// animation urls can be relative to the containing url document.
|
// animation urls can be relative to the containing url document.
|
||||||
auto tempUrl = QUrl(url);
|
auto tempUrl = QUrl(url);
|
||||||
tempUrl = jsonUrl.resolved(tempUrl);
|
tempUrl = jsonUrl.resolved(tempUrl);
|
||||||
|
|
||||||
auto node = std::make_shared<AnimClip>(id, tempUrl.toString(), startFrame, endFrame, timeScale, loopFlag, mirrorFlag);
|
// AJT:
|
||||||
|
AnimBlendType blendTypeEnum = AnimBlendType_Normal; // default value
|
||||||
|
if (!blendType.isEmpty()) {
|
||||||
|
blendTypeEnum = stringToAnimBlendType(blendType);
|
||||||
|
if (blendTypeEnum == AnimBlendType_NumTypes) {
|
||||||
|
qCCritical(animation) << "AnimNodeLoader, bad blendType on clip, id = " << id;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto node = std::make_shared<AnimClip>(id, tempUrl.toString(), startFrame, endFrame, timeScale, loopFlag, mirrorFlag, blendTypeEnum, baseURL, baseFrame);
|
||||||
|
|
||||||
if (!startFrameVar.isEmpty()) {
|
if (!startFrameVar.isEmpty()) {
|
||||||
node->setStartFrameVar(startFrameVar);
|
node->setStartFrameVar(startFrameVar);
|
||||||
|
@ -409,10 +436,19 @@ static AnimNode::Pointer loadClipNode(const QJsonObject& jsonObj, const QString&
|
||||||
static AnimNode::Pointer loadBlendLinearNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) {
|
static AnimNode::Pointer loadBlendLinearNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) {
|
||||||
|
|
||||||
READ_FLOAT(alpha, jsonObj, id, jsonUrl, nullptr);
|
READ_FLOAT(alpha, jsonObj, id, jsonUrl, nullptr);
|
||||||
|
READ_OPTIONAL_STRING(blendType, jsonObj);
|
||||||
READ_OPTIONAL_STRING(alphaVar, jsonObj);
|
READ_OPTIONAL_STRING(alphaVar, jsonObj);
|
||||||
|
|
||||||
auto node = std::make_shared<AnimBlendLinear>(id, alpha);
|
AnimBlendType blendTypeEnum = AnimBlendType_Normal; // default value
|
||||||
|
if (!blendType.isEmpty()) {
|
||||||
|
blendTypeEnum = stringToAnimBlendType(blendType);
|
||||||
|
if (blendTypeEnum == AnimBlendType_NumTypes) {
|
||||||
|
qCCritical(animation) << "AnimNodeLoader, bad blendType on blendLinear, id = " << id;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto node = std::make_shared<AnimBlendLinear>(id, alpha, blendTypeEnum);
|
||||||
|
|
||||||
if (!alphaVar.isEmpty()) {
|
if (!alphaVar.isEmpty()) {
|
||||||
node->setAlphaVar(alphaVar);
|
node->setAlphaVar(alphaVar);
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
// TODO: use restrict keyword
|
// TODO: use restrict keyword
|
||||||
// TODO: excellent candidate for simd vectorization.
|
// TODO: excellent candidate for simd vectorization.
|
||||||
|
|
||||||
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) {
|
||||||
for (size_t i = 0; i < numPoses; i++) {
|
for (size_t i = 0; i < numPoses; i++) {
|
||||||
const AnimPose& aPose = a[i];
|
const AnimPose& aPose = a[i];
|
||||||
|
@ -27,6 +26,29 @@ void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// additive blend
|
||||||
|
void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result) {
|
||||||
|
|
||||||
|
const glm::quat identity = glm::quat();
|
||||||
|
for (size_t i = 0; i < numPoses; i++) {
|
||||||
|
const AnimPose& aPose = a[i];
|
||||||
|
const AnimPose& bPose = b[i];
|
||||||
|
|
||||||
|
result[i].scale() = lerp(aPose.scale(), bPose.scale(), alpha);
|
||||||
|
|
||||||
|
// ensure that delta has the same "polarity" as the identity quat.
|
||||||
|
// we don't need to do a full dot product, just sign of w is sufficient.
|
||||||
|
glm::quat delta = bPose.rot();
|
||||||
|
if (delta.w < 0.0f) {
|
||||||
|
delta = -delta;
|
||||||
|
}
|
||||||
|
delta = glm::lerp(identity, delta, alpha);
|
||||||
|
result[i].rot() = glm::normalize(delta * aPose.rot());
|
||||||
|
|
||||||
|
result[i].trans() = aPose.trans() + (alpha * bPose.trans());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glm::quat averageQuats(size_t numQuats, const glm::quat* quats) {
|
glm::quat averageQuats(size_t numQuats, const glm::quat* quats) {
|
||||||
if (numQuats == 0) {
|
if (numQuats == 0) {
|
||||||
return glm::quat();
|
return glm::quat();
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
// 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);
|
||||||
|
|
||||||
|
// additive blending
|
||||||
|
void blendAdd(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, AnimPose* result);
|
||||||
|
|
||||||
glm::quat averageQuats(size_t numQuats, const glm::quat* quats);
|
glm::quat averageQuats(size_t numQuats, const glm::quat* quats);
|
||||||
|
|
||||||
float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag,
|
float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag,
|
||||||
|
|
|
@ -564,7 +564,7 @@ void Rig::overrideRoleAnimation(const QString& role, const QString& url, float f
|
||||||
_origRoleAnimations[role] = node;
|
_origRoleAnimations[role] = node;
|
||||||
const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
|
const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
|
||||||
float timeScale = fps / REFERENCE_FRAMES_PER_SECOND;
|
float timeScale = fps / REFERENCE_FRAMES_PER_SECOND;
|
||||||
auto clipNode = std::make_shared<AnimClip>(role, url, firstFrame, lastFrame, timeScale, loop, false);
|
auto clipNode = std::make_shared<AnimClip>(role, url, firstFrame, lastFrame, timeScale, loop, false, AnimBlendType_Normal, "", 0.0f);
|
||||||
_roleAnimStates[role] = { role, url, fps, loop, firstFrame, lastFrame };
|
_roleAnimStates[role] = { role, url, fps, loop, firstFrame, lastFrame };
|
||||||
AnimNode::Pointer parent = node->getParent();
|
AnimNode::Pointer parent = node->getParent();
|
||||||
parent->replaceChild(node, clipNode);
|
parent->replaceChild(node, clipNode);
|
||||||
|
@ -1973,7 +1973,7 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
|
||||||
|
|
||||||
// TODO: does not properly handle avatar scale.
|
// TODO: does not properly handle avatar scale.
|
||||||
|
|
||||||
if (isIndexValid(index)) {
|
if (isIndexValid(index) && !_internalPoseSet._overrideFlags[index]) {
|
||||||
const glm::mat4 rigToWorld = createMatFromQuatAndPos(modelRotation, modelTranslation);
|
const glm::mat4 rigToWorld = createMatFromQuatAndPos(modelRotation, modelTranslation);
|
||||||
const glm::mat4 worldToRig = glm::inverse(rigToWorld);
|
const glm::mat4 worldToRig = glm::inverse(rigToWorld);
|
||||||
const glm::vec3 lookAtVector = glm::normalize(transformPoint(worldToRig, lookAtSpot) - _internalPoseSet._absolutePoses[index].trans());
|
const glm::vec3 lookAtVector = glm::normalize(transformPoint(worldToRig, lookAtSpot) - _internalPoseSet._absolutePoses[index].trans());
|
||||||
|
|
|
@ -72,7 +72,6 @@
|
||||||
#include "EntityTreeRenderer.h"
|
#include "EntityTreeRenderer.h"
|
||||||
|
|
||||||
#include "RenderablePolyVoxEntityItem.h"
|
#include "RenderablePolyVoxEntityItem.h"
|
||||||
#include "EntityEditPacketSender.h"
|
|
||||||
#include "PhysicalEntitySimulation.h"
|
#include "PhysicalEntitySimulation.h"
|
||||||
|
|
||||||
const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
|
const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
|
||||||
|
@ -83,30 +82,60 @@ const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
|
||||||
_voxelData -- compressed QByteArray representation of which voxels have which values
|
_voxelData -- compressed QByteArray representation of which voxels have which values
|
||||||
_volData -- datastructure from the PolyVox library which holds which voxels have which values
|
_volData -- datastructure from the PolyVox library which holds which voxels have which values
|
||||||
_mesh -- renderable representation of the voxels
|
_mesh -- renderable representation of the voxels
|
||||||
_shape -- used for bullet collisions
|
_shape -- used for bullet (physics) collisions
|
||||||
|
|
||||||
Each one depends on the one before it, except that _voxelData is set from _volData if a script edits the voxels.
|
Each one depends on the one before it, except that _voxelData is set from _volData if a script edits the voxels.
|
||||||
|
|
||||||
There are booleans to indicate that something has been updated and the dependents now need to be updated.
|
There are booleans to indicate that something has been updated and the dependents now need to be updated.
|
||||||
|
_meshReady -- do we have something to give scripts that ask for the mesh?
|
||||||
|
_voxelDataDirty -- do we need to uncompress data and expand it into _volData?
|
||||||
|
_volDataDirty -- does recomputeMesh need to be called?
|
||||||
|
_shapeReady -- are we ready to tell bullet our shape?
|
||||||
|
|
||||||
_voxelDataDirty
|
|
||||||
_volDataDirty
|
|
||||||
_meshDirty
|
|
||||||
|
|
||||||
In RenderablePolyVoxEntityItem::render, these flags are checked and changes are propagated along the chain.
|
Here is a simplified diagram of the state machine implemented in RenderablePolyVoxEntityItem::update
|
||||||
decompressVolumeData() is called to decompress _voxelData into _volData. recomputeMesh() is called to invoke the
|
|
||||||
polyVox surface extractor to create _mesh (as well as set Simulation _flags). Because Simulation::DIRTY_SHAPE
|
|
||||||
is set, isReadyToComputeShape() gets called and _shape is created either from _volData or _shape, depending on
|
|
||||||
the surface style.
|
|
||||||
|
|
||||||
When a script changes _volData, compressVolumeDataAndSendEditPacket is called to update _voxelData and to
|
+-------------------+
|
||||||
send a packet to the entity-server.
|
| |
|
||||||
|
| |
|
||||||
|
| volDataDirty | voxelDataDirty
|
||||||
|
| +--v--+
|
||||||
|
| +------+Ready+--------+
|
||||||
|
| | +-----+ |
|
||||||
|
| | |
|
||||||
|
| +-----v----+ +------v------+
|
||||||
|
| |BakingMesh| |Uncompressing|
|
||||||
|
| +-----+----+ +------+------+
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| +---v-------+ +-------v------------+
|
||||||
|
| |Compressing| |BakingMeshNoCompress|
|
||||||
|
| +---------+-+ ++-------------------+
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| +-v--------v+
|
||||||
|
| |BakingShape|
|
||||||
|
| +-----+-----+
|
||||||
|
| |
|
||||||
|
+-------------------+
|
||||||
|
|
||||||
decompressVolumeData, recomputeMesh, computeShapeInfoWorker, and compressVolumeDataAndSendEditPacket are too expensive
|
|
||||||
to run on a thread that has other things to do. These use QtConcurrent::run to spawn a thread. As each thread
|
|
||||||
finishes, it adjusts the dirty flags so that the next call to render() will kick off the next step.
|
|
||||||
|
|
||||||
polyvoxes are designed to seemlessly fit up against neighbors. If voxels go right up to the edge of polyvox,
|
The work for each step is done on temporary worker threads. The PolyVox entity will update _updateNeeded and
|
||||||
|
enable or disable update calls on the entity, depending on if there is more work to do.
|
||||||
|
|
||||||
|
From the 'Ready' state, if we receive an update from the network, _voxelDataDirty will be set true. We
|
||||||
|
uncompress the received data, bake the mesh (for the render-engine's benefit), and then compute the shape
|
||||||
|
(for the physics-engine's benefit). This is the right-hand side of the diagram.
|
||||||
|
|
||||||
|
From the 'Ready' state, if a script changes a voxel, _volDataDirty will be set true. We bake the mesh,
|
||||||
|
compress the voxels into a new _voxelData, and transmit the new _voxelData to the entity-server. We then
|
||||||
|
bake the shape. This is the left-hand side of the diagram.
|
||||||
|
|
||||||
|
The actual state machine is more complicated than the diagram, because it's possible for _volDataDirty or
|
||||||
|
_voxelDataDirty to be set true while worker threads are attempting to bake meshes or shapes. If this happens,
|
||||||
|
we jump back to a higher point in the diagram to avoid wasting effort.
|
||||||
|
|
||||||
|
PolyVoxes are designed to seemlessly fit up against neighbors. If voxels go right up to the edge of polyvox,
|
||||||
the resulting mesh wont be closed -- the library assumes you'll have another polyvox next to it to continue the
|
the resulting mesh wont be closed -- the library assumes you'll have another polyvox next to it to continue the
|
||||||
mesh.
|
mesh.
|
||||||
|
|
||||||
|
@ -114,8 +143,8 @@ const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
|
||||||
previously mentioned gaps along the edges.
|
previously mentioned gaps along the edges.
|
||||||
|
|
||||||
Non-edged polyvox entities can be told about their neighbors in all 6 cardinal directions. On the positive
|
Non-edged polyvox entities can be told about their neighbors in all 6 cardinal directions. On the positive
|
||||||
edges of the polyvox, the values are set from the (negative edge of) relevant neighbor so that their meshes
|
edges of the polyvox, the values are set from the (negative edge of the) relevant neighbor so that their meshes
|
||||||
knit together. This is handled by bonkNeighbors and copyUpperEdgesFromNeighbors. In these functions, variable
|
knit together. This is handled by tellNeighborsToRecopyEdges and copyUpperEdgesFromNeighbors. In these functions, variable
|
||||||
names have XP for x-positive, XN x-negative, etc.
|
names have XP for x-positive, XN x-negative, etc.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -140,7 +169,8 @@ EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entit
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID) : PolyVoxEntityItem(entityItemID) { }
|
RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID) : PolyVoxEntityItem(entityItemID) {
|
||||||
|
}
|
||||||
|
|
||||||
RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() {
|
RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
|
@ -165,11 +195,12 @@ bool isEdged(PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::setVoxelData(const QByteArray& voxelData) {
|
void RenderablePolyVoxEntityItem::setVoxelData(const QByteArray& voxelData) {
|
||||||
// compressed voxel information from the entity-server
|
// accept compressed voxel information from the entity-server
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
if (_voxelData != voxelData) {
|
if (_voxelData != voxelData) {
|
||||||
_voxelData = voxelData;
|
_voxelData = voxelData;
|
||||||
_voxelDataDirty = true;
|
_voxelDataDirty = true;
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -189,21 +220,22 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
|
||||||
bool willBeEdged = isEdged(voxelSurfaceStyle);
|
bool willBeEdged = isEdged(voxelSurfaceStyle);
|
||||||
|
|
||||||
if (wasEdged != willBeEdged) {
|
if (wasEdged != willBeEdged) {
|
||||||
_volDataDirty = true;
|
|
||||||
_volData.reset();
|
_volData.reset();
|
||||||
_voxelSurfaceStyle = voxelSurfaceStyle;
|
|
||||||
_voxelDataDirty = true;
|
_voxelDataDirty = true;
|
||||||
volSizeChanged = true;
|
volSizeChanged = true;
|
||||||
} else {
|
|
||||||
_volDataDirty = true;
|
|
||||||
_voxelSurfaceStyle = voxelSurfaceStyle;
|
|
||||||
}
|
}
|
||||||
|
_voxelSurfaceStyle = voxelSurfaceStyle;
|
||||||
|
startUpdates();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (volSizeChanged) {
|
if (volSizeChanged) {
|
||||||
// setVoxelVolumeSize will re-alloc _volData with the right size
|
// setVoxelVolumeSize will re-alloc _volData with the right size
|
||||||
setVoxelVolumeSize(_voxelVolumeSize);
|
setVoxelVolumeSize(_voxelVolumeSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateFromNeighborXEdge = _updateFromNeighborYEdge = _updateFromNeighborZEdge = true;
|
||||||
|
tellNeighborsToRecopyEdges(true);
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
|
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
|
||||||
|
@ -262,9 +294,6 @@ bool RenderablePolyVoxEntityItem::setVoxel(const ivec3& v, uint8_t toValue) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
result = setVoxelInternal(v, toValue);
|
result = setVoxelInternal(v, toValue);
|
||||||
});
|
});
|
||||||
if (result) {
|
|
||||||
compressVolumeDataAndSendEditPacket();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -311,9 +340,6 @@ bool RenderablePolyVoxEntityItem::setAll(uint8_t toValue) {
|
||||||
result |= setVoxelInternal(v, toValue);
|
result |= setVoxelInternal(v, toValue);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (result) {
|
|
||||||
compressVolumeDataAndSendEditPacket();
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,9 +362,6 @@ bool RenderablePolyVoxEntityItem::setCuboid(const glm::vec3& lowPosition, const
|
||||||
result |= setVoxelInternal(v, toValue);
|
result |= setVoxelInternal(v, toValue);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (result) {
|
|
||||||
compressVolumeDataAndSendEditPacket();
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,9 +397,6 @@ bool RenderablePolyVoxEntityItem::setSphereInVolume(const vec3& center, float ra
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
|
||||||
compressVolumeDataAndSendEditPacket();
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,9 +454,6 @@ bool RenderablePolyVoxEntityItem::setSphere(const vec3& centerWorldCoords, float
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
|
||||||
compressVolumeDataAndSendEditPacket();
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,9 +499,6 @@ bool RenderablePolyVoxEntityItem::setCapsule(const vec3& startWorldCoords, const
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
|
||||||
compressVolumeDataAndSendEditPacket();
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,8 +724,9 @@ ShapeType RenderablePolyVoxEntityItem::getShapeType() const {
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::setRegistrationPoint(const glm::vec3& value) {
|
void RenderablePolyVoxEntityItem::setRegistrationPoint(const glm::vec3& value) {
|
||||||
if (value != _registrationPoint) {
|
if (value != _registrationPoint) {
|
||||||
_meshDirty = true;
|
_shapeReady = false;
|
||||||
EntityItem::setRegistrationPoint(value);
|
EntityItem::setRegistrationPoint(value);
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,15 +736,11 @@ bool RenderablePolyVoxEntityItem::isReadyToComputeShape() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we determine if we are ready to compute the physics shape by actually doing so.
|
bool result;
|
||||||
// if _voxelDataDirty or _volDataDirty is set, don't do this yet -- wait for their
|
withReadLock([&] {
|
||||||
// threads to finish before creating the collision shape.
|
result = _shapeReady;
|
||||||
if (_meshDirty && !_voxelDataDirty && !_volDataDirty) {
|
});
|
||||||
const_cast<RenderablePolyVoxEntityItem*>(this)->_meshDirty = false;
|
return result;
|
||||||
const_cast<RenderablePolyVoxEntityItem*>(this)->computeShapeInfoWorker();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
|
void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
|
@ -739,33 +750,155 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the shape was actually computed in isReadyToComputeShape. Just hand it off, here.
|
withReadLock([&] {
|
||||||
withWriteLock([&] {
|
|
||||||
info = _shapeInfo;
|
info = _shapeInfo;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderablePolyVoxEntityItem::updateDependents() {
|
void RenderablePolyVoxEntityItem::changeUpdates(bool value) {
|
||||||
bool voxelDataDirty;
|
if (_updateNeeded != value) {
|
||||||
bool volDataDirty;
|
EntityTreePointer entityTree = getTree();
|
||||||
|
if (entityTree) {
|
||||||
|
EntitySimulationPointer simulation = entityTree->getSimulation();
|
||||||
|
if (simulation) {
|
||||||
|
_updateNeeded = value;
|
||||||
|
_flags |= Simulation::DIRTY_UPDATEABLE;
|
||||||
|
simulation->changeEntity(getThisPointer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::startUpdates() {
|
||||||
|
changeUpdates(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::stopUpdates() {
|
||||||
|
changeUpdates(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::update(const quint64& now) {
|
||||||
|
bool doRecomputeMesh { false };
|
||||||
|
bool doUncompress { false };
|
||||||
|
bool doCompress { false };
|
||||||
|
bool doRecomputeShape { false };
|
||||||
|
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
voxelDataDirty = _voxelDataDirty;
|
tellNeighborsToRecopyEdges(false);
|
||||||
volDataDirty = _volDataDirty;
|
|
||||||
if (_voxelDataDirty) {
|
switch (_state) {
|
||||||
_voxelDataDirty = false;
|
|
||||||
} else if (_volDataDirty) {
|
case PolyVoxState::Ready: {
|
||||||
_volDataDirty = false;
|
if (_volDataDirty) {
|
||||||
} else {
|
_volDataDirty = _voxelDataDirty = false;
|
||||||
_meshReady = true;
|
_state = PolyVoxState::BakingMesh;
|
||||||
|
doRecomputeMesh = true;
|
||||||
|
} else if (_voxelDataDirty) {
|
||||||
|
_voxelDataDirty = false;
|
||||||
|
_state = PolyVoxState::Uncompressing;
|
||||||
|
doUncompress = true;
|
||||||
|
} else {
|
||||||
|
copyUpperEdgesFromNeighbors();
|
||||||
|
if (!_volDataDirty && !_voxelDataDirty) {
|
||||||
|
// nothing to do
|
||||||
|
stopUpdates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PolyVoxState::Uncompressing: {
|
||||||
|
break; // wait
|
||||||
|
}
|
||||||
|
case PolyVoxState::UncompressingFinished: {
|
||||||
|
if (_volDataDirty) {
|
||||||
|
_volDataDirty = _voxelDataDirty = false;
|
||||||
|
_state = PolyVoxState::BakingMeshNoCompress;
|
||||||
|
doRecomputeMesh = true;
|
||||||
|
} else if (_voxelDataDirty) {
|
||||||
|
_voxelDataDirty = false;
|
||||||
|
// _voxelData changed while we were uncompressing the previous version, uncompress again
|
||||||
|
_state = PolyVoxState::Uncompressing;
|
||||||
|
doUncompress = true;
|
||||||
|
} else {
|
||||||
|
_state = PolyVoxState::Ready;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PolyVoxState::BakingMesh: {
|
||||||
|
break; // wait
|
||||||
|
}
|
||||||
|
case PolyVoxState::BakingMeshFinished: {
|
||||||
|
if (_volDataDirty) {
|
||||||
|
_volDataDirty = _voxelDataDirty = false;
|
||||||
|
_state = PolyVoxState::BakingMesh;
|
||||||
|
// a local edit happened while we were baking the mesh. rebake mesh...
|
||||||
|
doRecomputeMesh = true;
|
||||||
|
} else if (_voxelDataDirty) {
|
||||||
|
_voxelDataDirty = false;
|
||||||
|
// we received a change from the wire while baking the mesh.
|
||||||
|
_state = PolyVoxState::Uncompressing;
|
||||||
|
doUncompress = true;
|
||||||
|
} else {
|
||||||
|
_state = PolyVoxState::Compressing;
|
||||||
|
doCompress = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PolyVoxState::BakingMeshNoCompress: {
|
||||||
|
break; // wait
|
||||||
|
}
|
||||||
|
case PolyVoxState::BakingMeshNoCompressFinished: {
|
||||||
|
if (_volDataDirty) {
|
||||||
|
_volDataDirty = _voxelDataDirty = false;
|
||||||
|
_state = PolyVoxState::BakingMesh;
|
||||||
|
// a local edit happened while we were baking the mesh. rebake mesh...
|
||||||
|
doRecomputeMesh = true;
|
||||||
|
} else if (_voxelDataDirty) {
|
||||||
|
_voxelDataDirty = false;
|
||||||
|
// we received a change from the wire while baking the mesh.
|
||||||
|
_state = PolyVoxState::Uncompressing;
|
||||||
|
doUncompress = true;
|
||||||
|
} else {
|
||||||
|
_state = PolyVoxState::BakingShape;
|
||||||
|
doRecomputeShape = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PolyVoxState::Compressing: {
|
||||||
|
break; // wait
|
||||||
|
}
|
||||||
|
case PolyVoxState::CompressingFinished: {
|
||||||
|
_state = PolyVoxState::BakingShape;
|
||||||
|
doRecomputeShape = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PolyVoxState::BakingShape: {
|
||||||
|
break; // wait
|
||||||
|
}
|
||||||
|
case PolyVoxState::BakingShapeFinished: {
|
||||||
|
_state = PolyVoxState::Ready;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (voxelDataDirty) {
|
|
||||||
decompressVolumeData();
|
if (doRecomputeMesh) {
|
||||||
} else if (volDataDirty) {
|
|
||||||
recomputeMesh();
|
recomputeMesh();
|
||||||
}
|
}
|
||||||
|
if (doUncompress) {
|
||||||
return !volDataDirty;
|
uncompressVolumeData();
|
||||||
|
}
|
||||||
|
if (doCompress) {
|
||||||
|
compressVolumeDataAndSendEditPacket();
|
||||||
|
}
|
||||||
|
if (doRecomputeShape) {
|
||||||
|
computeShapeInfoWorker();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::setVoxelVolumeSize(const glm::vec3& voxelVolumeSize) {
|
void RenderablePolyVoxEntityItem::setVoxelVolumeSize(const glm::vec3& voxelVolumeSize) {
|
||||||
|
@ -782,6 +915,8 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(const glm::vec3& voxelVolum
|
||||||
_voxelVolumeSize = voxelVolumeSize;
|
_voxelVolumeSize = voxelVolumeSize;
|
||||||
_volData.reset();
|
_volData.reset();
|
||||||
_onCount = 0;
|
_onCount = 0;
|
||||||
|
_updateFromNeighborXEdge = _updateFromNeighborYEdge = _updateFromNeighborZEdge = true;
|
||||||
|
startUpdates();
|
||||||
|
|
||||||
static const PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
|
static const PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
|
||||||
PolyVox::Vector3DInt32 highCorner;
|
PolyVox::Vector3DInt32 highCorner;
|
||||||
|
@ -806,6 +941,8 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(const glm::vec3& voxelVolum
|
||||||
// having the "outside of voxel-space" value be 255 has helped me notice some problems.
|
// having the "outside of voxel-space" value be 255 has helped me notice some problems.
|
||||||
_volData->setBorderValue(255);
|
_volData->setBorderValue(255);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tellNeighborsToRecopyEdges(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inUserBounds(const std::shared_ptr<PolyVox::SimpleVolume<uint8_t>> vol,
|
bool inUserBounds(const std::shared_ptr<PolyVox::SimpleVolume<uint8_t>> vol,
|
||||||
|
@ -853,32 +990,38 @@ uint8_t RenderablePolyVoxEntityItem::getVoxelInternal(const ivec3& v) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::setVoxelMarkNeighbors(int x, int y, int z, uint8_t toValue) {
|
||||||
|
_volData->setVoxelAt(x, y, z, toValue);
|
||||||
|
if (x == 0) {
|
||||||
|
_neighborXNeedsUpdate = true;
|
||||||
|
startUpdates();
|
||||||
|
}
|
||||||
|
if (y == 0) {
|
||||||
|
_neighborYNeedsUpdate = true;
|
||||||
|
startUpdates();
|
||||||
|
}
|
||||||
|
if (z == 0) {
|
||||||
|
_neighborZNeedsUpdate = true;
|
||||||
|
startUpdates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool RenderablePolyVoxEntityItem::setVoxelInternal(const ivec3& v, uint8_t toValue) {
|
bool RenderablePolyVoxEntityItem::setVoxelInternal(const ivec3& v, uint8_t toValue) {
|
||||||
// set a voxel without recompressing the voxel data. This assumes that the caller has
|
// set a voxel without recompressing the voxel data. This assumes that the caller has write-locked the entity.
|
||||||
// write-locked the entity.
|
bool result = updateOnCount(v, toValue);
|
||||||
bool result = false;
|
if (result) {
|
||||||
if (!inUserBounds(_volData, _voxelSurfaceStyle, v)) {
|
if (isEdged()) {
|
||||||
return result;
|
setVoxelMarkNeighbors(v.x + 1, v.y + 1, v.z + 1, toValue);
|
||||||
|
} else {
|
||||||
|
setVoxelMarkNeighbors(v.x, v.y, v.z, toValue);
|
||||||
|
}
|
||||||
|
_volDataDirty = true;
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
result = updateOnCount(v, toValue);
|
|
||||||
|
|
||||||
if (isEdged()) {
|
|
||||||
_volData->setVoxelAt(v.x + 1, v.y + 1, v.z + 1, toValue);
|
|
||||||
} else {
|
|
||||||
_volData->setVoxelAt(v.x, v.y, v.z, toValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glm::any(glm::equal(ivec3(0), v))) {
|
|
||||||
_neighborsNeedUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_volDataDirty |= result;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool RenderablePolyVoxEntityItem::updateOnCount(const ivec3& v, uint8_t toValue) {
|
bool RenderablePolyVoxEntityItem::updateOnCount(const ivec3& v, uint8_t toValue) {
|
||||||
// keep _onCount up to date
|
// keep _onCount up to date
|
||||||
if (!inUserBounds(_volData, _voxelSurfaceStyle, v)) {
|
if (!inUserBounds(_volData, _voxelSurfaceStyle, v)) {
|
||||||
|
@ -902,7 +1045,7 @@ bool RenderablePolyVoxEntityItem::updateOnCount(const ivec3& v, uint8_t toValue)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
void RenderablePolyVoxEntityItem::uncompressVolumeData() {
|
||||||
// take compressed data and expand it into _volData.
|
// take compressed data and expand it into _volData.
|
||||||
QByteArray voxelData;
|
QByteArray voxelData;
|
||||||
auto entity = std::static_pointer_cast<RenderablePolyVoxEntityItem>(getThisPointer());
|
auto entity = std::static_pointer_cast<RenderablePolyVoxEntityItem>(getThisPointer());
|
||||||
|
@ -921,9 +1064,9 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
||||||
if (voxelXSize == 0 || voxelXSize > PolyVoxEntityItem::MAX_VOXEL_DIMENSION ||
|
if (voxelXSize == 0 || voxelXSize > PolyVoxEntityItem::MAX_VOXEL_DIMENSION ||
|
||||||
voxelYSize == 0 || voxelYSize > PolyVoxEntityItem::MAX_VOXEL_DIMENSION ||
|
voxelYSize == 0 || voxelYSize > PolyVoxEntityItem::MAX_VOXEL_DIMENSION ||
|
||||||
voxelZSize == 0 || voxelZSize > PolyVoxEntityItem::MAX_VOXEL_DIMENSION) {
|
voxelZSize == 0 || voxelZSize > PolyVoxEntityItem::MAX_VOXEL_DIMENSION) {
|
||||||
qCDebug(entitiesrenderer) << "voxelSize is not reasonable, skipping decompressions."
|
qCDebug(entitiesrenderer) << "voxelSize is not reasonable, skipping uncompressions."
|
||||||
<< voxelXSize << voxelYSize << voxelZSize << getName() << getID();
|
<< voxelXSize << voxelYSize << voxelZSize << getName() << getID();
|
||||||
entity->setVoxelDataDirty(false);
|
entity->setVoxelsFromData(QByteArray(1, 0), 1, 1, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int rawSize = voxelXSize * voxelYSize * voxelZSize;
|
int rawSize = voxelXSize * voxelYSize * voxelZSize;
|
||||||
|
@ -934,10 +1077,10 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
||||||
QByteArray uncompressedData = qUncompress(compressedData);
|
QByteArray uncompressedData = qUncompress(compressedData);
|
||||||
|
|
||||||
if (uncompressedData.size() != rawSize) {
|
if (uncompressedData.size() != rawSize) {
|
||||||
qCDebug(entitiesrenderer) << "PolyVox decompress -- size is (" << voxelXSize << voxelYSize << voxelZSize << ")"
|
qCDebug(entitiesrenderer) << "PolyVox uncompress -- size is (" << voxelXSize << voxelYSize << voxelZSize << ")"
|
||||||
<< "so expected uncompressed length of" << rawSize << "but length is" << uncompressedData.size()
|
<< "so expected uncompressed length of" << rawSize << "but length is" << uncompressedData.size()
|
||||||
<< getName() << getID();
|
<< getName() << getID();
|
||||||
entity->setVoxelDataDirty(false);
|
entity->setVoxelsFromData(QByteArray(1, 0), 1, 1, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -947,13 +1090,14 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::setVoxelsFromData(QByteArray uncompressedData,
|
void RenderablePolyVoxEntityItem::setVoxelsFromData(QByteArray uncompressedData,
|
||||||
quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) {
|
quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) {
|
||||||
// this accepts the payload from decompressVolumeData
|
// this accepts the payload from uncompressVolumeData
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
loop3(ivec3(0), ivec3(voxelXSize, voxelYSize, voxelZSize), [&](const ivec3& v) {
|
loop3(ivec3(0), ivec3(voxelXSize, voxelYSize, voxelZSize), [&](const ivec3& v) {
|
||||||
int uncompressedIndex = (v.z * voxelYSize * voxelXSize) + (v.y * voxelZSize) + v.x;
|
int uncompressedIndex = (v.z * voxelYSize * voxelXSize) + (v.y * voxelZSize) + v.x;
|
||||||
setVoxelInternal(v, uncompressedData[uncompressedIndex]);
|
setVoxelInternal(v, uncompressedData[uncompressedIndex]);
|
||||||
});
|
});
|
||||||
_volDataDirty = true;
|
|
||||||
|
_state = PolyVoxState::UncompressingFinished;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -972,10 +1116,7 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() {
|
||||||
voxelZSize = _voxelVolumeSize.z;
|
voxelZSize = _voxelVolumeSize.z;
|
||||||
});
|
});
|
||||||
|
|
||||||
EntityTreeElementPointer element = getElement();
|
QtConcurrent::run([voxelXSize, voxelYSize, voxelZSize, entity] {
|
||||||
EntityTreePointer tree = element ? element->getTree() : nullptr;
|
|
||||||
|
|
||||||
QtConcurrent::run([voxelXSize, voxelYSize, voxelZSize, entity, tree] {
|
|
||||||
auto polyVoxEntity = std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity);
|
auto polyVoxEntity = std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity);
|
||||||
QByteArray uncompressedData = polyVoxEntity->volDataToArray(voxelXSize, voxelYSize, voxelZSize);
|
QByteArray uncompressedData = polyVoxEntity->volDataToArray(voxelXSize, voxelYSize, voxelZSize);
|
||||||
|
|
||||||
|
@ -992,17 +1133,37 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() {
|
||||||
// HACK -- until we have a way to allow for properties larger than MTU, don't update.
|
// HACK -- until we have a way to allow for properties larger than MTU, don't update.
|
||||||
// revert the active voxel-space to the last version that fit.
|
// revert the active voxel-space to the last version that fit.
|
||||||
qCDebug(entitiesrenderer) << "compressed voxel data is too large" << entity->getName() << entity->getID();
|
qCDebug(entitiesrenderer) << "compressed voxel data is too large" << entity->getName() << entity->getID();
|
||||||
|
|
||||||
|
const auto polyVoxEntity = std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity);
|
||||||
|
polyVoxEntity->compressVolumeDataFinished(QByteArray());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto now = usecTimestampNow();
|
std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity)->compressVolumeDataFinished(newVoxelData);
|
||||||
entity->setLastEdited(now);
|
});
|
||||||
entity->setLastBroadcast(now);
|
}
|
||||||
|
|
||||||
std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity)->setVoxelData(newVoxelData);
|
void RenderablePolyVoxEntityItem::compressVolumeDataFinished(const QByteArray& voxelData) {
|
||||||
|
// compressed voxel information from the entity-server
|
||||||
|
withWriteLock([&] {
|
||||||
|
if (voxelData.size() > 0 && _voxelData != voxelData) {
|
||||||
|
_voxelData = voxelData;
|
||||||
|
}
|
||||||
|
_state = PolyVoxState::CompressingFinished;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
setLastEdited(now);
|
||||||
|
setLastBroadcast(now);
|
||||||
|
|
||||||
|
EntityTreeElementPointer element = getElement();
|
||||||
|
EntityTreePointer tree = element ? element->getTree() : nullptr;
|
||||||
|
|
||||||
|
if (tree) {
|
||||||
tree->withReadLock([&] {
|
tree->withReadLock([&] {
|
||||||
EntityItemProperties properties = entity->getProperties();
|
EntityPropertyFlags desiredProperties;
|
||||||
|
desiredProperties.setHasProperty(PROP_VOXEL_DATA);
|
||||||
|
EntityItemProperties properties = getProperties(desiredProperties, false);
|
||||||
properties.setVoxelDataDirty();
|
properties.setVoxelDataDirty();
|
||||||
properties.setLastEdited(now);
|
properties.setLastEdited(now);
|
||||||
|
|
||||||
|
@ -1010,12 +1171,13 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() {
|
||||||
PhysicalEntitySimulationPointer peSimulation = std::static_pointer_cast<PhysicalEntitySimulation>(simulation);
|
PhysicalEntitySimulationPointer peSimulation = std::static_pointer_cast<PhysicalEntitySimulation>(simulation);
|
||||||
EntityEditPacketSender* packetSender = peSimulation ? peSimulation->getPacketSender() : nullptr;
|
EntityEditPacketSender* packetSender = peSimulation ? peSimulation->getPacketSender() : nullptr;
|
||||||
if (packetSender) {
|
if (packetSender) {
|
||||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, tree, entity->getID(), properties);
|
packetSender->queueEditEntityMessage(PacketType::EntityEdit, tree, getID(), properties);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EntityItemPointer lookUpNeighbor(EntityTreePointer tree, EntityItemID neighborID, EntityItemWeakPointer& currentWP) {
|
EntityItemPointer lookUpNeighbor(EntityTreePointer tree, EntityItemID neighborID, EntityItemWeakPointer& currentWP) {
|
||||||
EntityItemPointer current = currentWP.lock();
|
EntityItemPointer current = currentWP.lock();
|
||||||
|
|
||||||
|
@ -1064,56 +1226,103 @@ void RenderablePolyVoxEntityItem::copyUpperEdgesFromNeighbors() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto currentXPNeighbor = getXPNeighbor();
|
if (!_updateFromNeighborXEdge && !_updateFromNeighborYEdge && !_updateFromNeighborZEdge) {
|
||||||
auto currentYPNeighbor = getYPNeighbor();
|
return;
|
||||||
auto currentZPNeighbor = getZPNeighbor();
|
|
||||||
|
|
||||||
if (currentXPNeighbor && currentXPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
|
||||||
withWriteLock([&] {
|
|
||||||
for (int y = 0; y < _volData->getHeight(); y++) {
|
|
||||||
for (int z = 0; z < _volData->getDepth(); z++) {
|
|
||||||
uint8_t neighborValue = currentXPNeighbor->getVoxel({ 0, y, z });
|
|
||||||
if ((y == 0 || z == 0) && _volData->getVoxelAt(_volData->getWidth() - 1, y, z) != neighborValue) {
|
|
||||||
bonkNeighbors();
|
|
||||||
}
|
|
||||||
_volData->setVoxelAt(_volData->getWidth() - 1, y, z, neighborValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cacheNeighbors();
|
||||||
|
|
||||||
if (currentYPNeighbor && currentYPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
if (_updateFromNeighborXEdge) {
|
||||||
withWriteLock([&] {
|
_updateFromNeighborXEdge = false;
|
||||||
for (int x = 0; x < _volData->getWidth(); x++) {
|
auto currentXPNeighbor = getXPNeighbor();
|
||||||
for (int z = 0; z < _volData->getDepth(); z++) {
|
if (currentXPNeighbor && currentXPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
||||||
uint8_t neighborValue = currentYPNeighbor->getVoxel({ x, 0, z });
|
withWriteLock([&] {
|
||||||
if ((x == 0 || z == 0) && _volData->getVoxelAt(x, _volData->getHeight() - 1, z) != neighborValue) {
|
int x = _volData->getWidth() - 1;
|
||||||
bonkNeighbors();
|
|
||||||
}
|
|
||||||
_volData->setVoxelAt(x, _volData->getHeight() - 1, z, neighborValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (currentZPNeighbor && currentZPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
|
||||||
withWriteLock([&] {
|
|
||||||
for (int x = 0; x < _volData->getWidth(); x++) {
|
|
||||||
for (int y = 0; y < _volData->getHeight(); y++) {
|
for (int y = 0; y < _volData->getHeight(); y++) {
|
||||||
uint8_t neighborValue = currentZPNeighbor->getVoxel({ x, y, 0 });
|
for (int z = 0; z < _volData->getDepth(); z++) {
|
||||||
_volData->setVoxelAt(x, y, _volData->getDepth() - 1, neighborValue);
|
uint8_t neighborValue = currentXPNeighbor->getVoxel({ 0, y, z });
|
||||||
if ((x == 0 || y == 0) && _volData->getVoxelAt(x, y, _volData->getDepth() - 1) != neighborValue) {
|
uint8_t prevValue = _volData->getVoxelAt(x, y, z);
|
||||||
bonkNeighbors();
|
if (prevValue != neighborValue) {
|
||||||
|
_volData->setVoxelAt(x, y, z, neighborValue);
|
||||||
|
_volDataDirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_volData->setVoxelAt(x, y, _volData->getDepth() - 1, neighborValue);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_updateFromNeighborYEdge) {
|
||||||
|
_updateFromNeighborYEdge = false;
|
||||||
|
auto currentYPNeighbor = getYPNeighbor();
|
||||||
|
if (currentYPNeighbor && currentYPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
||||||
|
withWriteLock([&] {
|
||||||
|
int y = _volData->getHeight() - 1;
|
||||||
|
for (int x = 0; x < _volData->getWidth(); x++) {
|
||||||
|
for (int z = 0; z < _volData->getDepth(); z++) {
|
||||||
|
uint8_t neighborValue = currentYPNeighbor->getVoxel({ x, 0, z });
|
||||||
|
uint8_t prevValue = _volData->getVoxelAt(x, y, z);
|
||||||
|
if (prevValue != neighborValue) {
|
||||||
|
_volData->setVoxelAt(x, y, z, neighborValue);
|
||||||
|
_volDataDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_updateFromNeighborZEdge) {
|
||||||
|
_updateFromNeighborZEdge = false;
|
||||||
|
auto currentZPNeighbor = getZPNeighbor();
|
||||||
|
if (currentZPNeighbor && currentZPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
||||||
|
withWriteLock([&] {
|
||||||
|
int z = _volData->getDepth() - 1;
|
||||||
|
for (int x = 0; x < _volData->getWidth(); x++) {
|
||||||
|
for (int y = 0; y < _volData->getHeight(); y++) {
|
||||||
|
uint8_t neighborValue = currentZPNeighbor->getVoxel({ x, y, 0 });
|
||||||
|
uint8_t prevValue = _volData->getVoxelAt(x, y, z);
|
||||||
|
if (prevValue != neighborValue) {
|
||||||
|
_volData->setVoxelAt(x, y, z, neighborValue);
|
||||||
|
_volDataDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::tellNeighborsToRecopyEdges(bool force) {
|
||||||
|
// if this polyvox has changed any of its voxels with a zero coord (in x, y, or z) notify neighbors, if there are any
|
||||||
|
if (force || _neighborXNeedsUpdate || _neighborYNeedsUpdate || _neighborZNeedsUpdate) {
|
||||||
|
cacheNeighbors();
|
||||||
|
|
||||||
|
if (force || _neighborXNeedsUpdate) {
|
||||||
|
_neighborXNeedsUpdate = false;
|
||||||
|
auto currentXNNeighbor = getXNNeighbor();
|
||||||
|
if (currentXNNeighbor) {
|
||||||
|
currentXNNeighbor->neighborXEdgeChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (force || _neighborYNeedsUpdate) {
|
||||||
|
_neighborYNeedsUpdate = false;
|
||||||
|
auto currentYNNeighbor = getYNNeighbor();
|
||||||
|
if (currentYNNeighbor) {
|
||||||
|
currentYNNeighbor->neighborYEdgeChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (force || _neighborZNeedsUpdate) {
|
||||||
|
_neighborZNeedsUpdate = false;
|
||||||
|
auto currentZNNeighbor = getZNNeighbor();
|
||||||
|
if (currentZNNeighbor) {
|
||||||
|
currentZNNeighbor->neighborZEdgeChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::recomputeMesh() {
|
void RenderablePolyVoxEntityItem::recomputeMesh() {
|
||||||
// use _volData to make a renderable mesh
|
// use _volData to make a renderable mesh
|
||||||
PolyVoxSurfaceStyle voxelSurfaceStyle;
|
PolyVoxSurfaceStyle voxelSurfaceStyle;
|
||||||
|
@ -1121,9 +1330,6 @@ void RenderablePolyVoxEntityItem::recomputeMesh() {
|
||||||
voxelSurfaceStyle = _voxelSurfaceStyle;
|
voxelSurfaceStyle = _voxelSurfaceStyle;
|
||||||
});
|
});
|
||||||
|
|
||||||
cacheNeighbors();
|
|
||||||
copyUpperEdgesFromNeighbors();
|
|
||||||
|
|
||||||
auto entity = std::static_pointer_cast<RenderablePolyVoxEntityItem>(getThisPointer());
|
auto entity = std::static_pointer_cast<RenderablePolyVoxEntityItem>(getThisPointer());
|
||||||
|
|
||||||
QtConcurrent::run([entity, voxelSurfaceStyle] {
|
QtConcurrent::run([entity, voxelSurfaceStyle] {
|
||||||
|
@ -1135,24 +1341,14 @@ void RenderablePolyVoxEntityItem::recomputeMesh() {
|
||||||
entity->withReadLock([&] {
|
entity->withReadLock([&] {
|
||||||
PolyVox::SimpleVolume<uint8_t>* volData = entity->getVolData();
|
PolyVox::SimpleVolume<uint8_t>* volData = entity->getVolData();
|
||||||
switch (voxelSurfaceStyle) {
|
switch (voxelSurfaceStyle) {
|
||||||
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: {
|
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
|
||||||
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
|
||||||
(volData, volData->getEnclosingRegion(), &polyVoxMesh);
|
|
||||||
surfaceExtractor.execute();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: {
|
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: {
|
||||||
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||||
(volData, volData->getEnclosingRegion(), &polyVoxMesh);
|
(volData, volData->getEnclosingRegion(), &polyVoxMesh);
|
||||||
surfaceExtractor.execute();
|
surfaceExtractor.execute();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: {
|
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
||||||
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
|
||||||
(volData, volData->getEnclosingRegion(), &polyVoxMesh);
|
|
||||||
surfaceExtractor.execute();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PolyVoxEntityItem::SURFACE_CUBIC: {
|
case PolyVoxEntityItem::SURFACE_CUBIC: {
|
||||||
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||||
(volData, volData->getEnclosingRegion(), &polyVoxMesh);
|
(volData, volData->getEnclosingRegion(), &polyVoxMesh);
|
||||||
|
@ -1180,7 +1376,6 @@ void RenderablePolyVoxEntityItem::recomputeMesh() {
|
||||||
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||||
mesh->setVertexBuffer(vertexBufferView);
|
mesh->setVertexBuffer(vertexBufferView);
|
||||||
|
|
||||||
|
|
||||||
// TODO -- use 3-byte normals rather than 3-float normals
|
// TODO -- use 3-byte normals rather than 3-float normals
|
||||||
mesh->addAttribute(gpu::Stream::NORMAL,
|
mesh->addAttribute(gpu::Stream::NORMAL,
|
||||||
gpu::BufferView(vertexBufferPtr,
|
gpu::BufferView(vertexBufferPtr,
|
||||||
|
@ -1194,28 +1389,24 @@ void RenderablePolyVoxEntityItem::recomputeMesh() {
|
||||||
(graphics::Index)vecIndices.size(), // numIndices
|
(graphics::Index)vecIndices.size(), // numIndices
|
||||||
(graphics::Index)0, // baseVertex
|
(graphics::Index)0, // baseVertex
|
||||||
graphics::Mesh::TRIANGLES)); // topology
|
graphics::Mesh::TRIANGLES)); // topology
|
||||||
mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part),
|
mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part), (gpu::Byte*) parts.data()),
|
||||||
(gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
|
gpu::Element::PART_DRAWCALL));
|
||||||
entity->setMesh(mesh);
|
entity->setMesh(mesh);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::setMesh(graphics::MeshPointer mesh) {
|
void RenderablePolyVoxEntityItem::setMesh(graphics::MeshPointer mesh) {
|
||||||
// this catches the payload from recomputeMesh
|
// this catches the payload from recomputeMesh
|
||||||
bool neighborsNeedUpdate;
|
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
if (!_collisionless) {
|
if (!_collisionless) {
|
||||||
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
|
||||||
}
|
}
|
||||||
|
_shapeReady = false;
|
||||||
_mesh = mesh;
|
_mesh = mesh;
|
||||||
_meshDirty = true;
|
_state = PolyVoxState::BakingMeshFinished;
|
||||||
_meshReady = true;
|
_meshReady = true;
|
||||||
neighborsNeedUpdate = _neighborsNeedUpdate;
|
startUpdates();
|
||||||
_neighborsNeedUpdate = false;
|
|
||||||
});
|
});
|
||||||
if (neighborsNeedUpdate) {
|
|
||||||
bonkNeighbors();
|
|
||||||
}
|
|
||||||
|
|
||||||
somethingChangedNotification();
|
somethingChangedNotification();
|
||||||
}
|
}
|
||||||
|
@ -1223,9 +1414,6 @@ void RenderablePolyVoxEntityItem::setMesh(graphics::MeshPointer mesh) {
|
||||||
void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
|
void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
|
||||||
// this creates a collision-shape for the physics engine. The shape comes from
|
// this creates a collision-shape for the physics engine. The shape comes from
|
||||||
// _volData for cubic extractors and from _mesh for marching-cube extractors
|
// _volData for cubic extractors and from _mesh for marching-cube extractors
|
||||||
if (!_meshReady) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityItemPointer entity = getThisPointer();
|
EntityItemPointer entity = getThisPointer();
|
||||||
|
|
||||||
|
@ -1360,6 +1548,10 @@ void RenderablePolyVoxEntityItem::setCollisionPoints(ShapeInfo::PointCollection
|
||||||
// this catches the payload from computeShapeInfoWorker
|
// this catches the payload from computeShapeInfoWorker
|
||||||
if (pointCollection.isEmpty()) {
|
if (pointCollection.isEmpty()) {
|
||||||
EntityItem::computeShapeInfo(_shapeInfo);
|
EntityItem::computeShapeInfo(_shapeInfo);
|
||||||
|
withWriteLock([&] {
|
||||||
|
_shapeReady = true;
|
||||||
|
_state = PolyVoxState::BakingShapeFinished;
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1373,7 +1565,8 @@ void RenderablePolyVoxEntityItem::setCollisionPoints(ShapeInfo::PointCollection
|
||||||
QString::number(_registrationPoint.z);
|
QString::number(_registrationPoint.z);
|
||||||
_shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, shapeKey);
|
_shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, shapeKey);
|
||||||
_shapeInfo.setPointCollection(pointCollection);
|
_shapeInfo.setPointCollection(pointCollection);
|
||||||
_meshDirty = false;
|
_shapeReady = true;
|
||||||
|
_state = PolyVoxState::BakingShapeFinished;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1384,7 +1577,8 @@ void RenderablePolyVoxEntityItem::setXNNeighborID(const EntityItemID& xNNeighbor
|
||||||
|
|
||||||
if (xNNeighborID != _xNNeighborID) {
|
if (xNNeighborID != _xNNeighborID) {
|
||||||
PolyVoxEntityItem::setXNNeighborID(xNNeighborID);
|
PolyVoxEntityItem::setXNNeighborID(xNNeighborID);
|
||||||
cacheNeighbors();
|
_neighborXNeedsUpdate = true;
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1395,7 +1589,8 @@ void RenderablePolyVoxEntityItem::setYNNeighborID(const EntityItemID& yNNeighbor
|
||||||
|
|
||||||
if (yNNeighborID != _yNNeighborID) {
|
if (yNNeighborID != _yNNeighborID) {
|
||||||
PolyVoxEntityItem::setYNNeighborID(yNNeighborID);
|
PolyVoxEntityItem::setYNNeighborID(yNNeighborID);
|
||||||
cacheNeighbors();
|
_neighborYNeedsUpdate = true;
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1406,7 +1601,8 @@ void RenderablePolyVoxEntityItem::setZNNeighborID(const EntityItemID& zNNeighbor
|
||||||
|
|
||||||
if (zNNeighborID != _zNNeighborID) {
|
if (zNNeighborID != _zNNeighborID) {
|
||||||
PolyVoxEntityItem::setZNNeighborID(zNNeighborID);
|
PolyVoxEntityItem::setZNNeighborID(zNNeighborID);
|
||||||
cacheNeighbors();
|
_neighborZNeedsUpdate = true;
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1416,7 +1612,8 @@ void RenderablePolyVoxEntityItem::setXPNeighborID(const EntityItemID& xPNeighbor
|
||||||
}
|
}
|
||||||
if (xPNeighborID != _xPNeighborID) {
|
if (xPNeighborID != _xPNeighborID) {
|
||||||
PolyVoxEntityItem::setXPNeighborID(xPNeighborID);
|
PolyVoxEntityItem::setXPNeighborID(xPNeighborID);
|
||||||
_volDataDirty = true;
|
_updateFromNeighborXEdge = true;
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1426,7 +1623,8 @@ void RenderablePolyVoxEntityItem::setYPNeighborID(const EntityItemID& yPNeighbor
|
||||||
}
|
}
|
||||||
if (yPNeighborID != _yPNeighborID) {
|
if (yPNeighborID != _yPNeighborID) {
|
||||||
PolyVoxEntityItem::setYPNeighborID(yPNeighborID);
|
PolyVoxEntityItem::setYPNeighborID(yPNeighborID);
|
||||||
_volDataDirty = true;
|
_updateFromNeighborYEdge = true;
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1436,7 +1634,8 @@ void RenderablePolyVoxEntityItem::setZPNeighborID(const EntityItemID& zPNeighbor
|
||||||
}
|
}
|
||||||
if (zPNeighborID != _zPNeighborID) {
|
if (zPNeighborID != _zPNeighborID) {
|
||||||
PolyVoxEntityItem::setZPNeighborID(zPNeighborID);
|
PolyVoxEntityItem::setZPNeighborID(zPNeighborID);
|
||||||
_volDataDirty = true;
|
_updateFromNeighborZEdge = true;
|
||||||
|
startUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1464,31 +1663,8 @@ std::shared_ptr<RenderablePolyVoxEntityItem> RenderablePolyVoxEntityItem::getZPN
|
||||||
return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_zPNeighbor.lock());
|
return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_zPNeighbor.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::bonkNeighbors() {
|
|
||||||
// flag neighbors to the negative of this entity as needing to rebake their meshes.
|
|
||||||
cacheNeighbors();
|
|
||||||
|
|
||||||
auto currentXNNeighbor = getXNNeighbor();
|
|
||||||
auto currentYNNeighbor = getYNNeighbor();
|
|
||||||
auto currentZNNeighbor = getZNNeighbor();
|
|
||||||
|
|
||||||
if (currentXNNeighbor) {
|
|
||||||
currentXNNeighbor->setVolDataDirty();
|
|
||||||
}
|
|
||||||
if (currentYNNeighbor) {
|
|
||||||
currentYNNeighbor->setVolDataDirty();
|
|
||||||
}
|
|
||||||
if (currentZNNeighbor) {
|
|
||||||
currentZNNeighbor->setVolDataDirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// deprecated
|
// deprecated
|
||||||
bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
|
bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
|
||||||
if (!updateDependents()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (_mesh) {
|
if (_mesh) {
|
||||||
MeshProxy* meshProxy = nullptr;
|
MeshProxy* meshProxy = nullptr;
|
||||||
|
@ -1517,7 +1693,7 @@ bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptable::ScriptableModelBase RenderablePolyVoxEntityItem::getScriptableModel() {
|
scriptable::ScriptableModelBase RenderablePolyVoxEntityItem::getScriptableModel() {
|
||||||
if (!updateDependents() || !_mesh) {
|
if (!_mesh) {
|
||||||
return scriptable::ScriptableModelBase();
|
return scriptable::ScriptableModelBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,9 +1804,6 @@ bool PolyVoxEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPo
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||||
if (entity->_voxelDataDirty || entity->_volDataDirty) {
|
|
||||||
entity->updateDependents();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
|
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
|
||||||
if (!_hasTransitioned) {
|
if (!_hasTransitioned) {
|
||||||
|
@ -1662,7 +1835,6 @@ void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoi
|
||||||
graphics::MeshPointer newMesh;
|
graphics::MeshPointer newMesh;
|
||||||
entity->withReadLock([&] {
|
entity->withReadLock([&] {
|
||||||
newMesh = entity->_mesh;
|
newMesh = entity->_mesh;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newMesh && newMesh->getIndexBuffer()._buffer) {
|
if (newMesh && newMesh->getIndexBuffer()._buffer) {
|
||||||
|
@ -1705,3 +1877,41 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) {
|
||||||
batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)_mesh->getNumIndices(), 0);
|
batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)_mesh->getNumIndices(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, PolyVoxState state) {
|
||||||
|
switch (state) {
|
||||||
|
case PolyVoxState::Ready:
|
||||||
|
debug << "Ready";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::Uncompressing:
|
||||||
|
debug << "Uncompressing";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::UncompressingFinished:
|
||||||
|
debug << "UncompressingFinished";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::BakingMesh:
|
||||||
|
debug << "BakingMesh";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::BakingMeshFinished:
|
||||||
|
debug << "BakingMeshFinished";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::BakingMeshNoCompress:
|
||||||
|
debug << "BakingMeshNoCompress";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::BakingMeshNoCompressFinished:
|
||||||
|
debug << "BakingMeshNoCompressFinished";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::Compressing:
|
||||||
|
debug << "Compressing";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::CompressingFinished:
|
||||||
|
debug << "CompressingFinished";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::BakingShape:
|
||||||
|
debug << "BakingShape";
|
||||||
|
break;
|
||||||
|
case PolyVoxState::BakingShapeFinished:
|
||||||
|
debug << "BakingShapeFinished";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
|
@ -32,6 +32,24 @@ namespace render { namespace entities {
|
||||||
class PolyVoxEntityRenderer;
|
class PolyVoxEntityRenderer;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
|
||||||
|
enum class PolyVoxState {
|
||||||
|
Ready,
|
||||||
|
Uncompressing,
|
||||||
|
UncompressingFinished,
|
||||||
|
BakingMesh,
|
||||||
|
BakingMeshFinished,
|
||||||
|
BakingMeshNoCompress,
|
||||||
|
BakingMeshNoCompressFinished,
|
||||||
|
Compressing,
|
||||||
|
CompressingFinished,
|
||||||
|
BakingShape,
|
||||||
|
BakingShapeFinished
|
||||||
|
};
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, PolyVoxState state);
|
||||||
|
|
||||||
|
|
||||||
class RenderablePolyVoxEntityItem : public PolyVoxEntityItem, public scriptable::ModelProvider {
|
class RenderablePolyVoxEntityItem : public PolyVoxEntityItem, public scriptable::ModelProvider {
|
||||||
friend class render::entities::PolyVoxEntityRenderer;
|
friend class render::entities::PolyVoxEntityRenderer;
|
||||||
|
|
||||||
|
@ -113,41 +131,61 @@ public:
|
||||||
|
|
||||||
uint8_t getVoxelInternal(const ivec3& v) const;
|
uint8_t getVoxelInternal(const ivec3& v) const;
|
||||||
bool setVoxelInternal(const ivec3& v, uint8_t toValue);
|
bool setVoxelInternal(const ivec3& v, uint8_t toValue);
|
||||||
|
void setVoxelMarkNeighbors(int x, int y, int z, uint8_t toValue);
|
||||||
|
|
||||||
void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; _meshReady = false; }); }
|
void compressVolumeDataFinished(const QByteArray& voxelData);
|
||||||
|
void neighborXEdgeChanged() { withWriteLock([&] { _updateFromNeighborXEdge = true; }); startUpdates(); }
|
||||||
|
void neighborYEdgeChanged() { withWriteLock([&] { _updateFromNeighborYEdge = true; }); startUpdates(); }
|
||||||
|
void neighborZEdgeChanged() { withWriteLock([&] { _updateFromNeighborZEdge = true; }); startUpdates(); }
|
||||||
|
|
||||||
bool getMeshes(MeshProxyList& result) override; // deprecated
|
bool getMeshes(MeshProxyList& result) override; // deprecated
|
||||||
virtual scriptable::ScriptableModelBase getScriptableModel() override;
|
virtual scriptable::ScriptableModelBase getScriptableModel() override;
|
||||||
|
|
||||||
|
virtual void update(const quint64& now) override;
|
||||||
|
bool needsToCallUpdate() const override { return _updateNeeded; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool updateOnCount(const ivec3& v, uint8_t toValue);
|
bool updateOnCount(const ivec3& v, uint8_t toValue);
|
||||||
PolyVox::RaycastResult doRayCast(glm::vec4 originInVoxel, glm::vec4 farInVoxel, glm::vec4& result) const;
|
PolyVox::RaycastResult doRayCast(glm::vec4 originInVoxel, glm::vec4 farInVoxel, glm::vec4& result) const;
|
||||||
|
|
||||||
|
void changeUpdates(bool value);
|
||||||
|
void startUpdates();
|
||||||
|
void stopUpdates();
|
||||||
|
|
||||||
void recomputeMesh();
|
void recomputeMesh();
|
||||||
void cacheNeighbors();
|
void cacheNeighbors();
|
||||||
void copyUpperEdgesFromNeighbors();
|
void copyUpperEdgesFromNeighbors();
|
||||||
void bonkNeighbors();
|
void tellNeighborsToRecopyEdges(bool force);
|
||||||
bool updateDependents();
|
bool updateDependents();
|
||||||
|
|
||||||
// these are run off the main thread
|
// these are run off the main thread
|
||||||
void decompressVolumeData();
|
void uncompressVolumeData();
|
||||||
void compressVolumeDataAndSendEditPacket();
|
void compressVolumeDataAndSendEditPacket();
|
||||||
void computeShapeInfoWorker();
|
void computeShapeInfoWorker();
|
||||||
|
|
||||||
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
|
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
|
||||||
// may not match _voxelVolumeSize.
|
// may not match _voxelVolumeSize.
|
||||||
bool _meshDirty { true }; // does collision-shape need to be recomputed?
|
bool _meshReady { false }; // do we have something to give scripts that ask for the mesh?
|
||||||
bool _meshReady{ false };
|
bool _voxelDataDirty { false }; // do we need to uncompress data and expand it into _volData?
|
||||||
|
bool _volDataDirty { false }; // does recomputeMesh need to be called?
|
||||||
|
bool _shapeReady { false }; // are we ready to tell bullet our shape?
|
||||||
|
PolyVoxState _state { PolyVoxState::Ready };
|
||||||
|
bool _updateNeeded { true };
|
||||||
|
|
||||||
graphics::MeshPointer _mesh;
|
graphics::MeshPointer _mesh;
|
||||||
|
|
||||||
ShapeInfo _shapeInfo;
|
ShapeInfo _shapeInfo;
|
||||||
|
|
||||||
std::shared_ptr<PolyVox::SimpleVolume<uint8_t>> _volData;
|
std::shared_ptr<PolyVox::SimpleVolume<uint8_t>> _volData;
|
||||||
bool _voxelDataDirty{ true };
|
|
||||||
bool _volDataDirty { false }; // does recomputeMesh need to be called?
|
|
||||||
int _onCount; // how many non-zero voxels are in _volData
|
int _onCount; // how many non-zero voxels are in _volData
|
||||||
|
|
||||||
bool _neighborsNeedUpdate { false };
|
bool _neighborXNeedsUpdate { false };
|
||||||
|
bool _neighborYNeedsUpdate { false };
|
||||||
|
bool _neighborZNeedsUpdate { false };
|
||||||
|
|
||||||
|
bool _updateFromNeighborXEdge { false };
|
||||||
|
bool _updateFromNeighborYEdge { false };
|
||||||
|
bool _updateFromNeighborZEdge { false };
|
||||||
|
|
||||||
// these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID
|
// these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID
|
||||||
EntityItemWeakPointer _xNNeighbor; // neighbor found by going along negative X axis
|
EntityItemWeakPointer _xNNeighbor; // neighbor found by going along negative X axis
|
||||||
|
@ -156,7 +194,6 @@ private:
|
||||||
EntityItemWeakPointer _xPNeighbor; // neighbor found by going along positive X axis
|
EntityItemWeakPointer _xPNeighbor; // neighbor found by going along positive X axis
|
||||||
EntityItemWeakPointer _yPNeighbor;
|
EntityItemWeakPointer _yPNeighbor;
|
||||||
EntityItemWeakPointer _zPNeighbor;
|
EntityItemWeakPointer _zPNeighbor;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace render { namespace entities {
|
namespace render { namespace entities {
|
||||||
|
@ -192,7 +229,6 @@ private:
|
||||||
glm::mat4 _lastVoxelToWorldMatrix;
|
glm::mat4 _lastVoxelToWorldMatrix;
|
||||||
PolyVoxEntityItem::PolyVoxSurfaceStyle _lastSurfaceStyle { PolyVoxEntityItem::SURFACE_MARCHING_CUBES };
|
PolyVoxEntityItem::PolyVoxSurfaceStyle _lastSurfaceStyle { PolyVoxEntityItem::SURFACE_MARCHING_CUBES };
|
||||||
std::array<QString, 3> _xyzTextureUrls;
|
std::array<QString, 3> _xyzTextureUrls;
|
||||||
bool _neighborsNeedUpdate{ false };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -965,7 +965,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
* // Value overrides entity's "color" property.
|
* // Value overrides entity's "color" property.
|
||||||
* albedo: [1.0, 1.0, 0] // Yellow
|
* albedo: [1.0, 1.0, 0] // Yellow
|
||||||
* }
|
* }
|
||||||
* }),
|
* })
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1294,7 +1294,7 @@ public slots:
|
||||||
Q_INVOKABLE int getJointParent(const QUuid& entityID, int index);
|
Q_INVOKABLE int getJointParent(const QUuid& entityID, int index);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Gets the translation of a joint in a {@link Entities.EntityProperties-Model|Model} entity relative to the entity's
|
* Gets the rotation of a joint in a {@link Entities.EntityProperties-Model|Model} entity relative to the entity's
|
||||||
* position and orientation.
|
* position and orientation.
|
||||||
* @function Entities.getAbsoluteJointRotationInObjectFrame
|
* @function Entities.getAbsoluteJointRotationInObjectFrame
|
||||||
* @param {Uuid} entityID - The ID of the entity.
|
* @param {Uuid} entityID - The ID of the entity.
|
||||||
|
|
|
@ -139,6 +139,11 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
void AntialiasingConfig::setAAMode(int mode) {
|
||||||
|
_mode = std::min((int)AntialiasingConfig::MODE_COUNT, std::max(0, mode));
|
||||||
|
emit dirty();
|
||||||
|
}
|
||||||
|
|
||||||
Antialiasing::Antialiasing(bool isSharpenEnabled) :
|
Antialiasing::Antialiasing(bool isSharpenEnabled) :
|
||||||
_isSharpenEnabled{ isSharpenEnabled } {
|
_isSharpenEnabled{ isSharpenEnabled } {
|
||||||
}
|
}
|
||||||
|
@ -189,6 +194,8 @@ const gpu::PipelinePointer& Antialiasing::getDebugBlendPipeline() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Antialiasing::configure(const Config& config) {
|
void Antialiasing::configure(const Config& config) {
|
||||||
|
_mode = (AntialiasingConfig::Mode) config.getAAMode();
|
||||||
|
|
||||||
_sharpen = config.sharpen * 0.25f;
|
_sharpen = config.sharpen * 0.25f;
|
||||||
if (!_isSharpenEnabled) {
|
if (!_isSharpenEnabled) {
|
||||||
_sharpen = 0.0f;
|
_sharpen = 0.0f;
|
||||||
|
@ -298,29 +305,33 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void JitterSampleConfig::setIndex(int current) {
|
void JitterSampleConfig::setIndex(int current) {
|
||||||
_index = (current) % JitterSample::SEQUENCE_LENGTH;
|
_index = (current) % JitterSample::SEQUENCE_LENGTH;
|
||||||
emit dirty();
|
emit dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
int JitterSampleConfig::cycleStopPauseRun() {
|
void JitterSampleConfig::setState(int state) {
|
||||||
_state = (_state + 1) % 3;
|
_state = (state) % 3;
|
||||||
switch (_state) {
|
switch (_state) {
|
||||||
case 0: {
|
case 0: {
|
||||||
return none();
|
none();
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
return pause();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
default: {
|
|
||||||
return play();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case 1: {
|
||||||
|
pause();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
default: {
|
||||||
|
play();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int JitterSampleConfig::cycleStopPauseRun() {
|
||||||
|
setState((_state + 1) % 3);
|
||||||
return _state;
|
return _state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ class JitterSampleConfig : public render::Job::Config {
|
||||||
Q_PROPERTY(bool freeze MEMBER freeze NOTIFY dirty)
|
Q_PROPERTY(bool freeze MEMBER freeze NOTIFY dirty)
|
||||||
Q_PROPERTY(bool stop MEMBER stop NOTIFY dirty)
|
Q_PROPERTY(bool stop MEMBER stop NOTIFY dirty)
|
||||||
Q_PROPERTY(int index READ getIndex NOTIFY dirty)
|
Q_PROPERTY(int index READ getIndex NOTIFY dirty)
|
||||||
|
Q_PROPERTY(int state READ getState WRITE setState NOTIFY dirty)
|
||||||
public:
|
public:
|
||||||
JitterSampleConfig() : render::Job::Config(true) {}
|
JitterSampleConfig() : render::Job::Config(true) {}
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ public:
|
||||||
bool freeze{ false };
|
bool freeze{ false };
|
||||||
|
|
||||||
void setIndex(int current);
|
void setIndex(int current);
|
||||||
|
void setState(int state);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
int cycleStopPauseRun();
|
int cycleStopPauseRun();
|
||||||
|
@ -86,6 +88,7 @@ private:
|
||||||
|
|
||||||
class AntialiasingConfig : public render::Job::Config {
|
class AntialiasingConfig : public render::Job::Config {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int mode READ getAAMode WRITE setAAMode NOTIFY dirty)
|
||||||
Q_PROPERTY(float blend MEMBER blend NOTIFY dirty)
|
Q_PROPERTY(float blend MEMBER blend NOTIFY dirty)
|
||||||
Q_PROPERTY(float sharpen MEMBER sharpen NOTIFY dirty)
|
Q_PROPERTY(float sharpen MEMBER sharpen NOTIFY dirty)
|
||||||
Q_PROPERTY(float covarianceGamma MEMBER covarianceGamma NOTIFY dirty)
|
Q_PROPERTY(float covarianceGamma MEMBER covarianceGamma NOTIFY dirty)
|
||||||
|
@ -106,9 +109,21 @@ class AntialiasingConfig : public render::Job::Config {
|
||||||
public:
|
public:
|
||||||
AntialiasingConfig() : render::Job::Config(true) {}
|
AntialiasingConfig() : render::Job::Config(true) {}
|
||||||
|
|
||||||
|
enum Mode {
|
||||||
|
OFF = 0,
|
||||||
|
TAA,
|
||||||
|
FXAA,
|
||||||
|
MODE_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
void setAAMode(int mode);
|
||||||
|
int getAAMode() const { return _mode; }
|
||||||
|
|
||||||
void setDebugFXAA(bool debug) { debugFXAAX = (debug ? 0.0f : 1.0f); emit dirty();}
|
void setDebugFXAA(bool debug) { debugFXAAX = (debug ? 0.0f : 1.0f); emit dirty();}
|
||||||
bool debugFXAA() const { return (debugFXAAX == 0.0f ? true : false); }
|
bool debugFXAA() const { return (debugFXAAX == 0.0f ? true : false); }
|
||||||
|
|
||||||
|
int _mode{ TAA };
|
||||||
|
|
||||||
float blend{ 0.25f };
|
float blend{ 0.25f };
|
||||||
float sharpen{ 0.05f };
|
float sharpen{ 0.05f };
|
||||||
|
|
||||||
|
@ -195,6 +210,7 @@ private:
|
||||||
gpu::PipelinePointer _debugBlendPipeline;
|
gpu::PipelinePointer _debugBlendPipeline;
|
||||||
|
|
||||||
TAAParamsBuffer _params;
|
TAAParamsBuffer _params;
|
||||||
|
AntialiasingConfig::Mode _mode{ AntialiasingConfig::TAA };
|
||||||
float _sharpen{ 0.15f };
|
float _sharpen{ 0.15f };
|
||||||
bool _isSharpenEnabled{ true };
|
bool _isSharpenEnabled{ true };
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,12 +35,13 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
|
||||||
const auto frameTransform = inputs.get0();
|
const auto frameTransform = inputs.get0();
|
||||||
const auto inputFrameBuffer = inputs.get1();
|
const auto inputFrameBuffer = inputs.get1();
|
||||||
const auto bloomFrame = inputs.get2();
|
const auto bloomFrame = inputs.get2();
|
||||||
|
const auto lightingModel = inputs.get3();
|
||||||
const auto& bloomStage = renderContext->_scene->getStage<BloomStage>();
|
const auto& bloomStage = renderContext->_scene->getStage<BloomStage>();
|
||||||
graphics::BloomPointer bloom;
|
graphics::BloomPointer bloom;
|
||||||
if (bloomStage && bloomFrame->_blooms.size()) {
|
if (bloomStage && bloomFrame->_blooms.size()) {
|
||||||
bloom = bloomStage->getBloom(bloomFrame->_blooms.front());
|
bloom = bloomStage->getBloom(bloomFrame->_blooms.front());
|
||||||
}
|
}
|
||||||
if (!bloom) {
|
if (!bloom || (lightingModel && !lightingModel->isBloomEnabled())) {
|
||||||
renderContext->taskFlow.abortTask();
|
renderContext->taskFlow.abortTask();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -187,12 +188,17 @@ void BloomDraw::run(const render::RenderContextPointer& renderContext, const Inp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugBloomConfig::setMode(int mode) {
|
||||||
|
_mode = std::min((int)DebugBloomConfig::MODE_COUNT, std::max(0, mode));
|
||||||
|
emit dirty();
|
||||||
|
}
|
||||||
|
|
||||||
DebugBloom::DebugBloom() {
|
DebugBloom::DebugBloom() {
|
||||||
_params = std::make_shared<gpu::Buffer>(sizeof(glm::vec4), nullptr);
|
_params = std::make_shared<gpu::Buffer>(sizeof(glm::vec4), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugBloom::configure(const Config& config) {
|
void DebugBloom::configure(const Config& config) {
|
||||||
_mode = static_cast<DebugBloomConfig::Mode>(config.mode);
|
_mode = (DebugBloomConfig::Mode) config.getMode();
|
||||||
assert(_mode < DebugBloomConfig::MODE_COUNT);
|
assert(_mode < DebugBloomConfig::MODE_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +207,10 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In
|
||||||
assert(renderContext->args->hasViewFrustum());
|
assert(renderContext->args->hasViewFrustum());
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
|
if (_mode == DebugBloomConfig::OFF) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto frameBuffer = inputs.get0();
|
const auto frameBuffer = inputs.get0();
|
||||||
const auto combinedBlurBuffer = inputs.get4();
|
const auto combinedBlurBuffer = inputs.get4();
|
||||||
const auto framebufferSize = frameBuffer->getSize();
|
const auto framebufferSize = frameBuffer->getSize();
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "BloomStage.h"
|
#include "BloomStage.h"
|
||||||
|
|
||||||
#include "DeferredFrameTransform.h"
|
#include "DeferredFrameTransform.h"
|
||||||
|
#include "LightingModel.h"
|
||||||
|
|
||||||
class BloomConfig : public render::Task::Config {
|
class BloomConfig : public render::Task::Config {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -28,7 +29,7 @@ class BloomThresholdConfig : public render::Job::Config {
|
||||||
|
|
||||||
class BloomThreshold {
|
class BloomThreshold {
|
||||||
public:
|
public:
|
||||||
using Inputs = render::VaryingSet3<DeferredFrameTransformPointer, gpu::FramebufferPointer, BloomStage::FramePointer>;
|
using Inputs = render::VaryingSet4<DeferredFrameTransformPointer, gpu::FramebufferPointer, BloomStage::FramePointer, LightingModelPointer>;
|
||||||
using Outputs = render::VaryingSet3<gpu::FramebufferPointer, float, graphics::BloomPointer>;
|
using Outputs = render::VaryingSet3<gpu::FramebufferPointer, float, graphics::BloomPointer>;
|
||||||
using Config = BloomThresholdConfig;
|
using Config = BloomThresholdConfig;
|
||||||
using JobModel = render::Job::ModelIO<BloomThreshold, Inputs, Outputs, Config>;
|
using JobModel = render::Job::ModelIO<BloomThreshold, Inputs, Outputs, Config>;
|
||||||
|
@ -87,12 +88,13 @@ private:
|
||||||
|
|
||||||
class DebugBloomConfig : public render::Job::Config {
|
class DebugBloomConfig : public render::Job::Config {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(int mode MEMBER mode NOTIFY dirty)
|
Q_PROPERTY(int mode READ getMode WRITE setMode NOTIFY dirty)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Mode {
|
enum Mode {
|
||||||
MODE_LEVEL0 = 0,
|
OFF = 0,
|
||||||
|
MODE_LEVEL0,
|
||||||
MODE_LEVEL1,
|
MODE_LEVEL1,
|
||||||
MODE_LEVEL2,
|
MODE_LEVEL2,
|
||||||
MODE_ALL_LEVELS,
|
MODE_ALL_LEVELS,
|
||||||
|
@ -102,7 +104,10 @@ public:
|
||||||
|
|
||||||
DebugBloomConfig() : render::Job::Config(false) {}
|
DebugBloomConfig() : render::Job::Config(false) {}
|
||||||
|
|
||||||
int mode{ MODE_ALL_LEVELS };
|
void setMode(int mode);
|
||||||
|
int getMode() const { return _mode; }
|
||||||
|
|
||||||
|
int _mode{ MODE_ALL_LEVELS };
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dirty();
|
void dirty();
|
||||||
|
@ -127,14 +132,14 @@ private:
|
||||||
|
|
||||||
class BloomEffect {
|
class BloomEffect {
|
||||||
public:
|
public:
|
||||||
using Inputs = render::VaryingSet3<DeferredFrameTransformPointer, gpu::FramebufferPointer, BloomStage::FramePointer>;
|
using Inputs = render::VaryingSet4<DeferredFrameTransformPointer, gpu::FramebufferPointer, BloomStage::FramePointer, LightingModelPointer>;
|
||||||
using Config = BloomConfig;
|
using Config = BloomConfig;
|
||||||
using JobModel = render::Task::ModelI<BloomEffect, Inputs, Config>;
|
using JobModel = render::Task::ModelI<BloomEffect, Inputs, Config>;
|
||||||
|
|
||||||
BloomEffect();
|
BloomEffect();
|
||||||
|
|
||||||
void configure(const Config& config);
|
void configure(const Config& config);
|
||||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
|
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -150,8 +150,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
||||||
// Prepare deferred, generate the shared Deferred Frame Transform. Only valid with the scaled frame buffer
|
// Prepare deferred, generate the shared Deferred Frame Transform. Only valid with the scaled frame buffer
|
||||||
const auto deferredFrameTransform = task.addJob<GenerateDeferredFrameTransform>("DeferredFrameTransform", jitter);
|
const auto deferredFrameTransform = task.addJob<GenerateDeferredFrameTransform>("DeferredFrameTransform", jitter);
|
||||||
|
|
||||||
const auto opaqueRangeTimer = task.addJob<BeginGPURangeTimer>("BeginOpaqueRangeTimer", "DrawOpaques");
|
|
||||||
|
|
||||||
const auto prepareDeferredInputs = PrepareDeferred::Inputs(scaledPrimaryFramebuffer, lightingModel).asVarying();
|
const auto prepareDeferredInputs = PrepareDeferred::Inputs(scaledPrimaryFramebuffer, lightingModel).asVarying();
|
||||||
const auto prepareDeferredOutputs = task.addJob<PrepareDeferred>("PrepareDeferred", prepareDeferredInputs);
|
const auto prepareDeferredOutputs = task.addJob<PrepareDeferred>("PrepareDeferred", prepareDeferredInputs);
|
||||||
const auto deferredFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(0);
|
const auto deferredFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(0);
|
||||||
|
@ -164,8 +162,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
||||||
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel, jitter).asVarying();
|
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel, jitter).asVarying();
|
||||||
task.addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaqueInputs, shapePlumber);
|
task.addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaqueInputs, shapePlumber);
|
||||||
|
|
||||||
task.addJob<EndGPURangeTimer>("OpaqueRangeTimer", opaqueRangeTimer);
|
|
||||||
|
|
||||||
// Opaque all rendered
|
// Opaque all rendered
|
||||||
|
|
||||||
// Linear Depth Pass
|
// Linear Depth Pass
|
||||||
|
@ -216,13 +212,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
||||||
const auto transparentsInputs = RenderTransparentDeferred::Inputs(transparents, hazeFrame, lightFrame, lightingModel, lightClusters, shadowFrame, jitter).asVarying();
|
const auto transparentsInputs = RenderTransparentDeferred::Inputs(transparents, hazeFrame, lightFrame, lightingModel, lightClusters, shadowFrame, jitter).asVarying();
|
||||||
task.addJob<RenderTransparentDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
task.addJob<RenderTransparentDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
||||||
|
|
||||||
const auto outlineRangeTimer = task.addJob<BeginGPURangeTimer>("BeginHighlightRangeTimer", "Highlight");
|
// Highlight
|
||||||
|
|
||||||
const auto outlineInputs = DrawHighlightTask::Inputs(items, deferredFramebuffer, lightingFramebuffer, deferredFrameTransform, jitter).asVarying();
|
const auto outlineInputs = DrawHighlightTask::Inputs(items, deferredFramebuffer, lightingFramebuffer, deferredFrameTransform, jitter).asVarying();
|
||||||
task.addJob<DrawHighlightTask>("DrawHighlight", outlineInputs);
|
task.addJob<DrawHighlightTask>("DrawHighlight", outlineInputs);
|
||||||
|
|
||||||
task.addJob<EndGPURangeTimer>("HighlightRangeTimer", outlineRangeTimer);
|
|
||||||
|
|
||||||
// Layered Over (in front)
|
// Layered Over (in front)
|
||||||
const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, hazeFrame, jitter).asVarying();
|
const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, hazeFrame, jitter).asVarying();
|
||||||
const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, hazeFrame, jitter).asVarying();
|
const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, hazeFrame, jitter).asVarying();
|
||||||
|
@ -234,7 +227,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
||||||
task.addJob<Antialiasing>("Antialiasing", antialiasingInputs);
|
task.addJob<Antialiasing>("Antialiasing", antialiasingInputs);
|
||||||
|
|
||||||
// Add bloom
|
// Add bloom
|
||||||
const auto bloomInputs = BloomEffect::Inputs(deferredFrameTransform, lightingFramebuffer, bloomFrame).asVarying();
|
const auto bloomInputs = BloomEffect::Inputs(deferredFrameTransform, lightingFramebuffer, bloomFrame, lightingModel).asVarying();
|
||||||
task.addJob<BloomEffect>("Bloom", bloomInputs);
|
task.addJob<BloomEffect>("Bloom", bloomInputs);
|
||||||
|
|
||||||
const auto destFramebuffer = static_cast<gpu::FramebufferPointer>(nullptr);
|
const auto destFramebuffer = static_cast<gpu::FramebufferPointer>(nullptr);
|
||||||
|
|
|
@ -2210,7 +2210,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString&
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Triggered when the script starts for a user. See also, {@link Script.entityScriptPreloadFinished}.
|
* Triggered when the script starts for a user. See also, {@link Script.entityScriptPreloadFinished}.
|
||||||
* <p>Note: Can only be connected to via <code>this.preload = function (...) { ... }</code> in the entity script.</p>
|
* <p>Note: Can only be connected to via <code>this.preload = function (...) { ... }</code> in the entity script.</p>
|
||||||
* <table><tr><th>Available in:</th><td>Client Entity Scripts</td><td>Server Entity Scripts</td></tr></table>
|
* <p class="availableIn"><strong>Supported Script Types:</strong> Client Entity Scripts • Server Entity Scripts</p>
|
||||||
* @function Entities.preload
|
* @function Entities.preload
|
||||||
* @param {Uuid} entityID - The ID of the entity that the script is running in.
|
* @param {Uuid} entityID - The ID of the entity that the script is running in.
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
|
@ -2416,7 +2416,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Triggered when the script terminates for a user.
|
* Triggered when the script terminates for a user.
|
||||||
* <p>Note: Can only be connected to via <code>this.unoad = function () { ... }</code> in the entity script.</p>
|
* <p>Note: Can only be connected to via <code>this.unoad = function () { ... }</code> in the entity script.</p>
|
||||||
* <table><tr><th>Available in:</th><td>Client Entity Scripts</td><td>Server Entity Scripts</td></tr></table>
|
* <p class="availableIn"><strong>Supported Script Types:</strong> Client Entity Scripts • Server Entity Scripts</p>
|
||||||
* @function Entities.unload
|
* @function Entities.unload
|
||||||
* @param {Uuid} entityID - The ID of the entity that the script is running in.
|
* @param {Uuid} entityID - The ID of the entity that the script is running in.
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
|
|
|
@ -416,8 +416,10 @@ public:
|
||||||
* Provides access to methods or objects provided in an external JavaScript or JSON file.
|
* Provides access to methods or objects provided in an external JavaScript or JSON file.
|
||||||
* See {@link https://docs.highfidelity.com/script/js-tips.html} for further details.
|
* See {@link https://docs.highfidelity.com/script/js-tips.html} for further details.
|
||||||
* @function Script.require
|
* @function Script.require
|
||||||
* @param {string} module - The module to use. May be a JavaScript file or the name of a system module such as
|
* @param {string} module - The module to use. May be a JavaScript file, a JSON file, or the name of a system module such
|
||||||
* <code>"sppUi"</code>.
|
* as <code>"appUi"</code> (i.e., the "appUi.js" system module JavaScript file).
|
||||||
|
* @returns {object|array} The value assigned to <code>module.exports</code> in the JavaScript file, or the value defined
|
||||||
|
* in the JSON file.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE QScriptValue require(const QString& moduleId);
|
Q_INVOKABLE QScriptValue require(const QString& moduleId);
|
||||||
|
|
||||||
|
@ -842,7 +844,7 @@ signals:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Triggered when the script starts for the user. See also, {@link Entities.preload}.
|
* Triggered when the script starts for the user. See also, {@link Entities.preload}.
|
||||||
* <table><tr><th>Available in:</th><td>Client Entity Scripts</td><td>Server Entity Scripts</td></tr></table>
|
* <p class="availableIn"><strong>Supported Script Types:</strong> Client Entity Scripts • Server Entity Scripts</p>
|
||||||
* @function Script.entityScriptPreloadFinished
|
* @function Script.entityScriptPreloadFinished
|
||||||
* @param {Uuid} entityID - The ID of the entity that the script is running in.
|
* @param {Uuid} entityID - The ID of the entity that the script is running in.
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
|
|
|
@ -1319,13 +1319,13 @@ void ViveControllerManager::InputDevice::setConfigFromString(const QString& valu
|
||||||
* <tr><td><code>RX</code></td><td>number</td><td>number</td><td>Right stick x-axis scale.</td></tr>
|
* <tr><td><code>RX</code></td><td>number</td><td>number</td><td>Right stick x-axis scale.</td></tr>
|
||||||
* <tr><td><code>RY</code></td><td>number</td><td>number</td><td>Right stick y-axis scale.</td></tr>
|
* <tr><td><code>RY</code></td><td>number</td><td>number</td><td>Right stick y-axis scale.</td></tr>
|
||||||
* <tr><td><code>LS</code></td><td>number</td><td>number</td><td>Left touch pad pressed.</td></tr>
|
* <tr><td><code>LS</code></td><td>number</td><td>number</td><td>Left touch pad pressed.</td></tr>
|
||||||
* <tr><td><code>LS_CENTER</code></td><td>number</td><td>number</td><td>Left touch pad center pressed.</td></tr>
|
* <tr><td><code>LSCenter</code></td><td>number</td><td>number</td><td>Left touch pad center pressed.</td></tr>
|
||||||
* <tr><td><code>LS_X</code></td><td>number</td><td>number</td><td>Left touch pad pressed x-coordinate.</td></tr>
|
* <tr><td><code>LSX</code></td><td>number</td><td>number</td><td>Left touch pad pressed x-coordinate.</td></tr>
|
||||||
* <tr><td><code>LS_Y</code></td><td>number</td><td>number</td><td>Left touch pad pressed y-coordinate.</td></tr>
|
* <tr><td><code>LSY</code></td><td>number</td><td>number</td><td>Left touch pad pressed y-coordinate.</td></tr>
|
||||||
* <tr><td><code>RS</code></td><td>number</td><td>number</td><td>Right touch pad pressed.</td></tr>
|
* <tr><td><code>RS</code></td><td>number</td><td>number</td><td>Right touch pad pressed.</td></tr>
|
||||||
* <tr><td><code>RS_CENTER</code></td><td>number</td><td>number</td><td>Right touch pad center pressed.</td></tr>
|
* <tr><td><code>RSCenter</code></td><td>number</td><td>number</td><td>Right touch pad center pressed.</td></tr>
|
||||||
* <tr><td><code>RS_X</code></td><td>number</td><td>number</td><td>Right touch pad pressed x-coordinate.</td></tr>
|
* <tr><td><code>RSX</code></td><td>number</td><td>number</td><td>Right touch pad pressed x-coordinate.</td></tr>
|
||||||
* <tr><td><code>RS_Y</code></td><td>number</td><td>number</td><td>Right touch pad pressed y-coordinate.</td></tr>
|
* <tr><td><code>RSY</code></td><td>number</td><td>number</td><td>Right touch pad pressed y-coordinate.</td></tr>
|
||||||
* <tr><td><code>LSTouch</code></td><td>number</td><td>number</td><td>Left touch pad is touched.</td></tr>
|
* <tr><td><code>LSTouch</code></td><td>number</td><td>number</td><td>Left touch pad is touched.</td></tr>
|
||||||
* <tr><td><code>RSTouch</code></td><td>number</td><td>number</td><td>Right touch pad is touched.</td></tr>
|
* <tr><td><code>RSTouch</code></td><td>number</td><td>number</td><td>Right touch pad is touched.</td></tr>
|
||||||
* <tr><td colspan="4"><strong>Triggers</strong></td></tr>
|
* <tr><td colspan="4"><strong>Triggers</strong></td></tr>
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
//
|
|
||||||
// bloom.qml
|
|
||||||
// developer/utilities/render
|
|
||||||
//
|
|
||||||
// Olivier Prat, created on 09/25/2017.
|
|
||||||
// Copyright 2017 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
import QtQuick 2.5
|
|
||||||
import QtQuick.Controls 1.4
|
|
||||||
import "configSlider"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
property var configDebug: Render.getConfig("RenderMainView.DebugBloom")
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: 8
|
|
||||||
|
|
||||||
GroupBox {
|
|
||||||
title: "Debug"
|
|
||||||
Row {
|
|
||||||
ExclusiveGroup { id: debugGroup }
|
|
||||||
RadioButton {
|
|
||||||
text : "Off"
|
|
||||||
checked : !root.configDebug["enabled"]
|
|
||||||
onCheckedChanged: {
|
|
||||||
if (checked) {
|
|
||||||
root.configDebug["enabled"] = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveGroup : debugGroup
|
|
||||||
}
|
|
||||||
RadioButton {
|
|
||||||
text : "Lvl 0"
|
|
||||||
checked :root.configDebug["enabled"] && root.configDebug["mode"]==0
|
|
||||||
onCheckedChanged: {
|
|
||||||
if (checked) {
|
|
||||||
root.configDebug["enabled"] = true
|
|
||||||
root.configDebug["mode"] = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveGroup : debugGroup
|
|
||||||
}
|
|
||||||
RadioButton {
|
|
||||||
text : "Lvl 1"
|
|
||||||
checked : root.configDebug["enabled"] && root.configDebug["mode"]==1
|
|
||||||
onCheckedChanged: {
|
|
||||||
if (checked) {
|
|
||||||
root.configDebug["enabled"] = true
|
|
||||||
root.configDebug["mode"] = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveGroup : debugGroup
|
|
||||||
}
|
|
||||||
RadioButton {
|
|
||||||
text : "Lvl 2"
|
|
||||||
checked : root.configDebug["enabled"] && root.configDebug["mode"]==2
|
|
||||||
onCheckedChanged: {
|
|
||||||
if (checked) {
|
|
||||||
root.configDebug["enabled"] = true
|
|
||||||
root.configDebug["mode"] = 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveGroup : debugGroup
|
|
||||||
}
|
|
||||||
RadioButton {
|
|
||||||
text : "All"
|
|
||||||
checked : root.configDebug["enabled"] && root.configDebug["mode"]==3
|
|
||||||
onCheckedChanged: {
|
|
||||||
if (checked) {
|
|
||||||
root.configDebug["enabled"] = true
|
|
||||||
root.configDebug["mode"] = 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveGroup : debugGroup
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,11 +10,8 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
// Set up the qml ui
|
// Set up the qml ui
|
||||||
var qml = Script.resolvePath('bloom.qml');
|
var window = Desktop.createWindow(Script.resolvePath('./luci/Bloom.qml'), {
|
||||||
var window = new OverlayWindow({
|
title: "Bloom",
|
||||||
title: 'Bloom',
|
presentationMode: Desktop.PresentationMode.NATIVE,
|
||||||
source: qml,
|
size: {x: 285, y: 40}
|
||||||
width: 285,
|
|
||||||
height: 40,
|
|
||||||
});
|
});
|
||||||
window.closed.connect(function() { Script.stop(); });
|
|
|
@ -1,103 +0,0 @@
|
||||||
//
|
|
||||||
// deferredLighting.qml
|
|
||||||
//
|
|
||||||
// Created by Sam Gateau on 6/6/2016
|
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
import QtQuick 2.7
|
|
||||||
import QtQuick.Controls 1.4
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
|
|
||||||
import stylesUit 1.0
|
|
||||||
import controlsUit 1.0 as HifiControls
|
|
||||||
import "configSlider"
|
|
||||||
import "luci"
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
HifiConstants { id: hifi;}
|
|
||||||
id: render;
|
|
||||||
anchors.margins: hifi.dimensions.contentMargin.x
|
|
||||||
|
|
||||||
color: hifi.colors.baseGray;
|
|
||||||
property var mainViewTask: Render.getConfig("RenderMainView")
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: 5
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.margins: hifi.dimensions.contentMargin.x
|
|
||||||
|
|
||||||
|
|
||||||
HifiControls.Label {
|
|
||||||
text: "Shading"
|
|
||||||
}
|
|
||||||
ShadingModel {}
|
|
||||||
|
|
||||||
Separator {}
|
|
||||||
ToneMapping {}
|
|
||||||
|
|
||||||
Separator {}
|
|
||||||
Column {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
spacing: 5
|
|
||||||
Repeater {
|
|
||||||
model: [ "MSAA:PreparePrimaryBufferForward:numSamples:4:1"
|
|
||||||
]
|
|
||||||
ConfigSlider {
|
|
||||||
label: qsTr(modelData.split(":")[0])
|
|
||||||
integral: true
|
|
||||||
config: render.mainViewTask.getConfig(modelData.split(":")[1])
|
|
||||||
property: modelData.split(":")[2]
|
|
||||||
max: modelData.split(":")[3]
|
|
||||||
min: modelData.split(":")[4]
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Separator {}
|
|
||||||
Framebuffer {}
|
|
||||||
|
|
||||||
Separator {}
|
|
||||||
BoundingBoxes {
|
|
||||||
|
|
||||||
}
|
|
||||||
Separator {}
|
|
||||||
Row {
|
|
||||||
HifiControls.Button {
|
|
||||||
text: "Engine"
|
|
||||||
// activeFocusOnPress: false
|
|
||||||
onClicked: {
|
|
||||||
sendToScript({method: "openEngineView"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HifiControls.Button {
|
|
||||||
text: "LOD"
|
|
||||||
// activeFocusOnPress: false
|
|
||||||
onClicked: {
|
|
||||||
sendToScript({method: "openEngineLODView"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HifiControls.Button {
|
|
||||||
text: "Cull"
|
|
||||||
// activeFocusOnPress: false
|
|
||||||
onClicked: {
|
|
||||||
sendToScript({method: "openCullInspectorView"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
HifiControls.Button {
|
|
||||||
text: "Material"
|
|
||||||
onClicked: {
|
|
||||||
sendToScript({method: "openMaterialInspectorView"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +1,84 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//
|
|
||||||
// Luci.js
|
|
||||||
// tablet-engine app
|
|
||||||
//
|
|
||||||
// Copyright 2017 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
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
var MaterialInspector = Script.require('./materialInspector.js');
|
||||||
|
var Page = Script.require('./luci/Page.js');
|
||||||
|
|
||||||
(function() {
|
|
||||||
var AppUi = Script.require('appUi');
|
|
||||||
|
|
||||||
var MaterialInspector = Script.require('./materialInspector.js');
|
function openView() {
|
||||||
var Page = Script.require('./luci/Page.js');
|
//window.closed.connect(function() { Script.stop(); });
|
||||||
|
|
||||||
var moveDebugCursor = false;
|
|
||||||
var onMousePressEvent = function (e) {
|
|
||||||
if (e.isMiddleButton) {
|
|
||||||
moveDebugCursor = true;
|
|
||||||
setDebugCursor(e.x, e.y);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Controller.mousePressEvent.connect(onMousePressEvent);
|
|
||||||
|
|
||||||
var onMouseReleaseEvent = function () {
|
|
||||||
moveDebugCursor = false;
|
|
||||||
};
|
|
||||||
Controller.mouseReleaseEvent.connect(onMouseReleaseEvent);
|
|
||||||
|
|
||||||
var onMouseMoveEvent = function (e) {
|
|
||||||
if (moveDebugCursor) {
|
|
||||||
setDebugCursor(e.x, e.y);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Controller.mouseMoveEvent.connect(onMouseMoveEvent);
|
|
||||||
|
|
||||||
function setDebugCursor(x, y) {
|
|
||||||
var nx = 2.0 * (x / Window.innerWidth) - 1.0;
|
|
||||||
var ny = 1.0 - 2.0 * ((y) / (Window.innerHeight));
|
|
||||||
|
|
||||||
Render.getConfig("RenderMainView").getConfig("DebugDeferredBuffer").size = { x: nx, y: ny, z: 1.0, w: 1.0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var pages = new Pages();
|
var pages = new Pages();
|
||||||
|
|
||||||
pages.addPage('openEngineLODView', 'Render LOD', '../lod.qml', 300, 400);
|
|
||||||
pages.addPage('openCullInspectorView', 'Cull Inspector', '../luci/Culling.qml', 300, 400);
|
|
||||||
pages.addPage('openMaterialInspectorView', 'Material Inspector', '../materialInspector.qml', 300, 400, MaterialInspector.setWindow);
|
|
||||||
|
|
||||||
function fromQml(message) {
|
function fromQml(message) {
|
||||||
if (pages.open(message.method)) {
|
if (pages.open(message.method)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ui;
|
var luciWindow
|
||||||
function startup() {
|
function openLuciWindow(window) {
|
||||||
ui = new AppUi({
|
if (luciWindow !== undefined) {
|
||||||
buttonName: "LUCI",
|
activeWindow.fromQml.disconnect(fromQml);
|
||||||
home: Script.resolvePath("deferredLighting.qml"),
|
}
|
||||||
additionalAppScreens : Script.resolvePath("engineInspector.qml"),
|
if (window !== undefined) {
|
||||||
onMessage: fromQml,
|
window.fromQml.connect(fromQml);
|
||||||
normalButton: Script.resolvePath("../../../system/assets/images/luci-i.svg"),
|
}
|
||||||
activeButton: Script.resolvePath("../../../system/assets/images/luci-a.svg")
|
luciWindow = window;
|
||||||
});
|
|
||||||
|
|
||||||
|
var moveDebugCursor = false;
|
||||||
|
var onMousePressEvent = function (e) {
|
||||||
|
if (e.isMiddleButton) {
|
||||||
|
moveDebugCursor = true;
|
||||||
|
setDebugCursor(e.x, e.y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Controller.mousePressEvent.connect(onMousePressEvent);
|
||||||
|
|
||||||
|
var onMouseReleaseEvent = function () {
|
||||||
|
moveDebugCursor = false;
|
||||||
|
};
|
||||||
|
Controller.mouseReleaseEvent.connect(onMouseReleaseEvent);
|
||||||
|
|
||||||
|
var onMouseMoveEvent = function (e) {
|
||||||
|
if (moveDebugCursor) {
|
||||||
|
setDebugCursor(e.x, e.y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Controller.mouseMoveEvent.connect(onMouseMoveEvent);
|
||||||
|
|
||||||
|
function setDebugCursor(x, y) {
|
||||||
|
var nx = 2.0 * (x / Window.innerWidth) - 1.0;
|
||||||
|
var ny = 1.0 - 2.0 * ((y) / (Window.innerHeight));
|
||||||
|
|
||||||
|
Render.getConfig("RenderMainView").getConfig("DebugDeferredBuffer").size = { x: nx, y: ny, z: 1.0, w: 1.0 };
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
startup();
|
|
||||||
Script.scriptEnding.connect(function () {
|
function closeLuciWindow() {
|
||||||
|
if (luciWindow !== undefined) {
|
||||||
|
activeWindow.fromQml.disconnect(fromQml);
|
||||||
|
}
|
||||||
|
luciWindow = {};
|
||||||
|
|
||||||
Controller.mousePressEvent.disconnect(onMousePressEvent);
|
Controller.mousePressEvent.disconnect(onMousePressEvent);
|
||||||
Controller.mouseReleaseEvent.disconnect(onMouseReleaseEvent);
|
Controller.mouseReleaseEvent.disconnect(onMouseReleaseEvent);
|
||||||
Controller.mouseMoveEvent.disconnect(onMouseMoveEvent);
|
Controller.mouseMoveEvent.disconnect(onMouseMoveEvent);
|
||||||
pages.clear();
|
pages.clear();
|
||||||
});
|
}
|
||||||
}());
|
|
||||||
|
pages.addPage('Luci', 'Luci', '../luci.qml', 300, 420, openLuciWindow, closeLuciWindow);
|
||||||
|
pages.addPage('openEngineInspectorView', 'Render Engine Inspector', '../engineInspector.qml', 300, 400);
|
||||||
|
pages.addPage('openEngineLODView', 'Render LOD', '../lod.qml', 300, 400);
|
||||||
|
pages.addPage('openMaterialInspectorView', 'Material Inspector', '../materialInspector.qml', 300, 400, MaterialInspector.setWindow, MaterialInspector.setWindow);
|
||||||
|
|
||||||
|
pages.open('Luci');
|
||||||
|
|
||||||
|
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
openView();
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,12 @@ Rectangle {
|
||||||
Antialiasing {}
|
Antialiasing {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Prop.PropFolderPanel {
|
||||||
|
label: "Bloom"
|
||||||
|
panelFrameData: Component {
|
||||||
|
Bloom {}
|
||||||
|
}
|
||||||
|
}
|
||||||
Prop.PropFolderPanel {
|
Prop.PropFolderPanel {
|
||||||
label: "Culling"
|
label: "Culling"
|
||||||
panelFrameData: Component {
|
panelFrameData: Component {
|
||||||
|
|
|
@ -22,15 +22,12 @@ import "../../lib/prop" as Prop
|
||||||
|
|
||||||
|
|
||||||
Column{
|
Column{
|
||||||
HifiConstants { id: hifi; }
|
id: antialiasing
|
||||||
|
|
||||||
id: antialiasing
|
|
||||||
padding: 10
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
spacing: 10
|
Prop.PropScalar {
|
||||||
Prop.PropScalar {
|
|
||||||
label: "MSAA"
|
label: "MSAA"
|
||||||
object: Render.getConfig("RenderMainView.PreparePrimaryBufferForward")
|
object: Render.getConfig("RenderMainView.PreparePrimaryBufferForward")
|
||||||
property: "numSamples"
|
property: "numSamples"
|
||||||
|
@ -38,49 +35,44 @@ Column{
|
||||||
max: 32
|
max: 32
|
||||||
integral: true
|
integral: true
|
||||||
}
|
}
|
||||||
Row {
|
|
||||||
spacing: 10
|
|
||||||
id: fxaaOnOff
|
|
||||||
property bool debugFXAA: false
|
|
||||||
HifiControls.Button {
|
|
||||||
function getTheText() {
|
|
||||||
if (Render.getConfig("RenderMainView.Antialiasing").fxaaOnOff) {
|
|
||||||
return "FXAA"
|
|
||||||
} else {
|
|
||||||
return "TAA"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
text: getTheText()
|
|
||||||
onClicked: {
|
|
||||||
var onOff = !Render.getConfig("RenderMainView.Antialiasing").fxaaOnOff;
|
|
||||||
if (onOff) {
|
|
||||||
Render.getConfig("RenderMainView.JitterCam").none();
|
|
||||||
Render.getConfig("RenderMainView.Antialiasing").fxaaOnOff = true;
|
|
||||||
} else {
|
|
||||||
Render.getConfig("RenderMainView.JitterCam").play();
|
|
||||||
Render.getConfig("RenderMainView.Antialiasing").fxaaOnOff = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
Prop.PropEnum {
|
||||||
}
|
label: "Deferred AA Method"
|
||||||
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
|
property: "mode"
|
||||||
|
enums: [
|
||||||
|
"Off",
|
||||||
|
"TAA",
|
||||||
|
"FXAA",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Prop.PropEnum {
|
||||||
|
id: jitter
|
||||||
|
label: "Jitter"
|
||||||
|
object: Render.getConfig("RenderMainView.JitterCam")
|
||||||
|
property: "state"
|
||||||
|
enums: [
|
||||||
|
"Off",
|
||||||
|
"On",
|
||||||
|
"Paused",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
Separator {}
|
Separator {}
|
||||||
|
|
||||||
|
Prop.PropScalar {
|
||||||
|
visible: (Render.getConfig("RenderMainView.JitterCam").state == 2)
|
||||||
|
label: "Sample Index"
|
||||||
|
object: Render.getConfig("RenderMainView.JitterCam")
|
||||||
|
property: "index"
|
||||||
|
// min: -1
|
||||||
|
// max: 32
|
||||||
|
readOnly: true
|
||||||
|
integral: true
|
||||||
|
}
|
||||||
Row {
|
Row {
|
||||||
|
visible: (Render.getConfig("RenderMainView.JitterCam").state == 2)
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
HifiControls.Button {
|
|
||||||
text: {
|
|
||||||
var state = 2 - (Render.getConfig("RenderMainView.JitterCam").freeze * 1 - Render.getConfig("RenderMainView.JitterCam").stop * 2);
|
|
||||||
if (state === 2) {
|
|
||||||
return "Jitter"
|
|
||||||
} else if (state === 1) {
|
|
||||||
return "Paused at " + Render.getConfig("RenderMainView.JitterCam").index + ""
|
|
||||||
} else {
|
|
||||||
return "No Jitter"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onClicked: { Render.getConfig("RenderMainView.JitterCam").cycleStopPauseRun(); }
|
|
||||||
}
|
|
||||||
HifiControls.Button {
|
HifiControls.Button {
|
||||||
text: "<"
|
text: "<"
|
||||||
onClicked: { Render.getConfig("RenderMainView.JitterCam").prev(); }
|
onClicked: { Render.getConfig("RenderMainView.JitterCam").prev(); }
|
||||||
|
@ -91,95 +83,74 @@ Column{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Separator {}
|
Separator {}
|
||||||
HifiControls.CheckBox {
|
Prop.PropBool {
|
||||||
boxSize: 20
|
label: "Constrain color"
|
||||||
text: "Constrain color"
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
checked: Render.getConfig("RenderMainView.Antialiasing")["constrainColor"]
|
property: "constrainColor"
|
||||||
onCheckedChanged: { Render.getConfig("RenderMainView.Antialiasing")["constrainColor"] = checked }
|
|
||||||
}
|
}
|
||||||
ConfigSlider {
|
Prop.PropScalar {
|
||||||
label: qsTr("Covariance gamma")
|
label: "Covariance gamma"
|
||||||
integral: false
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
config: Render.getConfig("RenderMainView.Antialiasing")
|
|
||||||
property: "covarianceGamma"
|
property: "covarianceGamma"
|
||||||
max: 1.5
|
max: 1.5
|
||||||
min: 0.5
|
min: 0.5
|
||||||
height: 38
|
|
||||||
}
|
}
|
||||||
Separator {}
|
Separator {}
|
||||||
HifiControls.CheckBox {
|
Prop.PropBool {
|
||||||
boxSize: 20
|
label: "Feedback history color"
|
||||||
text: "Feedback history color"
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
checked: Render.getConfig("RenderMainView.Antialiasing")["feedbackColor"]
|
property: "feedbackColor"
|
||||||
onCheckedChanged: { Render.getConfig("RenderMainView.Antialiasing")["feedbackColor"] = checked }
|
|
||||||
}
|
}
|
||||||
|
Prop.PropScalar {
|
||||||
ConfigSlider {
|
label: "Source blend"
|
||||||
label: qsTr("Source blend")
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
integral: false
|
|
||||||
config: Render.getConfig("RenderMainView.Antialiasing")
|
|
||||||
property: "blend"
|
property: "blend"
|
||||||
max: 1.0
|
max: 1.0
|
||||||
min: 0.0
|
min: 0.0
|
||||||
height: 38
|
|
||||||
}
|
}
|
||||||
|
Prop.PropScalar {
|
||||||
ConfigSlider {
|
label: "Post sharpen"
|
||||||
label: qsTr("Post sharpen")
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
integral: false
|
|
||||||
config: Render.getConfig("RenderMainView.Antialiasing")
|
|
||||||
property: "sharpen"
|
property: "sharpen"
|
||||||
max: 1.0
|
max: 1.0
|
||||||
min: 0.0
|
min: 0.0
|
||||||
}
|
}
|
||||||
Separator {}
|
Separator {}
|
||||||
Row {
|
Prop.PropBool {
|
||||||
|
label: "Debug"
|
||||||
spacing: 10
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
HifiControls.CheckBox {
|
property: "debug"
|
||||||
boxSize: 20
|
|
||||||
text: "Debug"
|
|
||||||
checked: Render.getConfig("RenderMainView.Antialiasing")["debug"]
|
|
||||||
onCheckedChanged: { Render.getConfig("RenderMainView.Antialiasing")["debug"] = checked }
|
|
||||||
}
|
|
||||||
HifiControls.CheckBox {
|
|
||||||
boxSize: 20
|
|
||||||
text: "Show Debug Cursor"
|
|
||||||
checked: Render.getConfig("RenderMainView.Antialiasing")["showCursorPixel"]
|
|
||||||
onCheckedChanged: { Render.getConfig("RenderMainView.Antialiasing")["showCursorPixel"] = checked }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ConfigSlider {
|
Prop.PropBool {
|
||||||
label: qsTr("Debug Region <")
|
label: "Show Debug Cursor"
|
||||||
integral: false
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
config: Render.getConfig("RenderMainView.Antialiasing")
|
property: "showCursorPixel"
|
||||||
|
}
|
||||||
|
Prop.PropScalar {
|
||||||
|
label: "Debug Region <"
|
||||||
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
property: "debugX"
|
property: "debugX"
|
||||||
max: 1.0
|
max: 1.0
|
||||||
min: 0.0
|
min: 0.0
|
||||||
}
|
}
|
||||||
HifiControls.CheckBox {
|
Prop.PropBool {
|
||||||
boxSize: 20
|
label: "Closest Fragment"
|
||||||
text: "Closest Fragment"
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
checked: Render.getConfig("RenderMainView.Antialiasing")["showClosestFragment"]
|
property: "showClosestFragment"
|
||||||
onCheckedChanged: { Render.getConfig("RenderMainView.Antialiasing")["showClosestFragment"] = checked }
|
|
||||||
}
|
}
|
||||||
ConfigSlider {
|
Prop.PropScalar {
|
||||||
label: qsTr("Debug Velocity Threshold [pix]")
|
label: "Debug Velocity Threshold [pix]"
|
||||||
integral: false
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
config: Render.getConfig("RenderMainView.Antialiasing")
|
|
||||||
property: "debugShowVelocityThreshold"
|
property: "debugShowVelocityThreshold"
|
||||||
max: 50
|
max: 50
|
||||||
min: 0.0
|
min: 0.0
|
||||||
height: 38
|
|
||||||
}
|
}
|
||||||
ConfigSlider {
|
Prop.PropScalar {
|
||||||
label: qsTr("Debug Orb Zoom")
|
label: "Debug Orb Zoom"
|
||||||
integral: false
|
object: Render.getConfig("RenderMainView.Antialiasing")
|
||||||
config: Render.getConfig("RenderMainView.Antialiasing")
|
|
||||||
property: "debugOrbZoom"
|
property: "debugOrbZoom"
|
||||||
max: 32.0
|
max: 32.0
|
||||||
min: 1.0
|
min: 1.0
|
||||||
height: 38
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
48
scripts/developer/utilities/render/luci/Bloom.qml
Normal file
48
scripts/developer/utilities/render/luci/Bloom.qml
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
//
|
||||||
|
// bloom.qml
|
||||||
|
//
|
||||||
|
// Olivier Prat, created on 09/25/2017.
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
import QtQuick 2.7
|
||||||
|
import "../../lib/prop" as Prop
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
id: bloom
|
||||||
|
|
||||||
|
property var config: Render.getConfig("RenderMainView.DebugBloom")
|
||||||
|
|
||||||
|
Prop.PropBool {
|
||||||
|
label: "Apply Bloom"
|
||||||
|
object: Render.getConfig("RenderMainView.LightingModel")
|
||||||
|
property: "enableBloom"
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDebugMode(mode) {
|
||||||
|
console.log("Bloom mode is " + mode)
|
||||||
|
bloom.config.enabled = (mode != 0);
|
||||||
|
bloom.config.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Prop.PropEnum {
|
||||||
|
label: "Debug Bloom Buffer"
|
||||||
|
// object: config
|
||||||
|
// property: "mode"
|
||||||
|
enums: [
|
||||||
|
"Off",
|
||||||
|
"Lvl 0",
|
||||||
|
"Lvl 1",
|
||||||
|
"Lvl 2",
|
||||||
|
"All",
|
||||||
|
]
|
||||||
|
|
||||||
|
valueVarSetter: function (mode) { bloom.setDebugMode(mode) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ Column {
|
||||||
Prop.PropCheckBox {
|
Prop.PropCheckBox {
|
||||||
text: "Zones"
|
text: "Zones"
|
||||||
checked: root.mainViewTask.getConfig("DrawZones")["enabled"]
|
checked: root.mainViewTask.getConfig("DrawZones")["enabled"]
|
||||||
onCheckedChanged: { root.mainViewTask.getConfig("ZoneRenderer")["enabled"] = checked; root.mainViewTask.getConfig("DrawZones")["enabled"] = checked; }
|
onCheckedChanged: { root.mainViewTask.getConfig("DrawZones")["enabled"] = checked; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Column {
|
Column {
|
||||||
|
|
|
@ -36,6 +36,7 @@ Column {
|
||||||
"Lightmap:LightingModel:enableLightmap",
|
"Lightmap:LightingModel:enableLightmap",
|
||||||
"Background:LightingModel:enableBackground",
|
"Background:LightingModel:enableBackground",
|
||||||
"Haze:LightingModel:enableHaze",
|
"Haze:LightingModel:enableHaze",
|
||||||
|
"Bloom:LightingModel:enableBloom",
|
||||||
"AO:LightingModel:enableAmbientOcclusion",
|
"AO:LightingModel:enableAmbientOcclusion",
|
||||||
"Textures:LightingModel:enableMaterialTexturing"
|
"Textures:LightingModel:enableMaterialTexturing"
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,6 +5,7 @@ BoundingBoxes 1.0 BoundingBoxes.qml
|
||||||
Framebuffer 1.0 Framebuffer.qml
|
Framebuffer 1.0 Framebuffer.qml
|
||||||
Antialiasing 1.0 Antialiasing.qml
|
Antialiasing 1.0 Antialiasing.qml
|
||||||
Culling 1.0 Culling.qml
|
Culling 1.0 Culling.qml
|
||||||
|
Bloom 1.0 Bloom.qml
|
||||||
|
|
||||||
Platform 1.0 Platform.qml
|
Platform 1.0 Platform.qml
|
||||||
RenderSettings 1.0 RenderSettings.qml
|
RenderSettings 1.0 RenderSettings.qml
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
var MaterialInspector = Script.require('./materialInspector.js');
|
|
||||||
var Page = Script.require('./luci/Page.js');
|
|
||||||
|
|
||||||
|
|
||||||
function openView() {
|
|
||||||
//window.closed.connect(function() { Script.stop(); });
|
|
||||||
|
|
||||||
|
|
||||||
var pages = new Pages();
|
|
||||||
function fromQml(message) {
|
|
||||||
if (pages.open(message.method)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var luciWindow
|
|
||||||
function openLuciWindow(window) {
|
|
||||||
if (luciWindow !== undefined) {
|
|
||||||
activeWindow.fromQml.disconnect(fromQml);
|
|
||||||
}
|
|
||||||
if (window !== undefined) {
|
|
||||||
window.fromQml.connect(fromQml);
|
|
||||||
}
|
|
||||||
luciWindow = window;
|
|
||||||
|
|
||||||
|
|
||||||
var moveDebugCursor = false;
|
|
||||||
var onMousePressEvent = function (e) {
|
|
||||||
if (e.isMiddleButton) {
|
|
||||||
moveDebugCursor = true;
|
|
||||||
setDebugCursor(e.x, e.y);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Controller.mousePressEvent.connect(onMousePressEvent);
|
|
||||||
|
|
||||||
var onMouseReleaseEvent = function () {
|
|
||||||
moveDebugCursor = false;
|
|
||||||
};
|
|
||||||
Controller.mouseReleaseEvent.connect(onMouseReleaseEvent);
|
|
||||||
|
|
||||||
var onMouseMoveEvent = function (e) {
|
|
||||||
if (moveDebugCursor) {
|
|
||||||
setDebugCursor(e.x, e.y);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Controller.mouseMoveEvent.connect(onMouseMoveEvent);
|
|
||||||
|
|
||||||
function setDebugCursor(x, y) {
|
|
||||||
var nx = 2.0 * (x / Window.innerWidth) - 1.0;
|
|
||||||
var ny = 1.0 - 2.0 * ((y) / (Window.innerHeight));
|
|
||||||
|
|
||||||
Render.getConfig("RenderMainView").getConfig("DebugDeferredBuffer").size = { x: nx, y: ny, z: 1.0, w: 1.0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeLuciWindow() {
|
|
||||||
if (luciWindow !== undefined) {
|
|
||||||
activeWindow.fromQml.disconnect(fromQml);
|
|
||||||
}
|
|
||||||
luciWindow = {};
|
|
||||||
|
|
||||||
Controller.mousePressEvent.disconnect(onMousePressEvent);
|
|
||||||
Controller.mouseReleaseEvent.disconnect(onMouseReleaseEvent);
|
|
||||||
Controller.mouseMoveEvent.disconnect(onMouseMoveEvent);
|
|
||||||
pages.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pages.addPage('Luci', 'Luci', '../luci.qml', 300, 420, openLuciWindow, closeLuciWindow);
|
|
||||||
pages.addPage('openEngineInspectorView', 'Render Engine Inspector', '../engineInspector.qml', 300, 400);
|
|
||||||
pages.addPage('openEngineLODView', 'Render LOD', '../lod.qml', 300, 400);
|
|
||||||
pages.addPage('openMaterialInspectorView', 'Material Inspector', '../materialInspector.qml', 300, 400, MaterialInspector.setWindow, MaterialInspector.setWindow);
|
|
||||||
|
|
||||||
pages.open('Luci');
|
|
||||||
|
|
||||||
|
|
||||||
return pages;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
openView();
|
|
||||||
|
|
|
@ -388,7 +388,8 @@ function playPopAnimation() {
|
||||||
var emojiCodeMap;
|
var emojiCodeMap;
|
||||||
var customEmojiCodeMap;
|
var customEmojiCodeMap;
|
||||||
var signalsConnected = false;
|
var signalsConnected = false;
|
||||||
function init() {
|
var _this;
|
||||||
|
function startup() {
|
||||||
// make a map of just the utf codes to help with accesing
|
// make a map of just the utf codes to help with accesing
|
||||||
emojiCodeMap = emojiList.reduce(function (codeMap, currentEmojiInList, index) {
|
emojiCodeMap = emojiList.reduce(function (codeMap, currentEmojiInList, index) {
|
||||||
if (
|
if (
|
||||||
|
@ -414,55 +415,30 @@ function init() {
|
||||||
|
|
||||||
pruneOldAvimojis();
|
pruneOldAvimojis();
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(unload);
|
||||||
Window.domainChanged.connect(onDomainChanged);
|
Window.domainChanged.connect(onDomainChanged);
|
||||||
MyAvatar.scaleChanged.connect(onScaleChanged);
|
MyAvatar.scaleChanged.connect(onScaleChanged);
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
|
||||||
signalsConnected = true;
|
signalsConnected = true;
|
||||||
}
|
|
||||||
|
|
||||||
|
function AviMoji() {
|
||||||
// #endregion
|
_this = this;
|
||||||
// *************************************
|
this._avimojiQMLWindow = null;
|
||||||
// END main
|
|
||||||
// *************************************
|
|
||||||
|
|
||||||
// *************************************
|
|
||||||
// START cleanup
|
|
||||||
// *************************************
|
|
||||||
// #region cleanup
|
|
||||||
|
|
||||||
|
|
||||||
function scriptEnding() {
|
|
||||||
resetEmojis();
|
|
||||||
if (signalsConnected) {
|
|
||||||
Script.scriptEnding.disconnect(scriptEnding);
|
|
||||||
Window.domainChanged.disconnect(onDomainChanged);
|
|
||||||
MyAvatar.scaleChanged.disconnect(onScaleChanged);
|
|
||||||
signalsConnected = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AviMoji.prototype = {
|
||||||
|
addEmoji: addEmojiFromQML,
|
||||||
|
registerAvimojiQMLWindow: registerAvimojiQMLWindow
|
||||||
|
};
|
||||||
|
|
||||||
|
return new AviMoji();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #endregion
|
|
||||||
// *************************************
|
|
||||||
// END cleanup
|
|
||||||
// *************************************
|
|
||||||
|
|
||||||
// *************************************
|
|
||||||
// START API
|
|
||||||
// *************************************
|
|
||||||
// #region API
|
|
||||||
|
|
||||||
var _this;
|
|
||||||
function AviMoji() {
|
|
||||||
_this = this;
|
|
||||||
this._avimojiQMLWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerAvimojiQMLWindow(avimojiQMLWindow) {
|
function registerAvimojiQMLWindow(avimojiQMLWindow) {
|
||||||
this._avimojiQMLWindow = avimojiQMLWindow;
|
this._avimojiQMLWindow = avimojiQMLWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function addEmojiFromQML(code) {
|
function addEmojiFromQML(code) {
|
||||||
var emojiObject = emojiList[emojiCodeMap[code]];
|
var emojiObject = emojiList[emojiCodeMap[code]];
|
||||||
var emojiFilename;
|
var emojiFilename;
|
||||||
|
@ -475,25 +451,17 @@ function addEmojiFromQML(code) {
|
||||||
handleSelectedEmoji(emojiFilename);
|
handleSelectedEmoji(emojiFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function unload() {
|
function unload() {
|
||||||
scriptEnding();
|
resetEmojis();
|
||||||
|
if (signalsConnected) {
|
||||||
|
Window.domainChanged.disconnect(onDomainChanged);
|
||||||
|
MyAvatar.scaleChanged.disconnect(onScaleChanged);
|
||||||
|
signalsConnected = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startup() {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
AviMoji.prototype = {
|
var aviMoji = startup();
|
||||||
startup: startup,
|
|
||||||
addEmoji: addEmojiFromQML,
|
|
||||||
unload: unload,
|
|
||||||
registerAvimojiQMLWindow: registerAvimojiQMLWindow
|
|
||||||
};
|
|
||||||
|
|
||||||
|
module.exports = aviMoji;
|
||||||
module.exports = AviMoji;
|
|
||||||
|
|
||||||
// #endregion
|
|
||||||
// *************************************
|
|
||||||
// END API
|
|
||||||
// *************************************
|
|
|
@ -38,7 +38,6 @@ var customEmojiList = Script.require("./emojiApp/resources/modules/customEmojiLi
|
||||||
// #region EMOTE_UTILITY
|
// #region EMOTE_UTILITY
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function updateEmoteAppBarPosition() {
|
function updateEmoteAppBarPosition() {
|
||||||
if (!emoteAppBarWindow) {
|
if (!emoteAppBarWindow) {
|
||||||
return;
|
return;
|
||||||
|
@ -425,7 +424,7 @@ function onGeometryChanged(rect) {
|
||||||
function onWindowMinimizedChanged(isMinimized) {
|
function onWindowMinimizedChanged(isMinimized) {
|
||||||
if (isMinimized) {
|
if (isMinimized) {
|
||||||
handleEmoteIndicatorVisibleChanged(false);
|
handleEmoteIndicatorVisibleChanged(false);
|
||||||
} else if (!HMD.active && Settings.getValue("simplifiedUI/emoteIndicatorVisible", true)) {
|
} else if (!HMD.active) {
|
||||||
handleEmoteIndicatorVisibleChanged(true);
|
handleEmoteIndicatorVisibleChanged(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -520,8 +519,8 @@ function showEmoteAppBar() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function handleEmoteIndicatorVisibleChanged(newValue) {
|
function handleEmoteIndicatorVisibleChanged(shouldBeVisible) {
|
||||||
if (newValue && !emoteAppBarWindow) {
|
if (shouldBeVisible && !emoteAppBarWindow) {
|
||||||
showEmoteAppBar();
|
showEmoteAppBar();
|
||||||
} else if (emoteAppBarWindow) {
|
} else if (emoteAppBarWindow) {
|
||||||
emoteAppBarWindow.fromQml.disconnect(onMessageFromEmoteAppBar);
|
emoteAppBarWindow.fromQml.disconnect(onMessageFromEmoteAppBar);
|
||||||
|
@ -531,13 +530,6 @@ function handleEmoteIndicatorVisibleChanged(newValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function onSettingsValueChanged(settingName, newValue) {
|
|
||||||
if (settingName === "simplifiedUI/emoteIndicatorVisible") {
|
|
||||||
handleEmoteIndicatorVisibleChanged(newValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function onDisplayModeChanged(isHMDMode) {
|
function onDisplayModeChanged(isHMDMode) {
|
||||||
reactionsBegun.forEach(function(react) {
|
reactionsBegun.forEach(function(react) {
|
||||||
endReactionWrapper(react);
|
endReactionWrapper(react);
|
||||||
|
@ -545,18 +537,17 @@ function onDisplayModeChanged(isHMDMode) {
|
||||||
|
|
||||||
if (isHMDMode) {
|
if (isHMDMode) {
|
||||||
handleEmoteIndicatorVisibleChanged(false);
|
handleEmoteIndicatorVisibleChanged(false);
|
||||||
} else if (Settings.getValue("simplifiedUI/emoteIndicatorVisible", true)) {
|
} else {
|
||||||
handleEmoteIndicatorVisibleChanged(true);
|
handleEmoteIndicatorVisibleChanged(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var EmojiAPI = Script.require("./emojiApp/simplifiedEmoji.js");
|
var emojiAPI = Script.require("./emojiApp/simplifiedEmoji.js");
|
||||||
var emojiAPI = new EmojiAPI();
|
|
||||||
var keyPressSignalsConnected = false;
|
var keyPressSignalsConnected = false;
|
||||||
var emojiCodeMap;
|
var emojiCodeMap;
|
||||||
var customEmojiCodeMap;
|
var customEmojiCodeMap;
|
||||||
function init() {
|
function setup() {
|
||||||
deleteOldReticles();
|
deleteOldReticles();
|
||||||
|
|
||||||
// make a map of just the utf codes to help with accesing
|
// make a map of just the utf codes to help with accesing
|
||||||
|
@ -584,22 +575,19 @@ function init() {
|
||||||
|
|
||||||
Window.minimizedChanged.connect(onWindowMinimizedChanged);
|
Window.minimizedChanged.connect(onWindowMinimizedChanged);
|
||||||
Window.geometryChanged.connect(onGeometryChanged);
|
Window.geometryChanged.connect(onGeometryChanged);
|
||||||
Settings.valueChanged.connect(onSettingsValueChanged);
|
|
||||||
HMD.displayModeChanged.connect(onDisplayModeChanged);
|
HMD.displayModeChanged.connect(onDisplayModeChanged);
|
||||||
emojiAPI.startup();
|
|
||||||
|
|
||||||
getSounds();
|
getSounds();
|
||||||
handleEmoteIndicatorVisibleChanged(Settings.getValue("simplifiedUI/emoteIndicatorVisible", true));
|
handleEmoteIndicatorVisibleChanged(true);
|
||||||
|
|
||||||
Controller.keyPressEvent.connect(keyPressHandler);
|
Controller.keyPressEvent.connect(keyPressHandler);
|
||||||
Controller.keyReleaseEvent.connect(keyReleaseHandler);
|
Controller.keyReleaseEvent.connect(keyReleaseHandler);
|
||||||
keyPressSignalsConnected = true;
|
keyPressSignalsConnected = true;
|
||||||
|
Script.scriptEnding.connect(unload);
|
||||||
Script.scriptEnding.connect(shutdown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function shutdown() {
|
function unload() {
|
||||||
if (emoteAppBarWindow) {
|
if (emoteAppBarWindow) {
|
||||||
emoteAppBarWindow.fromQml.disconnect(onMessageFromEmoteAppBar);
|
emoteAppBarWindow.fromQml.disconnect(onMessageFromEmoteAppBar);
|
||||||
emoteAppBarWindow.close();
|
emoteAppBarWindow.close();
|
||||||
|
@ -614,14 +602,12 @@ function shutdown() {
|
||||||
endReactionWrapper(react);
|
endReactionWrapper(react);
|
||||||
});
|
});
|
||||||
|
|
||||||
emojiAPI.unload();
|
|
||||||
maybeClearClapSoundInterval();
|
maybeClearClapSoundInterval();
|
||||||
maybeClearReticleUpdateLimiterTimeout();
|
maybeClearReticleUpdateLimiterTimeout();
|
||||||
maybeDeleteRemoteIndicatorTimeout();
|
maybeDeleteRemoteIndicatorTimeout();
|
||||||
|
|
||||||
Window.minimizedChanged.disconnect(onWindowMinimizedChanged);
|
Window.minimizedChanged.disconnect(onWindowMinimizedChanged);
|
||||||
Window.geometryChanged.disconnect(onGeometryChanged);
|
Window.geometryChanged.disconnect(onGeometryChanged);
|
||||||
Settings.valueChanged.disconnect(onSettingsValueChanged);
|
|
||||||
HMD.displayModeChanged.disconnect(onDisplayModeChanged);
|
HMD.displayModeChanged.disconnect(onDisplayModeChanged);
|
||||||
|
|
||||||
if (keyPressSignalsConnected) {
|
if (keyPressSignalsConnected) {
|
||||||
|
@ -768,37 +754,4 @@ function toggleEmojiApp() {
|
||||||
// END EMOJI
|
// END EMOJI
|
||||||
// *************************************
|
// *************************************
|
||||||
|
|
||||||
// *************************************
|
setup();
|
||||||
// START API
|
|
||||||
// *************************************
|
|
||||||
// #region API
|
|
||||||
|
|
||||||
|
|
||||||
function startup() {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function unload() {
|
|
||||||
shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
var _this;
|
|
||||||
function EmoteBar() {
|
|
||||||
_this = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EmoteBar.prototype = {
|
|
||||||
startup: startup,
|
|
||||||
unload: unload
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = EmoteBar;
|
|
||||||
|
|
||||||
|
|
||||||
// #endregion
|
|
||||||
// *************************************
|
|
||||||
// END API
|
|
||||||
// *************************************
|
|
||||||
|
|
|
@ -21,20 +21,24 @@ Rectangle {
|
||||||
id: root
|
id: root
|
||||||
color: simplifiedUI.colors.white
|
color: simplifiedUI.colors.white
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
property int originalWidth: 48
|
property int originalWidth: 48
|
||||||
property int expandedWidth: mainEmojiContainer.width + drawerContainer.width
|
property int expandedWidth: mainEmojiContainer.width + drawerContainer.width
|
||||||
// For the below to work, the Repeater's Item's second child must be the individual button's `MouseArea`
|
// For the below to work, the Repeater's Item's second child must be the individual button's `MouseArea`
|
||||||
property int requestedWidth: (drawerContainer.keepDrawerExpanded ||
|
property int requestedWidth: (
|
||||||
emoteIndicatorMouseArea.containsMouse ||
|
root.allowEmoteDrawerExpansion && (
|
||||||
emoteButtonsRepeater.itemAt(0).hovered ||
|
drawerContainer.keepDrawerExpanded ||
|
||||||
emoteButtonsRepeater.itemAt(1).hovered ||
|
emoteIndicatorMouseArea.containsMouse ||
|
||||||
emoteButtonsRepeater.itemAt(2).hovered ||
|
emoteButtonsRepeater.itemAt(0).hovered ||
|
||||||
emoteButtonsRepeater.itemAt(3).hovered ||
|
emoteButtonsRepeater.itemAt(1).hovered ||
|
||||||
emoteButtonsRepeater.itemAt(4).hovered ||
|
emoteButtonsRepeater.itemAt(2).hovered ||
|
||||||
emoteButtonsRepeater.itemAt(5).hovered) ? expandedWidth : originalWidth;
|
emoteButtonsRepeater.itemAt(3).hovered ||
|
||||||
|
emoteButtonsRepeater.itemAt(4).hovered ||
|
||||||
|
emoteButtonsRepeater.itemAt(5).hovered)
|
||||||
|
) ? expandedWidth : originalWidth;
|
||||||
readonly property int totalEmojiDurationMS: 7000 // Must match `TOTAL_EMOJI_DURATION_MS` in `simplifiedEmoji.js`
|
readonly property int totalEmojiDurationMS: 7000 // Must match `TOTAL_EMOJI_DURATION_MS` in `simplifiedEmoji.js`
|
||||||
readonly property string emoteIconSource: "images/emote_Icon.svg"
|
readonly property string emoteIconSource: "images/emote_Icon.svg"
|
||||||
|
property bool allowEmoteDrawerExpansion: Settings.getValue("simplifiedUI/allowEmoteDrawerExpansion", true)
|
||||||
|
|
||||||
|
|
||||||
onRequestedWidthChanged: {
|
onRequestedWidthChanged: {
|
||||||
root.requestNewWidth(root.requestedWidth);
|
root.requestNewWidth(root.requestedWidth);
|
||||||
|
@ -45,6 +49,16 @@ Rectangle {
|
||||||
SmoothedAnimation { duration: 220 }
|
SmoothedAnimation { duration: 220 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: Settings
|
||||||
|
|
||||||
|
onValueChanged: {
|
||||||
|
if (setting === "simplifiedUI/allowEmoteDrawerExpansion") {
|
||||||
|
root.allowEmoteDrawerExpansion = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SimplifiedConstants.SimplifiedConstants {
|
SimplifiedConstants.SimplifiedConstants {
|
||||||
id: simplifiedUI
|
id: simplifiedUI
|
||||||
}
|
}
|
||||||
|
@ -158,7 +172,7 @@ Rectangle {
|
||||||
anchors.fill: lockIcon
|
anchors.fill: lockIcon
|
||||||
source: lockIcon
|
source: lockIcon
|
||||||
color: "#ffffff"
|
color: "#ffffff"
|
||||||
visible: drawerContainer.keepDrawerExpanded
|
visible: root.allowEmoteDrawerExpansion && drawerContainer.keepDrawerExpanded
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|
|
@ -47,15 +47,24 @@ function onAvatarAdded(uuid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Called on init
|
// Create a new nametag list manager, connect signals, and return back a new Nametag object.
|
||||||
var avatarNametagMode;
|
var avatarNametagMode;
|
||||||
function startup() {
|
function startup() {
|
||||||
nameTagListManager.create();
|
nameTagListManager.create();
|
||||||
handleAvatarNametagMode(Settings.getValue("simplifiedNametag/avatarNametagMode", "on"));
|
handleAvatarNametagMode(Settings.getValue("simplifiedNametag/avatarNametagMode", "on"));
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(unload);
|
||||||
Window.domainChanged.connect(onDomainChange);
|
Window.domainChanged.connect(onDomainChange);
|
||||||
AvatarManager.avatarRemovedEvent.connect(onAvatarRemoved);
|
AvatarManager.avatarRemovedEvent.connect(onAvatarRemoved);
|
||||||
AvatarManager.avatarAddedEvent.connect(onAvatarAdded);
|
AvatarManager.avatarAddedEvent.connect(onAvatarAdded);
|
||||||
|
|
||||||
|
function NameTag() {}
|
||||||
|
|
||||||
|
NameTag.prototype = {
|
||||||
|
handleAvatarNametagMode: handleAvatarNametagMode
|
||||||
|
};
|
||||||
|
|
||||||
|
return new NameTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,23 +86,7 @@ function handleAvatarNametagMode(newAvatarNameTagMode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// *************************************
|
var nameTag = startup();
|
||||||
// START api
|
|
||||||
// *************************************
|
|
||||||
// #region api
|
|
||||||
|
|
||||||
function NameTag() {}
|
module.exports = nameTag;
|
||||||
|
|
||||||
NameTag.prototype = {
|
|
||||||
startup: startup,
|
|
||||||
unload: unload,
|
|
||||||
handleAvatarNametagMode: handleAvatarNametagMode
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = NameTag;
|
|
||||||
|
|
||||||
|
|
||||||
// #endregion
|
|
||||||
// *************************************
|
|
||||||
// END api
|
|
||||||
// *************************************
|
|
|
@ -8,7 +8,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
|
||||||
function simplifiedStatusIndicator(properties) {
|
function SimplifiedStatusIndicator() {
|
||||||
var that = this;
|
var that = this;
|
||||||
var DEBUG = false;
|
var DEBUG = false;
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ function simplifiedStatusIndicator(properties) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Get status from database
|
// Get status from database
|
||||||
function getStatus(callback) {
|
function getStatus(callback) {
|
||||||
var queryParamString = "type=getStatus";
|
var queryParamString = "type=getStatus";
|
||||||
|
@ -125,6 +126,17 @@ function simplifiedStatusIndicator(properties) {
|
||||||
|
|
||||||
// #region SIGNALS
|
// #region SIGNALS
|
||||||
|
|
||||||
|
function updateProperties(properties) {
|
||||||
|
// Overwrite with the given properties
|
||||||
|
var overwriteableKeys = ["statusChanged"];
|
||||||
|
Object.keys(properties).forEach(function (key) {
|
||||||
|
if (overwriteableKeys.indexOf(key) > -1) {
|
||||||
|
that[key] = properties[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var currentStatus = "available"; // Default is available
|
var currentStatus = "available"; // Default is available
|
||||||
function toggleStatus() {
|
function toggleStatus() {
|
||||||
if (currentStatus === "busy") {
|
if (currentStatus === "busy") {
|
||||||
|
@ -207,6 +219,8 @@ function simplifiedStatusIndicator(properties) {
|
||||||
Window.domainChanged.connect(onDomainChanged);
|
Window.domainChanged.connect(onDomainChanged);
|
||||||
|
|
||||||
getStatus(setStatus);
|
getStatus(setStatus);
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(unload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,20 +238,15 @@ function simplifiedStatusIndicator(properties) {
|
||||||
|
|
||||||
// #endregion APP LIFETIME
|
// #endregion APP LIFETIME
|
||||||
|
|
||||||
that.startup = startup;
|
|
||||||
that.unload = unload;
|
|
||||||
that.toggleStatus = toggleStatus;
|
that.toggleStatus = toggleStatus;
|
||||||
that.setStatus = setStatus;
|
that.setStatus = setStatus;
|
||||||
that.getLocalStatus = getLocalStatus;
|
that.getLocalStatus = getLocalStatus;
|
||||||
that.statusChanged = statusChanged;
|
that.statusChanged = statusChanged;
|
||||||
|
that.updateProperties = updateProperties;
|
||||||
|
|
||||||
// Overwrite with the given properties
|
startup();
|
||||||
var overwriteableKeys = ["statusChanged"];
|
|
||||||
Object.keys(properties).forEach(function (key) {
|
|
||||||
if (overwriteableKeys.indexOf(key) > -1) {
|
|
||||||
that[key] = properties[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var simplifiedStatusIndicator = new SimplifiedStatusIndicator();
|
||||||
|
|
||||||
module.exports = simplifiedStatusIndicator;
|
module.exports = simplifiedStatusIndicator;
|
|
@ -583,12 +583,9 @@ function restoreLODSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var SimplifiedNametag = Script.require("./simplifiedNametag/simplifiedNametag.js?" + Date.now());
|
var nametag = Script.require("./simplifiedNametag/simplifiedNametag.js?" + Date.now());
|
||||||
var SimplifiedStatusIndicator = Script.require("./simplifiedStatusIndicator/simplifiedStatusIndicator.js?" + Date.now());
|
var si = Script.require("./simplifiedStatusIndicator/simplifiedStatusIndicator.js?" + Date.now())
|
||||||
var SimplifiedEmote = Script.require("../simplifiedEmote/simplifiedEmote.js?" + Date.now());
|
var emote = Script.require("../simplifiedEmote/simplifiedEmote.js?" + Date.now());
|
||||||
var si;
|
|
||||||
var nametag;
|
|
||||||
var emote;
|
|
||||||
var oldShowAudioTools;
|
var oldShowAudioTools;
|
||||||
var oldShowBubbleTools;
|
var oldShowBubbleTools;
|
||||||
var keepExistingUIAndScriptsSetting = Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false);
|
var keepExistingUIAndScriptsSetting = Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false);
|
||||||
|
@ -607,16 +604,8 @@ function startup() {
|
||||||
|
|
||||||
loadSimplifiedTopBar();
|
loadSimplifiedTopBar();
|
||||||
|
|
||||||
si = new SimplifiedStatusIndicator({
|
|
||||||
statusChanged: onStatusChanged
|
|
||||||
});
|
|
||||||
si.startup();
|
|
||||||
|
|
||||||
nametag = new SimplifiedNametag();
|
si.updateProperties({ statusChanged: onStatusChanged });
|
||||||
nametag.startup();
|
|
||||||
|
|
||||||
emote = new SimplifiedEmote();
|
|
||||||
emote.startup();
|
|
||||||
|
|
||||||
updateInputDeviceMutedOverlay(Audio.muted);
|
updateInputDeviceMutedOverlay(Audio.muted);
|
||||||
updateOutputDeviceMutedOverlay(isOutputMuted());
|
updateOutputDeviceMutedOverlay(isOutputMuted());
|
||||||
|
@ -665,10 +654,6 @@ function shutdown() {
|
||||||
maybeDeleteInputDeviceMutedOverlay();
|
maybeDeleteInputDeviceMutedOverlay();
|
||||||
maybeDeleteOutputDeviceMutedOverlay();
|
maybeDeleteOutputDeviceMutedOverlay();
|
||||||
|
|
||||||
nametag.unload();
|
|
||||||
si.unload();
|
|
||||||
emote.unload();
|
|
||||||
|
|
||||||
Audio.mutedDesktopChanged.disconnect(onDesktopInputDeviceMutedChanged);
|
Audio.mutedDesktopChanged.disconnect(onDesktopInputDeviceMutedChanged);
|
||||||
Audio.mutedHMDChanged.disconnect(onHMDInputDeviceMutedChanged);
|
Audio.mutedHMDChanged.disconnect(onHMDInputDeviceMutedChanged);
|
||||||
Window.geometryChanged.disconnect(onGeometryChanged);
|
Window.geometryChanged.disconnect(onGeometryChanged);
|
||||||
|
|
Loading…
Reference in a new issue