mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-24 21:11:05 +00:00
Initial Oculus Quest support added.
This commit is contained in:
parent
c0b15329e3
commit
791e90b22a
64 changed files with 11622 additions and 72 deletions
17
.gitignore
vendored
17
.gitignore
vendored
|
@ -1,8 +1,9 @@
|
|||
build
|
||||
Makefile.local
|
||||
*.swp
|
||||
*tags
|
||||
*~
|
||||
*.ccls-cache/
|
||||
compile_commands.json
|
||||
|
||||
# OS X
|
||||
####################
|
||||
|
@ -39,3 +40,17 @@ profile
|
|||
*.sdf
|
||||
*.opensdf
|
||||
*.suo
|
||||
|
||||
# Android
|
||||
####################
|
||||
.gradle/
|
||||
.cxx/
|
||||
.settings/
|
||||
assets/
|
||||
jniLibs/
|
||||
Debug/
|
||||
Release/
|
||||
*.iml
|
||||
.classpath
|
||||
.project
|
||||
local.properties
|
||||
|
|
73
Makefile
73
Makefile
|
@ -111,6 +111,10 @@ ifndef CLIENTBIN
|
|||
CLIENTBIN=ioquake3
|
||||
endif
|
||||
|
||||
ifndef LIBPREFIX
|
||||
LIBPREFIX=
|
||||
endif
|
||||
|
||||
ifndef SERVERBIN
|
||||
SERVERBIN=ioq3ded
|
||||
endif
|
||||
|
@ -250,6 +254,7 @@ RGL1DIR=$(MOUNT_DIR)/renderergl1
|
|||
RGL2DIR=$(MOUNT_DIR)/renderergl2
|
||||
CMDIR=$(MOUNT_DIR)/qcommon
|
||||
SDLDIR=$(MOUNT_DIR)/sdl
|
||||
VRDIR=$(MOUNT_DIR)/vr
|
||||
ASMDIR=$(MOUNT_DIR)/asm
|
||||
SYSDIR=$(MOUNT_DIR)/sys
|
||||
GDIR=$(MOUNT_DIR)/game
|
||||
|
@ -276,6 +281,7 @@ LOKISETUPDIR=misc/setup
|
|||
NSISDIR=misc/nsis
|
||||
SDLHDIR=$(MOUNT_DIR)/SDL2
|
||||
LIBSDIR=$(MOUNT_DIR)/libs
|
||||
VRAPIDIR=$(MOUNT_DIR)/VrApi
|
||||
|
||||
bin_path=$(shell which $(1) 2> /dev/null)
|
||||
|
||||
|
@ -422,6 +428,51 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu")
|
|||
endif
|
||||
else # ifeq Linux
|
||||
|
||||
#############################################################################
|
||||
# SETUP AND BUILD -- Android
|
||||
#############################################################################
|
||||
|
||||
ifeq ($(PLATFORM),android)
|
||||
ANDROID_NDK = ~/Android/Sdk/ndk/21.1.6352462
|
||||
ARCH = aarch64
|
||||
CC = $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android26-clang
|
||||
RANLIB = $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ranlib
|
||||
TOOLS_CFLAGS += -DARCH_STRING=\"$(COMPILE_ARCH)\"
|
||||
BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes -pipe \
|
||||
-fno-builtin-cos -fno-builtin-sin -fPIC -DARCH_STRING=\\\"$(ARCH)\\\"
|
||||
CLIENT_CFLAGS += $(SDL_CFLAGS) -DSDL_DISABLE_IMMINTRIN_H -fno-builtin-cos -fno-builtin-sin
|
||||
|
||||
OPTIMIZEVM = -O3 -funroll-loops -fomit-frame-pointer
|
||||
OPTIMIZE = $(OPTIMIZEVM) -ffast-math
|
||||
|
||||
HAVE_VM_COMPILED = false
|
||||
|
||||
LIBPREFIX = lib
|
||||
CLIENTBIN = $(LIBPREFIX)ioquake3
|
||||
FULLBINEXT = .so
|
||||
SHLIBEXT = so
|
||||
SHLIBCFLAGS =
|
||||
SHLIBLDFLAGS = -shared -lm $(LDFLAGS)
|
||||
|
||||
THREAD_LIBS =
|
||||
LIBS = -ldl -lm -Wl,--no-undefined -shared
|
||||
|
||||
CLIENT_LIBS = -lGLESv3
|
||||
RENDERER_LIBS = -lGLESv3 -lEGL
|
||||
|
||||
# SDL
|
||||
BASE_CFLAGS += -I$(SDLHDIR)/include
|
||||
CLIENT_LIBS += $(LIBSDIR)/android/arm64-v8a/libSDL2.so
|
||||
RENDERER_LIBS += $(LIBSDIR)/android/arm64-v8a/libSDL2.so
|
||||
CLIENT_EXTRA_FILES += $(LIBSDIR)/android/arm64-v8a/libSDL2.so
|
||||
|
||||
# VrApi
|
||||
BASE_CFLAGS += -I$(VRAPIDIR)/Include
|
||||
CLIENT_LIBS += $(VRAPIDIR)/Libs/Android/arm64-v8a/Release/libvrapi.so
|
||||
RENDERER_LIBS += $(VRAPIDIR)/Libs/Android/arm64-v8a/Release/libvrapi.so
|
||||
CLIENT_EXTRA_FILES += $(VRAPIDIR)/Libs/Android/arm64-v8a/Release/libvrapi.so
|
||||
else # ifeq Android
|
||||
|
||||
#############################################################################
|
||||
# SETUP AND BUILD -- MAC OS X
|
||||
#############################################################################
|
||||
|
@ -954,6 +1005,7 @@ else # ifeq sunos
|
|||
SHLIBLDFLAGS=-shared
|
||||
|
||||
endif #Linux
|
||||
endif #Android
|
||||
endif #darwin
|
||||
endif #MINGW
|
||||
endif #FreeBSD
|
||||
|
@ -991,9 +1043,9 @@ endif
|
|||
|
||||
ifneq ($(BUILD_CLIENT),0)
|
||||
ifneq ($(USE_RENDERER_DLOPEN),0)
|
||||
TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) $(B)/renderer_opengl1_$(SHLIBNAME)
|
||||
TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) $(B)/$(LIBPREFIX)renderer_opengl1_$(SHLIBNAME)
|
||||
ifneq ($(BUILD_RENDERER_OPENGL2),0)
|
||||
TARGETS += $(B)/renderer_opengl2_$(SHLIBNAME)
|
||||
TARGETS += $(B)/$(LIBPREFIX)renderer_opengl2_$(SHLIBNAME)
|
||||
endif
|
||||
else
|
||||
TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT)
|
||||
|
@ -1223,7 +1275,7 @@ define DO_REF_STR
|
|||
$(echo_cmd) "REF_STR $<"
|
||||
$(Q)rm -f $@
|
||||
$(Q)echo "const char *fallbackShader_$(notdir $(basename $<)) =" >> $@
|
||||
$(Q)cat $< | sed -e 's/^\(.*\)$$/\"\1\"/' >> $@
|
||||
$(Q)cat $< | sed -e 's/^/\"/;s/$$/\\n\"/' | tr -d '\r' >> $@
|
||||
$(Q)echo ";" >> $@
|
||||
endef
|
||||
|
||||
|
@ -1759,6 +1811,10 @@ Q3OBJ = \
|
|||
$(B)/client/sdl_input.o \
|
||||
$(B)/client/sdl_snd.o \
|
||||
\
|
||||
$(B)/client/vr_base.o \
|
||||
$(B)/client/vr_input.o \
|
||||
$(B)/client/vr_renderer.o \
|
||||
\
|
||||
$(B)/client/con_log.o \
|
||||
$(B)/client/sys_autoupdater.o \
|
||||
$(B)/client/sys_main.o
|
||||
|
@ -2191,12 +2247,12 @@ $(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(LIBSDLMAIN)
|
|||
-o $@ $(Q3OBJ) \
|
||||
$(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
|
||||
|
||||
$(B)/renderer_opengl1_$(SHLIBNAME): $(Q3ROBJ) $(JPGOBJ)
|
||||
$(B)/$(LIBPREFIX)renderer_opengl1_$(SHLIBNAME): $(Q3ROBJ) $(JPGOBJ)
|
||||
$(echo_cmd) "LD $@"
|
||||
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3ROBJ) $(JPGOBJ) \
|
||||
$(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS)
|
||||
|
||||
$(B)/renderer_opengl2_$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ)
|
||||
$(B)/$(LIBPREFIX)renderer_opengl2_$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ)
|
||||
$(echo_cmd) "LD $@"
|
||||
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \
|
||||
$(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS)
|
||||
|
@ -2697,6 +2753,9 @@ $(B)/client/%.o: $(ZDIR)/%.c
|
|||
$(B)/client/%.o: $(SDLDIR)/%.c
|
||||
$(DO_CC)
|
||||
|
||||
$(B)/client/%.o: $(VRDIR)/%.c
|
||||
$(DO_CC)
|
||||
|
||||
$(B)/client/%.o: $(SYSDIR)/%.c
|
||||
$(DO_CC)
|
||||
|
||||
|
@ -2882,9 +2941,9 @@ endif
|
|||
ifneq ($(BUILD_CLIENT),0)
|
||||
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)$(FULLBINEXT)
|
||||
ifneq ($(USE_RENDERER_DLOPEN),0)
|
||||
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_opengl1_$(SHLIBNAME) $(COPYBINDIR)/renderer_opengl1_$(SHLIBNAME)
|
||||
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(LIBPREFIX)renderer_opengl1_$(SHLIBNAME) $(COPYBINDIR)/$(LIBPREFIX)renderer_opengl1_$(SHLIBNAME)
|
||||
ifneq ($(BUILD_RENDERER_OPENGL2),0)
|
||||
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_opengl2_$(SHLIBNAME) $(COPYBINDIR)/renderer_opengl2_$(SHLIBNAME)
|
||||
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(LIBPREFIX)renderer_opengl2_$(SHLIBNAME) $(COPYBINDIR)/$(LIBPREFIX)renderer_opengl2_$(SHLIBNAME)
|
||||
endif
|
||||
else
|
||||
ifneq ($(BUILD_RENDERER_OPENGL2),0)
|
||||
|
|
20
Makefile.local
Normal file
20
Makefile.local
Normal file
|
@ -0,0 +1,20 @@
|
|||
PLATFORM=android
|
||||
BUILD_CLIENT=1
|
||||
BUILD_CLIENT_SMP=0
|
||||
BUILD_GAME_QVM=0
|
||||
BUILD_GAME_SO=1
|
||||
BUILD_MISSIONPACK=0
|
||||
BUILD_SERVER=0
|
||||
BUILD_STANDALONE=1
|
||||
GENERATE_DEPENDENCIES=0
|
||||
USE_CODEC_VORBIS=0
|
||||
USE_CURL=0
|
||||
USE_CURL_DLOPEN=0
|
||||
USE_INTERNAL_SPEEX=0
|
||||
USE_LOCAL_HEADERS=0
|
||||
USE_MUMBLE=0
|
||||
USE_OPENAL=0
|
||||
USE_OPENAL_DLOPEN=0
|
||||
USE_RENDERER_DLOPEN=0
|
||||
USE_SVN=0
|
||||
USE_VOIP=0
|
44
android/app/build.gradle
Normal file
44
android/app/build.gradle
Normal file
|
@ -0,0 +1,44 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
defaultConfig {
|
||||
applicationId = 'com.spark.ioq3quest'
|
||||
minSdkVersion 25
|
||||
targetSdkVersion 26
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments '-DANDROID_STL=c++_static'
|
||||
}
|
||||
}
|
||||
ndk {
|
||||
abiFilters 'arm64-v8a'
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path 'src/main/cpp/CMakeLists.txt'
|
||||
version '3.10.2'
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs.srcDirs 'src/main/jniLibs'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
}
|
33
android/app/src/main/AndroidManifest.xml
Normal file
33
android/app/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.spark.ioq3quest"
|
||||
android:installLocation="preferExternal"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<uses-feature android:name="android.hardware.vr.headtracking" android:version="1" android:required="true" />
|
||||
<uses-permission android:name="oculus.permission.handtracking" />
|
||||
<uses-feature android:name="oculus.software.handtracking" android:required="false" />
|
||||
<uses-feature android:glEsVersion="0x00030001" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:hasCode="true">
|
||||
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
|
||||
<activity android:name="com.spark.ioq3quest.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:screenOrientation="landscape"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
|
||||
android:configChanges="density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode"
|
||||
android:launchMode="singleTask"
|
||||
android:resizeableActivity="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
41
android/app/src/main/cpp/CMakeLists.txt
Normal file
41
android/app/src/main/cpp/CMakeLists.txt
Normal file
|
@ -0,0 +1,41 @@
|
|||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
set(${CMAKE_C_FLAGS}, "${CMAKE_C_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall -Werror")
|
||||
link_directories(../jniLibs/arm64-v8a)
|
||||
|
||||
add_library(main SHARED main.cpp)
|
||||
|
||||
SET(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE)
|
||||
SET(BUILD_FOLDER release-android-aarch64)
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
SET(BUILD_FOLDER debug-android-aarch64)
|
||||
endif()
|
||||
add_custom_target(copy_libs
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/libioquake3_opengl2.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libioquake3_opengl2.so
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/libSDL2.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libSDL2.so
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/libvrapi.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libvrapi.so
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/baseq3/cgameaarch64.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libcgameaarch64.so
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/baseq3/qagameaarch64.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libqagameaarch64.so
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/baseq3/uiaarch64.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libuiaarch64.so
|
||||
)
|
||||
|
||||
add_dependencies(main copy_libs)
|
||||
|
||||
target_include_directories(main PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/../../../../../code/VrApi/Include
|
||||
${CMAKE_SOURCE_DIR}/../../../../../code/SDL2/include
|
||||
${CMAKE_SOURCE_DIR}/../../../../../code)
|
||||
|
||||
target_compile_definitions(main PRIVATE
|
||||
ARCH_STRING=android)
|
||||
|
||||
find_library(log-lib log)
|
||||
|
||||
target_link_libraries(main
|
||||
android
|
||||
ioquake3_opengl2
|
||||
SDL2
|
||||
vrapi
|
||||
${log-lib})
|
127
android/app/src/main/cpp/main.cpp
Normal file
127
android/app/src/main/cpp/main.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
#include <jni.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include <VrApi.h>
|
||||
#include <VrApi_Helpers.h>
|
||||
#include <string>
|
||||
|
||||
extern "C" {
|
||||
#include <qcommon/q_shared.h>
|
||||
#include <qcommon/qcommon.h>
|
||||
#include <vr/vr_base.h>
|
||||
#include <vr/vr_renderer.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
extern void CON_LogcatFn( void (*LogcatFn)( const char* message ) );
|
||||
}
|
||||
|
||||
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "Quake3", __VA_ARGS__))
|
||||
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "Quake3", __VA_ARGS__))
|
||||
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "Quake3", __VA_ARGS__))
|
||||
#define LOGF(...) ((void)__android_log_print(ANDROID_LOG_FATAL, "Quake3", __VA_ARGS__))
|
||||
|
||||
static JNIEnv* g_Env = NULL;
|
||||
static JavaVM* g_JavaVM = NULL;
|
||||
static jobject g_ActivityObject = NULL;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
JNIEXPORT void JNICALL Java_com_spark_ioq3quest_MainActivity_nativeCreate(JNIEnv* env, jclass cls, jobject thisObject)
|
||||
{
|
||||
g_ActivityObject = env->NewGlobalRef(thisObject);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
{
|
||||
g_JavaVM = vm;
|
||||
if (g_JavaVM->GetEnv((void**) &g_Env, JNI_VERSION_1_4) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
}
|
||||
|
||||
static void ioq3_logfn(const char* msg)
|
||||
{
|
||||
LOGI("%s", msg);
|
||||
}
|
||||
|
||||
static ovrJava engine_get_ovrJava() {
|
||||
ovrJava java;
|
||||
java.Vm = g_JavaVM;
|
||||
java.ActivityObject = g_ActivityObject;
|
||||
java.Vm->AttachCurrentThread(&java.Env, NULL);
|
||||
return java;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
CON_LogcatFn(&ioq3_logfn);
|
||||
|
||||
std::string defaultArgs("+set fs_basepath ");
|
||||
defaultArgs += SDL_AndroidGetExternalStoragePath();
|
||||
defaultArgs += " +set fs_game baseq3 +map q3dm6";
|
||||
|
||||
char* args = new char[defaultArgs.length() + 1];
|
||||
args[defaultArgs.length()] = '\0';
|
||||
memcpy(args, defaultArgs.c_str(), defaultArgs.length());
|
||||
Com_Init(args);
|
||||
|
||||
ovrJava java = engine_get_ovrJava();
|
||||
|
||||
constexpr auto vrEnabled = true;
|
||||
engine_t* engine = nullptr;
|
||||
|
||||
if (vrEnabled)
|
||||
{
|
||||
engine = VR_Init(java);
|
||||
VR_InitRenderer(engine);
|
||||
|
||||
VR_EnterVR(engine, java);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
LOGI("Received SDL Event: %d", event.type);
|
||||
if (vrEnabled)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
VR_EnterVR(engine, engine_get_ovrJava());
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
VR_LeaveVR(engine);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vrEnabled)
|
||||
{
|
||||
VR_DrawFrame(engine);
|
||||
}
|
||||
else
|
||||
{
|
||||
Com_Frame();
|
||||
}
|
||||
}
|
||||
if (vrEnabled)
|
||||
{
|
||||
VR_LeaveVR(engine);
|
||||
VR_DestroyRenderer(engine);
|
||||
}
|
||||
|
||||
Com_Shutdown();
|
||||
if (vrEnabled)
|
||||
{
|
||||
VR_Destroy(engine);
|
||||
}
|
||||
delete [] args;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.spark.ioq3quest;
|
||||
|
||||
import android.os.Bundle;
|
||||
import org.libsdl.app.SDLActivity;
|
||||
|
||||
public class MainActivity extends SDLActivity
|
||||
{
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
nativeCreate(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
public static native void nativeCreate(MainActivity thisObject);
|
||||
|
||||
static {
|
||||
System.loadLibrary("main");
|
||||
}
|
||||
}
|
37
android/app/src/main/java/org/libsdl/app/SDL.java
Normal file
37
android/app/src/main/java/org/libsdl/app/SDL.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
package org.libsdl.app;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
SDL library initialization
|
||||
*/
|
||||
public class SDL {
|
||||
|
||||
// This function should be called first and sets up the native code
|
||||
// so it can call into the Java classes
|
||||
public static void setupJNI() {
|
||||
SDLActivity.nativeSetupJNI();
|
||||
SDLAudioManager.nativeSetupJNI();
|
||||
SDLControllerManager.nativeSetupJNI();
|
||||
}
|
||||
|
||||
// This function should be called each time the activity is started
|
||||
public static void initialize() {
|
||||
setContext(null);
|
||||
|
||||
SDLActivity.initialize();
|
||||
SDLAudioManager.initialize();
|
||||
SDLControllerManager.initialize();
|
||||
}
|
||||
|
||||
// This function stores the current activity (SDL or not)
|
||||
public static void setContext(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public static Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
protected static Context mContext;
|
||||
}
|
1688
android/app/src/main/java/org/libsdl/app/SDLActivity.java
Normal file
1688
android/app/src/main/java/org/libsdl/app/SDLActivity.java
Normal file
File diff suppressed because it is too large
Load diff
178
android/app/src/main/java/org/libsdl/app/SDLAudioManager.java
Normal file
178
android/app/src/main/java/org/libsdl/app/SDLAudioManager.java
Normal file
|
@ -0,0 +1,178 @@
|
|||
package org.libsdl.app;
|
||||
|
||||
import android.media.*;
|
||||
import android.util.Log;
|
||||
|
||||
public class SDLAudioManager
|
||||
{
|
||||
protected static final String TAG = "SDLAudio";
|
||||
|
||||
protected static AudioTrack mAudioTrack;
|
||||
protected static AudioRecord mAudioRecord;
|
||||
|
||||
public static void initialize() {
|
||||
mAudioTrack = null;
|
||||
mAudioRecord = null;
|
||||
}
|
||||
|
||||
// Audio
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
|
||||
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
|
||||
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
|
||||
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
|
||||
|
||||
Log.v(TAG, "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
||||
|
||||
// Let the user pick a larger buffer if they really want -- but ye
|
||||
// gods they probably shouldn't, the minimums are horrifyingly high
|
||||
// latency already
|
||||
desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
|
||||
|
||||
if (mAudioTrack == null) {
|
||||
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
|
||||
channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
|
||||
|
||||
// Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
|
||||
// Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
|
||||
// Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
|
||||
|
||||
if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
|
||||
Log.e(TAG, "Failed during initialization of Audio Track");
|
||||
mAudioTrack = null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mAudioTrack.play();
|
||||
}
|
||||
|
||||
Log.v(TAG, "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static void audioWriteShortBuffer(short[] buffer) {
|
||||
if (mAudioTrack == null) {
|
||||
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < buffer.length; ) {
|
||||
int result = mAudioTrack.write(buffer, i, buffer.length - i);
|
||||
if (result > 0) {
|
||||
i += result;
|
||||
} else if (result == 0) {
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch(InterruptedException e) {
|
||||
// Nom nom
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "SDL audio: error return from write(short)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static void audioWriteByteBuffer(byte[] buffer) {
|
||||
if (mAudioTrack == null) {
|
||||
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < buffer.length; ) {
|
||||
int result = mAudioTrack.write(buffer, i, buffer.length - i);
|
||||
if (result > 0) {
|
||||
i += result;
|
||||
} else if (result == 0) {
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch(InterruptedException e) {
|
||||
// Nom nom
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "SDL audio: error return from write(byte)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
|
||||
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
|
||||
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
|
||||
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
|
||||
|
||||
Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
||||
|
||||
// Let the user pick a larger buffer if they really want -- but ye
|
||||
// gods they probably shouldn't, the minimums are horrifyingly high
|
||||
// latency already
|
||||
desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
|
||||
|
||||
if (mAudioRecord == null) {
|
||||
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
|
||||
channelConfig, audioFormat, desiredFrames * frameSize);
|
||||
|
||||
// see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
|
||||
if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
|
||||
Log.e(TAG, "Failed during initialization of AudioRecord");
|
||||
mAudioRecord.release();
|
||||
mAudioRecord = null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mAudioRecord.startRecording();
|
||||
}
|
||||
|
||||
Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** This method is called by SDL using JNI. */
|
||||
public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
|
||||
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
|
||||
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
||||
return mAudioRecord.read(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
/** This method is called by SDL using JNI. */
|
||||
public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
|
||||
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
|
||||
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
|
||||
return mAudioRecord.read(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
|
||||
/** This method is called by SDL using JNI. */
|
||||
public static void audioClose() {
|
||||
if (mAudioTrack != null) {
|
||||
mAudioTrack.stop();
|
||||
mAudioTrack.release();
|
||||
mAudioTrack = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** This method is called by SDL using JNI. */
|
||||
public static void captureClose() {
|
||||
if (mAudioRecord != null) {
|
||||
mAudioRecord.stop();
|
||||
mAudioRecord.release();
|
||||
mAudioRecord = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static native int nativeSetupJNI();
|
||||
}
|
|
@ -0,0 +1,435 @@
|
|||
package org.libsdl.app;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.*;
|
||||
import android.view.*;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
public class SDLControllerManager
|
||||
{
|
||||
|
||||
public static native int nativeSetupJNI();
|
||||
|
||||
public static native int nativeAddJoystick(int device_id, String name, String desc,
|
||||
int is_accelerometer, int nbuttons,
|
||||
int naxes, int nhats, int nballs);
|
||||
public static native int nativeRemoveJoystick(int device_id);
|
||||
public static native int nativeAddHaptic(int device_id, String name);
|
||||
public static native int nativeRemoveHaptic(int device_id);
|
||||
public static native int onNativePadDown(int device_id, int keycode);
|
||||
public static native int onNativePadUp(int device_id, int keycode);
|
||||
public static native void onNativeJoy(int device_id, int axis,
|
||||
float value);
|
||||
public static native void onNativeHat(int device_id, int hat_id,
|
||||
int x, int y);
|
||||
|
||||
protected static SDLJoystickHandler mJoystickHandler;
|
||||
protected static SDLHapticHandler mHapticHandler;
|
||||
|
||||
private static final String TAG = "SDLControllerManager";
|
||||
|
||||
public static void initialize() {
|
||||
mJoystickHandler = null;
|
||||
mHapticHandler = null;
|
||||
|
||||
SDLControllerManager.setup();
|
||||
}
|
||||
|
||||
public static void setup() {
|
||||
if (Build.VERSION.SDK_INT >= 16) {
|
||||
mJoystickHandler = new SDLJoystickHandler_API16();
|
||||
} else if (Build.VERSION.SDK_INT >= 12) {
|
||||
mJoystickHandler = new SDLJoystickHandler_API12();
|
||||
} else {
|
||||
mJoystickHandler = new SDLJoystickHandler();
|
||||
}
|
||||
mHapticHandler = new SDLHapticHandler();
|
||||
}
|
||||
|
||||
// Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
|
||||
public static boolean handleJoystickMotionEvent(MotionEvent event) {
|
||||
return mJoystickHandler.handleMotionEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static void pollInputDevices() {
|
||||
mJoystickHandler.pollInputDevices();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static void pollHapticDevices() {
|
||||
mHapticHandler.pollHapticDevices();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
public static void hapticRun(int device_id, int length) {
|
||||
mHapticHandler.run(device_id, length);
|
||||
}
|
||||
|
||||
// Check if a given device is considered a possible SDL joystick
|
||||
public static boolean isDeviceSDLJoystick(int deviceId) {
|
||||
InputDevice device = InputDevice.getDevice(deviceId);
|
||||
// We cannot use InputDevice.isVirtual before API 16, so let's accept
|
||||
// only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
|
||||
if ((device == null) || (deviceId < 0)) {
|
||||
return false;
|
||||
}
|
||||
int sources = device.getSources();
|
||||
|
||||
/* This is called for every button press, so let's not spam the logs */
|
||||
/**
|
||||
if ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) {
|
||||
Log.v(TAG, "Input device " + device.getName() + " is a joystick.");
|
||||
}
|
||||
if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) {
|
||||
Log.v(TAG, "Input device " + device.getName() + " is a dpad.");
|
||||
}
|
||||
if ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
|
||||
Log.v(TAG, "Input device " + device.getName() + " is a gamepad.");
|
||||
}
|
||||
**/
|
||||
|
||||
return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
|
||||
((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
|
||||
((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
|
||||
class SDLJoystickHandler {
|
||||
|
||||
/**
|
||||
* Handles given MotionEvent.
|
||||
* @param event the event to be handled.
|
||||
* @return if given event was processed.
|
||||
*/
|
||||
public boolean handleMotionEvent(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles adding and removing of input devices.
|
||||
*/
|
||||
public void pollInputDevices() {
|
||||
}
|
||||
}
|
||||
|
||||
/* Actual joystick functionality available for API >= 12 devices */
|
||||
class SDLJoystickHandler_API12 extends SDLJoystickHandler {
|
||||
|
||||
static class SDLJoystick {
|
||||
public int device_id;
|
||||
public String name;
|
||||
public String desc;
|
||||
public ArrayList<InputDevice.MotionRange> axes;
|
||||
public ArrayList<InputDevice.MotionRange> hats;
|
||||
}
|
||||
static class RangeComparator implements Comparator<InputDevice.MotionRange> {
|
||||
@Override
|
||||
public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
|
||||
return arg0.getAxis() - arg1.getAxis();
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<SDLJoystick> mJoysticks;
|
||||
|
||||
public SDLJoystickHandler_API12() {
|
||||
|
||||
mJoysticks = new ArrayList<SDLJoystick>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pollInputDevices() {
|
||||
int[] deviceIds = InputDevice.getDeviceIds();
|
||||
// It helps processing the device ids in reverse order
|
||||
// For example, in the case of the XBox 360 wireless dongle,
|
||||
// so the first controller seen by SDL matches what the receiver
|
||||
// considers to be the first controller
|
||||
|
||||
for(int i=deviceIds.length-1; i>-1; i--) {
|
||||
SDLJoystick joystick = getJoystick(deviceIds[i]);
|
||||
if (joystick == null) {
|
||||
joystick = new SDLJoystick();
|
||||
InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
|
||||
if (SDLControllerManager.isDeviceSDLJoystick(deviceIds[i])) {
|
||||
joystick.device_id = deviceIds[i];
|
||||
joystick.name = joystickDevice.getName();
|
||||
joystick.desc = getJoystickDescriptor(joystickDevice);
|
||||
joystick.axes = new ArrayList<InputDevice.MotionRange>();
|
||||
joystick.hats = new ArrayList<InputDevice.MotionRange>();
|
||||
|
||||
List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
|
||||
Collections.sort(ranges, new RangeComparator());
|
||||
for (InputDevice.MotionRange range : ranges ) {
|
||||
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
|
||||
if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
|
||||
range.getAxis() == MotionEvent.AXIS_HAT_Y) {
|
||||
joystick.hats.add(range);
|
||||
}
|
||||
else {
|
||||
joystick.axes.add(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mJoysticks.add(joystick);
|
||||
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, 0, -1,
|
||||
joystick.axes.size(), joystick.hats.size()/2, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check removed devices */
|
||||
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
|
||||
for(int i=0; i < mJoysticks.size(); i++) {
|
||||
int device_id = mJoysticks.get(i).device_id;
|
||||
int j;
|
||||
for (j=0; j < deviceIds.length; j++) {
|
||||
if (device_id == deviceIds[j]) break;
|
||||
}
|
||||
if (j == deviceIds.length) {
|
||||
removedDevices.add(Integer.valueOf(device_id));
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i < removedDevices.size(); i++) {
|
||||
int device_id = removedDevices.get(i).intValue();
|
||||
SDLControllerManager.nativeRemoveJoystick(device_id);
|
||||
for (int j=0; j < mJoysticks.size(); j++) {
|
||||
if (mJoysticks.get(j).device_id == device_id) {
|
||||
mJoysticks.remove(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected SDLJoystick getJoystick(int device_id) {
|
||||
for(int i=0; i < mJoysticks.size(); i++) {
|
||||
if (mJoysticks.get(i).device_id == device_id) {
|
||||
return mJoysticks.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMotionEvent(MotionEvent event) {
|
||||
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
|
||||
int actionPointerIndex = event.getActionIndex();
|
||||
int action = event.getActionMasked();
|
||||
switch(action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
SDLJoystick joystick = getJoystick(event.getDeviceId());
|
||||
if ( joystick != null ) {
|
||||
for (int i = 0; i < joystick.axes.size(); i++) {
|
||||
InputDevice.MotionRange range = joystick.axes.get(i);
|
||||
/* Normalize the value to -1...1 */
|
||||
float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
|
||||
SDLControllerManager.onNativeJoy(joystick.device_id, i, value );
|
||||
}
|
||||
for (int i = 0; i < joystick.hats.size(); i+=2) {
|
||||
int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
|
||||
int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
|
||||
SDLControllerManager.onNativeHat(joystick.device_id, i/2, hatX, hatY );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getJoystickDescriptor(InputDevice joystickDevice) {
|
||||
return joystickDevice.getName();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SDLJoystickHandler_API16 extends SDLJoystickHandler_API12 {
|
||||
|
||||
@Override
|
||||
public String getJoystickDescriptor(InputDevice joystickDevice) {
|
||||
String desc = joystickDevice.getDescriptor();
|
||||
|
||||
if (desc != null && !desc.isEmpty()) {
|
||||
return desc;
|
||||
}
|
||||
|
||||
return super.getJoystickDescriptor(joystickDevice);
|
||||
}
|
||||
}
|
||||
|
||||
class SDLHapticHandler {
|
||||
|
||||
class SDLHaptic {
|
||||
public int device_id;
|
||||
public String name;
|
||||
public Vibrator vib;
|
||||
}
|
||||
|
||||
private ArrayList<SDLHaptic> mHaptics;
|
||||
|
||||
public SDLHapticHandler() {
|
||||
mHaptics = new ArrayList<SDLHaptic>();
|
||||
}
|
||||
|
||||
public void run(int device_id, int length) {
|
||||
SDLHaptic haptic = getHaptic(device_id);
|
||||
if (haptic != null) {
|
||||
haptic.vib.vibrate (length);
|
||||
}
|
||||
}
|
||||
|
||||
public void pollHapticDevices() {
|
||||
|
||||
final int deviceId_VIBRATOR_SERVICE = 999999;
|
||||
boolean hasVibratorService = false;
|
||||
|
||||
int[] deviceIds = InputDevice.getDeviceIds();
|
||||
// It helps processing the device ids in reverse order
|
||||
// For example, in the case of the XBox 360 wireless dongle,
|
||||
// so the first controller seen by SDL matches what the receiver
|
||||
// considers to be the first controller
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 16)
|
||||
{
|
||||
for (int i = deviceIds.length - 1; i > -1; i--) {
|
||||
SDLHaptic haptic = getHaptic(deviceIds[i]);
|
||||
if (haptic == null) {
|
||||
InputDevice device = InputDevice.getDevice(deviceIds[i]);
|
||||
Vibrator vib = device.getVibrator();
|
||||
if (vib.hasVibrator()) {
|
||||
haptic = new SDLHaptic();
|
||||
haptic.device_id = deviceIds[i];
|
||||
haptic.name = device.getName();
|
||||
haptic.vib = vib;
|
||||
mHaptics.add(haptic);
|
||||
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check VIBRATOR_SERVICE */
|
||||
Vibrator vib = (Vibrator) SDL.getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (vib != null) {
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
hasVibratorService = vib.hasVibrator();
|
||||
} else {
|
||||
hasVibratorService = true;
|
||||
}
|
||||
|
||||
if (hasVibratorService) {
|
||||
SDLHaptic haptic = getHaptic(deviceId_VIBRATOR_SERVICE);
|
||||
if (haptic == null) {
|
||||
haptic = new SDLHaptic();
|
||||
haptic.device_id = deviceId_VIBRATOR_SERVICE;
|
||||
haptic.name = "VIBRATOR_SERVICE";
|
||||
haptic.vib = vib;
|
||||
mHaptics.add(haptic);
|
||||
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check removed devices */
|
||||
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
|
||||
for(int i=0; i < mHaptics.size(); i++) {
|
||||
int device_id = mHaptics.get(i).device_id;
|
||||
int j;
|
||||
for (j=0; j < deviceIds.length; j++) {
|
||||
if (device_id == deviceIds[j]) break;
|
||||
}
|
||||
|
||||
if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) {
|
||||
// don't remove the vibrator if it is still present
|
||||
} else if (j == deviceIds.length) {
|
||||
removedDevices.add(device_id);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i < removedDevices.size(); i++) {
|
||||
int device_id = removedDevices.get(i);
|
||||
SDLControllerManager.nativeRemoveHaptic(device_id);
|
||||
for (int j=0; j < mHaptics.size(); j++) {
|
||||
if (mHaptics.get(j).device_id == device_id) {
|
||||
mHaptics.remove(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected SDLHaptic getHaptic(int device_id) {
|
||||
for(int i=0; i < mHaptics.size(); i++) {
|
||||
if (mHaptics.get(i).device_id == device_id) {
|
||||
return mHaptics.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
|
||||
// Generic Motion (mouse hover, joystick...) events go here
|
||||
@Override
|
||||
public boolean onGenericMotion(View v, MotionEvent event) {
|
||||
float x, y;
|
||||
int action;
|
||||
|
||||
switch ( event.getSource() ) {
|
||||
case InputDevice.SOURCE_JOYSTICK:
|
||||
case InputDevice.SOURCE_GAMEPAD:
|
||||
case InputDevice.SOURCE_DPAD:
|
||||
return SDLControllerManager.handleJoystickMotionEvent(event);
|
||||
|
||||
case InputDevice.SOURCE_MOUSE:
|
||||
if (!SDLActivity.mSeparateMouseAndTouch) {
|
||||
break;
|
||||
}
|
||||
action = event.getActionMasked();
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_SCROLL:
|
||||
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
|
||||
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
|
||||
SDLActivity.onNativeMouse(0, action, x, y);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
x = event.getX(0);
|
||||
y = event.getY(0);
|
||||
|
||||
SDLActivity.onNativeMouse(0, action, x, y);
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Event was not managed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.5 KiB |
4
android/app/src/main/res/values/strings.xml
Normal file
4
android/app/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">NativeActivity</string>
|
||||
</resources>
|
14
android/autoexec.cfg
Normal file
14
android/autoexec.cfg
Normal file
|
@ -0,0 +1,14 @@
|
|||
bind LEFTARROW +moveleft
|
||||
bind RIGHTARROW +moveright
|
||||
sensitivity 100
|
||||
set in_joystick 1
|
||||
set r_externalGLSL 1
|
||||
set r_stereoEnabled 1
|
||||
set r_mode -2
|
||||
set cg_runpitch 0
|
||||
set cg_runroll 0
|
||||
set cg_bobup 0
|
||||
set cg_bobpitch 0
|
||||
set cg_bobroll 0
|
||||
set cg_weaponbob 0
|
||||
set sv_pure 0
|
21
android/build.gradle
Normal file
21
android/build.gradle
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
20
android/gradle.properties
Normal file
20
android/gradle.properties
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
#Fri May 22 15:31:25 CEST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
164
android/gradlew
vendored
Executable file
164
android/gradlew
vendored
Executable file
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
90
android/gradlew.bat
vendored
Normal file
90
android/gradlew.bat
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
3
android/make.sh
Executable file
3
android/make.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
./gradlew :app:assembleDebug
|
58
android/run.sh
Executable file
58
android/run.sh
Executable file
|
@ -0,0 +1,58 @@
|
|||
#!/bin/sh
|
||||
|
||||
cd ..
|
||||
|
||||
TARGET=debug
|
||||
|
||||
make -j24 $TARGET
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to build ioq3"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd android
|
||||
|
||||
./make.sh
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to build android project"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PACKAGE_NAME=com.spark.ioq3quest
|
||||
ANDROID_STORAGE_LOCATION=/sdcard/Android/data/$PACKAGE_NAME/files/
|
||||
APK_LOCATION=./app/build/outputs/apk/debug/app-debug.apk
|
||||
|
||||
adb install -r $APK_LOCATION
|
||||
if [ $? -ne 0 ]; then
|
||||
adb uninstall $PACKAGE_NAME
|
||||
adb install $APK_LOCATION
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to install apk."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
adb shell mkdir -p $ANDROID_STORAGE_LOCATION
|
||||
adb push --sync ~/.local/share/Steam/steamapps/common/Quake\ 3\ Arena/baseq3 $ANDROID_STORAGE_LOCATION
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to transfer files."
|
||||
exit 1
|
||||
fi
|
||||
adb push --sync ../code/renderergl2/glsl $ANDROID_STORAGE_LOCATION/baseq3/
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to transfer shaders."
|
||||
exit 1
|
||||
fi
|
||||
adb push --sync autoexec.cfg $ANDROID_STORAGE_LOCATION/baseq3/
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to transfer autoexec."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
adb logcat -c
|
||||
adb shell am start -n $PACKAGE_NAME/.MainActivity
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to start application."
|
||||
exit 1
|
||||
fi
|
||||
adb logcat *:S Quake3:V SDL:V DEBUG:V
|
2
android/settings.gradle
Normal file
2
android/settings.gradle
Normal file
|
@ -0,0 +1,2 @@
|
|||
include ':app'
|
||||
|
|
@ -1089,6 +1089,7 @@ extern vmCvar_t cg_runroll;
|
|||
extern vmCvar_t cg_bobup;
|
||||
extern vmCvar_t cg_bobpitch;
|
||||
extern vmCvar_t cg_bobroll;
|
||||
extern vmCvar_t cg_weaponbob;
|
||||
extern vmCvar_t cg_swingSpeed;
|
||||
extern vmCvar_t cg_shadows;
|
||||
extern vmCvar_t cg_gibs;
|
||||
|
|
|
@ -96,6 +96,7 @@ vmCvar_t cg_runroll;
|
|||
vmCvar_t cg_bobup;
|
||||
vmCvar_t cg_bobpitch;
|
||||
vmCvar_t cg_bobroll;
|
||||
vmCvar_t cg_weaponbob;
|
||||
vmCvar_t cg_swingSpeed;
|
||||
vmCvar_t cg_shadows;
|
||||
vmCvar_t cg_gibs;
|
||||
|
@ -246,6 +247,7 @@ static cvarTable_t cvarTable[] = {
|
|||
{ &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
|
||||
{ &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
|
||||
{ &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
|
||||
{ &cg_weaponbob, "cg_weaponbob", "1", CVAR_ARCHIVE },
|
||||
{ &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
|
||||
{ &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
|
||||
{ &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT },
|
||||
|
|
|
@ -921,9 +921,12 @@ static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
|
|||
}
|
||||
|
||||
// gun angles from bobbing
|
||||
angles[ROLL] += scale * cg.bobfracsin * 0.005;
|
||||
angles[YAW] += scale * cg.bobfracsin * 0.01;
|
||||
angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
|
||||
if (cg_weaponbob.value != 0)
|
||||
{
|
||||
angles[ROLL] += scale * cg.bobfracsin * 0.005;
|
||||
angles[YAW] += scale * cg.bobfracsin * 0.01;
|
||||
angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
|
||||
}
|
||||
|
||||
// drop the weapon when landing
|
||||
delta = cg.time - cg.landTime;
|
||||
|
|
BIN
code/libs/android/arm64-v8a/libSDL2.so
Executable file
BIN
code/libs/android/arm64-v8a/libSDL2.so
Executable file
Binary file not shown.
BIN
code/libs/android/armeabi-v7a/libSDL2.so
Executable file
BIN
code/libs/android/armeabi-v7a/libSDL2.so
Executable file
Binary file not shown.
|
@ -1473,6 +1473,10 @@ int FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, i
|
|||
|
||||
if(enableDll)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
Com_sprintf(found, foundlen, "lib%s", dllName);
|
||||
return VMI_NATIVE;
|
||||
#else
|
||||
netpath = FS_BuildOSPath(dir->path, dir->gamedir, dllName);
|
||||
|
||||
if(FS_FileInPathExists(netpath))
|
||||
|
@ -1482,6 +1486,7 @@ int FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, i
|
|||
|
||||
return VMI_NATIVE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if(FS_FOpenFileReadDir(qvmName, search, NULL, qfalse, qfalse) > 0)
|
||||
|
|
|
@ -575,6 +575,10 @@ it will attempt to load as a system dll
|
|||
*/
|
||||
vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
|
||||
vmInterpret_t interpret ) {
|
||||
#if __ANDROID__
|
||||
interpret = VMI_NATIVE;
|
||||
#endif
|
||||
|
||||
vm_t *vm;
|
||||
vmHeader_t *header;
|
||||
int i, remaining, retval;
|
||||
|
|
|
@ -28,8 +28,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
#ifdef USE_LOCAL_HEADERS
|
||||
# include "SDL_opengl.h"
|
||||
# include "SDL_opengles2.h"
|
||||
#else
|
||||
# include <SDL_opengl.h>
|
||||
# include <SDL_opengles2.h>
|
||||
#endif
|
||||
|
||||
extern void (APIENTRYP qglActiveTextureARB) (GLenum texture);
|
||||
|
@ -80,7 +82,6 @@ extern void (APIENTRYP qglUnlockArraysEXT) (void);
|
|||
GLE(void, TexParameterf, GLenum target, GLenum pname, GLfloat param) \
|
||||
GLE(void, TexParameteri, GLenum target, GLenum pname, GLint param) \
|
||||
GLE(void, TexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) \
|
||||
GLE(void, Translatef, GLfloat x, GLfloat y, GLfloat z) \
|
||||
GLE(void, Viewport, GLint x, GLint y, GLsizei width, GLsizei height) \
|
||||
|
||||
// OpenGL 1.0/1.1 and OpenGL ES 1.x but not OpenGL 3.2 core profile
|
||||
|
@ -167,6 +168,7 @@ extern void (APIENTRYP qglUnlockArraysEXT) (void);
|
|||
GLE(void, DeleteProgram, GLuint program) \
|
||||
GLE(void, DeleteShader, GLuint shader) \
|
||||
GLE(void, DetachShader, GLuint program, GLuint shader) \
|
||||
GLE(void, DrawBuffersEXT, GLsizei n, const GLenum *bufs) \
|
||||
GLE(void, DisableVertexAttribArray, GLuint index) \
|
||||
GLE(void, EnableVertexAttribArray, GLuint index) \
|
||||
GLE(void, GetActiveUniform, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) \
|
||||
|
|
7656
code/renderercommon/stb_image.h
Normal file
7656
code/renderercommon/stb_image.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -24,6 +24,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
#include "tr_common.h"
|
||||
|
||||
static void* stb_malloc_impl(size_t size) { return ri.Malloc(size); }
|
||||
static void* stb_realloc_impl(void* p, size_t newsize) { free(p); return ri.Malloc(newsize); }
|
||||
static void stb_free_impl(void* p) { ri.Free(p); }
|
||||
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_NO_STDIO
|
||||
#define STBI_MALLOC(sz) stb_malloc_impl(sz)
|
||||
#define STBI_REALLOC(p,newsz) stb_realloc_impl(p, newsz)
|
||||
#define STBI_FREE(p) stb_free_impl(p)
|
||||
#include "stb_image.h"
|
||||
|
||||
/*
|
||||
* Include file for users of JPEG library.
|
||||
* You will need to have included system headers that define at least
|
||||
|
@ -80,6 +92,46 @@ static void R_JPGOutputMessage(j_common_ptr cinfo)
|
|||
|
||||
void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *height)
|
||||
{
|
||||
int len;
|
||||
int channels;
|
||||
union {
|
||||
byte *b;
|
||||
void *v;
|
||||
} fbuffer;
|
||||
|
||||
len = ri.FS_ReadFile ( ( char * ) filename, &fbuffer.v);
|
||||
if (!fbuffer.b || len < 0) {
|
||||
return;
|
||||
}
|
||||
channels = 3;
|
||||
|
||||
unsigned char* loaded_data = stbi_load_from_memory(fbuffer.b, len, width, height, &channels, 0);
|
||||
|
||||
ri.FS_FreeFile (fbuffer.v);
|
||||
|
||||
if (loaded_data)
|
||||
{
|
||||
const size_t img_size = *width * *height;
|
||||
*pic = ri.Malloc(img_size * 4);
|
||||
size_t src_index = 0;
|
||||
size_t tgt_index = 0;
|
||||
for (size_t i = 0; i < img_size; ++i)
|
||||
{
|
||||
(*pic)[tgt_index++] = loaded_data[src_index++];
|
||||
(*pic)[tgt_index++] = loaded_data[src_index++];
|
||||
(*pic)[tgt_index++] = loaded_data[src_index++];
|
||||
(*pic)[tgt_index++] = 255;
|
||||
}
|
||||
|
||||
ri.Free(loaded_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pic = NULL;
|
||||
}
|
||||
|
||||
// NOTE (SB): Need to figure out what is wrong with the JPEG implementation on Android.
|
||||
#if 0
|
||||
/* This struct contains the JPEG decompression parameters and pointers to
|
||||
* working space (which is allocated as needed by the JPEG library).
|
||||
*/
|
||||
|
@ -264,6 +316,7 @@ void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *heigh
|
|||
*/
|
||||
|
||||
/* And we're done! */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
#include "tr_types.h"
|
||||
|
||||
#if __ANDROID__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wstrict-prototypes"
|
||||
#include <VrApi.h>
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#define REF_API_VERSION 8
|
||||
|
||||
//
|
||||
|
@ -82,6 +89,9 @@ typedef struct {
|
|||
// if the pointers are not NULL, timing info will be returned
|
||||
void (*EndFrame)( int *frontEndMsec, int *backEndMsec );
|
||||
|
||||
#if __ANDROID__
|
||||
void (*SetVRHeadsetParms)( const ovrTracking2* ovrTracking, int renderBufferL, int renderBufferR );
|
||||
#endif
|
||||
|
||||
int (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,
|
||||
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
|
||||
|
|
|
@ -707,7 +707,9 @@ void RB_DrawSun( float scale, shader_t *shader ) {
|
|||
}
|
||||
|
||||
qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
|
||||
#ifndef __ANDROID__
|
||||
qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
|
||||
#endif
|
||||
|
||||
dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
|
||||
size = dist * scale;
|
||||
|
@ -770,7 +772,9 @@ void RB_StageIteratorSky( void ) {
|
|||
qglPushMatrix ();
|
||||
GL_State( 0 );
|
||||
GL_Cull( CT_FRONT_SIDED );
|
||||
#ifndef __ANDROID__
|
||||
qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
|
||||
#endif
|
||||
|
||||
DrawSkyBox( tess.shader );
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
precision mediump sampler2D;
|
||||
|
||||
uniform sampler2D u_DiffuseMap;
|
||||
|
||||
#if defined(USE_LIGHTMAP)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
precision mediump sampler2D;
|
||||
uniform sampler2D u_ShadowMap;
|
||||
|
||||
uniform vec3 u_LightForward;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
precision mediump sampler2D;
|
||||
precision mediump sampler2DShadow;
|
||||
|
||||
uniform sampler2D u_ScreenDepthMap;
|
||||
|
||||
uniform sampler2DShadow u_ShadowMap;
|
||||
|
|
|
@ -274,9 +274,21 @@ void GL_SetProjectionMatrix(mat4_t matrix)
|
|||
}
|
||||
|
||||
|
||||
void GL_SetModelviewMatrix(mat4_t matrix)
|
||||
void GL_SetModelviewMatrix(mat4_t matrix, qboolean applyStereoView)
|
||||
{
|
||||
Mat4Copy(matrix, glState.modelview);
|
||||
if (applyStereoView)
|
||||
{
|
||||
if (tr.refdef.stereoFrame == STEREO_LEFT) {
|
||||
Mat4Multiply(tr.vrParms.viewL, matrix, glState.modelview);
|
||||
} else if (tr.refdef.stereoFrame == STEREO_RIGHT) {
|
||||
Mat4Multiply(tr.vrParms.viewR, matrix, glState.modelview);
|
||||
} else {
|
||||
Mat4Copy(matrix, glState.modelview);
|
||||
}
|
||||
} else {
|
||||
Mat4Copy(matrix, glState.modelview);
|
||||
}
|
||||
|
||||
Mat4Multiply(glState.projection, glState.modelview, glState.modelviewProjection);
|
||||
}
|
||||
|
||||
|
@ -412,7 +424,7 @@ void RB_BeginDrawingView (void) {
|
|||
plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane);
|
||||
plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];
|
||||
#endif
|
||||
GL_SetModelviewMatrix( s_flipMatrix );
|
||||
GL_SetModelviewMatrix( s_flipMatrix, qtrue );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -531,7 +543,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
|
||||
}
|
||||
|
||||
GL_SetModelviewMatrix( backEnd.or.modelMatrix );
|
||||
GL_SetModelviewMatrix( backEnd.or.modelMatrix, qtrue );
|
||||
|
||||
//
|
||||
// change depthrange. Also change projection matrix so first person weapon does not look like coming
|
||||
|
@ -561,8 +573,13 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if(!oldDepthRange)
|
||||
glDepthRangef(0.0f, 0.3f);
|
||||
#else
|
||||
if(!oldDepthRange)
|
||||
qglDepthRange (0, 0.3);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -571,7 +588,11 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix );
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
glDepthRangef(0.0f, 1.0f);
|
||||
#else
|
||||
qglDepthRange (0, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
oldDepthRange = depthRange;
|
||||
|
@ -597,9 +618,13 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
|
||||
// go back to the world modelview matrix
|
||||
|
||||
GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix );
|
||||
GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix, qtrue );
|
||||
|
||||
#ifdef __ANDROID__
|
||||
glDepthRangef(0, 1);
|
||||
#else
|
||||
qglDepthRange (0, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -645,7 +670,7 @@ void RB_SetGL2D (void) {
|
|||
Mat4Ortho(0, width, height, 0, 0, 1, matrix);
|
||||
GL_SetProjectionMatrix(matrix);
|
||||
Mat4Identity(matrix);
|
||||
GL_SetModelviewMatrix(matrix);
|
||||
GL_SetModelviewMatrix(matrix, false);
|
||||
|
||||
GL_State( GLS_DEPTHTEST_DISABLE |
|
||||
GLS_SRCBLEND_SRC_ALPHA |
|
||||
|
@ -1176,7 +1201,6 @@ const void *RB_DrawSurfs( const void *data ) {
|
|||
return (const void *)(cmd + 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
RB_DrawBuffer
|
||||
|
@ -1195,7 +1219,11 @@ const void *RB_DrawBuffer( const void *data ) {
|
|||
if (glRefConfig.framebufferObject)
|
||||
FBO_Bind(NULL);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
qglDrawBuffersEXT( 1, (const GLenum*)&cmd->buffer );
|
||||
#else
|
||||
qglDrawBuffer( cmd->buffer );
|
||||
#endif
|
||||
|
||||
// clear screen for debugging
|
||||
if ( r_clear->integer ) {
|
||||
|
@ -1460,7 +1488,7 @@ const void *RB_PostProcess(const void *data)
|
|||
if(tess.numIndexes)
|
||||
RB_EndSurface();
|
||||
|
||||
if (!glRefConfig.framebufferObject || !r_postProcess->integer)
|
||||
if (__ANDROID__ || !glRefConfig.framebufferObject || !r_postProcess->integer)
|
||||
{
|
||||
// do nothing
|
||||
return (const void *)(cmd + 1);
|
||||
|
@ -1728,6 +1756,28 @@ const void *RB_ExportCubemaps(const void *data)
|
|||
return (const void *)(cmd + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
RB_SwitchEye
|
||||
====================
|
||||
*/
|
||||
const void* RB_SwitchEye( const void* data ) {
|
||||
const switchEyeCommand_t *cmd = data;
|
||||
|
||||
tr.renderFbo->frameBuffer = cmd->eye;
|
||||
|
||||
// Not calling FBO_Bind explicitly, since we just update the frameBuffer
|
||||
// within the struct.
|
||||
if (tr.renderFbo == glState.currentFBO)
|
||||
{
|
||||
GL_BindFramebuffer(GL_FRAMEBUFFER, tr.renderFbo->frameBuffer);
|
||||
glState.currentFBO = tr.renderFbo;
|
||||
}
|
||||
|
||||
tr.refdef.stereoFrame = cmd->stereoFrame;
|
||||
|
||||
return (const void*)(cmd + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
|
@ -1779,6 +1829,9 @@ void RB_ExecuteRenderCommands( const void *data ) {
|
|||
case RC_EXPORT_CUBEMAPS:
|
||||
data = RB_ExportCubemaps(data);
|
||||
break;
|
||||
case RC_SWITCH_EYE:
|
||||
data = RB_SwitchEye(data);
|
||||
break;
|
||||
case RC_END_OF_LIST:
|
||||
default:
|
||||
// finish any 2D drawing if needed
|
||||
|
|
|
@ -411,15 +411,32 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) {
|
|||
}
|
||||
|
||||
if (glConfig.stereoEnabled) {
|
||||
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
|
||||
return;
|
||||
|
||||
cmd->commandId = RC_DRAW_BUFFER;
|
||||
|
||||
if (tr.renderFbo && tr.vrParms.renderBufferOriginal == 0) {
|
||||
tr.vrParms.renderBufferOriginal = tr.renderFbo->frameBuffer;
|
||||
}
|
||||
|
||||
if ( stereoFrame == STEREO_LEFT ) {
|
||||
cmd->buffer = (int)GL_BACK_LEFT;
|
||||
if (tr.vrParms.valid == qtrue) {
|
||||
if (tr.renderFbo) {
|
||||
switchEyeCommand_t* sec;
|
||||
if (!(sec = R_GetCommandBuffer(sizeof(*sec))))
|
||||
return;
|
||||
sec->commandId = RC_SWITCH_EYE;
|
||||
sec->eye = tr.vrParms.renderBufferL;
|
||||
sec->stereoFrame = stereoFrame;
|
||||
}
|
||||
}
|
||||
} else if ( stereoFrame == STEREO_RIGHT ) {
|
||||
cmd->buffer = (int)GL_BACK_RIGHT;
|
||||
if (tr.vrParms.valid == qtrue) {
|
||||
if (tr.renderFbo) {
|
||||
switchEyeCommand_t* sec;
|
||||
if (!(sec = R_GetCommandBuffer(sizeof(*sec))))
|
||||
return;
|
||||
sec->commandId = RC_SWITCH_EYE;
|
||||
sec->eye = tr.vrParms.renderBufferR;
|
||||
sec->stereoFrame = stereoFrame;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
|
||||
}
|
||||
|
@ -556,6 +573,41 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
|
|||
backEnd.pc.msec = 0;
|
||||
}
|
||||
|
||||
#if __ANDROID__
|
||||
void R_Mat4Transpose( const float in[4][4], float* out ) {
|
||||
int i, j;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
out[i * 4 + j] = in[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RE_SetVRHeadsetParms( const ovrTracking2* tracking, int renderBufferL, int renderBufferR ) {
|
||||
if (tracking) {
|
||||
R_Mat4Transpose(tracking->Eye[0].ProjectionMatrix.M, tr.vrParms.projectionL);
|
||||
R_Mat4Transpose(tracking->Eye[1].ProjectionMatrix.M, tr.vrParms.projectionR);
|
||||
R_Mat4Transpose(tracking->Eye[0].ViewMatrix.M, tr.vrParms.viewL);
|
||||
R_Mat4Transpose(tracking->Eye[1].ViewMatrix.M, tr.vrParms.viewR);
|
||||
|
||||
const float worldToMeter = 25.0f; // https://quakewiki.org/wiki/unit, assume 25 units is 1 meter.
|
||||
tr.vrParms.viewL[12] *= worldToMeter;
|
||||
tr.vrParms.viewL[13] *= worldToMeter;
|
||||
tr.vrParms.viewL[14] *= worldToMeter;
|
||||
tr.vrParms.viewR[12] *= worldToMeter;
|
||||
tr.vrParms.viewR[13] *= worldToMeter;
|
||||
tr.vrParms.viewR[14] *= worldToMeter;
|
||||
|
||||
tr.vrParms.renderBufferL = renderBufferL;
|
||||
tr.vrParms.renderBufferR = renderBufferR;
|
||||
|
||||
tr.vrParms.valid = qtrue;
|
||||
} else {
|
||||
tr.vrParms.valid = qfalse;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
=============
|
||||
RE_TakeVideoFrame
|
||||
|
|
|
@ -58,7 +58,11 @@ void GLimp_InitExtraExtensions(void)
|
|||
QGL_ARB_occlusion_query_PROCS;
|
||||
|
||||
// OpenGL 3.0 - GL_ARB_framebuffer_object
|
||||
#ifdef __ANDROID__
|
||||
extension = "GL_OES_framebuffer_object";
|
||||
#else
|
||||
extension = "GL_ARB_framebuffer_object";
|
||||
#endif
|
||||
glRefConfig.framebufferObject = qfalse;
|
||||
glRefConfig.framebufferBlit = qfalse;
|
||||
glRefConfig.framebufferMultisample = qfalse;
|
||||
|
@ -81,7 +85,11 @@ void GLimp_InitExtraExtensions(void)
|
|||
}
|
||||
|
||||
// OpenGL 3.0 - GL_ARB_vertex_array_object
|
||||
#ifdef __ANDROID__
|
||||
extension = "GL_OES_vertex_array_object";
|
||||
#else
|
||||
extension = "GL_ARB_vertex_array_object";
|
||||
#endif
|
||||
glRefConfig.vertexArrayObject = qfalse;
|
||||
if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
|
||||
{
|
||||
|
@ -105,7 +113,11 @@ void GLimp_InitExtraExtensions(void)
|
|||
}
|
||||
|
||||
// OpenGL 3.0 - GL_ARB_texture_float
|
||||
#ifdef __ANDROID
|
||||
extension = "GL_OES_texture_float";
|
||||
#else
|
||||
extension = "GL_ARB_texture_float";
|
||||
#endif
|
||||
glRefConfig.textureFloat = qfalse;
|
||||
if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
|
||||
{
|
||||
|
|
|
@ -529,7 +529,7 @@ void RB_RenderFlares (void) {
|
|||
Mat4Copy(glState.projection, oldprojection);
|
||||
Mat4Copy(glState.modelview, oldmodelview);
|
||||
Mat4Identity(matrix);
|
||||
GL_SetModelviewMatrix(matrix);
|
||||
GL_SetModelviewMatrix(matrix, qtrue);
|
||||
Mat4Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
|
||||
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
|
||||
-99999, 99999, matrix );
|
||||
|
@ -544,7 +544,7 @@ void RB_RenderFlares (void) {
|
|||
}
|
||||
|
||||
GL_SetProjectionMatrix(oldprojection);
|
||||
GL_SetModelviewMatrix(oldmodelview);
|
||||
GL_SetModelviewMatrix(oldmodelview, qtrue);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -241,6 +241,25 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLchar *extra, char *
|
|||
dest[0] = '\0';
|
||||
|
||||
// HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones
|
||||
#ifdef __ANDROID__
|
||||
Q_strcat(dest, size, "#version 300 es\n");
|
||||
Q_strcat(dest, size, "precision mediump float;\n");
|
||||
if(shaderType == GL_VERTEX_SHADER)
|
||||
{
|
||||
Q_strcat(dest, size, "#define attribute in\n");
|
||||
Q_strcat(dest, size, "#define varying out\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strcat(dest, size, "#define varying in\n");
|
||||
|
||||
Q_strcat(dest, size, "out vec4 out_Color;\n");
|
||||
Q_strcat(dest, size, "#define gl_FragColor out_Color\n");
|
||||
Q_strcat(dest, size, "#define texture2D texture\n");
|
||||
Q_strcat(dest, size, "#define textureCubeLod textureLod\n");
|
||||
Q_strcat(dest, size, "#define shadow2D texture\n");
|
||||
}
|
||||
#else
|
||||
if(glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 30))
|
||||
{
|
||||
if (glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 50))
|
||||
|
@ -269,6 +288,7 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLchar *extra, char *
|
|||
Q_strcat(dest, size, "#version 120\n");
|
||||
Q_strcat(dest, size, "#define shadow2D(a,b) shadow2D(a,b).r \n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// HACK: add some macros to avoid extra uniforms and save speed and code maintenance
|
||||
//Q_strcat(dest, size,
|
||||
|
|
|
@ -1624,6 +1624,9 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou
|
|||
|
||||
static qboolean RawImage_HasAlpha(const byte *scan, int numPixels)
|
||||
{
|
||||
#if __ANDROID__
|
||||
return qtrue; // Using RGB as internalFormat is not supported if data format is RGBA.
|
||||
#else
|
||||
int i;
|
||||
|
||||
if (!scan)
|
||||
|
@ -1638,6 +1641,7 @@ static qboolean RawImage_HasAlpha(const byte *scan, int numPixels)
|
|||
}
|
||||
|
||||
return qfalse;
|
||||
#endif
|
||||
}
|
||||
|
||||
static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picFormat, qboolean lightMap, imgType_t type, imgFlags_t flags)
|
||||
|
@ -1942,6 +1946,21 @@ static GLenum PixelDataFormatFromInternalFormat(GLenum internalFormat)
|
|||
}
|
||||
}
|
||||
|
||||
static GLenum PixelTypeFromInternalFormat(GLenum internalFormat)
|
||||
{
|
||||
switch (internalFormat)
|
||||
{
|
||||
case GL_DEPTH_COMPONENT:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
case GL_DEPTH_COMPONENT24:
|
||||
return GL_UNSIGNED_INT;
|
||||
case GL_DEPTH_COMPONENT32F:
|
||||
return GL_FLOAT;
|
||||
default:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
}
|
||||
}
|
||||
|
||||
static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int width, int height, GLenum target, GLenum picFormat, int numMips, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture )
|
||||
{
|
||||
GLenum dataFormat, dataType;
|
||||
|
@ -2106,7 +2125,7 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
|||
qboolean picmip = !!(flags & IMGFLAG_PICMIP);
|
||||
qboolean lastMip;
|
||||
GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
|
||||
GLenum dataFormat;
|
||||
GLenum dataFormat, pixelType;
|
||||
|
||||
if (strlen(name) >= MAX_QPATH ) {
|
||||
ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name);
|
||||
|
@ -2163,6 +2182,7 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
|||
|
||||
// Allocate texture storage so we don't have to worry about it later.
|
||||
dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
|
||||
pixelType = PixelTypeFromInternalFormat(internalFormat);
|
||||
mipWidth = width;
|
||||
mipHeight = height;
|
||||
miplevel = 0;
|
||||
|
@ -2178,7 +2198,7 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
|||
}
|
||||
else
|
||||
{
|
||||
qglTextureImage2DEXT(image->texnum, GL_TEXTURE_2D, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL);
|
||||
qglTextureImage2DEXT(image->texnum, GL_TEXTURE_2D, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, pixelType, NULL);
|
||||
}
|
||||
|
||||
mipWidth = MAX(1, mipWidth >> 1);
|
||||
|
@ -2213,7 +2233,9 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
|||
case GL_DEPTH_COMPONENT32_ARB:
|
||||
// Fix for sampling depth buffer on old nVidia cards.
|
||||
// from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844
|
||||
#ifndef __ANDROID__
|
||||
qglTextureParameterfEXT(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
|
||||
#endif
|
||||
qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
break;
|
||||
|
|
|
@ -955,7 +955,11 @@ const void *RB_TakeVideoFrameCmd( const void *data )
|
|||
*/
|
||||
void GL_SetDefaultState( void )
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
glClearDepthf( 1.0f );
|
||||
#else
|
||||
qglClearDepth( 1.0f );
|
||||
#endif
|
||||
|
||||
qglCullFace(GL_FRONT);
|
||||
|
||||
|
@ -987,7 +991,9 @@ void GL_SetDefaultState( void )
|
|||
glState.currentVao = NULL;
|
||||
glState.vertexAttribsEnabled = 0;
|
||||
|
||||
#ifndef __ANDROID__
|
||||
qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
||||
#endif
|
||||
qglDepthMask( GL_TRUE );
|
||||
qglDisable( GL_DEPTH_TEST );
|
||||
qglEnable( GL_SCISSOR_TEST );
|
||||
|
@ -1345,7 +1351,7 @@ void R_Register( void )
|
|||
r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT);
|
||||
r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT );
|
||||
r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT );
|
||||
r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT);
|
||||
r_nocull = ri.Cvar_Get ("r_nocull", "1", CVAR_CHEAT);
|
||||
r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT);
|
||||
r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT);
|
||||
r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT);
|
||||
|
@ -1536,7 +1542,13 @@ void RE_Shutdown( qboolean destroyWindow ) {
|
|||
R_IssuePendingRenderCommands();
|
||||
R_ShutDownQueries();
|
||||
if (glRefConfig.framebufferObject)
|
||||
{
|
||||
if (tr.vrParms.renderBufferOriginal != 0)
|
||||
{
|
||||
tr.renderFbo->frameBuffer = tr.vrParms.renderBufferOriginal;
|
||||
}
|
||||
FBO_Shutdown();
|
||||
}
|
||||
R_DeleteTextures();
|
||||
R_ShutdownVaos();
|
||||
GLSL_ShutdownGPUShaders();
|
||||
|
@ -1617,6 +1629,10 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
|
|||
re.BeginFrame = RE_BeginFrame;
|
||||
re.EndFrame = RE_EndFrame;
|
||||
|
||||
#if __ANDROID__
|
||||
re.SetVRHeadsetParms = RE_SetVRHeadsetParms;
|
||||
#endif
|
||||
|
||||
re.MarkFragments = R_MarkFragments;
|
||||
re.LerpTag = R_LerpTag;
|
||||
re.ModelBounds = R_ModelBounds;
|
||||
|
|
|
@ -839,6 +839,17 @@ typedef struct {
|
|||
stereoFrame_t stereoFrame;
|
||||
} viewParms_t;
|
||||
|
||||
typedef struct {
|
||||
qboolean valid;
|
||||
float projectionL[16];
|
||||
float projectionR[16];
|
||||
float viewL[16];
|
||||
float viewR[16];
|
||||
int renderBufferL;
|
||||
int renderBufferR;
|
||||
|
||||
int renderBufferOriginal;
|
||||
} vrParms_t;
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
@ -1599,6 +1610,7 @@ typedef struct {
|
|||
// -----------------------------------------
|
||||
|
||||
viewParms_t viewParms;
|
||||
vrParms_t vrParms;
|
||||
|
||||
float identityLight; // 1.0 / ( 1 << overbrightBits )
|
||||
int identityLightByte; // identityLight * 255
|
||||
|
@ -1906,7 +1918,7 @@ void GL_CheckErrs( char *file, int line );
|
|||
#define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__)
|
||||
void GL_State( unsigned long stateVector );
|
||||
void GL_SetProjectionMatrix(mat4_t matrix);
|
||||
void GL_SetModelviewMatrix(mat4_t matrix);
|
||||
void GL_SetModelviewMatrix(mat4_t matrix, qboolean applyStereoView);
|
||||
void GL_Cull( int cullType );
|
||||
|
||||
#define GLS_SRCBLEND_ZERO 0x00000001
|
||||
|
@ -2433,6 +2445,12 @@ typedef struct {
|
|||
int commandId;
|
||||
} exportCubemapsCommand_t;
|
||||
|
||||
typedef struct {
|
||||
int commandId;
|
||||
int eye;
|
||||
stereoFrame_t stereoFrame;
|
||||
} switchEyeCommand_t;
|
||||
|
||||
typedef enum {
|
||||
RC_END_OF_LIST,
|
||||
RC_SET_COLOR,
|
||||
|
@ -2446,7 +2464,8 @@ typedef enum {
|
|||
RC_CLEARDEPTH,
|
||||
RC_CAPSHADOWMAP,
|
||||
RC_POSTPROCESS,
|
||||
RC_EXPORT_CUBEMAPS
|
||||
RC_EXPORT_CUBEMAPS,
|
||||
RC_SWITCH_EYE
|
||||
} renderCommand_t;
|
||||
|
||||
|
||||
|
@ -2488,6 +2507,9 @@ void RE_StretchPic ( float x, float y, float w, float h,
|
|||
float s1, float t1, float s2, float t2, qhandle_t hShader );
|
||||
void RE_BeginFrame( stereoFrame_t stereoFrame );
|
||||
void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
|
||||
#if __ANDROID__
|
||||
void RE_SetVRHeadsetParms( const ovrTracking2* ovrTracking, int renderBufferL, int renderBufferR );
|
||||
#endif
|
||||
void RE_SaveJPG(char * filename, int quality, int image_width, int image_height,
|
||||
unsigned char *image_buffer, int padding);
|
||||
size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
|
||||
|
|
|
@ -755,21 +755,6 @@ void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean comp
|
|||
float xmin, xmax, ymin, ymax;
|
||||
float width, height, stereoSep = r_stereoSeparation->value;
|
||||
|
||||
/*
|
||||
* offset the view origin of the viewer for stereo rendering
|
||||
* by setting the projection matrix appropriately.
|
||||
*/
|
||||
|
||||
if(stereoSep != 0)
|
||||
{
|
||||
if(dest->stereoFrame == STEREO_LEFT)
|
||||
stereoSep = zProj / stereoSep;
|
||||
else if(dest->stereoFrame == STEREO_RIGHT)
|
||||
stereoSep = zProj / -stereoSep;
|
||||
else
|
||||
stereoSep = 0;
|
||||
}
|
||||
|
||||
ymax = zProj * tan(dest->fovY * M_PI / 360.0f);
|
||||
ymin = -ymax;
|
||||
|
||||
|
@ -778,21 +763,44 @@ void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean comp
|
|||
|
||||
width = xmax - xmin;
|
||||
height = ymax - ymin;
|
||||
|
||||
dest->projectionMatrix[0] = 2 * zProj / width;
|
||||
dest->projectionMatrix[4] = 0;
|
||||
dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
|
||||
dest->projectionMatrix[12] = 2 * zProj * stereoSep / width;
|
||||
|
||||
dest->projectionMatrix[1] = 0;
|
||||
dest->projectionMatrix[5] = 2 * zProj / height;
|
||||
dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
|
||||
dest->projectionMatrix[13] = 0;
|
||||
if (tr.vrParms.valid) {
|
||||
if (dest->stereoFrame == STEREO_LEFT) {
|
||||
memcpy(&dest->projectionMatrix, &tr.vrParms.projectionL, sizeof(dest->projectionMatrix));
|
||||
}
|
||||
else {
|
||||
memcpy(&dest->projectionMatrix, &tr.vrParms.projectionR, sizeof(dest->projectionMatrix));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* offset the view origin of the viewer for stereo rendering
|
||||
* by setting the projection matrix appropriately.
|
||||
*/
|
||||
if(stereoSep != 0)
|
||||
{
|
||||
if(dest->stereoFrame == STEREO_LEFT)
|
||||
stereoSep = zProj / stereoSep;
|
||||
else if(dest->stereoFrame == STEREO_RIGHT)
|
||||
stereoSep = zProj / -stereoSep;
|
||||
else
|
||||
stereoSep = 0;
|
||||
}
|
||||
|
||||
dest->projectionMatrix[3] = 0;
|
||||
dest->projectionMatrix[7] = 0;
|
||||
dest->projectionMatrix[11] = -1;
|
||||
dest->projectionMatrix[15] = 0;
|
||||
dest->projectionMatrix[0] = 2 * zProj / width;
|
||||
dest->projectionMatrix[4] = 0;
|
||||
dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
|
||||
dest->projectionMatrix[12] = 2 * zProj * stereoSep / width;
|
||||
|
||||
dest->projectionMatrix[1] = 0;
|
||||
dest->projectionMatrix[5] = 2 * zProj / height;
|
||||
dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
|
||||
dest->projectionMatrix[13] = 0;
|
||||
|
||||
dest->projectionMatrix[3] = 0;
|
||||
dest->projectionMatrix[7] = 0;
|
||||
dest->projectionMatrix[11] = -1;
|
||||
dest->projectionMatrix[15] = 0;
|
||||
}
|
||||
|
||||
// Now that we have all the data for the projection matrix we can also setup the view frustum.
|
||||
if(computeFrustum)
|
||||
|
@ -815,10 +823,12 @@ void R_SetupProjectionZ(viewParms_t *dest)
|
|||
|
||||
depth = zFar - zNear;
|
||||
|
||||
dest->projectionMatrix[2] = 0;
|
||||
dest->projectionMatrix[6] = 0;
|
||||
dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
|
||||
dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
|
||||
if (!tr.vrParms.valid) {
|
||||
dest->projectionMatrix[2] = 0;
|
||||
dest->projectionMatrix[6] = 0;
|
||||
dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
|
||||
dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
|
||||
}
|
||||
|
||||
if (dest->isPortal)
|
||||
{
|
||||
|
|
|
@ -804,7 +804,7 @@ void RB_DrawSun( float scale, shader_t *shader ) {
|
|||
|
||||
Mat4Translation( backEnd.viewParms.or.origin, translation );
|
||||
Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview );
|
||||
GL_SetModelviewMatrix( modelview );
|
||||
GL_SetModelviewMatrix( modelview, qtrue );
|
||||
}
|
||||
|
||||
dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
|
||||
|
@ -855,11 +855,19 @@ void RB_StageIteratorSky( void ) {
|
|||
// r_showsky will let all the sky blocks be drawn in
|
||||
// front of everything to allow developers to see how
|
||||
// much sky is getting sucked in
|
||||
#ifdef __ANDROID__
|
||||
if ( r_showsky->integer ) {
|
||||
glDepthRangef( 0.0, 0.0 );
|
||||
} else {
|
||||
glDepthRangef( 1.0, 1.0 );
|
||||
}
|
||||
#else
|
||||
if ( r_showsky->integer ) {
|
||||
qglDepthRange( 0.0, 0.0 );
|
||||
} else {
|
||||
qglDepthRange( 1.0, 1.0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
// draw the outer skybox
|
||||
if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
|
||||
|
@ -876,13 +884,13 @@ void RB_StageIteratorSky( void ) {
|
|||
Mat4Copy( glState.modelview, oldmodelview );
|
||||
Mat4Translation( backEnd.viewParms.or.origin, trans );
|
||||
Mat4Multiply( glState.modelview, trans, product );
|
||||
GL_SetModelviewMatrix( product );
|
||||
GL_SetModelviewMatrix( product, qtrue );
|
||||
|
||||
}
|
||||
|
||||
DrawSkyBox( tess.shader );
|
||||
|
||||
GL_SetModelviewMatrix( oldmodelview );
|
||||
GL_SetModelviewMatrix( oldmodelview, qtrue );
|
||||
}
|
||||
|
||||
// generate the vertexes for all the clouds, which will be drawn
|
||||
|
@ -893,9 +901,12 @@ void RB_StageIteratorSky( void ) {
|
|||
|
||||
// draw the inner skybox
|
||||
|
||||
|
||||
#ifdef __ANDROID__
|
||||
glDepthRangef( 0.0, 1.0 );
|
||||
#else
|
||||
// back to normal depth range
|
||||
qglDepthRange( 0.0, 1.0 );
|
||||
#endif
|
||||
|
||||
// note that sky was drawn so we will draw a sun later
|
||||
backEnd.skyRenderedThisView = qtrue;
|
||||
|
|
|
@ -112,6 +112,7 @@ GLimp_LogComment
|
|||
*/
|
||||
void GLimp_LogComment( char *comment )
|
||||
{
|
||||
// CON_Print(comment);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -307,7 +308,9 @@ static qboolean GLimp_GetProcAddresses( qboolean fixedFunction ) {
|
|||
QGL_1_5_PROCS;
|
||||
QGL_2_0_PROCS;
|
||||
// error so this doesn't segfault due to NULL desktop GL functions being used
|
||||
#ifndef __ANDROID__
|
||||
Com_Error( ERR_FATAL, "Unsupported OpenGL Version: %s", version );
|
||||
#endif
|
||||
} else {
|
||||
Com_Error( ERR_FATAL, "Unsupported OpenGL Version (%s), OpenGL 2.0 is required", version );
|
||||
}
|
||||
|
@ -431,7 +434,7 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool
|
|||
// use desktop video resolution
|
||||
if( desktopMode.h > 0 )
|
||||
{
|
||||
glConfig.vidWidth = desktopMode.w;
|
||||
glConfig.vidWidth = r_stereoEnabled->integer ? desktopMode.w * 0.5f : desktopMode.w;
|
||||
glConfig.vidHeight = desktopMode.h;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -33,6 +33,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include "../client/client.h"
|
||||
#include "../sys/sys_local.h"
|
||||
|
||||
#if __ANDROID__
|
||||
#include "../vr/vr_input.h"
|
||||
#endif
|
||||
|
||||
static cvar_t *in_keyboardDebug = NULL;
|
||||
|
||||
static SDL_GameController *gamepad = NULL;
|
||||
|
@ -1197,6 +1201,10 @@ void IN_Frame( void )
|
|||
|
||||
IN_ProcessEvents( );
|
||||
|
||||
#if __ANDROID__
|
||||
IN_VRInputFrame( );
|
||||
#endif
|
||||
|
||||
// Set event time for next frame to earliest possible time an event could happen
|
||||
in_eventTime = Sys_Milliseconds( );
|
||||
|
||||
|
@ -1206,6 +1214,8 @@ void IN_Frame( void )
|
|||
vidRestartTime = 0;
|
||||
Cbuf_AddText( "vid_restart\n" );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -501,6 +501,8 @@ char *CON_Input( void )
|
|||
CON_Print
|
||||
==================
|
||||
*/
|
||||
void (*GLogcatFn) ( const char *msg );
|
||||
|
||||
void CON_Print( const char *msg )
|
||||
{
|
||||
if (!msg[0])
|
||||
|
@ -513,6 +515,12 @@ void CON_Print( const char *msg )
|
|||
else
|
||||
fputs( msg, stderr );
|
||||
|
||||
#if __ANDROID__
|
||||
if (GLogcatFn) {
|
||||
(*GLogcatFn)(msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ttycon_on) {
|
||||
// CON_Hide didn't do anything.
|
||||
return;
|
||||
|
@ -535,3 +543,15 @@ void CON_Print( const char *msg )
|
|||
ttycon_show_overdue++;
|
||||
}
|
||||
}
|
||||
|
||||
#if __ANDROID__
|
||||
/*
|
||||
==================
|
||||
CON_LogcatFn
|
||||
==================
|
||||
*/
|
||||
void CON_LogcatFn( void (*LogcatFn)( const char* message ) )
|
||||
{
|
||||
GLogcatFn = LogcatFn;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -45,6 +45,9 @@ void CON_Shutdown( void );
|
|||
void CON_Init( void );
|
||||
char *CON_Input( void );
|
||||
void CON_Print( const char *message );
|
||||
#if __ANDROID__
|
||||
void CON_LogcatFn( void (*LogcatFn)( const char* message ) );
|
||||
#endif
|
||||
|
||||
unsigned int CON_LogSize( void );
|
||||
unsigned int CON_LogWrite( const char *in );
|
||||
|
|
|
@ -255,7 +255,7 @@ Sys_InitPIDFile
|
|||
*/
|
||||
void Sys_InitPIDFile( const char *gamedir ) {
|
||||
if( Sys_WritePIDFile( gamedir ) ) {
|
||||
#ifndef DEDICATED
|
||||
#if !defined(DEDICATED) && !defined(__ANDROID__)
|
||||
char message[1024];
|
||||
char modName[MAX_OSPATH];
|
||||
|
||||
|
|
62
code/vr/vr_base.c
Normal file
62
code/vr/vr_base.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "vr_base.h"
|
||||
#include "VrApi_Types.h"
|
||||
|
||||
#if __ANDROID__
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wstrict-prototypes"
|
||||
#include <VrApi_Helpers.h>
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static engine_t vr_engine;
|
||||
|
||||
engine_t* VR_Init( ovrJava java )
|
||||
{
|
||||
ovrInitParms initParams;
|
||||
ovrResult initResult;
|
||||
|
||||
memset(&vr_engine, 0, sizeof(vr_engine));
|
||||
|
||||
initParams = vrapi_DefaultInitParms(&java);
|
||||
initResult = vrapi_Initialize(&initParams);
|
||||
assert(initResult == VRAPI_INITIALIZE_SUCCESS);
|
||||
|
||||
return &vr_engine;
|
||||
}
|
||||
|
||||
void VR_Destroy( engine_t* engine )
|
||||
{
|
||||
if (engine == &vr_engine) {
|
||||
vrapi_Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void VR_EnterVR( engine_t* engine, ovrJava java ) {
|
||||
if (!engine->ovr) {
|
||||
ovrModeParms modeParams = vrapi_DefaultModeParms(&java);
|
||||
modeParams.Display = (size_t)eglGetCurrentDisplay();
|
||||
modeParams.WindowSurface = (size_t)eglGetCurrentSurface(EGL_DRAW);
|
||||
modeParams.ShareContext = (size_t)eglGetCurrentContext();
|
||||
|
||||
engine->ovr = vrapi_EnterVrMode(&modeParams);
|
||||
engine->frameIndex = 0;
|
||||
|
||||
vrapi_SetTrackingSpace(engine->ovr, VRAPI_TRACKING_SPACE_LOCAL);
|
||||
}
|
||||
}
|
||||
|
||||
void VR_LeaveVR( engine_t* engine ) {
|
||||
if (engine->ovr) {
|
||||
vrapi_LeaveVrMode(engine->ovr);
|
||||
engine->ovr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
engine_t* VR_GetEngine( void ) {
|
||||
return &vr_engine;
|
||||
}
|
||||
#endif
|
17
code/vr/vr_base.h
Normal file
17
code/vr/vr_base.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef __VR_BASE
|
||||
#define __VR_BASE
|
||||
|
||||
#if __ANDROID__
|
||||
|
||||
#include "vr_types.h"
|
||||
|
||||
engine_t* VR_Init( ovrJava java );
|
||||
void VR_Destroy( engine_t* engine );
|
||||
void VR_EnterVR( engine_t* engine, ovrJava java );
|
||||
void VR_LeaveVR( engine_t* engine );
|
||||
|
||||
engine_t* VR_GetEngine( void );
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
197
code/vr/vr_input.c
Normal file
197
code/vr/vr_input.c
Normal file
|
@ -0,0 +1,197 @@
|
|||
#include "vr_input.h"
|
||||
|
||||
#if __ANDROID__
|
||||
|
||||
#include "../qcommon/q_shared.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "../client/keycodes.h"
|
||||
#include "vr_base.h"
|
||||
#include "VrApi_Input.h"
|
||||
|
||||
#ifdef USE_LOCAL_HEADERS
|
||||
# include "SDL.h"
|
||||
#else
|
||||
# include <SDL.h>
|
||||
#endif
|
||||
|
||||
enum {
|
||||
VR_TOUCH_AXIS_UP = 1 << 0,
|
||||
VR_TOUCH_AXIS_DOWN = 1 << 1,
|
||||
VR_TOUCH_AXIS_LEFT = 1 << 2,
|
||||
VR_TOUCH_AXIS_RIGHT = 1 << 3,
|
||||
VR_TOUCH_AXIS_TRIGGER_INDEX = 1 << 4,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t buttons;
|
||||
uint32_t axisButtons;
|
||||
} vrController_t;
|
||||
|
||||
static qboolean controllerInit = qfalse;
|
||||
|
||||
static vrController_t leftController;
|
||||
static vrController_t rightController;
|
||||
static int in_vrEventTime = 0;
|
||||
|
||||
static float pressedThreshold = 0.75f;
|
||||
static float releasedThreshold = 0.5f;
|
||||
|
||||
extern cvar_t *cl_sensitivity;
|
||||
extern cvar_t *m_pitch;
|
||||
extern cvar_t *m_yaw;
|
||||
|
||||
static void IN_VRJoystick( qboolean isRightController, float joystickX, float joystickY )
|
||||
{
|
||||
vrController_t* controller = isRightController == qtrue ? &rightController : &leftController;
|
||||
|
||||
// Menu controls mapped to keyboard codes...
|
||||
if (isRightController == qfalse) {
|
||||
if (!(controller->axisButtons & VR_TOUCH_AXIS_UP) && joystickY > pressedThreshold) {
|
||||
controller->axisButtons |= VR_TOUCH_AXIS_UP;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_UPARROW, qtrue, 0, NULL);
|
||||
} else if ((controller->axisButtons & VR_TOUCH_AXIS_UP) && joystickY < releasedThreshold) {
|
||||
controller->axisButtons &= ~VR_TOUCH_AXIS_UP;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_UPARROW, qfalse, 0, NULL);
|
||||
}
|
||||
|
||||
if (!(controller->axisButtons & VR_TOUCH_AXIS_DOWN) && joystickY < -pressedThreshold) {
|
||||
controller->axisButtons |= VR_TOUCH_AXIS_DOWN;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_DOWNARROW, qtrue, 0, NULL);
|
||||
} else if ((controller->axisButtons & VR_TOUCH_AXIS_DOWN) && joystickY > -releasedThreshold) {
|
||||
controller->axisButtons &= ~VR_TOUCH_AXIS_DOWN;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_DOWNARROW, qfalse, 0, NULL);
|
||||
}
|
||||
|
||||
if (!(controller->axisButtons & VR_TOUCH_AXIS_LEFT) && joystickX < -pressedThreshold) {
|
||||
controller->axisButtons |= VR_TOUCH_AXIS_LEFT;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_LEFTARROW, qtrue, 0, NULL);
|
||||
} else if ((controller->axisButtons & VR_TOUCH_AXIS_LEFT) && joystickX > -releasedThreshold) {
|
||||
controller->axisButtons &= ~VR_TOUCH_AXIS_LEFT;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_LEFTARROW, qfalse, 0, NULL);
|
||||
}
|
||||
|
||||
if (!(controller->axisButtons & VR_TOUCH_AXIS_RIGHT) && joystickX > pressedThreshold) {
|
||||
controller->axisButtons |= VR_TOUCH_AXIS_RIGHT;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_RIGHTARROW, qtrue, 0, NULL);
|
||||
} else if ((controller->axisButtons & VR_TOUCH_AXIS_RIGHT) && joystickX < releasedThreshold) {
|
||||
controller->axisButtons &= ~VR_TOUCH_AXIS_RIGHT;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_RIGHTARROW, qfalse, 0, NULL);
|
||||
}
|
||||
} else {
|
||||
const float sensitivity = cl_sensitivity->value;
|
||||
const float x = joystickX * sensitivity * m_yaw->value;
|
||||
const float y = joystickY * sensitivity * -m_pitch->value;
|
||||
Com_QueueEvent(in_vrEventTime, SE_MOUSE, x, y, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void IN_VRTriggers( qboolean isRightController, float index ) {
|
||||
vrController_t* controller = isRightController == qtrue ? &rightController : &leftController;
|
||||
|
||||
if (isRightController == qtrue) {
|
||||
if (!(controller->axisButtons & VR_TOUCH_AXIS_TRIGGER_INDEX) && index > pressedThreshold) {
|
||||
controller->axisButtons |= VR_TOUCH_AXIS_TRIGGER_INDEX;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_MOUSE1, qtrue, 0, NULL);
|
||||
} else if ((controller->axisButtons & VR_TOUCH_AXIS_TRIGGER_INDEX) && index < releasedThreshold) {
|
||||
controller->axisButtons &= ~VR_TOUCH_AXIS_TRIGGER_INDEX;
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_MOUSE1, qfalse, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void IN_VRButtonsChanged( qboolean isRightController, uint32_t buttons )
|
||||
{
|
||||
vrController_t* controller = isRightController == qtrue ? &rightController : &leftController;
|
||||
|
||||
if ((buttons & ovrButton_A) && !(controller->buttons & ovrButton_A)) {
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_A, qtrue, 0, NULL);
|
||||
} else if (!(buttons & ovrButton_A) && (controller->buttons & ovrButton_A)) {
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_A, qfalse, 0, NULL);
|
||||
}
|
||||
|
||||
if ((buttons & ovrButton_B) && !(controller->buttons & ovrButton_B)) {
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_B, qtrue, 0, NULL);
|
||||
} else if (!(buttons & ovrButton_B) && (controller->buttons & ovrButton_B)) {
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_B, qfalse, 0, NULL);
|
||||
}
|
||||
|
||||
if ((buttons & ovrButton_X) && !(controller->buttons & ovrButton_B)) {
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_X, qtrue, 0, NULL);
|
||||
} else if (!(buttons & ovrButton_B) && (controller->buttons & ovrButton_B)) {
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_X, qfalse, 0, NULL);
|
||||
}
|
||||
|
||||
if ((buttons & ovrButton_Y) && !(controller->buttons & ovrButton_B)) {
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_Y, qtrue, 0, NULL);
|
||||
} else if (!(buttons & ovrButton_B) && (controller->buttons & ovrButton_B)) {
|
||||
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_Y, qfalse, 0, NULL);
|
||||
}
|
||||
|
||||
controller->buttons = buttons;
|
||||
}
|
||||
|
||||
void IN_VRInputFrame( void )
|
||||
{
|
||||
if (controllerInit == qfalse) {
|
||||
memset(&leftController, 0, sizeof(leftController));
|
||||
memset(&rightController, 0, sizeof(rightController));
|
||||
controllerInit = qtrue;
|
||||
}
|
||||
|
||||
ovrMobile* ovr = VR_GetEngine()->ovr;
|
||||
if (!ovr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ovrInputCapabilityHeader capsHeader;
|
||||
uint32_t index = 0;
|
||||
for (;;) {
|
||||
ovrResult enumResult = vrapi_EnumerateInputDevices(ovr, index, &capsHeader);
|
||||
if (enumResult < 0) {
|
||||
break;
|
||||
}
|
||||
++index;
|
||||
|
||||
if (capsHeader.Type != ovrControllerType_TrackedRemote) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ovrInputTrackedRemoteCapabilities caps;
|
||||
caps.Header = capsHeader;
|
||||
ovrResult capsResult = vrapi_GetInputDeviceCapabilities(ovr, &caps.Header);
|
||||
if (capsResult < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ovrInputStateTrackedRemote state;
|
||||
state.Header.ControllerType = ovrControllerType_TrackedRemote;
|
||||
ovrResult stateResult = vrapi_GetCurrentInputState(ovr, capsHeader.DeviceID, &state.Header);
|
||||
if (stateResult < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
qboolean isRight;
|
||||
vrController_t* controller;
|
||||
if (caps.ControllerCapabilities & ovrControllerCaps_LeftHand) {
|
||||
isRight = qfalse;
|
||||
controller = &leftController;
|
||||
} else if (caps.ControllerCapabilities & ovrControllerCaps_RightHand) {
|
||||
isRight = qtrue;
|
||||
controller = &rightController;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
IN_VRJoystick(isRight, state.JoystickNoDeadZone.x, state.JoystickNoDeadZone.y);
|
||||
IN_VRTriggers(isRight, state.IndexTrigger);
|
||||
|
||||
if (controller->buttons ^ state.Buttons) {
|
||||
IN_VRButtonsChanged(isRight, state.Buttons);
|
||||
}
|
||||
}
|
||||
|
||||
in_vrEventTime = Sys_Milliseconds( );
|
||||
}
|
||||
|
||||
#endif
|
10
code/vr/vr_input.h
Normal file
10
code/vr/vr_input.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef __VR_INPUT_H
|
||||
#define __VR_INPUT_H
|
||||
|
||||
#if __ANDROID__
|
||||
|
||||
void IN_VRInputFrame( void );
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
141
code/vr/vr_renderer.c
Normal file
141
code/vr/vr_renderer.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
#include "vr_renderer.h"
|
||||
|
||||
#include "../qcommon/q_shared.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "../client/client.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wstrict-prototypes"
|
||||
#include <VrApi_Helpers.h>
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ENABLE_GL_DEBUG 1
|
||||
#define ENABLE_GL_DEBUG_VERBOSE 0
|
||||
#if ENABLE_GL_DEBUG
|
||||
#include <GLES3/gl32.h>
|
||||
#endif
|
||||
|
||||
void APIENTRY VR_GLDebugLog(GLenum source, GLenum type, GLuint id,
|
||||
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
||||
{
|
||||
if (type == GL_DEBUG_TYPE_ERROR || type == GL_DEBUG_TYPE_PERFORMANCE || ENABLE_GL_DEBUG_VERBOSE)
|
||||
{
|
||||
Com_Printf("GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
|
||||
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type, severity, message);
|
||||
}
|
||||
}
|
||||
|
||||
void VR_InitRenderer( engine_t* engine ) {
|
||||
#if ENABLE_GL_DEBUG
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glDebugMessageCallback(VR_GLDebugLog, 0);
|
||||
#endif
|
||||
|
||||
int eyeW, eyeH;
|
||||
|
||||
eyeW = 1440; // vrapi_GetSystemPropertyInt(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH);
|
||||
eyeH = 1600; // vrapi_GetSystemPropertyInt(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT);
|
||||
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
|
||||
framebuffer_t* framebuffer = &engine->framebuffers[eye];
|
||||
framebuffer->colorTexture = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_2D, GL_RGBA8,
|
||||
eyeW, eyeH, 1, 3);
|
||||
framebuffer->swapchainLength = vrapi_GetTextureSwapChainLength(framebuffer->colorTexture);
|
||||
framebuffer->depthBuffers = (GLuint*)malloc(framebuffer->swapchainLength * sizeof(GLuint));
|
||||
framebuffer->framebuffers = (GLuint*)malloc(framebuffer->swapchainLength * sizeof(GLuint));
|
||||
|
||||
for (int index = 0; index < framebuffer->swapchainLength; ++index) {
|
||||
GLuint colorTexture;
|
||||
GLenum framebufferStatus;
|
||||
|
||||
colorTexture = vrapi_GetTextureSwapChainHandle(framebuffer->colorTexture, index);
|
||||
glBindTexture(GL_TEXTURE_2D, colorTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glGenRenderbuffers(1, &framebuffer->depthBuffers[index]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, framebuffer->depthBuffers[index]);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, eyeW, eyeH);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
glGenFramebuffers(1, &framebuffer->framebuffers[index]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer->framebuffers[index]);
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
|
||||
framebuffer->depthBuffers[index]);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
|
||||
framebufferStatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
|
||||
assert(framebufferStatus == GL_FRAMEBUFFER_COMPLETE);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VR_DestroyRenderer( engine_t* engine ) {
|
||||
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye)
|
||||
{
|
||||
if (engine->framebuffers[eye].swapchainLength > 0) {
|
||||
glDeleteFramebuffers(engine->framebuffers[eye].swapchainLength,
|
||||
engine->framebuffers[eye].depthBuffers);
|
||||
free(engine->framebuffers[eye].depthBuffers);
|
||||
free(engine->framebuffers[eye].framebuffers);
|
||||
|
||||
vrapi_DestroyTextureSwapChain(engine->framebuffers[eye].colorTexture);
|
||||
|
||||
memset(&engine->framebuffers[eye], 0, sizeof(engine->framebuffers[eye]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void VR_DrawFrame( engine_t* engine ) {
|
||||
double predictedDisplayTime;
|
||||
ovrTracking2 tracking;
|
||||
ovrLayerProjection2 layer;
|
||||
|
||||
if (!engine->ovr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
++engine->frameIndex;
|
||||
predictedDisplayTime = vrapi_GetPredictedDisplayTime(engine->ovr, engine->frameIndex);
|
||||
tracking = vrapi_GetPredictedTracking2(engine->ovr, predictedDisplayTime);
|
||||
|
||||
layer = vrapi_DefaultLayerProjection2();
|
||||
layer.HeadPose = tracking.HeadPose;
|
||||
|
||||
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
|
||||
layer.Textures[eye].ColorSwapChain = engine->framebuffers[eye].colorTexture;
|
||||
layer.Textures[eye].SwapChainIndex = engine->framebuffers[eye].swapchainIndex;
|
||||
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&tracking.Eye[eye].ProjectionMatrix);
|
||||
}
|
||||
|
||||
const framebuffer_t* framebuffers = engine->framebuffers;
|
||||
re.SetVRHeadsetParms(&tracking,
|
||||
framebuffers[0].framebuffers[framebuffers[0].swapchainIndex],
|
||||
framebuffers[1].framebuffers[framebuffers[1].swapchainIndex]);
|
||||
Com_Frame();
|
||||
|
||||
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
|
||||
engine->framebuffers[eye].swapchainIndex = (engine->framebuffers[eye].swapchainIndex + 1) %
|
||||
engine->framebuffers[eye].swapchainLength;
|
||||
}
|
||||
|
||||
const ovrLayerHeader2* layers[] = {
|
||||
&layer.Header
|
||||
};
|
||||
|
||||
ovrSubmitFrameDescription2 frameDesc = { 0 };
|
||||
frameDesc.Flags = 0;
|
||||
frameDesc.SwapInterval = 1;
|
||||
frameDesc.FrameIndex = engine->frameIndex;
|
||||
frameDesc.DisplayTime = predictedDisplayTime;
|
||||
frameDesc.LayerCount = 1;
|
||||
frameDesc.Layers = layers;
|
||||
|
||||
vrapi_SubmitFrame2(engine->ovr, &frameDesc);
|
||||
}
|
14
code/vr/vr_renderer.h
Normal file
14
code/vr/vr_renderer.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef __VR_RENDERER
|
||||
#define __VR_RENDERER
|
||||
|
||||
#if __ANDROID__
|
||||
|
||||
#include "vr_types.h"
|
||||
|
||||
void VR_InitRenderer( engine_t* engine );
|
||||
void VR_DestroyRenderer( engine_t* engine );
|
||||
void VR_DrawFrame( engine_t* engine );
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
31
code/vr/vr_types.h
Normal file
31
code/vr/vr_types.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef __VR_TYPES
|
||||
#define __VR_TYPES
|
||||
|
||||
#ifdef USE_LOCAL_HEADERS
|
||||
# include "SDL_opengl.h"
|
||||
# include "SDL_opengles2.h"
|
||||
#else
|
||||
# include <SDL_opengl.h>
|
||||
# include <SDL_opengles2.h>
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wstrict-prototypes"
|
||||
#include <VrApi.h>
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
typedef struct {
|
||||
int swapchainLength;
|
||||
int swapchainIndex;
|
||||
ovrTextureSwapChain* colorTexture;
|
||||
GLuint* depthBuffers;
|
||||
GLuint* framebuffers;
|
||||
} framebuffer_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t frameIndex;
|
||||
ovrMobile* ovr;
|
||||
framebuffer_t framebuffers[VRAPI_FRAME_LAYER_EYE_MAX];
|
||||
} engine_t;
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue