summaryrefslogtreecommitdiff
path: root/src/android/app
diff options
context:
space:
mode:
authorGravatar Charles Lombardo2023-03-11 00:34:09 -0500
committerGravatar bunnei2023-06-03 00:05:39 -0700
commit42b3e72e9608584d873b78defc63bc61218efd5b (patch)
tree218d6115fc1e814676b5761520d75300cc290a3a /src/android/app
parentandroid: Convert MainActivity to Kotlin (diff)
downloadyuzu-42b3e72e9608584d873b78defc63bc61218efd5b.tar.gz
yuzu-42b3e72e9608584d873b78defc63bc61218efd5b.tar.xz
yuzu-42b3e72e9608584d873b78defc63bc61218efd5b.zip
android: Convert InputOverlayDrawableJoystick to Kotlin
Diffstat (limited to 'src/android/app')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.java243
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt205
2 files changed, 205 insertions, 243 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.java
deleted file mode 100644
index f7919e483..000000000
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.java
+++ /dev/null
@@ -1,243 +0,0 @@
1/**
2 * Copyright 2013 Dolphin Emulator Project
3 * Licensed under GPLv2+
4 * Refer to the license.txt file included.
5 */
6
7package org.yuzu.yuzu_emu.overlay;
8
9import android.content.res.Resources;
10import android.graphics.Bitmap;
11import android.graphics.Canvas;
12import android.graphics.Rect;
13import android.graphics.drawable.BitmapDrawable;
14import android.view.MotionEvent;
15
16import org.yuzu.yuzu_emu.NativeLibrary;
17import org.yuzu.yuzu_emu.NativeLibrary.ButtonType;
18import org.yuzu.yuzu_emu.utils.EmulationMenuSettings;
19
20/**
21 * Custom {@link BitmapDrawable} that is capable
22 * of storing it's own ID.
23 */
24public final class InputOverlayDrawableJoystick {
25 // The ID value what type of joystick this Drawable represents.
26 private int mJoystickId;
27 // The ID value what type of button this Drawable represents.
28 private int mButtonId;
29 // The ID value what motion event is tracking
30 private int mTrackId = -1;
31 private float mXAxis;
32 private float mYAxis;
33 private int mControlPositionX, mControlPositionY;
34 private int mWidth;
35 private int mHeight;
36 private Rect mVirtBounds;
37 private Rect mOrigBounds;
38 private BitmapDrawable mOuterBitmap;
39 private BitmapDrawable mDefaultStateInnerBitmap;
40 private BitmapDrawable mPressedStateInnerBitmap;
41 private BitmapDrawable mBoundsBoxBitmap;
42 private boolean mPressedState = false;
43
44 /**
45 * Constructor
46 *
47 * @param res {@link Resources} instance.
48 * @param bitmapOuter {@link Bitmap} which represents the outer non-movable part of the joystick.
49 * @param bitmapInnerDefault {@link Bitmap} which represents the default inner movable part of the joystick.
50 * @param bitmapInnerPressed {@link Bitmap} which represents the pressed inner movable part of the joystick.
51 * @param rectOuter {@link Rect} which represents the outer joystick bounds.
52 * @param rectInner {@link Rect} which represents the inner joystick bounds.
53 * @param joystick Identifier for which joystick this is.
54 */
55 public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter,
56 Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed,
57 Rect rectOuter, Rect rectInner, int joystick, int button) {
58 mJoystickId = joystick;
59 mButtonId = button;
60
61 mOuterBitmap = new BitmapDrawable(res, bitmapOuter);
62 mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault);
63 mPressedStateInnerBitmap = new BitmapDrawable(res, bitmapInnerPressed);
64 mBoundsBoxBitmap = new BitmapDrawable(res, bitmapOuter);
65 mWidth = bitmapOuter.getWidth();
66 mHeight = bitmapOuter.getHeight();
67
68 setBounds(rectOuter);
69 mDefaultStateInnerBitmap.setBounds(rectInner);
70 mPressedStateInnerBitmap.setBounds(rectInner);
71 mVirtBounds = getBounds();
72 mOrigBounds = mOuterBitmap.copyBounds();
73 mBoundsBoxBitmap.setAlpha(0);
74 mBoundsBoxBitmap.setBounds(getVirtBounds());
75 SetInnerBounds();
76 }
77
78 public void draw(Canvas canvas) {
79 mOuterBitmap.draw(canvas);
80 getCurrentStateBitmapDrawable().draw(canvas);
81 mBoundsBoxBitmap.draw(canvas);
82 }
83
84 public boolean updateStatus(MotionEvent event) {
85 int pointerIndex = event.getActionIndex();
86 int xPosition = (int) event.getX(pointerIndex);
87 int yPosition = (int) event.getY(pointerIndex);
88 int pointerId = event.getPointerId(pointerIndex);
89 int motion_event = event.getAction() & MotionEvent.ACTION_MASK;
90 boolean isActionDown = motion_event == MotionEvent.ACTION_DOWN || motion_event == MotionEvent.ACTION_POINTER_DOWN;
91 boolean isActionUp = motion_event == MotionEvent.ACTION_UP || motion_event == MotionEvent.ACTION_POINTER_UP;
92
93 if (isActionDown) {
94 if (!getBounds().contains(xPosition, yPosition)) {
95 return false;
96 }
97 mPressedState = true;
98 mOuterBitmap.setAlpha(0);
99 mBoundsBoxBitmap.setAlpha(255);
100 if (EmulationMenuSettings.getJoystickRelCenter()) {
101 getVirtBounds().offset(xPosition - getVirtBounds().centerX(),
102 yPosition - getVirtBounds().centerY());
103 }
104 mBoundsBoxBitmap.setBounds(getVirtBounds());
105 mTrackId = pointerId;
106 }
107
108 if (isActionUp) {
109 if (mTrackId != pointerId) {
110 return false;
111 }
112 mPressedState = false;
113 mXAxis = 0.0f;
114 mYAxis = 0.0f;
115 mOuterBitmap.setAlpha(255);
116 mBoundsBoxBitmap.setAlpha(0);
117 setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
118 mOrigBounds.bottom));
119 setBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
120 mOrigBounds.bottom));
121 SetInnerBounds();
122 mTrackId = -1;
123 return true;
124 }
125
126 if (mTrackId == -1)
127 return false;
128
129 for (int i = 0; i < event.getPointerCount(); i++) {
130 if (mTrackId != event.getPointerId(i)) {
131 continue;
132 }
133 float touchX = event.getX(i);
134 float touchY = event.getY(i);
135 float maxY = getVirtBounds().bottom;
136 float maxX = getVirtBounds().right;
137 touchX -= getVirtBounds().centerX();
138 maxX -= getVirtBounds().centerX();
139 touchY -= getVirtBounds().centerY();
140 maxY -= getVirtBounds().centerY();
141 final float AxisX = touchX / maxX;
142 final float AxisY = touchY / maxY;
143 final float oldXAxis = mXAxis;
144 final float oldYAxis = mYAxis;
145
146 // Clamp the circle pad input to a circle
147 final float angle = (float) Math.atan2(AxisY, AxisX);
148 float radius = (float) Math.sqrt(AxisX * AxisX + AxisY * AxisY);
149 if (radius > 1.0f) {
150 radius = 1.0f;
151 }
152 mXAxis = ((float) Math.cos(angle) * radius);
153 mYAxis = ((float) Math.sin(angle) * radius);
154 SetInnerBounds();
155 return oldXAxis != mXAxis && oldYAxis != mYAxis;
156 }
157
158 return false;
159 }
160
161 private void SetInnerBounds() {
162 int X = getVirtBounds().centerX() + (int) ((mXAxis) * (getVirtBounds().width() / 2));
163 int Y = getVirtBounds().centerY() + (int) ((mYAxis) * (getVirtBounds().height() / 2));
164
165 if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2))
166 X = getVirtBounds().centerX() + (getVirtBounds().width() / 2);
167 if (X < getVirtBounds().centerX() - (getVirtBounds().width() / 2))
168 X = getVirtBounds().centerX() - (getVirtBounds().width() / 2);
169 if (Y > getVirtBounds().centerY() + (getVirtBounds().height() / 2))
170 Y = getVirtBounds().centerY() + (getVirtBounds().height() / 2);
171 if (Y < getVirtBounds().centerY() - (getVirtBounds().height() / 2))
172 Y = getVirtBounds().centerY() - (getVirtBounds().height() / 2);
173
174 int width = mPressedStateInnerBitmap.getBounds().width() / 2;
175 int height = mPressedStateInnerBitmap.getBounds().height() / 2;
176 mDefaultStateInnerBitmap.setBounds(X - width, Y - height, X + width, Y + height);
177 mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds());
178 }
179
180 public void setPosition(int x, int y) {
181 mControlPositionX = x;
182 mControlPositionY = y;
183 }
184
185 private BitmapDrawable getCurrentStateBitmapDrawable() {
186 return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap;
187 }
188
189 /**
190 * Gets this InputOverlayDrawableJoystick's button ID.
191 *
192 * @return this InputOverlayDrawableJoystick's button ID.
193 */
194 public int getJoystickId() {
195 return mJoystickId;
196 }
197
198 public float getXAxis() {
199 return mXAxis;
200 }
201
202 public float getYAxis() {
203 // Nintendo joysticks have y axis inverted
204 return -mYAxis;
205 }
206
207 public int getButtonId() {
208 return mButtonId;
209 }
210
211 public int getTrackId() {
212 return mTrackId;
213 }
214
215 public int getButtonStatus() {
216 // TODO: Add button support
217 return NativeLibrary.ButtonState.RELEASED;
218 }
219
220 public Rect getBounds() {
221 return mOuterBitmap.getBounds();
222 }
223
224 public void setBounds(Rect bounds) {
225 mOuterBitmap.setBounds(bounds);
226 }
227
228 private Rect getVirtBounds() {
229 return mVirtBounds;
230 }
231
232 private void setVirtBounds(Rect bounds) {
233 mVirtBounds = bounds;
234 }
235
236 public int getWidth() {
237 return mWidth;
238 }
239
240 public int getHeight() {
241 return mHeight;
242 }
243}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
new file mode 100644
index 000000000..84a3ea40b
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
@@ -0,0 +1,205 @@
1package org.yuzu.yuzu_emu.overlay
2
3import android.content.res.Resources
4import android.graphics.Bitmap
5import android.graphics.Canvas
6import android.graphics.Rect
7import android.graphics.drawable.BitmapDrawable
8import android.view.MotionEvent
9import org.yuzu.yuzu_emu.NativeLibrary
10import org.yuzu.yuzu_emu.utils.EmulationMenuSettings
11import kotlin.math.atan2
12import kotlin.math.cos
13import kotlin.math.sin
14import kotlin.math.sqrt
15
16/**
17 * Custom [BitmapDrawable] that is capable
18 * of storing it's own ID.
19 *
20 * @param res [Resources] instance.
21 * @param bitmapOuter [Bitmap] which represents the outer non-movable part of the joystick.
22 * @param bitmapInnerDefault [Bitmap] which represents the default inner movable part of the joystick.
23 * @param bitmapInnerPressed [Bitmap] which represents the pressed inner movable part of the joystick.
24 * @param rectOuter [Rect] which represents the outer joystick bounds.
25 * @param rectInner [Rect] which represents the inner joystick bounds.
26 * @param joystickId The ID value what type of joystick this Drawable represents.
27 * @param buttonId The ID value what type of button this Drawable represents.
28 */
29class InputOverlayDrawableJoystick(
30 res: Resources,
31 bitmapOuter: Bitmap,
32 bitmapInnerDefault: Bitmap,
33 bitmapInnerPressed: Bitmap,
34 rectOuter: Rect,
35 rectInner: Rect,
36 val joystickId: Int,
37 val buttonId: Int
38) {
39
40 // The ID value what motion event is tracking
41 var trackId = -1
42 var xAxis = 0f
43 private var yAxis = 0f
44 private var controlPositionX = 0
45 private var controlPositionY = 0
46 val width: Int
47 val height: Int
48 private var virtBounds: Rect
49 private val origBounds: Rect
50 private val outerBitmap: BitmapDrawable
51 private val defaultStateInnerBitmap: BitmapDrawable
52 private val pressedStateInnerBitmap: BitmapDrawable
53 private val boundsBoxBitmap: BitmapDrawable
54 private var pressedState = false
55
56 // TODO: Add button support
57 val buttonStatus: Int
58 get() =
59 NativeLibrary.ButtonState.RELEASED
60 var bounds: Rect?
61 get() = outerBitmap.bounds
62 set(bounds) {
63 outerBitmap.bounds = bounds!!
64 }
65
66 // Nintendo joysticks have y axis inverted
67 val realYAxis: Float
68 get() = -yAxis
69
70 private val currentStateBitmapDrawable: BitmapDrawable
71 get() = if (pressedState) pressedStateInnerBitmap else defaultStateInnerBitmap
72
73 init {
74 outerBitmap = BitmapDrawable(res, bitmapOuter)
75 defaultStateInnerBitmap = BitmapDrawable(res, bitmapInnerDefault)
76 pressedStateInnerBitmap = BitmapDrawable(res, bitmapInnerPressed)
77 boundsBoxBitmap = BitmapDrawable(res, bitmapOuter)
78 width = bitmapOuter.width
79 height = bitmapOuter.height
80 bounds = rectOuter
81 defaultStateInnerBitmap.bounds = rectInner
82 pressedStateInnerBitmap.bounds = rectInner
83 virtBounds = bounds!!
84 origBounds = outerBitmap.copyBounds()
85 boundsBoxBitmap.alpha = 0
86 boundsBoxBitmap.bounds = virtBounds
87 setInnerBounds()
88 }
89
90 fun draw(canvas: Canvas?) {
91 outerBitmap.draw(canvas!!)
92 currentStateBitmapDrawable.draw(canvas)
93 boundsBoxBitmap.draw(canvas)
94 }
95
96 fun updateStatus(event: MotionEvent): Boolean {
97 val pointerIndex = event.actionIndex
98 val xPosition = event.getX(pointerIndex).toInt()
99 val yPosition = event.getY(pointerIndex).toInt()
100 val pointerId = event.getPointerId(pointerIndex)
101 val motionEvent = event.action and MotionEvent.ACTION_MASK
102 val isActionDown =
103 motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN
104 val isActionUp =
105 motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP
106 if (isActionDown) {
107 if (!bounds!!.contains(xPosition, yPosition)) {
108 return false
109 }
110 pressedState = true
111 outerBitmap.alpha = 0
112 boundsBoxBitmap.alpha = 255
113 if (EmulationMenuSettings.joystickRelCenter) {
114 virtBounds.offset(
115 xPosition - virtBounds.centerX(),
116 yPosition - virtBounds.centerY()
117 )
118 }
119 boundsBoxBitmap.bounds = virtBounds
120 trackId = pointerId
121 }
122 if (isActionUp) {
123 if (trackId != pointerId) {
124 return false
125 }
126 pressedState = false
127 xAxis = 0.0f
128 yAxis = 0.0f
129 outerBitmap.alpha = 255
130 boundsBoxBitmap.alpha = 0
131 virtBounds = Rect(
132 origBounds.left,
133 origBounds.top,
134 origBounds.right,
135 origBounds.bottom
136 )
137 bounds = Rect(
138 origBounds.left,
139 origBounds.top,
140 origBounds.right,
141 origBounds.bottom
142 )
143 setInnerBounds()
144 trackId = -1
145 return true
146 }
147 if (trackId == -1) return false
148 for (i in 0 until event.pointerCount) {
149 if (trackId != event.getPointerId(i)) {
150 continue
151 }
152 var touchX = event.getX(i)
153 var touchY = event.getY(i)
154 var maxY = virtBounds.bottom.toFloat()
155 var maxX = virtBounds.right.toFloat()
156 touchX -= virtBounds.centerX().toFloat()
157 maxX -= virtBounds.centerX().toFloat()
158 touchY -= virtBounds.centerY().toFloat()
159 maxY -= virtBounds.centerY().toFloat()
160 val axisX = touchX / maxX
161 val axisY = touchY / maxY
162 val oldXAxis = xAxis
163 val oldYAxis = yAxis
164
165 // Clamp the circle pad input to a circle
166 val angle = atan2(axisY.toDouble(), axisX.toDouble()).toFloat()
167 var radius = sqrt((axisX * axisX + axisY * axisY).toDouble()).toFloat()
168 if (radius > 1.0f) {
169 radius = 1.0f
170 }
171 xAxis = cos(angle.toDouble()).toFloat() * radius
172 yAxis = sin(angle.toDouble()).toFloat() * radius
173 setInnerBounds()
174 return oldXAxis != xAxis && oldYAxis != yAxis
175 }
176 return false
177 }
178
179 private fun setInnerBounds() {
180 var x = virtBounds.centerX() + (xAxis * (virtBounds.width() / 2)).toInt()
181 var y = virtBounds.centerY() + (yAxis * (virtBounds.height() / 2)).toInt()
182 if (x > virtBounds.centerX() + virtBounds.width() / 2) x =
183 virtBounds.centerX() + virtBounds.width() / 2
184 if (x < virtBounds.centerX() - virtBounds.width() / 2) x =
185 virtBounds.centerX() - virtBounds.width() / 2
186 if (y > virtBounds.centerY() + virtBounds.height() / 2) y =
187 virtBounds.centerY() + virtBounds.height() / 2
188 if (y < virtBounds.centerY() - virtBounds.height() / 2) y =
189 virtBounds.centerY() - virtBounds.height() / 2
190 val width = pressedStateInnerBitmap.bounds.width() / 2
191 val height = pressedStateInnerBitmap.bounds.height() / 2
192 defaultStateInnerBitmap.setBounds(
193 x - width,
194 y - height,
195 x + width,
196 y + height
197 )
198 pressedStateInnerBitmap.bounds = defaultStateInnerBitmap.bounds
199 }
200
201 fun setPosition(x: Int, y: Int) {
202 controlPositionX = x
203 controlPositionY = y
204 }
205}