mirror of
https://github.com/amwatson/CitraVR.git
synced 2024-09-20 03:11:40 +02:00
added abstract class for keyboard and did dimension measuring
This commit is contained in:
parent
043f57ec8c
commit
f231577afd
7 changed files with 99 additions and 58 deletions
2
src/android/app/proguard-rules.pro
vendored
2
src/android/app/proguard-rules.pro
vendored
|
@ -26,3 +26,5 @@
|
|||
-keep class org.citra.citra_emu.vr.GameSurfaceLayer { *; }
|
||||
-keep class org.citra.citra_emu.vr.VrActivity { *; }
|
||||
-keep class org.citra.citra_emu.vr.ui.VrUILayer { *; }
|
||||
-keep class org.citra.citra_emu.vr.ui.VrKeyboardLayer { *; }
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package org.citra.citra_emu.vr.ui
|
||||
|
||||
import org.citra.citra_emu.R
|
||||
import org.citra.citra_emu.vr.VrActivity
|
||||
|
||||
class VrKeyboardLayer(activity: VrActivity) : VrUILayer(activity, R.layout.vr_keyboard) {
|
||||
|
||||
override fun onSurfaceCreated() {
|
||||
super.onSurfaceCreated()
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@ import android.view.Surface
|
|||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import org.citra.citra_emu.R
|
||||
import org.citra.citra_emu.utils.Log
|
||||
import org.citra.citra_emu.vr.VrActivity
|
||||
import java.io.File
|
||||
|
@ -34,8 +33,8 @@ import kotlin.math.roundToInt
|
|||
**/
|
||||
abstract class VrUILayer(
|
||||
val activity: VrActivity,
|
||||
densityDpi: Int = DEFAULT_DENSITY.toInt(),
|
||||
private val layoutId: Int = R.layout.vr_keyboard
|
||||
private val layoutId: Int,
|
||||
densityDpi: Int = DEFAULT_DENSITY.toInt()
|
||||
) {
|
||||
private val requestedDensity: Float = densityDpi.toFloat()
|
||||
private var virtualDisplay: VirtualDisplay? = null
|
||||
|
@ -46,33 +45,63 @@ abstract class VrUILayer(
|
|||
|
||||
/// Called from JNI ////
|
||||
fun getBoundsForView(handle: Long): Int {
|
||||
val inflater = activity.getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE
|
||||
) as LayoutInflater
|
||||
val contentView = inflater.inflate(layoutId, null, false)
|
||||
val contentView = LayoutInflater.from(activity).inflate(layoutId, null, false)
|
||||
if (contentView == null) {
|
||||
Log.error( "Failed to inflate content view")
|
||||
Log.warning("contentView is null")
|
||||
return -1
|
||||
}
|
||||
val (widthPx, heightPx) = calculateDynamicDimensions(activity, 1.0f, 1.0f)
|
||||
|
||||
contentView.measure(
|
||||
View.MeasureSpec.UNSPECIFIED,
|
||||
View.MeasureSpec.UNSPECIFIED
|
||||
View.MeasureSpec.makeMeasureSpec(widthPx, View.MeasureSpec.EXACTLY),
|
||||
View.MeasureSpec.makeMeasureSpec(heightPx, View.MeasureSpec.EXACTLY)
|
||||
)
|
||||
|
||||
val measuredWidthPx = contentView.measuredWidth
|
||||
val measuredHeightPx = contentView.measuredHeight
|
||||
|
||||
val displayMetrics = activity.resources.displayMetrics
|
||||
val widthDp = contentView.measuredWidth.toFloat() / displayMetrics.density /
|
||||
(DEFAULT_DENSITY / requestedDensity)
|
||||
val heightDp = contentView.measuredHeight.toFloat() / displayMetrics.density /
|
||||
(DEFAULT_DENSITY / requestedDensity)
|
||||
// roundToInt() matching the rounding Android uses to convert view dimensions to display units
|
||||
nativeSetBounds(
|
||||
handle, 0, 0, widthDp.roundToInt(),
|
||||
heightDp.roundToInt()
|
||||
)
|
||||
val measuredWidthDp = measuredWidthPx / displayMetrics.density
|
||||
val measuredHeightDp = measuredHeightPx / displayMetrics.density
|
||||
|
||||
// Call native method with measured dimensions
|
||||
nativeSetBounds(handle, 0, 0, measuredWidthDp.roundToInt(), measuredHeightDp.roundToInt())
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
fun sendClickToUI(x: Float, y: Float, motionType: Int): Int {
|
||||
val action = when (motionType) {
|
||||
0 -> MotionEvent.ACTION_UP
|
||||
1 -> MotionEvent.ACTION_DOWN
|
||||
2 -> MotionEvent.ACTION_MOVE
|
||||
else -> MotionEvent.ACTION_HOVER_ENTER
|
||||
}
|
||||
activity.runOnUiThread { dispatchTouchEvent(x, y, action) }
|
||||
return 0
|
||||
}
|
||||
|
||||
fun setSurface(
|
||||
surface: Surface, widthDp: Int,
|
||||
heightDp: Int
|
||||
): Int {
|
||||
activity.runOnUiThread { setSurface_(surface, widthDp, heightDp) }
|
||||
return 0
|
||||
}
|
||||
|
||||
protected open fun onSurfaceCreated() {}
|
||||
|
||||
private fun calculateDynamicDimensions(context: Context, widthPercentage: Float, heightPercentage: Float): Pair<Int, Int> {
|
||||
val displayMetrics = context.resources.displayMetrics
|
||||
val screenWidthPx = displayMetrics.widthPixels
|
||||
val screenHeightPx = displayMetrics.heightPixels
|
||||
|
||||
val desiredWidthPx = (screenWidthPx * widthPercentage).toInt()
|
||||
val desiredHeightPx = (screenHeightPx * heightPercentage).toInt()
|
||||
|
||||
return Pair(desiredWidthPx, desiredHeightPx)
|
||||
}
|
||||
|
||||
private fun dispatchTouchEvent(x: Float, y: Float, action: Int) {
|
||||
val eventTime = SystemClock.uptimeMillis()
|
||||
MotionEvent.obtain(
|
||||
|
@ -100,25 +129,6 @@ abstract class VrUILayer(
|
|||
}
|
||||
}
|
||||
|
||||
fun sendClickToUI(x: Float, y: Float, motionType: Int): Int {
|
||||
val action = when (motionType) {
|
||||
0 -> MotionEvent.ACTION_UP
|
||||
1 -> MotionEvent.ACTION_DOWN
|
||||
2 -> MotionEvent.ACTION_MOVE
|
||||
else -> MotionEvent.ACTION_HOVER_ENTER
|
||||
}
|
||||
activity.runOnUiThread { dispatchTouchEvent(x, y, action) }
|
||||
return 0
|
||||
}
|
||||
|
||||
fun setSurface(
|
||||
surface: Surface, widthDp: Int,
|
||||
heightDp: Int
|
||||
): Int {
|
||||
activity.runOnUiThread { setSurface_(surface, widthDp, heightDp) }
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun setSurface_(
|
||||
surface: Surface, widthDp: Int,
|
||||
heightDp: Int
|
||||
|
@ -140,8 +150,6 @@ abstract class VrUILayer(
|
|||
onSurfaceCreated()
|
||||
}
|
||||
|
||||
protected fun onSurfaceCreated() {}
|
||||
|
||||
fun writeBitmapToDisk(bmp: Bitmap, outName: String?) {
|
||||
val sdCard = activity.externalCacheDir
|
||||
if (sdCard != null && outName != null) {
|
||||
|
|
|
@ -99,7 +99,7 @@ struct BoundsHandle
|
|||
//-----------------------------------------------------------------------------
|
||||
// JNI functions
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_org_citra_citra_1emu_vr_ui_UILayer_00024Companion_nativeSetBounds(
|
||||
Java_org_citra_citra_1emu_vr_ui_VrUILayer_00024Companion_nativeSetBounds(
|
||||
JNIEnv* env, jobject thiz, jlong handle, jint left, jint top, jint right,
|
||||
jint bottom)
|
||||
{
|
||||
|
@ -255,7 +255,7 @@ bool UILayer::GetRayIntersectionWithPanel(const XrVector3f& start,
|
|||
result2d, result3d);
|
||||
}
|
||||
|
||||
// Next error code: -5
|
||||
// Next error code: -6
|
||||
int32_t UILayer::Init(const std::string& className,
|
||||
const jobject activityObject, const XrVector3f& position,
|
||||
const XrSession& session)
|
||||
|
@ -279,7 +279,10 @@ int32_t UILayer::Init(const std::string& className,
|
|||
BAIL_ON_COND(mGetBoundsMethodID == nullptr,
|
||||
"could not find getBoundsForView()", -4);
|
||||
|
||||
TryCreateSwapchain();
|
||||
mSetSurfaceMethodId = mEnv->GetMethodID(mVrUILayerClass, "setSurface",
|
||||
"(Landroid/view/Surface;II)I");
|
||||
BAIL_ON_COND(mSetSurfaceMethodId == nullptr, "could not find setSurface()",
|
||||
-5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -296,11 +299,24 @@ void UILayer::TryCreateSwapchain()
|
|||
|
||||
AndroidWindowBounds viewBounds;
|
||||
{
|
||||
if (mEnv->ExceptionCheck()) { mEnv->ExceptionClear(); }
|
||||
const jint ret = mEnv->CallIntMethod(
|
||||
mVrUILayerObject, mGetBoundsMethodID, BoundsHandle(&viewBounds).l);
|
||||
// Check for exceptions (and log them).
|
||||
if (mEnv->ExceptionCheck())
|
||||
{
|
||||
mEnv->ExceptionDescribe();
|
||||
mEnv->ExceptionClear();
|
||||
}
|
||||
if (ret < 0)
|
||||
{
|
||||
ALOGD("getBoundsForView() returned error %d", ret);
|
||||
ALOGE("{}() returned error {}", __FUNCTION__, ret);
|
||||
return;
|
||||
}
|
||||
if (viewBounds.Width() == 0 || viewBounds.Height() == 0)
|
||||
{
|
||||
ALOGE("{}() returned invalid bounds {} x {}", __FUNCTION__,
|
||||
viewBounds.Width(), viewBounds.Height());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -338,18 +354,19 @@ void UILayer::TryCreateSwapchain()
|
|||
mSession, &swapchainCreateInfo, &mSwapchain.mHandle, &mSurface));
|
||||
mSwapchain.mWidth = viewBounds.Width();
|
||||
mSwapchain.mHeight = viewBounds.Height();
|
||||
ALOGD("UILayer: created swapchain {}x{}", mSwapchain.mWidth,
|
||||
mSwapchain.mHeight);
|
||||
|
||||
jmethodID setSurfaceMethodId = mEnv->GetMethodID(
|
||||
mVrUILayerClass, "setSurface", "(Landroid/view/Surface;II)I");
|
||||
if (setSurfaceMethodId == nullptr)
|
||||
{
|
||||
FAIL("Couldn't find setSurface()");
|
||||
}
|
||||
mEnv->CallIntMethod(mVrUILayerObject, setSurfaceMethodId, mSurface,
|
||||
mIsSwapchainCreated = true;
|
||||
|
||||
mEnv->CallIntMethod(mVrUILayerObject, mSetSurfaceMethodId, mSurface,
|
||||
(int)viewBounds.Width(), (int)viewBounds.Height());
|
||||
if (mEnv->ExceptionCheck())
|
||||
{
|
||||
mEnv->ExceptionDescribe();
|
||||
mEnv->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
mIsSwapchainCreated = true;
|
||||
}
|
||||
|
||||
void UILayer::SendClickToUI(const XrVector2f& pos2d, const int type)
|
||||
|
|
|
@ -97,4 +97,5 @@ private:
|
|||
// like window decorations or status bars.
|
||||
jmethodID mGetBoundsMethodID = nullptr;
|
||||
jmethodID mSendClickToWindowMethodID = nullptr;
|
||||
jmethodID mSetSurfaceMethodId = nullptr;
|
||||
};
|
||||
|
|
|
@ -278,10 +278,10 @@ public:
|
|||
jni, mActivityObject, gOpenXr->mSession);
|
||||
#endif
|
||||
|
||||
|
||||
mUILayer = std::make_unique<UILayer>(
|
||||
"org/citra/citra_emu/vr/ui/VrUILayer",
|
||||
XrVector3f{0, 0.0f, -1.5f}, jni, mActivityObject, gOpenXr->mSession);
|
||||
"org/citra/citra_emu/vr/ui/VrKeyboardLayer",
|
||||
XrVector3f{0, 0.0f, -1.5f}, jni, mActivityObject,
|
||||
gOpenXr->mSession);
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Intialize JNI methods
|
||||
|
@ -523,6 +523,8 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
if (!mUILayer->IsSwapchainCreated()) { mUILayer->TryCreateSwapchain(); }
|
||||
|
||||
////////////////////////////////
|
||||
// XrWaitFrame()
|
||||
////////////////////////////////
|
||||
|
|
|
@ -13,8 +13,8 @@ app's packagename and returns information for the wrong window.-->
|
|||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/vr_keyboard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="1200dp"
|
||||
android:layout_height="800dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="30dp"
|
||||
android:gravity="center"
|
||||
|
|
Loading…
Reference in a new issue