mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2025-02-17 17:41:28 +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
|
build
|
||||||
Makefile.local
|
|
||||||
*.swp
|
*.swp
|
||||||
*tags
|
*tags
|
||||||
*~
|
*~
|
||||||
|
*.ccls-cache/
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
# OS X
|
# OS X
|
||||||
####################
|
####################
|
||||||
|
@ -39,3 +40,17 @@ profile
|
||||||
*.sdf
|
*.sdf
|
||||||
*.opensdf
|
*.opensdf
|
||||||
*.suo
|
*.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
|
CLIENTBIN=ioquake3
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifndef LIBPREFIX
|
||||||
|
LIBPREFIX=
|
||||||
|
endif
|
||||||
|
|
||||||
ifndef SERVERBIN
|
ifndef SERVERBIN
|
||||||
SERVERBIN=ioq3ded
|
SERVERBIN=ioq3ded
|
||||||
endif
|
endif
|
||||||
|
@ -250,6 +254,7 @@ RGL1DIR=$(MOUNT_DIR)/renderergl1
|
||||||
RGL2DIR=$(MOUNT_DIR)/renderergl2
|
RGL2DIR=$(MOUNT_DIR)/renderergl2
|
||||||
CMDIR=$(MOUNT_DIR)/qcommon
|
CMDIR=$(MOUNT_DIR)/qcommon
|
||||||
SDLDIR=$(MOUNT_DIR)/sdl
|
SDLDIR=$(MOUNT_DIR)/sdl
|
||||||
|
VRDIR=$(MOUNT_DIR)/vr
|
||||||
ASMDIR=$(MOUNT_DIR)/asm
|
ASMDIR=$(MOUNT_DIR)/asm
|
||||||
SYSDIR=$(MOUNT_DIR)/sys
|
SYSDIR=$(MOUNT_DIR)/sys
|
||||||
GDIR=$(MOUNT_DIR)/game
|
GDIR=$(MOUNT_DIR)/game
|
||||||
|
@ -276,6 +281,7 @@ LOKISETUPDIR=misc/setup
|
||||||
NSISDIR=misc/nsis
|
NSISDIR=misc/nsis
|
||||||
SDLHDIR=$(MOUNT_DIR)/SDL2
|
SDLHDIR=$(MOUNT_DIR)/SDL2
|
||||||
LIBSDIR=$(MOUNT_DIR)/libs
|
LIBSDIR=$(MOUNT_DIR)/libs
|
||||||
|
VRAPIDIR=$(MOUNT_DIR)/VrApi
|
||||||
|
|
||||||
bin_path=$(shell which $(1) 2> /dev/null)
|
bin_path=$(shell which $(1) 2> /dev/null)
|
||||||
|
|
||||||
|
@ -422,6 +428,51 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu")
|
||||||
endif
|
endif
|
||||||
else # ifeq Linux
|
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
|
# SETUP AND BUILD -- MAC OS X
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
@ -954,6 +1005,7 @@ else # ifeq sunos
|
||||||
SHLIBLDFLAGS=-shared
|
SHLIBLDFLAGS=-shared
|
||||||
|
|
||||||
endif #Linux
|
endif #Linux
|
||||||
|
endif #Android
|
||||||
endif #darwin
|
endif #darwin
|
||||||
endif #MINGW
|
endif #MINGW
|
||||||
endif #FreeBSD
|
endif #FreeBSD
|
||||||
|
@ -991,9 +1043,9 @@ endif
|
||||||
|
|
||||||
ifneq ($(BUILD_CLIENT),0)
|
ifneq ($(BUILD_CLIENT),0)
|
||||||
ifneq ($(USE_RENDERER_DLOPEN),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)
|
ifneq ($(BUILD_RENDERER_OPENGL2),0)
|
||||||
TARGETS += $(B)/renderer_opengl2_$(SHLIBNAME)
|
TARGETS += $(B)/$(LIBPREFIX)renderer_opengl2_$(SHLIBNAME)
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT)
|
TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT)
|
||||||
|
@ -1223,7 +1275,7 @@ define DO_REF_STR
|
||||||
$(echo_cmd) "REF_STR $<"
|
$(echo_cmd) "REF_STR $<"
|
||||||
$(Q)rm -f $@
|
$(Q)rm -f $@
|
||||||
$(Q)echo "const char *fallbackShader_$(notdir $(basename $<)) =" >> $@
|
$(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 ";" >> $@
|
$(Q)echo ";" >> $@
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
@ -1759,6 +1811,10 @@ Q3OBJ = \
|
||||||
$(B)/client/sdl_input.o \
|
$(B)/client/sdl_input.o \
|
||||||
$(B)/client/sdl_snd.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/con_log.o \
|
||||||
$(B)/client/sys_autoupdater.o \
|
$(B)/client/sys_autoupdater.o \
|
||||||
$(B)/client/sys_main.o
|
$(B)/client/sys_main.o
|
||||||
|
@ -2191,12 +2247,12 @@ $(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(LIBSDLMAIN)
|
||||||
-o $@ $(Q3OBJ) \
|
-o $@ $(Q3OBJ) \
|
||||||
$(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
|
$(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
|
||||||
|
|
||||||
$(B)/renderer_opengl1_$(SHLIBNAME): $(Q3ROBJ) $(JPGOBJ)
|
$(B)/$(LIBPREFIX)renderer_opengl1_$(SHLIBNAME): $(Q3ROBJ) $(JPGOBJ)
|
||||||
$(echo_cmd) "LD $@"
|
$(echo_cmd) "LD $@"
|
||||||
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3ROBJ) $(JPGOBJ) \
|
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3ROBJ) $(JPGOBJ) \
|
||||||
$(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS)
|
$(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS)
|
||||||
|
|
||||||
$(B)/renderer_opengl2_$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ)
|
$(B)/$(LIBPREFIX)renderer_opengl2_$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ)
|
||||||
$(echo_cmd) "LD $@"
|
$(echo_cmd) "LD $@"
|
||||||
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \
|
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \
|
||||||
$(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS)
|
$(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS)
|
||||||
|
@ -2697,6 +2753,9 @@ $(B)/client/%.o: $(ZDIR)/%.c
|
||||||
$(B)/client/%.o: $(SDLDIR)/%.c
|
$(B)/client/%.o: $(SDLDIR)/%.c
|
||||||
$(DO_CC)
|
$(DO_CC)
|
||||||
|
|
||||||
|
$(B)/client/%.o: $(VRDIR)/%.c
|
||||||
|
$(DO_CC)
|
||||||
|
|
||||||
$(B)/client/%.o: $(SYSDIR)/%.c
|
$(B)/client/%.o: $(SYSDIR)/%.c
|
||||||
$(DO_CC)
|
$(DO_CC)
|
||||||
|
|
||||||
|
@ -2882,9 +2941,9 @@ endif
|
||||||
ifneq ($(BUILD_CLIENT),0)
|
ifneq ($(BUILD_CLIENT),0)
|
||||||
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)$(FULLBINEXT)
|
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)$(FULLBINEXT)
|
||||||
ifneq ($(USE_RENDERER_DLOPEN),0)
|
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)
|
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
|
endif
|
||||||
else
|
else
|
||||||
ifneq ($(BUILD_RENDERER_OPENGL2),0)
|
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_bobup;
|
||||||
extern vmCvar_t cg_bobpitch;
|
extern vmCvar_t cg_bobpitch;
|
||||||
extern vmCvar_t cg_bobroll;
|
extern vmCvar_t cg_bobroll;
|
||||||
|
extern vmCvar_t cg_weaponbob;
|
||||||
extern vmCvar_t cg_swingSpeed;
|
extern vmCvar_t cg_swingSpeed;
|
||||||
extern vmCvar_t cg_shadows;
|
extern vmCvar_t cg_shadows;
|
||||||
extern vmCvar_t cg_gibs;
|
extern vmCvar_t cg_gibs;
|
||||||
|
|
|
@ -96,6 +96,7 @@ vmCvar_t cg_runroll;
|
||||||
vmCvar_t cg_bobup;
|
vmCvar_t cg_bobup;
|
||||||
vmCvar_t cg_bobpitch;
|
vmCvar_t cg_bobpitch;
|
||||||
vmCvar_t cg_bobroll;
|
vmCvar_t cg_bobroll;
|
||||||
|
vmCvar_t cg_weaponbob;
|
||||||
vmCvar_t cg_swingSpeed;
|
vmCvar_t cg_swingSpeed;
|
||||||
vmCvar_t cg_shadows;
|
vmCvar_t cg_shadows;
|
||||||
vmCvar_t cg_gibs;
|
vmCvar_t cg_gibs;
|
||||||
|
@ -246,6 +247,7 @@ static cvarTable_t cvarTable[] = {
|
||||||
{ &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
|
{ &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
|
||||||
{ &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
|
{ &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
|
||||||
{ &cg_bobroll, "cg_bobroll", "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_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
|
||||||
{ &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
|
{ &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
|
||||||
{ &cg_debugAnim, "cg_debuganim", "0", 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
|
// gun angles from bobbing
|
||||||
angles[ROLL] += scale * cg.bobfracsin * 0.005;
|
if (cg_weaponbob.value != 0)
|
||||||
angles[YAW] += scale * cg.bobfracsin * 0.01;
|
{
|
||||||
angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
|
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
|
// drop the weapon when landing
|
||||||
delta = cg.time - cg.landTime;
|
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)
|
if(enableDll)
|
||||||
{
|
{
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
Com_sprintf(found, foundlen, "lib%s", dllName);
|
||||||
|
return VMI_NATIVE;
|
||||||
|
#else
|
||||||
netpath = FS_BuildOSPath(dir->path, dir->gamedir, dllName);
|
netpath = FS_BuildOSPath(dir->path, dir->gamedir, dllName);
|
||||||
|
|
||||||
if(FS_FileInPathExists(netpath))
|
if(FS_FileInPathExists(netpath))
|
||||||
|
@ -1482,6 +1486,7 @@ int FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, i
|
||||||
|
|
||||||
return VMI_NATIVE;
|
return VMI_NATIVE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if(FS_FOpenFileReadDir(qvmName, search, NULL, qfalse, qfalse) > 0)
|
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 *),
|
vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
|
||||||
vmInterpret_t interpret ) {
|
vmInterpret_t interpret ) {
|
||||||
|
#if __ANDROID__
|
||||||
|
interpret = VMI_NATIVE;
|
||||||
|
#endif
|
||||||
|
|
||||||
vm_t *vm;
|
vm_t *vm;
|
||||||
vmHeader_t *header;
|
vmHeader_t *header;
|
||||||
int i, remaining, retval;
|
int i, remaining, retval;
|
||||||
|
|
|
@ -28,8 +28,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
#ifdef USE_LOCAL_HEADERS
|
#ifdef USE_LOCAL_HEADERS
|
||||||
# include "SDL_opengl.h"
|
# include "SDL_opengl.h"
|
||||||
|
# include "SDL_opengles2.h"
|
||||||
#else
|
#else
|
||||||
# include <SDL_opengl.h>
|
# include <SDL_opengl.h>
|
||||||
|
# include <SDL_opengles2.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void (APIENTRYP qglActiveTextureARB) (GLenum texture);
|
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, TexParameterf, GLenum target, GLenum pname, GLfloat param) \
|
||||||
GLE(void, TexParameteri, GLenum target, GLenum pname, GLint 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, 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) \
|
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
|
// 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, DeleteProgram, GLuint program) \
|
||||||
GLE(void, DeleteShader, GLuint shader) \
|
GLE(void, DeleteShader, GLuint shader) \
|
||||||
GLE(void, DetachShader, GLuint program, GLuint shader) \
|
GLE(void, DetachShader, GLuint program, GLuint shader) \
|
||||||
|
GLE(void, DrawBuffersEXT, GLsizei n, const GLenum *bufs) \
|
||||||
GLE(void, DisableVertexAttribArray, GLuint index) \
|
GLE(void, DisableVertexAttribArray, GLuint index) \
|
||||||
GLE(void, EnableVertexAttribArray, GLuint index) \
|
GLE(void, EnableVertexAttribArray, GLuint index) \
|
||||||
GLE(void, GetActiveUniform, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) \
|
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"
|
#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.
|
* Include file for users of JPEG library.
|
||||||
* You will need to have included system headers that define at least
|
* 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)
|
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
|
/* This struct contains the JPEG decompression parameters and pointers to
|
||||||
* working space (which is allocated as needed by the JPEG library).
|
* 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! */
|
/* 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"
|
#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
|
#define REF_API_VERSION 8
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -82,6 +89,9 @@ typedef struct {
|
||||||
// if the pointers are not NULL, timing info will be returned
|
// if the pointers are not NULL, timing info will be returned
|
||||||
void (*EndFrame)( int *frontEndMsec, int *backEndMsec );
|
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 (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,
|
||||||
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
|
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 );
|
qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
|
||||||
|
#ifndef __ANDROID__
|
||||||
qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
|
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)
|
dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
|
||||||
size = dist * scale;
|
size = dist * scale;
|
||||||
|
@ -770,7 +772,9 @@ void RB_StageIteratorSky( void ) {
|
||||||
qglPushMatrix ();
|
qglPushMatrix ();
|
||||||
GL_State( 0 );
|
GL_State( 0 );
|
||||||
GL_Cull( CT_FRONT_SIDED );
|
GL_Cull( CT_FRONT_SIDED );
|
||||||
|
#ifndef __ANDROID__
|
||||||
qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
|
qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
|
||||||
|
#endif
|
||||||
|
|
||||||
DrawSkyBox( tess.shader );
|
DrawSkyBox( tess.shader );
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
precision mediump sampler2D;
|
||||||
|
|
||||||
uniform sampler2D u_DiffuseMap;
|
uniform sampler2D u_DiffuseMap;
|
||||||
|
|
||||||
#if defined(USE_LIGHTMAP)
|
#if defined(USE_LIGHTMAP)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
precision mediump sampler2D;
|
||||||
uniform sampler2D u_ShadowMap;
|
uniform sampler2D u_ShadowMap;
|
||||||
|
|
||||||
uniform vec3 u_LightForward;
|
uniform vec3 u_LightForward;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
precision mediump sampler2D;
|
||||||
|
precision mediump sampler2DShadow;
|
||||||
|
|
||||||
uniform sampler2D u_ScreenDepthMap;
|
uniform sampler2D u_ScreenDepthMap;
|
||||||
|
|
||||||
uniform sampler2DShadow u_ShadowMap;
|
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);
|
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[2] = DotProduct (backEnd.viewParms.or.axis[2], plane);
|
||||||
plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];
|
plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];
|
||||||
#endif
|
#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 );
|
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
|
// 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)
|
if(!oldDepthRange)
|
||||||
qglDepthRange (0, 0.3);
|
qglDepthRange (0, 0.3);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -571,7 +588,11 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
||||||
GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix );
|
GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
glDepthRangef(0.0f, 1.0f);
|
||||||
|
#else
|
||||||
qglDepthRange (0, 1);
|
qglDepthRange (0, 1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
oldDepthRange = depthRange;
|
oldDepthRange = depthRange;
|
||||||
|
@ -597,9 +618,13 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
||||||
|
|
||||||
// go back to the world modelview matrix
|
// 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);
|
qglDepthRange (0, 1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -645,7 +670,7 @@ void RB_SetGL2D (void) {
|
||||||
Mat4Ortho(0, width, height, 0, 0, 1, matrix);
|
Mat4Ortho(0, width, height, 0, 0, 1, matrix);
|
||||||
GL_SetProjectionMatrix(matrix);
|
GL_SetProjectionMatrix(matrix);
|
||||||
Mat4Identity(matrix);
|
Mat4Identity(matrix);
|
||||||
GL_SetModelviewMatrix(matrix);
|
GL_SetModelviewMatrix(matrix, false);
|
||||||
|
|
||||||
GL_State( GLS_DEPTHTEST_DISABLE |
|
GL_State( GLS_DEPTHTEST_DISABLE |
|
||||||
GLS_SRCBLEND_SRC_ALPHA |
|
GLS_SRCBLEND_SRC_ALPHA |
|
||||||
|
@ -1176,7 +1201,6 @@ const void *RB_DrawSurfs( const void *data ) {
|
||||||
return (const void *)(cmd + 1);
|
return (const void *)(cmd + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
RB_DrawBuffer
|
RB_DrawBuffer
|
||||||
|
@ -1195,7 +1219,11 @@ const void *RB_DrawBuffer( const void *data ) {
|
||||||
if (glRefConfig.framebufferObject)
|
if (glRefConfig.framebufferObject)
|
||||||
FBO_Bind(NULL);
|
FBO_Bind(NULL);
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
qglDrawBuffersEXT( 1, (const GLenum*)&cmd->buffer );
|
||||||
|
#else
|
||||||
qglDrawBuffer( cmd->buffer );
|
qglDrawBuffer( cmd->buffer );
|
||||||
|
#endif
|
||||||
|
|
||||||
// clear screen for debugging
|
// clear screen for debugging
|
||||||
if ( r_clear->integer ) {
|
if ( r_clear->integer ) {
|
||||||
|
@ -1460,7 +1488,7 @@ const void *RB_PostProcess(const void *data)
|
||||||
if(tess.numIndexes)
|
if(tess.numIndexes)
|
||||||
RB_EndSurface();
|
RB_EndSurface();
|
||||||
|
|
||||||
if (!glRefConfig.framebufferObject || !r_postProcess->integer)
|
if (__ANDROID__ || !glRefConfig.framebufferObject || !r_postProcess->integer)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
return (const void *)(cmd + 1);
|
return (const void *)(cmd + 1);
|
||||||
|
@ -1728,6 +1756,28 @@ const void *RB_ExportCubemaps(const void *data)
|
||||||
return (const void *)(cmd + 1);
|
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:
|
case RC_EXPORT_CUBEMAPS:
|
||||||
data = RB_ExportCubemaps(data);
|
data = RB_ExportCubemaps(data);
|
||||||
break;
|
break;
|
||||||
|
case RC_SWITCH_EYE:
|
||||||
|
data = RB_SwitchEye(data);
|
||||||
|
break;
|
||||||
case RC_END_OF_LIST:
|
case RC_END_OF_LIST:
|
||||||
default:
|
default:
|
||||||
// finish any 2D drawing if needed
|
// finish any 2D drawing if needed
|
||||||
|
|
|
@ -411,15 +411,32 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glConfig.stereoEnabled) {
|
if (glConfig.stereoEnabled) {
|
||||||
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
|
if (tr.renderFbo && tr.vrParms.renderBufferOriginal == 0) {
|
||||||
return;
|
tr.vrParms.renderBufferOriginal = tr.renderFbo->frameBuffer;
|
||||||
|
}
|
||||||
cmd->commandId = RC_DRAW_BUFFER;
|
|
||||||
|
|
||||||
if ( stereoFrame == STEREO_LEFT ) {
|
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 ) {
|
} 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 {
|
} else {
|
||||||
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
|
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;
|
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
|
RE_TakeVideoFrame
|
||||||
|
|
|
@ -58,7 +58,11 @@ void GLimp_InitExtraExtensions(void)
|
||||||
QGL_ARB_occlusion_query_PROCS;
|
QGL_ARB_occlusion_query_PROCS;
|
||||||
|
|
||||||
// OpenGL 3.0 - GL_ARB_framebuffer_object
|
// OpenGL 3.0 - GL_ARB_framebuffer_object
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
extension = "GL_OES_framebuffer_object";
|
||||||
|
#else
|
||||||
extension = "GL_ARB_framebuffer_object";
|
extension = "GL_ARB_framebuffer_object";
|
||||||
|
#endif
|
||||||
glRefConfig.framebufferObject = qfalse;
|
glRefConfig.framebufferObject = qfalse;
|
||||||
glRefConfig.framebufferBlit = qfalse;
|
glRefConfig.framebufferBlit = qfalse;
|
||||||
glRefConfig.framebufferMultisample = qfalse;
|
glRefConfig.framebufferMultisample = qfalse;
|
||||||
|
@ -81,7 +85,11 @@ void GLimp_InitExtraExtensions(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenGL 3.0 - GL_ARB_vertex_array_object
|
// OpenGL 3.0 - GL_ARB_vertex_array_object
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
extension = "GL_OES_vertex_array_object";
|
||||||
|
#else
|
||||||
extension = "GL_ARB_vertex_array_object";
|
extension = "GL_ARB_vertex_array_object";
|
||||||
|
#endif
|
||||||
glRefConfig.vertexArrayObject = qfalse;
|
glRefConfig.vertexArrayObject = qfalse;
|
||||||
if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
|
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
|
// OpenGL 3.0 - GL_ARB_texture_float
|
||||||
|
#ifdef __ANDROID
|
||||||
|
extension = "GL_OES_texture_float";
|
||||||
|
#else
|
||||||
extension = "GL_ARB_texture_float";
|
extension = "GL_ARB_texture_float";
|
||||||
|
#endif
|
||||||
glRefConfig.textureFloat = qfalse;
|
glRefConfig.textureFloat = qfalse;
|
||||||
if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
|
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.projection, oldprojection);
|
||||||
Mat4Copy(glState.modelview, oldmodelview);
|
Mat4Copy(glState.modelview, oldmodelview);
|
||||||
Mat4Identity(matrix);
|
Mat4Identity(matrix);
|
||||||
GL_SetModelviewMatrix(matrix);
|
GL_SetModelviewMatrix(matrix, qtrue);
|
||||||
Mat4Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
|
Mat4Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
|
||||||
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
|
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
|
||||||
-99999, 99999, matrix );
|
-99999, 99999, matrix );
|
||||||
|
@ -544,7 +544,7 @@ void RB_RenderFlares (void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GL_SetProjectionMatrix(oldprojection);
|
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';
|
dest[0] = '\0';
|
||||||
|
|
||||||
// HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones
|
// 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 >= 30))
|
||||||
{
|
{
|
||||||
if (glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 50))
|
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, "#version 120\n");
|
||||||
Q_strcat(dest, size, "#define shadow2D(a,b) shadow2D(a,b).r \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
|
// HACK: add some macros to avoid extra uniforms and save speed and code maintenance
|
||||||
//Q_strcat(dest, size,
|
//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)
|
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;
|
int i;
|
||||||
|
|
||||||
if (!scan)
|
if (!scan)
|
||||||
|
@ -1638,6 +1641,7 @@ static qboolean RawImage_HasAlpha(const byte *scan, int numPixels)
|
||||||
}
|
}
|
||||||
|
|
||||||
return qfalse;
|
return qfalse;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picFormat, qboolean lightMap, imgType_t type, imgFlags_t flags)
|
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 )
|
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;
|
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 picmip = !!(flags & IMGFLAG_PICMIP);
|
||||||
qboolean lastMip;
|
qboolean lastMip;
|
||||||
GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
|
GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
|
||||||
GLenum dataFormat;
|
GLenum dataFormat, pixelType;
|
||||||
|
|
||||||
if (strlen(name) >= MAX_QPATH ) {
|
if (strlen(name) >= MAX_QPATH ) {
|
||||||
ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name);
|
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.
|
// Allocate texture storage so we don't have to worry about it later.
|
||||||
dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
|
dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
|
||||||
|
pixelType = PixelTypeFromInternalFormat(internalFormat);
|
||||||
mipWidth = width;
|
mipWidth = width;
|
||||||
mipHeight = height;
|
mipHeight = height;
|
||||||
miplevel = 0;
|
miplevel = 0;
|
||||||
|
@ -2178,7 +2198,7 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
||||||
}
|
}
|
||||||
else
|
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);
|
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:
|
case GL_DEPTH_COMPONENT32_ARB:
|
||||||
// Fix for sampling depth buffer on old nVidia cards.
|
// Fix for sampling depth buffer on old nVidia cards.
|
||||||
// from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844
|
// from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844
|
||||||
|
#ifndef __ANDROID__
|
||||||
qglTextureParameterfEXT(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
|
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_MIN_FILTER, GL_NEAREST);
|
||||||
qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -955,7 +955,11 @@ const void *RB_TakeVideoFrameCmd( const void *data )
|
||||||
*/
|
*/
|
||||||
void GL_SetDefaultState( void )
|
void GL_SetDefaultState( void )
|
||||||
{
|
{
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
glClearDepthf( 1.0f );
|
||||||
|
#else
|
||||||
qglClearDepth( 1.0f );
|
qglClearDepth( 1.0f );
|
||||||
|
#endif
|
||||||
|
|
||||||
qglCullFace(GL_FRONT);
|
qglCullFace(GL_FRONT);
|
||||||
|
|
||||||
|
@ -987,7 +991,9 @@ void GL_SetDefaultState( void )
|
||||||
glState.currentVao = NULL;
|
glState.currentVao = NULL;
|
||||||
glState.vertexAttribsEnabled = 0;
|
glState.vertexAttribsEnabled = 0;
|
||||||
|
|
||||||
|
#ifndef __ANDROID__
|
||||||
qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
#endif
|
||||||
qglDepthMask( GL_TRUE );
|
qglDepthMask( GL_TRUE );
|
||||||
qglDisable( GL_DEPTH_TEST );
|
qglDisable( GL_DEPTH_TEST );
|
||||||
qglEnable( GL_SCISSOR_TEST );
|
qglEnable( GL_SCISSOR_TEST );
|
||||||
|
@ -1345,7 +1351,7 @@ void R_Register( void )
|
||||||
r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT);
|
r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT);
|
||||||
r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT );
|
r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT );
|
||||||
r_ignore = ri.Cvar_Get( "r_ignore", "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_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT);
|
||||||
r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT);
|
r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT);
|
||||||
r_speeds = ri.Cvar_Get ("r_speeds", "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_IssuePendingRenderCommands();
|
||||||
R_ShutDownQueries();
|
R_ShutDownQueries();
|
||||||
if (glRefConfig.framebufferObject)
|
if (glRefConfig.framebufferObject)
|
||||||
|
{
|
||||||
|
if (tr.vrParms.renderBufferOriginal != 0)
|
||||||
|
{
|
||||||
|
tr.renderFbo->frameBuffer = tr.vrParms.renderBufferOriginal;
|
||||||
|
}
|
||||||
FBO_Shutdown();
|
FBO_Shutdown();
|
||||||
|
}
|
||||||
R_DeleteTextures();
|
R_DeleteTextures();
|
||||||
R_ShutdownVaos();
|
R_ShutdownVaos();
|
||||||
GLSL_ShutdownGPUShaders();
|
GLSL_ShutdownGPUShaders();
|
||||||
|
@ -1617,6 +1629,10 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
|
||||||
re.BeginFrame = RE_BeginFrame;
|
re.BeginFrame = RE_BeginFrame;
|
||||||
re.EndFrame = RE_EndFrame;
|
re.EndFrame = RE_EndFrame;
|
||||||
|
|
||||||
|
#if __ANDROID__
|
||||||
|
re.SetVRHeadsetParms = RE_SetVRHeadsetParms;
|
||||||
|
#endif
|
||||||
|
|
||||||
re.MarkFragments = R_MarkFragments;
|
re.MarkFragments = R_MarkFragments;
|
||||||
re.LerpTag = R_LerpTag;
|
re.LerpTag = R_LerpTag;
|
||||||
re.ModelBounds = R_ModelBounds;
|
re.ModelBounds = R_ModelBounds;
|
||||||
|
|
|
@ -839,6 +839,17 @@ typedef struct {
|
||||||
stereoFrame_t stereoFrame;
|
stereoFrame_t stereoFrame;
|
||||||
} viewParms_t;
|
} 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;
|
viewParms_t viewParms;
|
||||||
|
vrParms_t vrParms;
|
||||||
|
|
||||||
float identityLight; // 1.0 / ( 1 << overbrightBits )
|
float identityLight; // 1.0 / ( 1 << overbrightBits )
|
||||||
int identityLightByte; // identityLight * 255
|
int identityLightByte; // identityLight * 255
|
||||||
|
@ -1906,7 +1918,7 @@ void GL_CheckErrs( char *file, int line );
|
||||||
#define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__)
|
#define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__)
|
||||||
void GL_State( unsigned long stateVector );
|
void GL_State( unsigned long stateVector );
|
||||||
void GL_SetProjectionMatrix(mat4_t matrix);
|
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 );
|
void GL_Cull( int cullType );
|
||||||
|
|
||||||
#define GLS_SRCBLEND_ZERO 0x00000001
|
#define GLS_SRCBLEND_ZERO 0x00000001
|
||||||
|
@ -2433,6 +2445,12 @@ typedef struct {
|
||||||
int commandId;
|
int commandId;
|
||||||
} exportCubemapsCommand_t;
|
} exportCubemapsCommand_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int commandId;
|
||||||
|
int eye;
|
||||||
|
stereoFrame_t stereoFrame;
|
||||||
|
} switchEyeCommand_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RC_END_OF_LIST,
|
RC_END_OF_LIST,
|
||||||
RC_SET_COLOR,
|
RC_SET_COLOR,
|
||||||
|
@ -2446,7 +2464,8 @@ typedef enum {
|
||||||
RC_CLEARDEPTH,
|
RC_CLEARDEPTH,
|
||||||
RC_CAPSHADOWMAP,
|
RC_CAPSHADOWMAP,
|
||||||
RC_POSTPROCESS,
|
RC_POSTPROCESS,
|
||||||
RC_EXPORT_CUBEMAPS
|
RC_EXPORT_CUBEMAPS,
|
||||||
|
RC_SWITCH_EYE
|
||||||
} renderCommand_t;
|
} 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 );
|
float s1, float t1, float s2, float t2, qhandle_t hShader );
|
||||||
void RE_BeginFrame( stereoFrame_t stereoFrame );
|
void RE_BeginFrame( stereoFrame_t stereoFrame );
|
||||||
void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
|
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,
|
void RE_SaveJPG(char * filename, int quality, int image_width, int image_height,
|
||||||
unsigned char *image_buffer, int padding);
|
unsigned char *image_buffer, int padding);
|
||||||
size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
|
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 xmin, xmax, ymin, ymax;
|
||||||
float width, height, stereoSep = r_stereoSeparation->value;
|
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);
|
ymax = zProj * tan(dest->fovY * M_PI / 360.0f);
|
||||||
ymin = -ymax;
|
ymin = -ymax;
|
||||||
|
|
||||||
|
@ -778,21 +763,44 @@ void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean comp
|
||||||
|
|
||||||
width = xmax - xmin;
|
width = xmax - xmin;
|
||||||
height = ymax - ymin;
|
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;
|
if (tr.vrParms.valid) {
|
||||||
dest->projectionMatrix[5] = 2 * zProj / height;
|
if (dest->stereoFrame == STEREO_LEFT) {
|
||||||
dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
|
memcpy(&dest->projectionMatrix, &tr.vrParms.projectionL, sizeof(dest->projectionMatrix));
|
||||||
dest->projectionMatrix[13] = 0;
|
}
|
||||||
|
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[0] = 2 * zProj / width;
|
||||||
dest->projectionMatrix[7] = 0;
|
dest->projectionMatrix[4] = 0;
|
||||||
dest->projectionMatrix[11] = -1;
|
dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
|
||||||
dest->projectionMatrix[15] = 0;
|
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.
|
// Now that we have all the data for the projection matrix we can also setup the view frustum.
|
||||||
if(computeFrustum)
|
if(computeFrustum)
|
||||||
|
@ -815,10 +823,12 @@ void R_SetupProjectionZ(viewParms_t *dest)
|
||||||
|
|
||||||
depth = zFar - zNear;
|
depth = zFar - zNear;
|
||||||
|
|
||||||
dest->projectionMatrix[2] = 0;
|
if (!tr.vrParms.valid) {
|
||||||
dest->projectionMatrix[6] = 0;
|
dest->projectionMatrix[2] = 0;
|
||||||
dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
|
dest->projectionMatrix[6] = 0;
|
||||||
dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
|
dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
|
||||||
|
dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
|
||||||
|
}
|
||||||
|
|
||||||
if (dest->isPortal)
|
if (dest->isPortal)
|
||||||
{
|
{
|
||||||
|
|
|
@ -804,7 +804,7 @@ void RB_DrawSun( float scale, shader_t *shader ) {
|
||||||
|
|
||||||
Mat4Translation( backEnd.viewParms.or.origin, translation );
|
Mat4Translation( backEnd.viewParms.or.origin, translation );
|
||||||
Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview );
|
Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview );
|
||||||
GL_SetModelviewMatrix( modelview );
|
GL_SetModelviewMatrix( modelview, qtrue );
|
||||||
}
|
}
|
||||||
|
|
||||||
dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
|
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
|
// r_showsky will let all the sky blocks be drawn in
|
||||||
// front of everything to allow developers to see how
|
// front of everything to allow developers to see how
|
||||||
// much sky is getting sucked in
|
// 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 ) {
|
if ( r_showsky->integer ) {
|
||||||
qglDepthRange( 0.0, 0.0 );
|
qglDepthRange( 0.0, 0.0 );
|
||||||
} else {
|
} else {
|
||||||
qglDepthRange( 1.0, 1.0 );
|
qglDepthRange( 1.0, 1.0 );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// draw the outer skybox
|
// draw the outer skybox
|
||||||
if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
|
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 );
|
Mat4Copy( glState.modelview, oldmodelview );
|
||||||
Mat4Translation( backEnd.viewParms.or.origin, trans );
|
Mat4Translation( backEnd.viewParms.or.origin, trans );
|
||||||
Mat4Multiply( glState.modelview, trans, product );
|
Mat4Multiply( glState.modelview, trans, product );
|
||||||
GL_SetModelviewMatrix( product );
|
GL_SetModelviewMatrix( product, qtrue );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawSkyBox( tess.shader );
|
DrawSkyBox( tess.shader );
|
||||||
|
|
||||||
GL_SetModelviewMatrix( oldmodelview );
|
GL_SetModelviewMatrix( oldmodelview, qtrue );
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate the vertexes for all the clouds, which will be drawn
|
// generate the vertexes for all the clouds, which will be drawn
|
||||||
|
@ -893,9 +901,12 @@ void RB_StageIteratorSky( void ) {
|
||||||
|
|
||||||
// draw the inner skybox
|
// draw the inner skybox
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
glDepthRangef( 0.0, 1.0 );
|
||||||
|
#else
|
||||||
// back to normal depth range
|
// back to normal depth range
|
||||||
qglDepthRange( 0.0, 1.0 );
|
qglDepthRange( 0.0, 1.0 );
|
||||||
|
#endif
|
||||||
|
|
||||||
// note that sky was drawn so we will draw a sun later
|
// note that sky was drawn so we will draw a sun later
|
||||||
backEnd.skyRenderedThisView = qtrue;
|
backEnd.skyRenderedThisView = qtrue;
|
||||||
|
|
|
@ -112,6 +112,7 @@ GLimp_LogComment
|
||||||
*/
|
*/
|
||||||
void GLimp_LogComment( char *comment )
|
void GLimp_LogComment( char *comment )
|
||||||
{
|
{
|
||||||
|
// CON_Print(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -307,7 +308,9 @@ static qboolean GLimp_GetProcAddresses( qboolean fixedFunction ) {
|
||||||
QGL_1_5_PROCS;
|
QGL_1_5_PROCS;
|
||||||
QGL_2_0_PROCS;
|
QGL_2_0_PROCS;
|
||||||
// error so this doesn't segfault due to NULL desktop GL functions being used
|
// 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 );
|
Com_Error( ERR_FATAL, "Unsupported OpenGL Version: %s", version );
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
Com_Error( ERR_FATAL, "Unsupported OpenGL Version (%s), OpenGL 2.0 is required", version );
|
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
|
// use desktop video resolution
|
||||||
if( desktopMode.h > 0 )
|
if( desktopMode.h > 0 )
|
||||||
{
|
{
|
||||||
glConfig.vidWidth = desktopMode.w;
|
glConfig.vidWidth = r_stereoEnabled->integer ? desktopMode.w * 0.5f : desktopMode.w;
|
||||||
glConfig.vidHeight = desktopMode.h;
|
glConfig.vidHeight = desktopMode.h;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -33,6 +33,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
#include "../client/client.h"
|
#include "../client/client.h"
|
||||||
#include "../sys/sys_local.h"
|
#include "../sys/sys_local.h"
|
||||||
|
|
||||||
|
#if __ANDROID__
|
||||||
|
#include "../vr/vr_input.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static cvar_t *in_keyboardDebug = NULL;
|
static cvar_t *in_keyboardDebug = NULL;
|
||||||
|
|
||||||
static SDL_GameController *gamepad = NULL;
|
static SDL_GameController *gamepad = NULL;
|
||||||
|
@ -1197,6 +1201,10 @@ void IN_Frame( void )
|
||||||
|
|
||||||
IN_ProcessEvents( );
|
IN_ProcessEvents( );
|
||||||
|
|
||||||
|
#if __ANDROID__
|
||||||
|
IN_VRInputFrame( );
|
||||||
|
#endif
|
||||||
|
|
||||||
// Set event time for next frame to earliest possible time an event could happen
|
// Set event time for next frame to earliest possible time an event could happen
|
||||||
in_eventTime = Sys_Milliseconds( );
|
in_eventTime = Sys_Milliseconds( );
|
||||||
|
|
||||||
|
@ -1206,6 +1214,8 @@ void IN_Frame( void )
|
||||||
vidRestartTime = 0;
|
vidRestartTime = 0;
|
||||||
Cbuf_AddText( "vid_restart\n" );
|
Cbuf_AddText( "vid_restart\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -501,6 +501,8 @@ char *CON_Input( void )
|
||||||
CON_Print
|
CON_Print
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
|
void (*GLogcatFn) ( const char *msg );
|
||||||
|
|
||||||
void CON_Print( const char *msg )
|
void CON_Print( const char *msg )
|
||||||
{
|
{
|
||||||
if (!msg[0])
|
if (!msg[0])
|
||||||
|
@ -513,6 +515,12 @@ void CON_Print( const char *msg )
|
||||||
else
|
else
|
||||||
fputs( msg, stderr );
|
fputs( msg, stderr );
|
||||||
|
|
||||||
|
#if __ANDROID__
|
||||||
|
if (GLogcatFn) {
|
||||||
|
(*GLogcatFn)(msg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!ttycon_on) {
|
if (!ttycon_on) {
|
||||||
// CON_Hide didn't do anything.
|
// CON_Hide didn't do anything.
|
||||||
return;
|
return;
|
||||||
|
@ -535,3 +543,15 @@ void CON_Print( const char *msg )
|
||||||
ttycon_show_overdue++;
|
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 );
|
void CON_Init( void );
|
||||||
char *CON_Input( void );
|
char *CON_Input( void );
|
||||||
void CON_Print( const char *message );
|
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_LogSize( void );
|
||||||
unsigned int CON_LogWrite( const char *in );
|
unsigned int CON_LogWrite( const char *in );
|
||||||
|
|
|
@ -255,7 +255,7 @@ Sys_InitPIDFile
|
||||||
*/
|
*/
|
||||||
void Sys_InitPIDFile( const char *gamedir ) {
|
void Sys_InitPIDFile( const char *gamedir ) {
|
||||||
if( Sys_WritePIDFile( gamedir ) ) {
|
if( Sys_WritePIDFile( gamedir ) ) {
|
||||||
#ifndef DEDICATED
|
#if !defined(DEDICATED) && !defined(__ANDROID__)
|
||||||
char message[1024];
|
char message[1024];
|
||||||
char modName[MAX_OSPATH];
|
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