mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 15:47:02 +02:00
merge with master
This commit is contained in:
commit
0d1e4bed66
198 changed files with 8878 additions and 4566 deletions
.gitignoreCMakeLists.txtINSTALL.md
android
assignment-client/src/audio
cmake
domain-server/src
interface
resources/qml
LoginDialog.qml
LoginDialog
CompleteProfileBody.qmlLinkAccountBody.qmlLoggingInBody.qmlSignUpBody.qmlUsernameCollisionBody.qml
OverlayLoginDialog.qmlimages
androidAppForce
controlsUit
dialogs
hifi
src
libraries
animation/src
avatars-renderer/src/avatars-renderer
avatars/src
controllers/src/controllers
display-plugins/src/display-plugins
Basic2DWindowOpenGLDisplayPlugin.hNullDisplayPlugin.hOpenGLDisplayPlugin.cppOpenGLDisplayPlugin.h
hmd
stereo
entities-renderer/src
RenderableEntityItem.cppRenderableGizmoEntityItem.cppRenderableShapeEntityItem.cppRenderableShapeEntityItem.h
entities/src
fbx/src
gl/src/gl
gpu-gl-common/src/gpu/gl
gpu
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -104,4 +104,6 @@ tools/unity-avatar-exporter/Logs
|
|||
tools/unity-avatar-exporter/Packages
|
||||
tools/unity-avatar-exporter/ProjectSettings
|
||||
tools/unity-avatar-exporter/Temp
|
||||
|
||||
server-console/package-lock.json
|
||||
vcpkg/
|
||||
/tools/nitpick/compiledResources
|
||||
|
|
|
@ -108,8 +108,10 @@ set(PLATFORM_QT_GL OpenGL)
|
|||
|
||||
if (USE_GLES)
|
||||
add_definitions(-DUSE_GLES)
|
||||
add_definitions(-DGPU_POINTER_STORAGE_SHARED)
|
||||
set(PLATFORM_GL_BACKEND gpu-gl-common gpu-gles)
|
||||
else()
|
||||
add_definitions(-DGPU_POINTER_STORAGE_RAW)
|
||||
set(PLATFORM_GL_BACKEND gpu-gl-common gpu-gl)
|
||||
endif()
|
||||
|
||||
|
|
75
INSTALL.md
75
INSTALL.md
|
@ -4,7 +4,8 @@ During generation, CMake should produce an `install` target and a `package` targ
|
|||
|
||||
### Install
|
||||
|
||||
The `install` target will copy the High Fidelity targets and their dependencies to your `CMAKE_INSTALL_PREFIX`.
|
||||
The `install` target will copy the High Fidelity targets and their dependencies to your `CMAKE_INSTALL_PREFIX`.
|
||||
This variable is set by the `project(hifi)` command in `CMakeLists.txt` to `C:/Program Files/hifi` and stored in `build/CMakeCache.txt`
|
||||
|
||||
### Packaging
|
||||
|
||||
|
@ -14,17 +15,67 @@ To produce an installer, run the `package` target.
|
|||
|
||||
To produce an executable installer on Windows, the following are required:
|
||||
|
||||
- [Nullsoft Scriptable Install System](http://nsis.sourceforge.net/Download) - 3.0b3
|
||||
- [UAC Plug-in for Nullsoft](http://nsis.sourceforge.net/UAC_plug-in) - 0.2.4c
|
||||
- [nsProcess Plug-in for Nullsoft](http://nsis.sourceforge.net/NsProcess_plugin) - 1.6
|
||||
- [Inetc Plug-in for Nullsoft](http://nsis.sourceforge.net/Inetc_plug-in) - 1.0
|
||||
- [NSISpcre Plug-in for Nullsoft](http://nsis.sourceforge.net/NSISpcre_plug-in) - 1.0
|
||||
- [nsisSlideshow Plug-in for Nullsoft](http://nsis.sourceforge.net/NsisSlideshow_plug-in) - 1.7
|
||||
- [Nsisunz plug-in for Nullsoft](http://nsis.sourceforge.net/Nsisunz_plug-in)
|
||||
- [ApplicationID plug-in for Nullsoft](http://nsis.sourceforge.net/ApplicationID_plug-in) - 1.0
|
||||
1. [7-zip](<https://www.7-zip.org/download.html>)
|
||||
|
||||
Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System.
|
||||
1. [Nullsoft Scriptable Install System](http://nsis.sourceforge.net/Download) - 3.04
|
||||
Install using defaults (will install to `C:\Program Files (x86)\NSIS`)
|
||||
1. [UAC Plug-in for Nullsoft](http://nsis.sourceforge.net/UAC_plug-in) - 0.2.4c
|
||||
1. Extract Zip
|
||||
1. Copy `UAC.nsh` to `C:\Program Files (x86)\NSIS\Include\`
|
||||
1. Copy `Plugins\x86-ansi\UAC.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-ansi\`
|
||||
1. Copy `Plugins\x86-unicode\UAC.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-unicode\`
|
||||
1. [nsProcess Plug-in for Nullsoft](http://nsis.sourceforge.net/NsProcess_plugin) - 1.6 (use the link marked **nsProcess_1_6.7z**)
|
||||
1. Extract Zip
|
||||
1. Copy `Include\nsProcess.nsh` to `C:\Program Files (x86)\NSIS\Include\`
|
||||
1. Copy `Plugins\nsProcess.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-ansi\`
|
||||
1. Copy `Plugins\nsProcessW.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-unicode\`
|
||||
|
||||
1. [InetC Plug-in for Nullsoft](http://nsis.sourceforge.net/Inetc_plug-in) - 1.0
|
||||
1. Extract Zip
|
||||
1. Copy `Plugin\x86-ansi\InetC.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-ansi\`
|
||||
1. Copy `Plugin\x86-unicode\InetC.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-unicode\`
|
||||
|
||||
1. [NSISpcre Plug-in for Nullsoft](http://nsis.sourceforge.net/NSISpcre_plug-in) - 1.0
|
||||
1. Extract Zip
|
||||
1. Copy `NSISpre.nsh` to `C:\Program Files (x86)\NSIS\Include\`
|
||||
1. Copy `NSISpre.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-ansi\`
|
||||
|
||||
1. [nsisSlideshow Plug-in for Nullsoft](<http://wiz0u.free.fr/prog/nsisSlideshow/>) - 1.7
|
||||
1. Extract Zip
|
||||
1. Copy `bin\nsisSlideshow.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-ansi\`
|
||||
1. Copy `bin\nsisSlideshowW.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-unicode\`
|
||||
|
||||
1. [Nsisunz plug-in for Nullsoft](http://nsis.sourceforge.net/Nsisunz_plug-in)
|
||||
1. Download both Zips and unzip
|
||||
1. Copy `nsisunz\Release\nsisunz.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-ansi\`
|
||||
1. Copy `NSISunzU\Plugin unicode\nsisunz.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-unicode\`
|
||||
|
||||
1. [ApplicationID plug-in for Nullsoft]() - 1.0
|
||||
1. Download [`Pre-built DLLs`](<https://github.com/connectiblutz/NSIS-ApplicationID/releases/download/1.1/NSIS-ApplicationID.zip>)
|
||||
1. Extract Zip
|
||||
1. Copy `Release\ApplicationID.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-ansi\`
|
||||
1. Copy `ReleaseUnicode\ApplicationID.dll` to `C:\Program Files (x86)\NSIS\Plugins\x86-unicode\`
|
||||
|
||||
1. [npm](<https://www.npmjs.com/get-npm>)
|
||||
1. Install version 10.15.0 LTS
|
||||
|
||||
1. Perform a clean cmake from a new terminal.
|
||||
1. Open the `hifi.sln` Solution and select the Release configuration.
|
||||
1. Build the Solution.
|
||||
1. Build `packaged-server-console` (found under **Server Console**)
|
||||
This will add 2 folders to `build\server-console\` -
|
||||
`server-console-win32-x64` and `x64`
|
||||
1. Build CMakeTargets->PACKAGE
|
||||
Installer is now available in `build\_CPack_Packages\win64\NSIS`
|
||||
|
||||
#### OS X
|
||||
|
||||
Run the `package` target to create an Apple Disk Image (.dmg).
|
||||
1. [npm](<https://www.npmjs.com/get-npm>)
|
||||
Install version 10.15.0 LTS
|
||||
|
||||
1. Perform a clean cmake.
|
||||
1. Perform a Release build of ALL_BUILD
|
||||
1. Perform a Release build of `packaged-server-console`
|
||||
This will add a folder to `build\server-console\` -
|
||||
Sandbox-darwin-x64
|
||||
1. Perform a Release build of `package`
|
||||
Installer is now available in `build/_CPack_Packages/Darwin/DragNDrop
|
||||
|
|
5
android/apps/framePlayer/CMakeLists.txt
Normal file
5
android/apps/framePlayer/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
set(TARGET_NAME framePlayer)
|
||||
setup_hifi_library(AndroidExtras)
|
||||
link_hifi_libraries(shared ktx shaders qml gpu gl ${PLATFORM_GL_BACKEND})
|
||||
target_link_libraries(${TARGET_NAME} android log m)
|
||||
target_opengl()
|
50
android/apps/framePlayer/build.gradle
Normal file
50
android/apps/framePlayer/build.gradle
Normal file
|
@ -0,0 +1,50 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias 'key0'
|
||||
keyPassword 'password'
|
||||
storeFile file('C:/android/keystore.jks')
|
||||
storePassword 'password'
|
||||
}
|
||||
}
|
||||
|
||||
compileSdkVersion 28
|
||||
defaultConfig {
|
||||
applicationId "io.highfidelity.frameplayer"
|
||||
minSdkVersion 25
|
||||
targetSdkVersion 28
|
||||
ndk { abiFilters 'arm64-v8a' }
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments '-DHIFI_ANDROID=1',
|
||||
'-DHIFI_ANDROID_APP=framePlayer',
|
||||
'-DANDROID_TOOLCHAIN=clang',
|
||||
'-DANDROID_STL=c++_shared',
|
||||
'-DCMAKE_VERBOSE_MAKEFILE=ON'
|
||||
targets = ['framePlayer']
|
||||
}
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild.cmake.path '../../../CMakeLists.txt'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: '../../libraries/qt/libs')
|
||||
//implementation project(':oculus')
|
||||
implementation project(':qt')
|
||||
}
|
25
android/apps/framePlayer/proguard-rules.pro
vendored
Normal file
25
android/apps/framePlayer/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:\Android\SDK/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
38
android/apps/framePlayer/src/main/AndroidManifest.xml
Normal file
38
android/apps/framePlayer/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.highfidelity.frameplayer"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0"
|
||||
android:installLocation="auto">
|
||||
<uses-feature android:glEsVersion="0x00030002" android:required="true" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<application android:label="Frame Viewer"
|
||||
android:allowBackup="false"
|
||||
android:name="org.qtproject.qt5.android.bindings.QtApplication"
|
||||
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon">
|
||||
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
|
||||
<activity
|
||||
android:name="org.qtproject.qt5.android.bindings.QtActivity"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="landscape"
|
||||
android:excludeFromRecents="false"
|
||||
android:configChanges="screenSize|screenLayout|orientation|keyboardHidden|keyboard|navigation|uiMode">
|
||||
<!-- JNI nonsense -->
|
||||
<meta-data android:name="android.app.lib_name" android:value="framePlayer"/>
|
||||
<!-- Qt nonsense -->
|
||||
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
|
||||
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
|
||||
<meta-data android:name="android.app.load_local_libs" android:value="plugins/platforms/android/libqtforandroid.so:plugins/bearer/libqandroidbearer.so"/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
6
android/apps/framePlayer/src/main/cpp/FramePlayer.qrc
Normal file
6
android/apps/framePlayer/src/main/cpp/FramePlayer.qrc
Normal file
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE RCC>
|
||||
<RCC version="1.0">
|
||||
<qresource prefix="/">
|
||||
<file>qml/main.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
91
android/apps/framePlayer/src/main/cpp/PlayerWindow.cpp
Normal file
91
android/apps/framePlayer/src/main/cpp/PlayerWindow.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2018/10/21
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "PlayerWindow.h"
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtGui/QImageReader>
|
||||
#include <QtQml/QQmlContext>
|
||||
#include <QtQuick/QQuickItem>
|
||||
|
||||
#include <gpu/Frame.h>
|
||||
#include <gpu/FrameIO.h>
|
||||
|
||||
PlayerWindow::PlayerWindow() {
|
||||
setFlags(Qt::MSWindowsOwnDC | Qt::Window | Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint);
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
create();
|
||||
showFullScreen();
|
||||
|
||||
// Make sure the window has been created by processing events
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
// Start the rendering thread
|
||||
_renderThread.initialize(this, &_surface);
|
||||
|
||||
// Start the UI
|
||||
_surface.resize(size());
|
||||
connect(&_surface, &hifi::qml::OffscreenSurface::rootContextCreated, this, [](QQmlContext* context){
|
||||
context->setContextProperty("FRAMES_FOLDER", "file:assets:/frames");
|
||||
});
|
||||
_surface.load("qrc:///qml/main.qml");
|
||||
|
||||
// Connect the UI handler
|
||||
QObject::connect(_surface.getRootItem(), SIGNAL(loadFile(QString)),
|
||||
this, SLOT(loadFile(QString))
|
||||
);
|
||||
|
||||
// Turn on UI input events
|
||||
installEventFilter(&_surface);
|
||||
}
|
||||
|
||||
PlayerWindow::~PlayerWindow() {
|
||||
}
|
||||
|
||||
// static const char* FRAME_FILE = "assets:/frames/20190110_1635.json";
|
||||
|
||||
static void textureLoader(const std::string& filename, const gpu::TexturePointer& texture, uint16_t layer) {
|
||||
QImage image;
|
||||
QImageReader(filename.c_str()).read(&image);
|
||||
if (layer > 0) {
|
||||
return;
|
||||
}
|
||||
texture->assignStoredMip(0, image.byteCount(), image.constBits());
|
||||
}
|
||||
|
||||
void PlayerWindow::loadFile(QString filename) {
|
||||
QString realFilename = QUrl(filename).toLocalFile();
|
||||
if (QFileInfo(realFilename).exists()) {
|
||||
auto frame = gpu::readFrame(realFilename.toStdString(), _renderThread._externalTexture, &textureLoader);
|
||||
_surface.pause();
|
||||
_renderThread.submitFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWindow::touchEvent(QTouchEvent* event) {
|
||||
// Super basic input handling when the 3D scene is active.... tap with two finders to return to the
|
||||
// QML UI
|
||||
static size_t touches = 0;
|
||||
switch (event->type()) {
|
||||
case QEvent::TouchBegin:
|
||||
case QEvent::TouchUpdate:
|
||||
touches = std::max<size_t>(touches, event->touchPoints().size());
|
||||
break;
|
||||
|
||||
case QEvent::TouchEnd:
|
||||
if (touches >= 2) {
|
||||
_renderThread.submitFrame(nullptr);
|
||||
_surface.resume();
|
||||
}
|
||||
touches = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
35
android/apps/framePlayer/src/main/cpp/PlayerWindow.h
Normal file
35
android/apps/framePlayer/src/main/cpp/PlayerWindow.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2018/10/21
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include <qml/OffscreenSurface.h>
|
||||
#include <gpu/Forward.h>
|
||||
#include "RenderThread.h"
|
||||
|
||||
// Create a simple OpenGL window that renders text in various ways
|
||||
class PlayerWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PlayerWindow();
|
||||
virtual ~PlayerWindow();
|
||||
|
||||
protected:
|
||||
void touchEvent(QTouchEvent *ev) override;
|
||||
|
||||
public slots:
|
||||
void loadFile(QString filename);
|
||||
|
||||
private:
|
||||
hifi::qml::OffscreenSurface _surface;
|
||||
QSettings _settings;
|
||||
RenderThread _renderThread;
|
||||
};
|
162
android/apps/framePlayer/src/main/cpp/RenderThread.cpp
Normal file
162
android/apps/framePlayer/src/main/cpp/RenderThread.cpp
Normal file
|
@ -0,0 +1,162 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2018/10/21
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "RenderThread.h"
|
||||
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
void RenderThread::submitFrame(const gpu::FramePointer& frame) {
|
||||
std::unique_lock<std::mutex> lock(_frameLock);
|
||||
_pendingFrames.push(frame);
|
||||
}
|
||||
|
||||
void RenderThread::move(const glm::vec3& v) {
|
||||
std::unique_lock<std::mutex> lock(_frameLock);
|
||||
_correction = glm::inverse(glm::translate(mat4(), v)) * _correction;
|
||||
}
|
||||
|
||||
void RenderThread::setup() {
|
||||
// Wait until the context has been moved to this thread
|
||||
{ std::unique_lock<std::mutex> lock(_frameLock); }
|
||||
|
||||
makeCurrent();
|
||||
// Disable vsync for profiling
|
||||
::gl::setSwapInterval(0);
|
||||
|
||||
glClearColor(1, 1, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
_glContext.swapBuffers();
|
||||
|
||||
// GPU library init
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
_backend = _gpuContext->getBackend();
|
||||
_gpuContext->beginFrame();
|
||||
_gpuContext->endFrame();
|
||||
makeCurrent();
|
||||
|
||||
|
||||
glGenFramebuffers(1, &_uiFbo);
|
||||
glGenTextures(1, &_externalTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, _externalTexture);
|
||||
static const glm::u8vec4 color{ 0 };
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &color);
|
||||
|
||||
glClearColor(0, 1, 1, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
_glContext.swapBuffers();
|
||||
}
|
||||
|
||||
void RenderThread::initialize(QWindow* window, hifi::qml::OffscreenSurface* offscreen) {
|
||||
std::unique_lock<std::mutex> lock(_frameLock);
|
||||
setObjectName("RenderThread");
|
||||
Parent::initialize();
|
||||
|
||||
_offscreen = offscreen;
|
||||
_window = window;
|
||||
_glContext.setWindow(_window);
|
||||
_glContext.create();
|
||||
_glContext.makeCurrent();
|
||||
|
||||
hifi::qml::OffscreenSurface::setSharedContext(_glContext.qglContext());
|
||||
glClearColor(1, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
_glContext.swapBuffers();
|
||||
_glContext.doneCurrent();
|
||||
_glContext.moveToThread(_thread);
|
||||
_thread->setObjectName("RenderThread");
|
||||
}
|
||||
|
||||
void RenderThread::shutdown() {
|
||||
_activeFrame.reset();
|
||||
while (!_pendingFrames.empty()) {
|
||||
_gpuContext->consumeFrameUpdates(_pendingFrames.front());
|
||||
_pendingFrames.pop();
|
||||
}
|
||||
_gpuContext->shutdown();
|
||||
_gpuContext.reset();
|
||||
}
|
||||
|
||||
void RenderThread::renderFrame() {
|
||||
auto windowSize = _window->geometry().size();
|
||||
uvec2 readFboSize;
|
||||
uint32_t readFbo{ 0 };
|
||||
|
||||
if (_activeFrame) {
|
||||
const auto &frame = _activeFrame;
|
||||
_backend->recycle();
|
||||
_backend->syncCache();
|
||||
_gpuContext->enableStereo(frame->stereoState._enable);
|
||||
if (frame && !frame->batches.empty()) {
|
||||
_gpuContext->executeFrame(frame);
|
||||
}
|
||||
auto &glBackend = static_cast<gpu::gl::GLBackend&>(*_backend);
|
||||
readFbo = glBackend.getFramebufferID(frame->framebuffer);
|
||||
readFboSize = frame->framebuffer->getSize();
|
||||
CHECK_GL_ERROR();
|
||||
} else {
|
||||
hifi::qml::OffscreenSurface::TextureAndFence newTextureAndFence;
|
||||
if (_offscreen->fetchTexture(newTextureAndFence)) {
|
||||
if (_uiTexture != 0) {
|
||||
auto readFence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
glFlush();
|
||||
_offscreen->getDiscardLambda()(_uiTexture, readFence);
|
||||
_uiTexture = 0;
|
||||
}
|
||||
|
||||
glWaitSync((GLsync)newTextureAndFence.second, 0, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync((GLsync)newTextureAndFence.second);
|
||||
_uiTexture = newTextureAndFence.first;
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, _uiFbo);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _uiTexture, 0);
|
||||
}
|
||||
|
||||
if (_uiTexture != 0) {
|
||||
readFbo = _uiFbo;
|
||||
readFboSize = { windowSize.width(), windowSize.height() };
|
||||
}
|
||||
}
|
||||
|
||||
if (readFbo) {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo);
|
||||
glBlitFramebuffer(
|
||||
0, 0, readFboSize.x, readFboSize.y,
|
||||
0, 0, windowSize.width(), windowSize.height(),
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
} else {
|
||||
glClearColor(1, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
_glContext.swapBuffers();
|
||||
}
|
||||
|
||||
void RenderThread::updateFrame() {
|
||||
std::queue<gpu::FramePointer> pendingFrames;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_frameLock);
|
||||
pendingFrames.swap(_pendingFrames);
|
||||
}
|
||||
|
||||
while (!pendingFrames.empty()) {
|
||||
_activeFrame = pendingFrames.front();
|
||||
pendingFrames.pop();
|
||||
if (_activeFrame) {
|
||||
_gpuContext->consumeFrameUpdates(_activeFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderThread::process() {
|
||||
updateFrame();
|
||||
makeCurrent();
|
||||
renderFrame();
|
||||
return true;
|
||||
}
|
54
android/apps/framePlayer/src/main/cpp/RenderThread.h
Normal file
54
android/apps/framePlayer/src/main/cpp/RenderThread.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2018/10/21
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <GenericThread.h>
|
||||
|
||||
#include <gl/Context.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <qml/OffscreenSurface.h>
|
||||
|
||||
class RenderThread : public GenericThread {
|
||||
using Parent = GenericThread;
|
||||
public:
|
||||
QWindow* _window{ nullptr };
|
||||
std::mutex _mutex;
|
||||
gpu::ContextPointer _gpuContext; // initialized during window creation
|
||||
std::shared_ptr<gpu::Backend> _backend;
|
||||
std::atomic<size_t> _presentCount{ 0 };
|
||||
std::mutex _frameLock;
|
||||
std::queue<gpu::FramePointer> _pendingFrames;
|
||||
gpu::FramePointer _activeFrame;
|
||||
uint32_t _externalTexture{ 0 };
|
||||
glm::mat4 _correction;
|
||||
hifi::qml::OffscreenSurface* _offscreen{ nullptr };
|
||||
|
||||
gl::Context _glContext;
|
||||
uint32_t _uiTexture{ 0 };
|
||||
uint32_t _uiFbo{ 0 };
|
||||
|
||||
void move(const glm::vec3& v);
|
||||
void setup() override;
|
||||
bool process() override;
|
||||
void shutdown() override;
|
||||
|
||||
void initialize(QWindow* window, hifi::qml::OffscreenSurface* offscreen);
|
||||
|
||||
void submitFrame(const gpu::FramePointer& frame);
|
||||
void updateFrame();
|
||||
void renderFrame();
|
||||
|
||||
bool makeCurrent() {
|
||||
return _glContext.makeCurrent();
|
||||
}
|
||||
|
||||
void doneCurrent() {
|
||||
_glContext.doneCurrent();
|
||||
}
|
||||
};
|
54
android/apps/framePlayer/src/main/cpp/main.cpp
Normal file
54
android/apps/framePlayer/src/main/cpp/main.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2018/11/22
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
#include <Trace.h>
|
||||
|
||||
#include "PlayerWindow.h"
|
||||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
if (!message.isEmpty()) {
|
||||
const char * local=message.toStdString().c_str();
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"Interface",local);
|
||||
break;
|
||||
case QtInfoMsg:
|
||||
__android_log_write(ANDROID_LOG_INFO,"Interface",local);
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
__android_log_write(ANDROID_LOG_WARN,"Interface",local);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
__android_log_write(ANDROID_LOG_ERROR,"Interface",local);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
default:
|
||||
__android_log_write(ANDROID_LOG_FATAL,"Interface",local);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
setupHifiApplication("gpuFramePlayer");
|
||||
QGuiApplication app(argc, argv);
|
||||
auto oldMessageHandler = qInstallMessageHandler(messageHandler);
|
||||
DependencyManager::set<tracing::Tracer>();
|
||||
PlayerWindow window;
|
||||
app.exec();
|
||||
qInstallMessageHandler(oldMessageHandler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
36
android/apps/framePlayer/src/main/cpp/qml/main.qml
Normal file
36
android/apps/framePlayer/src/main/cpp/qml/main.qml
Normal file
|
@ -0,0 +1,36 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Dialogs 1.1
|
||||
import Qt.labs.folderlistmodel 2.11
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 640
|
||||
height: 480
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
|
||||
FolderListModel {
|
||||
id: folderModel
|
||||
folder: FRAMES_FOLDER
|
||||
nameFilters: ["*.json"]
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fileDelegate
|
||||
Text {
|
||||
text: fileName
|
||||
font.pointSize: 36
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.loadFile(folderModel.folder + "/" + fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model: folderModel
|
||||
delegate: fileDelegate
|
||||
}
|
||||
|
||||
signal loadFile(string filename);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--suppress AndroidUnknownAttribute -->
|
||||
<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="192"
|
||||
android:viewportHeight="192"
|
||||
android:width="192dp"
|
||||
android:height="192dp">
|
||||
<path
|
||||
android:pathData="M189.5 96.5A93.5 93.5 0 0 1 96 190 93.5 93.5 0 0 1 2.5 96.5 93.5 93.5 0 0 1 96 3 93.5 93.5 0 0 1 189.5 96.5Z"
|
||||
android:fillColor="#333333" />
|
||||
<path
|
||||
android:pathData="M96.2 173.1c-10.3 0 -20.4 -2.1 -29.8 -6 -9.2 -3.8 -17.3 -9.4 -24.3 -16.4 -7 -7 -12.6 -15.2 -16.4 -24.3 -4.1 -9.6 -6.2 -19.6 -6.2 -30 0 -10.3 2.1 -20.4 6 -29.8 3.8 -9.2 9.4 -17.3 16.4 -24.3 7 -7 15.2 -12.6 24.3 -16.4 9.5 -4 19.5 -6 29.8 -6 10.3 0 20.4 2.1 29.8 6 9.2 3.8 17.3 9.4 24.3 16.4 7 7 12.6 15.2 16.4 24.3 4 9.5 6 19.5 6 29.8 0 10.3 -2.1 20.4 -6 29.8 -3.8 9.2 -9.4 17.3 -16.4 24.3 -7 7 -15.2 12.6 -24.3 16.4 -9.2 4.1 -19.3 6.2 -29.6 6.2zm0 -145.3c-37.8 0 -68.6 30.8 -68.6 68.6 0 37.8 30.8 68.6 68.6 68.6 37.8 0 68.6 -30.8 68.6 -68.6 0 -37.8 -30.8 -68.6 -68.6 -68.6z"
|
||||
android:fillColor="#00b4f0" />
|
||||
<path
|
||||
android:pathData="M119.6 129l0 -53.8c3.4 -1.1 5.8 -4.3 5.8 -8 0 -4.6 -3.8 -8.4 -8.4 -8.4 -4.6 0 -8.4 3.8 -8.4 8.4 0 3.6 2.2 6.6 5.4 7.9l0 25L79 83.8 79 64c3.4 -1.1 5.8 -4.3 5.8 -8 0 -4.6 -3.8 -8.4 -8.4 -8.4 -4.6 0 -8.4 3.8 -8.4 8.4 0 3.6 2.2 6.6 5.4 7.9l0 54.1c-3.1 1.2 -5.4 4.3 -5.4 7.9 0 4.6 3.8 8.4 8.4 8.4 4.6 0 8.4 -3.8 8.4 -8.4 0 -3.7 -2.4 -6.9 -5.8 -8l0 -27.3 35 16.3 0 22.2c-3.1 1.2 -5.4 4.3 -5.4 7.9 0 4.6 3.8 8.4 8.4 8.4 4.6 0 8.4 -3.8 8.4 -8.4 0 -3.8 -2.4 -6.9 -5.8 -8z"
|
||||
android:fillColor="#00b4f0" />
|
||||
</vector>
|
3
android/apps/framePlayer/src/main/res/values/strings.xml
Normal file
3
android/apps/framePlayer/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name" translatable="false">GPU Frame Player</string>
|
||||
</resources>
|
|
@ -3,3 +3,6 @@ project(':qt').projectDir = new File(settingsDir, 'libraries/qt')
|
|||
|
||||
include ':interface'
|
||||
project(':interface').projectDir = new File(settingsDir, 'apps/interface')
|
||||
|
||||
//include ':framePlayer'
|
||||
//project(':framePlayer').projectDir = new File(settingsDir, 'apps/framePlayer')
|
||||
|
|
|
@ -68,6 +68,13 @@ AudioMixer::AudioMixer(ReceivedMessage& message) :
|
|||
// hash the available codecs (on the mixer)
|
||||
_availableCodecs.clear(); // Make sure struct is clean
|
||||
auto pluginManager = DependencyManager::set<PluginManager>();
|
||||
// Only load codec plugins; for now assume codec plugins have 'codec' in their name.
|
||||
auto codecPluginFilter = [](const QJsonObject& metaData) {
|
||||
QJsonValue nameValue = metaData["MetaData"]["name"];
|
||||
return nameValue.toString().contains("codec", Qt::CaseInsensitive);
|
||||
};
|
||||
pluginManager->setPluginFilter(codecPluginFilter);
|
||||
|
||||
auto codecPlugins = pluginManager->getCodecPlugins();
|
||||
for_each(codecPlugins.cbegin(), codecPlugins.cend(),
|
||||
[&](const CodecPluginPointer& codec) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#
|
||||
macro(TARGET_GLAD)
|
||||
if (ANDROID)
|
||||
include(SelectLibraryConfigurations)
|
||||
set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/glad)
|
||||
set(GLAD_INCLUDE_DIRS "${INSTALL_DIR}/include")
|
||||
set(GLAD_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libglad_d.a)
|
||||
|
@ -31,8 +32,8 @@ macro(TARGET_GLAD)
|
|||
set(GLAD_INCLUDE_DIRS ${${GLAD_UPPER}_INCLUDE_DIRS})
|
||||
set(GLAD_LIBRARY ${${GLAD_UPPER}_LIBRARY})
|
||||
endif()
|
||||
|
||||
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLAD_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${GLAD_LIBRARY})
|
||||
target_link_libraries(${TARGET_NAME} ${GLAD_EXTRA_LIBRARIES})
|
||||
target_link_libraries(${TARGET_NAME} ${GLAD_EXTRA_LIBRARIES})
|
||||
endmacro()
|
||||
|
|
|
@ -6,8 +6,13 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_ZLIB)
|
||||
# using VCPKG for zlib
|
||||
find_package(ZLIB REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${ZLIB_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
|
||||
if (ANDROID)
|
||||
# zlib is part of the NDK
|
||||
target_link_libraries(${TARGET_NAME} z)
|
||||
else()
|
||||
# using VCPKG for zlib
|
||||
find_package(ZLIB REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${ZLIB_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
endmacro()
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
Source: nvtt
|
||||
Version: 8c7e6b40ee5095f227b75880fabd89c99d6f34c0
|
||||
Version: 330c4d56274a0f602a5c70596e2eb670a4ed56c2
|
||||
Description: Texture processing tools with support for Direct3D 10 and 11 formats.
|
|
@ -10,8 +10,8 @@ include(vcpkg_common_functions)
|
|||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO highfidelity/nvidia-texture-tools
|
||||
REF 8c7e6b40ee5095f227b75880fabd89c99d6f34c0
|
||||
SHA512 f107d19dbbd6651ef2126b1422a5db8db291bf70311ac4fb1dbacb5ceaa8752fee38becbd32964f57596f0b84e1223bb2c3ff9d9c4fdc65c3e77a47836657cef
|
||||
REF 330c4d56274a0f602a5c70596e2eb670a4ed56c2
|
||||
SHA512 4c0bc2f369120d696cc27710b6d33086b27eef55f537ec66b9a5c8b1839bc2426c0413670b0f65be52c5d353468f0126dfe024be1f0690611d4d7e33ac530127
|
||||
HEAD_REF master
|
||||
)
|
||||
|
||||
|
|
|
@ -246,6 +246,7 @@ void AssetsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) {
|
|||
|
||||
if (_assetServerEnabled && _lastMappingsRefresh.time_since_epoch().count() == 0) {
|
||||
qCWarning(asset_backup) << "Current mappings not yet loaded.";
|
||||
_backups.emplace_back(backupName, AssetUtils::Mappings(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,8 @@ FocusScope {
|
|||
Image {
|
||||
z: -10
|
||||
id: loginDialogBackground
|
||||
source: "LoginDialog/images/background.jpg"
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: "LoginDialog/images/background.png"
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
|
@ -119,6 +120,6 @@ FocusScope {
|
|||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
|
||||
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false, "linkOculus": false });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,11 +22,16 @@ Item {
|
|||
width: root.width
|
||||
height: root.height
|
||||
readonly property string termsContainerText: qsTr("By creating this user profile, you agree to High Fidelity's Terms of Service")
|
||||
readonly property string termsContainerOculusText: qsTr("By signing up, you agree to High Fidelity's Terms of Service")
|
||||
readonly property int textFieldHeight: 31
|
||||
readonly property string fontFamily: "Raleway"
|
||||
readonly property int fontSize: 15
|
||||
readonly property bool fontBold: true
|
||||
readonly property int textFieldFontSize: 18
|
||||
readonly property var passwordImageRatio: 16 / 23
|
||||
|
||||
readonly property bool withSteam: withSteam
|
||||
property bool withOculus: withOculus
|
||||
property bool withSteam: withSteam
|
||||
property string errorString: errorString
|
||||
|
||||
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
|
||||
|
@ -61,15 +66,20 @@ Item {
|
|||
|
||||
Item {
|
||||
id: contentItem
|
||||
anchors.fill: parent
|
||||
width: parent.width
|
||||
height: errorContainer.height + fields.height + buttons.height + additionalTextContainer.height +
|
||||
termsContainer.height
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: root.bannerHeight + 0.25 * parent.height
|
||||
anchors.left: parent.left
|
||||
|
||||
Item {
|
||||
id: errorContainer
|
||||
width: parent.width
|
||||
width: root.bannerWidth
|
||||
height: loginErrorMessageTextMetrics.height
|
||||
anchors {
|
||||
bottom: buttons.top;
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y;
|
||||
bottom: completeProfileBody.withOculus ? fields.top : buttons.top;
|
||||
bottomMargin: 1.5 * hifi.dimensions.contentSpacing.y;
|
||||
left: buttons.left;
|
||||
}
|
||||
TextMetrics {
|
||||
|
@ -79,8 +89,8 @@ Item {
|
|||
}
|
||||
Text {
|
||||
id: loginErrorMessage;
|
||||
width: root.bannerWidth
|
||||
color: "red";
|
||||
width: root.bannerWidth;
|
||||
font.family: completeProfileBody.fontFamily
|
||||
font.pixelSize: 18
|
||||
font.bold: completeProfileBody.fontBold
|
||||
|
@ -88,13 +98,196 @@ Item {
|
|||
horizontalAlignment: Text.AlignHCenter
|
||||
text: completeProfileBody.errorString
|
||||
visible: true
|
||||
onTextChanged: {
|
||||
mainContainer.recalculateErrorMessage();
|
||||
}
|
||||
Component.onCompleted: {
|
||||
mainContainer.recalculateErrorMessage();
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
if (loginErrorMessageTextMetrics.width > root.bannerWidth && root.isTablet) {
|
||||
loginErrorMessage.wrapMode = Text.WordWrap;
|
||||
loginErrorMessage.verticalAlignment = Text.AlignLeft;
|
||||
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
|
||||
errorContainer.height = 3 * loginErrorMessageTextMetrics.height;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: fields
|
||||
width: root.bannerWidth
|
||||
height: 3 * completeProfileBody.textFieldHeight + 2 * hifi.dimensions.contentSpacing.y
|
||||
visible: completeProfileBody.withOculus
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: (parent.width - root.bannerWidth) / 2
|
||||
bottom: buttons.top
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
HifiControlsUit.TextField {
|
||||
id: usernameField
|
||||
width: root.bannerWidth
|
||||
height: completeProfileBody.textFieldHeight
|
||||
placeholderText: "Username"
|
||||
font.pixelSize: completeProfileBody.textFieldFontSize
|
||||
styleRenderType: Text.QtRendering
|
||||
anchors {
|
||||
top: parent.top
|
||||
}
|
||||
Keys.onPressed: {
|
||||
if (!usernameField.visible) {
|
||||
return;
|
||||
}
|
||||
switch (event.key) {
|
||||
case Qt.Key_Tab:
|
||||
event.accepted = true;
|
||||
if (event.modifiers === Qt.ShiftModifier) {
|
||||
passwordField.focus = true;
|
||||
} else {
|
||||
emailField.focus = true;
|
||||
}
|
||||
break;
|
||||
case Qt.Key_Backtab:
|
||||
event.accepted = true;
|
||||
passwordField.focus = true;
|
||||
break;
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true;
|
||||
loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
|
||||
"linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
|
||||
break;
|
||||
}
|
||||
}
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
if (focus) {
|
||||
root.isPassword = false;
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
var userID = "";
|
||||
if (completeProfileBody.withOculus) {
|
||||
userID = loginDialog.oculusUserID();
|
||||
}
|
||||
usernameField.text = userID;
|
||||
}
|
||||
}
|
||||
HifiControlsUit.TextField {
|
||||
id: emailField
|
||||
width: root.bannerWidth
|
||||
height: completeProfileBody.textFieldHeight
|
||||
anchors {
|
||||
top: usernameField.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
placeholderText: "Email"
|
||||
font.pixelSize: completeProfileBody.textFieldFontSize
|
||||
styleRenderType: Text.QtRendering
|
||||
activeFocusOnPress: true
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Tab:
|
||||
event.accepted = true;
|
||||
if (event.modifiers === Qt.ShiftModifier) {
|
||||
usernameField.focus = true;
|
||||
} else {
|
||||
passwordField.focus = true;
|
||||
}
|
||||
break;
|
||||
case Qt.Key_Backtab:
|
||||
event.accepted = true;
|
||||
usernameField.focus = true;
|
||||
break;
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true;
|
||||
loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
|
||||
"linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
|
||||
break;
|
||||
}
|
||||
}
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
if (focus) {
|
||||
root.isPassword = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
HifiControlsUit.TextField {
|
||||
id: passwordField
|
||||
width: root.bannerWidth
|
||||
height: completeProfileBody.textFieldHeight
|
||||
placeholderText: "Password (optional)"
|
||||
font.pixelSize: completeProfileBody.textFieldFontSize
|
||||
styleRenderType: Text.QtRendering
|
||||
activeFocusOnPress: true
|
||||
echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
|
||||
anchors {
|
||||
top: emailField.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
root.isPassword = focus;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: showPasswordContainer
|
||||
z: 10
|
||||
// width + image's rightMargin
|
||||
width: showPasswordImage.width + 8
|
||||
height: parent.height
|
||||
anchors {
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
Image {
|
||||
id: showPasswordImage
|
||||
width: passwordField.height * passwordImageRatio
|
||||
height: passwordField.height * passwordImageRatio
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: 8
|
||||
top: parent.top
|
||||
topMargin: passwordFieldMouseArea.showPassword ? 6 : 8
|
||||
bottom: parent.bottom
|
||||
bottomMargin: passwordFieldMouseArea.showPassword ? 5 : 8
|
||||
}
|
||||
source: passwordFieldMouseArea.showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg"
|
||||
MouseArea {
|
||||
id: passwordFieldMouseArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
property bool showPassword: false
|
||||
onClicked: {
|
||||
showPassword = !showPassword;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Tab:
|
||||
event.accepted = true;
|
||||
if (event.modifiers === Qt.ShiftModifier) {
|
||||
emailField.focus = true;
|
||||
} else if (usernameField.visible) {
|
||||
usernameField.focus = true;
|
||||
} else {
|
||||
emailField.focus = true;
|
||||
}
|
||||
break;
|
||||
case Qt.Key_Backtab:
|
||||
event.accepted = true;
|
||||
emailField.focus = true;
|
||||
break;
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true;
|
||||
loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
|
||||
"linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +298,7 @@ Item {
|
|||
height: d.minHeightButton
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: (parent.height - additionalTextContainer.height) / 2 - hifi.dimensions.contentSpacing.y
|
||||
topMargin: (parent.height - additionalTextContainer.height + fields.height) / 2 - hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
leftMargin: (parent.width - root.bannerWidth) / 2
|
||||
}
|
||||
|
@ -144,7 +337,7 @@ Item {
|
|||
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
|
||||
height: d.minHeightButton
|
||||
|
||||
text: qsTr("Create your profile")
|
||||
text: completeProfileBody.withOculus ? qsTr("Sign Up") : qsTr("Create your profile")
|
||||
color: hifi.buttons.blue
|
||||
|
||||
fontFamily: completeProfileBody.fontFamily
|
||||
|
@ -158,55 +351,12 @@ Item {
|
|||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
loginErrorMessage.visible = false;
|
||||
loginDialog.createAccountFromSteam();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: additionalTextContainer
|
||||
width: parent.width
|
||||
height: additionalTextMetrics.height
|
||||
anchors {
|
||||
top: buttons.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: additionalTextMetrics
|
||||
font: additionalText.font
|
||||
text: "Already have a High Fidelity profile? Link to an existing profile here."
|
||||
}
|
||||
|
||||
HifiStylesUit.ShortcutText {
|
||||
id: additionalText
|
||||
text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
|
||||
|
||||
font.family: completeProfileBody.fontFamily
|
||||
font.pixelSize: completeProfileBody.fontSize
|
||||
font.bold: completeProfileBody.fontBold
|
||||
wrapMode: Text.NoWrap
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
linkColor: hifi.colors.blueAccent
|
||||
|
||||
onLinkActivated: {
|
||||
loginDialog.isLogIn = true;
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "", "withSteam": true, "linkSteam": true });
|
||||
}
|
||||
Component.onCompleted: {
|
||||
if (additionalTextMetrics.width > root.bannerWidth && root.isTablet) {
|
||||
additionalText.width = root.bannerWidth;
|
||||
additionalText.wrapMode = Text.WordWrap;
|
||||
additionalText.verticalAlignment = Text.AlignLeft;
|
||||
additionalText.horizontalAlignment = Text.AlignLeft;
|
||||
additionalTextContainer.height = (additionalTextMetrics.width / root.bannerWidth) * additionalTextMetrics.height;
|
||||
additionalTextContainer.anchors.left = buttons.left;
|
||||
} else {
|
||||
additionalText.anchors.centerIn = additionalTextContainer;
|
||||
if (completeProfileBody.withOculus) {
|
||||
loginDialog.createAccountFromOculus(emailField.text, usernameField.text, passwordField.text);
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
|
||||
"linkSteam": false, "withOculus": completeProfileBody.withOculus, "linkOculus": false, "createOculus": true });
|
||||
} else if (completeProfileBody.withSteam) {
|
||||
loginDialog.createAccountFromSteam();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -217,29 +367,33 @@ Item {
|
|||
width: parent.width
|
||||
height: termsTextMetrics.height
|
||||
anchors {
|
||||
top: additionalTextContainer.bottom
|
||||
top: buttons.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
}
|
||||
TextMetrics {
|
||||
id: termsTextMetrics
|
||||
font: termsText.font
|
||||
text: completeProfileBody.termsContainerText
|
||||
text: completeProfileBody.withOculus ? completeProfileBody.termsContainerOculusText : completeProfileBody.termsContainerText
|
||||
Component.onCompleted: {
|
||||
// with the link.
|
||||
termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||
if (completeProfileBody.withOculus) {
|
||||
termsText.text = qsTr("By signing up, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||
} else {
|
||||
termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiStylesUit.InfoItem {
|
||||
id: termsText
|
||||
text: completeProfileBody.termsContainerText
|
||||
text: completeProfileBody.withOculus ? completeProfileBody.termsContainerOculusText : completeProfileBody.termsContainerText
|
||||
font.family: completeProfileBody.fontFamily
|
||||
font.pixelSize: completeProfileBody.fontSize
|
||||
font.bold: completeProfileBody.fontBold
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.lightGray
|
||||
color: hifi.colors.white
|
||||
linkColor: hifi.colors.blueAccent
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
|
@ -247,7 +401,7 @@ Item {
|
|||
onLinkActivated: loginDialog.openUrl(link);
|
||||
|
||||
Component.onCompleted: {
|
||||
if (termsTextMetrics.width > root.bannerWidth && root.isTablet) {
|
||||
if (termsTextMetrics.width > root.bannerWidth) {
|
||||
termsText.width = root.bannerWidth;
|
||||
termsText.wrapMode = Text.WordWrap;
|
||||
additionalText.verticalAlignment = Text.AlignLeft;
|
||||
|
@ -260,14 +414,86 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: additionalTextContainer
|
||||
width: parent.width
|
||||
height: additionalTextMetrics.height
|
||||
anchors {
|
||||
top: termsContainer.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: additionalTextMetrics
|
||||
font: additionalText.font
|
||||
text: "Already have a High Fidelity profile? Link to an existing profile here."
|
||||
}
|
||||
|
||||
HifiStylesUit.ShortcutText {
|
||||
id: additionalText
|
||||
text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
|
||||
width: root.bannerWidth;
|
||||
font.family: completeProfileBody.fontFamily
|
||||
font.pixelSize: completeProfileBody.fontSize
|
||||
font.bold: completeProfileBody.fontBold
|
||||
wrapMode: Text.NoWrap
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
linkColor: hifi.colors.blueAccent
|
||||
|
||||
onLinkActivated: {
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "",
|
||||
"withSteam": completeProfileBody.withSteam, "linkSteam": completeProfileBody.withSteam, "withOculus": completeProfileBody.withOculus,
|
||||
"linkOculus": completeProfileBody.withOculus });
|
||||
}
|
||||
Component.onCompleted: {
|
||||
if (additionalTextMetrics.width > root.bannerWidth) {
|
||||
additionalText.wrapMode = Text.WordWrap;
|
||||
additionalText.verticalAlignment = Text.AlignLeft;
|
||||
additionalText.horizontalAlignment = Text.AlignLeft;
|
||||
additionalTextContainer.height = (additionalTextMetrics.width / root.bannerWidth) * additionalTextMetrics.height;
|
||||
additionalTextContainer.anchors.left = buttons.left;
|
||||
} else {
|
||||
additionalText.anchors.centerIn = additionalTextContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function recalculateErrorMessage() {
|
||||
if (completeProfileBody.errorString !== "") {
|
||||
loginErrorMessage.visible = true;
|
||||
var errorLength = completeProfileBody.errorString.split(/\r\n|\r|\n/).length;
|
||||
var errorStringEdited = completeProfileBody.errorString.replace(/[\n\r]+/g, "\n");
|
||||
loginErrorMessage.text = errorStringEdited;
|
||||
if (errorLength > 1.0) {
|
||||
loginErrorMessage.wrapMode = Text.WordWrap;
|
||||
loginErrorMessage.verticalAlignment = Text.AlignLeft;
|
||||
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
|
||||
errorContainer.height = errorLength * loginErrorMessageTextMetrics.height;
|
||||
} else if (loginErrorMessageTextMetrics.width > root.bannerWidth) {
|
||||
loginErrorMessage.wrapMode = Text.WordWrap;
|
||||
loginErrorMessage.verticalAlignment = Text.AlignLeft;
|
||||
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
|
||||
errorContainer.height = (loginErrorMessageTextMetrics.width / root.bannerWidth) * loginErrorMessageTextMetrics.height;
|
||||
} else {
|
||||
loginErrorMessage.wrapMode = Text.NoWrap;
|
||||
loginErrorMessage.verticalAlignment = Text.AlignVCenter;
|
||||
loginErrorMessage.horizontalAlignment = Text.AlignHCenter;
|
||||
errorContainer.height = loginErrorMessageTextMetrics.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleCreateCompleted: {
|
||||
console.log("Create Succeeded")
|
||||
|
||||
console.log("Create Succeeded");
|
||||
if (completeProfileBody.withSteam) {
|
||||
if (completeProfileBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
|
@ -277,20 +503,24 @@ Item {
|
|||
}
|
||||
loginDialog.loginThroughSteam();
|
||||
}
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam, "linkSteam": false });
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam, "linkSteam": false,
|
||||
"withOculus": completeProfileBody.withOculus, "linkOculus": false });
|
||||
}
|
||||
onHandleCreateFailed: {
|
||||
console.log("Create Failed: " + error);
|
||||
if (completeProfileBody.withSteam) {
|
||||
if (completeProfileBody.withSteam || completeProfileBody.withOculus) {
|
||||
if (completeProfileBody.loginDialogPoppedUp) {
|
||||
action = completeProfileBody.withSteam ? "Steam" : "Oculus";
|
||||
var data = {
|
||||
"action": "user failed to create a profile with Steam from the complete profile screen"
|
||||
"action": "user failed to create a profile with " + action + " from the complete profile screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
}
|
||||
|
||||
bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam });
|
||||
if (!completeProfileBody.withOculus) {
|
||||
bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam,
|
||||
"withOculus": completeProfileBody.withOculus });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,5 +532,6 @@ Item {
|
|||
}
|
||||
d.resize();
|
||||
root.text = "";
|
||||
usernameField.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,9 +36,10 @@ Item {
|
|||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
property bool withSteam: false
|
||||
property bool withSteam: withSteam
|
||||
property bool linkSteam: linkSteam
|
||||
property bool withOculus: false
|
||||
property bool withOculus: withOculus
|
||||
property bool linkOculus: linkOculus
|
||||
property string errorString: errorString
|
||||
property bool lostFocus: false
|
||||
|
||||
|
@ -83,23 +84,24 @@ Item {
|
|||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam });
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam,
|
||||
"withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus });
|
||||
}
|
||||
|
||||
function init() {
|
||||
// going to/from sign in/up dialog.
|
||||
loginDialog.isLogIn = true;
|
||||
loginErrorMessage.text = linkAccountBody.errorString;
|
||||
loginErrorMessage.visible = (linkAccountBody.errorString !== "");
|
||||
loginButton.text = !linkAccountBody.linkSteam ? "Log In" : "Link Account";
|
||||
if (loginErrorMessageTextMetrics.width > emailField.width) {
|
||||
loginErrorMessage.wrapMode = Text.WordWrap;
|
||||
errorContainer.height = (loginErrorMessageTextMetrics.width / emailField.width) * loginErrorMessageTextMetrics.height;
|
||||
}
|
||||
loginButton.text = (!linkAccountBody.linkSteam && !linkAccountBody.linkOculus) ? "Log In" : "Link Account";
|
||||
loginButton.color = hifi.buttons.blue;
|
||||
emailField.placeholderText = "Username or Email";
|
||||
var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
|
||||
emailField.text = keepMeLoggedInCheckbox.checked ? savedUsername === "Unknown user" ? "" : savedUsername : "";
|
||||
if (linkAccountBody.linkSteam) {
|
||||
steamInfoText.anchors.top = passwordField.bottom;
|
||||
keepMeLoggedInCheckbox.anchors.top = steamInfoText.bottom;
|
||||
if (linkAccountBody.linkSteam || linkAccountBody.linkOculus) {
|
||||
loginButton.width = (passwordField.width - hifi.dimensions.contentSpacing.x) / 2;
|
||||
loginButton.anchors.right = emailField.right;
|
||||
} else {
|
||||
|
@ -125,7 +127,7 @@ Item {
|
|||
id: loginContainer
|
||||
width: emailField.width
|
||||
height: errorContainer.height + emailField.height + passwordField.height + 5.5 * hifi.dimensions.contentSpacing.y +
|
||||
keepMeLoggedInCheckbox.height + loginButton.height + cantAccessTextMetrics.height + continueButton.height + steamInfoTextMetrics.height
|
||||
keepMeLoggedInCheckbox.height + loginButton.height + cantAccessTextMetrics.height + continueButton.height
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: root.bannerHeight + 0.25 * parent.height
|
||||
|
@ -135,7 +137,7 @@ Item {
|
|||
|
||||
Item {
|
||||
id: errorContainer
|
||||
width: loginErrorMessageTextMetrics.width
|
||||
width: parent.width
|
||||
height: loginErrorMessageTextMetrics.height
|
||||
anchors {
|
||||
bottom: emailField.top;
|
||||
|
@ -304,7 +306,7 @@ Item {
|
|||
fontSize: linkAccountBody.fontSize
|
||||
fontBold: linkAccountBody.fontBold
|
||||
color: hifi.buttons.noneBorderlessWhite;
|
||||
visible: linkAccountBody.linkSteam
|
||||
visible: linkAccountBody.linkSteam || linkAccountBody.linkOculus
|
||||
anchors {
|
||||
top: keepMeLoggedInCheckbox.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
|
@ -315,10 +317,9 @@ Item {
|
|||
"action": "user clicked cancel at link account screen"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
loginDialog.dismissLoginDialog();
|
||||
}
|
||||
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "errorString": "" });
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam,
|
||||
"withOculus": linkAccountBody.withOculus, "errorString": "" });
|
||||
}
|
||||
}
|
||||
HifiControlsUit.Button {
|
||||
|
@ -337,33 +338,6 @@ Item {
|
|||
linkAccountBody.login();
|
||||
}
|
||||
}
|
||||
TextMetrics {
|
||||
id: steamInfoTextMetrics
|
||||
font: steamInfoText.font
|
||||
text: steamInfoText.text
|
||||
}
|
||||
Text {
|
||||
id: steamInfoText
|
||||
width: root.bannerWidth
|
||||
visible: linkAccountBody.linkSteam
|
||||
anchors {
|
||||
top: loginButton.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
left: emailField.left
|
||||
}
|
||||
|
||||
font.family: linkAccountBody.fontFamily
|
||||
font.pixelSize: linkAccountBody.textFieldFontSize
|
||||
color: "white"
|
||||
text: qsTr("Your Steam account information will not be exposed to others.");
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Component.onCompleted: {
|
||||
if (steamInfoTextMetrics.width > root.bannerWidth) {
|
||||
steamInfoText.wrapMode = Text.WordWrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
TextMetrics {
|
||||
id: cantAccessTextMetrics
|
||||
font: cantAccessText.font
|
||||
|
@ -372,7 +346,7 @@ Item {
|
|||
HifiStylesUit.ShortcutText {
|
||||
id: cantAccessText
|
||||
z: 10
|
||||
visible: !linkAccountBody.linkSteam
|
||||
visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus
|
||||
anchors {
|
||||
top: loginButton.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
|
@ -423,10 +397,10 @@ Item {
|
|||
buttonGlyphSize: 24
|
||||
buttonGlyphRightMargin: 10
|
||||
onClicked: {
|
||||
// if (loginDialog.isOculusStoreRunning()) {
|
||||
// linkAccountBody.withOculus = true;
|
||||
// loginDialog.loginThroughSteam();
|
||||
// } else
|
||||
if (loginDialog.isOculusRunning()) {
|
||||
linkAccountBody.withOculus = true;
|
||||
loginDialog.loginThroughOculus();
|
||||
} else
|
||||
if (loginDialog.isSteamRunning()) {
|
||||
linkAccountBody.withSteam = true;
|
||||
loginDialog.loginThroughSteam();
|
||||
|
@ -446,18 +420,17 @@ Item {
|
|||
}
|
||||
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
|
||||
"withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam });
|
||||
"withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus });
|
||||
}
|
||||
Component.onCompleted: {
|
||||
if (linkAccountBody.linkSteam) {
|
||||
if (linkAccountBody.linkSteam || linkAccountBody.linkOculus) {
|
||||
continueButton.visible = false;
|
||||
return;
|
||||
}
|
||||
// if (loginDialog.isOculusStoreRunning()) {
|
||||
// continueButton.text = qsTr("CONTINUE WITH OCULUS");
|
||||
// continueButton.buttonGlyph = hifi.glyphs.oculus;
|
||||
// } else
|
||||
if (loginDialog.isSteamRunning()) {
|
||||
if (loginDialog.isOculusRunning()) {
|
||||
continueButton.text = qsTr("CONTINUE WITH OCULUS");
|
||||
continueButton.buttonGlyph = hifi.glyphs.oculus;
|
||||
} else if (loginDialog.isSteamRunning()) {
|
||||
continueButton.text = qsTr("CONTINUE WITH STEAM");
|
||||
continueButton.buttonGlyph = hifi.glyphs.steamSquare;
|
||||
} else {
|
||||
|
@ -470,7 +443,7 @@ Item {
|
|||
id: signUpContainer
|
||||
width: loginContainer.width
|
||||
height: signUpTextMetrics.height
|
||||
visible: !linkAccountBody.linkSteam
|
||||
visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus
|
||||
anchors {
|
||||
left: loginContainer.left
|
||||
top: loginContainer.bottom
|
||||
|
@ -519,7 +492,7 @@ Item {
|
|||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("SignUpBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
|
||||
"errorString": "", "linkSteam": linkAccountBody.linkSteam });
|
||||
"errorString": "" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -543,7 +516,7 @@ Item {
|
|||
fontFamily: linkAccountBody.fontFamily
|
||||
fontSize: linkAccountBody.fontSize
|
||||
fontBold: linkAccountBody.fontBold
|
||||
visible: linkAccountBody.loginDialogPoppedUp && !linkAccountBody.linkSteam;
|
||||
visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam && !linkAccountBody.linkOculus;
|
||||
onClicked: {
|
||||
if (linkAccountBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
|
|
|
@ -29,6 +29,8 @@ Item {
|
|||
property bool withSteam: withSteam
|
||||
property bool withOculus: withOculus
|
||||
property bool linkSteam: linkSteam
|
||||
property bool linkOculus: linkOculus
|
||||
property bool createOculus: createOculus
|
||||
|
||||
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
|
||||
|
||||
|
@ -75,15 +77,25 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: oculusSuccessTimer
|
||||
interval: 500;
|
||||
running: false;
|
||||
repeat: false;
|
||||
onTriggered: {
|
||||
loginDialog.loginThroughOculus();
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
// For the process of logging in.
|
||||
loggingInText.wrapMode = Text.NoWrap;
|
||||
|
||||
if (loggingInBody.linkSteam) {
|
||||
if (loggingInBody.createOculus) {
|
||||
loggingInGlyph.text = hifi.glyphs.oculus;
|
||||
loggingInGlyph.visible = true;
|
||||
loggingInText.text = "Linking to Steam";
|
||||
loggingInText.text = "Creating account with Oculus";
|
||||
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
|
||||
loginDialog.linkSteam();
|
||||
} else if (loggingInBody.withSteam) {
|
||||
loggingInGlyph.visible = true;
|
||||
loggingInText.text = "Logging in to Steam";
|
||||
|
@ -100,12 +112,18 @@ Item {
|
|||
loggingInSpinner.visible = true;
|
||||
}
|
||||
function loadingSuccess() {
|
||||
loggingInSpinner.visible = false;
|
||||
if (loggingInBody.linkSteam) {
|
||||
loggingInText.text = "Linking to Steam";
|
||||
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
|
||||
loginDialog.linkSteam();
|
||||
return;
|
||||
} else if (loggingInBody.linkOculus) {
|
||||
loggingInText.text = "Linking to Oculus";
|
||||
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
|
||||
loginDialog.linkOculus();
|
||||
return;
|
||||
}
|
||||
loggingInSpinner.visible = false;
|
||||
if (loggingInBody.withSteam) {
|
||||
// reset the flag.
|
||||
loggingInGlyph.visible = false;
|
||||
|
@ -246,6 +264,26 @@ Item {
|
|||
verticalAlignment: Text.AlignVCenter;
|
||||
visible: false;
|
||||
}
|
||||
HifiControlsUit.Button {
|
||||
id: okButton;
|
||||
width: d.minWidthButton
|
||||
height: d.minHeightButton
|
||||
text: qsTr("OK")
|
||||
color: hifi.buttons.white
|
||||
anchors {
|
||||
top: loggedInGlyph.bottom
|
||||
topMargin: 3 * hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
leftMargin: (parent.width - width) / 2;
|
||||
}
|
||||
onClicked: {
|
||||
root.tryDestroy();
|
||||
if (loginDialog.getLoginDialogPoppedUp()) {
|
||||
loginDialog.dismissLoginDialog();
|
||||
}
|
||||
}
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,6 +295,34 @@ Item {
|
|||
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleCreateCompleted: {
|
||||
console.log("Create Succeeded")
|
||||
if (loggingInBody.withOculus) {
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user created Oculus account successfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
loggingInBody.createOculus = false;
|
||||
loggingInText.text = "Account created!";
|
||||
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
|
||||
oculusSuccessTimer.start();
|
||||
}
|
||||
}
|
||||
onHandleCreateFailed: {
|
||||
console.log("Create Failed: " + error);
|
||||
if (loggingInBody.withOculus) {
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user created Oculus account unsuccessfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
|
||||
"withOculus": loggingInBody.withOculus, "errorString": error });
|
||||
}
|
||||
}
|
||||
onHandleLinkCompleted: {
|
||||
console.log("Link Succeeded");
|
||||
if (loggingInBody.linkSteam) {
|
||||
|
@ -267,21 +333,40 @@ Item {
|
|||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
loggingInBody.loadingSuccess();
|
||||
} else if (loggingInBody.linkOculus) {
|
||||
loggingInBody.linkOculus = false;
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user linked Oculus with their hifi account credentials successfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
}
|
||||
loggingInBody.loadingSuccess();
|
||||
}
|
||||
onHandleLinkFailed: {
|
||||
console.log("Link Failed: " + error);
|
||||
if (loggingInBody.linkSteam) {
|
||||
loggingInSpinner.visible = false;
|
||||
if (loggingInBody.linkOculus) {
|
||||
loggingInText.text = "Oculus failed to link";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user linked Oculus unsuccessfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
okButton.visible = true;
|
||||
} else if (loggingInBody.linkSteam){
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user linked Steam unsuccessfully"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
} else {
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": loggingInBody.linkSteam,
|
||||
"linkOculus": loggingInBody.linkOculus, "errorString": error });
|
||||
}
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": true, "errorString": error });
|
||||
}
|
||||
|
||||
onHandleLoginCompleted: {
|
||||
|
@ -292,8 +377,19 @@ Item {
|
|||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
loggingInSpinner.visible = false;
|
||||
loggingInGlyph.visible = false;
|
||||
var errorString = "";
|
||||
if (loggingInBody.linkSteam && loggingInBody.withSteam) {
|
||||
if (loggingInBody.linkOculus && loggingInBody.withOculus) {
|
||||
errorString = "Username or password is incorrect.";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user failed to link Oculus with their hifi account credentials"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
|
||||
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
|
||||
} else if (loggingInBody.linkSteam && loggingInBody.withSteam) {
|
||||
errorString = "Username or password is incorrect.";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
|
@ -301,9 +397,9 @@ Item {
|
|||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "linkSteam": loggingInBody.linkSteam, "errorString": errorString });
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
|
||||
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
|
||||
} else if (loggingInBody.withSteam) {
|
||||
loggingInGlyph.visible = false;
|
||||
errorString = "Your Steam authentication has failed. Please make sure you are logged into Steam and try again.";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
|
@ -311,19 +407,19 @@ Item {
|
|||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "errorString": errorString });
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
|
||||
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
|
||||
} else if (loggingInBody.withOculus) {
|
||||
loggingInGlyph.visible = false;
|
||||
errorString = "Your Oculus authentication has failed. Please make sure you are logged into Oculus and try again."
|
||||
errorString = "Your Oculus account is not connected to an existing High Fidelity account. Please create a new one."
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user failed to authenticate with Oculus to log in"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString });
|
||||
}
|
||||
else {
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam,
|
||||
"withOculus": loggingInBody.withOculus, "linkSteam": loggingInBody.linkSteam, "linkOculus": loggingInBody.linkOculus, "errorString": errorString });
|
||||
} else {
|
||||
errorString = "Username or password is incorrect.";
|
||||
if (loggingInBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
|
|
|
@ -23,6 +23,7 @@ Item {
|
|||
clip: true
|
||||
height: root.height
|
||||
width: root.width
|
||||
readonly property string termsContainerText: qsTr("By signing up, you agree to High Fidelity's Terms of Service")
|
||||
property int textFieldHeight: 31
|
||||
property string fontFamily: "Raleway"
|
||||
property int fontSize: 15
|
||||
|
@ -37,7 +38,6 @@ Item {
|
|||
onKeyboardRaisedChanged: d.resize();
|
||||
|
||||
property string errorString: errorString
|
||||
property bool linkSteam: linkSteam
|
||||
property bool lostFocus: false
|
||||
|
||||
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
|
||||
|
@ -73,7 +73,6 @@ Item {
|
|||
|
||||
function init() {
|
||||
// going to/from sign in/up dialog.
|
||||
loginDialog.isLogIn = false;
|
||||
emailField.placeholderText = "Email";
|
||||
emailField.text = "";
|
||||
emailField.anchors.top = usernameField.bottom;
|
||||
|
@ -353,7 +352,7 @@ Item {
|
|||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": signUpBody.linkSteam });
|
||||
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
|
||||
}
|
||||
}
|
||||
HifiControlsUit.Button {
|
||||
|
@ -380,6 +379,54 @@ Item {
|
|||
signUpBody.signup();
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: termsContainer
|
||||
width: parent.width
|
||||
height: termsTextMetrics.height
|
||||
anchors {
|
||||
top: signUpButton.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
}
|
||||
TextMetrics {
|
||||
id: termsTextMetrics
|
||||
font: termsText.font
|
||||
text: signUpBody.termsContainerText
|
||||
Component.onCompleted: {
|
||||
// with the link.
|
||||
termsText.text = qsTr("By signing up, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||
}
|
||||
}
|
||||
|
||||
HifiStylesUit.InfoItem {
|
||||
id: termsText
|
||||
text: signUpBody.termsContainerText
|
||||
font.family: signUpBody.fontFamily
|
||||
font.pixelSize: signUpBody.fontSize
|
||||
font.bold: signUpBody.fontBold
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.white
|
||||
linkColor: hifi.colors.blueAccent
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link);
|
||||
|
||||
Component.onCompleted: {
|
||||
if (termsTextMetrics.width > root.bannerWidth) {
|
||||
termsText.width = root.bannerWidth;
|
||||
termsText.wrapMode = Text.WordWrap;
|
||||
additionalText.verticalAlignment = Text.AlignLeft;
|
||||
additionalText.horizontalAlignment = Text.AlignLeft;
|
||||
termsContainer.height = (termsTextMetrics.width / root.bannerWidth) * termsTextMetrics.height;
|
||||
termsContainer.anchors.left = buttons.left;
|
||||
} else {
|
||||
termsText.anchors.centerIn = termsContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,14 +480,15 @@ Item {
|
|||
|
||||
if (errorString !== "") {
|
||||
loginErrorMessage.visible = true;
|
||||
var errorLength = errorString.split(/\r\n|\r|\n/).length;
|
||||
var errorStringEdited = errorString.replace(/[\n\r]+/g, "\n");
|
||||
loginErrorMessage.text = errorStringEdited;
|
||||
loginErrorMessageTextMetrics.text = errorString;
|
||||
if (loginErrorMessageTextMetrics.width > usernameField.width) {
|
||||
if (errorLength > 1.0) {
|
||||
loginErrorMessage.width = root.bannerWidth;
|
||||
loginErrorMessage.wrapMode = Text.WordWrap;
|
||||
loginErrorMessage.verticalAlignment = Text.AlignLeft;
|
||||
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
|
||||
errorContainer.height = (loginErrorMessageTextMetrics.width / usernameField.width) * loginErrorMessageTextMetrics.height;
|
||||
errorContainer.height = errorLength * loginErrorMessageTextMetrics.height;
|
||||
}
|
||||
errorContainer.anchors.bottom = usernameField.top;
|
||||
errorContainer.anchors.bottomMargin = hifi.dimensions.contentSpacing.y;
|
||||
|
|
|
@ -19,6 +19,7 @@ import TabletScriptingInterface 1.0
|
|||
Item {
|
||||
id: usernameCollisionBody
|
||||
clip: true
|
||||
readonly property string termsContainerText: qsTr("By creating this user profile, you agree to High Fidelity's Terms of Service")
|
||||
width: root.width
|
||||
height: root.height
|
||||
readonly property string fontFamily: "Raleway"
|
||||
|
@ -26,13 +27,18 @@ Item {
|
|||
readonly property int textFieldFontSize: 18
|
||||
readonly property bool fontBold: true
|
||||
|
||||
readonly property bool withSteam: withSteam
|
||||
property bool withSteam: withSteam
|
||||
property bool withOculus: withOculus
|
||||
|
||||
readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp()
|
||||
|
||||
function create() {
|
||||
mainTextContainer.visible = false
|
||||
loginDialog.createAccountFromSteam(textField.text);
|
||||
if (usernameCollisionBody.withOculus) {
|
||||
loginDialog.createAccountFromOculus(textField.text);
|
||||
} else if (usernameCollisionBody.withSteam) {
|
||||
loginDialog.createAccountFromSteam(textField.text);
|
||||
}
|
||||
}
|
||||
|
||||
property bool keyboardEnabled: false
|
||||
|
@ -90,12 +96,19 @@ Item {
|
|||
font.family: usernameCollisionBody.fontFamily
|
||||
font.pixelSize: usernameCollisionBody.fontSize
|
||||
font.bold: usernameCollisionBody.fontBold
|
||||
text: qsTr("Your Steam username is not available.");
|
||||
text: qsTr("");
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.redAccent
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Component.onCompleted: {
|
||||
if (usernameCollisionBody.withOculus) {
|
||||
text = qsTr("Your Oculus username is not available.");
|
||||
} else if (usernameCollisionBody.withSteam) {
|
||||
text = qsTr("Your Steam username is not available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -164,7 +177,8 @@ Item {
|
|||
fontSize: usernameCollisionBody.fontSize
|
||||
fontBold: usernameCollisionBody.fontBold
|
||||
onClicked: {
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "" });
|
||||
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam,
|
||||
"withOculus": usernameCollisionBody.withOculus, "errorString": "" });
|
||||
}
|
||||
}
|
||||
HifiControlsUit.Button {
|
||||
|
@ -187,6 +201,55 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: termsContainer
|
||||
width: parent.width
|
||||
height: termsTextMetrics.height
|
||||
anchors {
|
||||
top: buttons.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
leftMargin: (parent.width - buttons.width) / 2
|
||||
}
|
||||
TextMetrics {
|
||||
id: termsTextMetrics
|
||||
font: termsText.font
|
||||
text: usernameCollisionBody.termsContainerText
|
||||
Component.onCompleted: {
|
||||
// with the link.
|
||||
termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||
}
|
||||
}
|
||||
|
||||
HifiStylesUit.InfoItem {
|
||||
id: termsText
|
||||
text: usernameCollisionBody.termsContainerText
|
||||
font.family: usernameCollisionBody.fontFamily
|
||||
font.pixelSize: usernameCollisionBody.fontSize
|
||||
font.bold: usernameCollisionBody.fontBold
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.white
|
||||
linkColor: hifi.colors.blueAccent
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link);
|
||||
|
||||
Component.onCompleted: {
|
||||
if (termsTextMetrics.width > root.bannerWidth) {
|
||||
termsText.width = root.bannerWidth;
|
||||
termsText.wrapMode = Text.WordWrap;
|
||||
additionalText.verticalAlignment = Text.AlignLeft;
|
||||
additionalText.horizontalAlignment = Text.AlignLeft;
|
||||
termsContainer.height = (termsTextMetrics.width / root.bannerWidth) * termsTextMetrics.height;
|
||||
termsContainer.anchors.left = buttons.left;
|
||||
} else {
|
||||
termsText.anchors.centerIn = termsContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
@ -201,18 +264,25 @@ Item {
|
|||
target: loginDialog
|
||||
onHandleCreateCompleted: {
|
||||
console.log("Create Succeeded");
|
||||
if (usernameCollisionBody.withSteam) {
|
||||
if (usernameCollisionBody.withOculus) {
|
||||
if (usernameCollisionBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user created a profile with Oculus successfully in the username collision screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
loginDialog.loginThroughOculus();
|
||||
} else if (usernameCollisionBody.withSteam) {
|
||||
if (usernameCollisionBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user created a profile with Steam successfully in the username collision screen"
|
||||
}
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
}
|
||||
|
||||
loginDialog.loginThroughSteam();
|
||||
}
|
||||
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam, "linkSteam": false })
|
||||
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam,
|
||||
"withOculus": usernameCollisionBody.withOculus, "linkSteam": false, "linkOculus": false })
|
||||
}
|
||||
onHandleCreateFailed: {
|
||||
console.log("Create Failed: " + error)
|
||||
|
|
Binary file not shown.
Before ![]() (image error) Size: 960 KiB |
BIN
interface/resources/qml/LoginDialog/images/background.png
Normal file
BIN
interface/resources/qml/LoginDialog/images/background.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 2.2 MiB |
Binary file not shown.
Before ![]() (image error) Size: 272 KiB |
BIN
interface/resources/qml/LoginDialog/images/background_tablet.png
Normal file
BIN
interface/resources/qml/LoginDialog/images/background_tablet.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 456 KiB |
|
@ -55,7 +55,8 @@ FocusScope {
|
|||
Image {
|
||||
z: -10
|
||||
id: loginDialogBackground
|
||||
source: "LoginDialog/images/background.jpg"
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: "LoginDialog/images/background.png"
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
|
@ -149,6 +150,6 @@ FocusScope {
|
|||
|
||||
Component.onCompleted: {
|
||||
keyboardTimer.start();
|
||||
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
|
||||
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false, "linkOculus": false });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Dialogs 1.1
|
||||
import Qt.labs.folderlistmodel 2.11
|
||||
|
||||
Item {
|
||||
width: 640
|
||||
height: 480
|
||||
|
||||
ListView {
|
||||
width: 200; height: 400
|
||||
|
||||
FolderListModel {
|
||||
id: folderModel
|
||||
folder: "assets:/frames/"
|
||||
nameFilters: ["*.json"]
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fileDelegate
|
||||
Text { text: fileName }
|
||||
}
|
||||
|
||||
model: folderModel
|
||||
delegate: fileDelegate
|
||||
}
|
||||
}
|
|
@ -57,16 +57,23 @@ SpinBox {
|
|||
|
||||
locale: Qt.locale("en_US")
|
||||
|
||||
onValueModified: realValue = value/factor
|
||||
onValueChanged: realValue = value/factor
|
||||
onValueModified: {
|
||||
realValue = value / factor
|
||||
}
|
||||
|
||||
onValueChanged: {
|
||||
realValue = value / factor
|
||||
spinBox.editingFinished();
|
||||
}
|
||||
|
||||
onRealValueChanged: {
|
||||
var newValue = Math.round(realValue*factor);
|
||||
var newValue = Math.round(realValue * factor);
|
||||
if(value != newValue) {
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
stepSize: realStepSize*factor
|
||||
stepSize: realStepSize * factor
|
||||
to : realTo*factor
|
||||
from : realFrom*factor
|
||||
|
||||
|
@ -90,11 +97,11 @@ SpinBox {
|
|||
}
|
||||
|
||||
textFromValue: function(value, locale) {
|
||||
return parseFloat(value/factor).toFixed(decimals);
|
||||
return parseFloat(value / factor).toFixed(decimals);
|
||||
}
|
||||
|
||||
valueFromText: function(text, locale) {
|
||||
return Number.fromLocaleString(locale, text)*factor;
|
||||
return Number.fromLocaleString(locale, text) * factor;
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,7 +109,7 @@ SpinBox {
|
|||
id: spinboxText
|
||||
z: 2
|
||||
color: isLightColorScheme
|
||||
? (spinBox.activeFocus ? hifi.colors.black : hifi.colors.lightGray)
|
||||
? (spinBox.activeFocus ? hifi.colors.black : hifi.colors.faintGray)
|
||||
: (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGrayText)
|
||||
selectedTextColor: hifi.colors.black
|
||||
selectionColor: hifi.colors.primaryHighlight
|
||||
|
@ -112,8 +119,6 @@ SpinBox {
|
|||
verticalAlignment: Qt.AlignVCenter
|
||||
leftPadding: spinBoxLabelInside.visible ? 30 : hifi.dimensions.textPadding
|
||||
width: spinBox.width - hifi.dimensions.spinnerSize
|
||||
onEditingFinished: spinBox.editingFinished()
|
||||
|
||||
Text {
|
||||
id: suffixText
|
||||
x: metrics.advanceWidth(spinboxText.text + '*')
|
||||
|
@ -125,7 +130,7 @@ SpinBox {
|
|||
}
|
||||
|
||||
color: isLightColorScheme
|
||||
? (spinBox.activeFocus ? hifi.colors.black : hifi.colors.lightGray)
|
||||
? (spinBox.activeFocus ? hifi.colors.black : hifi.colors.faintGray)
|
||||
: (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGrayText)
|
||||
text: suffix
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
|
@ -170,6 +175,22 @@ SpinBox {
|
|||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.key === Qt.Key_Return) {
|
||||
if (!spinboxText.acceptableInput) {
|
||||
var number = spinBox.valueFromText(spinboxText.text, spinBox.locale) / spinBox.factor
|
||||
|
||||
if (number < spinBox.minimumValue) {
|
||||
number = spinBox.minimumValue;
|
||||
} else if (number > maximumValue) {
|
||||
number = spinBox.maximumValue;
|
||||
}
|
||||
|
||||
spinboxText.text = spinBox.textFromValue(Math.round(number * factor), spinBox.locale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Label {
|
||||
id: spinBoxLabel
|
||||
text: spinBox.label
|
||||
|
|
|
@ -14,6 +14,8 @@ import QtQuick 2.5
|
|||
import controlsUit 1.0 as HifiControlsUit
|
||||
import stylesUit 1.0 as HifiStylesUit
|
||||
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
import "../LoginDialog"
|
||||
|
||||
FocusScope {
|
||||
|
@ -25,10 +27,9 @@ FocusScope {
|
|||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
signal sendToScript(var message);
|
||||
signal canceled();
|
||||
property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
|
||||
property bool isHMD: false
|
||||
property bool isHMD: HMD.active
|
||||
property bool gotoPreviousApp: false;
|
||||
|
||||
property bool keyboardEnabled: false
|
||||
|
@ -52,6 +53,7 @@ FocusScope {
|
|||
}
|
||||
|
||||
function tryDestroy() {
|
||||
tabletProxy.gotoHomeScreen();
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
@ -76,7 +78,7 @@ FocusScope {
|
|||
interval: 200
|
||||
|
||||
onTriggered: {
|
||||
if (MenuInterface.isOptionChecked("Use 3D Keyboard")) {
|
||||
if (MenuInterface.isOptionChecked("Use 3D Keyboard") && root.isHMD) {
|
||||
KeyboardScriptingInterface.raised = true;
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +97,8 @@ FocusScope {
|
|||
Image {
|
||||
z: -10
|
||||
id: loginDialogBackground
|
||||
source: "../LoginDialog/images/background_tablet.jpg"
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: "../LoginDialog/images/background_tablet.png"
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
|
@ -168,11 +171,13 @@ FocusScope {
|
|||
|
||||
Component.onDestruction: {
|
||||
loginKeyboard.raised = false;
|
||||
KeyboardScriptingInterface.raised = false;
|
||||
if (root.isHMD) {
|
||||
KeyboardScriptingInterface.raised = false;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
keyboardTimer.start();
|
||||
bodyLoader.setSource("../LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
|
||||
bodyLoader.setSource("../LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false, "linkOculus": false });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ Windows.ScrollingWindow {
|
|||
}
|
||||
|
||||
function canAddToWorld(path) {
|
||||
var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i];
|
||||
var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i, /\.gltf\b/i];
|
||||
|
||||
if (selectedItemCount > 1) {
|
||||
return false;
|
||||
|
|
|
@ -254,6 +254,7 @@ Rectangle {
|
|||
onSaveClicked: function() {
|
||||
var avatarSettings = {
|
||||
dominantHand : settings.dominantHandIsLeft ? 'left' : 'right',
|
||||
hmdAvatarAlignmentType : settings.hmdAvatarAlignmentTypeIsEyes ? 'eyes' : 'head',
|
||||
collisionsEnabled : settings.environmentCollisionsOn,
|
||||
otherAvatarsCollisionsEnabled : settings.otherAvatarsCollisionsOn,
|
||||
animGraphOverrideUrl : settings.avatarAnimationOverrideJSON,
|
||||
|
|
|
@ -37,6 +37,7 @@ Rectangle {
|
|||
property alias dominantHandIsLeft: leftHandRadioButton.checked
|
||||
property alias otherAvatarsCollisionsOn: otherAvatarsCollisionsEnabledRadiobutton.checked
|
||||
property alias environmentCollisionsOn: environmentCollisionsEnabledRadiobutton.checked
|
||||
property alias hmdAvatarAlignmentTypeIsEyes: eyesRadioButton.checked
|
||||
property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text
|
||||
property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText
|
||||
property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text
|
||||
|
@ -65,6 +66,11 @@ Rectangle {
|
|||
} else {
|
||||
environmentCollisionsDisabledRadiobutton.checked = true;
|
||||
}
|
||||
if (settings.hmdAvatarAlignmentType === 'eyes') {
|
||||
eyesRadioButton.checked = true;
|
||||
} else {
|
||||
headRadioButton.checked = true;
|
||||
}
|
||||
|
||||
avatarAnimationJSON = settings.animGraphUrl;
|
||||
avatarAnimationOverrideJSON = settings.animGraphOverrideUrl;
|
||||
|
@ -210,7 +216,7 @@ Rectangle {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
rows: 2
|
||||
rows: 4
|
||||
rowSpacing: 25
|
||||
|
||||
columns: 3
|
||||
|
@ -233,7 +239,7 @@ Rectangle {
|
|||
|
||||
Layout.row: 0
|
||||
Layout.column: 1
|
||||
Layout.leftMargin: -20
|
||||
Layout.leftMargin: -15
|
||||
|
||||
ButtonGroup.group: leftRight
|
||||
checked: true
|
||||
|
@ -249,7 +255,7 @@ Rectangle {
|
|||
id: rightHandRadioButton
|
||||
|
||||
Layout.row: 0
|
||||
Layout.column: 3
|
||||
Layout.column: 2
|
||||
Layout.rightMargin: -15
|
||||
|
||||
ButtonGroup.group: leftRight
|
||||
|
@ -260,7 +266,7 @@ Rectangle {
|
|||
text: "Right"
|
||||
boxSize: 20
|
||||
}
|
||||
|
||||
|
||||
HifiConstants {
|
||||
id: hifi
|
||||
}
|
||||
|
@ -272,17 +278,17 @@ Rectangle {
|
|||
Layout.column: 0
|
||||
text: "Avatar to avatar collision"
|
||||
}
|
||||
|
||||
|
||||
ButtonGroup {
|
||||
id: otherAvatarsOnOff
|
||||
}
|
||||
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: otherAvatarsCollisionsEnabledRadiobutton
|
||||
|
||||
Layout.row: 1
|
||||
Layout.column: 1
|
||||
Layout.leftMargin: -20
|
||||
Layout.leftMargin: -15
|
||||
|
||||
ButtonGroup.group: otherAvatarsOnOff
|
||||
|
||||
|
@ -297,7 +303,7 @@ Rectangle {
|
|||
id: otherAvatarsCollisionsDisabledRadiobutton
|
||||
|
||||
Layout.row: 1
|
||||
Layout.column: 3
|
||||
Layout.column: 2
|
||||
Layout.rightMargin: -15
|
||||
|
||||
ButtonGroup.group: otherAvatarsOnOff
|
||||
|
@ -320,13 +326,13 @@ Rectangle {
|
|||
ButtonGroup {
|
||||
id: worldOnOff
|
||||
}
|
||||
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: environmentCollisionsEnabledRadiobutton
|
||||
|
||||
Layout.row: 2
|
||||
Layout.column: 1
|
||||
Layout.leftMargin: -20
|
||||
Layout.leftMargin: -15
|
||||
|
||||
ButtonGroup.group: worldOnOff
|
||||
|
||||
|
@ -341,7 +347,7 @@ Rectangle {
|
|||
id: environmentCollisionsDisabledRadiobutton
|
||||
|
||||
Layout.row: 2
|
||||
Layout.column: 3
|
||||
Layout.column: 2
|
||||
Layout.rightMargin: -15
|
||||
|
||||
ButtonGroup.group: worldOnOff
|
||||
|
@ -352,6 +358,52 @@ Rectangle {
|
|||
text: "Off"
|
||||
boxSize: 20
|
||||
}
|
||||
|
||||
// TextStyle9
|
||||
RalewaySemiBold {
|
||||
size: 17;
|
||||
Layout.row: 3
|
||||
Layout.column: 0
|
||||
text: "HMD Alignment"
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
id: headEyes
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: headRadioButton
|
||||
|
||||
Layout.row: 3
|
||||
Layout.column: 1
|
||||
Layout.leftMargin: -15
|
||||
|
||||
ButtonGroup.group: headEyes
|
||||
checked: true
|
||||
|
||||
colorScheme: hifi.colorSchemes.light
|
||||
fontSize: 17
|
||||
letterSpacing: 1.4
|
||||
text: "Head"
|
||||
boxSize: 20
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: eyesRadioButton
|
||||
|
||||
Layout.row: 3
|
||||
Layout.column: 2
|
||||
Layout.rightMargin: -15
|
||||
|
||||
ButtonGroup.group: headEyes
|
||||
|
||||
colorScheme: hifi.colorSchemes.light
|
||||
fontSize: 17
|
||||
letterSpacing: 1.4
|
||||
text: "Eyes"
|
||||
boxSize: 20
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
|
|
@ -148,7 +148,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
function canAddToWorld(path) {
|
||||
var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i];
|
||||
var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i, /\.gltf\b/i];
|
||||
|
||||
if (selectedItemCount > 1) {
|
||||
return false;
|
||||
|
|
|
@ -70,7 +70,7 @@ Flickable {
|
|||
readonly property bool hmdDesktop: hmdInDesktop.checked
|
||||
|
||||
property int state: buttonState.disabled
|
||||
property var lastConfiguration: null
|
||||
property var lastConfiguration: null
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
|
@ -90,7 +90,6 @@ Flickable {
|
|||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
onPressed: {
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
@ -169,9 +168,7 @@ Flickable {
|
|||
boxRadius: 7
|
||||
visible: viveInDesktop.checked
|
||||
|
||||
anchors.top: viveInDesktop.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: openVrConfiguration.left
|
||||
anchors.leftMargin: leftMargin + 10
|
||||
|
||||
onClicked: {
|
||||
|
@ -214,13 +211,13 @@ Flickable {
|
|||
|
||||
onRealValueChanged: {
|
||||
sendConfigurationSettings();
|
||||
openVrConfiguration.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HifiControls.SpinBox {
|
||||
id: headZOffset
|
||||
z: 10
|
||||
width: 112
|
||||
label: "Z Offset"
|
||||
minimumValue: -50
|
||||
|
@ -232,7 +229,6 @@ Flickable {
|
|||
|
||||
onRealValueChanged: {
|
||||
sendConfigurationSettings();
|
||||
openVrConfiguration.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -326,7 +322,6 @@ Flickable {
|
|||
|
||||
onRealValueChanged: {
|
||||
sendConfigurationSettings();
|
||||
openVrConfiguration.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,7 +339,6 @@ Flickable {
|
|||
|
||||
onRealValueChanged: {
|
||||
sendConfigurationSettings();
|
||||
openVrConfiguration.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -578,7 +572,6 @@ Flickable {
|
|||
|
||||
onRealValueChanged: {
|
||||
sendConfigurationSettings();
|
||||
openVrConfiguration.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -596,7 +589,6 @@ Flickable {
|
|||
|
||||
onRealValueChanged: {
|
||||
sendConfigurationSettings();
|
||||
openVrConfiguration.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -747,8 +739,8 @@ Flickable {
|
|||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
InputConfiguration.calibrationStatus.connect(calibrationStatusInfo);
|
||||
lastConfiguration = composeConfigurationSettings();
|
||||
InputConfiguration.calibrationStatus.connect(calibrationStatusInfo);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
|
@ -777,7 +769,6 @@ Flickable {
|
|||
calibrationTimer.interval = realValue * 1000;
|
||||
openVrConfiguration.countDown = realValue;
|
||||
numberAnimation.duration = calibrationTimer.interval;
|
||||
openVrConfiguration.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1048,6 +1039,9 @@ Flickable {
|
|||
}
|
||||
|
||||
function updateButtonState() {
|
||||
if (lastConfiguration === null) {
|
||||
lastConfiguration = composeConfigurationSettings();
|
||||
}
|
||||
var settings = composeConfigurationSettings();
|
||||
var bodySetting = settings["bodyConfiguration"];
|
||||
var headSetting = settings["headConfiguration"];
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
#include <plugins/PluginManager.h>
|
||||
#include <plugins/PluginUtils.h>
|
||||
#include <plugins/SteamClientPlugin.h>
|
||||
#include <plugins/OculusPlatformPlugin.h>
|
||||
#include <plugins/InputConfiguration.h>
|
||||
#include <RecordingScriptingInterface.h>
|
||||
#include <render/EngineStats.h>
|
||||
|
@ -780,7 +781,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
if (auto steamClient = pluginManager->getSteamClientPlugin()) {
|
||||
steamClient->init();
|
||||
}
|
||||
|
||||
PROFILE_SET_THREAD_NAME("Main Thread");
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
|
@ -2387,7 +2387,6 @@ void Application::updateVerboseLogging() {
|
|||
bool enable = menu->isOptionChecked(MenuOption::VerboseLogging);
|
||||
|
||||
QString rules =
|
||||
"hifi.*.debug=%1\n"
|
||||
"hifi.*.info=%1\n"
|
||||
"hifi.audio-stream.debug=false\n"
|
||||
"hifi.audio-stream.info=false";
|
||||
|
@ -2706,6 +2705,7 @@ Application::~Application() {
|
|||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||
steamClient->shutdown();
|
||||
}
|
||||
|
||||
DependencyManager::destroy<PluginManager>();
|
||||
|
||||
DependencyManager::destroy<CompositorHelper>(); // must be destroyed before the FramebufferCache
|
||||
|
@ -3512,8 +3512,10 @@ void Application::resizeGL() {
|
|||
auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
|
||||
assert(renderConfig);
|
||||
auto mainView = renderConfig->getConfig("RenderMainView.RenderDeferredTask");
|
||||
assert(mainView);
|
||||
mainView->setProperty("resolutionScale", renderResolutionScale);
|
||||
// mainView can be null if we're rendering in forward mode
|
||||
if (mainView) {
|
||||
mainView->setProperty("resolutionScale", renderResolutionScale);
|
||||
}
|
||||
displayPlugin->setRenderResolutionScale(renderResolutionScale);
|
||||
}
|
||||
|
||||
|
@ -4039,6 +4041,19 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_G:
|
||||
if (isShifted && isMeta && Menu::getInstance() && Menu::getInstance()->getMenu("Developer")->isVisible()) {
|
||||
static const QString HIFI_FRAMES_FOLDER_VAR = "HIFI_FRAMES_FOLDER";
|
||||
static const QString GPU_FRAME_FOLDER = QProcessEnvironment::systemEnvironment().contains(HIFI_FRAMES_FOLDER_VAR)
|
||||
? QProcessEnvironment::systemEnvironment().value(HIFI_FRAMES_FOLDER_VAR)
|
||||
: "hifiFrames";
|
||||
static QString GPU_FRAME_TEMPLATE = GPU_FRAME_FOLDER + "/{DATE}_{TIME}";
|
||||
QString fullPath = FileUtils::computeDocumentPath(FileUtils::replaceDateTimeTokens(GPU_FRAME_TEMPLATE));
|
||||
if (FileUtils::canCreateFile(fullPath)) {
|
||||
getActiveDisplayPlugin()->captureFrame(fullPath.toStdString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Qt::Key_X:
|
||||
if (isShifted && isMeta) {
|
||||
auto offscreenUi = getOffscreenUI();
|
||||
|
@ -4820,6 +4835,10 @@ void Application::idle() {
|
|||
steamClient->runCallbacks();
|
||||
}
|
||||
|
||||
if (auto oculusPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
|
||||
oculusPlugin->handleOVREvents();
|
||||
}
|
||||
|
||||
float secondsSinceLastUpdate = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_MSEC / MSECS_PER_SECOND;
|
||||
_lastTimeUpdated.start();
|
||||
|
||||
|
@ -5958,6 +5977,13 @@ void Application::update(float deltaTime) {
|
|||
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
|
||||
controller::HmdAvatarAlignmentType hmdAvatarAlignmentType;
|
||||
if (myAvatar->getHmdAvatarAlignmentType() == "eyes") {
|
||||
hmdAvatarAlignmentType = controller::HmdAvatarAlignmentType::Eyes;
|
||||
} else {
|
||||
hmdAvatarAlignmentType = controller::HmdAvatarAlignmentType::Head;
|
||||
}
|
||||
|
||||
controller::InputCalibrationData calibrationData = {
|
||||
myAvatar->getSensorToWorldMatrix(),
|
||||
createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()),
|
||||
|
@ -5971,7 +5997,8 @@ void Application::update(float deltaTime) {
|
|||
myAvatar->getRightArmCalibrationMat(),
|
||||
myAvatar->getLeftArmCalibrationMat(),
|
||||
myAvatar->getRightHandCalibrationMat(),
|
||||
myAvatar->getLeftHandCalibrationMat()
|
||||
myAvatar->getLeftHandCalibrationMat(),
|
||||
hmdAvatarAlignmentType
|
||||
};
|
||||
|
||||
InputPluginPointer keyboardMousePlugin;
|
||||
|
@ -8131,7 +8158,18 @@ void Application::toggleLogDialog() {
|
|||
return;
|
||||
}
|
||||
if (! _logDialog) {
|
||||
|
||||
bool keepOnTop =_keepLogWindowOnTop.get();
|
||||
#ifdef Q_OS_WIN
|
||||
_logDialog = new LogDialog(keepOnTop ? qApp->getWindow() : nullptr, getLogger());
|
||||
#else
|
||||
_logDialog = new LogDialog(nullptr, getLogger());
|
||||
|
||||
if (keepOnTop) {
|
||||
Qt::WindowFlags flags = _logDialog->windowFlags() | Qt::Tool;
|
||||
_logDialog->setWindowFlags(flags);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_logDialog->isVisible()) {
|
||||
|
@ -8141,6 +8179,19 @@ void Application::toggleLogDialog() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::recreateLogWindow(int keepOnTop) {
|
||||
_keepLogWindowOnTop.set(keepOnTop != 0);
|
||||
if (_logDialog) {
|
||||
bool toggle = _logDialog->isVisible();
|
||||
_logDialog->close();
|
||||
_logDialog = nullptr;
|
||||
|
||||
if (toggle) {
|
||||
toggleLogDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::toggleEntityScriptServerLogDialog() {
|
||||
if (! _entityScriptServerLogDialog) {
|
||||
_entityScriptServerLogDialog = new EntityScriptServerLogDialog(nullptr);
|
||||
|
|
|
@ -217,6 +217,8 @@ public:
|
|||
void setDesktopTabletScale(float desktopTabletScale);
|
||||
|
||||
bool getDesktopTabletBecomesToolbarSetting() { return _desktopTabletBecomesToolbarSetting.get(); }
|
||||
bool getLogWindowOnTopSetting() { return _keepLogWindowOnTop.get(); }
|
||||
void setLogWindowOnTopSetting(bool keepOnTop) { _keepLogWindowOnTop.set(keepOnTop); }
|
||||
void setDesktopTabletBecomesToolbarSetting(bool value);
|
||||
bool getHmdTabletBecomesToolbarSetting() { return _hmdTabletBecomesToolbarSetting.get(); }
|
||||
void setHmdTabletBecomesToolbarSetting(bool value);
|
||||
|
@ -365,6 +367,7 @@ public slots:
|
|||
Q_INVOKABLE void loadDialog();
|
||||
Q_INVOKABLE void loadScriptURLDialog() const;
|
||||
void toggleLogDialog();
|
||||
void recreateLogWindow(int);
|
||||
void toggleEntityScriptServerLogDialog();
|
||||
Q_INVOKABLE void showAssetServerWidget(QString filePath = "");
|
||||
Q_INVOKABLE void loadAddAvatarBookmarkDialog() const;
|
||||
|
@ -653,6 +656,7 @@ private:
|
|||
Setting::Handle<bool> _constrainToolbarPosition;
|
||||
Setting::Handle<QString> _preferredCursor;
|
||||
Setting::Handle<bool> _miniTabletEnabledSetting;
|
||||
Setting::Handle<bool> _keepLogWindowOnTop { "keepLogWindowOnTop", false };
|
||||
|
||||
float _scaleMirror;
|
||||
float _mirrorYawOffset;
|
||||
|
|
|
@ -288,39 +288,37 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
|||
glm::vec3 oneFrameVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep;
|
||||
|
||||
_measuredLinearVelocities[_measuredLinearVelocitiesIndex++] = oneFrameVelocity;
|
||||
if (_measuredLinearVelocitiesIndex >= AvatarActionHold::velocitySmoothFrames) {
|
||||
_measuredLinearVelocitiesIndex = 0;
|
||||
_measuredLinearVelocitiesIndex %= AvatarActionHold::velocitySmoothFrames;
|
||||
}
|
||||
|
||||
if (_kinematicSetVelocity) {
|
||||
glm::vec3 measuredLinearVelocity = _measuredLinearVelocities[0];
|
||||
for (int i = 1; i < AvatarActionHold::velocitySmoothFrames; i++) {
|
||||
// there is a bit of lag between when someone releases the trigger and when the software reacts to
|
||||
// the release. we calculate the velocity from previous frames but we don't include several
|
||||
// of the most recent.
|
||||
//
|
||||
// if _measuredLinearVelocitiesIndex is
|
||||
// 0 -- ignore i of 3 4 5
|
||||
// 1 -- ignore i of 4 5 0
|
||||
// 2 -- ignore i of 5 0 1
|
||||
// 3 -- ignore i of 0 1 2
|
||||
// 4 -- ignore i of 1 2 3
|
||||
// 5 -- ignore i of 2 3 4
|
||||
|
||||
// This code is now disabled, but I'm leaving it commented-out because I suspect it will come back.
|
||||
// if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex ||
|
||||
// (i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex ||
|
||||
// (i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
measuredLinearVelocity += _measuredLinearVelocities[i];
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 measuredLinearVelocity;
|
||||
for (int i = 0; i < AvatarActionHold::velocitySmoothFrames; i++) {
|
||||
// there is a bit of lag between when someone releases the trigger and when the software reacts to
|
||||
// the release. we calculate the velocity from previous frames but we don't include several
|
||||
// of the most recent.
|
||||
//
|
||||
// if _measuredLinearVelocitiesIndex is
|
||||
// 0 -- ignore i of 3 4 5
|
||||
// 1 -- ignore i of 4 5 0
|
||||
// 2 -- ignore i of 5 0 1
|
||||
// 3 -- ignore i of 0 1 2
|
||||
// 4 -- ignore i of 1 2 3
|
||||
// 5 -- ignore i of 2 3 4
|
||||
|
||||
// This code is now disabled, but I'm leaving it commented-out because I suspect it will come back.
|
||||
// if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex ||
|
||||
// (i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex ||
|
||||
// (i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
measuredLinearVelocity += _measuredLinearVelocities[i];
|
||||
}
|
||||
measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames
|
||||
measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames
|
||||
// - 3 // 3 because of the 3 we skipped, above
|
||||
);
|
||||
|
||||
if (_kinematicSetVelocity) {
|
||||
rigidBody->setLinearVelocity(glmToBullet(measuredLinearVelocity));
|
||||
rigidBody->setAngularVelocity(glmToBullet(_angularVelocityTarget));
|
||||
}
|
||||
|
|
3
interface/src/avatar/AvatarManager.cpp
Normal file → Executable file
3
interface/src/avatar/AvatarManager.cpp
Normal file → Executable file
|
@ -270,7 +270,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
if (avatar->getSkeletonModel()->isLoaded()) {
|
||||
// remove the orb if it is there
|
||||
avatar->removeOrb();
|
||||
avatar->updateCollisionGroup(_myAvatar->getOtherAvatarsCollisionsEnabled());
|
||||
if (avatar->needsPhysicsUpdate()) {
|
||||
_avatarsToChangeInPhysics.insert(avatar);
|
||||
}
|
||||
|
@ -376,7 +375,6 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
|
|||
}
|
||||
|
||||
AvatarSharedPointer AvatarManager::newSharedAvatar(const QUuid& sessionUUID) {
|
||||
|
||||
auto otherAvatar = new OtherAvatar(qApp->thread());
|
||||
otherAvatar->setSessionUUID(sessionUUID);
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
@ -452,6 +450,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar
|
|||
_spaceProxiesToDelete.push_back(avatar->getSpaceIndex());
|
||||
}
|
||||
AvatarHashMap::handleRemovedAvatar(avatar, removalReason);
|
||||
avatar->tearDownGrabs();
|
||||
|
||||
avatar->die();
|
||||
queuePhysicsChange(avatar);
|
||||
|
|
6
interface/src/avatar/AvatarMotionState.cpp
Normal file → Executable file
6
interface/src/avatar/AvatarMotionState.cpp
Normal file → Executable file
|
@ -15,7 +15,6 @@
|
|||
#include <PhysicsEngine.h>
|
||||
#include <PhysicsHelpers.h>
|
||||
|
||||
|
||||
AvatarMotionState::AvatarMotionState(OtherAvatarPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
|
||||
assert(_avatar);
|
||||
_type = MOTIONSTATE_TYPE_AVATAR;
|
||||
|
@ -172,7 +171,10 @@ QUuid AvatarMotionState::getSimulatorID() const {
|
|||
// virtual
|
||||
void AvatarMotionState::computeCollisionGroupAndMask(int32_t& group, int32_t& mask) const {
|
||||
group = _collisionGroup;
|
||||
mask = _collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS ? 0 : Physics::getDefaultCollisionMask(group);
|
||||
mask = Physics::getDefaultCollisionMask(group);
|
||||
if (!_avatar->getCollideWithOtherAvatars()) {
|
||||
mask &= ~(BULLET_COLLISION_GROUP_MY_AVATAR | BULLET_COLLISION_GROUP_OTHER_AVATAR);
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
|
|
@ -95,6 +95,37 @@ const float CENTIMETERS_PER_METER = 100.0f;
|
|||
|
||||
const QString AVATAR_SETTINGS_GROUP_NAME { "Avatar" };
|
||||
|
||||
static const QString USER_RECENTER_MODEL_FORCE_SIT = QStringLiteral("ForceSit");
|
||||
static const QString USER_RECENTER_MODEL_FORCE_STAND = QStringLiteral("ForceStand");
|
||||
static const QString USER_RECENTER_MODEL_AUTO = QStringLiteral("Auto");
|
||||
static const QString USER_RECENTER_MODEL_DISABLE_HMD_LEAN = QStringLiteral("DisableHMDLean");
|
||||
|
||||
MyAvatar::SitStandModelType stringToUserRecenterModel(const QString& str) {
|
||||
if (str == USER_RECENTER_MODEL_FORCE_SIT) {
|
||||
return MyAvatar::ForceSit;
|
||||
} else if (str == USER_RECENTER_MODEL_FORCE_STAND) {
|
||||
return MyAvatar::ForceStand;
|
||||
} else if (str == USER_RECENTER_MODEL_DISABLE_HMD_LEAN) {
|
||||
return MyAvatar::DisableHMDLean;
|
||||
} else {
|
||||
return MyAvatar::Auto;
|
||||
}
|
||||
}
|
||||
|
||||
QString userRecenterModelToString(MyAvatar::SitStandModelType model) {
|
||||
switch (model) {
|
||||
case MyAvatar::ForceSit:
|
||||
return USER_RECENTER_MODEL_FORCE_SIT;
|
||||
case MyAvatar::ForceStand:
|
||||
return USER_RECENTER_MODEL_FORCE_STAND;
|
||||
case MyAvatar::DisableHMDLean:
|
||||
return USER_RECENTER_MODEL_DISABLE_HMD_LEAN;
|
||||
case MyAvatar::Auto:
|
||||
default:
|
||||
return USER_RECENTER_MODEL_AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
MyAvatar::MyAvatar(QThread* thread) :
|
||||
Avatar(thread),
|
||||
_yawSpeed(YAW_SPEED_DEFAULT),
|
||||
|
@ -125,6 +156,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
_prevShouldDrawHead(true),
|
||||
_audioListenerMode(FROM_HEAD),
|
||||
_dominantHandSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "dominantHand", DOMINANT_RIGHT_HAND),
|
||||
_hmdAvatarAlignmentTypeSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "hmdAvatarAlignmentType", DEFAULT_HMD_AVATAR_ALIGNMENT_TYPE),
|
||||
_headPitchSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "", 0.0f),
|
||||
_scaleSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "scale", _targetScale),
|
||||
_yawSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "yawSpeed", _yawSpeed),
|
||||
|
@ -138,7 +170,8 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
_useSnapTurnSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "useSnapTurn", _useSnapTurn),
|
||||
_userHeightSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "userHeight", DEFAULT_AVATAR_HEIGHT),
|
||||
_flyingHMDSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "flyingHMD", _flyingPrefHMD),
|
||||
_avatarEntityCountSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData" << "size", 0)
|
||||
_avatarEntityCountSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData" << "size", 0),
|
||||
_userRecenterModelSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "userRecenterModel", USER_RECENTER_MODEL_AUTO)
|
||||
{
|
||||
_clientTraitsHandler.reset(new ClientTraitsHandler(this));
|
||||
|
||||
|
@ -205,12 +238,12 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
if (recordingInterface->getPlayFromCurrentLocation()) {
|
||||
setRecordingBasis();
|
||||
}
|
||||
_previousCollisionGroup = _characterController.computeCollisionGroup();
|
||||
_previousCollisionMask = _characterController.computeCollisionMask();
|
||||
_characterController.setCollisionless(true);
|
||||
} else {
|
||||
clearRecordingBasis();
|
||||
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
||||
if (_previousCollisionGroup != BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
if (_previousCollisionMask != BULLET_COLLISION_MASK_COLLISIONLESS) {
|
||||
_characterController.setCollisionless(false);
|
||||
}
|
||||
}
|
||||
|
@ -286,10 +319,25 @@ MyAvatar::~MyAvatar() {
|
|||
_myScriptEngine = nullptr;
|
||||
}
|
||||
|
||||
QString MyAvatar::getDominantHand() const {
|
||||
return _dominantHand.get();
|
||||
}
|
||||
|
||||
void MyAvatar::setDominantHand(const QString& hand) {
|
||||
if (hand == DOMINANT_LEFT_HAND || hand == DOMINANT_RIGHT_HAND) {
|
||||
_dominantHand = hand;
|
||||
emit dominantHandChanged(_dominantHand);
|
||||
_dominantHand.set(hand);
|
||||
emit dominantHandChanged(hand);
|
||||
}
|
||||
}
|
||||
|
||||
QString MyAvatar::getHmdAvatarAlignmentType() const {
|
||||
return _hmdAvatarAlignmentType.get();
|
||||
}
|
||||
|
||||
void MyAvatar::setHmdAvatarAlignmentType(const QString& type) {
|
||||
if (type != _hmdAvatarAlignmentType.get()) {
|
||||
_hmdAvatarAlignmentType.set(type);
|
||||
emit hmdAvatarAlignmentTypeChanged(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,6 +425,7 @@ void MyAvatar::resetSensorsAndBody() {
|
|||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "resetSensorsAndBody");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
qApp->getActiveDisplayPlugin()->resetSensors();
|
||||
|
@ -817,7 +866,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
|
|||
// and all of its joints, now update our attachements.
|
||||
Avatar::simulateAttachments(deltaTime);
|
||||
relayJointDataToChildren();
|
||||
if (updateGrabs()) {
|
||||
if (applyGrabChanges()) {
|
||||
_cauterizationNeedsUpdate = true;
|
||||
}
|
||||
|
||||
|
@ -1277,7 +1326,8 @@ void MyAvatar::resizeAvatarEntitySettingHandles(uint32_t maxIndex) {
|
|||
}
|
||||
|
||||
void MyAvatar::saveData() {
|
||||
_dominantHandSetting.set(_dominantHand);
|
||||
_dominantHandSetting.set(getDominantHand());
|
||||
_hmdAvatarAlignmentTypeSetting.set(getHmdAvatarAlignmentType());
|
||||
_headPitchSetting.set(getHead()->getBasePitch());
|
||||
_scaleSetting.set(_targetScale);
|
||||
_yawSpeedSetting.set(_yawSpeed);
|
||||
|
@ -1300,6 +1350,7 @@ void MyAvatar::saveData() {
|
|||
_useSnapTurnSetting.set(_useSnapTurn);
|
||||
_userHeightSetting.set(getUserHeight());
|
||||
_flyingHMDSetting.set(getFlyingHMDPref());
|
||||
_userRecenterModelSetting.set(userRecenterModelToString(getUserRecenterModel()));
|
||||
|
||||
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||
saveAvatarEntityDataToSettings();
|
||||
|
@ -1882,9 +1933,12 @@ void MyAvatar::loadData() {
|
|||
setCollisionSoundURL(_collisionSoundURLSetting.get(QUrl(DEFAULT_AVATAR_COLLISION_SOUND_URL)).toString());
|
||||
setSnapTurn(_useSnapTurnSetting.get());
|
||||
setDominantHand(_dominantHandSetting.get(DOMINANT_RIGHT_HAND).toLower());
|
||||
setHmdAvatarAlignmentType(_hmdAvatarAlignmentTypeSetting.get(DEFAULT_HMD_AVATAR_ALIGNMENT_TYPE).toLower());
|
||||
setUserHeight(_userHeightSetting.get(DEFAULT_AVATAR_HEIGHT));
|
||||
setTargetScale(_scaleSetting.get());
|
||||
|
||||
setUserRecenterModel(stringToUserRecenterModel(_userRecenterModelSetting.get(USER_RECENTER_MODEL_AUTO)));
|
||||
|
||||
setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible));
|
||||
_follow.setToggleHipsFollowing (Menu::getInstance()->isOptionChecked(MenuOption::ToggleHipsFollowing));
|
||||
setEnableDebugDrawBaseOfSupport(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawBaseOfSupport));
|
||||
|
@ -2534,7 +2588,7 @@ void MyAvatar::updateMotors() {
|
|||
float verticalMotorTimescale;
|
||||
|
||||
if (_characterController.getState() == CharacterController::State::Hover ||
|
||||
_characterController.computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) {
|
||||
horizontalMotorTimescale = FLYING_MOTOR_TIMESCALE;
|
||||
verticalMotorTimescale = FLYING_MOTOR_TIMESCALE;
|
||||
} else {
|
||||
|
@ -2544,7 +2598,7 @@ void MyAvatar::updateMotors() {
|
|||
|
||||
if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) {
|
||||
if (_characterController.getState() == CharacterController::State::Hover ||
|
||||
_characterController.computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) {
|
||||
motorRotation = getMyHead()->getHeadOrientation();
|
||||
} else {
|
||||
// non-hovering = walking: follow camera twist about vertical but not lift
|
||||
|
@ -2599,7 +2653,7 @@ void MyAvatar::prepareForPhysicsSimulation() {
|
|||
qDebug() << "Warning: getParentVelocity failed" << getID();
|
||||
parentVelocity = glm::vec3();
|
||||
}
|
||||
_characterController.handleChangedCollisionGroup();
|
||||
_characterController.handleChangedCollisionMask();
|
||||
_characterController.setParentVelocity(parentVelocity);
|
||||
_characterController.setScaleFactor(getSensorToWorldScale());
|
||||
|
||||
|
@ -3279,7 +3333,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
head->setBaseRoll(ROLL(euler));
|
||||
} else {
|
||||
head->setBaseYaw(0.0f);
|
||||
head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime
|
||||
head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime
|
||||
+ getDriveKey(DELTA_PITCH) * _pitchSpeed / PITCH_SPEED_DEFAULT);
|
||||
head->setBaseRoll(0.0f);
|
||||
}
|
||||
|
@ -3325,7 +3379,7 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
|||
|
||||
glm::vec3 direction = forward + right;
|
||||
if (state == CharacterController::State::Hover ||
|
||||
_characterController.computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) {
|
||||
glm::vec3 up = (getDriveKey(TRANSLATE_Y)) * IDENTITY_UP;
|
||||
direction += up;
|
||||
}
|
||||
|
@ -3881,7 +3935,7 @@ void MyAvatar::setCollisionsEnabled(bool enabled) {
|
|||
bool MyAvatar::getCollisionsEnabled() {
|
||||
// may return 'false' even though the collisionless option was requested
|
||||
// because the zone may disallow collisionless avatars
|
||||
return _characterController.computeCollisionGroup() != BULLET_COLLISION_GROUP_COLLISIONLESS;
|
||||
return _characterController.computeCollisionMask() != BULLET_COLLISION_MASK_COLLISIONLESS;
|
||||
}
|
||||
|
||||
void MyAvatar::setOtherAvatarsCollisionsEnabled(bool enabled) {
|
||||
|
@ -3890,7 +3944,11 @@ void MyAvatar::setOtherAvatarsCollisionsEnabled(bool enabled) {
|
|||
QMetaObject::invokeMethod(this, "setOtherAvatarsCollisionsEnabled", Q_ARG(bool, enabled));
|
||||
return;
|
||||
}
|
||||
bool change = _collideWithOtherAvatars != enabled;
|
||||
_collideWithOtherAvatars = enabled;
|
||||
if (change) {
|
||||
setCollisionWithOtherAvatarsFlags();
|
||||
}
|
||||
emit otherAvatarsCollisionsEnabledChanged(enabled);
|
||||
}
|
||||
|
||||
|
@ -3898,6 +3956,11 @@ bool MyAvatar::getOtherAvatarsCollisionsEnabled() {
|
|||
return _collideWithOtherAvatars;
|
||||
}
|
||||
|
||||
void MyAvatar::setCollisionWithOtherAvatarsFlags() {
|
||||
_characterController.setCollideWithOtherAvatars(_collideWithOtherAvatars);
|
||||
_characterController.setPendingFlagsUpdateCollisionMask();
|
||||
}
|
||||
|
||||
void MyAvatar::updateCollisionCapsuleCache() {
|
||||
glm::vec3 start, end;
|
||||
float radius;
|
||||
|
@ -4752,7 +4815,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons
|
|||
}
|
||||
|
||||
bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||
const float CYLINDER_TOP = 0.1f;
|
||||
const float CYLINDER_TOP = 2.0f;
|
||||
const float CYLINDER_BOTTOM = -1.5f;
|
||||
const float SITTING_BOTTOM = -0.02f;
|
||||
|
||||
|
@ -5310,7 +5373,7 @@ void MyAvatar::releaseGrab(const QUuid& grabID) {
|
|||
|
||||
_avatarGrabsLock.withWriteLock([&] {
|
||||
if (_avatarGrabData.remove(grabID)) {
|
||||
_deletedAvatarGrabs.insert(grabID);
|
||||
_grabsToDelete.push_back(grabID);
|
||||
tellHandler = true;
|
||||
}
|
||||
});
|
||||
|
|
30
interface/src/avatar/MyAvatar.h
Normal file → Executable file
30
interface/src/avatar/MyAvatar.h
Normal file → Executable file
|
@ -252,6 +252,7 @@ class MyAvatar : public Avatar {
|
|||
|
||||
const QString DOMINANT_LEFT_HAND = "left";
|
||||
const QString DOMINANT_RIGHT_HAND = "right";
|
||||
const QString DEFAULT_HMD_AVATAR_ALIGNMENT_TYPE = "head";
|
||||
|
||||
using Clock = std::chrono::system_clock;
|
||||
using TimePoint = Clock::time_point;
|
||||
|
@ -297,6 +298,8 @@ public:
|
|||
|
||||
void reset(bool andRecenter = false, bool andReload = true, bool andHead = true);
|
||||
|
||||
void setCollisionWithOtherAvatarsFlags() override;
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.resetSensorsAndBody
|
||||
*/
|
||||
|
@ -517,7 +520,18 @@ public:
|
|||
* @function MyAvatar.getDominantHand
|
||||
* @returns {string}
|
||||
*/
|
||||
Q_INVOKABLE QString getDominantHand() const { return _dominantHand; }
|
||||
Q_INVOKABLE QString getDominantHand() const;
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.setHmdAvatarAlignmentType
|
||||
* @param {string} hand
|
||||
*/
|
||||
Q_INVOKABLE void setHmdAvatarAlignmentType(const QString& hand);
|
||||
/**jsdoc
|
||||
* @function MyAvatar.setHmdAvatarAlignmentType
|
||||
* @returns {string}
|
||||
*/
|
||||
Q_INVOKABLE QString getHmdAvatarAlignmentType() const;
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.setCenterOfGravityModelEnabled
|
||||
|
@ -1583,6 +1597,13 @@ signals:
|
|||
*/
|
||||
void dominantHandChanged(const QString& hand);
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.hmdAvatarAlignmentTypeChanged
|
||||
* @param {string} type
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void hmdAvatarAlignmentTypeChanged(const QString& type);
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.sensorToWorldScaleChanged
|
||||
* @param {number} scale
|
||||
|
@ -1732,7 +1753,7 @@ private:
|
|||
SharedSoundPointer _collisionSound;
|
||||
|
||||
MyCharacterController _characterController;
|
||||
int32_t _previousCollisionGroup { BULLET_COLLISION_GROUP_MY_AVATAR };
|
||||
int32_t _previousCollisionMask { BULLET_COLLISION_MASK_MY_AVATAR };
|
||||
|
||||
AvatarWeakPointer _lookAtTargetAvatar;
|
||||
glm::vec3 _targetAvatarPosition;
|
||||
|
@ -1771,7 +1792,8 @@ private:
|
|||
ThreadSafeValueCache<QUrl> _prefOverrideAnimGraphUrl;
|
||||
QUrl _fstAnimGraphOverrideUrl;
|
||||
bool _useSnapTurn { true };
|
||||
QString _dominantHand { DOMINANT_RIGHT_HAND };
|
||||
ThreadSafeValueCache<QString> _dominantHand { DOMINANT_RIGHT_HAND };
|
||||
ThreadSafeValueCache<QString> _hmdAvatarAlignmentType { DEFAULT_HMD_AVATAR_ALIGNMENT_TYPE };
|
||||
|
||||
const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // degrees
|
||||
const float ROLL_CONTROL_RATE_DEFAULT = 114.0f; // degrees / sec
|
||||
|
@ -1944,6 +1966,7 @@ private:
|
|||
TimePoint _nextTraitsSendWindow;
|
||||
|
||||
Setting::Handle<QString> _dominantHandSetting;
|
||||
Setting::Handle<QString> _hmdAvatarAlignmentTypeSetting;
|
||||
Setting::Handle<float> _headPitchSetting;
|
||||
Setting::Handle<float> _scaleSetting;
|
||||
Setting::Handle<float> _yawSpeedSetting;
|
||||
|
@ -1960,6 +1983,7 @@ private:
|
|||
Setting::Handle<bool> _allowTeleportingSetting { "allowTeleporting", true };
|
||||
std::vector<Setting::Handle<QUuid>> _avatarEntityIDSettings;
|
||||
std::vector<Setting::Handle<QByteArray>> _avatarEntityDataSettings;
|
||||
Setting::Handle<QString> _userRecenterModelSetting;
|
||||
|
||||
// AvatarEntities stuff:
|
||||
// We cache the "map of unfortunately-formatted-binary-blobs" because they are expensive to compute
|
||||
|
|
|
@ -202,6 +202,29 @@ bool MyCharacterController::testRayShotgun(const glm::vec3& position, const glm:
|
|||
return result.hitFraction < 1.0f;
|
||||
}
|
||||
|
||||
int32_t MyCharacterController::computeCollisionMask() const {
|
||||
int32_t collisionMask = BULLET_COLLISION_MASK_MY_AVATAR;
|
||||
if (_collisionless && _collisionlessAllowed) {
|
||||
collisionMask = BULLET_COLLISION_MASK_COLLISIONLESS;
|
||||
} else if (!_collideWithOtherAvatars) {
|
||||
collisionMask &= ~BULLET_COLLISION_GROUP_OTHER_AVATAR;
|
||||
}
|
||||
return collisionMask;
|
||||
}
|
||||
|
||||
void MyCharacterController::handleChangedCollisionMask() {
|
||||
if (_pendingFlags & PENDING_FLAG_UPDATE_COLLISION_MASK) {
|
||||
// ATM the easiest way to update collision groups/masks is to remove/re-add the RigidBody
|
||||
if (_dynamicsWorld) {
|
||||
_dynamicsWorld->removeRigidBody(_rigidBody);
|
||||
int32_t collisionMask = computeCollisionMask();
|
||||
_dynamicsWorld->addRigidBody(_rigidBody, BULLET_COLLISION_GROUP_MY_AVATAR, collisionMask);
|
||||
}
|
||||
_pendingFlags &= ~PENDING_FLAG_UPDATE_COLLISION_MASK;
|
||||
updateCurrentGravity();
|
||||
}
|
||||
}
|
||||
|
||||
btConvexHullShape* MyCharacterController::computeShape() const {
|
||||
// HACK: the avatar collides using convex hull with a collision margin equal to
|
||||
// the old capsule radius. Two points define a capsule and additional points are
|
||||
|
|
6
interface/src/avatar/MyCharacterController.h
Normal file → Executable file
6
interface/src/avatar/MyCharacterController.h
Normal file → Executable file
|
@ -42,6 +42,12 @@ public:
|
|||
|
||||
void setDensity(btScalar density) { _density = density; }
|
||||
|
||||
int32_t computeCollisionMask() const override;
|
||||
void handleChangedCollisionMask() override;
|
||||
|
||||
bool _collideWithOtherAvatars{ true };
|
||||
void setCollideWithOtherAvatars(bool collideWithOtherAvatars) { _collideWithOtherAvatars = collideWithOtherAvatars; }
|
||||
|
||||
protected:
|
||||
void initRayShotgun(const btCollisionWorld* world);
|
||||
void updateMassProperties() override;
|
||||
|
|
4
interface/src/avatar/MySkeletonModel.cpp
Normal file → Executable file
4
interface/src/avatar/MySkeletonModel.cpp
Normal file → Executable file
|
@ -187,7 +187,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
}
|
||||
}
|
||||
|
||||
bool isFlying = (myAvatar->getCharacterController()->getState() == CharacterController::State::Hover || myAvatar->getCharacterController()->computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS);
|
||||
bool isFlying = (myAvatar->getCharacterController()->getState() == CharacterController::State::Hover || myAvatar->getCharacterController()->computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS);
|
||||
if (isFlying != _prevIsFlying) {
|
||||
const float FLY_TO_IDLE_HIPS_TRANSITION_TIME = 0.5f;
|
||||
_flyIdleTimer = FLY_TO_IDLE_HIPS_TRANSITION_TIME;
|
||||
|
@ -198,7 +198,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
|
||||
// if hips are not under direct control, estimate the hips position.
|
||||
if (avatarHeadPose.isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Hips] & (uint8_t)Rig::ControllerFlags::Enabled)) {
|
||||
bool isFlying = (myAvatar->getCharacterController()->getState() == CharacterController::State::Hover || myAvatar->getCharacterController()->computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS);
|
||||
bool isFlying = (myAvatar->getCharacterController()->getState() == CharacterController::State::Hover || myAvatar->getCharacterController()->computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS);
|
||||
|
||||
// timescale in seconds
|
||||
const float TRANS_HORIZ_TIMESCALE = 0.15f;
|
||||
|
|
14
interface/src/avatar/OtherAvatar.cpp
Normal file → Executable file
14
interface/src/avatar/OtherAvatar.cpp
Normal file → Executable file
|
@ -138,17 +138,9 @@ void OtherAvatar::rebuildCollisionShape() {
|
|||
}
|
||||
}
|
||||
|
||||
void OtherAvatar::updateCollisionGroup(bool myAvatarCollide) {
|
||||
void OtherAvatar::setCollisionWithOtherAvatarsFlags() {
|
||||
if (_motionState) {
|
||||
bool collides = _motionState->getCollisionGroup() == BULLET_COLLISION_GROUP_OTHER_AVATAR && myAvatarCollide;
|
||||
if (_collideWithOtherAvatars != collides) {
|
||||
if (!myAvatarCollide) {
|
||||
_collideWithOtherAvatars = false;
|
||||
}
|
||||
auto newCollisionGroup = _collideWithOtherAvatars ? BULLET_COLLISION_GROUP_OTHER_AVATAR : BULLET_COLLISION_GROUP_COLLISIONLESS;
|
||||
_motionState->setCollisionGroup(newCollisionGroup);
|
||||
_motionState->addDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
|
||||
}
|
||||
_motionState->addDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,7 +220,7 @@ void OtherAvatar::simulate(float deltaTime, bool inView) {
|
|||
|
||||
{
|
||||
PROFILE_RANGE(simulation, "grabs");
|
||||
updateGrabs();
|
||||
applyGrabChanges();
|
||||
}
|
||||
|
||||
updateFadingStatus();
|
||||
|
|
4
interface/src/avatar/OtherAvatar.h
Normal file → Executable file
4
interface/src/avatar/OtherAvatar.h
Normal file → Executable file
|
@ -44,7 +44,9 @@ public:
|
|||
bool shouldBeInPhysicsSimulation() const;
|
||||
bool needsPhysicsUpdate() const;
|
||||
|
||||
void updateCollisionGroup(bool myAvatarCollide);
|
||||
bool getCollideWithOtherAvatars() const { return _collideWithOtherAvatars; }
|
||||
|
||||
void setCollisionWithOtherAvatarsFlags() override;
|
||||
|
||||
void simulate(float deltaTime, bool inView) override;
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
#include <PathUtils.h>
|
||||
|
||||
const int TOP_BAR_HEIGHT = 124;
|
||||
const int INITIAL_WIDTH = 720;
|
||||
const int INITIAL_WIDTH = 800;
|
||||
const int INITIAL_HEIGHT = 480;
|
||||
const int MINIMAL_WIDTH = 700;
|
||||
const int MINIMAL_WIDTH = 780;
|
||||
const int SEARCH_BUTTON_LEFT = 25;
|
||||
const int SEARCH_BUTTON_WIDTH = 20;
|
||||
const int SEARCH_TOGGLE_BUTTON_WIDTH = 50;
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
|
||||
#include <shared/AbstractLoggerInterface.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
const int REVEAL_BUTTON_WIDTH = 122;
|
||||
const int ALL_LOGS_BUTTON_WIDTH = 90;
|
||||
const int MARGIN_LEFT = 25;
|
||||
|
@ -148,6 +151,16 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog
|
|||
_messageCount->setObjectName("messageCount");
|
||||
_messageCount->show();
|
||||
|
||||
_keepOnTopBox = new QCheckBox(" Keep window on top", this);
|
||||
bool isOnTop = qApp-> getLogWindowOnTopSetting();
|
||||
_keepOnTopBox->setCheckState(isOnTop ? Qt::Checked : Qt::Unchecked);
|
||||
#ifdef Q_OS_WIN
|
||||
connect(_keepOnTopBox, &QCheckBox::stateChanged, qApp, &Application::recreateLogWindow);
|
||||
#else
|
||||
connect(_keepOnTopBox, &QCheckBox::stateChanged, this, &LogDialog::handleKeepWindowOnTop);
|
||||
#endif
|
||||
_keepOnTopBox->show();
|
||||
|
||||
_extraDebuggingBox = new QCheckBox("Extra debugging", this);
|
||||
if (_logger->extraDebugging()) {
|
||||
_extraDebuggingBox->setCheckState(Qt::Checked);
|
||||
|
@ -183,6 +196,11 @@ void LogDialog::resizeEvent(QResizeEvent* event) {
|
|||
THIRD_ROW,
|
||||
COMBOBOX_WIDTH,
|
||||
ELEMENT_HEIGHT);
|
||||
|
||||
_keepOnTopBox->setGeometry(width() - ELEMENT_MARGIN - COMBOBOX_WIDTH - ELEMENT_MARGIN - ALL_LOGS_BUTTON_WIDTH - ELEMENT_MARGIN - COMBOBOX_WIDTH - ELEMENT_MARGIN,
|
||||
THIRD_ROW,
|
||||
COMBOBOX_WIDTH,
|
||||
ELEMENT_HEIGHT);
|
||||
_messageCount->setGeometry(_leftPad,
|
||||
THIRD_ROW,
|
||||
COMBOBOX_WIDTH,
|
||||
|
@ -234,6 +252,23 @@ void LogDialog::handleInfoPrintBox(int state) {
|
|||
printLogFile();
|
||||
}
|
||||
|
||||
void LogDialog::handleKeepWindowOnTop(int state) {
|
||||
bool keepOnTop = (state != 0);
|
||||
|
||||
Qt::WindowFlags flags = windowFlags();
|
||||
|
||||
if (keepOnTop) {
|
||||
flags |= Qt::Tool;
|
||||
} else {
|
||||
flags &= ~Qt::Tool;
|
||||
}
|
||||
|
||||
setWindowFlags(flags);
|
||||
qApp->setLogWindowOnTopSetting(keepOnTop);
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
void LogDialog::handleCriticalPrintBox(int state) {
|
||||
_logger->setCriticalPrint(state != 0);
|
||||
printLogFile();
|
||||
|
|
|
@ -34,6 +34,7 @@ public slots:
|
|||
private slots:
|
||||
void handleRevealButton();
|
||||
void handleExtraDebuggingCheckbox(int);
|
||||
void handleKeepWindowOnTop(int);
|
||||
void handleDebugPrintBox(int);
|
||||
void handleInfoPrintBox(int);
|
||||
void handleCriticalPrintBox(int);
|
||||
|
@ -55,6 +56,7 @@ protected:
|
|||
|
||||
private:
|
||||
QCheckBox* _extraDebuggingBox;
|
||||
QCheckBox* _keepOnTopBox;
|
||||
QPushButton* _revealLogButton;
|
||||
QPushButton* _allLogsButton;
|
||||
QCheckBox* _debugPrintBox;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <plugins/SteamClientPlugin.h>
|
||||
#include <plugins/OculusPlatformPlugin.h>
|
||||
#include <shared/GlobalAppProperties.h>
|
||||
#include <ui/TabletScriptingInterface.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
@ -109,8 +110,16 @@ bool LoginDialog::isSteamRunning() const {
|
|||
return steamClient && steamClient->isRunning();
|
||||
}
|
||||
|
||||
bool LoginDialog::isOculusStoreRunning() const {
|
||||
return qApp->property(hifi::properties::OCULUS_STORE).toBool();
|
||||
bool LoginDialog::isOculusRunning() const {
|
||||
auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin();
|
||||
return (oculusPlatformPlugin && oculusPlatformPlugin->isRunning());
|
||||
}
|
||||
|
||||
QString LoginDialog::oculusUserID() const {
|
||||
if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
|
||||
return oculusPlatformPlugin->getOculusUserID();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void LoginDialog::dismissLoginDialog() {
|
||||
|
@ -126,6 +135,79 @@ void LoginDialog::login(const QString& username, const QString& password) const
|
|||
DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
|
||||
}
|
||||
|
||||
void LoginDialog::loginThroughOculus() {
|
||||
qDebug() << "Attempting to login through Oculus";
|
||||
if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
|
||||
oculusPlatformPlugin->requestNonceAndUserID([this] (QString nonce, QString oculusID) {
|
||||
DependencyManager::get<AccountManager>()->requestAccessTokenWithOculus(nonce, oculusID);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void LoginDialog::linkOculus() {
|
||||
qDebug() << "Attempting to link Oculus account";
|
||||
if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
|
||||
oculusPlatformPlugin->requestNonceAndUserID([this] (QString nonce, QString oculusID) {
|
||||
if (nonce.isEmpty() || oculusID.isEmpty()) {
|
||||
emit handleLoginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "linkCompleted";
|
||||
callbackParams.errorCallbackMethod = "linkFailed";
|
||||
const QString LINK_OCULUS_PATH = "api/v1/user/oculus/link";
|
||||
|
||||
QJsonObject payload;
|
||||
payload["oculus_nonce"] = nonce;
|
||||
payload["oculus_id"] = oculusID;
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->sendRequest(LINK_OCULUS_PATH, AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::PostOperation, callbackParams,
|
||||
QJsonDocument(payload).toJson());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void LoginDialog::createAccountFromOculus(QString email, QString username, QString password) {
|
||||
qDebug() << "Attempting to create account from Oculus info";
|
||||
if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) {
|
||||
oculusPlatformPlugin->requestNonceAndUserID([this, email, username, password] (QString nonce, QString oculusID) {
|
||||
if (nonce.isEmpty() || oculusID.isEmpty()) {
|
||||
emit handleLoginFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
JSONCallbackParameters callbackParams;
|
||||
callbackParams.callbackReceiver = this;
|
||||
callbackParams.jsonCallbackMethod = "createCompleted";
|
||||
callbackParams.errorCallbackMethod = "createFailed";
|
||||
|
||||
const QString CREATE_ACCOUNT_FROM_OCULUS_PATH = "api/v1/user/oculus/create";
|
||||
|
||||
QJsonObject payload;
|
||||
payload["oculus_nonce"] = nonce;
|
||||
payload["oculus_id"] = oculusID;
|
||||
if (!email.isEmpty()) {
|
||||
payload["email"] = email;
|
||||
}
|
||||
if (!username.isEmpty()) {
|
||||
payload["username"] = username;
|
||||
}
|
||||
if (!password.isEmpty()) {
|
||||
payload["password"] = password;
|
||||
}
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->sendRequest(CREATE_ACCOUNT_FROM_OCULUS_PATH, AccountManagerAuth::None,
|
||||
QNetworkAccessManager::PostOperation, callbackParams,
|
||||
QJsonDocument(payload).toJson());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void LoginDialog::loginThroughSteam() {
|
||||
qDebug() << "Attempting to login through Steam";
|
||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||
|
@ -157,7 +239,7 @@ void LoginDialog::linkSteam() {
|
|||
const QString LINK_STEAM_PATH = "api/v1/user/steam/link";
|
||||
|
||||
QJsonObject payload;
|
||||
payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));
|
||||
payload["steam_auth_ticket"] = QJsonValue::fromVariant(QVariant(ticket));
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->sendRequest(LINK_STEAM_PATH, AccountManagerAuth::Required,
|
||||
|
@ -184,9 +266,9 @@ void LoginDialog::createAccountFromSteam(QString username) {
|
|||
const QString CREATE_ACCOUNT_FROM_STEAM_PATH = "api/v1/user/steam/create";
|
||||
|
||||
QJsonObject payload;
|
||||
payload.insert("steam_auth_ticket", QJsonValue::fromVariant(QVariant(ticket)));
|
||||
payload["steam_auth_ticket"] = QJsonValue::fromVariant(QVariant(ticket));
|
||||
if (!username.isEmpty()) {
|
||||
payload.insert("username", QJsonValue::fromVariant(QVariant(username)));
|
||||
payload["username"] = username;
|
||||
}
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
@ -214,6 +296,45 @@ void LoginDialog::createCompleted(QNetworkReply* reply) {
|
|||
}
|
||||
|
||||
void LoginDialog::createFailed(QNetworkReply* reply) {
|
||||
if (isOculusRunning()) {
|
||||
auto replyData = reply->readAll();
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(replyData, &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
emit handleCreateFailed(reply->errorString());
|
||||
return;
|
||||
}
|
||||
auto data = doc["data"];
|
||||
auto error = data["error"];
|
||||
auto oculusError = data["oculus"];
|
||||
auto user = error["username"].toArray();
|
||||
auto uid = error["uid"].toArray();
|
||||
auto email = error["email"].toArray();
|
||||
auto password = error["password"].toArray();
|
||||
QString reply;
|
||||
if (uid[0].isString()) {
|
||||
emit handleCreateFailed("Oculus ID " + uid[0].toString() + ".");
|
||||
return;
|
||||
}
|
||||
if (user[0].isString()) {
|
||||
reply = "Username " + user[0].toString() + ".";
|
||||
}
|
||||
if (email[0].isString()) {
|
||||
reply.append((!reply.isEmpty()) ? "\n" : "");
|
||||
reply.append("Email " + email[0].toString() + ".");
|
||||
}
|
||||
if (password[0].isString()) {
|
||||
reply.append((!reply.isEmpty()) ? "\n" : "");
|
||||
reply.append("Password " + password[0].toString() + ".");
|
||||
}
|
||||
if (!oculusError.isNull() && !oculusError.isUndefined()) {
|
||||
emit handleCreateFailed("Could not verify token with Oculus. Please try again.");
|
||||
return;
|
||||
} else {
|
||||
emit handleCreateFailed(reply);
|
||||
return;
|
||||
}
|
||||
}
|
||||
emit handleCreateFailed(reply->errorString());
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ extern const QUrl LOGIN_DIALOG;
|
|||
|
||||
class LoginDialog : public OffscreenQmlDialog {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isLogIn READ getIsLogIn WRITE setIsLogIn)
|
||||
HIFI_QML_DECL
|
||||
|
||||
public:
|
||||
|
@ -67,24 +66,23 @@ protected slots:
|
|||
Q_INVOKABLE void dismissLoginDialog();
|
||||
|
||||
Q_INVOKABLE bool isSteamRunning() const;
|
||||
Q_INVOKABLE bool isOculusStoreRunning() const;
|
||||
Q_INVOKABLE bool isOculusRunning() const;
|
||||
|
||||
Q_INVOKABLE QString oculusUserID() const;
|
||||
|
||||
Q_INVOKABLE void login(const QString& username, const QString& password) const;
|
||||
Q_INVOKABLE void loginThroughSteam();
|
||||
Q_INVOKABLE void linkSteam();
|
||||
Q_INVOKABLE void createAccountFromSteam(QString username = QString());
|
||||
Q_INVOKABLE void loginThroughOculus();
|
||||
Q_INVOKABLE void linkOculus();
|
||||
Q_INVOKABLE void createAccountFromOculus(QString email = QString(), QString username = QString(), QString password = QString());
|
||||
|
||||
Q_INVOKABLE void signup(const QString& email, const QString& username, const QString& password);
|
||||
|
||||
Q_INVOKABLE void openUrl(const QString& url) const;
|
||||
|
||||
Q_INVOKABLE bool getLoginDialogPoppedUp() const;
|
||||
|
||||
private:
|
||||
bool getIsLogIn() const { return _isLogIn; }
|
||||
void setIsLogIn(const bool isLogIn) { _isLogIn = isLogIn; }
|
||||
|
||||
bool _isLogIn{ false };
|
||||
};
|
||||
|
||||
#endif // hifi_LoginDialog_h
|
||||
|
|
|
@ -237,8 +237,17 @@ void AnimSkeleton::buildSkeletonFromJoints(const std::vector<HFMJoint>& joints,
|
|||
_relativeDefaultPoses = _absoluteDefaultPoses;
|
||||
convertAbsolutePosesToRelative(_relativeDefaultPoses);
|
||||
|
||||
// build _jointIndicesByName hash
|
||||
for (int i = 0; i < _jointsSize; i++) {
|
||||
_jointIndicesByName[_joints[i].name] = i;
|
||||
auto iter = _jointIndicesByName.find(_joints[i].name);
|
||||
if (iter != _jointIndicesByName.end()) {
|
||||
// prefer joints over meshes if there is a name collision.
|
||||
if (_joints[i].isSkeletonJoint && !_joints[iter.value()].isSkeletonJoint) {
|
||||
iter.value() = i;
|
||||
}
|
||||
} else {
|
||||
_jointIndicesByName.insert(_joints[i].name, i);
|
||||
}
|
||||
}
|
||||
|
||||
// build mirror map.
|
||||
|
|
|
@ -324,88 +324,79 @@ void Avatar::removeAvatarEntitiesFromTree() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Avatar::updateGrabs() {
|
||||
bool Avatar::applyGrabChanges() {
|
||||
if (!_avatarGrabDataChanged && _grabsToChange.empty() && _grabsToDelete.empty()) {
|
||||
// early exit for most common case: nothing to do
|
||||
return false;
|
||||
}
|
||||
|
||||
bool grabAddedOrRemoved = false;
|
||||
// update the Grabs according to any changes in _avatarGrabData
|
||||
_avatarGrabsLock.withWriteLock([&] {
|
||||
if (_avatarGrabDataChanged) {
|
||||
// collect changes in _avatarGrabData
|
||||
foreach (auto grabID, _avatarGrabData.keys()) {
|
||||
AvatarGrabMap::iterator grabItr = _avatarGrabs.find(grabID);
|
||||
if (grabItr == _avatarGrabs.end()) {
|
||||
MapOfGrabs::iterator itr = _avatarGrabs.find(grabID);
|
||||
if (itr == _avatarGrabs.end()) {
|
||||
GrabPointer grab = std::make_shared<Grab>();
|
||||
grab->fromByteArray(_avatarGrabData.value(grabID));
|
||||
_avatarGrabs[grabID] = grab;
|
||||
_changedAvatarGrabs.insert(grabID);
|
||||
_grabsToChange.insert(grabID);
|
||||
} else {
|
||||
GrabPointer grab = grabItr.value();
|
||||
bool changed = grab->fromByteArray(_avatarGrabData.value(grabID));
|
||||
bool changed = itr->second->fromByteArray(_avatarGrabData.value(grabID));
|
||||
if (changed) {
|
||||
_changedAvatarGrabs.insert(grabID);
|
||||
_grabsToChange.insert(grabID);
|
||||
}
|
||||
}
|
||||
}
|
||||
_avatarGrabDataChanged = false;
|
||||
}
|
||||
|
||||
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
auto entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||
EntityEditPacketSender* packetSender = treeRenderer ? treeRenderer->getPacketSender() : nullptr;
|
||||
auto sessionID = DependencyManager::get<NodeList>()->getSessionUUID();
|
||||
|
||||
QMutableSetIterator<QUuid> delItr(_deletedAvatarGrabs);
|
||||
while (delItr.hasNext()) {
|
||||
QUuid grabID = delItr.next();
|
||||
GrabPointer grab = _avatarGrabs[grabID];
|
||||
if (!grab) {
|
||||
delItr.remove();
|
||||
// delete _avatarGrabs
|
||||
VectorOfIDs undeleted;
|
||||
for (const auto& id : _grabsToDelete) {
|
||||
MapOfGrabs::iterator itr = _avatarGrabs.find(id);
|
||||
if (itr == _avatarGrabs.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool success;
|
||||
const GrabPointer& grab = itr->second;
|
||||
SpatiallyNestablePointer target = SpatiallyNestable::findByID(grab->getTargetID(), success);
|
||||
|
||||
// only clear this entry from the _deletedAvatarGrabs if we found the entity.
|
||||
if (success && target) {
|
||||
bool iShouldTellServer = target->getEditSenderID() == sessionID;
|
||||
|
||||
EntityItemPointer entity = std::dynamic_pointer_cast<EntityItem>(target);
|
||||
if (entity && entity->isAvatarEntity() && (entity->getOwningAvatarID() == sessionID ||
|
||||
entity->getOwningAvatarID() == AVATAR_SELF_ID)) {
|
||||
// this is our own avatar-entity, so we always tell the server about the release
|
||||
iShouldTellServer = true;
|
||||
}
|
||||
|
||||
target->removeGrab(grab);
|
||||
delItr.remove();
|
||||
// in case this is the last grab on an entity, we need to shrink the queryAACube and tell the server
|
||||
// about the final position.
|
||||
if (entityTree) {
|
||||
bool force = true;
|
||||
entityTree->withWriteLock([&] {
|
||||
entityTree->updateEntityQueryAACube(target, packetSender, force, iShouldTellServer);
|
||||
});
|
||||
}
|
||||
_avatarGrabs.erase(itr);
|
||||
grabAddedOrRemoved = true;
|
||||
} else {
|
||||
undeleted.push_back(id);
|
||||
}
|
||||
_avatarGrabs.remove(grabID);
|
||||
_changedAvatarGrabs.remove(grabID);
|
||||
}
|
||||
_grabsToDelete = std::move(undeleted);
|
||||
|
||||
QMutableSetIterator<QUuid> changeItr(_changedAvatarGrabs);
|
||||
while (changeItr.hasNext()) {
|
||||
QUuid grabID = changeItr.next();
|
||||
GrabPointer& grab = _avatarGrabs[grabID];
|
||||
// change _avatarGrabs and add Actions to target
|
||||
SetOfIDs unchanged;
|
||||
for (const auto& id : _grabsToChange) {
|
||||
MapOfGrabs::iterator itr = _avatarGrabs.find(id);
|
||||
if (itr == _avatarGrabs.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool success;
|
||||
const GrabPointer& grab = itr->second;
|
||||
SpatiallyNestablePointer target = SpatiallyNestable::findByID(grab->getTargetID(), success);
|
||||
|
||||
if (success && target) {
|
||||
target->addGrab(grab);
|
||||
// only clear this entry from the _changedAvatarGrabs if we found the entity.
|
||||
changeItr.remove();
|
||||
if (isMyAvatar()) {
|
||||
EntityItemPointer entity = std::dynamic_pointer_cast<EntityItem>(target);
|
||||
if (entity) {
|
||||
entity->upgradeScriptSimulationPriority(PERSONAL_SIMULATION_PRIORITY);
|
||||
}
|
||||
}
|
||||
grabAddedOrRemoved = true;
|
||||
} else {
|
||||
unchanged.insert(id);
|
||||
}
|
||||
}
|
||||
_grabsToChange = std::move(unchanged);
|
||||
});
|
||||
return grabAddedOrRemoved;
|
||||
}
|
||||
|
@ -413,8 +404,8 @@ bool Avatar::updateGrabs() {
|
|||
void Avatar::accumulateGrabPositions(std::map<QUuid, GrabLocationAccumulator>& grabAccumulators) {
|
||||
// relay avatar's joint position to grabbed target in a way that allows for averaging
|
||||
_avatarGrabsLock.withReadLock([&] {
|
||||
foreach (auto grabID, _avatarGrabs.keys()) {
|
||||
const GrabPointer& grab = _avatarGrabs.value(grabID);
|
||||
for (const auto& entry : _avatarGrabs) {
|
||||
const GrabPointer& grab = entry.second;
|
||||
|
||||
if (!grab || !grab->getActionID().isNull()) {
|
||||
continue; // the accumulated value isn't used, in this case.
|
||||
|
@ -432,6 +423,20 @@ void Avatar::accumulateGrabPositions(std::map<QUuid, GrabLocationAccumulator>& g
|
|||
});
|
||||
}
|
||||
|
||||
void Avatar::tearDownGrabs() {
|
||||
_avatarGrabsLock.withWriteLock([&] {
|
||||
for (const auto& entry : _avatarGrabs) {
|
||||
_grabsToDelete.push_back(entry.first);
|
||||
}
|
||||
_grabsToChange.clear();
|
||||
});
|
||||
applyGrabChanges();
|
||||
if (!_grabsToDelete.empty()) {
|
||||
// some grabs failed to delete, which is a possible "leak", so we log about it
|
||||
qWarning() << "Failed to tearDown" << _grabsToDelete.size() << "grabs for Avatar" << getID();
|
||||
}
|
||||
}
|
||||
|
||||
void Avatar::relayJointDataToChildren() {
|
||||
forEachChild([&](SpatiallyNestablePointer child) {
|
||||
if (child->getNestableType() == NestableType::Entity) {
|
||||
|
@ -1929,3 +1934,12 @@ scriptable::ScriptableModelBase Avatar::getScriptableModel() {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Avatar::clearAvatarGrabData(const QUuid& id) {
|
||||
AvatarData::clearAvatarGrabData(id);
|
||||
_avatarGrabsLock.withWriteLock([&] {
|
||||
if (_avatarGrabs.find(id) != _avatarGrabs.end()) {
|
||||
_grabsToDelete.push_back(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
#include <functional>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
|
@ -23,10 +26,12 @@
|
|||
#include <graphics-scripting/Forward.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include <Grab.h>
|
||||
#include <ThreadSafeValueCache.h>
|
||||
|
||||
#include "Head.h"
|
||||
#include "SkeletonModel.h"
|
||||
#include "Rig.h"
|
||||
#include <ThreadSafeValueCache.h>
|
||||
|
||||
#include "MetaModelPayload.h"
|
||||
|
||||
|
@ -436,6 +441,8 @@ public:
|
|||
|
||||
void accumulateGrabPositions(std::map<QUuid, GrabLocationAccumulator>& grabAccumulators);
|
||||
|
||||
void tearDownGrabs();
|
||||
|
||||
signals:
|
||||
void targetScaleChanged(float targetScale);
|
||||
|
||||
|
@ -538,7 +545,7 @@ protected:
|
|||
|
||||
// protected methods...
|
||||
bool isLookingAtMe(AvatarSharedPointer avatar) const;
|
||||
bool updateGrabs();
|
||||
bool applyGrabChanges();
|
||||
void relayJointDataToChildren();
|
||||
|
||||
void fade(render::Transaction& transaction, render::Transition::Type type);
|
||||
|
@ -625,8 +632,15 @@ protected:
|
|||
|
||||
static void metaBlendshapeOperator(render::ItemID renderItemID, int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets,
|
||||
const QVector<int>& blendedMeshSizes, const render::ItemIDs& subItemIDs);
|
||||
void clearAvatarGrabData(const QUuid& grabID) override;
|
||||
|
||||
AvatarGrabMap _avatarGrabs;
|
||||
using SetOfIDs = std::set<QUuid>;
|
||||
using VectorOfIDs = std::vector<QUuid>;
|
||||
using MapOfGrabs = std::map<QUuid, GrabPointer>;
|
||||
|
||||
MapOfGrabs _avatarGrabs;
|
||||
SetOfIDs _grabsToChange; // updated grab IDs -- changes needed to entities or physics
|
||||
VectorOfIDs _grabsToDelete; // deleted grab IDs -- changes needed to entities or physics
|
||||
};
|
||||
|
||||
#endif // hifi_Avatar_h
|
||||
|
|
20
libraries/avatars/src/AvatarData.cpp
Normal file → Executable file
20
libraries/avatars/src/AvatarData.cpp
Normal file → Executable file
|
@ -639,7 +639,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
|
||||
// compute maxTranslationDimension before we send any joint data.
|
||||
float maxTranslationDimension = 0.001f;
|
||||
for (int i = sendStatus.rotationsSent; i < numJoints; ++i) {
|
||||
for (int i = sendStatus.translationsSent; i < numJoints; ++i) {
|
||||
const JointData& data = jointData[i];
|
||||
if (!data.translationIsDefaultPose) {
|
||||
maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension);
|
||||
|
@ -1172,6 +1172,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
|
||||
sourceBuffer += sizeof(AvatarDataPacket::AdditionalFlags);
|
||||
|
||||
if (collideWithOtherAvatarsChanged) {
|
||||
setCollisionWithOtherAvatarsFlags();
|
||||
}
|
||||
if (somethingChanged) {
|
||||
_additionalFlagsChanged = now;
|
||||
}
|
||||
|
@ -2428,7 +2431,8 @@ static const QString JSON_AVATAR_VERSION = QStringLiteral("version");
|
|||
enum class JsonAvatarFrameVersion : int {
|
||||
JointRotationsInRelativeFrame = 0,
|
||||
JointRotationsInAbsoluteFrame,
|
||||
JointDefaultPoseBits
|
||||
JointDefaultPoseBits,
|
||||
JointUnscaledTranslations,
|
||||
};
|
||||
|
||||
QJsonValue toJsonValue(const JointData& joint) {
|
||||
|
@ -2445,7 +2449,16 @@ JointData jointDataFromJsonValue(int version, const QJsonValue& json) {
|
|||
if (json.isArray()) {
|
||||
QJsonArray array = json.toArray();
|
||||
result.rotation = quatFromJsonValue(array[0]);
|
||||
|
||||
result.translation = vec3FromJsonValue(array[1]);
|
||||
|
||||
// In old recordings, translations are scaled by _geometryOffset. Undo that scaling.
|
||||
if (version < (int)JsonAvatarFrameVersion::JointUnscaledTranslations) {
|
||||
// because we don't have access to the actual _geometryOffset used. we have to guess.
|
||||
// most avatar FBX files were authored in centimeters.
|
||||
const float METERS_TO_CENTIMETERS = 100.0f;
|
||||
result.translation *= METERS_TO_CENTIMETERS;
|
||||
}
|
||||
if (version >= (int)JsonAvatarFrameVersion::JointDefaultPoseBits) {
|
||||
result.rotationIsDefaultPose = array[2].toBool();
|
||||
result.translationIsDefaultPose = array[3].toBool();
|
||||
|
@ -2464,7 +2477,7 @@ void AvatarData::avatarEntityDataToJson(QJsonObject& root) const {
|
|||
QJsonObject AvatarData::toJson() const {
|
||||
QJsonObject root;
|
||||
|
||||
root[JSON_AVATAR_VERSION] = (int)JsonAvatarFrameVersion::JointDefaultPoseBits;
|
||||
root[JSON_AVATAR_VERSION] = (int)JsonAvatarFrameVersion::JointUnscaledTranslations;
|
||||
|
||||
if (!getSkeletonModelURL().isEmpty()) {
|
||||
root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString();
|
||||
|
@ -2997,7 +3010,6 @@ void AvatarData::clearAvatarGrabData(const QUuid& grabID) {
|
|||
_avatarGrabsLock.withWriteLock([&] {
|
||||
if (_avatarGrabData.remove(grabID)) {
|
||||
_avatarGrabDataChanged = true;
|
||||
_deletedAvatarGrabs.insert(grabID);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
9
libraries/avatars/src/AvatarData.h
Normal file → Executable file
9
libraries/avatars/src/AvatarData.h
Normal file → Executable file
|
@ -54,7 +54,6 @@
|
|||
#include "AvatarTraits.h"
|
||||
#include "HeadData.h"
|
||||
#include "PathUtils.h"
|
||||
#include "Grab.h"
|
||||
|
||||
#include <graphics/Material.h>
|
||||
|
||||
|
@ -67,8 +66,6 @@ using PackedAvatarEntityMap = QMap<QUuid, QByteArray>; // similar to AvatarEntit
|
|||
using AvatarEntityIDs = QSet<QUuid>;
|
||||
|
||||
using AvatarGrabDataMap = QMap<QUuid, QByteArray>;
|
||||
using AvatarGrabIDs = QSet<QUuid>;
|
||||
using AvatarGrabMap = QMap<QUuid, GrabPointer>;
|
||||
|
||||
using AvatarDataSequenceNumber = uint16_t;
|
||||
|
||||
|
@ -496,6 +493,8 @@ public:
|
|||
/// \return number of bytes parsed
|
||||
virtual int parseDataFromBuffer(const QByteArray& buffer);
|
||||
|
||||
virtual void setCollisionWithOtherAvatarsFlags() {};
|
||||
|
||||
// Body Rotation (degrees)
|
||||
float getBodyYaw() const;
|
||||
void setBodyYaw(float bodyYaw);
|
||||
|
@ -1473,8 +1472,6 @@ protected:
|
|||
mutable ReadWriteLockable _avatarGrabsLock;
|
||||
AvatarGrabDataMap _avatarGrabData;
|
||||
bool _avatarGrabDataChanged { false }; // by network
|
||||
AvatarGrabIDs _changedAvatarGrabs; // updated grab IDs -- changes needed to entities or physics
|
||||
AvatarGrabIDs _deletedAvatarGrabs; // deleted grab IDs -- changes needed to entities or physics
|
||||
|
||||
// used to transform any sensor into world space, including the _hmdSensorMat, or hand controllers.
|
||||
ThreadSafeValueCache<glm::mat4> _sensorToWorldMatrixCache { glm::mat4() };
|
||||
|
@ -1537,7 +1534,7 @@ protected:
|
|||
}
|
||||
|
||||
bool updateAvatarGrabData(const QUuid& grabID, const QByteArray& grabData);
|
||||
void clearAvatarGrabData(const QUuid& grabID);
|
||||
virtual void clearAvatarGrabData(const QUuid& grabID);
|
||||
|
||||
private:
|
||||
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
|
||||
namespace controller {
|
||||
|
||||
enum class HmdAvatarAlignmentType {
|
||||
Eyes = 0, // align the user's eyes with the avatars eyes
|
||||
Head // align the user's head with the avatars head
|
||||
};
|
||||
|
||||
struct InputCalibrationData {
|
||||
glm::mat4 sensorToWorldMat; // sensor to world
|
||||
glm::mat4 avatarMat; // avatar to world
|
||||
|
@ -29,6 +34,7 @@ struct InputCalibrationData {
|
|||
glm::mat4 defaultLeftArm; // default pose for leftArm joint in sensor space
|
||||
glm::mat4 defaultRightHand; // default pose for rightHand joint in sensor space
|
||||
glm::mat4 defaultLeftHand; // default pose for leftHand joint in sensor space
|
||||
HmdAvatarAlignmentType hmdAvatarAlignmentType;
|
||||
};
|
||||
|
||||
enum class ChannelType {
|
||||
|
|
|
@ -31,6 +31,8 @@ public:
|
|||
|
||||
virtual void compositeExtra() override;
|
||||
|
||||
virtual void pluginUpdate() override {};
|
||||
|
||||
protected:
|
||||
mutable bool _isThrottled = false;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ public:
|
|||
QImage getScreenshot(float aspectRatio = 0.0f) const override;
|
||||
QImage getSecondaryCameraScreenshot() const override;
|
||||
void copyTextureToQuickFramebuffer(NetworkTexturePointer source, QOpenGLFramebufferObject* target, GLsync* fenceSync) override {};
|
||||
void pluginUpdate() override {};
|
||||
private:
|
||||
static const QString NAME;
|
||||
};
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QImageWriter>
|
||||
#include <QtGui/QOpenGLFramebufferObject>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
|
@ -30,6 +32,7 @@
|
|||
#include <gl/OffscreenGLCanvas.h>
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
#include <gpu/FrameIO.h>
|
||||
#include <shaders/Shaders.h>
|
||||
#include <gpu/gl/GLShared.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
|
@ -465,11 +468,43 @@ void OpenGLDisplayPlugin::submitFrame(const gpu::FramePointer& newFrame) {
|
|||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor) {
|
||||
renderFromTexture(batch, texture, viewport, scissor, gpu::FramebufferPointer());
|
||||
void OpenGLDisplayPlugin::captureFrame(const std::string& filename) const {
|
||||
withOtherThreadContext([&] {
|
||||
using namespace gpu;
|
||||
auto glBackend = const_cast<OpenGLDisplayPlugin&>(*this).getGLBackend();
|
||||
FramebufferPointer framebuffer{ Framebuffer::create("captureFramebuffer") };
|
||||
TextureCapturer captureLambda = [&](const std::string& filename, const gpu::TexturePointer& texture, uint16 layer) {
|
||||
QImage image;
|
||||
if (texture->getUsageType() == TextureUsageType::STRICT_RESOURCE) {
|
||||
image = QImage{ 1, 1, QImage::Format_ARGB32 };
|
||||
auto storedImage = texture->accessStoredMipFace(0, 0);
|
||||
memcpy(image.bits(), storedImage->data(), image.sizeInBytes());
|
||||
//if (texture == textureCache->getWhiteTexture()) {
|
||||
//} else if (texture == textureCache->getBlackTexture()) {
|
||||
//} else if (texture == textureCache->getBlueTexture()) {
|
||||
//} else if (texture == textureCache->getGrayTexture()) {
|
||||
} else {
|
||||
ivec4 rect = { 0, 0, texture->getWidth(), texture->getHeight() };
|
||||
framebuffer->setRenderBuffer(0, texture, layer);
|
||||
glBackend->syncGPUObject(*framebuffer);
|
||||
|
||||
image = QImage{ rect.z, rect.w, QImage::Format_ARGB32 };
|
||||
glBackend->downloadFramebuffer(framebuffer, rect, image);
|
||||
}
|
||||
QImageWriter(filename.c_str()).write(image);
|
||||
};
|
||||
|
||||
if (_currentFrame) {
|
||||
gpu::writeFrame(filename, _currentFrame, captureLambda);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor, gpu::FramebufferPointer copyFbo /*=gpu::FramebufferPointer()*/) {
|
||||
void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer& texture, const glm::ivec4& viewport, const glm::ivec4& scissor) {
|
||||
renderFromTexture(batch, texture, viewport, scissor, nullptr);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer& texture, const glm::ivec4& viewport, const glm::ivec4& scissor, const gpu::FramebufferPointer& copyFbo /*=gpu::FramebufferPointer()*/) {
|
||||
auto fbo = gpu::FramebufferPointer();
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
void endSession() override final;
|
||||
bool eventFilter(QObject* receiver, QEvent* event) override;
|
||||
bool isDisplayVisible() const override { return true; }
|
||||
|
||||
void captureFrame(const std::string& outputName) const override;
|
||||
void submitFrame(const gpu::FramePointer& newFrame) override;
|
||||
|
||||
glm::uvec2 getRecommendedRenderSize() const override {
|
||||
|
@ -113,8 +113,8 @@ protected:
|
|||
// Plugin specific functionality to send the composed scene to the output window or device
|
||||
virtual void internalPresent();
|
||||
|
||||
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor, gpu::FramebufferPointer fbo);
|
||||
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor);
|
||||
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer& texture, const glm::ivec4& viewport, const glm::ivec4& scissor, const gpu::FramebufferPointer& fbo);
|
||||
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer& texture, const glm::ivec4& viewport, const glm::ivec4& scissor);
|
||||
virtual void updateFrameData();
|
||||
virtual glm::mat4 getViewCorrection() { return glm::mat4(); }
|
||||
|
||||
|
|
|
@ -69,7 +69,10 @@ bool DebugHmdDisplayPlugin::internalActivate() {
|
|||
_eyeInverseProjections[1] = glm::inverse(_eyeProjections[1]);
|
||||
_eyeOffsets[0][3] = vec4{ -0.0327499993, 0.0, -0.0149999997, 1.0 };
|
||||
_eyeOffsets[1][3] = vec4{ 0.0327499993, 0.0, -0.0149999997, 1.0 };
|
||||
_renderTargetSize = { 3024, 1680 };
|
||||
// Test HMD per-eye resolution
|
||||
_renderTargetSize = uvec2{ 1214 * 2 , 1344 };
|
||||
// uncomment to capture a quarter size frame
|
||||
//_renderTargetSize /= 2;
|
||||
_cullingProjection = _eyeProjections[0];
|
||||
// This must come after the initialization, so that the values calculated
|
||||
// above are available during the customizeContext call (when not running
|
||||
|
|
|
@ -46,6 +46,8 @@ public:
|
|||
|
||||
virtual bool onDisplayTextureReset() override { _clearPreviewFlag = true; return true; };
|
||||
|
||||
void pluginUpdate() override {};
|
||||
|
||||
signals:
|
||||
void hmdMountedChanged();
|
||||
void hmdVisibleChanged(bool visible);
|
||||
|
|
|
@ -28,6 +28,8 @@ public:
|
|||
// to the HMD plugins.
|
||||
//virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
|
||||
|
||||
virtual void pluginUpdate() override {};
|
||||
|
||||
protected:
|
||||
virtual bool internalActivate() override;
|
||||
virtual void internalDeactivate() override;
|
||||
|
|
|
@ -141,7 +141,7 @@ std::shared_ptr<T> make_renderer(const EntityItemPointer& entity) {
|
|||
return std::shared_ptr<T>(new T(entity), [](T* ptr) { ptr->deleteLater(); });
|
||||
}
|
||||
|
||||
EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _entity(entity), _created(entity->getCreated()) {
|
||||
EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _created(entity->getCreated()), _entity(entity) {
|
||||
connect(entity.get(), &EntityItem::requestRenderUpdate, this, [&] {
|
||||
_needsRenderUpdate = true;
|
||||
emit requestRenderUpdate();
|
||||
|
@ -479,7 +479,7 @@ glm::vec4 EntityRenderer::calculatePulseColor(const glm::vec4& color, const Puls
|
|||
}
|
||||
|
||||
float t = ((float)(usecTimestampNow() - start)) / ((float)USECS_PER_SECOND);
|
||||
float pulse = 0.5f * (glm::cos(t * (2.0f * M_PI) / pulseProperties.getPeriod()) + 1.0f) * (pulseProperties.getMax() - pulseProperties.getMin()) + pulseProperties.getMin();
|
||||
float pulse = 0.5f * (cosf(t * (2.0f * (float)M_PI) / pulseProperties.getPeriod()) + 1.0f) * (pulseProperties.getMax() - pulseProperties.getMin()) + pulseProperties.getMin();
|
||||
float outPulse = (1.0f - pulse);
|
||||
|
||||
glm::vec4 result = color;
|
||||
|
|
|
@ -286,4 +286,4 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,10 +42,23 @@ ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Pare
|
|||
// TODO: move into Procedural.cpp
|
||||
PrepareStencil::testMaskDrawShape(*_procedural._opaqueState);
|
||||
PrepareStencil::testMask(*_procedural._transparentState);
|
||||
|
||||
addMaterial(graphics::MaterialLayer(_material, 0), "0");
|
||||
}
|
||||
|
||||
bool ShapeEntityRenderer::needsRenderUpdate() const {
|
||||
if (_procedural.isEnabled() && _procedural.isFading()) {
|
||||
if (resultWithReadLock<bool>([&] {
|
||||
if (_procedural.isEnabled() && _procedural.isFading()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.needsUpdate()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -56,7 +69,11 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
if (_lastUserData != entity->getUserData()) {
|
||||
return true;
|
||||
}
|
||||
if (_material != entity->getMaterial()) {
|
||||
|
||||
if (_color != entity->getColor()) {
|
||||
return true;
|
||||
}
|
||||
if (_alpha != entity->getAlpha()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -83,10 +100,6 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
_procedural.setProceduralData(ProceduralData::parse(_lastUserData));
|
||||
}
|
||||
|
||||
removeMaterial(_material, "0");
|
||||
_material = entity->getMaterial();
|
||||
addMaterial(graphics::MaterialLayer(_material, 0), "0");
|
||||
|
||||
_shape = entity->getShape();
|
||||
_pulseProperties = entity->getPulseProperties();
|
||||
});
|
||||
|
@ -116,6 +129,20 @@ void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
_procedural.setIsFading(isFading);
|
||||
}
|
||||
});
|
||||
|
||||
glm::u8vec3 color = entity->getColor();
|
||||
float alpha = entity->getAlpha();
|
||||
if (_color != color || _alpha != alpha) {
|
||||
_color = color;
|
||||
_alpha = alpha;
|
||||
_material->setAlbedo(toGlm(_color));
|
||||
_material->setOpacity(_alpha);
|
||||
|
||||
auto materials = _materials.find("0");
|
||||
if (materials != _materials.end()) {
|
||||
materials->second.setNeedsUpdate(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ShapeEntityRenderer::isTransparent() const {
|
||||
|
@ -129,18 +156,15 @@ bool ShapeEntityRenderer::isTransparent() const {
|
|||
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end()) {
|
||||
if (mat->second.top().material) {
|
||||
auto matKey = mat->second.top().material->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
return true;
|
||||
}
|
||||
if (mat->second.getMaterialKey().isTranslucent()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Parent::isTransparent();
|
||||
}
|
||||
|
||||
bool ShapeEntityRenderer::useMaterialPipeline() const {
|
||||
bool ShapeEntityRenderer::useMaterialPipeline(const graphics::MultiMaterial& materials) const {
|
||||
bool proceduralReady = resultWithReadLock<bool>([&] {
|
||||
return _procedural.isReady();
|
||||
});
|
||||
|
@ -148,12 +172,7 @@ bool ShapeEntityRenderer::useMaterialPipeline() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.top().material) {
|
||||
drawMaterialKey = mat->second.top().material->getKey();
|
||||
}
|
||||
|
||||
graphics::MaterialKey drawMaterialKey = materials.getMaterialKey();
|
||||
if (drawMaterialKey.isEmissive() || drawMaterialKey.isUnlit() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -168,11 +187,13 @@ bool ShapeEntityRenderer::useMaterialPipeline() const {
|
|||
}
|
||||
|
||||
ShapeKey ShapeEntityRenderer::getShapeKey() {
|
||||
if (useMaterialPipeline()) {
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
if (_materials["0"].top().material) {
|
||||
drawMaterialKey = _materials["0"].top().material->getKey();
|
||||
}
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.needsUpdate()) {
|
||||
RenderPipelines::updateMultiMaterial(mat->second);
|
||||
}
|
||||
|
||||
if (mat != _materials.end() && useMaterialPipeline(mat->second)) {
|
||||
graphics::MaterialKey drawMaterialKey = mat->second.getMaterialKey();
|
||||
|
||||
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||
bool hasTangents = drawMaterialKey.isNormalMap();
|
||||
|
@ -225,7 +246,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
std::shared_ptr<graphics::Material> mat;
|
||||
graphics::MultiMaterial materials;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
GeometryCache::Shape geometryShape;
|
||||
bool proceduralRender = false;
|
||||
|
@ -233,30 +254,25 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
withReadLock([&] {
|
||||
geometryShape = geometryCache->getShapeForEntityShape(_shape);
|
||||
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
|
||||
mat = _materials["0"].top().material;
|
||||
if (mat) {
|
||||
outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity());
|
||||
outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
|
||||
if (_procedural.isReady()) {
|
||||
outColor = _procedural.getColor(outColor);
|
||||
outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f;
|
||||
_procedural.prepare(batch, _position, _dimensions, _orientation, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
proceduralRender = true;
|
||||
}
|
||||
materials = _materials["0"];
|
||||
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||
outColor = glm::vec4(schema._albedo, schema._opacity);
|
||||
outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
|
||||
if (_procedural.isReady()) {
|
||||
outColor = _procedural.getColor(outColor);
|
||||
outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f;
|
||||
_procedural.prepare(batch, _position, _dimensions, _orientation, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
proceduralRender = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!mat) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (proceduralRender) {
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
|
||||
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
||||
} else {
|
||||
geometryCache->renderShape(batch, geometryShape, outColor);
|
||||
}
|
||||
} else if (!useMaterialPipeline()) {
|
||||
} else if (!useMaterialPipeline(materials)) {
|
||||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
render::ShapePipelinePointer pipeline;
|
||||
|
@ -272,7 +288,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
}
|
||||
} else {
|
||||
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
|
||||
RenderPipelines::bindMaterial(mat, batch, args->_enableTexturing);
|
||||
RenderPipelines::bindMaterials(materials, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
|
@ -291,8 +307,9 @@ scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel() {
|
|||
{
|
||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||
result.appendMaterials(_materials);
|
||||
if (_materials["0"].top().material) {
|
||||
vertexColor = _materials["0"].top().material->getAlbedo();
|
||||
auto materials = _materials.find("0");
|
||||
if (materials != _materials.end()) {
|
||||
vertexColor = materials->second.getSchemaBuffer().get<graphics::MultiMaterial::Schema>()._albedo;
|
||||
}
|
||||
}
|
||||
if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) {
|
||||
|
|
|
@ -35,13 +35,17 @@ private:
|
|||
virtual void doRender(RenderArgs* args) override;
|
||||
virtual bool isTransparent() const override;
|
||||
|
||||
bool useMaterialPipeline() const;
|
||||
bool useMaterialPipeline(const graphics::MultiMaterial& materials) const;
|
||||
|
||||
Procedural _procedural;
|
||||
QString _lastUserData;
|
||||
entity::Shape _shape { entity::Sphere };
|
||||
|
||||
PulsePropertyGroup _pulseProperties;
|
||||
std::shared_ptr<graphics::Material> _material;
|
||||
std::shared_ptr<graphics::Material> _material { std::make_shared<graphics::Material>() };
|
||||
glm::u8vec3 _color;
|
||||
float _alpha;
|
||||
|
||||
glm::vec3 _position;
|
||||
glm::vec3 _dimensions;
|
||||
glm::quat _orientation;
|
||||
|
|
|
@ -3425,7 +3425,19 @@ void EntityItem::addGrab(GrabPointer grab) {
|
|||
enableNoBootstrap();
|
||||
SpatiallyNestable::addGrab(grab);
|
||||
|
||||
if (getDynamic() && getParentID().isNull()) {
|
||||
if (!getParentID().isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int jointIndex = grab->getParentJointIndex();
|
||||
bool isFarGrab = jointIndex == FARGRAB_RIGHTHAND_INDEX
|
||||
|| jointIndex == FARGRAB_LEFTHAND_INDEX
|
||||
|| jointIndex == FARGRAB_MOUSE_INDEX;
|
||||
|
||||
// GRAB HACK: FarGrab doesn't work on non-dynamic things yet, but we really really want NearGrab
|
||||
// (aka Hold) to work for such ojects, hence we filter the useAction case like so:
|
||||
bool useAction = getDynamic() || (_physicsInfo && !isFarGrab);
|
||||
if (useAction) {
|
||||
EntityTreePointer entityTree = getTree();
|
||||
assert(entityTree);
|
||||
EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr;
|
||||
|
@ -3436,13 +3448,11 @@ void EntityItem::addGrab(GrabPointer grab) {
|
|||
|
||||
EntityDynamicType dynamicType;
|
||||
QVariantMap arguments;
|
||||
int grabParentJointIndex =grab->getParentJointIndex();
|
||||
if (grabParentJointIndex == FARGRAB_RIGHTHAND_INDEX || grabParentJointIndex == FARGRAB_LEFTHAND_INDEX ||
|
||||
grabParentJointIndex == FARGRAB_MOUSE_INDEX) {
|
||||
if (isFarGrab) {
|
||||
// add a far-grab action
|
||||
dynamicType = DYNAMIC_TYPE_FAR_GRAB;
|
||||
arguments["otherID"] = grab->getOwnerID();
|
||||
arguments["otherJointIndex"] = grabParentJointIndex;
|
||||
arguments["otherJointIndex"] = jointIndex;
|
||||
arguments["targetPosition"] = vec3ToQMap(grab->getPositionalOffset());
|
||||
arguments["targetRotation"] = quatToQMap(grab->getRotationalOffset());
|
||||
arguments["linearTimeScale"] = 0.05;
|
||||
|
@ -3463,11 +3473,23 @@ void EntityItem::addGrab(GrabPointer grab) {
|
|||
grab->setActionID(actionID);
|
||||
_grabActions[actionID] = action;
|
||||
simulation->addDynamic(action);
|
||||
markDirtyFlags(Simulation::DIRTY_MOTION_TYPE);
|
||||
simulation->changeEntity(getThisPointer());
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::removeGrab(GrabPointer grab) {
|
||||
int oldNumGrabs = _grabs.size();
|
||||
SpatiallyNestable::removeGrab(grab);
|
||||
if (!getDynamic() && _grabs.size() != oldNumGrabs) {
|
||||
// GRAB HACK: the expected behavior is for non-dynamic grabbed things to NOT be throwable
|
||||
// so we slam the velocities to zero here whenever the number of grabs change.
|
||||
// NOTE: if there is still another grab in effect this shouldn't interfere with the object's motion
|
||||
// because that grab will slam the position+velocities next frame.
|
||||
setLocalVelocity(glm::vec3(0.0f));
|
||||
setAngularVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
markDirtyFlags(Simulation::DIRTY_MOTION_TYPE);
|
||||
|
||||
QUuid actionID = grab->getActionID();
|
||||
if (!actionID.isNull()) {
|
||||
|
|
|
@ -1023,7 +1023,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* parse the JSON string into a JavaScript object of name, URL pairs. <em>Read-only.</em>
|
||||
*
|
||||
* @property {ShapeType} shapeType="none" - The shape of the collision hull used if collisions are enabled.
|
||||
* @property {string} compoundShapeURL="" - The OBJ file to use for the compound shape if <code>shapeType</code> is
|
||||
* @property {string} compoundShapeURL="" - The model file to use for the compound shape if <code>shapeType</code> is
|
||||
* <code>"compound"</code>.
|
||||
*
|
||||
* @property {Entities.AnimationProperties} animation - An animation to play on the model.
|
||||
|
@ -1373,7 +1373,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {ShapeType} shapeType="box" - The shape of the volume in which the zone's lighting effects and avatar
|
||||
* permissions have effect. Reverts to the default value if set to <code>"none"</code>, or set to <code>"compound"</code>
|
||||
* and <code>compoundShapeURL</code> is <code>""</code>.
|
||||
* @property {string} compoundShapeURL="" - The OBJ file to use for the compound shape if <code>shapeType</code> is
|
||||
* @property {string} compoundShapeURL="" - The model file to use for the compound shape if <code>shapeType</code> is
|
||||
* <code>"compound"</code>.
|
||||
*
|
||||
* @property {string} keyLightMode="inherit" - Configures the key light in the zone. Possible values:<br />
|
||||
|
|
|
@ -112,7 +112,6 @@ EntityItemPointer ShapeEntityItem::sphereFactory(const EntityItemID& entityID, c
|
|||
ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
|
||||
_type = EntityTypes::Shape;
|
||||
_volumeMultiplier *= PI / 6.0f;
|
||||
_material = std::make_shared<graphics::Material>();
|
||||
}
|
||||
|
||||
EntityItemProperties ShapeEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
|
||||
|
@ -234,7 +233,6 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
void ShapeEntityItem::setColor(const glm::u8vec3& value) {
|
||||
withWriteLock([&] {
|
||||
_color = value;
|
||||
_material->setAlbedo(toGlm(_color));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -247,7 +245,6 @@ glm::u8vec3 ShapeEntityItem::getColor() const {
|
|||
void ShapeEntityItem::setAlpha(float alpha) {
|
||||
withWriteLock([&] {
|
||||
_alpha = alpha;
|
||||
_material->setOpacity(alpha);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -101,8 +101,6 @@ public:
|
|||
virtual void computeShapeInfo(ShapeInfo& info) override;
|
||||
virtual ShapeType getShapeType() const override;
|
||||
|
||||
std::shared_ptr<graphics::Material> getMaterial() { return _material; }
|
||||
|
||||
PulsePropertyGroup getPulseProperties() const;
|
||||
|
||||
protected:
|
||||
|
@ -115,8 +113,6 @@ protected:
|
|||
//! prior functionality where new or unsupported shapes are treated as
|
||||
//! ellipsoids.
|
||||
ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID };
|
||||
|
||||
std::shared_ptr<graphics::Material> _material;
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeEntityItem_h
|
||||
|
|
|
@ -96,11 +96,11 @@ const uint8_t RECRUIT_SIMULATION_PRIORITY = VOLUNTEER_SIMULATION_PRIORITY + 1;
|
|||
// When poking objects with scripts an observer will bid at SCRIPT_EDIT priority.
|
||||
const uint8_t SCRIPT_GRAB_SIMULATION_PRIORITY = 128;
|
||||
const uint8_t SCRIPT_POKE_SIMULATION_PRIORITY = SCRIPT_GRAB_SIMULATION_PRIORITY - 1;
|
||||
const uint8_t AVATAR_ENTITY_SIMULATION_PRIORITY = 255;
|
||||
|
||||
// PERSONAL priority (needs a better name) is the level at which a simulation observer owns its own avatar
|
||||
// which really just means: things that collide with it will be bid at a priority level one lower
|
||||
const uint8_t PERSONAL_SIMULATION_PRIORITY = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
||||
const uint8_t AVATAR_ENTITY_SIMULATION_PRIORITY = PERSONAL_SIMULATION_PRIORITY;
|
||||
|
||||
|
||||
class SimulationOwner {
|
||||
|
|
|
@ -131,6 +131,7 @@ public:
|
|||
glm::vec3 geometricTranslation;
|
||||
glm::quat geometricRotation;
|
||||
glm::vec3 geometricScaling;
|
||||
bool isLimbNode; // is this FBXModel transform is a "LimbNode" i.e. a joint
|
||||
};
|
||||
|
||||
glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParentMap,
|
||||
|
@ -559,9 +560,11 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
glm::vec3 geometricRotation;
|
||||
|
||||
glm::vec3 rotationMin, rotationMax;
|
||||
|
||||
bool isLimbNode = object.properties.size() >= 3 && object.properties.at(2) == "LimbNode";
|
||||
FBXModel fbxModel = { name, -1, glm::vec3(), glm::mat4(), glm::quat(), glm::quat(), glm::quat(),
|
||||
glm::mat4(), glm::vec3(), glm::vec3(),
|
||||
false, glm::vec3(), glm::quat(), glm::vec3(1.0f) };
|
||||
glm::mat4(), glm::vec3(), glm::vec3(),
|
||||
false, glm::vec3(), glm::quat(), glm::vec3(1.0f), isLimbNode };
|
||||
ExtractedMesh* mesh = NULL;
|
||||
QVector<ExtractedBlendshape> blendshapes;
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
|
@ -752,17 +755,17 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
} else if (subobject.name == "Texture_Alpha_Source" && subobject.properties.length() >= TEXTURE_ALPHA_SOURCE_MIN_SIZE) {
|
||||
tex.assign<uint8_t>(tex.alphaSource, subobject.properties.at(0).value<int>());
|
||||
} else if (subobject.name == "ModelUVTranslation" && subobject.properties.length() >= MODEL_UV_TRANSLATION_MIN_SIZE) {
|
||||
tex.assign(tex.UVTranslation, glm::vec2(subobject.properties.at(0).value<double>(),
|
||||
subobject.properties.at(1).value<double>()));
|
||||
auto newTranslation = glm::vec3(subobject.properties.at(0).value<double>(), subobject.properties.at(1).value<double>(), 0.0);
|
||||
tex.assign(tex.translation, tex.translation + newTranslation);
|
||||
} else if (subobject.name == "ModelUVScaling" && subobject.properties.length() >= MODEL_UV_SCALING_MIN_SIZE) {
|
||||
tex.assign(tex.UVScaling, glm::vec2(subobject.properties.at(0).value<double>(),
|
||||
subobject.properties.at(1).value<double>()));
|
||||
if (tex.UVScaling.x == 0.0f) {
|
||||
tex.UVScaling.x = 1.0f;
|
||||
auto newScaling = glm::vec3(subobject.properties.at(0).value<double>(), subobject.properties.at(1).value<double>(), 1.0);
|
||||
if (newScaling.x == 0.0f) {
|
||||
newScaling.x = 1.0f;
|
||||
}
|
||||
if (tex.UVScaling.y == 0.0f) {
|
||||
tex.UVScaling.y = 1.0f;
|
||||
if (newScaling.y == 0.0f) {
|
||||
newScaling.y = 1.0f;
|
||||
}
|
||||
tex.assign(tex.scaling, tex.scaling * newScaling);
|
||||
} else if (subobject.name == "Cropping" && subobject.properties.length() >= CROPPING_MIN_SIZE) {
|
||||
tex.assign(tex.cropping, glm::vec4(subobject.properties.at(0).value<int>(),
|
||||
subobject.properties.at(1).value<int>(),
|
||||
|
@ -790,20 +793,21 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
} else if (property.properties.at(0) == USE_MATERIAL) {
|
||||
tex.assign<bool>(tex.useMaterial, property.properties.at(index).value<int>());
|
||||
} else if (property.properties.at(0) == TRANSLATION) {
|
||||
tex.assign(tex.translation, getVec3(property.properties, index));
|
||||
tex.assign(tex.translation, tex.translation + getVec3(property.properties, index));
|
||||
} else if (property.properties.at(0) == ROTATION) {
|
||||
tex.assign(tex.rotation, getVec3(property.properties, index));
|
||||
} else if (property.properties.at(0) == SCALING) {
|
||||
tex.assign(tex.scaling, getVec3(property.properties, index));
|
||||
if (tex.scaling.x == 0.0f) {
|
||||
tex.scaling.x = 1.0f;
|
||||
auto newScaling = getVec3(property.properties, index);
|
||||
if (newScaling.x == 0.0f) {
|
||||
newScaling.x = 1.0f;
|
||||
}
|
||||
if (tex.scaling.y == 0.0f) {
|
||||
tex.scaling.y = 1.0f;
|
||||
if (newScaling.y == 0.0f) {
|
||||
newScaling.y = 1.0f;
|
||||
}
|
||||
if (tex.scaling.z == 0.0f) {
|
||||
tex.scaling.z = 1.0f;
|
||||
if (newScaling.z == 0.0f) {
|
||||
newScaling.z = 1.0f;
|
||||
}
|
||||
tex.assign(tex.scaling, tex.scaling * newScaling);
|
||||
}
|
||||
#if defined(DEBUG_FBXSERIALIZER)
|
||||
else {
|
||||
|
@ -848,6 +852,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
}
|
||||
} else if (object.name == "Material") {
|
||||
HFMMaterial material;
|
||||
MaterialParam materialParam;
|
||||
material.name = (object.properties.at(1).toString());
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
bool properties = false;
|
||||
|
@ -892,6 +897,10 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
static const QVariant MAYA_EMISSIVE_INTENSITY = QByteArray("Maya|emissive_intensity");
|
||||
static const QVariant MAYA_USE_EMISSIVE_MAP = QByteArray("Maya|use_emissive_map");
|
||||
static const QVariant MAYA_USE_AO_MAP = QByteArray("Maya|use_ao_map");
|
||||
static const QVariant MAYA_UV_SCALE = QByteArray("Maya|uv_scale");
|
||||
static const QVariant MAYA_UV_OFFSET = QByteArray("Maya|uv_offset");
|
||||
static const int MAYA_UV_OFFSET_PROPERTY_LENGTH = 6;
|
||||
static const int MAYA_UV_SCALE_PROPERTY_LENGTH = 6;
|
||||
|
||||
|
||||
|
||||
|
@ -980,6 +989,27 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
material.isPBSMaterial = true;
|
||||
material.useOcclusionMap = (bool)property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == MAYA_UV_SCALE) {
|
||||
if (property.properties.size() == MAYA_UV_SCALE_PROPERTY_LENGTH) {
|
||||
// properties: { "Maya|uv_scale", "Vector2D", "Vector2", nothing, double, double }
|
||||
glm::vec3 scale = glm::vec3(property.properties.at(4).value<double>(), property.properties.at(5).value<double>(), 1.0);
|
||||
if (scale.x == 0.0f) {
|
||||
scale.x = 1.0f;
|
||||
}
|
||||
if (scale.y == 0.0f) {
|
||||
scale.y = 1.0f;
|
||||
}
|
||||
if (scale.z == 0.0f) {
|
||||
scale.z = 1.0f;
|
||||
}
|
||||
materialParam.scaling *= scale;
|
||||
}
|
||||
} else if (property.properties.at(0) == MAYA_UV_OFFSET) {
|
||||
if (property.properties.size() == MAYA_UV_OFFSET_PROPERTY_LENGTH) {
|
||||
// properties: { "Maya|uv_offset", "Vector2D", "Vector2", nothing, double, double }
|
||||
glm::vec3 translation = glm::vec3(property.properties.at(4).value<double>(), property.properties.at(5).value<double>(), 1.0);
|
||||
materialParam.translation += translation;
|
||||
}
|
||||
} else {
|
||||
const QString propname = property.properties.at(0).toString();
|
||||
unknowns.push_back(propname.toStdString());
|
||||
|
@ -1001,6 +1031,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
}
|
||||
material.materialID = getID(object.properties);
|
||||
_hfmMaterials.insert(material.materialID, material);
|
||||
_materialParams.insert(material.materialID, materialParam);
|
||||
|
||||
|
||||
} else if (object.name == "NodeAttribute") {
|
||||
|
@ -1258,6 +1289,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
// convert the models to joints
|
||||
QVariantList freeJoints = mapping.values("freeJoint");
|
||||
hfmModel.hasSkeletonJoints = false;
|
||||
|
||||
foreach (const QString& modelID, modelIDs) {
|
||||
const FBXModel& fbxModel = fbxModels[modelID];
|
||||
HFMJoint joint;
|
||||
|
@ -1288,6 +1320,8 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
joint.geometricTranslation = fbxModel.geometricTranslation;
|
||||
joint.geometricRotation = fbxModel.geometricRotation;
|
||||
joint.geometricScaling = fbxModel.geometricScaling;
|
||||
joint.isSkeletonJoint = fbxModel.isLimbNode;
|
||||
hfmModel.hasSkeletonJoints = (hfmModel.hasSkeletonJoints || joint.isSkeletonJoint);
|
||||
|
||||
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
|
||||
|
||||
|
@ -1311,14 +1345,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
joint.name = hfmModel.hfmToHifiJointNameMapping.key(fbxModel.name);
|
||||
}
|
||||
|
||||
foreach (const QString& childID, _connectionChildMap.values(modelID)) {
|
||||
QString type = typeFlags.value(childID);
|
||||
if (!type.isEmpty()) {
|
||||
hfmModel.hasSkeletonJoints |= (joint.isSkeletonJoint = type.toLower().contains("Skeleton"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
joint.bindTransformFoundInCluster = false;
|
||||
|
||||
hfmModel.joints.append(joint);
|
||||
|
@ -1439,7 +1465,9 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
materialIndex++;
|
||||
|
||||
} else if (_textureFilenames.contains(childID)) {
|
||||
HFMTexture texture = getTexture(childID);
|
||||
// NOTE (Sabrina 2019/01/11): getTextures now takes in the materialID as a second parameter, because FBX material nodes can sometimes have uv transform information (ex: "Maya|uv_scale")
|
||||
// I'm leaving the second parameter blank right now as this code may never be used.
|
||||
HFMTexture texture = getTexture(childID, "");
|
||||
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
|
||||
int partTexture = extracted.partMaterialTextures.at(j).second;
|
||||
if (partTexture == textureIndex && !(partTexture == 0 && materialsHaveTextures)) {
|
||||
|
@ -1452,9 +1480,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
|||
}
|
||||
}
|
||||
|
||||
extracted.mesh.createMeshTangents(generateTangents);
|
||||
extracted.mesh.createBlendShapeTangents(generateTangents);
|
||||
|
||||
// find the clusters with which the mesh is associated
|
||||
QVector<QString> clusterIDs;
|
||||
foreach (const QString& childID, _connectionChildMap.values(it.key())) {
|
||||
|
|
|
@ -37,8 +37,6 @@ class FBXNode;
|
|||
|
||||
class TextureParam {
|
||||
public:
|
||||
glm::vec2 UVTranslation;
|
||||
glm::vec2 UVScaling;
|
||||
glm::vec4 cropping;
|
||||
QString UVSet;
|
||||
|
||||
|
@ -63,8 +61,6 @@ public:
|
|||
bool isDefault;
|
||||
|
||||
TextureParam() :
|
||||
UVTranslation(0.0f),
|
||||
UVScaling(1.0f),
|
||||
cropping(0.0f),
|
||||
UVSet("map1"),
|
||||
translation(0.0f),
|
||||
|
@ -77,8 +73,6 @@ public:
|
|||
{}
|
||||
|
||||
TextureParam(const TextureParam& src) :
|
||||
UVTranslation(src.UVTranslation),
|
||||
UVScaling(src.UVScaling),
|
||||
cropping(src.cropping),
|
||||
UVSet(src.UVSet),
|
||||
translation(src.translation),
|
||||
|
@ -92,6 +86,22 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class MaterialParam {
|
||||
public:
|
||||
glm::vec3 translation;
|
||||
glm::vec3 scaling;
|
||||
|
||||
MaterialParam() :
|
||||
translation(0.0),
|
||||
scaling(1.0)
|
||||
{}
|
||||
|
||||
MaterialParam(const MaterialParam& src) :
|
||||
translation(src.translation),
|
||||
scaling(src.scaling)
|
||||
{}
|
||||
};
|
||||
|
||||
class ExtractedMesh;
|
||||
|
||||
class FBXSerializer : public HFMSerializer {
|
||||
|
@ -114,7 +124,7 @@ public:
|
|||
static ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex, bool deduplicate = true);
|
||||
QHash<QString, ExtractedMesh> meshes;
|
||||
|
||||
HFMTexture getTexture(const QString& textureID);
|
||||
HFMTexture getTexture(const QString& textureID, const QString& materialID);
|
||||
|
||||
QHash<QString, QString> _textureNames;
|
||||
// Hashes the original RelativeFilename of textures
|
||||
|
@ -141,6 +151,7 @@ public:
|
|||
QHash<QString, QString> occlusionTextures;
|
||||
|
||||
QHash<QString, HFMMaterial> _hfmMaterials;
|
||||
QHash<QString, MaterialParam> _materialParams;
|
||||
|
||||
void consolidateHFMMaterials(const QVariantHash& mapping);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include <hfm/ModelFormatLogging.h>
|
||||
|
||||
HFMTexture FBXSerializer::getTexture(const QString& textureID) {
|
||||
HFMTexture FBXSerializer::getTexture(const QString& textureID, const QString& materialID) {
|
||||
HFMTexture texture;
|
||||
const QByteArray& filepath = _textureFilepaths.value(textureID);
|
||||
texture.content = _textureContent.value(filepath);
|
||||
|
@ -45,8 +45,8 @@ HFMTexture FBXSerializer::getTexture(const QString& textureID) {
|
|||
if (_textureParams.contains(textureID)) {
|
||||
auto p = _textureParams.value(textureID);
|
||||
|
||||
texture.transform.setTranslation(p.translation);
|
||||
texture.transform.setRotation(glm::quat(glm::radians(p.rotation)));
|
||||
texture.transform.postTranslate(p.translation);
|
||||
texture.transform.postRotate(glm::quat(glm::radians(p.rotation)));
|
||||
|
||||
auto scaling = p.scaling;
|
||||
// Protect from bad scaling which should never happen
|
||||
|
@ -59,13 +59,19 @@ HFMTexture FBXSerializer::getTexture(const QString& textureID) {
|
|||
if (scaling.z == 0.0f) {
|
||||
scaling.z = 1.0f;
|
||||
}
|
||||
texture.transform.setScale(scaling);
|
||||
texture.transform.postScale(scaling);
|
||||
|
||||
if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) {
|
||||
texture.texcoordSet = 1;
|
||||
}
|
||||
texture.texcoordSetName = p.UVSet;
|
||||
}
|
||||
auto materialParamItr = _materialParams.find(materialID);
|
||||
if (materialParamItr != _materialParams.end()) {
|
||||
auto& materialParam = materialParamItr.value();
|
||||
texture.transform.postTranslate(materialParam.translation);
|
||||
texture.transform.postScale(materialParam.scaling);
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
@ -102,12 +108,12 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
material.diffuseFactor = 1.0;
|
||||
}
|
||||
|
||||
diffuseTexture = getTexture(diffuseTextureID);
|
||||
diffuseTexture = getTexture(diffuseTextureID, material.materialID);
|
||||
|
||||
// FBX files generated by 3DSMax have an intermediate texture parent, apparently
|
||||
foreach(const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) {
|
||||
if (_textureFilenames.contains(childTextureID)) {
|
||||
diffuseTexture = getTexture(diffuseTextureID);
|
||||
diffuseTexture = getTexture(diffuseTextureID, material.materialID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,7 +128,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
transparentTextureID = diffuseTextureID;
|
||||
}
|
||||
if (!transparentTextureID.isNull()) {
|
||||
transparentTexture = getTexture(transparentTextureID);
|
||||
transparentTexture = getTexture(transparentTextureID, material.materialID);
|
||||
material.opacityTexture = transparentTexture;
|
||||
detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity());
|
||||
}
|
||||
|
@ -131,13 +137,13 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
QString bumpTextureID = bumpTextures.value(material.materialID);
|
||||
QString normalTextureID = normalTextures.value(material.materialID);
|
||||
if (!normalTextureID.isNull()) {
|
||||
normalTexture = getTexture(normalTextureID);
|
||||
normalTexture = getTexture(normalTextureID, material.materialID);
|
||||
normalTexture.isBumpmap = false;
|
||||
|
||||
material.normalTexture = normalTexture;
|
||||
detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity());
|
||||
} else if (!bumpTextureID.isNull()) {
|
||||
normalTexture = getTexture(bumpTextureID);
|
||||
normalTexture = getTexture(bumpTextureID, material.materialID);
|
||||
normalTexture.isBumpmap = true;
|
||||
|
||||
material.normalTexture = normalTexture;
|
||||
|
@ -147,7 +153,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
HFMTexture specularTexture;
|
||||
QString specularTextureID = specularTextures.value(material.materialID);
|
||||
if (!specularTextureID.isNull()) {
|
||||
specularTexture = getTexture(specularTextureID);
|
||||
specularTexture = getTexture(specularTextureID, material.materialID);
|
||||
detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity());
|
||||
material.specularTexture = specularTexture;
|
||||
}
|
||||
|
@ -155,7 +161,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
HFMTexture metallicTexture;
|
||||
QString metallicTextureID = metallicTextures.value(material.materialID);
|
||||
if (!metallicTextureID.isNull()) {
|
||||
metallicTexture = getTexture(metallicTextureID);
|
||||
metallicTexture = getTexture(metallicTextureID, material.materialID);
|
||||
detectDifferentUVs |= (metallicTexture.texcoordSet != 0) || (!metallicTexture.transform.isIdentity());
|
||||
material.metallicTexture = metallicTexture;
|
||||
}
|
||||
|
@ -163,7 +169,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
HFMTexture roughnessTexture;
|
||||
QString roughnessTextureID = roughnessTextures.value(material.materialID);
|
||||
if (!roughnessTextureID.isNull()) {
|
||||
roughnessTexture = getTexture(roughnessTextureID);
|
||||
roughnessTexture = getTexture(roughnessTextureID, material.materialID);
|
||||
material.roughnessTexture = roughnessTexture;
|
||||
detectDifferentUVs |= (roughnessTexture.texcoordSet != 0) || (!roughnessTexture.transform.isIdentity());
|
||||
}
|
||||
|
@ -171,7 +177,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
HFMTexture shininessTexture;
|
||||
QString shininessTextureID = shininessTextures.value(material.materialID);
|
||||
if (!shininessTextureID.isNull()) {
|
||||
shininessTexture = getTexture(shininessTextureID);
|
||||
shininessTexture = getTexture(shininessTextureID, material.materialID);
|
||||
material.glossTexture = shininessTexture;
|
||||
detectDifferentUVs |= (shininessTexture.texcoordSet != 0) || (!shininessTexture.transform.isIdentity());
|
||||
}
|
||||
|
@ -179,7 +185,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
HFMTexture emissiveTexture;
|
||||
QString emissiveTextureID = emissiveTextures.value(material.materialID);
|
||||
if (!emissiveTextureID.isNull()) {
|
||||
emissiveTexture = getTexture(emissiveTextureID);
|
||||
emissiveTexture = getTexture(emissiveTextureID, material.materialID);
|
||||
detectDifferentUVs |= (emissiveTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity());
|
||||
material.emissiveTexture = emissiveTexture;
|
||||
|
||||
|
@ -202,7 +208,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
}
|
||||
|
||||
if (!occlusionTextureID.isNull()) {
|
||||
occlusionTexture = getTexture(occlusionTextureID);
|
||||
occlusionTexture = getTexture(occlusionTextureID, material.materialID);
|
||||
detectDifferentUVs |= (occlusionTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity());
|
||||
material.occlusionTexture = occlusionTexture;
|
||||
}
|
||||
|
@ -222,7 +228,7 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) {
|
|||
}
|
||||
|
||||
if (_loadLightmaps && !ambientTextureID.isNull()) {
|
||||
ambientTexture = getTexture(ambientTextureID);
|
||||
ambientTexture = getTexture(ambientTextureID, material.materialID);
|
||||
detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity());
|
||||
material.lightmapTexture = ambientTexture;
|
||||
material.lightmapParams = lightmapParams;
|
||||
|
|
|
@ -118,6 +118,8 @@ void gl::setSwapInterval(int interval) {
|
|||
wglSwapIntervalEXT(interval);
|
||||
#elif defined(Q_OS_MAC)
|
||||
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||
#elif defined(Q_OS_ANDROID)
|
||||
eglSwapInterval(eglGetCurrentDisplay(), interval);
|
||||
#else
|
||||
Q_UNUSED(interval);
|
||||
#endif
|
||||
|
|
|
@ -34,22 +34,9 @@ bool Context::USE_CUSTOM_CONTEXT { true };
|
|||
#endif
|
||||
|
||||
bool Context::enableDebugLogger() {
|
||||
#if defined(Q_OS_MAC)
|
||||
// OSX does not support GL_KHR_debug or GL_ARB_debug_output
|
||||
return false;
|
||||
#else
|
||||
#if defined(DEBUG) || defined(USE_GLES)
|
||||
static bool enableDebugLogger = true;
|
||||
#else
|
||||
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENGL");
|
||||
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
#endif
|
||||
return enableDebugLogger;
|
||||
#endif
|
||||
return gl::debugContextEnabled();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::atomic<size_t> Context::_totalSwapchainMemoryUsage { 0 };
|
||||
|
||||
size_t Context::getSwapchainMemoryUsage() { return _totalSwapchainMemoryUsage.load(); }
|
||||
|
|
|
@ -52,6 +52,11 @@ void Context::moveToThread(QThread* thread) {
|
|||
}
|
||||
|
||||
void Context::debugMessageHandler(const QOpenGLDebugMessage& debugMessage) {
|
||||
auto type = debugMessage.type();
|
||||
if (type == QOpenGLDebugMessage::PerformanceType) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto severity = debugMessage.severity();
|
||||
switch (severity) {
|
||||
case QOpenGLDebugMessage::NotificationSeverity:
|
||||
|
@ -60,13 +65,13 @@ void Context::debugMessageHandler(const QOpenGLDebugMessage& debugMessage) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
qDebug(glLogging) << debugMessage;
|
||||
qWarning(glLogging) << debugMessage;
|
||||
return;
|
||||
}
|
||||
|
||||
void Context::setupDebugLogging(QOpenGLContext *context) {
|
||||
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(context);
|
||||
QObject::connect(logger, &QOpenGLDebugLogger::messageLogged, nullptr, [](const QOpenGLDebugMessage& message){
|
||||
QObject::connect(logger, &QOpenGLDebugLogger::messageLogged, context, [](const QOpenGLDebugMessage& message){
|
||||
Context::debugMessageHandler(message);
|
||||
});
|
||||
if (logger->initialize()) {
|
||||
|
|
|
@ -198,11 +198,48 @@ namespace gl {
|
|||
|
||||
|
||||
bool checkGLErrorDebug(const char* name) {
|
||||
#ifdef DEBUG
|
||||
// Disabling error checking macro on Android debug builds for now,
|
||||
// as it throws off performance testing, which must be done on
|
||||
// Debug builds
|
||||
#if defined(DEBUG) && !defined(Q_OS_ANDROID)
|
||||
return checkGLError(name);
|
||||
#else
|
||||
Q_UNUSED(name);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Enables annotation of captures made by tools like renderdoc
|
||||
bool khrDebugEnabled() {
|
||||
static std::once_flag once;
|
||||
static bool khrDebug = false;
|
||||
std::call_once(once, [&] {
|
||||
khrDebug = nullptr != glPushDebugGroupKHR;
|
||||
});
|
||||
return khrDebug;
|
||||
}
|
||||
|
||||
// Enables annotation of captures made by tools like renderdoc
|
||||
bool extDebugMarkerEnabled() {
|
||||
static std::once_flag once;
|
||||
static bool extMarker = false;
|
||||
std::call_once(once, [&] {
|
||||
extMarker = nullptr != glPushGroupMarkerEXT;
|
||||
});
|
||||
return extMarker;
|
||||
}
|
||||
|
||||
bool debugContextEnabled() {
|
||||
#if defined(Q_OS_MAC)
|
||||
// OSX does not support GL_KHR_debug or GL_ARB_debug_output
|
||||
static bool enableDebugLogger = false;
|
||||
#elif defined(DEBUG) || defined(USE_GLES)
|
||||
//static bool enableDebugLogger = true;
|
||||
static bool enableDebugLogger = false;
|
||||
#else
|
||||
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENGL");
|
||||
static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
#endif
|
||||
return enableDebugLogger;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,13 @@ bool isRenderThread();
|
|||
namespace gl {
|
||||
void globalLock();
|
||||
void globalRelease(bool finish = true);
|
||||
|
||||
|
||||
bool debugContextEnabled();
|
||||
|
||||
bool khrDebugEnabled();
|
||||
|
||||
bool extDebugMarkerEnabled();
|
||||
|
||||
void withSavedContext(const std::function<void()>& f);
|
||||
|
||||
bool checkGLError(const char* name);
|
||||
|
|
|
@ -392,8 +392,38 @@ void GLBackend::renderPassDraw(const Batch& batch) {
|
|||
}
|
||||
}
|
||||
|
||||
// Support annotating captures in tools like Renderdoc
|
||||
class GlDuration {
|
||||
public:
|
||||
#ifdef USE_GLES
|
||||
GlDuration(const char* name) {
|
||||
// We need to use strlen here instead of -1, because the Snapdragon profiler
|
||||
// will crash otherwise
|
||||
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, strlen(name), name);
|
||||
}
|
||||
~GlDuration() {
|
||||
glPopDebugGroup();
|
||||
}
|
||||
#else
|
||||
GlDuration(const char* name) {
|
||||
if (::gl::khrDebugEnabled()) {
|
||||
glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 0, -1, name);
|
||||
}
|
||||
}
|
||||
~GlDuration() {
|
||||
if (::gl::khrDebugEnabled()) {
|
||||
glPopDebugGroupKHR();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#define GL_PROFILE_RANGE(category, name) \
|
||||
PROFILE_RANGE(category, name); \
|
||||
GlDuration glProfileRangeThis(name);
|
||||
|
||||
void GLBackend::render(const Batch& batch) {
|
||||
PROFILE_RANGE(render_gpu_gl, batch.getName());
|
||||
GL_PROFILE_RANGE(render_gpu_gl, batch.getName().c_str());
|
||||
|
||||
_transform._skybox = _stereo._skybox = batch.isSkyboxEnabled();
|
||||
// Allow the batch to override the rendering stereo settings
|
||||
|
@ -406,7 +436,7 @@ void GLBackend::render(const Batch& batch) {
|
|||
_transform._projectionJitter = Vec2(0.0f, 0.0f);
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render_gpu_gl_detail, "Transfer");
|
||||
GL_PROFILE_RANGE(render_gpu_gl_detail, "Transfer");
|
||||
renderPassTransfer(batch);
|
||||
}
|
||||
|
||||
|
@ -416,7 +446,7 @@ void GLBackend::render(const Batch& batch) {
|
|||
}
|
||||
#endif
|
||||
{
|
||||
PROFILE_RANGE(render_gpu_gl_detail, _stereo.isStereo() ? "Render Stereo" : "Render");
|
||||
GL_PROFILE_RANGE(render_gpu_gl_detail, _stereo.isStereo() ? "Render Stereo" : "Render");
|
||||
renderPassDraw(batch);
|
||||
}
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
|
|
|
@ -54,153 +54,8 @@
|
|||
#define GPU_STEREO_CAMERA_BUFFER
|
||||
#endif
|
||||
|
||||
//
|
||||
// GL Backend pointer storage mechanism
|
||||
// One of the following three defines must be defined.
|
||||
// GPU_POINTER_STORAGE_SHARED
|
||||
|
||||
// The platonic ideal, use references to smart pointers.
|
||||
// However, this produces artifacts because there are too many places in the code right now that
|
||||
// create temporary values (undesirable smart pointer duplications) and then those temp variables
|
||||
// get passed on and have their reference taken, and then invalidated
|
||||
// GPU_POINTER_STORAGE_REF
|
||||
|
||||
// Raw pointer manipulation. Seems more dangerous than the reference wrappers,
|
||||
// but in practice, the danger of grabbing a reference to a temporary variable
|
||||
// is causing issues
|
||||
// GPU_POINTER_STORAGE_RAW
|
||||
|
||||
#if defined(USE_GLES)
|
||||
#define GPU_POINTER_STORAGE_SHARED
|
||||
#else
|
||||
#define GPU_POINTER_STORAGE_RAW
|
||||
#endif
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
#if defined(GPU_POINTER_STORAGE_SHARED)
|
||||
template <typename T>
|
||||
static inline bool compare(const std::shared_ptr<T>& a, const std::shared_ptr<T>& b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T* acquire(const std::shared_ptr<T>& pointer) {
|
||||
return pointer.get();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void reset(std::shared_ptr<T>& pointer) {
|
||||
return pointer.reset();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool valid(const std::shared_ptr<T>& pointer) {
|
||||
return pointer.operator bool();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void assign(std::shared_ptr<T>& pointer, const std::shared_ptr<T>& source) {
|
||||
pointer = source;
|
||||
}
|
||||
|
||||
using BufferReference = BufferPointer;
|
||||
using TextureReference = TexturePointer;
|
||||
using FramebufferReference = FramebufferPointer;
|
||||
using FormatReference = Stream::FormatPointer;
|
||||
using PipelineReference = PipelinePointer;
|
||||
|
||||
#define GPU_REFERENCE_INIT_VALUE nullptr
|
||||
|
||||
#elif defined(GPU_POINTER_STORAGE_REF)
|
||||
|
||||
template <typename T>
|
||||
class PointerReferenceWrapper : public std::reference_wrapper<const std::shared_ptr<T>> {
|
||||
using Parent = std::reference_wrapper<const std::shared_ptr<T>>;
|
||||
|
||||
public:
|
||||
using Pointer = std::shared_ptr<T>;
|
||||
PointerReferenceWrapper() : Parent(EMPTY()) {}
|
||||
PointerReferenceWrapper(const Pointer& pointer) : Parent(pointer) {}
|
||||
void clear() { *this = EMPTY(); }
|
||||
|
||||
private:
|
||||
static const Pointer& EMPTY() {
|
||||
static const Pointer EMPTY_VALUE;
|
||||
return EMPTY_VALUE;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static bool compare(const PointerReferenceWrapper<T>& reference, const std::shared_ptr<T>& pointer) {
|
||||
return reference.get() == pointer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T* acquire(const PointerReferenceWrapper<T>& reference) {
|
||||
return reference.get().get();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void assign(PointerReferenceWrapper<T>& reference, const std::shared_ptr<T>& pointer) {
|
||||
reference = pointer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool valid(const PointerReferenceWrapper<T>& reference) {
|
||||
return reference.get().operator bool();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void reset(PointerReferenceWrapper<T>& reference) {
|
||||
return reference.clear();
|
||||
}
|
||||
|
||||
using BufferReference = PointerReferenceWrapper<Buffer>;
|
||||
using TextureReference = PointerReferenceWrapper<Texture>;
|
||||
using FramebufferReference = PointerReferenceWrapper<Framebuffer>;
|
||||
using FormatReference = PointerReferenceWrapper<Stream::Format>;
|
||||
using PipelineReference = PointerReferenceWrapper<Pipeline>;
|
||||
|
||||
#define GPU_REFERENCE_INIT_VALUE
|
||||
|
||||
#elif defined(GPU_POINTER_STORAGE_RAW)
|
||||
|
||||
template <typename T>
|
||||
static bool compare(const T* const& rawPointer, const std::shared_ptr<T>& pointer) {
|
||||
return rawPointer == pointer.get();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T* acquire(T*& rawPointer) {
|
||||
return rawPointer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool valid(const T* const& rawPointer) {
|
||||
return rawPointer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void reset(T*& rawPointer) {
|
||||
rawPointer = nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void assign(T*& rawPointer, const std::shared_ptr<T>& pointer) {
|
||||
rawPointer = pointer.get();
|
||||
}
|
||||
|
||||
using BufferReference = Buffer*;
|
||||
using TextureReference = Texture*;
|
||||
using FramebufferReference = Framebuffer*;
|
||||
using FormatReference = Stream::Format*;
|
||||
using PipelineReference = Pipeline*;
|
||||
|
||||
#define GPU_REFERENCE_INIT_VALUE nullptr
|
||||
|
||||
#endif
|
||||
|
||||
class GLBackend : public Backend, public std::enable_shared_from_this<GLBackend> {
|
||||
// Context Backend static interface required
|
||||
friend class gpu::Context;
|
||||
|
@ -583,13 +438,13 @@ protected:
|
|||
|
||||
BufferState& operator=(const BufferState& other) = delete;
|
||||
void reset() {
|
||||
gpu::gl::reset(buffer);
|
||||
gpu::reset(buffer);
|
||||
offset = 0;
|
||||
size = 0;
|
||||
}
|
||||
bool compare(const BufferPointer& buffer, GLintptr offset, GLsizeiptr size) {
|
||||
const auto& self = *this;
|
||||
return (self.offset == offset && self.size == size && gpu::gl::compare(self.buffer, buffer));
|
||||
return (self.offset == offset && self.size == size && gpu::compare(self.buffer, buffer));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ void GLBackend::do_advance(const Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
|
||||
void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||
if (_stereo.isStereo() && !_pipeline._stateCache.scissorEnable) {
|
||||
if (_stereo.isStereo() && !_pipeline._stateCache.flags.scissorEnable) {
|
||||
qWarning("Clear without scissor in stereo mode");
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
|
||||
// Apply scissor if needed and if not already on
|
||||
bool doEnableScissor = (useScissor && (!_pipeline._stateCache.scissorEnable));
|
||||
bool doEnableScissor = (useScissor && (!_pipeline._stateCache.flags.scissorEnable));
|
||||
if (doEnableScissor) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
|
|
@ -100,17 +100,17 @@ void GLBackend::do_setStateCullMode(int32 mode) {
|
|||
}
|
||||
|
||||
void GLBackend::do_setStateFrontFaceClockwise(bool isClockwise) {
|
||||
if (_pipeline._stateCache.frontFaceClockwise != isClockwise) {
|
||||
if (_pipeline._stateCache.flags.frontFaceClockwise != isClockwise) {
|
||||
static GLenum GL_FRONT_FACES[] = { GL_CCW, GL_CW };
|
||||
glFrontFace(GL_FRONT_FACES[isClockwise]);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.frontFaceClockwise = isClockwise;
|
||||
_pipeline._stateCache.flags.frontFaceClockwise = isClockwise;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateDepthClampEnable(bool enable) {
|
||||
if (_pipeline._stateCache.depthClampEnable != enable) {
|
||||
if (_pipeline._stateCache.flags.depthClampEnable != enable) {
|
||||
#if !defined(USE_GLES)
|
||||
if (enable) {
|
||||
glEnable(GL_DEPTH_CLAMP);
|
||||
|
@ -118,13 +118,13 @@ void GLBackend::do_setStateDepthClampEnable(bool enable) {
|
|||
glDisable(GL_DEPTH_CLAMP);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
_pipeline._stateCache.depthClampEnable = enable;
|
||||
_pipeline._stateCache.flags.depthClampEnable = enable;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateScissorEnable(bool enable) {
|
||||
if (_pipeline._stateCache.scissorEnable != enable) {
|
||||
if (_pipeline._stateCache.flags.scissorEnable != enable) {
|
||||
if (enable) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
} else {
|
||||
|
@ -132,12 +132,12 @@ void GLBackend::do_setStateScissorEnable(bool enable) {
|
|||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.scissorEnable = enable;
|
||||
_pipeline._stateCache.flags.scissorEnable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateMultisampleEnable(bool enable) {
|
||||
if (_pipeline._stateCache.multisampleEnable != enable) {
|
||||
if (_pipeline._stateCache.flags.multisampleEnable != enable) {
|
||||
#if !defined(USE_GLES)
|
||||
if (enable) {
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
@ -146,13 +146,13 @@ void GLBackend::do_setStateMultisampleEnable(bool enable) {
|
|||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.multisampleEnable = enable;
|
||||
_pipeline._stateCache.flags.multisampleEnable = enable;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateAntialiasedLineEnable(bool enable) {
|
||||
if (_pipeline._stateCache.antialisedLineEnable != enable) {
|
||||
if (_pipeline._stateCache.flags.antialisedLineEnable != enable) {
|
||||
#if !defined(USE_GLES)
|
||||
if (enable) {
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
|
@ -161,7 +161,7 @@ void GLBackend::do_setStateAntialiasedLineEnable(bool enable) {
|
|||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.antialisedLineEnable = enable;
|
||||
_pipeline._stateCache.flags.antialisedLineEnable = enable;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ void GLBackend::do_setStateDepthTest(State::DepthTest test) {
|
|||
if (CHECK_GL_ERROR()) {
|
||||
qCDebug(gpulogging) << "DepthTest" << (test.isEnabled() ? "Enabled" : "Disabled")
|
||||
<< "Mask=" << (test.getWriteMask() ? "Write" : "no Write")
|
||||
<< "Func=" << test.getFunction()
|
||||
<< "Func=" << (uint16_t)test.getFunction()
|
||||
<< "Raw=" << test.getRaw();
|
||||
}
|
||||
_pipeline._stateCache.depthTest = test;
|
||||
|
@ -264,7 +264,7 @@ void GLBackend::do_setStateStencil(State::StencilActivation activation, State::S
|
|||
}
|
||||
|
||||
void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) {
|
||||
if (_pipeline._stateCache.alphaToCoverageEnable != enable) {
|
||||
if (_pipeline._stateCache.flags.alphaToCoverageEnable != enable) {
|
||||
if (enable) {
|
||||
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
} else {
|
||||
|
@ -272,7 +272,7 @@ void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) {
|
|||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.alphaToCoverageEnable = enable;
|
||||
_pipeline._stateCache.flags.alphaToCoverageEnable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,7 +317,7 @@ void GLBackend::do_setStateColorWriteMask(uint32 mask) {
|
|||
mask & State::ColorMask::WRITE_ALPHA);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.colorWriteMask = mask;
|
||||
_pipeline._stateCache.colorWriteMask = (State::ColorMask)mask;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -174,17 +174,17 @@ void getCurrentGLState(State::Data& state) {
|
|||
{
|
||||
GLint winding;
|
||||
glGetIntegerv(GL_FRONT_FACE, &winding);
|
||||
state.frontFaceClockwise = (winding == GL_CW);
|
||||
state.flags.frontFaceClockwise = (winding == GL_CW);
|
||||
#if defined(USE_GLES)
|
||||
state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE_EXT);
|
||||
state.antialisedLineEnable = false;
|
||||
state.depthClampEnable = false;
|
||||
state.flags.multisampleEnable = glIsEnabled(GL_MULTISAMPLE_EXT);
|
||||
state.flags.antialisedLineEnable = false;
|
||||
state.flags.depthClampEnable = false;
|
||||
#else
|
||||
state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE);
|
||||
state.antialisedLineEnable = glIsEnabled(GL_LINE_SMOOTH);
|
||||
state.depthClampEnable = glIsEnabled(GL_DEPTH_CLAMP);
|
||||
state.flags.multisampleEnable = glIsEnabled(GL_MULTISAMPLE);
|
||||
state.flags.antialisedLineEnable = glIsEnabled(GL_LINE_SMOOTH);
|
||||
state.flags.depthClampEnable = glIsEnabled(GL_DEPTH_CLAMP);
|
||||
#endif
|
||||
state.scissorEnable = glIsEnabled(GL_SCISSOR_TEST);
|
||||
state.flags.scissorEnable = glIsEnabled(GL_SCISSOR_TEST);
|
||||
}
|
||||
{
|
||||
if (glIsEnabled(GL_POLYGON_OFFSET_FILL)) {
|
||||
|
@ -247,7 +247,7 @@ void getCurrentGLState(State::Data& state) {
|
|||
state.sampleMask = mask;
|
||||
}
|
||||
{
|
||||
state.alphaToCoverageEnable = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
state.flags.alphaToCoverageEnable = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
}
|
||||
{
|
||||
GLboolean isEnabled = glIsEnabled(GL_BLEND);
|
||||
|
@ -272,10 +272,10 @@ void getCurrentGLState(State::Data& state) {
|
|||
{
|
||||
GLboolean mask[4];
|
||||
glGetBooleanv(GL_COLOR_WRITEMASK, mask);
|
||||
state.colorWriteMask = (mask[0] ? State::WRITE_RED : 0)
|
||||
state.colorWriteMask = (State::ColorMask)((mask[0] ? State::WRITE_RED : 0)
|
||||
| (mask[1] ? State::WRITE_GREEN : 0)
|
||||
| (mask[2] ? State::WRITE_BLUE : 0)
|
||||
| (mask[3] ? State::WRITE_ALPHA : 0);
|
||||
| (mask[3] ? State::WRITE_ALPHA : 0));
|
||||
}
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
|
|
@ -56,11 +56,11 @@ const GLState::Commands makeResetStateCommands() {
|
|||
return {
|
||||
std::make_shared<Command1I>(&GLBackend::do_setStateFillMode, DEFAULT.fillMode),
|
||||
std::make_shared<Command1I>(&GLBackend::do_setStateCullMode, DEFAULT.cullMode),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, DEFAULT.frontFaceClockwise),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, DEFAULT.depthClampEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, DEFAULT.scissorEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, DEFAULT.multisampleEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, DEFAULT.antialisedLineEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, DEFAULT.flags.frontFaceClockwise),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, DEFAULT.flags.depthClampEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, DEFAULT.flags.scissorEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, DEFAULT.flags.multisampleEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, DEFAULT.flags.antialisedLineEnable),
|
||||
|
||||
// Depth bias has 2 fields in State but really one call in GLBackend
|
||||
CommandPointer(depthBiasCommand),
|
||||
|
@ -75,7 +75,7 @@ const GLState::Commands makeResetStateCommands() {
|
|||
|
||||
std::make_shared<Command1U>(&GLBackend::do_setStateSampleMask, DEFAULT.sampleMask),
|
||||
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.alphaToCoverageEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.flags.alphaToCoverageEnable),
|
||||
|
||||
std::make_shared<CommandBlend>(&GLBackend::do_setStateBlend, DEFAULT.blendFunction),
|
||||
|
||||
|
|
|
@ -4,3 +4,4 @@ setup_hifi_library()
|
|||
link_hifi_libraries(shared ktx shaders)
|
||||
|
||||
target_nsight()
|
||||
target_json()
|
||||
|
|
|
@ -45,7 +45,7 @@ size_t Batch::_dataMax{ BATCH_PREALLOCATE_MIN };
|
|||
size_t Batch::_objectsMax{ BATCH_PREALLOCATE_MIN };
|
||||
size_t Batch::_drawCallInfosMax{ BATCH_PREALLOCATE_MIN };
|
||||
|
||||
Batch::Batch(const char* name) {
|
||||
Batch::Batch(const std::string& name) {
|
||||
_name = name;
|
||||
_commands.reserve(_commandsMax);
|
||||
_commandOffsets.reserve(_commandOffsetsMax);
|
||||
|
@ -64,7 +64,7 @@ Batch::~Batch() {
|
|||
_drawCallInfosMax = std::max(_drawCallInfos.size(), _drawCallInfosMax);
|
||||
}
|
||||
|
||||
void Batch::setName(const char* name) {
|
||||
void Batch::setName(const std::string& name) {
|
||||
_name = name;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ void Batch::clear() {
|
|||
_textureTables.clear();
|
||||
_transforms.clear();
|
||||
|
||||
_name = nullptr;
|
||||
_name.clear();
|
||||
_invalidModel = true;
|
||||
_currentModel = Transform();
|
||||
_drawcallUniform = 0;
|
||||
|
|
|
@ -89,14 +89,14 @@ public:
|
|||
void captureDrawCallInfo();
|
||||
void captureNamedDrawCallInfo(std::string name);
|
||||
|
||||
Batch(const char* name = nullptr);
|
||||
Batch(const std::string& name = "");
|
||||
// Disallow copy construction and assignement of batches
|
||||
Batch(const Batch& batch) = delete;
|
||||
Batch& operator=(const Batch& batch) = delete;
|
||||
~Batch();
|
||||
|
||||
void setName(const char* name);
|
||||
const char* getName() const { return _name; }
|
||||
void setName(const std::string& name);
|
||||
const std::string& getName() const { return _name; }
|
||||
void clear();
|
||||
|
||||
// Batches may need to override the context level stereo settings
|
||||
|
@ -440,6 +440,18 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
using CommandHandler = std::function<void(Command, const Param*)>;
|
||||
|
||||
void forEachCommand(const CommandHandler& handler) const {
|
||||
size_t count = _commands.size();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
const auto command = _commands[i];
|
||||
const auto offset = _commandOffsets[i];
|
||||
const Param* params = _params.data() + offset;
|
||||
handler(command, params);
|
||||
}
|
||||
}
|
||||
|
||||
typedef Cache<BufferPointer>::Vector BufferCaches;
|
||||
typedef Cache<TexturePointer>::Vector TextureCaches;
|
||||
typedef Cache<TextureTablePointer>::Vector TextureTableCaches;
|
||||
|
@ -519,7 +531,7 @@ public:
|
|||
bool _enableSkybox { false };
|
||||
|
||||
protected:
|
||||
const char* _name;
|
||||
std::string _name;
|
||||
|
||||
friend class Context;
|
||||
friend class Frame;
|
||||
|
|
|
@ -149,7 +149,8 @@ protected:
|
|||
Size _end{ 0 };
|
||||
Sysmem _sysmem;
|
||||
|
||||
|
||||
friend class Serializer;
|
||||
friend class Deserializer;
|
||||
friend class BufferView;
|
||||
friend class Frame;
|
||||
friend class Batch;
|
||||
|
|
|
@ -47,10 +47,7 @@ Context::Context(const Context& context) {
|
|||
}
|
||||
|
||||
Context::~Context() {
|
||||
for (auto batch : _batchPool) {
|
||||
delete batch;
|
||||
}
|
||||
_batchPool.clear();
|
||||
clearBatches();
|
||||
_syncedPrograms.clear();
|
||||
}
|
||||
|
||||
|
@ -97,6 +94,12 @@ FramePointer Context::endFrame() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void Context::executeBatch(const char* name, std::function<void(Batch&)> lambda) const {
|
||||
auto batch = acquireBatch(name);
|
||||
lambda(*batch);
|
||||
executeBatch(*batch);
|
||||
}
|
||||
|
||||
void Context::executeBatch(Batch& batch) const {
|
||||
PROFILE_RANGE(render_gpu, __FUNCTION__);
|
||||
batch.flush();
|
||||
|
@ -117,28 +120,27 @@ void Context::executeFrame(const FramePointer& frame) const {
|
|||
PROFILE_RANGE(render_gpu, __FUNCTION__);
|
||||
|
||||
// Grab the stats at the around the frame and delta to have a consistent sampling
|
||||
ContextStats beginStats;
|
||||
static ContextStats beginStats;
|
||||
getStats(beginStats);
|
||||
|
||||
// FIXME? probably not necessary, but safe
|
||||
consumeFrameUpdates(frame);
|
||||
_backend->setStereoState(frame->stereoState);
|
||||
{
|
||||
Batch beginBatch("Context::executeFrame::begin");
|
||||
_frameRangeTimer->begin(beginBatch);
|
||||
_backend->render(beginBatch);
|
||||
|
||||
// Execute the frame rendering commands
|
||||
for (auto& batch : frame->batches) {
|
||||
_backend->render(*batch);
|
||||
}
|
||||
|
||||
Batch endBatch("Context::executeFrame::end");
|
||||
_frameRangeTimer->end(endBatch);
|
||||
_backend->render(endBatch);
|
||||
executeBatch("Context::executeFrame::begin", [&](Batch& batch){
|
||||
batch.pushProfileRange("Frame");
|
||||
_frameRangeTimer->begin(batch);
|
||||
});
|
||||
// Execute the frame rendering commands
|
||||
for (auto& batch : frame->batches) {
|
||||
_backend->render(*batch);
|
||||
}
|
||||
executeBatch("Context::executeFrame::end", [&](Batch& batch){
|
||||
batch.popProfileRange();
|
||||
_frameRangeTimer->end(batch);
|
||||
});
|
||||
|
||||
ContextStats endStats;
|
||||
static ContextStats endStats;
|
||||
getStats(endStats);
|
||||
_frameStats.evalDelta(beginStats, endStats);
|
||||
}
|
||||
|
@ -381,6 +383,16 @@ void Context::processProgramsToSync() {
|
|||
}
|
||||
}
|
||||
|
||||
std::mutex Context::_batchPoolMutex;
|
||||
std::list<Batch*> Context::_batchPool;
|
||||
|
||||
void Context::clearBatches() {
|
||||
for (auto batch : _batchPool) {
|
||||
delete batch;
|
||||
}
|
||||
_batchPool.clear();
|
||||
}
|
||||
|
||||
BatchPointer Context::acquireBatch(const char* name) {
|
||||
Batch* rawBatch = nullptr;
|
||||
{
|
||||
|
@ -393,8 +405,10 @@ BatchPointer Context::acquireBatch(const char* name) {
|
|||
if (!rawBatch) {
|
||||
rawBatch = new Batch();
|
||||
}
|
||||
rawBatch->setName(name);
|
||||
return BatchPointer(rawBatch, [this](Batch* batch) { releaseBatch(batch); });
|
||||
if (name) {
|
||||
rawBatch->setName(name);
|
||||
}
|
||||
return BatchPointer(rawBatch, [](Batch* batch) { releaseBatch(batch); });
|
||||
}
|
||||
|
||||
void Context::releaseBatch(Batch* batch) {
|
||||
|
@ -406,7 +420,7 @@ void Context::releaseBatch(Batch* batch) {
|
|||
void gpu::doInBatch(const char* name,
|
||||
const std::shared_ptr<gpu::Context>& context,
|
||||
const std::function<void(Batch& batch)>& f) {
|
||||
auto batch = context->acquireBatch(name);
|
||||
auto batch = Context::acquireBatch(name);
|
||||
f(*batch);
|
||||
context->appendFrameBatch(batch);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue