forked from suyu/suyu
android: Convert InputOverlayDrawableJoystick to Kotlin
This commit is contained in:
parent
5c8372a566
commit
42b3e72e96
2 changed files with 205 additions and 243 deletions
|
@ -1,243 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2013 Dolphin Emulator Project
|
|
||||||
* Licensed under GPLv2+
|
|
||||||
* Refer to the license.txt file included.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.overlay;
|
|
||||||
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
|
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary;
|
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary.ButtonType;
|
|
||||||
import org.yuzu.yuzu_emu.utils.EmulationMenuSettings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom {@link BitmapDrawable} that is capable
|
|
||||||
* of storing it's own ID.
|
|
||||||
*/
|
|
||||||
public final class InputOverlayDrawableJoystick {
|
|
||||||
// The ID value what type of joystick this Drawable represents.
|
|
||||||
private int mJoystickId;
|
|
||||||
// The ID value what type of button this Drawable represents.
|
|
||||||
private int mButtonId;
|
|
||||||
// The ID value what motion event is tracking
|
|
||||||
private int mTrackId = -1;
|
|
||||||
private float mXAxis;
|
|
||||||
private float mYAxis;
|
|
||||||
private int mControlPositionX, mControlPositionY;
|
|
||||||
private int mWidth;
|
|
||||||
private int mHeight;
|
|
||||||
private Rect mVirtBounds;
|
|
||||||
private Rect mOrigBounds;
|
|
||||||
private BitmapDrawable mOuterBitmap;
|
|
||||||
private BitmapDrawable mDefaultStateInnerBitmap;
|
|
||||||
private BitmapDrawable mPressedStateInnerBitmap;
|
|
||||||
private BitmapDrawable mBoundsBoxBitmap;
|
|
||||||
private boolean mPressedState = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param res {@link Resources} instance.
|
|
||||||
* @param bitmapOuter {@link Bitmap} which represents the outer non-movable part of the joystick.
|
|
||||||
* @param bitmapInnerDefault {@link Bitmap} which represents the default inner movable part of the joystick.
|
|
||||||
* @param bitmapInnerPressed {@link Bitmap} which represents the pressed inner movable part of the joystick.
|
|
||||||
* @param rectOuter {@link Rect} which represents the outer joystick bounds.
|
|
||||||
* @param rectInner {@link Rect} which represents the inner joystick bounds.
|
|
||||||
* @param joystick Identifier for which joystick this is.
|
|
||||||
*/
|
|
||||||
public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter,
|
|
||||||
Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed,
|
|
||||||
Rect rectOuter, Rect rectInner, int joystick, int button) {
|
|
||||||
mJoystickId = joystick;
|
|
||||||
mButtonId = button;
|
|
||||||
|
|
||||||
mOuterBitmap = new BitmapDrawable(res, bitmapOuter);
|
|
||||||
mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault);
|
|
||||||
mPressedStateInnerBitmap = new BitmapDrawable(res, bitmapInnerPressed);
|
|
||||||
mBoundsBoxBitmap = new BitmapDrawable(res, bitmapOuter);
|
|
||||||
mWidth = bitmapOuter.getWidth();
|
|
||||||
mHeight = bitmapOuter.getHeight();
|
|
||||||
|
|
||||||
setBounds(rectOuter);
|
|
||||||
mDefaultStateInnerBitmap.setBounds(rectInner);
|
|
||||||
mPressedStateInnerBitmap.setBounds(rectInner);
|
|
||||||
mVirtBounds = getBounds();
|
|
||||||
mOrigBounds = mOuterBitmap.copyBounds();
|
|
||||||
mBoundsBoxBitmap.setAlpha(0);
|
|
||||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
|
||||||
SetInnerBounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void draw(Canvas canvas) {
|
|
||||||
mOuterBitmap.draw(canvas);
|
|
||||||
getCurrentStateBitmapDrawable().draw(canvas);
|
|
||||||
mBoundsBoxBitmap.draw(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean updateStatus(MotionEvent event) {
|
|
||||||
int pointerIndex = event.getActionIndex();
|
|
||||||
int xPosition = (int) event.getX(pointerIndex);
|
|
||||||
int yPosition = (int) event.getY(pointerIndex);
|
|
||||||
int pointerId = event.getPointerId(pointerIndex);
|
|
||||||
int motion_event = event.getAction() & MotionEvent.ACTION_MASK;
|
|
||||||
boolean isActionDown = motion_event == MotionEvent.ACTION_DOWN || motion_event == MotionEvent.ACTION_POINTER_DOWN;
|
|
||||||
boolean isActionUp = motion_event == MotionEvent.ACTION_UP || motion_event == MotionEvent.ACTION_POINTER_UP;
|
|
||||||
|
|
||||||
if (isActionDown) {
|
|
||||||
if (!getBounds().contains(xPosition, yPosition)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
mPressedState = true;
|
|
||||||
mOuterBitmap.setAlpha(0);
|
|
||||||
mBoundsBoxBitmap.setAlpha(255);
|
|
||||||
if (EmulationMenuSettings.getJoystickRelCenter()) {
|
|
||||||
getVirtBounds().offset(xPosition - getVirtBounds().centerX(),
|
|
||||||
yPosition - getVirtBounds().centerY());
|
|
||||||
}
|
|
||||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
|
||||||
mTrackId = pointerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isActionUp) {
|
|
||||||
if (mTrackId != pointerId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
mPressedState = false;
|
|
||||||
mXAxis = 0.0f;
|
|
||||||
mYAxis = 0.0f;
|
|
||||||
mOuterBitmap.setAlpha(255);
|
|
||||||
mBoundsBoxBitmap.setAlpha(0);
|
|
||||||
setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
|
||||||
mOrigBounds.bottom));
|
|
||||||
setBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
|
||||||
mOrigBounds.bottom));
|
|
||||||
SetInnerBounds();
|
|
||||||
mTrackId = -1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mTrackId == -1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = 0; i < event.getPointerCount(); i++) {
|
|
||||||
if (mTrackId != event.getPointerId(i)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
float touchX = event.getX(i);
|
|
||||||
float touchY = event.getY(i);
|
|
||||||
float maxY = getVirtBounds().bottom;
|
|
||||||
float maxX = getVirtBounds().right;
|
|
||||||
touchX -= getVirtBounds().centerX();
|
|
||||||
maxX -= getVirtBounds().centerX();
|
|
||||||
touchY -= getVirtBounds().centerY();
|
|
||||||
maxY -= getVirtBounds().centerY();
|
|
||||||
final float AxisX = touchX / maxX;
|
|
||||||
final float AxisY = touchY / maxY;
|
|
||||||
final float oldXAxis = mXAxis;
|
|
||||||
final float oldYAxis = mYAxis;
|
|
||||||
|
|
||||||
// Clamp the circle pad input to a circle
|
|
||||||
final float angle = (float) Math.atan2(AxisY, AxisX);
|
|
||||||
float radius = (float) Math.sqrt(AxisX * AxisX + AxisY * AxisY);
|
|
||||||
if (radius > 1.0f) {
|
|
||||||
radius = 1.0f;
|
|
||||||
}
|
|
||||||
mXAxis = ((float) Math.cos(angle) * radius);
|
|
||||||
mYAxis = ((float) Math.sin(angle) * radius);
|
|
||||||
SetInnerBounds();
|
|
||||||
return oldXAxis != mXAxis && oldYAxis != mYAxis;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetInnerBounds() {
|
|
||||||
int X = getVirtBounds().centerX() + (int) ((mXAxis) * (getVirtBounds().width() / 2));
|
|
||||||
int Y = getVirtBounds().centerY() + (int) ((mYAxis) * (getVirtBounds().height() / 2));
|
|
||||||
|
|
||||||
if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2))
|
|
||||||
X = getVirtBounds().centerX() + (getVirtBounds().width() / 2);
|
|
||||||
if (X < getVirtBounds().centerX() - (getVirtBounds().width() / 2))
|
|
||||||
X = getVirtBounds().centerX() - (getVirtBounds().width() / 2);
|
|
||||||
if (Y > getVirtBounds().centerY() + (getVirtBounds().height() / 2))
|
|
||||||
Y = getVirtBounds().centerY() + (getVirtBounds().height() / 2);
|
|
||||||
if (Y < getVirtBounds().centerY() - (getVirtBounds().height() / 2))
|
|
||||||
Y = getVirtBounds().centerY() - (getVirtBounds().height() / 2);
|
|
||||||
|
|
||||||
int width = mPressedStateInnerBitmap.getBounds().width() / 2;
|
|
||||||
int height = mPressedStateInnerBitmap.getBounds().height() / 2;
|
|
||||||
mDefaultStateInnerBitmap.setBounds(X - width, Y - height, X + width, Y + height);
|
|
||||||
mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPosition(int x, int y) {
|
|
||||||
mControlPositionX = x;
|
|
||||||
mControlPositionY = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BitmapDrawable getCurrentStateBitmapDrawable() {
|
|
||||||
return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this InputOverlayDrawableJoystick's button ID.
|
|
||||||
*
|
|
||||||
* @return this InputOverlayDrawableJoystick's button ID.
|
|
||||||
*/
|
|
||||||
public int getJoystickId() {
|
|
||||||
return mJoystickId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getXAxis() {
|
|
||||||
return mXAxis;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getYAxis() {
|
|
||||||
// Nintendo joysticks have y axis inverted
|
|
||||||
return -mYAxis;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getButtonId() {
|
|
||||||
return mButtonId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTrackId() {
|
|
||||||
return mTrackId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getButtonStatus() {
|
|
||||||
// TODO: Add button support
|
|
||||||
return NativeLibrary.ButtonState.RELEASED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rect getBounds() {
|
|
||||||
return mOuterBitmap.getBounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBounds(Rect bounds) {
|
|
||||||
mOuterBitmap.setBounds(bounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rect getVirtBounds() {
|
|
||||||
return mVirtBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setVirtBounds(Rect bounds) {
|
|
||||||
mVirtBounds = bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWidth() {
|
|
||||||
return mWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHeight() {
|
|
||||||
return mHeight;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
package org.yuzu.yuzu_emu.overlay
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
|
import org.yuzu.yuzu_emu.utils.EmulationMenuSettings
|
||||||
|
import kotlin.math.atan2
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.sin
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom [BitmapDrawable] that is capable
|
||||||
|
* of storing it's own ID.
|
||||||
|
*
|
||||||
|
* @param res [Resources] instance.
|
||||||
|
* @param bitmapOuter [Bitmap] which represents the outer non-movable part of the joystick.
|
||||||
|
* @param bitmapInnerDefault [Bitmap] which represents the default inner movable part of the joystick.
|
||||||
|
* @param bitmapInnerPressed [Bitmap] which represents the pressed inner movable part of the joystick.
|
||||||
|
* @param rectOuter [Rect] which represents the outer joystick bounds.
|
||||||
|
* @param rectInner [Rect] which represents the inner joystick bounds.
|
||||||
|
* @param joystickId The ID value what type of joystick this Drawable represents.
|
||||||
|
* @param buttonId The ID value what type of button this Drawable represents.
|
||||||
|
*/
|
||||||
|
class InputOverlayDrawableJoystick(
|
||||||
|
res: Resources,
|
||||||
|
bitmapOuter: Bitmap,
|
||||||
|
bitmapInnerDefault: Bitmap,
|
||||||
|
bitmapInnerPressed: Bitmap,
|
||||||
|
rectOuter: Rect,
|
||||||
|
rectInner: Rect,
|
||||||
|
val joystickId: Int,
|
||||||
|
val buttonId: Int
|
||||||
|
) {
|
||||||
|
|
||||||
|
// The ID value what motion event is tracking
|
||||||
|
var trackId = -1
|
||||||
|
var xAxis = 0f
|
||||||
|
private var yAxis = 0f
|
||||||
|
private var controlPositionX = 0
|
||||||
|
private var controlPositionY = 0
|
||||||
|
val width: Int
|
||||||
|
val height: Int
|
||||||
|
private var virtBounds: Rect
|
||||||
|
private val origBounds: Rect
|
||||||
|
private val outerBitmap: BitmapDrawable
|
||||||
|
private val defaultStateInnerBitmap: BitmapDrawable
|
||||||
|
private val pressedStateInnerBitmap: BitmapDrawable
|
||||||
|
private val boundsBoxBitmap: BitmapDrawable
|
||||||
|
private var pressedState = false
|
||||||
|
|
||||||
|
// TODO: Add button support
|
||||||
|
val buttonStatus: Int
|
||||||
|
get() =
|
||||||
|
NativeLibrary.ButtonState.RELEASED
|
||||||
|
var bounds: Rect?
|
||||||
|
get() = outerBitmap.bounds
|
||||||
|
set(bounds) {
|
||||||
|
outerBitmap.bounds = bounds!!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nintendo joysticks have y axis inverted
|
||||||
|
val realYAxis: Float
|
||||||
|
get() = -yAxis
|
||||||
|
|
||||||
|
private val currentStateBitmapDrawable: BitmapDrawable
|
||||||
|
get() = if (pressedState) pressedStateInnerBitmap else defaultStateInnerBitmap
|
||||||
|
|
||||||
|
init {
|
||||||
|
outerBitmap = BitmapDrawable(res, bitmapOuter)
|
||||||
|
defaultStateInnerBitmap = BitmapDrawable(res, bitmapInnerDefault)
|
||||||
|
pressedStateInnerBitmap = BitmapDrawable(res, bitmapInnerPressed)
|
||||||
|
boundsBoxBitmap = BitmapDrawable(res, bitmapOuter)
|
||||||
|
width = bitmapOuter.width
|
||||||
|
height = bitmapOuter.height
|
||||||
|
bounds = rectOuter
|
||||||
|
defaultStateInnerBitmap.bounds = rectInner
|
||||||
|
pressedStateInnerBitmap.bounds = rectInner
|
||||||
|
virtBounds = bounds!!
|
||||||
|
origBounds = outerBitmap.copyBounds()
|
||||||
|
boundsBoxBitmap.alpha = 0
|
||||||
|
boundsBoxBitmap.bounds = virtBounds
|
||||||
|
setInnerBounds()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun draw(canvas: Canvas?) {
|
||||||
|
outerBitmap.draw(canvas!!)
|
||||||
|
currentStateBitmapDrawable.draw(canvas)
|
||||||
|
boundsBoxBitmap.draw(canvas)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateStatus(event: MotionEvent): Boolean {
|
||||||
|
val pointerIndex = event.actionIndex
|
||||||
|
val xPosition = event.getX(pointerIndex).toInt()
|
||||||
|
val yPosition = event.getY(pointerIndex).toInt()
|
||||||
|
val pointerId = event.getPointerId(pointerIndex)
|
||||||
|
val motionEvent = event.action and MotionEvent.ACTION_MASK
|
||||||
|
val isActionDown =
|
||||||
|
motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN
|
||||||
|
val isActionUp =
|
||||||
|
motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP
|
||||||
|
if (isActionDown) {
|
||||||
|
if (!bounds!!.contains(xPosition, yPosition)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
pressedState = true
|
||||||
|
outerBitmap.alpha = 0
|
||||||
|
boundsBoxBitmap.alpha = 255
|
||||||
|
if (EmulationMenuSettings.joystickRelCenter) {
|
||||||
|
virtBounds.offset(
|
||||||
|
xPosition - virtBounds.centerX(),
|
||||||
|
yPosition - virtBounds.centerY()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
boundsBoxBitmap.bounds = virtBounds
|
||||||
|
trackId = pointerId
|
||||||
|
}
|
||||||
|
if (isActionUp) {
|
||||||
|
if (trackId != pointerId) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
pressedState = false
|
||||||
|
xAxis = 0.0f
|
||||||
|
yAxis = 0.0f
|
||||||
|
outerBitmap.alpha = 255
|
||||||
|
boundsBoxBitmap.alpha = 0
|
||||||
|
virtBounds = Rect(
|
||||||
|
origBounds.left,
|
||||||
|
origBounds.top,
|
||||||
|
origBounds.right,
|
||||||
|
origBounds.bottom
|
||||||
|
)
|
||||||
|
bounds = Rect(
|
||||||
|
origBounds.left,
|
||||||
|
origBounds.top,
|
||||||
|
origBounds.right,
|
||||||
|
origBounds.bottom
|
||||||
|
)
|
||||||
|
setInnerBounds()
|
||||||
|
trackId = -1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (trackId == -1) return false
|
||||||
|
for (i in 0 until event.pointerCount) {
|
||||||
|
if (trackId != event.getPointerId(i)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var touchX = event.getX(i)
|
||||||
|
var touchY = event.getY(i)
|
||||||
|
var maxY = virtBounds.bottom.toFloat()
|
||||||
|
var maxX = virtBounds.right.toFloat()
|
||||||
|
touchX -= virtBounds.centerX().toFloat()
|
||||||
|
maxX -= virtBounds.centerX().toFloat()
|
||||||
|
touchY -= virtBounds.centerY().toFloat()
|
||||||
|
maxY -= virtBounds.centerY().toFloat()
|
||||||
|
val axisX = touchX / maxX
|
||||||
|
val axisY = touchY / maxY
|
||||||
|
val oldXAxis = xAxis
|
||||||
|
val oldYAxis = yAxis
|
||||||
|
|
||||||
|
// Clamp the circle pad input to a circle
|
||||||
|
val angle = atan2(axisY.toDouble(), axisX.toDouble()).toFloat()
|
||||||
|
var radius = sqrt((axisX * axisX + axisY * axisY).toDouble()).toFloat()
|
||||||
|
if (radius > 1.0f) {
|
||||||
|
radius = 1.0f
|
||||||
|
}
|
||||||
|
xAxis = cos(angle.toDouble()).toFloat() * radius
|
||||||
|
yAxis = sin(angle.toDouble()).toFloat() * radius
|
||||||
|
setInnerBounds()
|
||||||
|
return oldXAxis != xAxis && oldYAxis != yAxis
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setInnerBounds() {
|
||||||
|
var x = virtBounds.centerX() + (xAxis * (virtBounds.width() / 2)).toInt()
|
||||||
|
var y = virtBounds.centerY() + (yAxis * (virtBounds.height() / 2)).toInt()
|
||||||
|
if (x > virtBounds.centerX() + virtBounds.width() / 2) x =
|
||||||
|
virtBounds.centerX() + virtBounds.width() / 2
|
||||||
|
if (x < virtBounds.centerX() - virtBounds.width() / 2) x =
|
||||||
|
virtBounds.centerX() - virtBounds.width() / 2
|
||||||
|
if (y > virtBounds.centerY() + virtBounds.height() / 2) y =
|
||||||
|
virtBounds.centerY() + virtBounds.height() / 2
|
||||||
|
if (y < virtBounds.centerY() - virtBounds.height() / 2) y =
|
||||||
|
virtBounds.centerY() - virtBounds.height() / 2
|
||||||
|
val width = pressedStateInnerBitmap.bounds.width() / 2
|
||||||
|
val height = pressedStateInnerBitmap.bounds.height() / 2
|
||||||
|
defaultStateInnerBitmap.setBounds(
|
||||||
|
x - width,
|
||||||
|
y - height,
|
||||||
|
x + width,
|
||||||
|
y + height
|
||||||
|
)
|
||||||
|
pressedStateInnerBitmap.bounds = defaultStateInnerBitmap.bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPosition(x: Int, y: Int) {
|
||||||
|
controlPositionX = x
|
||||||
|
controlPositionY = y
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue