mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 09:23:17 +02:00
Merge branch 'master' into QtImageCompare
This commit is contained in:
commit
e1e0163992
42 changed files with 655 additions and 1098 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -15,7 +15,9 @@ Makefile
|
|||
# Android Studio
|
||||
*.iml
|
||||
local.properties
|
||||
android/libraries
|
||||
android/gradle*
|
||||
android/.gradle
|
||||
android/app/src/main/jniLibs
|
||||
|
||||
# VSCode
|
||||
# List taken from Github Global Ignores master@435c4d92
|
||||
|
|
152
BUILD_ANDROID.md
152
BUILD_ANDROID.md
|
@ -1,25 +1,23 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Android specific instructions are found in this file.
|
||||
Please read the [general build guide](BUILD.md) for information on building other platform. Only Android specific instructions are found in this file.
|
||||
|
||||
# Android Dependencies
|
||||
# Dependencies
|
||||
|
||||
*Currently Android building is only supported on 64 bit Linux host environments*
|
||||
|
||||
You will need the following tools to build our Android targets.
|
||||
|
||||
* [Qt](http://www.qt.io/download-open-source/#) ~> 5.9.1
|
||||
* [Gradle](https://gradle.org/install/)
|
||||
* [Android Studio](https://developer.android.com/studio/index.html)
|
||||
* [Google VR SDK](https://github.com/googlevr/gvr-android-sdk/releases)
|
||||
* [Gradle](https://gradle.org/releases/)
|
||||
|
||||
### Qt
|
||||
### Gradle
|
||||
|
||||
Download the Qt online installer. Run the installer and select the android_armv7 binaries. Installing to the default path is recommended
|
||||
Install gradle version 4.1 or higher. Following the instructions to install via [SDKMAN!](http://sdkman.io/install.html) is recommended.
|
||||
|
||||
### Android Studio
|
||||
|
||||
Download the Android Studio installer and run it. Once installed, at the welcome screen, click configure in the lower right corner and select SDK manager
|
||||
|
||||
From the SDK Platforms tab, select API level 26.
|
||||
|
||||
* Install the ARM EABI v7a System Image if you want to run an emulator.
|
||||
From the SDK Platforms tab, select API levels 24 and 26.
|
||||
|
||||
From the SDK Tools tab select the following
|
||||
|
||||
|
@ -29,123 +27,41 @@ From the SDK Tools tab select the following
|
|||
* LLDB
|
||||
* Android SDK Platform-Tools
|
||||
* Android SDK Tools
|
||||
* Android SDK Tools
|
||||
* NDK (even if you have the NDK installed separately)
|
||||
|
||||
### Google VR SDK
|
||||
# Environment
|
||||
|
||||
Download the 1.8 Google VR SDK [release](https://github.com/googlevr/gvr-android-sdk/archive/v1.80.0.zip). Unzip the archive to a location on your drive.
|
||||
|
||||
### Gradle
|
||||
|
||||
Download [Gradle 4.1](https://services.gradle.org/distributions/gradle-4.1-all.zip) and unzip it on your local drive. You may wish to add the location of the bin directory within the archive to your path
|
||||
Setting up the environment for android builds requires some additional steps
|
||||
|
||||
#### Set up machine specific Gradle properties
|
||||
|
||||
Create a `gradle.properties` file in ~/.gradle. Edit the file to contain the following
|
||||
Create a `gradle.properties` file in $HOME/.gradle. Edit the file to contain the following
|
||||
|
||||
QT5_ROOT=C\:\\Qt\\5.9.1\\android_armv7
|
||||
GVR_ROOT=C\:\\Android\\gvr-android-sdk
|
||||
HIFI_ANDROID_PRECOMPILED=<your_home_directory>/Android/hifi_externals
|
||||
|
||||
Replace the paths with your local installations of Qt5 and the Google VR SDK
|
||||
Note, do not use `$HOME` for the path. It must be a fully qualified path name.
|
||||
|
||||
### Setup the repository
|
||||
|
||||
Clone the repository
|
||||
|
||||
`git clone https://github.com/highfidelity/hifi.git`
|
||||
|
||||
Enter the repository `android` directory
|
||||
|
||||
`cd hifi/android`
|
||||
|
||||
Execute a gradle pre-build setup. This step should only need to be done once
|
||||
|
||||
`gradle setupDepedencies`
|
||||
|
||||
|
||||
# TODO fix the rest
|
||||
# Building & Running
|
||||
|
||||
You will also need to cross-compile the dependencies required for all platforms for Android, and help CMake find these compiled libraries on your machine.
|
||||
* Open Android Studio
|
||||
* Choose _Open Existing Android Studio Project_
|
||||
* Navigate to the `hifi` repository and choose the `android` folder and select _OK_
|
||||
* If Android Studio asks you if you want to use the Gradle wrapper, select cancel and tell it where your local gradle installation is. If you used SDKMAN to install gradle it will be located in `$HOME/.sdkman/candidates/gradle/current/`
|
||||
* From the _Build_ menu select _Make Project_
|
||||
* Once the build completes, from the _Run_ menu select _Run App_
|
||||
|
||||
#### Scribe
|
||||
|
||||
High Fidelity has a shader pre-processing tool called `scribe` that various libraries will call on during the build process. You must compile scribe using your native toolchain (following the build instructions for your platform) and then pass a CMake variable or set an ENV variable `SCRIBE_PATH` that is a path to the scribe executable.
|
||||
|
||||
CMake will fatally error if it does not find the scribe executable while using the android toolchain.
|
||||
|
||||
#### Optional Components
|
||||
|
||||
* [Oculus Mobile SDK](https://developer.oculus.com/downloads/#sdk=mobile) ~> 0.4.2
|
||||
|
||||
#### ANDROID_LIB_DIR
|
||||
|
||||
Since you won't be installing Android dependencies to system paths on your development machine, CMake will need a little help tracking down your Android dependencies.
|
||||
|
||||
This is most easily accomplished by installing all Android dependencies in the same folder. You can place this folder wherever you like on your machine. In this build guide and across our CMakeLists files this folder is referred to as `ANDROID_LIB_DIR`. You can set `ANDROID_LIB_DIR` in your environment or by passing when you run CMake.
|
||||
|
||||
#### Qt
|
||||
|
||||
Install Qt 5.5.1 for Android for your host environment from the [Qt downloads page](http://www.qt.io/download/). Install Qt to ``$ANDROID_LIB_DIR/Qt``. This is required so that our root CMakeLists file can help CMake find your Android Qt installation.
|
||||
|
||||
The component required for the Android build is the `Android armv7` component.
|
||||
|
||||
If you would like to install Qt to a different location, or attempt to build with a different Qt version, you can pass `ANDROID_QT_CMAKE_PREFIX_PATH` to CMake. Point to the `cmake` folder inside `$VERSION_NUMBER/android_armv7/lib`. Otherwise, our root CMakeLists will set it to `$ANDROID_LIB_DIR/Qt/5.5/android_armv7/lib/cmake`.
|
||||
|
||||
#### OpenSSL
|
||||
|
||||
Cross-compilation of OpenSSL has been tested from an OS X machine running 10.10 compiling OpenSSL 1.0.2. It is likely that the steps below will work for other OpenSSL versions than 1.0.2.
|
||||
|
||||
The original instructions to compile OpenSSL for Android from your host environment can be found [here](http://wiki.openssl.org/index.php/Android). We required some tweaks to get OpenSSL to successfully compile, those tweaks are explained below.
|
||||
|
||||
Download the [OpenSSL source](https://www.openssl.org/source/) and extract the tarball inside your `ANDROID_LIB_DIR`. Rename the extracted folder to `openssl`.
|
||||
|
||||
You will need the [setenv-android.sh script](http://wiki.openssl.org/index.php/File:Setenv-android.sh) from the OpenSSL wiki.
|
||||
|
||||
You must change three values at the top of the `setenv-android.sh` script - `_ANDROID_NDK`, `_ANDROID_EABI` and `_ANDROID_API`.
|
||||
`_ANDROID_NDK` should be `android-ndk-r10`, `_ANDROID_EABI` should be `arm-linux-androidebi-4.9` and `_ANDROID_API` should be `19`.
|
||||
|
||||
First, make sure `ANDROID_NDK_ROOT` is set in your env. This should be the path to the root of your Android NDK install. `setenv-android.sh` needs `ANDROID_NDK_ROOT` to set the environment variables required for building OpenSSL.
|
||||
|
||||
Source the `setenv-android.sh` script so it can set environment variables that OpenSSL will use while compiling. If you use zsh as your shell you may need to modify the `setenv-android.sh` for it to set the correct variables in your env.
|
||||
|
||||
```
|
||||
export ANDROID_NDK_ROOT=YOUR_NDK_ROOT
|
||||
source setenv-android.sh
|
||||
```
|
||||
|
||||
Then, from the OpenSSL directory, run the following commands.
|
||||
|
||||
```
|
||||
perl -pi -e 's/install: all install_docs install_sw/install: install_docs install_sw/g' Makefile.org
|
||||
./config shared -no-ssl2 -no-ssl3 -no-comp -no-hw -no-engine --openssldir=/usr/local/ssl/$ANDROID_API
|
||||
make depend
|
||||
make all
|
||||
```
|
||||
|
||||
This should generate libcrypto and libssl in the root of the OpenSSL directory. YOU MUST remove the `libssl.so` and `libcrypto.so` files that are generated. They are symlinks to `libssl.so.VER` and `libcrypto.so.VER` which Android does not know how to handle. By removing `libssl.so` and `libcrypto.so` the FindOpenSSL module will find the static libs and use those instead.
|
||||
|
||||
If you have been building other components it is possible that the OpenSSL compile will fail based on the values other cross-compilations (tbb, bullet) have set. Ensure that you are in a new terminal window to avoid compilation errors from previously set environment variables.
|
||||
|
||||
#### Oculus Mobile SDK
|
||||
|
||||
The Oculus Mobile SDK is optional, for Gear VR support. It is not required to compile gvr-interface.
|
||||
|
||||
Download the [Oculus Mobile SDK](https://developer.oculus.com/downloads/#sdk=mobile) and extract the archive inside your `ANDROID_LIB_DIR` folder. Rename the extracted folder to `libovr`.
|
||||
|
||||
From the VRLib directory, use ndk-build to build VrLib.
|
||||
|
||||
```
|
||||
cd VRLib
|
||||
ndk-build
|
||||
```
|
||||
|
||||
This will create the liboculus.a archive that our FindLibOVR module will look for when cmake is run.
|
||||
|
||||
##### Hybrid testing
|
||||
|
||||
Currently the 'vr_dual' mode that would allow us to run a hybrid app has limited support in the Oculus Mobile SDK. The best way to have an application we can launch without having to connect to the GearVR is to put the Gear VR Service into developer mode. This stops Oculus Home from taking over the device when it is plugged into the Gear VR headset, and allows the application to be launched from the Applications page.
|
||||
|
||||
To put the Gear VR Service into developer mode you need an application with an Oculus Signature File on your device. Generate an Oculus Signature File for your device on the [Oculus osig tool page](https://developer.oculus.com/tools/osig/). Place this file in the gvr-interface/assets directory. Cmake will automatically copy it into your apk in the right place when you execute `make gvr-interface-apk`.
|
||||
|
||||
Once the application is on your device, go to `Settings->Application Manager->Gear VR Service->Manage Storage`. Tap on `VR Service Version` six times. It will scan your device to verify that you have an osig file in an application on your device, and then it will let you enable Developer mode.
|
||||
|
||||
### CMake
|
||||
|
||||
We use CMake to generate the makefiles that compile and deploy the Android APKs to your device. In order to create Makefiles for the Android targets, CMake requires that some environment variables are set, and that other variables are passed to it when it is run.
|
||||
|
||||
The following must be set in your environment:
|
||||
|
||||
* ANDROID_NDK - the root of your Android NDK install
|
||||
* ANDROID_HOME - the root of your Android SDK install
|
||||
* ANDROID_LIB_DIR - the directory containing cross-compiled versions of dependencies
|
||||
|
||||
The following must be passed to CMake when it is run:
|
||||
|
||||
* USE_ANDROID_TOOLCHAIN - set to true to build for Android
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
set(TARGET_NAME native-lib)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared networking gl gpu gpu-gles render-utils)
|
||||
autoscribe_shader_lib(gpu model render render-utils)
|
||||
target_opengl()
|
||||
link_hifi_libraries(shared networking gl gpu gpu-gles image fbx render-utils physics)
|
||||
|
||||
target_link_libraries(native-lib android log m)
|
||||
target_include_directories(native-lib PRIVATE "${GVR_ROOT}/libraries/headers")
|
||||
target_link_libraries(native-lib "C:/Users/bdavis/Git/hifi/android/libraries/jni/armeabi-v7a/libgvr.so")
|
||||
|
||||
target_opengl()
|
||||
target_googlevr()
|
||||
|
||||
|
||||
|
|
|
@ -1,27 +1,32 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
ext.RELEASE_NUMBER = project.hasProperty('RELEASE_NUMBER') ? project.getProperty('RELEASE_NUMBER') : '0'
|
||||
ext.RELEASE_TYPE = project.hasProperty('RELEASE_TYPE') ? project.getProperty('RELEASE_TYPE') : 'DEV'
|
||||
ext.BUILD_BRANCH = project.hasProperty('BUILD_BRANCH') ? project.getProperty('BUILD_BRANCH') : ''
|
||||
|
||||
android {
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion "26.0.1"
|
||||
defaultConfig {
|
||||
applicationId "org.saintandreas.testapp"
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 26
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
ndk { abiFilters 'armeabi-v7a' }
|
||||
ndk { abiFilters 'arm64-v8a' }
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments '-DHIFI_ANDROID=1',
|
||||
'-DANDROID_PLATFORM=android-24',
|
||||
'-DANDROID_TOOLCHAIN=clang',
|
||||
'-DANDROID_STL=gnustl_shared',
|
||||
'-DGVR_ROOT=' + GVR_ROOT,
|
||||
'-DNATIVE_SCRIBE=c:/bin/scribe.exe',
|
||||
"-DHIFI_ANDROID_PRECOMPILED=${project.rootDir}/libraries/jni/armeabi-v7a"
|
||||
'-DANDROID_STL=c++_shared',
|
||||
'-DQT_CMAKE_PREFIX_PATH=' + HIFI_ANDROID_PRECOMPILED + '/qt/lib/cmake',
|
||||
'-DNATIVE_SCRIBE=' + HIFI_ANDROID_PRECOMPILED + '/scribe',
|
||||
'-DHIFI_ANDROID_PRECOMPILED=' + HIFI_ANDROID_PRECOMPILED,
|
||||
'-DRELEASE_NUMBER=' + RELEASE_NUMBER,
|
||||
'-DRELEASE_TYPE=' + RELEASE_TYPE,
|
||||
'-DBUILD_BRANCH=' + BUILD_BRANCH
|
||||
}
|
||||
}
|
||||
jackOptions { enabled true }
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
|
@ -29,17 +34,20 @@ android {
|
|||
}
|
||||
|
||||
buildTypes {
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.all {
|
||||
if (RELEASE_NUMBER != '0') {
|
||||
outputFileName = "app_" + RELEASE_NUMBER + "_" + RELEASE_TYPE + ".apk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs.srcDirs += '../libraries/jni';
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path '../../CMakeLists.txt'
|
||||
|
@ -53,5 +61,3 @@ dependencies {
|
|||
compile 'com.google.vr:sdk-audio:1.80.0'
|
||||
compile 'com.google.vr:sdk-base:1.80.0'
|
||||
}
|
||||
|
||||
build.dependsOn(':extractQt5')
|
||||
|
|
|
@ -7,12 +7,10 @@
|
|||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true"/>
|
||||
<uses-feature android:name="android.software.vr.mode" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:theme="@style/VrActivityTheme"
|
||||
android:theme="@style/NoSystemUI"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round">
|
||||
<activity
|
||||
|
@ -20,17 +18,10 @@
|
|||
android:label="@string/app_name"
|
||||
android:screenOrientation="landscape"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:enableVrMode="@string/gvr_vr_mode_component"
|
||||
android:resizeableActivity="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="com.google.intent.category.DAYDREAM"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="com.google.intent.category.CARDBOARD" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
|
|
@ -37,12 +37,7 @@ extern "C" {
|
|||
JNI_METHOD(jlong, nativeCreateRenderer)
|
||||
(JNIEnv *env, jclass clazz, jobject class_loader, jobject android_context, jlong native_gvr_api) {
|
||||
qInstallMessageHandler(messageHandler);
|
||||
#if defined(GVR)
|
||||
auto gvrContext = reinterpret_cast<gvr_context *>(native_gvr_api);
|
||||
return toJni(new NativeRenderer(gvrContext));
|
||||
#else
|
||||
return toJni(new NativeRenderer(nullptr));
|
||||
#endif
|
||||
return toJni(new NativeRenderer());
|
||||
}
|
||||
|
||||
JNI_METHOD(void, nativeDestroyRenderer)
|
||||
|
|
|
@ -1,138 +1,14 @@
|
|||
#include "renderer.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include "GoogleVRHelpers.h"
|
||||
|
||||
#include <gl/GLShaders.h>
|
||||
#include <shared/Bilateral.h>
|
||||
|
||||
#include <gpu/DrawTransformUnitQuad_vert.h>
|
||||
#include <gpu/DrawTexcoordRectTransformUnitQuad_vert.h>
|
||||
#include <gpu/DrawViewportQuadTransformTexcoord_vert.h>
|
||||
#include <gpu/DrawTexture_frag.h>
|
||||
#include <gpu/DrawTextureOpaque_frag.h>
|
||||
#include <gpu/DrawColoredTexture_frag.h>
|
||||
|
||||
#include <render-utils/simple_vert.h>
|
||||
#include <render-utils/simple_frag.h>
|
||||
#include <render-utils/simple_textured_frag.h>
|
||||
#include <render-utils/simple_textured_unlit_frag.h>
|
||||
|
||||
#include <render-utils/deferred_light_vert.h>
|
||||
#include <render-utils/deferred_light_point_vert.h>
|
||||
#include <render-utils/deferred_light_spot_vert.h>
|
||||
|
||||
#include <render-utils/directional_ambient_light_frag.h>
|
||||
#include <render-utils/directional_skybox_light_frag.h>
|
||||
|
||||
#include <render-utils/standardTransformPNTC_vert.h>
|
||||
#include <render-utils/standardDrawTexture_frag.h>
|
||||
|
||||
#include <render-utils/model_vert.h>
|
||||
#include <render-utils/model_shadow_vert.h>
|
||||
#include <render-utils/model_normal_map_vert.h>
|
||||
#include <render-utils/model_lightmap_vert.h>
|
||||
#include <render-utils/model_lightmap_normal_map_vert.h>
|
||||
#include <render-utils/skin_model_vert.h>
|
||||
#include <render-utils/skin_model_shadow_vert.h>
|
||||
#include <render-utils/skin_model_normal_map_vert.h>
|
||||
|
||||
#include <render-utils/model_frag.h>
|
||||
#include <render-utils/model_shadow_frag.h>
|
||||
#include <render-utils/model_normal_map_frag.h>
|
||||
#include <render-utils/model_normal_specular_map_frag.h>
|
||||
#include <render-utils/model_specular_map_frag.h>
|
||||
#include <render-utils/model_lightmap_frag.h>
|
||||
#include <render-utils/model_lightmap_normal_map_frag.h>
|
||||
#include <render-utils/model_lightmap_normal_specular_map_frag.h>
|
||||
#include <render-utils/model_lightmap_specular_map_frag.h>
|
||||
#include <render-utils/model_translucent_frag.h>
|
||||
#include <render-utils/overlay3D_vert.h>
|
||||
#include <render-utils/overlay3D_frag.h>
|
||||
|
||||
#include <render-utils/sdf_text3D_vert.h>
|
||||
#include <render-utils/sdf_text3D_frag.h>
|
||||
|
||||
#if 0
|
||||
#include <model/skybox_vert.h>
|
||||
#include <model/skybox_frag.h>
|
||||
#include <entities-renderer/textured_particle_frag.h>
|
||||
#include <entities-renderer/textured_particle_vert.h>
|
||||
#include <entities-renderer/paintStroke_vert.h>
|
||||
#include <entities-renderer/paintStroke_frag.h>
|
||||
#include <entities-renderer/polyvox_vert.h>
|
||||
#include <entities-renderer/polyvox_frag.h>
|
||||
#endif
|
||||
|
||||
|
||||
template <typename F>
|
||||
void withFrameBuffer(gvr::Frame& frame, int32_t index, F f) {
|
||||
frame.BindBuffer(index);
|
||||
f();
|
||||
frame.Unbind();
|
||||
}
|
||||
|
||||
|
||||
static const uint64_t kPredictionTimeWithoutVsyncNanos = 50000000;
|
||||
|
||||
// Each shader has two variants: a single-eye ES 2.0 variant, and a multiview
|
||||
// ES 3.0 variant. The multiview vertex shaders use transforms defined by
|
||||
// arrays of mat4 uniforms, using gl_ViewID_OVR to determine the array index.
|
||||
|
||||
#define UNIFORM_LIGHT_POS 20
|
||||
#define UNIFORM_M 16
|
||||
#define UNIFORM_MV 8
|
||||
#define UNIFORM_MVP 0
|
||||
|
||||
#if 0
|
||||
uniform Transform { // API uses “Transform[2]” to refer to instance 2
|
||||
mat4 u_MVP[2];
|
||||
mat4 u_MVMatrix[2];
|
||||
mat4 u_Model;
|
||||
vec3 u_LightPos[2];
|
||||
};
|
||||
static const char *kDiffuseLightingVertexShader = R"glsl(
|
||||
#version 300 es
|
||||
#extension GL_OVR_multiview2 : enable
|
||||
|
||||
layout(num_views=2) in;
|
||||
|
||||
layout(location = 0) uniform mat4 u_MVP[2];
|
||||
layout(location = 8) uniform mat4 u_MVMatrix[2];
|
||||
layout(location = 16) uniform mat4 u_Model;
|
||||
layout(location = 20) uniform vec3 u_LightPos[2];
|
||||
|
||||
layout(location = 0) in vec4 a_Position;
|
||||
layout(location = 1) in vec4 a_Color;
|
||||
layout(location = 2) in vec3 a_Normal;
|
||||
|
||||
out vec4 v_Color;
|
||||
out vec3 v_Grid;
|
||||
|
||||
void main() {
|
||||
mat4 mvp = u_MVP[gl_ViewID_OVR];
|
||||
mat4 modelview = u_MVMatrix[gl_ViewID_OVR];
|
||||
vec3 lightpos = u_LightPos[gl_ViewID_OVR];
|
||||
v_Grid = vec3(u_Model * a_Position);
|
||||
vec3 modelViewVertex = vec3(modelview * a_Position);
|
||||
vec3 modelViewNormal = vec3(modelview * vec4(a_Normal, 0.0));
|
||||
float distance = length(lightpos - modelViewVertex);
|
||||
vec3 lightVector = normalize(lightpos - modelViewVertex);
|
||||
float diffuse = max(dot(modelViewNormal, lightVector), 0.5);
|
||||
diffuse = diffuse * (1.0 / (1.0 + (0.00001 * distance * distance)));
|
||||
v_Color = vec4(a_Color.rgb * diffuse, a_Color.a);
|
||||
gl_Position = mvp * a_Position;
|
||||
}
|
||||
)glsl";
|
||||
#endif
|
||||
|
||||
|
||||
static const char *kSimepleVertexShader = R"glsl(
|
||||
#version 300 es
|
||||
static const char *kSimepleVertexShader = R"glsl(#version 300 es
|
||||
#extension GL_OVR_multiview2 : enable
|
||||
|
||||
layout(num_views=2) in;
|
||||
|
@ -147,9 +23,7 @@ void main() {
|
|||
}
|
||||
)glsl";
|
||||
|
||||
|
||||
static const char *kPassthroughFragmentShader = R"glsl(
|
||||
#version 300 es
|
||||
static const char *kPassthroughFragmentShader = R"glsl(#version 300 es
|
||||
precision mediump float;
|
||||
in vec4 v_Color;
|
||||
out vec4 FragColor;
|
||||
|
@ -157,6 +31,17 @@ out vec4 FragColor;
|
|||
void main() { FragColor = v_Color; }
|
||||
)glsl";
|
||||
|
||||
|
||||
int LoadGLShader(int type, const char *shadercode) {
|
||||
GLuint result = 0;
|
||||
std::string shaderError;
|
||||
static const std::string SHADER_DEFINES;
|
||||
if (!gl::compileShader(type, shadercode, SHADER_DEFINES, result, shaderError)) {
|
||||
qWarning() << "QQQ" << __FUNCTION__ << "Shader compile failure" << shaderError.c_str();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void CheckGLError(const char* label) {
|
||||
int gl_error = glGetError();
|
||||
if (gl_error != GL_NO_ERROR) {
|
||||
|
@ -167,158 +52,6 @@ static void CheckGLError(const char* label) {
|
|||
}
|
||||
|
||||
// Contains vertex, normal and other data.
|
||||
namespace cube {
|
||||
const std::array<float, 108> CUBE_COORDS{{
|
||||
// Front face
|
||||
-1.0f, 1.0f, 1.0f,
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
1.0f, -1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
|
||||
// Right face
|
||||
1.0f, 1.0f, 1.0f,
|
||||
1.0f, -1.0f, 1.0f,
|
||||
1.0f, 1.0f, -1.0f,
|
||||
1.0f, -1.0f, 1.0f,
|
||||
1.0f, -1.0f, -1.0f,
|
||||
1.0f, 1.0f, -1.0f,
|
||||
|
||||
// Back face
|
||||
1.0f, 1.0f, -1.0f,
|
||||
1.0f, -1.0f, -1.0f,
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
1.0f, -1.0f, -1.0f,
|
||||
-1.0f, -1.0f, -1.0f,
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
|
||||
// Left face
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
-1.0f, -1.0f, -1.0f,
|
||||
-1.0f, 1.0f, 1.0f,
|
||||
-1.0f, -1.0f, -1.0f,
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
-1.0f, 1.0f, 1.0f,
|
||||
|
||||
// Top face
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
-1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, -1.0f,
|
||||
-1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, -1.0f,
|
||||
|
||||
// Bottom face
|
||||
1.0f, -1.0f, -1.0f,
|
||||
1.0f, -1.0f, 1.0f,
|
||||
-1.0f, -1.0f, -1.0f,
|
||||
1.0f, -1.0f, 1.0f,
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
-1.0f, -1.0f, -1.0f
|
||||
}};
|
||||
|
||||
const std::array<float, 108> CUBE_COLORS{{
|
||||
// front, green
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
|
||||
// right, blue
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
|
||||
// back, also green
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
0.0f, 0.5273f, 0.2656f,
|
||||
|
||||
// left, also blue
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
0.0f, 0.3398f, 0.9023f,
|
||||
|
||||
// top, red
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
|
||||
// bottom, also red
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f,
|
||||
0.8359375f, 0.17578125f, 0.125f
|
||||
}};
|
||||
|
||||
const std::array<float, 108> CUBE_NORMALS{{
|
||||
// Front face
|
||||
0.0f, 0.0f, 1.0f,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
|
||||
// Right face
|
||||
1.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
|
||||
// Back face
|
||||
0.0f, 0.0f, -1.0f,
|
||||
0.0f, 0.0f, -1.0f,
|
||||
0.0f, 0.0f, -1.0f,
|
||||
0.0f, 0.0f, -1.0f,
|
||||
0.0f, 0.0f, -1.0f,
|
||||
0.0f, 0.0f, -1.0f,
|
||||
|
||||
// Left face
|
||||
-1.0f, 0.0f, 0.0f,
|
||||
-1.0f, 0.0f, 0.0f,
|
||||
-1.0f, 0.0f, 0.0f,
|
||||
-1.0f, 0.0f, 0.0f,
|
||||
-1.0f, 0.0f, 0.0f,
|
||||
-1.0f, 0.0f, 0.0f,
|
||||
|
||||
// Top face
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
|
||||
// Bottom face
|
||||
0.0f, -1.0f, 0.0f,
|
||||
0.0f, -1.0f, 0.0f,
|
||||
0.0f, -1.0f, 0.0f,
|
||||
0.0f, -1.0f, 0.0f,
|
||||
0.0f, -1.0f, 0.0f,
|
||||
0.0f, -1.0f, 0.0f
|
||||
}};
|
||||
}
|
||||
|
||||
namespace triangle {
|
||||
static std::array<float, 9> TRIANGLE_VERTS {{
|
||||
-0.5f, -0.5f, 0.0f,
|
||||
|
@ -327,229 +60,36 @@ namespace triangle {
|
|||
}};
|
||||
}
|
||||
|
||||
std::array<gvr::BufferViewport, 2> buildViewports(const std::unique_ptr<gvr::GvrApi> &gvrapi) {
|
||||
return { {gvrapi->CreateBufferViewport(), gvrapi->CreateBufferViewport()} };
|
||||
};
|
||||
|
||||
const std::string VERTEX_SHADER_DEFINES{ R"GLSL(
|
||||
#version 300 es
|
||||
#extension GL_EXT_clip_cull_distance : enable
|
||||
#define GPU_VERTEX_SHADER
|
||||
#define GPU_SSBO_TRANSFORM_OBJECT 1
|
||||
#define GPU_TRANSFORM_IS_STEREO
|
||||
#define GPU_TRANSFORM_STEREO_CAMERA
|
||||
#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED
|
||||
#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN
|
||||
)GLSL" };
|
||||
|
||||
const std::string PIXEL_SHADER_DEFINES{ R"GLSL(
|
||||
#version 300 es
|
||||
precision mediump float;
|
||||
#define GPU_PIXEL_SHADER
|
||||
#define GPU_TRANSFORM_IS_STEREO
|
||||
#define GPU_TRANSFORM_STEREO_CAMERA
|
||||
#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED
|
||||
#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN
|
||||
)GLSL" };
|
||||
|
||||
|
||||
#if defined(GVR)
|
||||
NativeRenderer::NativeRenderer(gvr_context *vrContext) :
|
||||
_gvrapi(new gvr::GvrApi(vrContext, false)),
|
||||
_viewports(buildViewports(_gvrapi)),
|
||||
_gvr_viewer_type(_gvrapi->GetViewerType())
|
||||
#else
|
||||
NativeRenderer::NativeRenderer(void *vrContext)
|
||||
#endif
|
||||
{
|
||||
start = std::chrono::system_clock::now();
|
||||
qDebug() << "QQQ" << __FUNCTION__;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a raw text file, saved as a resource, into an OpenGL ES shader.
|
||||
*
|
||||
* @param type The type of shader we will be creating.
|
||||
* @param resId The resource ID of the raw text file.
|
||||
* @return The shader object handler.
|
||||
*/
|
||||
int LoadGLShader(int type, const char *shadercode) {
|
||||
GLuint result = 0;
|
||||
std::string shaderError;
|
||||
static const std::string SHADER_DEFINES;
|
||||
if (!gl::compileShader(type, shadercode, SHADER_DEFINES, result, shaderError)) {
|
||||
qWarning() << "QQQ" << __FUNCTION__ << "Shader compile failure" << shaderError.c_str();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Computes a texture size that has approximately half as many pixels. This is
|
||||
// equivalent to scaling each dimension by approximately sqrt(2)/2.
|
||||
static gvr::Sizei HalfPixelCount(const gvr::Sizei &in) {
|
||||
// Scale each dimension by sqrt(2)/2 ~= 7/10ths.
|
||||
gvr::Sizei out;
|
||||
out.width = (7 * in.width) / 10;
|
||||
out.height = (7 * in.height) / 10;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#if defined(GVR)
|
||||
void NativeRenderer::InitializeVR() {
|
||||
_gvrapi->InitializeGl();
|
||||
bool multiviewEnabled = _gvrapi->IsFeatureSupported(GVR_FEATURE_MULTIVIEW);
|
||||
qWarning() << "QQQ" << __FUNCTION__ << "Multiview enabled " << multiviewEnabled;
|
||||
// Because we are using 2X MSAA, we can render to half as many pixels and
|
||||
// achieve similar quality.
|
||||
_renderSize = HalfPixelCount(_gvrapi->GetMaximumEffectiveRenderTargetSize());
|
||||
|
||||
std::vector<gvr::BufferSpec> specs;
|
||||
specs.push_back(_gvrapi->CreateBufferSpec());
|
||||
specs[0].SetColorFormat(GVR_COLOR_FORMAT_RGBA_8888);
|
||||
specs[0].SetDepthStencilFormat(GVR_DEPTH_STENCIL_FORMAT_DEPTH_16);
|
||||
specs[0].SetSamples(2);
|
||||
gvr::Sizei half_size = {_renderSize.width / 2, _renderSize.height};
|
||||
specs[0].SetMultiviewLayers(2);
|
||||
specs[0].SetSize(half_size);
|
||||
|
||||
_swapchain.reset(new gvr::SwapChain(_gvrapi->CreateSwapChain(specs)));
|
||||
_viewportlist.reset(new gvr::BufferViewportList(_gvrapi->CreateEmptyBufferViewportList()));
|
||||
}
|
||||
void NativeRenderer::PrepareFramebuffer() {
|
||||
const gvr::Sizei recommended_size = HalfPixelCount(
|
||||
_gvrapi->GetMaximumEffectiveRenderTargetSize());
|
||||
if (_renderSize.width != recommended_size.width ||
|
||||
_renderSize.height != recommended_size.height) {
|
||||
// We need to resize the framebuffer. Note that multiview uses two texture
|
||||
// layers, each with half the render width.
|
||||
gvr::Sizei framebuffer_size = recommended_size;
|
||||
framebuffer_size.width /= 2;
|
||||
_swapchain->ResizeBuffer(0, framebuffer_size);
|
||||
_renderSize = recommended_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void testShaderBuild(const char* vs_src, const char * fs_src) {
|
||||
std::string error;
|
||||
GLuint vs, fs;
|
||||
if (!gl::compileShader(GL_VERTEX_SHADER, vs_src, VERTEX_SHADER_DEFINES, vs, error) ||
|
||||
!gl::compileShader(GL_FRAGMENT_SHADER, fs_src, PIXEL_SHADER_DEFINES, fs, error)) {
|
||||
throw std::runtime_error("Failed to compile shader");
|
||||
}
|
||||
auto pr = gl::compileProgram({ vs, fs }, error);
|
||||
if (!pr) {
|
||||
throw std::runtime_error("Failed to link shader");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeRenderer::InitializeGl() {
|
||||
qDebug() << "QQQ" << __FUNCTION__;
|
||||
//gl::initModuleGl();
|
||||
#if defined(GVR)
|
||||
InitializeVR();
|
||||
#endif
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
|
||||
|
||||
const uint32_t vertShader = LoadGLShader(GL_VERTEX_SHADER, kSimepleVertexShader);
|
||||
//const uint32_t vertShader = LoadGLShader(GL_VERTEX_SHADER, kDiffuseLightingVertexShader);
|
||||
const uint32_t fragShader = LoadGLShader(GL_FRAGMENT_SHADER, kPassthroughFragmentShader);
|
||||
std::string error;
|
||||
_cubeProgram = gl::compileProgram({ vertShader, fragShader }, error);
|
||||
_program = gl::compileProgram({ vertShader, fragShader }, error);
|
||||
CheckGLError("build program");
|
||||
|
||||
glGenBuffers(1, &_cubeBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _cubeBuffer);
|
||||
glGenBuffers(1, &_geometryBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _geometryBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 9, triangle::TRIANGLE_VERTS.data(), GL_STATIC_DRAW);
|
||||
/*
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 3, NULL, GL_STATIC_DRAW);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 0, sizeof(float) * 108, cube::CUBE_COORDS.data());
|
||||
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 1, sizeof(float) * 108, cube::CUBE_COLORS.data());
|
||||
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 2, sizeof(float) * 108, cube::CUBE_NORMALS.data());
|
||||
*/
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CheckGLError("upload vertices");
|
||||
|
||||
glGenVertexArrays(1, &_cubeVao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _cubeBuffer);
|
||||
glBindVertexArray(_cubeVao);
|
||||
glGenVertexArrays(1, &_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _geometryBuffer);
|
||||
glBindVertexArray(_vao);
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
/*
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, (const void*)(sizeof(float) * 108 * 1) );
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(2, 3, GL_FLOAT, false, 0, (const void*)(sizeof(float) * 108 * 2));
|
||||
glEnableVertexAttribArray(2);
|
||||
*/
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CheckGLError("build vao ");
|
||||
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]{
|
||||
testShaderBuild(sdf_text3D_vert, sdf_text3D_frag);
|
||||
|
||||
testShaderBuild(DrawTransformUnitQuad_vert, DrawTexture_frag);
|
||||
testShaderBuild(DrawTexcoordRectTransformUnitQuad_vert, DrawTexture_frag);
|
||||
testShaderBuild(DrawViewportQuadTransformTexcoord_vert, DrawTexture_frag);
|
||||
testShaderBuild(DrawTransformUnitQuad_vert, DrawTextureOpaque_frag);
|
||||
testShaderBuild(DrawTransformUnitQuad_vert, DrawColoredTexture_frag);
|
||||
|
||||
testShaderBuild(simple_vert, simple_frag);
|
||||
testShaderBuild(simple_vert, simple_textured_frag);
|
||||
testShaderBuild(simple_vert, simple_textured_unlit_frag);
|
||||
testShaderBuild(deferred_light_vert, directional_ambient_light_frag);
|
||||
testShaderBuild(deferred_light_vert, directional_skybox_light_frag);
|
||||
testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag);
|
||||
testShaderBuild(standardTransformPNTC_vert, DrawTextureOpaque_frag);
|
||||
|
||||
testShaderBuild(model_vert, model_frag);
|
||||
testShaderBuild(model_normal_map_vert, model_normal_map_frag);
|
||||
testShaderBuild(model_vert, model_specular_map_frag);
|
||||
testShaderBuild(model_normal_map_vert, model_normal_specular_map_frag);
|
||||
testShaderBuild(model_vert, model_translucent_frag);
|
||||
testShaderBuild(model_normal_map_vert, model_translucent_frag);
|
||||
testShaderBuild(model_lightmap_vert, model_lightmap_frag);
|
||||
testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_map_frag);
|
||||
testShaderBuild(model_lightmap_vert, model_lightmap_specular_map_frag);
|
||||
testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_specular_map_frag);
|
||||
|
||||
testShaderBuild(skin_model_vert, model_frag);
|
||||
testShaderBuild(skin_model_normal_map_vert, model_normal_map_frag);
|
||||
testShaderBuild(skin_model_vert, model_specular_map_frag);
|
||||
testShaderBuild(skin_model_normal_map_vert, model_normal_specular_map_frag);
|
||||
testShaderBuild(skin_model_vert, model_translucent_frag);
|
||||
testShaderBuild(skin_model_normal_map_vert, model_translucent_frag);
|
||||
|
||||
testShaderBuild(model_shadow_vert, model_shadow_frag);
|
||||
|
||||
testShaderBuild(overlay3D_vert, overlay3D_frag);
|
||||
|
||||
#if 0
|
||||
testShaderBuild(textured_particle_vert, textured_particle_frag);
|
||||
testShaderBuild(skybox_vert, skybox_frag);
|
||||
testShaderBuild(paintStroke_vert,paintStroke_frag);
|
||||
testShaderBuild(polyvox_vert, polyvox_frag);
|
||||
#endif
|
||||
|
||||
});
|
||||
|
||||
qDebug() << "done";
|
||||
}
|
||||
|
||||
static const float kZNear = 1.0f;
|
||||
static const float kZFar = 100.0f;
|
||||
static const gvr_rectf fullscreen = {0, 1, 0, 1};
|
||||
|
||||
void NativeRenderer::DrawFrame() {
|
||||
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
|
@ -559,65 +99,12 @@ void NativeRenderer::DrawFrame() {
|
|||
v.g = 1.0f - v.r;
|
||||
v.b = 1.0f;
|
||||
|
||||
PrepareFramebuffer();
|
||||
|
||||
// A client app does its rendering here.
|
||||
gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow();
|
||||
target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos;
|
||||
|
||||
using namespace googlevr;
|
||||
using namespace bilateral;
|
||||
const auto gvrHeadPose = _gvrapi->GetHeadSpaceFromStartSpaceRotation(target_time);
|
||||
_head_view = toGlm(gvrHeadPose);
|
||||
_viewportlist->SetToRecommendedBufferViewports();
|
||||
|
||||
glm::mat4 eye_views[2];
|
||||
for_each_side([&](bilateral::Side side) {
|
||||
int eye = index(side);
|
||||
const gvr::Eye gvr_eye = eye == 0 ? GVR_LEFT_EYE : GVR_RIGHT_EYE;
|
||||
const auto& eyeView = eye_views[eye] = toGlm(_gvrapi->GetEyeFromHeadMatrix(gvr_eye)) * _head_view;
|
||||
auto& viewport = _viewports[eye];
|
||||
|
||||
_viewportlist->GetBufferViewport(eye, &viewport);
|
||||
viewport.SetSourceUv(fullscreen);
|
||||
viewport.SetSourceLayer(eye);
|
||||
_viewportlist->SetBufferViewport(eye, viewport);
|
||||
const auto &mvc = _modelview_cube[eye] = eyeView * _model_cube;
|
||||
const auto &mvf = _modelview_floor[eye] = eyeView * _model_floor;
|
||||
const gvr_rectf fov = viewport.GetSourceFov();
|
||||
const glm::mat4 perspective = perspectiveMatrixFromView(fov, kZNear, kZFar);
|
||||
_modelview_projection_cube[eye] = perspective * mvc;
|
||||
_modelview_projection_floor[eye] = perspective * mvf;
|
||||
_light_pos_eye_space[eye] = glm::vec3(eyeView * _light_pos_world_space);
|
||||
});
|
||||
|
||||
|
||||
gvr::Frame frame = _swapchain->AcquireFrame();
|
||||
withFrameBuffer(frame, 0, [&]{
|
||||
glClearColor(v.r, v.g, v.b, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glViewport(0, 0, _renderSize.width / 2, _renderSize.height);
|
||||
glUseProgram(_cubeProgram);
|
||||
glBindVertexArray(_cubeVao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
/*
|
||||
float* fp;
|
||||
fp = (float*)&_light_pos_eye_space[0];
|
||||
glUniform3fv(UNIFORM_LIGHT_POS, 2, fp);
|
||||
fp = (float*)&_modelview_cube[0];
|
||||
glUniformMatrix4fv(UNIFORM_MV, 2, GL_FALSE, fp);
|
||||
fp = (float*)&_modelview_projection_cube[0];
|
||||
glUniformMatrix4fv(UNIFORM_MVP, 2, GL_FALSE, fp);
|
||||
fp = (float*)&_model_cube;
|
||||
glUniformMatrix4fv(UNIFORM_M, 1, GL_FALSE, fp);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||
*/
|
||||
glBindVertexArray(0);
|
||||
});
|
||||
|
||||
frame.Submit(*_viewportlist, gvrHeadPose);
|
||||
CheckGLError("onDrawFrame");
|
||||
|
||||
glClearColor(v.r, v.g, v.b, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glUseProgram(_program);
|
||||
glBindVertexArray(_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void NativeRenderer::OnTriggerEvent() {
|
||||
|
@ -626,11 +113,8 @@ void NativeRenderer::OnTriggerEvent() {
|
|||
|
||||
void NativeRenderer::OnPause() {
|
||||
qDebug() << "QQQ" << __FUNCTION__;
|
||||
_gvrapi->PauseTracking();
|
||||
}
|
||||
|
||||
void NativeRenderer::OnResume() {
|
||||
qDebug() << "QQQ" << __FUNCTION__;
|
||||
_gvrapi->ResumeTracking();
|
||||
_gvrapi->RefreshViewerProfile();
|
||||
}
|
||||
|
|
|
@ -4,21 +4,8 @@
|
|||
#include <array>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#define GVR
|
||||
|
||||
#if defined(GVR)
|
||||
#include <vr/gvr/capi/include/gvr.h>
|
||||
#endif
|
||||
|
||||
class NativeRenderer {
|
||||
public:
|
||||
|
||||
#if defined(GVR)
|
||||
NativeRenderer(gvr_context* vrContext);
|
||||
#else
|
||||
NativeRenderer(void* vrContext);
|
||||
#endif
|
||||
|
||||
void InitializeGl();
|
||||
void DrawFrame();
|
||||
void OnTriggerEvent();
|
||||
|
@ -26,35 +13,9 @@ public:
|
|||
void OnResume();
|
||||
|
||||
private:
|
||||
std::chrono::time_point<std::chrono::system_clock> start { std::chrono::system_clock::now() };
|
||||
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> start;
|
||||
#if defined(GVR)
|
||||
void InitializeVR();
|
||||
void PrepareFramebuffer();
|
||||
|
||||
std::unique_ptr<gvr::GvrApi> _gvrapi;
|
||||
gvr::ViewerType _gvr_viewer_type;
|
||||
std::unique_ptr<gvr::BufferViewportList> _viewportlist;
|
||||
std::unique_ptr<gvr::SwapChain> _swapchain;
|
||||
std::array<gvr::BufferViewport, 2> _viewports;
|
||||
gvr::Sizei _renderSize;
|
||||
#endif
|
||||
|
||||
uint32_t _cubeBuffer { 0 };
|
||||
uint32_t _cubeVao { 0 };
|
||||
uint32_t _cubeProgram { 0 };
|
||||
|
||||
glm::mat4 _head_view;
|
||||
glm::mat4 _model_cube;
|
||||
glm::mat4 _camera;
|
||||
glm::mat4 _view;
|
||||
glm::mat4 _model_floor;
|
||||
|
||||
std::array<glm::mat4, 2> _modelview_cube;
|
||||
std::array<glm::mat4, 2> _modelview_floor;
|
||||
std::array<glm::mat4, 2> _modelview_projection_cube;
|
||||
std::array<glm::mat4, 2> _modelview_projection_floor;
|
||||
std::array<glm::vec3, 2> _light_pos_eye_space;
|
||||
const glm::vec4 _light_pos_world_space{ 0, 2, 0, 1};
|
||||
uint32_t _geometryBuffer { 0 };
|
||||
uint32_t _vao { 0 };
|
||||
uint32_t _program { 0 };
|
||||
};
|
||||
|
|
|
@ -26,10 +26,9 @@ public class MainActivity extends Activity {
|
|||
}
|
||||
|
||||
private long nativeRenderer;
|
||||
private GvrLayout gvrLayout;
|
||||
private GLSurfaceView surfaceView;
|
||||
|
||||
private native long nativeCreateRenderer(ClassLoader appClassLoader, Context context, long nativeGvrContext);
|
||||
private native long nativeCreateRenderer(ClassLoader appClassLoader, Context context);
|
||||
private native void nativeDestroyRenderer(long renderer);
|
||||
private native void nativeInitializeGl(long renderer);
|
||||
private native void nativeDrawFrame(long renderer);
|
||||
|
@ -55,30 +54,21 @@ public class MainActivity extends Activity {
|
|||
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { setImmersiveSticky(); }
|
||||
});
|
||||
|
||||
gvrLayout = new GvrLayout(this);
|
||||
nativeRenderer = nativeCreateRenderer(
|
||||
getClass().getClassLoader(),
|
||||
getApplicationContext(),
|
||||
gvrLayout.getGvrApi().getNativeGvrContext());
|
||||
getApplicationContext());
|
||||
|
||||
surfaceView = new GLSurfaceView(this);
|
||||
surfaceView.setEGLContextClientVersion(3);
|
||||
surfaceView.setEGLConfigChooser(8, 8, 8, 0, 0, 0);
|
||||
surfaceView.setPreserveEGLContextOnPause(true);
|
||||
surfaceView.setRenderer(new NativeRenderer());
|
||||
|
||||
gvrLayout.setPresentationView(surfaceView);
|
||||
setContentView(gvrLayout);
|
||||
if (gvrLayout.setAsyncReprojectionEnabled(true)) {
|
||||
AndroidCompat.setSustainedPerformanceMode(this, true);
|
||||
}
|
||||
AndroidCompat.setVrModeEnabled(this, true);
|
||||
setContentView(surfaceView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
gvrLayout.shutdown();
|
||||
nativeDestroyRenderer(nativeRenderer);
|
||||
nativeRenderer = 0;
|
||||
}
|
||||
|
@ -87,14 +77,12 @@ public class MainActivity extends Activity {
|
|||
protected void onPause() {
|
||||
surfaceView.queueEvent(()->nativeOnPause(nativeRenderer));
|
||||
surfaceView.onPause();
|
||||
gvrLayout.onPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
gvrLayout.onResume();
|
||||
surfaceView.onResume();
|
||||
surfaceView.queueEvent(()->nativeOnResume(nativeRenderer));
|
||||
}
|
||||
|
|
|
@ -1,91 +1,216 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'de.undercouch.download' version '3.3.0'
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def baseFolder = new File(HIFI_ANDROID_PRECOMPILED)
|
||||
def jniFolder = new File('app/src/main/jniLibs/arm64-v8a')
|
||||
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
def baseUrl = 'https://hifi-public.s3.amazonaws.com/austin/android/'
|
||||
def qtFile='qt-5.9.3_linux_armv8-libcpp.tgz'
|
||||
def qtChecksum='547da3547d5690144e23d6504c6d6e91'
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||
qtFile = 'qt-5.9.3_osx_armv8-libcpp.tgz'
|
||||
qtChecksum='6fa3e068cfdee863fc909b294a3a0cc6'
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
qtFile = 'qt-5.9.3_win_armv8-libcpp.tgz'
|
||||
qtChecksum='3a757378a7e9dbbfc662177e0eb46408'
|
||||
}
|
||||
|
||||
def packages = [
|
||||
qt: [
|
||||
file: qtFile,
|
||||
checksum: qtChecksum,
|
||||
sharedLibFolder: '',
|
||||
includeLibs: ['lib/*.so', 'plugins/*/*.so']
|
||||
],
|
||||
bullet: [
|
||||
file: 'bullet-2.83_armv8-libcpp.tgz',
|
||||
checksum: '2c558d604fce337f5eba3eb7ec1252fd'
|
||||
],
|
||||
draco: [
|
||||
file: 'draco_armv8-libcpp.tgz',
|
||||
checksum: '617a80d213a5ec69fbfa21a1f2f738cd'
|
||||
],
|
||||
gvr: [
|
||||
file: 'gvrsdk_v1.101.0.tgz',
|
||||
checksum: '57fd02baa069176ba18597a29b6b4fc7'
|
||||
],
|
||||
openssl: [
|
||||
file: 'openssl-1.1.0g_armv8.tgz',
|
||||
checksum: 'cabb681fbccd79594f65fcc266e02f32'
|
||||
],
|
||||
polyvox: [
|
||||
file: 'polyvox_armv8-libcpp.tgz',
|
||||
checksum: '5c918288741ee754c16aeb12bb46b9e1',
|
||||
sharedLibFolder: 'lib',
|
||||
includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so']
|
||||
],
|
||||
tbb: [
|
||||
file: 'tbb-2018_U1_armv8_libcpp.tgz',
|
||||
checksum: '20768f298f53b195e71b414b0ae240c4',
|
||||
sharedLibFolder: 'lib/release',
|
||||
includeLibs: ['libtbb.so', 'libtbbmalloc.so']
|
||||
]
|
||||
]
|
||||
|
||||
task downloadDependencies {
|
||||
doLast {
|
||||
packages.each { entry ->
|
||||
def filename = entry.value['file'];
|
||||
def url = baseUrl + filename;
|
||||
download {
|
||||
src url
|
||||
dest new File(baseFolder, filename)
|
||||
onlyIfNewer true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import de.undercouch.gradle.tasks.download.Verify
|
||||
|
||||
task verifyQt(type: Verify) { def p = packages['qt']; src new File(baseFolder, p['file']); checksum p['checksum']; }
|
||||
task verifyBullet(type: Verify) { def p = packages['bullet']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyDraco(type: Verify) { def p = packages['draco']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyGvr(type: Verify) { def p = packages['gvr']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyOpenSSL(type: Verify) { def p = packages['openssl']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyPolyvox(type: Verify) { def p = packages['polyvox']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
task verifyTBB(type: Verify) { def p = packages['tbb']; src new File(baseFolder, p['file']); checksum p['checksum'] }
|
||||
|
||||
task verifyDependencyDownloads(dependsOn: downloadDependencies) { }
|
||||
verifyDependencyDownloads.dependsOn verifyQt
|
||||
verifyDependencyDownloads.dependsOn verifyBullet
|
||||
verifyDependencyDownloads.dependsOn verifyDraco
|
||||
verifyDependencyDownloads.dependsOn verifyGvr
|
||||
verifyDependencyDownloads.dependsOn verifyOpenSSL
|
||||
verifyDependencyDownloads.dependsOn verifyPolyvox
|
||||
verifyDependencyDownloads.dependsOn verifyTBB
|
||||
|
||||
task extractDependencies(dependsOn: verifyDependencyDownloads) {
|
||||
doLast {
|
||||
packages.each { entry ->
|
||||
def folder = entry.key;
|
||||
def filename = entry.value['file'];
|
||||
def localFile = new File(HIFI_ANDROID_PRECOMPILED, filename)
|
||||
def localFolder = new File(HIFI_ANDROID_PRECOMPILED, folder)
|
||||
copy {
|
||||
from tarTree(resources.gzip(localFile))
|
||||
into localFolder
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task copyDependencies(dependsOn: extractDependencies) {
|
||||
doLast {
|
||||
packages.each { entry ->
|
||||
def packageName = entry.key
|
||||
def currentPackage = entry.value;
|
||||
if (currentPackage.containsKey('sharedLibFolder')) {
|
||||
def localFolder = new File(baseFolder, packageName + '/' + currentPackage['sharedLibFolder'])
|
||||
def tree = fileTree(localFolder);
|
||||
if (currentPackage.containsKey('includeLibs')) {
|
||||
currentPackage['includeLibs'].each { includeSpec -> tree.include includeSpec }
|
||||
}
|
||||
tree.visit { element ->
|
||||
if (!element.file.isDirectory()) {
|
||||
copy { from element.file; into jniFolder }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def scribeFile='scribe_linux_x86_64'
|
||||
def scribeLocalFile='scribe'
|
||||
def scribeChecksum='c98678d9726bd8bbf1bab792acf3ff6c'
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||
scribeFile = 'scribe_osx_x86_64'
|
||||
scribeChecksum='a137ad62c1bf7cca739da219544a9a16'
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
scribeFile = 'scribe_win32_x86_64.exe'
|
||||
scribeLocalFile = 'scribe.exe'
|
||||
scribeChecksum='75c2ce9ed45d17de375e3988bfaba816'
|
||||
|
||||
}
|
||||
|
||||
import de.undercouch.gradle.tasks.download.Download
|
||||
|
||||
task downloadScribe(type: Download) {
|
||||
src baseUrl + scribeFile
|
||||
dest new File(baseFolder, scribeLocalFile)
|
||||
onlyIfNewer true
|
||||
}
|
||||
|
||||
task verifyScribe (type: Verify, dependsOn: downloadScribe) {
|
||||
src new File(baseFolder, scribeLocalFile);
|
||||
checksum scribeChecksum
|
||||
}
|
||||
|
||||
task fixScribePermissions(type: Exec, dependsOn: verifyScribe) {
|
||||
commandLine 'chmod', 'a+x', HIFI_ANDROID_PRECOMPILED + '/' + scribeLocalFile
|
||||
}
|
||||
|
||||
task setupScribe(dependsOn: verifyScribe) { }
|
||||
|
||||
// On Windows, we don't need to set the executable bit, but on OSX and Unix we do
|
||||
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
setupScribe.dependsOn fixScribePermissions
|
||||
}
|
||||
|
||||
task extractGvrBinaries(dependsOn: extractDependencies) {
|
||||
doLast {
|
||||
def gvrLibFolder = new File(HIFI_ANDROID_PRECOMPILED, 'gvr/gvr-android-sdk-1.101.0/libraries');
|
||||
zipTree(new File(HIFI_ANDROID_PRECOMPILED, 'gvr/gvr-android-sdk-1.101.0/libraries/sdk-audio-1.101.0.aar')).visit { element ->
|
||||
def fileName = element.file.toString();
|
||||
if (fileName.endsWith('libgvr_audio.so') && fileName.contains('arm64-v8a')) {
|
||||
copy { from element.file; into gvrLibFolder }
|
||||
}
|
||||
}
|
||||
zipTree(new File(HIFI_ANDROID_PRECOMPILED, 'gvr/gvr-android-sdk-1.101.0/libraries/sdk-base-1.101.0.aar')).visit { element ->
|
||||
def fileName = element.file.toString();
|
||||
if (fileName.endsWith('libgvr.so') && fileName.contains('arm64-v8a')) {
|
||||
copy { from element.file; into gvrLibFolder }
|
||||
}
|
||||
}
|
||||
fileTree(gvrLibFolder).visit { element ->
|
||||
if (element.file.toString().endsWith('.so')) {
|
||||
copy { from element.file; into jniFolder }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
task setupDependencies(dependsOn: [setupScribe, copyDependencies, extractGvrBinaries]) {
|
||||
}
|
||||
|
||||
task cleanDependencies(type: Delete) {
|
||||
delete HIFI_ANDROID_PRECOMPILED
|
||||
delete 'app/src/main/jniLibs/arm64-v8a'
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
task extractQt5jars(type: Copy) {
|
||||
from fileTree(QT5_ROOT + "/jar")
|
||||
into("${project.rootDir}/libraries/jar")
|
||||
include("*.jar")
|
||||
}
|
||||
|
||||
task extractQt5so(type: Copy) {
|
||||
from fileTree(QT5_ROOT + "/lib")
|
||||
into("${project.rootDir}/libraries/jni/armeabi-v7a/")
|
||||
include("libQt5AndroidExtras.so")
|
||||
include("libQt5Concurrent.so")
|
||||
include("libQt5Core.so")
|
||||
include("libQt5Gamepad.so")
|
||||
include("libQt5Gui.so")
|
||||
include("libQt5Location.so")
|
||||
include("libQt5Multimedia.so")
|
||||
include("libQt5MultimediaQuick_p.so")
|
||||
include("libQt5Network.so")
|
||||
include("libQt5NetworkAuth.so")
|
||||
include("libQt5OpenGL.so")
|
||||
include("libQt5Positioning.so")
|
||||
include("libQt5Qml.so")
|
||||
include("libQt5Quick.so")
|
||||
include("libQt5QuickControls2.so")
|
||||
include("libQt5QuickParticles.so")
|
||||
include("libQt5QuickTemplates2.so")
|
||||
include("libQt5QuickWidgets.so")
|
||||
include("libQt5Script.so")
|
||||
include("libQt5ScriptTools.so")
|
||||
include("libQt5Sensors.so")
|
||||
include("libQt5Svg.so")
|
||||
include("libQt5WebChannel.so")
|
||||
include("libQt5WebSockets.so")
|
||||
include("libQt5WebView.so")
|
||||
include("libQt5Widgets.so")
|
||||
include("libQt5Xml.so")
|
||||
include("libQt5XmlPatterns.so")
|
||||
}
|
||||
|
||||
task extractAudioSo(type: Copy) {
|
||||
from zipTree(GVR_ROOT + "/libraries/sdk-audio-1.80.0.aar")
|
||||
into "${project.rootDir}/libraries/"
|
||||
include "jni/armeabi-v7a/libgvr_audio.so"
|
||||
}
|
||||
|
||||
task extractGvrSo(type: Copy) {
|
||||
from zipTree(GVR_ROOT + "/libraries/sdk-base-1.80.0.aar")
|
||||
into "${project.rootDir}/libraries/"
|
||||
include "jni/armeabi-v7a/libgvr.so"
|
||||
}
|
||||
|
||||
task extractNdk { }
|
||||
extractNdk.dependsOn extractAudioSo
|
||||
extractNdk.dependsOn extractGvrSo
|
||||
|
||||
task extractQt5 { }
|
||||
extractQt5.dependsOn extractQt5so
|
||||
extractQt5.dependsOn extractQt5jars
|
||||
|
||||
task extractBinaries { }
|
||||
extractBinaries.dependsOn extractQt5
|
||||
extractBinaries.dependsOn extractNdk
|
||||
|
||||
task deleteBinaries(type: Delete) {
|
||||
delete "${project.rootDir}/libraries/jni"
|
||||
}
|
||||
|
||||
//clean.dependsOn(deleteBinaries)
|
||||
|
|
41
android/setupGVR.gradle
Normal file
41
android/setupGVR.gradle
Normal file
|
@ -0,0 +1,41 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||
classpath 'de.undercouch:gradle-download-task:3.3.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def file='gvrsdk_v1.101.0.tgz'
|
||||
def url='https://hifi-public.s3.amazonaws.com/austin/android/' + file
|
||||
def destFile = new File(HIFI_ANDROID_PRECOMPILED, file)
|
||||
|
||||
// FIXME find a way to only download if the file doesn't exist
|
||||
task downloadGVR(type: de.undercouch.gradle.tasks.download.Download) {
|
||||
src url
|
||||
dest destFile
|
||||
}
|
||||
|
||||
task extractGVR(dependsOn: downloadGVR, type: Copy) {
|
||||
from tarTree(resources.gzip(destFile))
|
||||
into new File(HIFI_ANDROID_PRECOMPILED, 'gvr')
|
||||
}
|
||||
|
||||
task copyGVRAudioLibs(dependsOn: extractGVR, type: Copy) {
|
||||
from zipTree(new File(HIFI_ANDROID_PRECOMPILED, 'gvr/gvr-android-sdk-1.101.0/libraries/sdk-audio-1.101.0.aar'))
|
||||
include 'jni/arm64-v8a/libgvr_audio.so'
|
||||
into HIFI_ANDROID_PRECOMPILED
|
||||
}
|
||||
|
||||
task copyGVRLibs(dependsOn: extractGVR, type: Copy) {
|
||||
from zipTree(new File(HIFI_ANDROID_PRECOMPILED, 'gvr/gvr-android-sdk-1.101.0/libraries/sdk-base-1.101.0.aar'))
|
||||
include 'jni/arm64-v8a/libgvr.so'
|
||||
into HIFI_ANDROID_PRECOMPILED
|
||||
}
|
||||
|
||||
task setupGVR(dependsOn: [copyGVRLibs, copyGVRAudioLibs]) {
|
||||
}
|
17
cmake/macros/SetFromEnv.cmake
Normal file
17
cmake/macros/SetFromEnv.cmake
Normal file
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Created by Bradley Austin Davis on 2017/11/27
|
||||
# Copyright 2013-2017 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
function(set_from_env _RESULT_NAME _ENV_VAR_NAME _DEFAULT_VALUE)
|
||||
if (NOT DEFINED ${_RESULT_NAME})
|
||||
if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "")
|
||||
set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE)
|
||||
else()
|
||||
set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
|
@ -15,13 +15,14 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set(PR_BUILD 0)
|
||||
set(PRODUCTION_BUILD 0)
|
||||
set(DEV_BUILD 0)
|
||||
|
||||
set(RELEASE_TYPE $ENV{RELEASE_TYPE})
|
||||
set(RELEASE_NUMBER $ENV{RELEASE_NUMBER})
|
||||
string(TOLOWER "$ENV{BRANCH}" BUILD_BRANCH)
|
||||
set(BUILD_GLOBAL_SERVICES "DEVELOPMENT")
|
||||
set(USE_STABLE_GLOBAL_SERVICES 0)
|
||||
|
||||
set_from_env(RELEASE_TYPE RELEASE_TYPE "DEV")
|
||||
set_from_env(RELEASE_NUMBER RELEASE_NUMBER "")
|
||||
set_from_env(BUILD_BRANCH BRANCH "")
|
||||
string(TOLOWER "${BUILD_BRANCH}" BUILD_BRANCH)
|
||||
|
||||
message(STATUS "The BUILD_BRANCH variable is: ${BUILD_BRANCH}")
|
||||
message(STATUS "The BRANCH environment variable is: $ENV{BRANCH}")
|
||||
message(STATUS "The RELEASE_TYPE variable is: ${RELEASE_TYPE}")
|
||||
|
|
|
@ -1,21 +1,11 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
# Created by Bradley Austin Davis on 2017/09/02
|
||||
# Copyright 2013-2017 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
function(set_from_env _RESULT_NAME _ENV_VAR_NAME _DEFAULT_VALUE)
|
||||
if (NOT DEFINED ${_RESULT_NAME})
|
||||
if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "")
|
||||
set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE)
|
||||
else()
|
||||
set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Construct a default QT location from a root path, a version and an architecture
|
||||
function(calculate_default_qt_dir _RESULT_NAME)
|
||||
if (ANDROID)
|
||||
|
|
|
@ -6,8 +6,19 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_BULLET)
|
||||
add_dependency_external_projects(bullet)
|
||||
find_package(Bullet REQUIRED)
|
||||
if (ANDROID)
|
||||
set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/bullet)
|
||||
set(BULLET_INCLUDE_DIRS "${INSTALL_DIR}/include/bullet" CACHE TYPE INTERNAL)
|
||||
|
||||
set(LIB_DIR ${INSTALL_DIR}/lib)
|
||||
list(APPEND BULLET_LIBRARIES ${LIB_DIR}/libBulletDynamics.a)
|
||||
list(APPEND BULLET_LIBRARIES ${LIB_DIR}/libBulletCollision.a)
|
||||
list(APPEND BULLET_LIBRARIES ${LIB_DIR}/libLinearMath.a)
|
||||
list(APPEND BULLET_LIBRARIES ${LIB_DIR}/libBulletSoftBody.a)
|
||||
else()
|
||||
add_dependency_external_projects(bullet)
|
||||
find_package(Bullet REQUIRED)
|
||||
endif()
|
||||
# perform the system include hack for OS X to ignore warnings
|
||||
if (APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${BULLET_INCLUDE_DIRS}")
|
||||
|
@ -16,3 +27,5 @@ macro(TARGET_BULLET)
|
|||
endif()
|
||||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
endmacro()
|
||||
|
||||
|
||||
|
|
18
cmake/macros/TargetDraco.cmake
Executable file
18
cmake/macros/TargetDraco.cmake
Executable file
|
@ -0,0 +1,18 @@
|
|||
macro(TARGET_DRACO)
|
||||
if (ANDROID)
|
||||
set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/draco)
|
||||
set(DRACO_INCLUDE_DIRS "${INSTALL_DIR}/include" CACHE TYPE INTERNAL)
|
||||
|
||||
set(LIB_DIR ${INSTALL_DIR}/lib)
|
||||
list(APPEND DRACO_LIBRARIES ${LIB_DIR}/libdraco.a)
|
||||
list(APPEND DRACO_LIBRARIES ${LIB_DIR}/libdracodec.a)
|
||||
list(APPEND DRACO_LIBRARIES ${LIB_DIR}/libdracoenc.a)
|
||||
else()
|
||||
add_dependency_external_projects(draco)
|
||||
find_package(Draco REQUIRED)
|
||||
list(APPEND DRACO_LIBRARIES ${DRACO_LIBRARY})
|
||||
list(APPEND DRACO_LIBRARIES ${DRACO_ENCODER_LIBRARY})
|
||||
endif()
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${DRACO_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${DRACO_LIBRARIES})
|
||||
endmacro()
|
14
cmake/macros/TargetGoogleVR.cmake
Normal file
14
cmake/macros/TargetGoogleVR.cmake
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Created by Bradley Austin Davis on 2017/11/28
|
||||
# Copyright 2013-2017 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_GOOGLEVR)
|
||||
if (ANDROID)
|
||||
set(GVR_ROOT "${HIFI_ANDROID_PRECOMPILED}/gvr/gvr-android-sdk-1.101.0/")
|
||||
target_include_directories(native-lib PRIVATE "${GVR_ROOT}/libraries/headers")
|
||||
target_link_libraries(native-lib "${GVR_ROOT}/libraries/libgvr.so")
|
||||
endif()
|
||||
endmacro()
|
|
@ -6,14 +6,10 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_OPENSSL)
|
||||
|
||||
if (ANDROID)
|
||||
|
||||
# FIXME use a distributable binary
|
||||
set(OPENSSL_INSTALL_DIR C:/Android/openssl)
|
||||
set(OPENSSL_INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/openssl)
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_INSTALL_DIR}/include" CACHE TYPE INTERNAL)
|
||||
set(OPENSSL_LIBRARIES "${OPENSSL_INSTALL_DIR}/lib/libcrypto.a;${OPENSSL_INSTALL_DIR}/lib/libssl.a" CACHE TYPE INTERNAL)
|
||||
|
||||
else()
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
@ -28,5 +24,4 @@ macro(TARGET_OPENSSL)
|
|||
|
||||
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
||||
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
|
||||
|
||||
endmacro()
|
||||
|
|
24
cmake/macros/TargetPolyvox.cmake
Normal file
24
cmake/macros/TargetPolyvox.cmake
Normal file
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
# Created by Bradley Austin Davis on 2017/11/28
|
||||
# Copyright 2013-2017 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_POLYVOX)
|
||||
if (ANDROID)
|
||||
set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/polyvox)
|
||||
set(POLYVOX_INCLUDE_DIRS "${INSTALL_DIR}/include" CACHE TYPE INTERNAL)
|
||||
set(LIB_DIR ${INSTALL_DIR}/lib)
|
||||
list(APPEND POLYVOX_LIBRARIES ${LIB_DIR}/libPolyVoxUtil.so)
|
||||
list(APPEND POLYVOX_LIBRARIES ${LIB_DIR}/Release/libPolyVoxCore.so)
|
||||
else()
|
||||
add_dependency_external_projects(polyvox)
|
||||
find_package(PolyVox REQUIRED)
|
||||
endif()
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
|
||||
endmacro()
|
||||
|
||||
|
||||
|
|
@ -8,10 +8,10 @@
|
|||
macro(TARGET_TBB)
|
||||
|
||||
if (ANDROID)
|
||||
set(TBB_INSTALL_DIR C:/tbb-2018/built)
|
||||
set(TBB_LIBRARY ${HIFI_ANDROID_PRECOMPILED}/libtbb.so CACHE FILEPATH "TBB library location")
|
||||
set(TBB_MALLOC_LIBRARY ${HIFI_ANDROID_PRECOMPILED}/libtbbmalloc.so CACHE FILEPATH "TBB malloc library location")
|
||||
set(TBB_INCLUDE_DIRS ${TBB_INSTALL_DIR}/include CACHE TYPE "List of tbb include directories" CACHE FILEPATH "TBB includes location")
|
||||
set(TBB_INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/tbb)
|
||||
set(TBB_INCLUDE_DIRS ${TBB_INSTALL_DIR}/include CACHE FILEPATH "TBB includes location")
|
||||
set(TBB_LIBRARY ${TBB_INSTALL_DIR}/lib/release/libtbb.so CACHE FILEPATH "TBB library location")
|
||||
set(TBB_MALLOC_LIBRARY ${TBB_INSTALL_DIR}/lib/release/libtbbmalloc.so CACHE FILEPATH "TBB malloc library location")
|
||||
set(TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY})
|
||||
else()
|
||||
add_dependency_external_projects(tbb)
|
||||
|
|
|
@ -27,11 +27,11 @@
|
|||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
|
||||
// I know, right? But per https://www.openssl.org/docs/faq.html
|
||||
// this avoids OPENSSL_Uplink(00007FF847238000,08): no OPENSSL_Applink
|
||||
|
@ -78,18 +78,19 @@ int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
|
|||
}
|
||||
}
|
||||
|
||||
RSA* readKeys(const char* filename) {
|
||||
EC_KEY* readKeys(const char* filename) {
|
||||
FILE* fp;
|
||||
RSA* key = NULL;
|
||||
EC_KEY *key = NULL;
|
||||
if ((fp = fopen(filename, "rt"))) {
|
||||
// file opened successfully
|
||||
qCDebug(commerce) << "opened key file" << filename;
|
||||
if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL))) {
|
||||
|
||||
if ((key = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL))) {
|
||||
// now read private key
|
||||
|
||||
qCDebug(commerce) << "read public key";
|
||||
|
||||
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
|
||||
if ((key = PEM_read_ECPrivateKey(fp, &key, passwordCallback, NULL))) {
|
||||
qCDebug(commerce) << "read private key";
|
||||
fclose(fp);
|
||||
return key;
|
||||
|
@ -137,18 +138,18 @@ bool Wallet::writeBackupInstructions() {
|
|||
return retval;
|
||||
}
|
||||
|
||||
bool writeKeys(const char* filename, RSA* keys) {
|
||||
bool writeKeys(const char* filename, EC_KEY* keys) {
|
||||
FILE* fp;
|
||||
bool retval = false;
|
||||
if ((fp = fopen(filename, "wt"))) {
|
||||
if (!PEM_write_RSAPublicKey(fp, keys)) {
|
||||
if (!PEM_write_EC_PUBKEY(fp, keys)) {
|
||||
fclose(fp);
|
||||
qCDebug(commerce) << "failed to write public key";
|
||||
QFile(QString(filename)).remove();
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!PEM_write_RSAPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
|
||||
if (!PEM_write_ECPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
|
||||
fclose(fp);
|
||||
qCDebug(commerce) << "failed to write private key";
|
||||
QFile(QString(filename)).remove();
|
||||
|
@ -164,50 +165,29 @@ bool writeKeys(const char* filename, RSA* keys) {
|
|||
return retval;
|
||||
}
|
||||
|
||||
// copied (without emits for various signals) from libraries/networking/src/RSAKeypairGenerator.cpp.
|
||||
// We will have a different implementation in practice, but this gives us a start for now
|
||||
//
|
||||
// TODO: we don't really use the private keys returned - we can see how this evolves, but probably
|
||||
// we should just return a list of public keys?
|
||||
// or perhaps return the RSA* instead?
|
||||
QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
|
||||
QPair<QByteArray*, QByteArray*> generateECKeypair() {
|
||||
|
||||
RSA* keyPair = RSA_new();
|
||||
BIGNUM* exponent = BN_new();
|
||||
EC_KEY* keyPair = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
QPair<QByteArray*, QByteArray*> retval;
|
||||
|
||||
const unsigned long RSA_KEY_EXPONENT = 65537;
|
||||
BN_set_word(exponent, RSA_KEY_EXPONENT);
|
||||
|
||||
// seed the random number generator before we call RSA_generate_key_ex
|
||||
srand(time(NULL));
|
||||
|
||||
const int RSA_KEY_BITS = 2048;
|
||||
|
||||
if (!RSA_generate_key_ex(keyPair, RSA_KEY_BITS, exponent, NULL)) {
|
||||
qCDebug(commerce) << "Error generating 2048-bit RSA Keypair -" << ERR_get_error();
|
||||
|
||||
// we're going to bust out of here but first we cleanup the BIGNUM
|
||||
BN_free(exponent);
|
||||
EC_KEY_set_asn1_flag(keyPair, OPENSSL_EC_NAMED_CURVE);
|
||||
if (!EC_KEY_generate_key(keyPair)) {
|
||||
qCDebug(commerce) << "Error generating EC Keypair -" << ERR_get_error();
|
||||
return retval;
|
||||
}
|
||||
|
||||
// we don't need the BIGNUM anymore so clean that up
|
||||
BN_free(exponent);
|
||||
|
||||
// grab the public key and private key from the file
|
||||
unsigned char* publicKeyDER = NULL;
|
||||
int publicKeyLength = i2d_RSAPublicKey(keyPair, &publicKeyDER);
|
||||
int publicKeyLength = i2d_EC_PUBKEY(keyPair, &publicKeyDER);
|
||||
|
||||
unsigned char* privateKeyDER = NULL;
|
||||
int privateKeyLength = i2d_RSAPrivateKey(keyPair, &privateKeyDER);
|
||||
int privateKeyLength = i2d_ECPrivateKey(keyPair, &privateKeyDER);
|
||||
|
||||
if (publicKeyLength <= 0 || privateKeyLength <= 0) {
|
||||
qCDebug(commerce) << "Error getting DER public or private key from RSA struct -" << ERR_get_error();
|
||||
qCDebug(commerce) << "Error getting DER public or private key from EC struct -" << ERR_get_error();
|
||||
|
||||
|
||||
// cleanup the RSA struct
|
||||
RSA_free(keyPair);
|
||||
// cleanup the EC struct
|
||||
EC_KEY_free(keyPair);
|
||||
|
||||
// cleanup the public and private key DER data, if required
|
||||
if (publicKeyLength > 0) {
|
||||
|
@ -227,13 +207,13 @@ QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
|
|||
return retval;
|
||||
}
|
||||
|
||||
RSA_free(keyPair);
|
||||
EC_KEY_free(keyPair);
|
||||
|
||||
// prepare the return values. TODO: Fix this - we probably don't really even want the
|
||||
// private key at all (better to read it when we need it?). Or maybe we do, when we have
|
||||
// multiple keys?
|
||||
retval.first = new QByteArray(reinterpret_cast<char*>(publicKeyDER), publicKeyLength ),
|
||||
retval.second = new QByteArray(reinterpret_cast<char*>(privateKeyDER), privateKeyLength );
|
||||
retval.first = new QByteArray(reinterpret_cast<char*>(publicKeyDER), publicKeyLength);
|
||||
retval.second = new QByteArray(reinterpret_cast<char*>(privateKeyDER), privateKeyLength);
|
||||
|
||||
// cleanup the publicKeyDER and publicKeyDER data
|
||||
OPENSSL_free(publicKeyDER);
|
||||
|
@ -245,18 +225,18 @@ QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
|
|||
// the public key can just go into a byte array
|
||||
QByteArray readPublicKey(const char* filename) {
|
||||
FILE* fp;
|
||||
RSA* key = NULL;
|
||||
EC_KEY* key = NULL;
|
||||
if ((fp = fopen(filename, "r"))) {
|
||||
// file opened successfully
|
||||
qCDebug(commerce) << "opened key file" << filename;
|
||||
if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL))) {
|
||||
if ((key = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL))) {
|
||||
// file read successfully
|
||||
unsigned char* publicKeyDER = NULL;
|
||||
int publicKeyLength = i2d_RSAPublicKey(key, &publicKeyDER);
|
||||
int publicKeyLength = i2d_EC_PUBKEY(key, &publicKeyDER);
|
||||
// TODO: check for 0 length?
|
||||
|
||||
// cleanup
|
||||
RSA_free(key);
|
||||
EC_KEY_free(key);
|
||||
fclose(fp);
|
||||
|
||||
qCDebug(commerce) << "parsed public key file successfully";
|
||||
|
@ -274,15 +254,15 @@ QByteArray readPublicKey(const char* filename) {
|
|||
return QByteArray();
|
||||
}
|
||||
|
||||
// the private key should be read/copied into heap memory. For now, we need the RSA struct
|
||||
// so I'll return that. Note we need to RSA_free(key) later!!!
|
||||
RSA* readPrivateKey(const char* filename) {
|
||||
// the private key should be read/copied into heap memory. For now, we need the EC_KEY struct
|
||||
// so I'll return that.
|
||||
EC_KEY* readPrivateKey(const char* filename) {
|
||||
FILE* fp;
|
||||
RSA* key = NULL;
|
||||
EC_KEY* key = NULL;
|
||||
if ((fp = fopen(filename, "r"))) {
|
||||
// file opened successfully
|
||||
qCDebug(commerce) << "opened key file" << filename;
|
||||
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
|
||||
if ((key = PEM_read_ECPrivateKey(fp, &key, passwordCallback, NULL))) {
|
||||
qCDebug(commerce) << "parsed private key file successfully";
|
||||
|
||||
} else {
|
||||
|
@ -509,7 +489,7 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
|||
|
||||
if (publicKey.size() > 0) {
|
||||
if (auto key = readPrivateKey(keyFilePath().toStdString().c_str())) {
|
||||
RSA_free(key);
|
||||
EC_KEY_free(key);
|
||||
|
||||
// be sure to add the public key so we don't do this over and over
|
||||
_publicKeys.push_back(publicKey.toBase64());
|
||||
|
@ -525,7 +505,7 @@ bool Wallet::generateKeyPair() {
|
|||
initialize();
|
||||
|
||||
qCInfo(commerce) << "Generating keypair.";
|
||||
auto keyPair = generateRSAKeypair();
|
||||
auto keyPair = generateECKeypair();
|
||||
|
||||
writeBackupInstructions();
|
||||
|
||||
|
@ -557,25 +537,25 @@ QStringList Wallet::listPublicKeys() {
|
|||
// the horror of code pages and so on (changing the bytes) by just returning a base64
|
||||
// encoded string representing the signature (suitable for http, etc...)
|
||||
QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
|
||||
qCInfo(commerce) << "Signing text.";
|
||||
RSA* rsaPrivateKey = NULL;
|
||||
if ((rsaPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
|
||||
QByteArray signature(RSA_size(rsaPrivateKey), 0);
|
||||
qCInfo(commerce) << "Signing text" << text << "with key" << key;
|
||||
EC_KEY* ecPrivateKey = NULL;
|
||||
if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
|
||||
unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)];
|
||||
|
||||
unsigned int signatureBytes = 0;
|
||||
|
||||
QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256);
|
||||
|
||||
int encryptReturn = RSA_sign(NID_sha256,
|
||||
reinterpret_cast<const unsigned char*>(hashedPlaintext.constData()),
|
||||
hashedPlaintext.size(),
|
||||
reinterpret_cast<unsigned char*>(signature.data()),
|
||||
&signatureBytes,
|
||||
rsaPrivateKey);
|
||||
|
||||
// free the private key RSA struct now that we are done with it
|
||||
RSA_free(rsaPrivateKey);
|
||||
int retrn = ECDSA_sign(0,
|
||||
reinterpret_cast<const unsigned char*>(hashedPlaintext.constData()),
|
||||
hashedPlaintext.size(),
|
||||
sig,
|
||||
&signatureBytes, ecPrivateKey);
|
||||
|
||||
if (encryptReturn != -1) {
|
||||
EC_KEY_free(ecPrivateKey);
|
||||
QByteArray signature(reinterpret_cast<const char*>(sig), signatureBytes);
|
||||
if (retrn != -1) {
|
||||
return signature.toBase64();
|
||||
}
|
||||
}
|
||||
|
@ -674,7 +654,7 @@ void Wallet::reset() {
|
|||
keyFile.remove();
|
||||
}
|
||||
bool Wallet::writeWallet(const QString& newPassphrase) {
|
||||
RSA* keys = readKeys(keyFilePath().toStdString().c_str());
|
||||
EC_KEY* keys = readKeys(keyFilePath().toStdString().c_str());
|
||||
if (keys) {
|
||||
// we read successfully, so now write to a new temp file
|
||||
QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp"));
|
||||
|
@ -720,82 +700,86 @@ bool Wallet::changePassphrase(const QString& newPassphrase) {
|
|||
void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// With EC keys, we receive a nonce from the metaverse server, which is signed
|
||||
// here with the private key and returned. Verification is done at server.
|
||||
|
||||
bool challengeOriginatedFromClient = packet->getType() == PacketType::ChallengeOwnershipRequest;
|
||||
unsigned char decryptedText[64];
|
||||
int status;
|
||||
int certIDByteArraySize;
|
||||
int encryptedTextByteArraySize;
|
||||
int textByteArraySize;
|
||||
int challengingNodeUUIDByteArraySize;
|
||||
|
||||
packet->readPrimitive(&certIDByteArraySize);
|
||||
packet->readPrimitive(&encryptedTextByteArraySize);
|
||||
packet->readPrimitive(&textByteArraySize); // returns a cast char*, size
|
||||
if (challengeOriginatedFromClient) {
|
||||
packet->readPrimitive(&challengingNodeUUIDByteArraySize);
|
||||
}
|
||||
|
||||
// "encryptedText" is now a series of random bytes, a nonce
|
||||
QByteArray certID = packet->read(certIDByteArraySize);
|
||||
QByteArray encryptedText = packet->read(encryptedTextByteArraySize);
|
||||
QByteArray text = packet->read(textByteArraySize);
|
||||
QByteArray challengingNodeUUID;
|
||||
if (challengeOriginatedFromClient) {
|
||||
challengingNodeUUID = packet->read(challengingNodeUUIDByteArraySize);
|
||||
}
|
||||
|
||||
RSA* rsa = readKeys(keyFilePath().toStdString().c_str());
|
||||
int decryptionStatus = -1;
|
||||
EC_KEY* ec = readKeys(keyFilePath().toStdString().c_str());
|
||||
QString sig;
|
||||
|
||||
if (rsa) {
|
||||
if (ec) {
|
||||
ERR_clear_error();
|
||||
decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize,
|
||||
reinterpret_cast<const unsigned char*>(encryptedText.constData()),
|
||||
decryptedText,
|
||||
rsa,
|
||||
RSA_PKCS1_OAEP_PADDING);
|
||||
|
||||
RSA_free(rsa);
|
||||
sig = signWithKey(text, ""); // base64 signature, QByteArray cast (on return) to QString FIXME should pass ec as string so we can tell which key to sign with
|
||||
status = 1;
|
||||
} else {
|
||||
qCDebug(commerce) << "During entity ownership challenge, creating the RSA object failed.";
|
||||
qCDebug(commerce) << "During entity ownership challenge, creating the EC-signed nonce failed.";
|
||||
status = -1;
|
||||
}
|
||||
|
||||
QByteArray decryptedTextByteArray;
|
||||
if (decryptionStatus > -1) {
|
||||
decryptedTextByteArray = QByteArray(reinterpret_cast<const char*>(decryptedText), decryptionStatus);
|
||||
EC_KEY_free(ec);
|
||||
QByteArray ba = sig.toLocal8Bit();
|
||||
const char *sigChar = ba.data();
|
||||
|
||||
QByteArray textByteArray;
|
||||
if (status > -1) {
|
||||
textByteArray = QByteArray(sigChar, (int) strlen(sigChar));
|
||||
}
|
||||
int decryptedTextByteArraySize = decryptedTextByteArray.size();
|
||||
textByteArraySize = textByteArray.size();
|
||||
int certIDSize = certID.size();
|
||||
// setup the packet
|
||||
if (challengeOriginatedFromClient) {
|
||||
auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnershipReply,
|
||||
certIDSize + decryptedTextByteArraySize + challengingNodeUUIDByteArraySize + 3 * sizeof(int),
|
||||
auto textPacket = NLPacket::create(PacketType::ChallengeOwnershipReply,
|
||||
certIDSize + textByteArraySize + challengingNodeUUIDByteArraySize + 3 * sizeof(int),
|
||||
true);
|
||||
|
||||
decryptedTextPacket->writePrimitive(certIDSize);
|
||||
decryptedTextPacket->writePrimitive(decryptedTextByteArraySize);
|
||||
decryptedTextPacket->writePrimitive(challengingNodeUUIDByteArraySize);
|
||||
decryptedTextPacket->write(certID);
|
||||
decryptedTextPacket->write(decryptedTextByteArray);
|
||||
decryptedTextPacket->write(challengingNodeUUID);
|
||||
textPacket->writePrimitive(certIDSize);
|
||||
textPacket->writePrimitive(textByteArraySize);
|
||||
textPacket->writePrimitive(challengingNodeUUIDByteArraySize);
|
||||
textPacket->write(certID);
|
||||
textPacket->write(textByteArray);
|
||||
textPacket->write(challengingNodeUUID);
|
||||
|
||||
qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID;
|
||||
qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing signed text" << textByteArray << "for CertID" << certID;
|
||||
|
||||
nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode);
|
||||
nodeList->sendPacket(std::move(textPacket), *sendingNode);
|
||||
} else {
|
||||
auto decryptedTextPacket = NLPacket::create(PacketType::ChallengeOwnership, certIDSize + decryptedTextByteArraySize + 2 * sizeof(int), true);
|
||||
auto textPacket = NLPacket::create(PacketType::ChallengeOwnership, certIDSize + textByteArraySize + 2 * sizeof(int), true);
|
||||
|
||||
decryptedTextPacket->writePrimitive(certIDSize);
|
||||
decryptedTextPacket->writePrimitive(decryptedTextByteArraySize);
|
||||
decryptedTextPacket->write(certID);
|
||||
decryptedTextPacket->write(decryptedTextByteArray);
|
||||
textPacket->writePrimitive(certIDSize);
|
||||
textPacket->writePrimitive(textByteArraySize);
|
||||
textPacket->write(certID);
|
||||
textPacket->write(textByteArray);
|
||||
|
||||
qCDebug(commerce) << "Sending ChallengeOwnership Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID;
|
||||
qCDebug(commerce) << "Sending ChallengeOwnership Packet containing signed text" << textByteArray << "for CertID" << certID;
|
||||
|
||||
nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode);
|
||||
nodeList->sendPacket(std::move(textPacket), *sendingNode);
|
||||
}
|
||||
|
||||
if (decryptionStatus == -1) {
|
||||
qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed.";
|
||||
if (status == -1) {
|
||||
qCDebug(commerce) << "During entity ownership challenge, signing the text failed.";
|
||||
long error = ERR_get_error();
|
||||
if (error != 0) {
|
||||
const char* error_str = ERR_error_string(error, NULL);
|
||||
qCWarning(entities) << "RSA error:" << error_str;
|
||||
qCWarning(entities) << "EC error:" << error_str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -326,21 +326,21 @@ void ContextOverlayInterface::openInspectionCertificate() {
|
|||
QString ownerKey = jsonObject["transfer_recipient_key"].toString();
|
||||
|
||||
QByteArray certID = entityProperties.getCertificateID().toUtf8();
|
||||
QByteArray encryptedText = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeEncryptedNonce(certID, ownerKey);
|
||||
QByteArray text = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeNonce(certID, ownerKey);
|
||||
QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
|
||||
|
||||
int certIDByteArraySize = certID.length();
|
||||
int encryptedTextByteArraySize = encryptedText.length();
|
||||
int textByteArraySize = text.length();
|
||||
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
|
||||
|
||||
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
|
||||
certIDByteArraySize + encryptedTextByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
|
||||
certIDByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
|
||||
true);
|
||||
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(encryptedTextByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(textByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
|
||||
challengeOwnershipPacket->write(certID);
|
||||
challengeOwnershipPacket->write(encryptedText);
|
||||
challengeOwnershipPacket->write(text);
|
||||
challengeOwnershipPacket->write(nodeToChallengeByteArray);
|
||||
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
|
||||
|
||||
|
@ -421,16 +421,16 @@ void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer
|
|||
_challengeOwnershipTimeoutTimer.stop();
|
||||
|
||||
int certIDByteArraySize;
|
||||
int decryptedTextByteArraySize;
|
||||
int textByteArraySize;
|
||||
|
||||
packet->readPrimitive(&certIDByteArraySize);
|
||||
packet->readPrimitive(&decryptedTextByteArraySize);
|
||||
packet->readPrimitive(&textByteArraySize);
|
||||
|
||||
QString certID(packet->read(certIDByteArraySize));
|
||||
QString decryptedText(packet->read(decryptedTextByteArraySize));
|
||||
QString text(packet->read(textByteArraySize));
|
||||
|
||||
EntityItemID id;
|
||||
bool verificationSuccess = DependencyManager::get<EntityTreeRenderer>()->getTree()->verifyDecryptedNonce(certID, decryptedText, id);
|
||||
bool verificationSuccess = DependencyManager::get<EntityTreeRenderer>()->getTree()->verifyNonce(certID, text, id);
|
||||
|
||||
if (verificationSuccess) {
|
||||
emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS));
|
||||
|
|
|
@ -199,7 +199,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) {
|
|||
|
||||
// define the uncaughtException function
|
||||
QScriptEngine& engineRef = *engine;
|
||||
filterData.uncaughtExceptions = [this, &engineRef, urlString]() { return hadUncaughtExceptions(engineRef, urlString); };
|
||||
filterData.uncaughtExceptions = [&engineRef, urlString]() { return hadUncaughtExceptions(engineRef, urlString); };
|
||||
|
||||
// now get the filter function
|
||||
auto global = engine->globalObject();
|
||||
|
|
|
@ -13,21 +13,18 @@
|
|||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QtCore/QJsonDocument>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
||||
#include <ByteCountCoding.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <Extents.h>
|
||||
|
||||
#include "EntitiesLogging.h"
|
||||
#include "EntityItem.h"
|
||||
#include "EntityItemProperties.h"
|
||||
|
@ -2508,48 +2505,47 @@ QByteArray EntityItemProperties::getStaticCertificateHash() const {
|
|||
return QCryptographicHash::hash(getStaticCertificateJSON(), QCryptographicHash::Sha256);
|
||||
}
|
||||
|
||||
bool EntityItemProperties::verifyStaticCertificateProperties() {
|
||||
// True IIF a non-empty certificateID matches the static certificate json.
|
||||
// I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash.
|
||||
// FIXME: This is largely copied from EntityItemProperties::verifyStaticCertificateProperties, which should be refactored to use this.
|
||||
// I also don't like the nested-if style, but for this step I'm deliberately preserving the similarity.
|
||||
bool EntityItemProperties::verifySignature(const QString& publicKey, const QByteArray& digestByteArray, const QByteArray& signatureByteArray) {
|
||||
|
||||
if (getCertificateID().isEmpty()) {
|
||||
if (digestByteArray.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QByteArray marketplacePublicKeyByteArray = EntityItem::_marketplacePublicKey.toUtf8();
|
||||
const unsigned char* marketplacePublicKey = reinterpret_cast<const unsigned char*>(marketplacePublicKeyByteArray.constData());
|
||||
int marketplacePublicKeyLength = marketplacePublicKeyByteArray.length();
|
||||
const unsigned char* key = reinterpret_cast<const unsigned char*>(publicKey.toUtf8().constData());
|
||||
int keyLength = publicKey.length();
|
||||
|
||||
BIO *bio = BIO_new_mem_buf((void*)marketplacePublicKey, marketplacePublicKeyLength);
|
||||
BIO *bio = BIO_new_mem_buf((void*)key, keyLength);
|
||||
EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
|
||||
if (evp_key) {
|
||||
RSA* rsa = EVP_PKEY_get1_RSA(evp_key);
|
||||
if (rsa) {
|
||||
const QByteArray digestByteArray = getStaticCertificateHash();
|
||||
EC_KEY* ec = EVP_PKEY_get1_EC_KEY(evp_key);
|
||||
if (ec) {
|
||||
const unsigned char* digest = reinterpret_cast<const unsigned char*>(digestByteArray.constData());
|
||||
int digestLength = digestByteArray.length();
|
||||
|
||||
const QByteArray signatureByteArray = QByteArray::fromBase64(getCertificateID().toUtf8());
|
||||
const unsigned char* signature = reinterpret_cast<const unsigned char*>(signatureByteArray.constData());
|
||||
int signatureLength = signatureByteArray.length();
|
||||
|
||||
ERR_clear_error();
|
||||
bool answer = RSA_verify(NID_sha256,
|
||||
// ECSDA verification prototype: note that type is currently ignored
|
||||
// int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen,
|
||||
// const unsigned char *sig, int siglen, EC_KEY *eckey);
|
||||
bool answer = ECDSA_verify(0,
|
||||
digest,
|
||||
digestLength,
|
||||
signature,
|
||||
signatureLength,
|
||||
rsa);
|
||||
ec);
|
||||
long error = ERR_get_error();
|
||||
if (error != 0) {
|
||||
const char* error_str = ERR_error_string(error, NULL);
|
||||
qCWarning(entities) << "ERROR while verifying static certificate properties! RSA error:" << error_str
|
||||
<< "\nStatic Cert JSON:" << getStaticCertificateJSON()
|
||||
<< "\nKey:" << EntityItem::_marketplacePublicKey << "\nKey Length:" << marketplacePublicKeyLength
|
||||
qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str
|
||||
<< "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength
|
||||
<< "\nDigest:" << digest << "\nDigest Length:" << digestLength
|
||||
<< "\nSignature:" << signature << "\nSignature Length:" << signatureLength;
|
||||
}
|
||||
RSA_free(rsa);
|
||||
EC_KEY_free(ec);
|
||||
if (bio) {
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
@ -2566,7 +2562,7 @@ bool EntityItemProperties::verifyStaticCertificateProperties() {
|
|||
}
|
||||
long error = ERR_get_error();
|
||||
const char* error_str = ERR_error_string(error, NULL);
|
||||
qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str;
|
||||
qCWarning(entities) << "Failed to verify signature! key" << publicKey << " EC key error:" << error_str;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -2575,7 +2571,13 @@ bool EntityItemProperties::verifyStaticCertificateProperties() {
|
|||
}
|
||||
long error = ERR_get_error();
|
||||
const char* error_str = ERR_error_string(error, NULL);
|
||||
qCWarning(entities) << "Failed to verify static certificate properties! RSA error:" << error_str;
|
||||
qCWarning(entities) << "Failed to verify signature! key" << publicKey << " EC PEM error:" << error_str;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EntityItemProperties::verifyStaticCertificateProperties() {
|
||||
// True IFF a non-empty certificateID matches the static certificate json.
|
||||
// I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash.
|
||||
return verifySignature(EntityItem::_marketplacePublicKey, getStaticCertificateHash(), QByteArray::fromBase64(getCertificateID().toUtf8()));
|
||||
}
|
||||
|
|
|
@ -339,6 +339,7 @@ public:
|
|||
QByteArray getStaticCertificateJSON() const;
|
||||
QByteArray getStaticCertificateHash() const;
|
||||
bool verifyStaticCertificateProperties();
|
||||
static bool verifySignature(const QString& key, const QByteArray& text, const QByteArray& signature);
|
||||
|
||||
protected:
|
||||
QString getCollisionMaskAsString() const;
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
#include "EntityTree.h"
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QQueue>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <NetworkingConstants.h>
|
||||
|
@ -1167,63 +1165,37 @@ void EntityTree::startPendingTransferStatusTimer(const QString& certID, const En
|
|||
transferStatusRetryTimer->start(90000);
|
||||
}
|
||||
|
||||
QByteArray EntityTree::computeEncryptedNonce(const QString& certID, const QString ownerKey) {
|
||||
QString ownerKeyWithHeaders = ("-----BEGIN RSA PUBLIC KEY-----\n" + ownerKey + "\n-----END RSA PUBLIC KEY-----");
|
||||
BIO* bio = BIO_new_mem_buf((void*)ownerKeyWithHeaders.toUtf8().constData(), -1);
|
||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); // NO NEWLINE
|
||||
RSA* rsa = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
|
||||
QByteArray EntityTree::computeNonce(const QString& certID, const QString ownerKey) {
|
||||
QUuid nonce = QUuid::createUuid(); //random, 5-hex value, separated by "-"
|
||||
QByteArray nonceBytes = nonce.toByteArray();
|
||||
|
||||
if (rsa) {
|
||||
QUuid nonce = QUuid::createUuid();
|
||||
const unsigned int textLength = nonce.toString().length();
|
||||
QByteArray encryptedText(RSA_size(rsa), 0);
|
||||
const int encryptStatus = RSA_public_encrypt(textLength,
|
||||
reinterpret_cast<const unsigned char*>(qPrintable(nonce.toString())),
|
||||
reinterpret_cast<unsigned char*>(encryptedText.data()),
|
||||
rsa,
|
||||
RSA_PKCS1_OAEP_PADDING);
|
||||
if (bio) {
|
||||
BIO_free(bio);
|
||||
}
|
||||
RSA_free(rsa);
|
||||
if (encryptStatus == -1) {
|
||||
long error = ERR_get_error();
|
||||
const char* error_str = ERR_error_string(error, NULL);
|
||||
qCWarning(entities) << "Unable to compute encrypted nonce for" << certID << "\nRSA error:" << error_str;
|
||||
return "";
|
||||
}
|
||||
QWriteLocker locker(&_certNonceMapLock);
|
||||
_certNonceMap.insert(certID, QPair<QUuid, QString>(nonce, ownerKey));
|
||||
|
||||
QWriteLocker locker(&_certNonceMapLock);
|
||||
_certNonceMap.insert(certID, nonce);
|
||||
|
||||
return encryptedText;
|
||||
} else {
|
||||
if (bio) {
|
||||
BIO_free(bio);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
return nonceBytes;
|
||||
}
|
||||
|
||||
bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce, EntityItemID& id) {
|
||||
bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, EntityItemID& id) {
|
||||
{
|
||||
QReadLocker certIdMapLocker(&_entityCertificateIDMapLock);
|
||||
id = _entityCertificateIDMap.value(certID);
|
||||
}
|
||||
|
||||
QString actualNonce;
|
||||
QString actualNonce, key;
|
||||
{
|
||||
QWriteLocker locker(&_certNonceMapLock);
|
||||
actualNonce = _certNonceMap.take(certID).toString();
|
||||
QPair<QUuid, QString> sent = _certNonceMap.take(certID);
|
||||
actualNonce = sent.first.toString();
|
||||
key = sent.second;
|
||||
}
|
||||
|
||||
bool verificationSuccess = (actualNonce == decryptedNonce);
|
||||
QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----";
|
||||
bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), actualNonce.toUtf8(), nonce.toUtf8());
|
||||
|
||||
if (verificationSuccess) {
|
||||
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded.";
|
||||
} else {
|
||||
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed."
|
||||
<< "\nActual nonce:" << actualNonce << "\nDecrypted nonce:" << decryptedNonce;
|
||||
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed for nonce" << actualNonce << "key" << key << "signature" << nonce;
|
||||
}
|
||||
|
||||
return verificationSuccess;
|
||||
|
@ -1231,67 +1203,67 @@ bool EntityTree::verifyDecryptedNonce(const QString& certID, const QString& decr
|
|||
|
||||
void EntityTree::processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
|
||||
int certIDByteArraySize;
|
||||
int encryptedTextByteArraySize;
|
||||
int textByteArraySize;
|
||||
int nodeToChallengeByteArraySize;
|
||||
|
||||
message.readPrimitive(&certIDByteArraySize);
|
||||
message.readPrimitive(&encryptedTextByteArraySize);
|
||||
message.readPrimitive(&textByteArraySize);
|
||||
message.readPrimitive(&nodeToChallengeByteArraySize);
|
||||
|
||||
QByteArray certID(message.read(certIDByteArraySize));
|
||||
QByteArray encryptedText(message.read(encryptedTextByteArraySize));
|
||||
QByteArray text(message.read(textByteArraySize));
|
||||
QByteArray nodeToChallenge(message.read(nodeToChallengeByteArraySize));
|
||||
|
||||
sendChallengeOwnershipRequestPacket(certID, encryptedText, nodeToChallenge, sourceNode);
|
||||
sendChallengeOwnershipRequestPacket(certID, text, nodeToChallenge, sourceNode);
|
||||
}
|
||||
|
||||
void EntityTree::processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
int certIDByteArraySize;
|
||||
int decryptedTextByteArraySize;
|
||||
int textByteArraySize;
|
||||
int challengingNodeUUIDByteArraySize;
|
||||
|
||||
message.readPrimitive(&certIDByteArraySize);
|
||||
message.readPrimitive(&decryptedTextByteArraySize);
|
||||
message.readPrimitive(&textByteArraySize);
|
||||
message.readPrimitive(&challengingNodeUUIDByteArraySize);
|
||||
|
||||
QByteArray certID(message.read(certIDByteArraySize));
|
||||
QByteArray decryptedText(message.read(decryptedTextByteArraySize));
|
||||
QByteArray text(message.read(textByteArraySize));
|
||||
QUuid challengingNode = QUuid::fromRfc4122(message.read(challengingNodeUUIDByteArraySize));
|
||||
|
||||
auto challengeOwnershipReplyPacket = NLPacket::create(PacketType::ChallengeOwnershipReply,
|
||||
certIDByteArraySize + decryptedText.length() + 2 * sizeof(int),
|
||||
certIDByteArraySize + text.length() + 2 * sizeof(int),
|
||||
true);
|
||||
challengeOwnershipReplyPacket->writePrimitive(certIDByteArraySize);
|
||||
challengeOwnershipReplyPacket->writePrimitive(decryptedText.length());
|
||||
challengeOwnershipReplyPacket->writePrimitive(text.length());
|
||||
challengeOwnershipReplyPacket->write(certID);
|
||||
challengeOwnershipReplyPacket->write(decryptedText);
|
||||
challengeOwnershipReplyPacket->write(text);
|
||||
|
||||
nodeList->sendPacket(std::move(challengeOwnershipReplyPacket), *(nodeList->nodeWithUUID(challengingNode)));
|
||||
}
|
||||
|
||||
void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode) {
|
||||
// 1. Encrypt a nonce with the owner's public key
|
||||
// 1. Obtain a nonce
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
QByteArray encryptedText = computeEncryptedNonce(certID, ownerKey);
|
||||
QByteArray text = computeNonce(certID, ownerKey);
|
||||
|
||||
if (encryptedText == "") {
|
||||
qCDebug(entities) << "CRITICAL ERROR: Couldn't compute encrypted nonce. Deleting entity...";
|
||||
if (text == "") {
|
||||
qCDebug(entities) << "CRITICAL ERROR: Couldn't compute nonce. Deleting entity...";
|
||||
deleteEntity(entityItemID, true);
|
||||
} else {
|
||||
qCDebug(entities) << "Challenging ownership of Cert ID" << certID;
|
||||
// 2. Send the encrypted text to the rezzing avatar's node
|
||||
// 2. Send the nonce to the rezzing avatar's node
|
||||
QByteArray certIDByteArray = certID.toUtf8();
|
||||
int certIDByteArraySize = certIDByteArray.size();
|
||||
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnership,
|
||||
certIDByteArraySize + encryptedText.length() + 2 * sizeof(int),
|
||||
certIDByteArraySize + text.length() + 2 * sizeof(int),
|
||||
true);
|
||||
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(encryptedText.length());
|
||||
challengeOwnershipPacket->writePrimitive(text.length());
|
||||
challengeOwnershipPacket->write(certIDByteArray);
|
||||
challengeOwnershipPacket->write(encryptedText);
|
||||
challengeOwnershipPacket->write(text);
|
||||
nodeList->sendPacket(std::move(challengeOwnershipPacket), *senderNode);
|
||||
|
||||
// 3. Kickoff a 10-second timeout timer that deletes the entity if we don't get an ownership response in time
|
||||
|
@ -1304,7 +1276,7 @@ void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QStri
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTree::sendChallengeOwnershipRequestPacket(const QByteArray& certID, const QByteArray& encryptedText, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode) {
|
||||
void EntityTree::sendChallengeOwnershipRequestPacket(const QByteArray& certID, const QByteArray& text, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// In this case, Client A is challenging Client B. Client A is inspecting a certified entity that it wants
|
||||
|
@ -1312,17 +1284,17 @@ void EntityTree::sendChallengeOwnershipRequestPacket(const QByteArray& certID, c
|
|||
QByteArray senderNodeUUID = senderNode->getUUID().toRfc4122();
|
||||
|
||||
int certIDByteArraySize = certID.length();
|
||||
int encryptedTextByteArraySize = encryptedText.length();
|
||||
int TextByteArraySize = text.length();
|
||||
int senderNodeUUIDSize = senderNodeUUID.length();
|
||||
|
||||
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
|
||||
certIDByteArraySize + encryptedTextByteArraySize + senderNodeUUIDSize + 3 * sizeof(int),
|
||||
certIDByteArraySize + TextByteArraySize + senderNodeUUIDSize + 3 * sizeof(int),
|
||||
true);
|
||||
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(encryptedTextByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(TextByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(senderNodeUUIDSize);
|
||||
challengeOwnershipPacket->write(certID);
|
||||
challengeOwnershipPacket->write(encryptedText);
|
||||
challengeOwnershipPacket->write(text);
|
||||
challengeOwnershipPacket->write(senderNodeUUID);
|
||||
|
||||
nodeList->sendPacket(std::move(challengeOwnershipPacket), *(nodeList->nodeWithUUID(QUuid::fromRfc4122(nodeToChallenge))));
|
||||
|
@ -1391,18 +1363,18 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
|
|||
|
||||
void EntityTree::processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
|
||||
int certIDByteArraySize;
|
||||
int decryptedTextByteArraySize;
|
||||
int textByteArraySize;
|
||||
|
||||
message.readPrimitive(&certIDByteArraySize);
|
||||
message.readPrimitive(&decryptedTextByteArraySize);
|
||||
message.readPrimitive(&textByteArraySize);
|
||||
|
||||
QString certID(message.read(certIDByteArraySize));
|
||||
QString decryptedText(message.read(decryptedTextByteArraySize));
|
||||
QString text(message.read(textByteArraySize));
|
||||
|
||||
emit killChallengeOwnershipTimeoutTimer(certID);
|
||||
|
||||
EntityItemID id;
|
||||
if (!verifyDecryptedNonce(certID, decryptedText, id)) {
|
||||
if (!verifyNonce(certID, text, id)) {
|
||||
if (!id.isNull()) {
|
||||
deleteEntity(id, true);
|
||||
}
|
||||
|
|
|
@ -275,8 +275,8 @@ public:
|
|||
|
||||
static const float DEFAULT_MAX_TMP_ENTITY_LIFETIME;
|
||||
|
||||
QByteArray computeEncryptedNonce(const QString& certID, const QString ownerKey);
|
||||
bool verifyDecryptedNonce(const QString& certID, const QString& decryptedNonce, EntityItemID& id);
|
||||
QByteArray computeNonce(const QString& certID, const QString ownerKey);
|
||||
bool verifyNonce(const QString& certID, const QString& nonce, EntityItemID& id);
|
||||
|
||||
void setMyAvatar(std::shared_ptr<AvatarData> myAvatar) { _myAvatar = myAvatar; }
|
||||
|
||||
|
@ -334,7 +334,7 @@ protected:
|
|||
QHash<QString, EntityItemID> _entityCertificateIDMap;
|
||||
|
||||
mutable QReadWriteLock _certNonceMapLock;
|
||||
QHash<QString, QUuid> _certNonceMap;
|
||||
QHash<QString, QPair<QUuid, QString>> _certNonceMap;
|
||||
|
||||
EntitySimulationPointer _simulation;
|
||||
|
||||
|
@ -383,7 +383,7 @@ protected:
|
|||
|
||||
private:
|
||||
void sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode);
|
||||
void sendChallengeOwnershipRequestPacket(const QByteArray& certID, const QByteArray& encryptedText, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode);
|
||||
void sendChallengeOwnershipRequestPacket(const QByteArray& certID, const QByteArray& text, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode);
|
||||
void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation);
|
||||
|
||||
std::shared_ptr<AvatarData> _myAvatar{ nullptr };
|
||||
|
|
|
@ -4,7 +4,4 @@ setup_hifi_library()
|
|||
link_hifi_libraries(shared model networking image)
|
||||
include_hifi_library_headers(gpu image)
|
||||
|
||||
add_dependency_external_projects(draco)
|
||||
find_package(Draco REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${DRACO_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${DRACO_LIBRARY} ${DRACO_ENCODER_LIBRARY})
|
||||
target_draco()
|
||||
|
|
|
@ -37,7 +37,7 @@ static const char* GL_BACKEND_PROPERTY_NAME = "com.highfidelity.gl.backend";
|
|||
BackendPointer GLBackend::createBackend() {
|
||||
// FIXME provide a mechanism to override the backend for testing
|
||||
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned
|
||||
auto version = QOpenGLContextWrapper::currentContextVersion();
|
||||
//auto version = QOpenGLContextWrapper::currentContextVersion();
|
||||
std::shared_ptr<GLBackend> result;
|
||||
|
||||
qDebug() << "Using OpenGL ES backend";
|
||||
|
|
|
@ -17,10 +17,10 @@ using namespace gpu::gl;
|
|||
|
||||
// Eventually, we want to test with TIME_ELAPSED instead of TIMESTAMP
|
||||
#ifdef Q_OS_MAC
|
||||
const uint32_t MAX_RANGE_QUERY_DEPTH = 1;
|
||||
//const uint32_t MAX_RANGE_QUERY_DEPTH = 1;
|
||||
static bool timeElapsed = true;
|
||||
#else
|
||||
const uint32_t MAX_RANGE_QUERY_DEPTH = 10000;
|
||||
//const uint32_t MAX_RANGE_QUERY_DEPTH = 10000;
|
||||
static bool timeElapsed = false;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -56,11 +56,11 @@ void GLBackend::syncPipelineStateCache() {
|
|||
|
||||
void GLBackend::do_setStateFillMode(int32 mode) {
|
||||
if (_pipeline._stateCache.fillMode != mode) {
|
||||
static GLenum GL_FILL_MODES[] = { /*GL_POINT, GL_LINE, GL_FILL*/ };
|
||||
//static GLenum GL_FILL_MODES[] = { /*GL_POINT, GL_LINE, GL_FILL*/ };
|
||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_MODES[mode]);
|
||||
qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode GL_POINT";
|
||||
qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode GL_LINE";
|
||||
qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode GL_FILL";
|
||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_MODES[mode]);
|
||||
qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode glPolygonMode";
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
|
|
|
@ -178,6 +178,10 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
|||
case gpu::NINT8:
|
||||
result = GL_RGBA8_SNORM;
|
||||
break;
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUINT2:
|
||||
case gpu::NINT16:
|
||||
case gpu::NUINT16:
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
case gpu::NUM_TYPES: // quiet compiler
|
||||
|
@ -446,6 +450,8 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
texel.internalFormat = GL_R8_SNORM;
|
||||
break;
|
||||
}
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUINT2:
|
||||
case gpu::NUM_TYPES: { // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
@ -489,6 +495,8 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
||||
break;
|
||||
}
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUINT2:
|
||||
case gpu::NUM_TYPES: { // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
@ -614,6 +622,8 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
break;
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUINT2:
|
||||
case gpu::NUM_TYPES: // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
|
|
@ -166,8 +166,7 @@ void GLESBackend::do_drawIndexedInstanced(const Batch& batch, size_t paramOffset
|
|||
void GLESBackend::do_multiDrawIndirect(const Batch& batch, size_t paramOffset) {
|
||||
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
|
||||
uint commandCount = batch._params[paramOffset + 0]._uint;
|
||||
GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint];
|
||||
|
||||
//GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint];
|
||||
//glMultiDrawArraysIndirect(mode, reinterpret_cast<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
|
||||
qDebug() << "TODO: GLESBackend.cpp:do_multiDrawIndirect do_multiDrawIndirect";
|
||||
_stats._DSNumDrawcalls += commandCount;
|
||||
|
@ -183,9 +182,8 @@ void GLESBackend::do_multiDrawIndirect(const Batch& batch, size_t paramOffset) {
|
|||
void GLESBackend::do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffset) {
|
||||
//#if (GPU_INPUT_PROFILE == GPU_CORE_43)
|
||||
uint commandCount = batch._params[paramOffset + 0]._uint;
|
||||
GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint];
|
||||
GLenum indexType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType];
|
||||
|
||||
//GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint];
|
||||
//GLenum indexType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType];
|
||||
//glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
|
||||
qDebug() << "TODO: GLESBackend.cpp:do_multiDrawIndexedIndirect glMultiDrawElementsIndirect";
|
||||
_stats._DSNumDrawcalls += commandCount;
|
||||
|
|
|
@ -99,7 +99,8 @@ public:
|
|||
if (!_colorBuffers.empty()) {
|
||||
glDrawBuffers((GLsizei)_colorBuffers.size(), _colorBuffers.data());
|
||||
} else {
|
||||
glDrawBuffers(1, {GL_NONE});
|
||||
static const std::vector<GLenum> NO_BUFFERS{ GL_NONE };
|
||||
glDrawBuffers((GLsizei)NO_BUFFERS.size(), NO_BUFFERS.data());
|
||||
}
|
||||
|
||||
// Now check for completness
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "Image.h"
|
||||
|
||||
#include <nvtt/nvtt.h>
|
||||
#include <glm/gtc/packing.hpp>
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
@ -20,6 +19,15 @@
|
|||
#include <QBuffer>
|
||||
#include <QImageReader>
|
||||
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#define CPU_MIPMAPS 0
|
||||
#else
|
||||
#define CPU_MIPMAPS 1
|
||||
#include <nvtt/nvtt.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <Finally.h>
|
||||
#include <Profile.h>
|
||||
#include <StatTracker.h>
|
||||
|
@ -29,13 +37,6 @@
|
|||
|
||||
using namespace gpu;
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#define CPU_MIPMAPS 0
|
||||
#else
|
||||
#define CPU_MIPMAPS 1
|
||||
#include <nvtt/nvtt.h>
|
||||
#endif
|
||||
|
||||
|
||||
static const glm::uvec2 SPARSE_PAGE_SIZE(128);
|
||||
static const glm::uvec2 MAX_TEXTURE_SIZE(4096);
|
||||
|
@ -410,7 +411,6 @@ struct MyErrorHandler : public nvtt::ErrorHandler {
|
|||
qCWarning(imagelogging) << "Texture compression error:" << nvtt::errorString(e);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class SequentialTaskDispatcher : public nvtt::TaskDispatcher {
|
||||
public:
|
||||
|
@ -637,6 +637,10 @@ void generateLDRMips(gpu::Texture* texture, QImage& image, const std::atomic<boo
|
|||
compressor.process(inputOptions, compressionOptions, outputOptions);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>& abortProcessing = false, int face = -1) {
|
||||
#if CPU_MIPMAPS
|
||||
PROFILE_RANGE(resource_parse, "generateMips");
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <memory>
|
||||
|
||||
#include <QtCore/QCryptographicHash>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtNetwork/QAbstractNetworkCache>
|
||||
|
||||
#include "NetworkAccessManager.h"
|
||||
|
|
|
@ -12,9 +12,10 @@
|
|||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <qjsondocument.h>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDataStream>
|
||||
#include <QtCore/QCryptographicHash>
|
||||
|
||||
#include <UUID.h>
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
#include <QtNetwork/QHostInfo>
|
||||
|
||||
#include <LogHandler.h>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QDateTime>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <SharedUtil.h>
|
||||
|
|
|
@ -211,6 +211,6 @@ void CauterizedModel::updateRenderItems() {
|
|||
}
|
||||
|
||||
const Model::MeshState& CauterizedModel::getCauterizeMeshState(int index) const {
|
||||
assert(index < _meshStates.size());
|
||||
assert((size_t)index < _meshStates.size());
|
||||
return _cauterizeMeshStates.at(index);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
|
||||
#include "DebugDeferredBuffer.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QDateTime>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
|
|
|
@ -180,7 +180,7 @@ LightStage::LightPointer LightStage::removeLight(Index index) {
|
|||
_lightMap.erase(removedLight);
|
||||
_descs[index] = Desc();
|
||||
}
|
||||
assert(_descs.size() <= index || _descs[index].shadowId == INVALID_INDEX);
|
||||
assert(_descs.size() <= (size_t)index || _descs[index].shadowId == INVALID_INDEX);
|
||||
return removedLight;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue