Merge branch 'main' into contributions
1
JKXR-PCVR-Installer/JKA/TeamBeefVR.bat
Normal file
|
@ -0,0 +1 @@
|
|||
openjk_sp.x86_64.exe
|
1
JKXR-PCVR-Installer/JKO/TeamBeefVR.bat
Normal file
|
@ -0,0 +1 @@
|
|||
openjo_sp.x86_64.exe
|
|
@ -2,7 +2,7 @@
|
|||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||
|
||||
#define MyAppName "JKXR - Jedi Academy"
|
||||
#define MyAppVersion "1.0.22"
|
||||
#define MyAppVersion "1.1.27"
|
||||
#define MyAppPublisher "Team Beef VR"
|
||||
#define MyAppURL "https://www.patreon.com/teambeef"
|
||||
#define MyAppExeName "openjk_sp.x86_64.exe"
|
||||
|
@ -24,7 +24,7 @@ DisableProgramGroupPage=yes
|
|||
;PrivilegesRequired=lowest
|
||||
OutputDir=C:\Dev\Quest\JKXR\JKXR-PCVR-Installer
|
||||
OutputBaseFilename=JKXR_JKA_Setup
|
||||
Compression=lzma
|
||||
Compression=zip
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
AlwaysShowDirOnReadyPage=yes
|
||||
|
@ -40,6 +40,7 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{
|
|||
[Files]
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKA\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKA\jagamex86_64.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKA\TeamBeefVR.bat"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKA\OpenAL32.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKA\rdsp-vanilla_x86_64.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\packaged_mods_credits.txt"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||
|
||||
#define MyAppName "JKXR - Jedi Outcast"
|
||||
#define MyAppVersion "1.0.22"
|
||||
#define MyAppVersion "1.1.27"
|
||||
#define MyAppPublisher "Team Beef VR"
|
||||
#define MyAppURL "https://www.patreon.com/teambeef"
|
||||
#define MyAppExeName "openjo_sp.x86_64.exe"
|
||||
|
@ -10,7 +10,7 @@
|
|||
[Setup]
|
||||
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
|
||||
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
||||
AppId={{3B2C9382-66B4-48E6-B625-F567F350283D}
|
||||
AppId={{962B9188-98B6-4216-BEB8-C8BCF901C6D0}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
;AppVerName={#MyAppName} {#MyAppVersion}
|
||||
|
@ -24,7 +24,7 @@ DisableProgramGroupPage=yes
|
|||
;PrivilegesRequired=lowest
|
||||
OutputDir=C:\Dev\Quest\JKXR\JKXR-PCVR-Installer
|
||||
OutputBaseFilename=JKXR_JKO_Setup
|
||||
Compression=lzma
|
||||
Compression=zip
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
AlwaysShowDirOnReadyPage=yes
|
||||
|
@ -40,6 +40,7 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{
|
|||
[Files]
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKO\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKO\jospgamex86_64.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKO\TeamBeefVR.bat"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKO\OpenAL32.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKO\rdjosp-vanilla_x86_64.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "C:\Dev\Quest\JKXR\JKXR-PCVR-Installer\JKO\SDL2.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
|
||||
####################################################
|
||||
# INSTALL AND RUN INSTRUCTIONS FOR JKXR FOR PCVR #
|
||||
####################################################
|
||||
|
||||
|
||||
|
||||
NOTES ON OPENXR
|
||||
===============
|
||||
|
||||
|
||||
This build of JKXR has so far only been tested on Meta and Pico devices. We recommend if you are using a Meta device that you set Oculus as the default OpenXR runtime. For all other devices you can set SteamVR as the OpenXR runtime. We're looking for feedback on what works and what doesn't (with Vive Wands expected not to work as yet - but still need info). If your headset manufacturer includes an OpenXR runtime better to use that.... use SteamVR as a fallback.
|
||||
|
||||
|
||||
|
||||
|
||||
STEAM INSTALLS
|
||||
==============
|
||||
|
||||
Please note, any instructions below that are for Jedi Outcast, the exact same instructions are applicable to Jedi Academy, though the folder/file names need to be change as appropriate.
|
||||
|
||||
|
||||
To Install
|
||||
----------
|
||||
|
||||
Simply double click on the file: Steam__Install.bat
|
||||
|
||||
This should copy all the necessary bits to the right places.
|
||||
If it fails, then you will have to find your steam install folder and follow the non-steam instructions below.
|
||||
|
||||
NOTE: If you've played JKO/JKA using OpenJK in the past, then there will probably be an old config file lying around that may mess stuff up.. browse to the install folder and delete openjo_sp.cfg or openjk_sp.cfg
|
||||
|
||||
|
||||
To Run
|
||||
------
|
||||
|
||||
Simply double click on the file: Steam__Run_JKXR.bat
|
||||
|
||||
|
||||
To Uninstall
|
||||
------------
|
||||
|
||||
Simply double click on the file: Steam__Uninstall.bat
|
||||
|
||||
|
||||
|
||||
|
||||
FOR OTHER (NON-STEAM)
|
||||
=====================
|
||||
|
||||
Please note, the instructions below are for Jedi Outcast, the exact same instructions are applicable to Jedi Academy, though the folder names need to be change as appropriate.
|
||||
|
||||
|
||||
To Install
|
||||
----------
|
||||
|
||||
You'll need to locate the folder in which your copy of Jedi Knight: Jedi Outcast/Academy is installed.
|
||||
|
||||
|
||||
For Jedi Outcast copy the following files into the same folder as the jk2sp.exe:
|
||||
|
||||
openjk_sp.x86_64.exe
|
||||
jagamex86_64.dll
|
||||
rdsp-vanilla_x86_64.dll
|
||||
SDL2.dll
|
||||
|
||||
|
||||
For Jedi Academy copy the following files into the same folder as the jasp.exe:
|
||||
|
||||
openjo_sp.x86_64.exe
|
||||
jospgamex86_64.dll
|
||||
rdjosp-vanilla_x86_64.dll
|
||||
SDL2.dll
|
||||
|
||||
And copy all the pk3 files from the base folder into the base folder of your install.
|
||||
|
||||
NOTE: If you've played JKO/JKA using OpenJK in the past, then there will probably be an old config file lying around that may mess stuff up.. browse to the install folder and delete openjo_sp.cfg or openjk_sp.cfg
|
||||
|
||||
|
||||
ANOTHER NOTE: Alternatively you can actually play JKXR from the extracted folder location.. all you need to do in that case is copy the pk3 files from your installation of Jedi Outcast/Academy into the base folder in the location you extracted the 7zip archive to. In this case if you are playing the single player campaign on flatscreen, none of the VR modifications will interfere with your game.
|
||||
|
||||
|
||||
To Start
|
||||
--------
|
||||
|
||||
Simply double click the executable you copied in to your JKO install folder: openjo_sp.x86_64.exe
|
||||
|
||||
|
||||
To Uninstall
|
||||
------------
|
||||
|
||||
Delete all the files you copied over originally
|
||||
|
||||
|
||||
|
||||
THINGS TO NOTE
|
||||
==============
|
||||
|
||||
1. There are bugs - feedback appreciated
|
||||
2. You will probably have to map your controllers if you aren't using a Quest or a Pico as we've not touched any controller mappings and configuration yet
|
||||
3. If you have no sound, ensure the JKXR window has focus and that you have selected your headset as the primary sound output
|
||||
|
||||
|
||||
|
||||
MODS
|
||||
====
|
||||
|
||||
This package contains some mods, please see the packaged_mods_credits.txt file for credits
|
||||
|
||||
We highly recommend the Expanded Menu for Jedi Outcast mod, this has a lot of excellent functionality:
|
||||
https://www.moddb.com/mods/jedi-outcast-expanded-menu
|
||||
|
||||
We also recommend The Ladder for Jedi Outcast:
|
||||
https://mrwonko.de/jk3files/Jedi%20Outcast/Maps/Single%20Player/2198/
|
||||
|
||||
Other mods will work with this build, however YMMV
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.drbeef.jkxr"
|
||||
android:versionCode="67"
|
||||
android:versionName="1.1.25" android:installLocation="auto" >
|
||||
android:versionCode="70"
|
||||
android:versionName="1.1.28" android:installLocation="auto" >
|
||||
|
||||
<!-- Tell the system this app requires OpenGL ES 3.1. -->
|
||||
<uses-feature android:glEsVersion="0x00030002" android:required="true"/>
|
||||
|
@ -17,8 +17,9 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
|
||||
<application android:allowBackup="false"
|
||||
android:icon="@drawable/ic_jkxr"
|
||||
android:icon="@mipmap/teambeef"
|
||||
android:label="@string/jkxr"
|
||||
android:extractNativeLibs="true"
|
||||
android:requestLegacyExternalStorage="true" >
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
google() // For Gradle 4.0+
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply from: "${rootProject.projectDir}/XrApp.gradle"
|
||||
|
||||
android {
|
||||
// This is the name of the generated apk file, which will have
|
||||
|
@ -14,12 +24,13 @@ android {
|
|||
// will replace an older one.
|
||||
applicationId "com.drbeef." + project.archivesBaseName
|
||||
|
||||
// override app plugin abiFilters for both 32 and 64-bit support
|
||||
externalNativeBuild {
|
||||
ndk {
|
||||
abiFilters 'arm64-v8a'
|
||||
}
|
||||
ndkBuild {
|
||||
def numProcs = Runtime.runtime.availableProcessors()
|
||||
arguments "V=0", "-j$numProcs", "-C$project.buildDir.parent", "APP_PLATFORM=android-29", "NDK_TOOLCHAIN_VERSION=clang", "APP_STL=c++_static"
|
||||
abiFilters 'arm64-v8a'
|
||||
}
|
||||
}
|
||||
|
@ -28,26 +39,95 @@ android {
|
|||
targetSdkVersion 29
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path file('jni/Android.mk')
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
def keystorePath = (project.hasProperty('key.store')) ?
|
||||
new File(project.getProperty('key.store')) :
|
||||
project.file('android.debug.keystore')
|
||||
|
||||
def keystorePassword = (project.hasProperty('key.store.password')) ?
|
||||
project.getProperty('key.store.password') : 'android'
|
||||
|
||||
def keystoreKeyAlias = (project.hasProperty('key.alias')) ?
|
||||
project.getProperty('key.alias') : 'androiddebugkey'
|
||||
|
||||
def keystoreKeyPassword = (project.hasProperty('key.alias.password')) ?
|
||||
project.getProperty('key.alias.password') : 'android'
|
||||
|
||||
debug {
|
||||
storeFile keystorePath
|
||||
storePassword keystorePassword
|
||||
keyAlias keystoreKeyAlias
|
||||
keyPassword keystoreKeyPassword
|
||||
v2SigningEnabled true
|
||||
}
|
||||
|
||||
release {
|
||||
storeFile keystorePath
|
||||
storePassword keystorePassword
|
||||
keyAlias keystoreKeyAlias
|
||||
keyPassword keystoreKeyPassword
|
||||
v2SigningEnabled true
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
debuggable true
|
||||
jniDebuggable true
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "NDK_DEBUG=1","USE_ASAN=1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
debuggable false
|
||||
jniDebuggable false
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "NDK_DEBUG=0","USE_ASAN=0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets.main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = ['../../java']
|
||||
jniLibs.srcDir 'libs'
|
||||
res.srcDirs = ['../../res']
|
||||
assets.srcDirs = ['../../assets']
|
||||
}
|
||||
jni.srcDirs = ['jni']
|
||||
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'lib/arm64-v8a/libopenxr_loader.so'
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
disable 'ExpiredTargetSdkVersion'
|
||||
}
|
||||
|
||||
//packagingOptions {
|
||||
// exclude 'lib/arm64-v8a/libopenxr_loader.so'
|
||||
//}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = '1.8'
|
||||
targetCompatibility = '1.8'
|
||||
}
|
||||
compileSdkVersion = 29
|
||||
buildToolsVersion = '29.0.3'
|
||||
ndkVersion '21.1.6352462'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -59,12 +139,15 @@ dependencies {
|
|||
repositories {
|
||||
google()
|
||||
}
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
}
|
||||
|
||||
// Workaround to fix issue in Android Studio Chipmunk 2021.2.1 and later
|
||||
// where opening a project would result in a 'prepareKotlinBuildScriptModel'
|
||||
// not found error
|
||||
if (!tasks.findByName("prepareKotlinBuildScriptModel")) {
|
||||
tasks.register("prepareKotlinBuildScriptModel") {}
|
||||
}
|
||||
|
||||
|
||||
task packBaseResources(type: Zip) {
|
||||
from "../../z_vr_assets_base/"
|
||||
destinationDir file("../../assets/")
|
||||
|
|
8
Projects/Android/gradle.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
org.gradle.jvmargs=-Xmx1536M \
|
||||
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED \
|
||||
--add-opens=java.base/java.lang=ALL-UNNAMED \
|
||||
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
|
||||
--add-opens=java.base/java.io=ALL-UNNAMED \
|
||||
--add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED
|
||||
org.gradle.caching=true
|
||||
org.gradle.configureondemand=true
|
|
@ -1,6 +1,5 @@
|
|||
#Sun Sep 04 16:36:21 BST 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -802,15 +802,24 @@ void TBXR_UpdateControllers( )
|
|||
trackpadPosition = GetActionStateVector2(trackPadAction, SIDE_LEFT).currentState;
|
||||
if (GetActionStateBoolean(trackPadClickAction, SIDE_LEFT).currentState)
|
||||
{
|
||||
if (trackpadPosition.x >= -0.2 && trackpadPosition.x <= 0.2)
|
||||
if (trackpadPosition.x >= -0.3 && trackpadPosition.x <= 0.3)
|
||||
{
|
||||
if (trackpadPosition.y >= 0.2)
|
||||
{
|
||||
leftTrackedRemoteState_new.Buttons |= xrButton_Y;
|
||||
//Always the in center for crouch
|
||||
//Crouch
|
||||
leftTrackedRemoteState_new.Buttons |= xrButton_LThumb;
|
||||
leftTrackedRemoteState_new.Buttons |= xrButton_Joystick;
|
||||
}
|
||||
else if (trackpadPosition.y <= -0.2)
|
||||
else
|
||||
{
|
||||
leftTrackedRemoteState_new.Buttons |= xrButton_X;
|
||||
if (trackpadPosition.x <= -0.3) //Left
|
||||
{
|
||||
//Ingame Menu - dont need this on Vive
|
||||
//leftTrackedRemoteState_new.Buttons |= xrButton_X;
|
||||
}
|
||||
else if(trackpadPosition.x >= 0.3) //Right
|
||||
{
|
||||
//DataPad
|
||||
leftTrackedRemoteState_new.Buttons |= xrButton_Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -821,31 +830,48 @@ void TBXR_UpdateControllers( )
|
|||
if (GetActionStateBoolean(XTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_X;
|
||||
if (GetActionStateBoolean(YAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Y;
|
||||
if (GetActionStateBoolean(YTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_Y;
|
||||
if (GetActionStateBoolean(thumbstickClickAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_LThumb;
|
||||
if (GetActionStateBoolean(thumbstickClickAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Joystick;
|
||||
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_LThumb;
|
||||
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_Joystick;
|
||||
}
|
||||
|
||||
//Defaults engage/disable at the same level
|
||||
float enableLevel = vr_engage_trigger->value;
|
||||
float disableLevel = vr_release_trigger->value;
|
||||
//INDEX we'll need to add force check so its not boolean
|
||||
if (gAppState.controllersPresent == VIVE_CONTROLLERS)
|
||||
{
|
||||
leftTrackedRemoteState_new.GripTrigger = GetActionStateBoolean(squeezeClickAction, SIDE_LEFT).currentState;
|
||||
enableLevel = 1.0f;
|
||||
disableLevel = 1.0f;
|
||||
}
|
||||
else if (gAppState.controllersPresent == INDEX_CONTROLLERS)
|
||||
{
|
||||
leftTrackedRemoteState_new.GripTrigger = GetActionStateFloat(squeezeForceAction, SIDE_LEFT).currentState;
|
||||
// Use different release level for the Index Knuckles
|
||||
enableLevel = vr_engage_trigger_index->value;
|
||||
disableLevel = vr_release_trigger_index->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftTrackedRemoteState_new.GripTrigger = GetActionStateFloat(squeezeAction, SIDE_LEFT).currentState;
|
||||
}
|
||||
if (leftTrackedRemoteState_new.GripTrigger > 0.7f)
|
||||
|
||||
static int leftGripEngaged = false;
|
||||
if (leftTrackedRemoteState_new.GripTrigger >= enableLevel && !leftGripEngaged)
|
||||
{
|
||||
leftGripEngaged = true;
|
||||
}
|
||||
else if (leftTrackedRemoteState_new.GripTrigger < disableLevel && leftGripEngaged)
|
||||
{
|
||||
leftGripEngaged = false;
|
||||
}
|
||||
if (leftGripEngaged)
|
||||
{
|
||||
leftTrackedRemoteState_new.Buttons |= xrButton_GripTrigger;
|
||||
}
|
||||
|
||||
if (GetActionStateBoolean(thumbstickClickAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_LThumb;
|
||||
if (GetActionStateBoolean(thumbstickClickAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Joystick;
|
||||
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_LThumb;
|
||||
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_Joystick;
|
||||
|
||||
leftTrackedRemoteState_new.IndexTrigger = GetActionStateFloat(triggerAction, SIDE_LEFT).currentState;
|
||||
if (leftTrackedRemoteState_new.IndexTrigger > 0.5f) leftTrackedRemoteState_new.Buttons |= xrButton_Trigger;
|
||||
if (GetActionStateBoolean(triggerTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_Trigger;
|
||||
|
@ -867,15 +893,25 @@ void TBXR_UpdateControllers( )
|
|||
{
|
||||
if (trackpadPosition.x >= -0.2 && trackpadPosition.x <= 0.2)
|
||||
{
|
||||
if (trackpadPosition.y >= 0.2)
|
||||
if (trackpadPosition.y >= 0.3)
|
||||
{
|
||||
//Menu button on Vive instead
|
||||
rightTrackedRemoteState_new.Buttons |= xrButton_B;
|
||||
}
|
||||
else if (trackpadPosition.y <= -0.2)
|
||||
else if (trackpadPosition.y <= -0.3)
|
||||
{
|
||||
rightTrackedRemoteState_new.Buttons |= xrButton_A;
|
||||
}
|
||||
else
|
||||
{
|
||||
rightTrackedRemoteState_new.Buttons |= xrButton_Joystick;
|
||||
rightTrackedRemoteState_new.Buttons |= xrButton_RThumb;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rightTrackedRemoteState_new.Buttons |= xrButton_Joystick;
|
||||
rightTrackedRemoteState_new.Buttons |= xrButton_RThumb;
|
||||
}
|
||||
}
|
||||
if (GetActionStateBoolean(backAction, SIDE_RIGHT).currentState)
|
||||
|
@ -890,9 +926,16 @@ void TBXR_UpdateControllers( )
|
|||
if (GetActionStateBoolean(BAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_B;
|
||||
if (GetActionStateBoolean(BTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_B;
|
||||
if (GetActionStateBoolean(backAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Enter;
|
||||
if (GetActionStateBoolean(thumbstickClickAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_RThumb;
|
||||
if (GetActionStateBoolean(thumbstickClickAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Joystick;
|
||||
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_RThumb;
|
||||
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_Joystick;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//INDEX we'll need to add force check so its not boolean
|
||||
//Defaults engage/disable at the same level
|
||||
if (gAppState.controllersPresent == VIVE_CONTROLLERS)
|
||||
{
|
||||
rightTrackedRemoteState_new.GripTrigger = GetActionStateBoolean(squeezeClickAction, SIDE_RIGHT).currentState;
|
||||
|
@ -905,12 +948,23 @@ void TBXR_UpdateControllers( )
|
|||
{
|
||||
rightTrackedRemoteState_new.GripTrigger = GetActionStateFloat(squeezeAction, SIDE_RIGHT).currentState;
|
||||
}
|
||||
if (rightTrackedRemoteState_new.GripTrigger > 0.7f) rightTrackedRemoteState_new.Buttons |= xrButton_GripTrigger;
|
||||
|
||||
if (GetActionStateBoolean(thumbstickClickAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_RThumb;
|
||||
if (GetActionStateBoolean(thumbstickClickAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Joystick;
|
||||
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_RThumb;
|
||||
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_Joystick;
|
||||
static int rightGripEngaged = false;
|
||||
if (rightTrackedRemoteState_new.GripTrigger >= enableLevel && !rightGripEngaged)
|
||||
{
|
||||
rightGripEngaged = true;
|
||||
}
|
||||
else if (rightTrackedRemoteState_new.GripTrigger < disableLevel && rightGripEngaged)
|
||||
{
|
||||
rightGripEngaged = false;
|
||||
}
|
||||
|
||||
if (rightGripEngaged)
|
||||
{
|
||||
rightTrackedRemoteState_new.Buttons |= xrButton_GripTrigger;
|
||||
}
|
||||
|
||||
|
||||
rightTrackedRemoteState_new.IndexTrigger = GetActionStateFloat(triggerAction, SIDE_RIGHT).currentState;
|
||||
if (rightTrackedRemoteState_new.IndexTrigger > 0.5f) rightTrackedRemoteState_new.Buttons |= xrButton_Trigger;
|
||||
if (GetActionStateBoolean(triggerTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_Trigger;
|
||||
|
|
|
@ -2,6 +2,7 @@ extern cvar_t *vr_turn_mode;
|
|||
extern cvar_t *vr_turn_angle;
|
||||
extern cvar_t *vr_positional_factor;
|
||||
extern cvar_t *vr_walkdirection;
|
||||
extern cvar_t *vr_3rdperson_digital_direction;
|
||||
extern cvar_t *vr_weapon_pitchadjust;
|
||||
extern cvar_t *vr_saber_pitchadjust;
|
||||
extern cvar_t *vr_control_scheme;
|
||||
|
@ -34,3 +35,7 @@ extern cvar_t *vr_use_gesture_boundary;
|
|||
extern cvar_t *vr_align_weapons; // Only used for development
|
||||
extern cvar_t *vr_refresh;
|
||||
extern cvar_t *vr_super_sampling;
|
||||
extern cvar_t *vr_engage_trigger;
|
||||
extern cvar_t *vr_release_trigger;
|
||||
extern cvar_t *vr_engage_trigger_index;
|
||||
extern cvar_t *vr_release_trigger_index;
|
||||
|
|
|
@ -15,6 +15,7 @@ cvar_t *vr_turn_mode;
|
|||
cvar_t *vr_turn_angle;
|
||||
cvar_t *vr_positional_factor;
|
||||
cvar_t *vr_walkdirection;
|
||||
cvar_t *vr_3rdperson_digital_direction;
|
||||
cvar_t *vr_weapon_pitchadjust;
|
||||
cvar_t *vr_saber_pitchadjust;
|
||||
cvar_t *vr_control_scheme;
|
||||
|
@ -47,6 +48,10 @@ cvar_t *vr_use_gesture_boundary;
|
|||
cvar_t *vr_align_weapons;
|
||||
cvar_t *vr_refresh;
|
||||
cvar_t *vr_super_sampling;
|
||||
cvar_t *vr_engage_trigger;
|
||||
cvar_t *vr_release_trigger;
|
||||
cvar_t *vr_engage_trigger_index;
|
||||
cvar_t *vr_release_trigger_index;
|
||||
|
||||
ovrInputStateTrackedRemote leftTrackedRemoteState_old;
|
||||
ovrInputStateTrackedRemote leftTrackedRemoteState_new;
|
||||
|
|
|
@ -39,6 +39,8 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
|||
vr.right_handed = vr_control_scheme->value < 10 ||
|
||||
vr_control_scheme->value == 99; // Always right-handed for weapon calibration
|
||||
|
||||
bool thirdPersonActive = !!((int) Cvar_VariableValue("cg_thirdPerson"));
|
||||
|
||||
static bool dominantGripPushed = false;
|
||||
|
||||
//Need this for the touch screen
|
||||
|
@ -347,7 +349,7 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
|||
VectorNormalize(weaponForward);
|
||||
|
||||
if (cl.frame.ps.weapon > WP_SABER &&
|
||||
DotProduct(weaponForward, dir) > 0.8f)
|
||||
DotProduct(weaponForward, dir) > 0.6f)
|
||||
{
|
||||
vr.weapon_stabilised = true;
|
||||
}
|
||||
|
@ -808,7 +810,7 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
|||
vr.offhandoffset[1] = pOff->Pose.position.y - vr.hmdposition[1];
|
||||
vr.offhandoffset[2] = pOff->Pose.position.z - vr.hmdposition[2];
|
||||
|
||||
if (vr_walkdirection->value == 0) {
|
||||
if (vr_walkdirection->value == 0 && !thirdPersonActive) {
|
||||
controllerYawHeading = vr.offhandangles[ANGLES_ADJUSTED][YAW] - vr.hmdorientation[YAW];
|
||||
} else {
|
||||
controllerYawHeading = 0.0f;
|
||||
|
@ -954,6 +956,17 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
|||
vec2_t v;
|
||||
rotateAboutOrigin(x, y, controllerYawHeading, v);
|
||||
|
||||
// If in third person, use digital input (North, North-East, East, South-East etc)
|
||||
// for movement as it allows execution of player special moves correctly in JKA
|
||||
if (thirdPersonActive && vr_3rdperson_digital_direction->integer)
|
||||
{
|
||||
float angle = RAD2DEG(atan2f(v[1], v[0])) + 22.5;
|
||||
int segment = angle / 45.0f;
|
||||
angle = segment * 45.0f;
|
||||
v[0] = nlf * cosf(DEG2RAD(angle));
|
||||
v[1] = nlf * sinf(DEG2RAD(angle));
|
||||
}
|
||||
|
||||
float move_speed_multiplier = 1.0f;
|
||||
switch (vr.move_speed)
|
||||
{
|
||||
|
@ -968,7 +981,7 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
|||
break;
|
||||
}
|
||||
|
||||
if (vr_always_run->integer)
|
||||
if (vr_always_run->integer || vr_3rdperson_digital_direction->integer)
|
||||
{
|
||||
move_speed_multiplier = 1.0f;
|
||||
}
|
||||
|
@ -1072,7 +1085,7 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
|||
|
||||
if (!usingSnapTurn && fabs(primaryJoystickX) > 0.1f) //smooth turn
|
||||
{
|
||||
vr.snapTurn -= ((vr_turn_angle->value / 10.0f) *
|
||||
vr.snapTurn -= ((vr_turn_angle->value / 25.0f) *
|
||||
primaryJoystickX);
|
||||
if (vr.snapTurn > 180.0f) {
|
||||
vr.snapTurn -= 360.f;
|
||||
|
@ -1158,7 +1171,6 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
|||
|
||||
// Process "use" gesture
|
||||
if (vr_gesture_triggered_use->integer) {
|
||||
bool thirdPersonActive = !!((int) Cvar_VariableValue("cg_thirdPerson"));
|
||||
bool gestureUseAllowed = !vr.weapon_stabilised && !vr.cin_camera && !vr.misc_camera && !vr.remote_turret && !vr.emplaced_gun && !vr.in_vehicle && !thirdPersonActive;
|
||||
// Off-hand gesture
|
||||
float distanceToBody = sqrt(vr.offhandoffset[0]*vr.offhandoffset[0] + vr.offhandoffset[2]*vr.offhandoffset[2]);
|
||||
|
|
|
@ -328,6 +328,7 @@ void VR_Init()
|
|||
vr_turn_angle = Cvar_Get( "vr_turn_angle", "45", CVAR_ARCHIVE);
|
||||
vr_positional_factor = Cvar_Get( "vr_positional_factor", "12", CVAR_ARCHIVE);
|
||||
vr_walkdirection = Cvar_Get( "vr_walkdirection", "1", CVAR_ARCHIVE);
|
||||
vr_3rdperson_digital_direction = Cvar_Get( "vr_3rdperson_digital_direction", "1", CVAR_ARCHIVE);
|
||||
vr_weapon_pitchadjust = Cvar_Get( "vr_weapon_pitchadjust", "-20.0", CVAR_ARCHIVE);
|
||||
vr_saber_pitchadjust = Cvar_Get( "vr_saber_pitchadjust", "-13.36", CVAR_ARCHIVE);
|
||||
vr_virtual_stock = Cvar_Get( "vr_virtual_stock", "0", CVAR_ARCHIVE);
|
||||
|
@ -363,6 +364,10 @@ void VR_Init()
|
|||
vr_align_weapons = Cvar_Get ("vr_align_weapons", "0", CVAR_ARCHIVE);
|
||||
vr_refresh = Cvar_Get ("vr_refresh", "72", CVAR_ARCHIVE);
|
||||
vr_super_sampling = Cvar_Get ("vr_super_sampling", "1.0", CVAR_ARCHIVE);
|
||||
vr_engage_trigger = Cvar_Get("vr_engage_trigger", "0.7", CVAR_ARCHIVE);
|
||||
vr_release_trigger = Cvar_Get("vr_release_trigger", "0.7", CVAR_ARCHIVE);
|
||||
vr_engage_trigger_index = Cvar_Get("vr_engage_trigger_index", "0.7", CVAR_ARCHIVE);
|
||||
vr_release_trigger_index = Cvar_Get("vr_release_trigger_index", "0.05", CVAR_ARCHIVE);
|
||||
|
||||
cvar_t *expanded_menu_enabled = Cvar_Get ("expanded_menu_enabled", "0", CVAR_ARCHIVE);
|
||||
if (FS_FileExists("expanded_menu.pk3") || FS_BaseFileExists("expanded_menu.pk3")) {
|
||||
|
|
|
@ -1848,6 +1848,7 @@ void TBXR_FrameSetup()
|
|||
VR_FrameSetup();
|
||||
|
||||
//Get controller state here
|
||||
TBXR_updateProjections();
|
||||
TBXR_GetHMDOrientation();
|
||||
VR_HandleControllerInput();
|
||||
|
||||
|
@ -1947,8 +1948,6 @@ void TBXR_submitFrame()
|
|||
return;
|
||||
}
|
||||
|
||||
TBXR_updateProjections();
|
||||
|
||||
//Calculate the maximum extent fov for use in culling in the engine (we won't want to cull inside this fov)
|
||||
vr.fov_x = (fabs(gAppState.Views[0].fov.angleLeft) + fabs(gAppState.Views[1].fov.angleRight)) * 180.0f / M_PI;
|
||||
vr.fov_y = (fabs(gAppState.Views[0].fov.angleUp) + fabs(gAppState.Views[0].fov.angleDown)) * 180.0f / M_PI;
|
||||
|
@ -1972,8 +1971,12 @@ void TBXR_submitFrame()
|
|||
|
||||
if (usingScreenLayer) {
|
||||
usingScreenLayer = qfalse;
|
||||
float configuredSuperSampling = Cvar_VariableValue("vr_super_sampling");
|
||||
if (configuredSuperSampling != 0.0f && configuredSuperSampling != superSampling)
|
||||
{
|
||||
VR_ResetRenderer();
|
||||
}
|
||||
}
|
||||
|
||||
memset(&projection_layer, 0, sizeof(XrCompositionLayerProjection));
|
||||
projection_layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
|
||||
|
|
|
@ -246,6 +246,7 @@ void VR_Init()
|
|||
vr_turn_angle = Cvar_Get( "vr_turn_angle", "45", CVAR_ARCHIVE);
|
||||
vr_positional_factor = Cvar_Get( "vr_positional_factor", "12", CVAR_ARCHIVE);
|
||||
vr_walkdirection = Cvar_Get( "vr_walkdirection", "1", CVAR_ARCHIVE);
|
||||
vr_3rdperson_digital_direction = Cvar_Get( "vr_3rdperson_digital_direction", "1", CVAR_ARCHIVE);
|
||||
vr_weapon_pitchadjust = Cvar_Get( "vr_weapon_pitchadjust", "-20.0", CVAR_ARCHIVE);
|
||||
vr_saber_pitchadjust = Cvar_Get( "vr_saber_pitchadjust", "-13.36", CVAR_ARCHIVE);
|
||||
vr_virtual_stock = Cvar_Get( "vr_virtual_stock", "0", CVAR_ARCHIVE);
|
||||
|
@ -280,6 +281,10 @@ void VR_Init()
|
|||
vr_use_gesture_boundary = Cvar_Get ("vr_use_gesture_boundary", "0.35", CVAR_ARCHIVE);
|
||||
vr_align_weapons = Cvar_Get ("vr_align_weapons", "0", CVAR_ARCHIVE);
|
||||
vr_refresh = Cvar_Get ("vr_refresh", "72", CVAR_ARCHIVE);
|
||||
vr_engage_trigger = Cvar_Get("vr_engage_trigger", "0.7", CVAR_ARCHIVE);
|
||||
vr_release_trigger = Cvar_Get("vr_release_trigger", "0.7", CVAR_ARCHIVE);
|
||||
vr_engage_trigger_index = Cvar_Get("vr_engage_trigger_index", "0.7", CVAR_ARCHIVE);
|
||||
vr_release_trigger_index = Cvar_Get("vr_release_trigger_index", "0.05", CVAR_ARCHIVE);
|
||||
|
||||
cvar_t *expanded_menu_enabled = Cvar_Get ("expanded_menu_enabled", "0", CVAR_ARCHIVE);
|
||||
if (FS_FileExists("expanded_menu.pk3") || FS_BaseFileExists("expanded_menu.pk3")) {
|
||||
|
|
|
@ -1040,7 +1040,7 @@ void TBXR_FrameSetup()
|
|||
//Game specific frame setup stuff called here
|
||||
VR_FrameSetup();
|
||||
|
||||
//Get controller state here
|
||||
TBXR_updateProjections();
|
||||
TBXR_GetHMDOrientation();
|
||||
VR_HandleControllerInput();
|
||||
|
||||
|
@ -1148,8 +1148,6 @@ void TBXR_submitFrame()
|
|||
return;
|
||||
}
|
||||
|
||||
TBXR_updateProjections();
|
||||
|
||||
//Calculate the maximum extent fov for use in culling in the engine (we won't want to cull inside this fov)
|
||||
vr.fov_x = (fabs(gAppState.Views[0].fov.angleLeft) + fabs(gAppState.Views[1].fov.angleRight)) * 180.0f / M_PI;
|
||||
vr.fov_y = (fabs(gAppState.Views[0].fov.angleUp) + fabs(gAppState.Views[0].fov.angleDown)) * 180.0f / M_PI;
|
||||
|
|
|
@ -1634,26 +1634,20 @@ static void CG_DrawWeapReticle( void )
|
|||
vec4_t light_color = {0.7, 0.7, 0.7, 1};
|
||||
vec4_t black = {0.0, 0.0, 0.0, 1};
|
||||
|
||||
float indent = 0.1;
|
||||
float indent = 0.12;
|
||||
float X_WIDTH=640;
|
||||
float Y_HEIGHT=480;
|
||||
float STRETCH = 6;
|
||||
|
||||
float x = (X_WIDTH * indent), y = (Y_HEIGHT * indent), w = (X_WIDTH * (1-(2*indent))) / 2.0f, h = (Y_HEIGHT * (1-(2*indent))) / 2;
|
||||
|
||||
// sides
|
||||
CG_FillRect( 0, 0, (X_WIDTH * indent)+1, Y_HEIGHT, black );
|
||||
CG_FillRect( X_WIDTH * (1 - indent) - 1, 0, (X_WIDTH * indent) + 2, Y_HEIGHT, black );
|
||||
// top/bottom
|
||||
CG_FillRect( X_WIDTH * indent, 0, X_WIDTH * (1-indent), Y_HEIGHT * indent + 1, black );
|
||||
CG_FillRect( X_WIDTH * indent, Y_HEIGHT * (1-indent) - 1, X_WIDTH * (1-indent), Y_HEIGHT * indent + 2, black );
|
||||
|
||||
{
|
||||
// center
|
||||
if ( cgs.media.reticleShader ) {
|
||||
cgi_R_DrawStretchPic( x, y, w, h, 0, 0, 1, 1, cgs.media.reticleShader ); // tl
|
||||
cgi_R_DrawStretchPic( x + w, y, w, h, 1, 0, 0, 1, cgs.media.reticleShader ); // tr
|
||||
cgi_R_DrawStretchPic( x, y + h, w, h, 0, 1, 1, 0, cgs.media.reticleShader ); // bl
|
||||
cgi_R_DrawStretchPic( x + w, y + h, w, h, 1, 1, 0, 0, cgs.media.reticleShader ); // br
|
||||
cgi_R_DrawStretchPic( x - STRETCH, y - STRETCH, w + STRETCH, h+STRETCH, 0, 0, 1, 1, cgs.media.reticleShader ); // tl
|
||||
cgi_R_DrawStretchPic( x + w, y - STRETCH, w + STRETCH, h + STRETCH, 1, 0, 0, 1, cgs.media.reticleShader ); // tr
|
||||
cgi_R_DrawStretchPic( x - STRETCH, y + h, w + STRETCH, h + STRETCH, 0, 1, 1, 0, cgs.media.reticleShader ); // bl
|
||||
cgi_R_DrawStretchPic( x + w, y + h, w + STRETCH, h + STRETCH, 1, 1, 0, 0, cgs.media.reticleShader ); // br
|
||||
}
|
||||
|
||||
// hairs
|
||||
|
@ -1662,6 +1656,13 @@ static void CG_DrawWeapReticle( void )
|
|||
CG_FillRect( 319, 300, 2, 178, black ); // center bot
|
||||
CG_FillRect( 380, 239, 177, 2, black ); // right
|
||||
}
|
||||
|
||||
// sides
|
||||
CG_FillRect( 0, 0, (X_WIDTH * indent)+1, Y_HEIGHT, black );
|
||||
CG_FillRect( X_WIDTH * (1 - indent) - 1, 0, (X_WIDTH * indent) + 2, Y_HEIGHT, black );
|
||||
// top/bottom
|
||||
CG_FillRect( X_WIDTH * indent, 0, X_WIDTH * (1-indent), Y_HEIGHT * indent + 1, black );
|
||||
CG_FillRect( X_WIDTH * indent, Y_HEIGHT * (1-indent) - 1, X_WIDTH * (1-indent), Y_HEIGHT * indent + 2, black );
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
|
|
|
@ -1371,7 +1371,7 @@ void Com_Frame( void ) {
|
|||
TBXR_FrameSetup();
|
||||
|
||||
// write config file if anything changed
|
||||
Com_WriteConfiguration();
|
||||
//Com_WriteConfiguration();
|
||||
|
||||
//
|
||||
// main event loop
|
||||
|
@ -1571,6 +1571,10 @@ Com_Shutdown
|
|||
=================
|
||||
*/
|
||||
void Com_Shutdown (void) {
|
||||
|
||||
// write config file if anything changed
|
||||
Com_WriteConfiguration();
|
||||
|
||||
CM_ClearMap();
|
||||
|
||||
if (logfile) {
|
||||
|
|
|
@ -23,7 +23,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|||
// Current version of the single player game
|
||||
#include "../win32/AutoVersion.h"
|
||||
|
||||
#define JKXR_VERSION "1.1.25"
|
||||
#define JKXR_VERSION "1.1.28"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define Q3_VERSION "(debug)OpenJK: v" VERSION_STRING_DOTTED " JKXR: " JKXR_VERSION
|
||||
|
|
|
@ -728,26 +728,20 @@ static void CG_DrawWeapReticle( void )
|
|||
vec4_t light_color = {0.7, 0.7, 0.7, 1};
|
||||
vec4_t black = {0.0, 0.0, 0.0, 1};
|
||||
|
||||
float indent = 0.1;
|
||||
float indent = 0.12;
|
||||
float X_WIDTH=640;
|
||||
float Y_HEIGHT=480;
|
||||
float STRETCH = 6;
|
||||
|
||||
float x = (X_WIDTH * indent), y = (Y_HEIGHT * indent), w = (X_WIDTH * (1-(2*indent))) / 2.0f, h = (Y_HEIGHT * (1-(2*indent))) / 2;
|
||||
|
||||
// sides
|
||||
CG_FillRect(0, 0, (X_WIDTH * indent) + 1, Y_HEIGHT, black);
|
||||
CG_FillRect(X_WIDTH * (1 - indent) - 1, 0, (X_WIDTH * indent) + 2, Y_HEIGHT, black);
|
||||
// top/bottom
|
||||
CG_FillRect(X_WIDTH * indent, 0, X_WIDTH * (1 - indent), Y_HEIGHT * indent + 1, black);
|
||||
CG_FillRect(X_WIDTH * indent, Y_HEIGHT * (1 - indent) - 1, X_WIDTH * (1 - indent), Y_HEIGHT * indent + 2, black);
|
||||
|
||||
{
|
||||
// center
|
||||
if ( cgs.media.reticleShader ) {
|
||||
cgi_R_DrawStretchPic( x, y, w, h, 0, 0, 1, 1, cgs.media.reticleShader ); // tl
|
||||
cgi_R_DrawStretchPic( x + w, y, w, h, 1, 0, 0, 1, cgs.media.reticleShader ); // tr
|
||||
cgi_R_DrawStretchPic( x, y + h, w, h, 0, 1, 1, 0, cgs.media.reticleShader ); // bl
|
||||
cgi_R_DrawStretchPic( x + w, y + h, w, h, 1, 1, 0, 0, cgs.media.reticleShader ); // br
|
||||
cgi_R_DrawStretchPic( x - STRETCH, y - STRETCH, w + STRETCH, h+STRETCH, 0, 0, 1, 1, cgs.media.reticleShader ); // tl
|
||||
cgi_R_DrawStretchPic( x + w, y - STRETCH, w + STRETCH, h + STRETCH, 1, 0, 0, 1, cgs.media.reticleShader ); // tr
|
||||
cgi_R_DrawStretchPic( x - STRETCH, y + h, w + STRETCH, h + STRETCH, 0, 1, 1, 0, cgs.media.reticleShader ); // bl
|
||||
cgi_R_DrawStretchPic( x + w, y + h, w + STRETCH, h + STRETCH, 1, 1, 0, 0, cgs.media.reticleShader ); // br
|
||||
}
|
||||
|
||||
// hairs
|
||||
|
@ -756,6 +750,13 @@ static void CG_DrawWeapReticle( void )
|
|||
CG_FillRect( 319, 300, 2, 178, black ); // center bot
|
||||
CG_FillRect( 380, 239, 177, 2, black ); // right
|
||||
}
|
||||
|
||||
// sides
|
||||
CG_FillRect( 0, 0, (X_WIDTH * indent)+1, Y_HEIGHT, black );
|
||||
CG_FillRect( X_WIDTH * (1 - indent) - 1, 0, (X_WIDTH * indent) + 2, Y_HEIGHT, black );
|
||||
// top/bottom
|
||||
CG_FillRect( X_WIDTH * indent, 0, X_WIDTH * (1-indent), Y_HEIGHT * indent + 1, black );
|
||||
CG_FillRect( X_WIDTH * indent, Y_HEIGHT * (1-indent) - 1, X_WIDTH * (1-indent), Y_HEIGHT * indent + 2, black );
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
|
|
|
@ -5,5 +5,4 @@
|
|||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
#Thu Dec 12 20:21:11 GMT 2019
|
||||
ndk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\Sdk\\ndk\\21.1.6352462
|
||||
sdk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\Sdk
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
rootProject.projectDir = new File(settingsDir, '../..')
|
||||
//rootProject.projectDir = settingsDir
|
||||
rootProject.name = "JKXR"
|
||||
|
||||
include ':', 'Projects:Android'
|
||||
|
|
54
README.md
|
@ -7,25 +7,24 @@
|
|||
|
||||
[SideQuest Latest Version (Pico Headsets)](https://sidequestvr.com/app/15541)
|
||||
|
||||
[PCVR Installers (found on the latest release here)](https://github.com/DrBeef/JKXR/releases)
|
||||
|
||||
JK XR is a VR port of the Jedi Knight games using OpenXR (the open standard for virtual and augmented reality devices) and is based on the excellent OpenJK port, originally forked from: https://github.com/JACoders/OpenJK
|
||||
|
||||
This is currently built for standalone VR HMDs (see the Building section below) and will currently **not** run on any other device, the list of supported devices is: Meta Quest (1, 2, Pro) and Pico (3 & 4).
|
||||
|
||||
Support for PCVR based devices will hopefully come in the future.
|
||||
|
||||
The easiest way to install this on your device is using SideQuest. Download SideQuest here:
|
||||
https://sidequestvr.com/setup-howto
|
||||
|
||||
|
||||
|
||||
### Jedi Knight: Jedi Outcast
|
||||
### Jedi Knight: Jedi Outcast / Jedi Academy
|
||||
|
||||
The public release of JK XR currently supports the game Jedi Outcast; access to the Jedi Academy early-access build can be found on the Team Beef patreon (link below). However there are lots of mods and access to the free demo level available through the accomapnying JK XR Companion App, which is also installed alongside JK XR on SideQuest.
|
||||
The public release of JK XR now supports the games Jedi Outcast and Jedi Academy.
|
||||
|
||||
## Team Beef Patreon
|
||||
[![Team Beef Patreon](https://github.com/DrBeef/JKXR/blob/main/assets/PatreonBanner.jpg)](https://www.patreon.com/teambeef)
|
||||
|
||||
The Team Beef Patreon where you can find all the in-development early-access builds for JK XR with Jedi Academy support, as well as other active projects can be found.
|
||||
The Team Beef Patreon where you can find all the in-development early-access builds other active Team Beef projects.
|
||||
|
||||
|
||||
## Gameplay and VR Features
|
||||
|
@ -68,22 +67,51 @@ The companion app will be installed at the same time when using the SideQuest of
|
|||
You can find the latest version, which also includes the Companion App hosted on Sidequest. Use the links at the top of the page (separated by headset). Before installing via SideQuest you must have enabled "Developer Mode" on your headset. You can find the details on how to do that below:
|
||||
|
||||
Pico 3/4 Instructions
|
||||
---------------------
|
||||
https://trello.com/c/Idb627uv/47-pico-4-installation-instructions
|
||||
|
||||
Meta Quest Install Instructions
|
||||
-------------------------------
|
||||
https://trello.com/c/C0YTFpvX/48-quest-quest-2-installation-instructions
|
||||
|
||||
## Copying the Full Game files to your Oculus Quest
|
||||
PCVR
|
||||
----
|
||||
Download the PCVR installers from the release page and use them to install to the game location.
|
||||
|
||||
### OpenXR runtimes information for PCVR Headsets
|
||||
|
||||
We recommend the following combinations to get the optimal experience while playing JKXR on PCVR:
|
||||
|
||||
**Valve Index** -> Via SteamVR (SteamVR OpenXR Runtime)
|
||||
|
||||
**HTC Vive** -> Via SteamVR (SteamVR OpenXR Runtime)
|
||||
|
||||
**Meta Headsets** -> Link / Airlink (Oculus OpenXR Runtime) / SteamLink / Virtual Desktop (VDXR or SteamVR)
|
||||
|
||||
**Windows Mixed Reality (WMR) Devices** (I.e. HP G2) -> Make sure you set the SteamVR to be the default OpenXR runtime.
|
||||
|
||||
**Pimax** -> Currently unplayable. We have been in discussions with Pimax and there is a new PimaxPlay that fixes the issues (upside down screens).
|
||||
When released the game must be played via unofficial PimaxXR OpenXR runtime (https://github.com/mbucchia/Pimax-OpenXR). Do not play via SteamVR OpenXR runtime
|
||||
|
||||
**Pico** - Virtual Desktop (VDXR or SteamVR) / Streaming Assistant (Currently Untested)
|
||||
|
||||
|
||||
## Copying the Full Game files to your Meta Quest / Pico
|
||||
|
||||
Before you are able to run the full game of Jedi Knight: Jedi Outcast in VR you will need to:
|
||||
|
||||
- Install JK XR thought SideQuest (this will also install the companion app)
|
||||
- Start JK XR for the first time, it will ask for appropriate permissions (which you must allow), create the necessary folders and then close down
|
||||
- You can now run the Companion App. This will check that it has the files for the full game.
|
||||
- (optional) Copy only the assets files (assets0.pk3, assets1.pk3, assets2.pk3, assets5.pk3) from your PC install of JKO (Jedi Outcast\GameData\base) into the following folder on your device:
|
||||
- Copy only the assets files (assets0.pk3, assets1.pk3, assets2.pk3, assets5.pk3) from your PC install of JKO (Jedi Outcast\GameData\base) into the following folder on your device:
|
||||
|
||||
\JKXR\JK2\base
|
||||
|
||||
or
|
||||
|
||||
\JKXR\JK3\base
|
||||
|
||||
|
||||
- You must then use the Companion App to download any mods and start the game. It is possible to play the JK Demo without having copied across the full game assets. All other mods require the full game.
|
||||
|
||||
|
||||
|
@ -108,6 +136,9 @@ This control scheme on how to play can also be found in the Controls -> JKXR HEL
|
|||
![Control Scheme](https://github.com/DrBeef/JKXR/blob/main/z_vr_assets_base/gfx/menus/control_scheme.jpg)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Building from Source
|
||||
|
||||
If you wish to build JK XR from source, then you need the following:
|
||||
|
@ -121,6 +152,9 @@ There is no dependency on any specific headset native libraries, as this port us
|
|||
|
||||
JKXR\Projects\Android\libs\arm64-v8a
|
||||
|
||||
|
||||
PCVR instructions will follow in the future (when I get round to adding them),
|
||||
|
||||
## Credits
|
||||
|
||||
* Team Beef are DrBeef, Baggyg, Bummser
|
||||
|
@ -128,7 +162,9 @@ JKXR\Projects\Android\libs\arm64-v8a
|
|||
* JKXR Companion App: BaggyG
|
||||
* Additional Development Contributions: MuadDib, BaggyG
|
||||
* VR Compatible Weapon Models: Vince Crusty and Elin
|
||||
* With Special Thanks to: Team Beef patrons, all Team Beef discord members,
|
||||
* VR Compatible Hand Models: LennyGuy20
|
||||
|
||||
With Special Thanks to: Team Beef patrons, all Team Beef discord members,
|
||||
the OpenJK Development Team and Raven Software for
|
||||
creating and open-sourcing these wonderful games
|
||||
|
||||
|
|
238
XrApp.gradle
|
@ -1,238 +0,0 @@
|
|||
import org.gradle.internal.os.OperatingSystem;
|
||||
import com.android.ddmlib.AndroidDebugBridge
|
||||
import com.android.ddmlib.IDevice
|
||||
import com.android.ddmlib.CollectingOutputReceiver
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.0'
|
||||
}
|
||||
|
||||
tasks.register("wrapper")
|
||||
}
|
||||
|
||||
class XrAppPlugin implements Plugin<Project> {
|
||||
Project project = null
|
||||
|
||||
void installApk( IDevice device, File apkFile, String applicationId ) {
|
||||
project.logger.quiet "Installing ${applicationId} on device ${device.serialNumber}"
|
||||
|
||||
String toinstall = "/data/local/tmp/toinstall.apk"
|
||||
|
||||
try {
|
||||
device.pushFile( apkFile.path, toinstall )
|
||||
} catch ( Exception e ) {
|
||||
throw new RuntimeException( "Failed to push ${apkFile.path} to ${toinstall}. ${e}", e )
|
||||
}
|
||||
|
||||
while ( true ) {
|
||||
try {
|
||||
device.installRemotePackage( toinstall, true )
|
||||
break
|
||||
} catch ( Exception e ) {
|
||||
project.logger.quiet "Failed to install ${applicationId} on device ${device.serialNumber} (${e}). Trying to uninstall first."
|
||||
}
|
||||
try {
|
||||
device.uninstallPackage( applicationId )
|
||||
} catch ( Exception e ) {
|
||||
throw new RuntimeException( "Failed to uninstall ${applicationId}. ${e}", e )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stopApk( IDevice device, String packageName ) {
|
||||
CollectingOutputReceiver receiver = new CollectingOutputReceiver()
|
||||
device.executeShellCommand( "am force-stop ${packageName}", receiver )
|
||||
}
|
||||
|
||||
void runApk( IDevice device, manifestFile ) {
|
||||
CollectingOutputReceiver receiver = new CollectingOutputReceiver()
|
||||
def activityClass = new XmlSlurper().parse( manifestFile ).application.activity.find{ it.'intent-filter'.find{ filter ->
|
||||
return filter.action .find{it.'@android:name'.text() == 'android.intent.action.MAIN' } \
|
||||
&& ( filter.category.find{it.'@android:name'.text() == 'android.intent.category.LAUNCHER'} \
|
||||
|| filter.category.find{it.'@android:name'.text() == 'android.intent.category.INFO'} )
|
||||
}}.'@android:name'
|
||||
def startActivity = "${project.android.defaultConfig.applicationId}/${activityClass}"
|
||||
project.logger.quiet "Starting \'$startActivity\' on ${project.deviceMap.size()} devices:"
|
||||
project.logger.quiet "- ${device.serialNumber}"
|
||||
device.executeShellCommand( "am start $startActivity", receiver )
|
||||
}
|
||||
|
||||
void apply( Project project ) {
|
||||
this.project = project
|
||||
|
||||
// FIXME: The Task.leftShift(Closure) method has been deprecated and is scheduled to be removed in Gradle 5.0. Please use Task.doLast(Action) instead.
|
||||
project.task( "cleanWorkAround" ) {
|
||||
description "Workaround for .externalNativeBuild not being deleted on clean"
|
||||
}.doLast {
|
||||
project.delete project.file( ".externalNativeBuild" )
|
||||
}
|
||||
|
||||
project.android {
|
||||
compileSdkVersion 26
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 25
|
||||
|
||||
externalNativeBuild {
|
||||
ndk {
|
||||
}
|
||||
ndkBuild {
|
||||
def numProcs = Runtime.runtime.availableProcessors()
|
||||
arguments "V=0", "-j$numProcs", "-C$project.buildDir.parent", "APP_PLATFORM=android-24", "NDK_TOOLCHAIN_VERSION=clang", "APP_STL=c++_static"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path 'jni/Android.mk'
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
def keystorePath = (project.hasProperty('key.store')) ?
|
||||
new File(project.getProperty('key.store')) :
|
||||
project.file('android.debug.keystore')
|
||||
|
||||
def keystorePassword = (project.hasProperty('key.store.password')) ?
|
||||
project.getProperty('key.store.password') : 'android'
|
||||
|
||||
def keystoreKeyAlias = (project.hasProperty('key.alias')) ?
|
||||
project.getProperty('key.alias') : 'androiddebugkey'
|
||||
|
||||
def keystoreKeyPassword = (project.hasProperty('key.alias.password')) ?
|
||||
project.getProperty('key.alias.password') : 'android'
|
||||
|
||||
debug {
|
||||
storeFile keystorePath
|
||||
storePassword keystorePassword
|
||||
keyAlias keystoreKeyAlias
|
||||
keyPassword keystoreKeyPassword
|
||||
v2SigningEnabled true
|
||||
}
|
||||
|
||||
release {
|
||||
storeFile keystorePath
|
||||
storePassword keystorePassword
|
||||
keyAlias keystoreKeyAlias
|
||||
keyPassword keystoreKeyPassword
|
||||
v2SigningEnabled true
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
debuggable true
|
||||
jniDebuggable true
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "NDK_DEBUG=1","USE_ASAN=1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
debuggable false
|
||||
jniDebuggable false
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "NDK_DEBUG=0","USE_ASAN=0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WORKAROUND: On Mac OS X, running ndk-build clean with a high num of parallel executions
|
||||
// set may result in the following build error: rm: fts_read: No such file or directory.
|
||||
// Currently, there isn't a good way to specify numProcs=1 only on clean. So, in order
|
||||
// to work around the issue, delete the auto-generated .externalNativeBuild artifacts
|
||||
// (where $numProcs specified) before executing the clean task.
|
||||
project.clean.dependsOn project.cleanWorkAround
|
||||
|
||||
project.clean {
|
||||
// remove the auto-generated debug keystore (currently generated by python build script)
|
||||
// delete "android.debug.keystore"
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
Task initDeviceList = project.task( "initDeviceList()" ).doLast {
|
||||
project.ext.deviceMap = [ : ]
|
||||
if (project.hasProperty( "should_install" ) == true) {
|
||||
AndroidDebugBridge.initIfNeeded( false )
|
||||
AndroidDebugBridge bridge = AndroidDebugBridge.createBridge( project.android.getAdbExe().absolutePath, false )
|
||||
|
||||
long timeOut = 30000 // 30 sec
|
||||
int sleepTime = 1000
|
||||
while ( !bridge.hasInitialDeviceList() && timeOut > 0 ) {
|
||||
sleep( sleepTime )
|
||||
timeOut -= sleepTime
|
||||
}
|
||||
if ( timeOut <= 0 && !bridge.hasInitialDeviceList() ) {
|
||||
throw new RuntimeException( "Timeout getting device list.", null )
|
||||
}
|
||||
|
||||
// if a device is connected both physically and over the network, only include the physical ID
|
||||
if ( project.hasProperty( "should_install" ) == true ) {
|
||||
bridge.devices.split { it.getProperty( "ro.serialno" ) != it.serialNumber }.each {
|
||||
it.collectEntries( project.deviceMap, { [ ( it.getProperty( "ro.serialno" )) : it ] } )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.task( "stopApk", dependsOn: initDeviceList ) {
|
||||
description "Stops app if currently running on device"
|
||||
}.doLast {
|
||||
project.deviceMap.each { deviceSerial, device ->
|
||||
stopApk( device, android.defaultConfig.applicationId )
|
||||
}
|
||||
}
|
||||
|
||||
project.android.applicationVariants.all { variant ->
|
||||
Task installAndRun = project.task( "installAndRun${variant.name.capitalize()}" ) {
|
||||
dependsOn variant.assembleProvider.get()
|
||||
dependsOn initDeviceList
|
||||
onlyIf { project.hasProperty( "should_install" ) }
|
||||
description "Installs and runs the APK file"
|
||||
}.doLast { variant.outputs.each { output ->
|
||||
if ( output.outputFile.exists() ) {
|
||||
if ( project.deviceMap.size() == 0 ) {
|
||||
project.logger.quiet "Install requested, but no devices found."
|
||||
} else {
|
||||
project.deviceMap.each { deviceSerial, device ->
|
||||
installApk( device, output.outputFile, project.android.defaultConfig.applicationId )
|
||||
runApk( device, new File(output.processManifest.manifestOutputDirectory.get().asFile, "AndroidManifest.xml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
variant.assembleProvider.get().finalizedBy installAndRun
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround to fix issue in Android Studio Chipmunk 2021.2.1 and later
|
||||
// where opening a project would result in a 'prepareKotlinBuildScriptModel'
|
||||
// not found error
|
||||
if (!tasks.findByName("prepareKotlinBuildScriptModel")) {
|
||||
tasks.register("prepareKotlinBuildScriptModel") {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
apply plugin: XrAppPlugin
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 167 KiB |
22
build.gradle
|
@ -1,22 +0,0 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.0'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
org.gradle.jvmargs=-Xmx1536M
|
||||
org.gradle.caching=true
|
||||
org.gradle.configureondemand=true
|
|
@ -1,9 +0,0 @@
|
|||
## This file must *NOT* be checked into Version Control Systems,
|
||||
# as it contains information specific to your local configuration.
|
||||
#
|
||||
# Location of the SDK. This is only used by Gradle.
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
#Thu Dec 12 20:21:11 GMT 2019
|
||||
ndk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\Sdk\\ndk\\21.1.6352462
|
||||
sdk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\Sdk
|
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 25 KiB |
5
res/mipmap-anydpi-v26/teambeef.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/teambeef_adaptive_back"/>
|
||||
<foreground android:drawable="@mipmap/teambeef_adaptive_fore"/>
|
||||
</adaptive-icon>
|
BIN
res/mipmap-hdpi/teambeef.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
res/mipmap-hdpi/teambeef_adaptive_back.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
res/mipmap-hdpi/teambeef_adaptive_fore.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
res/mipmap-mdpi/teambeef.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
res/mipmap-mdpi/teambeef_adaptive_back.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
res/mipmap-mdpi/teambeef_adaptive_fore.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
res/mipmap-xhdpi/teambeef.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
res/mipmap-xhdpi/teambeef_adaptive_back.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
res/mipmap-xhdpi/teambeef_adaptive_fore.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
res/mipmap-xxhdpi/teambeef.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
res/mipmap-xxhdpi/teambeef_adaptive_back.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
res/mipmap-xxhdpi/teambeef_adaptive_fore.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
res/mipmap-xxxhdpi/teambeef.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
res/mipmap-xxxhdpi/teambeef_adaptive_back.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
res/mipmap-xxxhdpi/teambeef_adaptive_fore.png
Normal file
After Width: | Height: | Size: 74 KiB |