Более менее стабильная версия
This commit is contained in:
Generated
+8
@@ -4,6 +4,14 @@
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2025-08-28T09:42:35.298333191Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="Default" identifier="serial=192.168.240.112:5555;connection=1b67fee5" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
|
||||
Generated
+2
-1
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<uses-configuration android:reqTouchScreen="finger"/>
|
||||
<application
|
||||
android:theme="@style/Theme.AppCompat.Light"
|
||||
android:theme="@style/Theme.AppCompat.NoActionBar"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/adaptive_icon"
|
||||
android:screenOrientation="userLandscape"
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
package com.ea.EAIO;
|
||||
package com.ea.EAIO
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Environment;
|
||||
import android.app.Activity
|
||||
import android.content.res.AssetManager
|
||||
import android.os.Environment
|
||||
|
||||
object EAIO {
|
||||
@JvmStatic
|
||||
external fun Shutdown()
|
||||
|
||||
public class EAIO {
|
||||
public static native void Shutdown();
|
||||
private external fun StartupNativeImpl(
|
||||
assetManager: AssetManager?,
|
||||
dataPath: String?,
|
||||
filesDirPath: String?,
|
||||
externalPath: String?
|
||||
)
|
||||
|
||||
private static native void StartupNativeImpl(AssetManager assetManager, String str, String str2, String str3);
|
||||
|
||||
public static void Startup(Activity activity) {
|
||||
StartupNativeImpl(activity.getAssets(), Environment.getDataDirectory().getAbsolutePath(), activity.getFilesDir().getAbsolutePath(), Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||
}
|
||||
@JvmStatic
|
||||
fun Startup(activity: Activity) = StartupNativeImpl(
|
||||
activity.assets,
|
||||
Environment.getDataDirectory().absolutePath,
|
||||
activity.filesDir.absolutePath,
|
||||
Environment.getExternalStorageDirectory().absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,42 +1,52 @@
|
||||
package com.ea.EAMIO;
|
||||
package com.ea.EAMIO
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Environment;
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.os.Environment
|
||||
|
||||
//На методы есть ссылка из нативного кода но они не вызываются и не несут полезной нагрузки
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
object StorageDirectory {
|
||||
@JvmStatic
|
||||
var sActivity: Activity? = null
|
||||
|
||||
public class StorageDirectory {
|
||||
public static Activity sActivity;
|
||||
private external fun ShutdownNativeImpl()
|
||||
|
||||
private static native void ShutdownNativeImpl();
|
||||
private external fun StartupNativeImpl()
|
||||
|
||||
private static native void StartupNativeImpl();
|
||||
|
||||
public static void Startup(Activity activity) {
|
||||
sActivity = activity;
|
||||
StartupNativeImpl();
|
||||
@JvmStatic
|
||||
fun Startup(activity: Activity) {
|
||||
sActivity = activity
|
||||
StartupNativeImpl()
|
||||
}
|
||||
|
||||
public static void Shutdown() {
|
||||
ShutdownNativeImpl();
|
||||
@JvmStatic
|
||||
fun Shutdown() {
|
||||
ShutdownNativeImpl()
|
||||
}
|
||||
|
||||
public static String GetInternalStorageDirectory() {
|
||||
return sActivity.getFilesDir().getAbsolutePath();
|
||||
@JvmStatic
|
||||
fun GetInternalStorageDirectory(): String {
|
||||
return sActivity?.filesDir?.absolutePath ?: ""
|
||||
}
|
||||
|
||||
public static String GetPrimaryExternalStorageDirectory() {
|
||||
return sActivity.getExternalFilesDir(null).getAbsolutePath();
|
||||
@JvmStatic
|
||||
fun GetPrimaryExternalStorageDirectory(): String {
|
||||
return sActivity?.getExternalFilesDir(null)?.absolutePath ?: ""
|
||||
}
|
||||
|
||||
public static String GetPrimaryExternalStorageDirectoryRoot() {
|
||||
return Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
@JvmStatic
|
||||
fun GetPrimaryExternalStorageDirectoryRoot(): String {
|
||||
return Environment.getExternalStorageDirectory().absolutePath
|
||||
}
|
||||
|
||||
public static int GetPrimaryExternalStorageState() {
|
||||
String externalStorageState = Environment.getExternalStorageState();
|
||||
if ("mounted".equals(externalStorageState)) {
|
||||
return 2;
|
||||
@JvmStatic
|
||||
fun GetPrimaryExternalStorageState(): Int {
|
||||
val externalStorageState = Environment.getExternalStorageState()
|
||||
return when {
|
||||
Environment.MEDIA_MOUNTED == externalStorageState -> 2
|
||||
Environment.MEDIA_MOUNTED_READ_ONLY == externalStorageState -> 1
|
||||
else -> 0
|
||||
}
|
||||
return "mounted_ro".equals(externalStorageState) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +1,58 @@
|
||||
package com.ea.ironmonkey;
|
||||
package com.ea.ironmonkey
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Typeface;
|
||||
import android.util.Log;
|
||||
import android.content.res.AssetManager
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.Typeface
|
||||
import androidx.core.graphics.createBitmap
|
||||
import com.ea.ironmonkey.GameActivityMain.Companion.mAssetLocationType
|
||||
import com.ea.ironmonkey.domain.AssetLocationType
|
||||
|
||||
import nfs.mod.mpcore.MultiplayerCore;
|
||||
class BitmapGraphics(width: Int, height: Int) {
|
||||
val bitmap = createBitmap(width, height)
|
||||
val canvas = Canvas()
|
||||
|
||||
|
||||
public class BitmapGraphics {
|
||||
private Bitmap bitmap;
|
||||
private Canvas canvas = new Canvas();
|
||||
|
||||
public BitmapGraphics(int i, int i2) {
|
||||
this.bitmap = Bitmap.createBitmap(i, i2, Bitmap.Config.ARGB_8888);
|
||||
this.canvas.setBitmap(this.bitmap);
|
||||
init {
|
||||
canvas.setBitmap(bitmap)
|
||||
}
|
||||
|
||||
public Bitmap getBitmap() {
|
||||
return this.bitmap;
|
||||
fun clear() {
|
||||
canvas.drawColor(0, PorterDuff.Mode.CLEAR)
|
||||
}
|
||||
|
||||
public Canvas getCanvas() {
|
||||
return this.canvas;
|
||||
}
|
||||
fun drawString(paint: Paint, text: String, x: Int, y: Int) = canvas.drawText(text, x.toFloat(), y.toFloat(), paint)
|
||||
|
||||
public void clear() {
|
||||
this.canvas.drawColor(0, PorterDuff.Mode.CLEAR);
|
||||
}
|
||||
companion object {
|
||||
private fun createPaint(typeface: Typeface?, f: Float): Paint {
|
||||
val paint = Paint()
|
||||
paint.setTypeface(typeface)
|
||||
paint.textSize = f
|
||||
paint.setColor(-1)
|
||||
paint.isAntiAlias = true
|
||||
return paint
|
||||
}
|
||||
|
||||
private static Paint createPaint(Typeface typeface, float f) {
|
||||
Paint paint = new Paint();
|
||||
paint.setTypeface(typeface);
|
||||
paint.setTextSize(f);
|
||||
paint.setColor(-1);
|
||||
paint.setAntiAlias(true);
|
||||
return paint;
|
||||
}
|
||||
@JvmStatic
|
||||
fun createPaintFromFamilyName(familyName: String, f: Float): Paint {
|
||||
return createPaint(Typeface.create(familyName, Typeface.NORMAL), f)
|
||||
}
|
||||
|
||||
public static Paint createPaintFromFamilyName(String str, float f) {
|
||||
return createPaint(Typeface.create(str, 0), f);
|
||||
}
|
||||
@JvmStatic
|
||||
fun createPaintFromFile(str: String, f: Float): Paint {
|
||||
return createPaint(internalCreateFromFile(str), f)
|
||||
}
|
||||
|
||||
public static Paint createPaintFromFile(String str, float f) {
|
||||
return createPaint(internalCreateFromFile(str), f);
|
||||
}
|
||||
|
||||
private static Typeface internalCreateFromFile(String str) {
|
||||
if (GameActivityMain.instance.useAssetsFileSystem()) {
|
||||
private fun internalCreateFromFile(str: String): Typeface? {
|
||||
var str = str
|
||||
/*if (mAssetLocationType != AssetLocationType.EXTERNAL) {
|
||||
return Typeface.createFromFile(str);
|
||||
}*/
|
||||
if (str.startsWith("/")) {
|
||||
str = str.substring(1);
|
||||
}
|
||||
return Typeface.createFromAsset(GameActivityMain.instance.getAssetManager(), str);
|
||||
}
|
||||
return Typeface.createFromFile(str);
|
||||
}
|
||||
return Typeface.createFromAsset(GameActivityMain.assetManager, str);
|
||||
|
||||
public void drawString(Paint paint, String str, int x, int y) {
|
||||
this.canvas.drawText(str, x, y, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.ea.ironmonkey;
|
||||
package com.ea.ironmonkey
|
||||
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import javax.microedition.khronos.opengles.GL10
|
||||
|
||||
|
||||
public interface DrawFrameListener {
|
||||
void onDrawFrame(GL10 gl10);
|
||||
interface DrawFrameListener {
|
||||
fun onDrawFrame(gl10: GL10?)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,46 +1,30 @@
|
||||
package com.ea.ironmonkey;
|
||||
package com.ea.ironmonkey
|
||||
|
||||
import android.util.Log
|
||||
|
||||
|
||||
public class Log {
|
||||
private static boolean enable;
|
||||
object Log {
|
||||
private var enable = false
|
||||
|
||||
public static void setEnable(boolean z) {
|
||||
enable = z;
|
||||
fun setEnable(enabled: Boolean) {
|
||||
enable = enabled
|
||||
}
|
||||
|
||||
public static void i(String str, String str2) {
|
||||
if (enable) {
|
||||
android.util.Log.i(str, str2);
|
||||
}
|
||||
}
|
||||
@JvmStatic
|
||||
fun i(tag: String, msg: String) = if (enable) Log.i(tag, msg) else Unit
|
||||
|
||||
public static void e(String str, String str2) {
|
||||
if (enable) {
|
||||
android.util.Log.e(str, str2);
|
||||
}
|
||||
}
|
||||
@JvmStatic
|
||||
fun e(tag: String, msg: String) = if (enable) Log.e(tag, msg) else Unit
|
||||
|
||||
public static void w(String str, String str2) {
|
||||
if (enable) {
|
||||
android.util.Log.w(str, str2);
|
||||
}
|
||||
}
|
||||
@JvmStatic
|
||||
fun w(tag: String, msg: String) = if (enable) Log.w(tag, msg) else Unit
|
||||
|
||||
public static void d(String str, String str2) {
|
||||
if (enable) {
|
||||
android.util.Log.d(str, str2);
|
||||
}
|
||||
}
|
||||
@JvmStatic
|
||||
fun d(tag: String, msg: String) = if (enable) Log.d(tag, msg) else Unit
|
||||
|
||||
public static void v(String str, String str2) {
|
||||
if (enable) {
|
||||
android.util.Log.v(str, str2);
|
||||
}
|
||||
}
|
||||
@JvmStatic
|
||||
fun v(tag: String, msg: String) = if (enable) Log.v(tag, msg) else Unit
|
||||
|
||||
public static void e(String str, String str2, Exception exc) {
|
||||
if (enable) {
|
||||
android.util.Log.e(str, str2, exc);
|
||||
}
|
||||
}
|
||||
@JvmStatic
|
||||
fun e(tag: String, msg: String?, exc: Exception?) = if (enable) Log.e(tag, msg, exc) else Unit
|
||||
}
|
||||
@@ -1,30 +1,117 @@
|
||||
package com.ea.ironmonkey;
|
||||
package com.ea.ironmonkey
|
||||
|
||||
import com.bda.controller.ControllerListener;
|
||||
import com.bda.controller.KeyEvent;
|
||||
import com.bda.controller.MotionEvent;
|
||||
import com.bda.controller.StateEvent;
|
||||
import android.content.Context
|
||||
import android.hardware.input.InputManager
|
||||
import android.util.Log
|
||||
import android.view.InputDevice
|
||||
import androidx.activity.ComponentActivity
|
||||
import com.bda.controller.ControllerListener
|
||||
import com.bda.controller.KeyEvent
|
||||
import com.bda.controller.MotionEvent
|
||||
import com.bda.controller.StateEvent
|
||||
|
||||
object MogaController : ControllerListener {
|
||||
external fun nativeOnKeyEvent(keyEvent: KeyEvent?)
|
||||
|
||||
public class MogaController implements ControllerListener {
|
||||
native void nativeOnKeyEvent(KeyEvent keyEvent);
|
||||
external fun nativeOnMotionEvent(motionEvent: MotionEvent?)
|
||||
|
||||
native void nativeOnMotionEvent(MotionEvent motionEvent);
|
||||
external fun nativeOnStateEvent(stateEvent: StateEvent?)
|
||||
|
||||
native void nativeOnStateEvent(StateEvent stateEvent);
|
||||
|
||||
@Override // com.bda.controller.ControllerListener
|
||||
public void onKeyEvent(KeyEvent keyEvent) {
|
||||
nativeOnKeyEvent(keyEvent);
|
||||
override fun onKeyEvent(keyEvent: KeyEvent?) {
|
||||
nativeOnKeyEvent(keyEvent)
|
||||
}
|
||||
|
||||
@Override // com.bda.controller.ControllerListener
|
||||
public void onMotionEvent(MotionEvent motionEvent) {
|
||||
nativeOnMotionEvent(motionEvent);
|
||||
override fun onMotionEvent(motionEvent: MotionEvent?) {
|
||||
nativeOnMotionEvent(motionEvent)
|
||||
}
|
||||
|
||||
@Override // com.bda.controller.ControllerListener
|
||||
public void onStateEvent(StateEvent stateEvent) {
|
||||
nativeOnStateEvent(stateEvent);
|
||||
override fun onStateEvent(stateEvent: StateEvent?) {
|
||||
nativeOnStateEvent(stateEvent)
|
||||
}
|
||||
|
||||
fun doForAllControllers(
|
||||
action: (Int) -> Unit
|
||||
){
|
||||
val deviceIds = InputDevice.getDeviceIds()
|
||||
|
||||
deviceIds.forEach {
|
||||
if(deviceIsController(it)) action(it)
|
||||
}
|
||||
}
|
||||
|
||||
infix fun Int.isFlag(flag: Int) = this and flag == flag
|
||||
|
||||
fun deviceIsController(deviceId: Int): Boolean {
|
||||
val inputDevice = InputDevice.getDevice(deviceId) ?: return false
|
||||
|
||||
if(inputDevice.id == -1) return false
|
||||
|
||||
return (inputDevice.sources isFlag InputDevice.SOURCE_GAMEPAD) &&
|
||||
(inputDevice.sources isFlag InputDevice.SOURCE_JOYSTICK)
|
||||
}
|
||||
|
||||
fun registerControllerHandlers(
|
||||
context: Context,
|
||||
onInputDeviceAdded: (Int) -> Unit,
|
||||
onInputDeviceRemoved: (Int) -> Unit,
|
||||
onInputDeviceChanged: (Int) -> Unit = {},
|
||||
){
|
||||
|
||||
val inputManager = context.getSystemService(ComponentActivity.INPUT_SERVICE) as InputManager
|
||||
|
||||
inputManager.registerInputDeviceListener(object : InputManager.InputDeviceListener {
|
||||
|
||||
var lastControllerId: Int = 0;
|
||||
|
||||
override fun onInputDeviceAdded(deviceId: Int) {
|
||||
if(deviceIsController(deviceId)) {
|
||||
lastControllerId = deviceId
|
||||
onInputDeviceAdded(deviceId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInputDeviceRemoved(deviceId: Int) {
|
||||
|
||||
if(deviceIsController(deviceId) || lastControllerId == deviceId) onInputDeviceRemoved(deviceId)
|
||||
}
|
||||
|
||||
override fun onInputDeviceChanged(deviceId: Int) {
|
||||
if(deviceIsController(deviceId)) onInputDeviceChanged(deviceId)
|
||||
}
|
||||
}, null)
|
||||
|
||||
}
|
||||
|
||||
fun createDisconnectEvent(deviceId: Int) = StateEvent(
|
||||
System.currentTimeMillis(),
|
||||
deviceId,
|
||||
StateEvent.STATE_UNKNOWN,
|
||||
StateEvent.ACTION_DISCONNECTED
|
||||
)
|
||||
|
||||
fun createConnectEvent(deviceId: Int) = StateEvent(
|
||||
System.currentTimeMillis(),
|
||||
deviceId,
|
||||
StateEvent.STATE_CONNECTION,
|
||||
StateEvent.ACTION_CONNECTED
|
||||
)
|
||||
|
||||
fun androidKeyEventToBda(keyEvent: android.view.KeyEvent) = KeyEvent(
|
||||
keyEvent.eventTime,
|
||||
keyEvent.deviceId,
|
||||
keyEvent.keyCode,
|
||||
keyEvent.action
|
||||
)
|
||||
|
||||
fun androidMotionEventToBda(motionEvent: android.view.MotionEvent) = MotionEvent(
|
||||
motionEvent.eventTime,
|
||||
motionEvent.deviceId,
|
||||
motionEvent.x,
|
||||
motionEvent.y,
|
||||
motionEvent.rawX,
|
||||
motionEvent.rawY,
|
||||
motionEvent.xPrecision,
|
||||
motionEvent.yPrecision
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
package com.ea.ironmonkey;
|
||||
package com.ea.ironmonkey
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Context
|
||||
|
||||
|
||||
class ObbHelper {
|
||||
ObbHelper() {
|
||||
}
|
||||
|
||||
public static String getObbFileName(Context context, int i) {
|
||||
return "main." + i + "." + context.getPackageName() + ".obb";
|
||||
}
|
||||
internal object ObbHelper {
|
||||
@JvmStatic
|
||||
fun getObbFileName(context: Context, versionCode: Int) = "main.$versionCode.${context.packageName}.obb"
|
||||
}
|
||||
|
||||
@@ -1,182 +1,186 @@
|
||||
package com.ea.ironmonkey;
|
||||
package com.ea.ironmonkey
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
class PermissionsActivity : AppCompatActivity() {
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import android.os.Build;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PermissionsActivity extends AppCompatActivity {
|
||||
private static final int SETTINGS_REQUEST_CODE = 100;
|
||||
private final ActivityResultLauncher<String[]> requestPermissionLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
|
||||
if (areAllPermissionsGranted()) {
|
||||
initActivity();
|
||||
} else {
|
||||
handlePermissionsDenied();
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
checkPermissions();
|
||||
companion object {
|
||||
private const val SETTINGS_REQUEST_CODE = 100
|
||||
}
|
||||
|
||||
private void checkPermissions() {
|
||||
private val requestPermissionLauncher: ActivityResultLauncher<Array<String>> =
|
||||
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
|
||||
if (areAllPermissionsGranted()) {
|
||||
initActivity()
|
||||
} else {
|
||||
handlePermissionsDenied()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
checkPermissions()
|
||||
}
|
||||
|
||||
private fun checkPermissions() {
|
||||
if (areAllPermissionsGranted()) {
|
||||
initActivity();
|
||||
initActivity()
|
||||
} else {
|
||||
requestPermissions();
|
||||
requestPermissions()
|
||||
}
|
||||
}
|
||||
|
||||
private boolean areAllPermissionsGranted() {
|
||||
for (String permission : getRequiredPermissions()) {
|
||||
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
return false;
|
||||
}
|
||||
private fun areAllPermissionsGranted(): Boolean {
|
||||
return getRequiredPermissions().all { permission ->
|
||||
ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String[] getRequiredPermissions() {
|
||||
List<String> permissions = new ArrayList<>();
|
||||
private fun getRequiredPermissions(): Array<String> {
|
||||
val permissions = mutableListOf<String>()
|
||||
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
||||
// Android 9 (Pie) и ниже - нужны оба разрешения
|
||||
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
} else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||
// Android 10 (Q) - только чтение
|
||||
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
// Android 13+ - новые раздельные разрешения для медиа
|
||||
//permissions.add(Manifest.permission.READ_MEDIA_IMAGES);
|
||||
//permissions.add(Manifest.permission.READ_MEDIA_VIDEO);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
// Android 14+ - дополнительно для аудио
|
||||
permissions.add(Manifest.permission.READ_MEDIA_AUDIO);
|
||||
when {
|
||||
Build.VERSION.SDK_INT <= Build.VERSION_CODES.P -> {
|
||||
// Android 9 (Pie) и ниже - нужны оба разрешения
|
||||
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
}
|
||||
Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q -> {
|
||||
// Android 10 (Q) - только чтение
|
||||
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
|
||||
// Android 13+ - новые раздельные разрешения для медиа
|
||||
// permissions.add(Manifest.permission.READ_MEDIA_IMAGES)
|
||||
// permissions.add(Manifest.permission.READ_MEDIA_VIDEO)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
// Android 14+ - дополнительно для аудио
|
||||
//permissions.add(Manifest.permission.READ_MEDIA_AUDIO)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// Android 11-12 - только чтение
|
||||
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
} else {
|
||||
// Android 11-12 - только чтение
|
||||
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
}
|
||||
|
||||
permissions.forEach(e -> {
|
||||
Log.i("Permissions", e);
|
||||
});
|
||||
permissions.forEach { permission ->
|
||||
Log.i("Permissions", permission)
|
||||
}
|
||||
|
||||
return permissions.toArray(new String[0]);
|
||||
return permissions.toTypedArray()
|
||||
}
|
||||
|
||||
private void requestPermissions() {
|
||||
String[] permissions = getRequiredPermissions();
|
||||
boolean shouldShowRationale = false;
|
||||
|
||||
for (String permission : permissions) {
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
|
||||
shouldShowRationale = true;
|
||||
break;
|
||||
}
|
||||
private fun requestPermissions() {
|
||||
val permissions = getRequiredPermissions()
|
||||
val shouldShowRationale = permissions.any { permission ->
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(this, permission)
|
||||
}
|
||||
|
||||
if (shouldShowRationale) {
|
||||
showPermissionRationaleDialog();
|
||||
showPermissionRationaleDialog()
|
||||
} else {
|
||||
requestPermissionLauncher.launch(permissions);
|
||||
requestPermissionLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
|
||||
private void showPermissionRationaleDialog() {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Требуются разрешения")
|
||||
.setMessage("Для корректной работы приложения необходимы разрешения на доступ к хранилищу. Пожалуйста, предоставьте запрашиваемые разрешения.")
|
||||
.setPositiveButton("OK", (dialog, which) -> requestPermissionLauncher.launch(getRequiredPermissions()))
|
||||
.setNegativeButton("Отмена", (dialog, which) -> finish())
|
||||
.setCancelable(false)
|
||||
.setOnKeyListener((dialog, keyCode, event) -> {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void handlePermissionsDenied() {
|
||||
if (areSomePermissionsPermanentlyDenied()) {
|
||||
showPermanentlyDeniedDialog();
|
||||
} else {
|
||||
Toast.makeText(this, "Разрешения необходимы для работы приложения", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean areSomePermissionsPermanentlyDenied() {
|
||||
for (String permission : getRequiredPermissions()) {
|
||||
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permission) &&
|
||||
ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
private fun showPermissionRationaleDialog() {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Требуются разрешения")
|
||||
.setMessage("Для корректной работы приложения необходимы разрешения на доступ к хранилищу. Пожалуйста, предоставьте запрашиваемые разрешения.")
|
||||
.setPositiveButton("OK") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
requestPermissionLauncher.launch(getRequiredPermissions())
|
||||
}
|
||||
.setNegativeButton("Отмена") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
finish()
|
||||
}
|
||||
.setCancelable(false)
|
||||
.setOnKeyListener { _, keyCode, event ->
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
finish()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun handlePermissionsDenied() {
|
||||
if (areSomePermissionsPermanentlyDenied()) {
|
||||
showPermanentlyDeniedDialog()
|
||||
} else {
|
||||
Toast.makeText(this, "Разрешения необходимы для работы приложения", Toast.LENGTH_SHORT).show()
|
||||
finish()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void showPermanentlyDeniedDialog() {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Разрешения отклонены")
|
||||
.setMessage("Вы навсегда отклонили некоторые разрешения. Чтобы использовать приложение, предоставьте разрешения в настройках.")
|
||||
.setPositiveButton("Настройки", (dialog, which) -> openAppSettings())
|
||||
.setNegativeButton("Выход", (dialog, which) -> finish())
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
private fun areSomePermissionsPermanentlyDenied(): Boolean {
|
||||
return getRequiredPermissions().any { permission ->
|
||||
!ActivityCompat.shouldShowRequestPermissionRationale(this, permission) &&
|
||||
ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
private void openAppSettings() {
|
||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(Uri.parse("package:" + getPackageName()));
|
||||
startActivityForResult(intent, SETTINGS_REQUEST_CODE);
|
||||
private fun showPermanentlyDeniedDialog() {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Разрешения отклонены")
|
||||
.setMessage("Вы навсегда отклонили некоторые разрешения. Чтобы использовать приложение, предоставьте разрешения в настройках.")
|
||||
.setPositiveButton("Настройки") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
openAppSettings()
|
||||
}
|
||||
.setNegativeButton("Выход") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
finish()
|
||||
}
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
private fun openAppSettings() {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.fromParts("package", packageName, null)
|
||||
}
|
||||
startActivityForResult(intent, SETTINGS_REQUEST_CODE)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == SETTINGS_REQUEST_CODE) {
|
||||
if (areAllPermissionsGranted()) {
|
||||
initActivity();
|
||||
initActivity()
|
||||
} else {
|
||||
handlePermissionsDenied();
|
||||
handlePermissionsDenied()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initActivity() {
|
||||
private fun initActivity() {
|
||||
try {
|
||||
startActivity(new Intent(this, GameActivityMain.class));
|
||||
finish();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "Ошибка запуска приложения", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
startActivity(Intent(this, GameActivityMain::class.java))
|
||||
finish()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(this, "Ошибка запуска приложения", Toast.LENGTH_SHORT).show()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,52 @@
|
||||
package com.ea.ironmonkey;
|
||||
|
||||
import android.opengl.GLSurfaceView;
|
||||
package com.ea.ironmonkey
|
||||
|
||||
|
||||
public class RunLoop {
|
||||
public static final int STATE_RUNNING = 1;
|
||||
public static final int STATE_STOPPED = 0;
|
||||
private GLSurfaceView glSurfaceView;
|
||||
private int state;
|
||||
import android.opengl.GLSurfaceView
|
||||
import android.util.Log
|
||||
|
||||
private native void nativeOnRunLoopTick();
|
||||
class RunLoop(private val glSurfaceView: GLSurfaceView) {
|
||||
|
||||
public RunLoop(GLSurfaceView gLSurfaceView) {
|
||||
this.glSurfaceView = gLSurfaceView;
|
||||
updateRenderMode();
|
||||
companion object {
|
||||
private const val TAG = "RunLoop"
|
||||
private const val STATE_STOPPED = 0
|
||||
private const val STATE_RUNNING = 1
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return this.state;
|
||||
private var state: Int = STATE_STOPPED
|
||||
|
||||
private external fun nativeOnRunLoopTick()
|
||||
|
||||
val currentState: Int
|
||||
get() = state
|
||||
|
||||
fun start() {
|
||||
setState(STATE_RUNNING)
|
||||
}
|
||||
|
||||
public void start() {
|
||||
setState(1);
|
||||
fun stop() {
|
||||
setState(STATE_STOPPED)
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
setState(0);
|
||||
fun join() {
|
||||
setState(STATE_STOPPED)
|
||||
}
|
||||
|
||||
public void join() {
|
||||
setState(0);
|
||||
private fun setState(newState: Int) {
|
||||
state = newState
|
||||
updateRenderMode()
|
||||
}
|
||||
|
||||
private void setState(int i) {
|
||||
this.state = i;
|
||||
updateRenderMode();
|
||||
}
|
||||
|
||||
private void updateRenderMode() {
|
||||
Log.v("RunLoop", "RunLoop.state = " + this.state);
|
||||
switch (this.state) {
|
||||
case 0:
|
||||
this.glSurfaceView.setRenderMode(0);
|
||||
break;
|
||||
case 1:
|
||||
this.glSurfaceView.setRenderMode(1);
|
||||
break;
|
||||
private fun updateRenderMode() {
|
||||
Log.v(TAG, "RunLoop.state = $state")
|
||||
when (state) {
|
||||
STATE_STOPPED -> glSurfaceView.renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
|
||||
STATE_RUNNING -> glSurfaceView.renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY
|
||||
}
|
||||
}
|
||||
|
||||
public void onRunLoopTick() {
|
||||
if (this.state == 1) {
|
||||
nativeOnRunLoopTick();
|
||||
fun onRunLoopTick() {
|
||||
if (state == STATE_RUNNING) {
|
||||
nativeOnRunLoopTick()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,255 +1,258 @@
|
||||
package com.ea.ironmonkey;
|
||||
package com.ea.ironmonkey
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLUtils;
|
||||
import android.app.Activity
|
||||
import android.graphics.BitmapFactory
|
||||
import android.opengl.GLES20
|
||||
import android.opengl.GLUtils
|
||||
import android.util.Log
|
||||
import java.io.IOException
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.FloatBuffer
|
||||
import javax.microedition.khronos.opengles.GL10
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
class SplashScreen(private val activity: Activity) {
|
||||
|
||||
|
||||
public class SplashScreen {
|
||||
private static final String TAG = "SplashScreen";
|
||||
private Activity _activity;
|
||||
private int _attPosition;
|
||||
private int _attSampler;
|
||||
private int _attTexCoord;
|
||||
private int _fragmentShader;
|
||||
private int _program;
|
||||
private int _vertexShader;
|
||||
private FloatBuffer vBuffer;
|
||||
|
||||
// Вершинный шейдер
|
||||
private final String vShaderStr =
|
||||
"attribute vec4 a_position; \n" +
|
||||
"attribute vec2 a_texCoord; \n" +
|
||||
"varying vec2 v_texCoord; \n" +
|
||||
"void main() { \n" +
|
||||
" gl_Position = a_position; \n" +
|
||||
" v_texCoord = a_texCoord; \n" +
|
||||
"} \n";
|
||||
|
||||
// Фрагментный шейдер
|
||||
private final String fShaderStr =
|
||||
"precision mediump float; \n" +
|
||||
"varying vec2 v_texCoord; \n" +
|
||||
"uniform sampler2D s_texture; \n" +
|
||||
"void main() { \n" +
|
||||
" gl_FragColor = texture2D(s_texture, v_texCoord); \n" +
|
||||
"} \n";
|
||||
|
||||
private int[] _textureId = new int[1];
|
||||
|
||||
public SplashScreen(Activity activity) {
|
||||
this._activity = activity;
|
||||
companion object {
|
||||
private const val TAG = "SplashScreen"
|
||||
}
|
||||
|
||||
public void init(GL10 gl10, int width, int height) {
|
||||
// Вершинный шейдер
|
||||
private val vertexShaderStr = """
|
||||
attribute vec4 a_position;
|
||||
attribute vec2 a_texCoord;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
gl_Position = a_position;
|
||||
v_texCoord = a_texCoord;
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
// Фрагментный шейдер
|
||||
private val fragmentShaderStr = """
|
||||
precision mediump float;
|
||||
varying vec2 v_texCoord;
|
||||
uniform sampler2D s_texture;
|
||||
void main() {
|
||||
gl_FragColor = texture2D(s_texture, v_texCoord);
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
private var attPosition = 0
|
||||
private var attSampler = 0
|
||||
private var attTexCoord = 0
|
||||
private var fragmentShader = 0
|
||||
private var program = 0
|
||||
private var vertexShader = 0
|
||||
private var vBuffer: FloatBuffer? = null
|
||||
private var textureId = IntArray(1)
|
||||
|
||||
fun init(gl10: GL10?, width: Int, height: Int) {
|
||||
Log.i("splash", "Я родился!")
|
||||
if (!initRenderer()) {
|
||||
destroy(gl10);
|
||||
return;
|
||||
destroy(gl10)
|
||||
return
|
||||
}
|
||||
|
||||
// Загрузка текстуры
|
||||
GLES20.glGenTextures(1, _textureId, 0);
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _textureId[0]);
|
||||
GLES20.glGenTextures(1, textureId, 0)
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId[0])
|
||||
|
||||
// Установка параметров текстуры
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR)
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR)
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE)
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE)
|
||||
|
||||
// Загрузка изображения
|
||||
Bitmap bitmap = null;
|
||||
try {
|
||||
InputStream is = _activity.getAssets().open("splash.png");
|
||||
bitmap = BitmapFactory.decodeStream(is);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Could not load bitmap", e);
|
||||
val bitmap = try {
|
||||
activity.assets.open("splash.png").use { stream ->
|
||||
BitmapFactory.decodeStream(stream)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "Could not load bitmap", e)
|
||||
null
|
||||
}
|
||||
|
||||
if (bitmap != null) {
|
||||
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
|
||||
bitmap.recycle();
|
||||
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0)
|
||||
bitmap.recycle()
|
||||
} else {
|
||||
Log.e(TAG, "Failed to load bitmap");
|
||||
destroy(gl10);
|
||||
return;
|
||||
Log.e(TAG, "Failed to load bitmap")
|
||||
destroy(gl10)
|
||||
return
|
||||
}
|
||||
|
||||
// Проверка ошибок
|
||||
int error = GLES20.glGetError();
|
||||
val error = GLES20.glGetError()
|
||||
if (error != GLES20.GL_NO_ERROR) {
|
||||
Log.e(TAG, "Texture Load GLError: " + error);
|
||||
destroy(gl10);
|
||||
Log.e(TAG, "Texture Load GLError: $error")
|
||||
destroy(gl10)
|
||||
}
|
||||
}
|
||||
|
||||
private boolean initRenderer() {
|
||||
private fun initRenderer(): Boolean {
|
||||
// Загрузка шейдеров
|
||||
_vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vShaderStr);
|
||||
_fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fShaderStr);
|
||||
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderStr)
|
||||
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderStr)
|
||||
|
||||
// Создание программы
|
||||
_program = GLES20.glCreateProgram();
|
||||
if (_program == 0) {
|
||||
Log.e(TAG, "Failed to create program");
|
||||
return false;
|
||||
program = GLES20.glCreateProgram()
|
||||
if (program == 0) {
|
||||
Log.e(TAG, "Failed to create program")
|
||||
return false
|
||||
}
|
||||
|
||||
// Прикрепление шейдеров
|
||||
GLES20.glAttachShader(_program, _vertexShader);
|
||||
GLES20.glAttachShader(_program, _fragmentShader);
|
||||
GLES20.glAttachShader(program, vertexShader)
|
||||
GLES20.glAttachShader(program, fragmentShader)
|
||||
|
||||
// Линковка программы
|
||||
GLES20.glLinkProgram(_program);
|
||||
GLES20.glLinkProgram(program)
|
||||
|
||||
// Проверка статуса линковки
|
||||
int[] linkStatus = new int[1];
|
||||
GLES20.glGetProgramiv(_program, GLES20.GL_LINK_STATUS, linkStatus, 0);
|
||||
val linkStatus = IntArray(1)
|
||||
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0)
|
||||
if (linkStatus[0] != GLES20.GL_TRUE) {
|
||||
Log.e(TAG, "Could not link program: " + GLES20.glGetProgramInfoLog(_program));
|
||||
GLES20.glDeleteProgram(_program);
|
||||
_program = 0;
|
||||
return false;
|
||||
Log.e(TAG, "Could not link program: ${GLES20.glGetProgramInfoLog(program)}")
|
||||
GLES20.glDeleteProgram(program)
|
||||
program = 0
|
||||
return false
|
||||
}
|
||||
|
||||
// Получение атрибутов
|
||||
_attPosition = GLES20.glGetAttribLocation(_program, "a_position");
|
||||
_attTexCoord = GLES20.glGetAttribLocation(_program, "a_texCoord");
|
||||
_attSampler = GLES20.glGetUniformLocation(_program, "s_texture");
|
||||
attPosition = GLES20.glGetAttribLocation(program, "a_position")
|
||||
attTexCoord = GLES20.glGetAttribLocation(program, "a_texCoord")
|
||||
attSampler = GLES20.glGetUniformLocation(program, "s_texture")
|
||||
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
private int loadShader(int type, String shaderCode) {
|
||||
int shader = GLES20.glCreateShader(type);
|
||||
private fun loadShader(type: Int, shaderCode: String): Int {
|
||||
val shader = GLES20.glCreateShader(type)
|
||||
if (shader == 0) {
|
||||
Log.e(TAG, "Failed to create shader");
|
||||
return 0;
|
||||
Log.e(TAG, "Failed to create shader")
|
||||
return 0
|
||||
}
|
||||
|
||||
GLES20.glShaderSource(shader, shaderCode);
|
||||
GLES20.glCompileShader(shader);
|
||||
GLES20.glShaderSource(shader, shaderCode)
|
||||
GLES20.glCompileShader(shader)
|
||||
|
||||
// Проверка статуса компиляции
|
||||
int[] compiled = new int[1];
|
||||
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
|
||||
val compiled = IntArray(1)
|
||||
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0)
|
||||
if (compiled[0] == 0) {
|
||||
Log.e(TAG, "Could not compile shader: " + GLES20.glGetShaderInfoLog(shader));
|
||||
GLES20.glDeleteShader(shader);
|
||||
return 0;
|
||||
Log.e(TAG, "Could not compile shader: ${GLES20.glGetShaderInfoLog(shader)}")
|
||||
GLES20.glDeleteShader(shader)
|
||||
return 0
|
||||
}
|
||||
|
||||
return shader;
|
||||
return shader
|
||||
}
|
||||
|
||||
public boolean draw(GL10 gl10, int width, int height) {
|
||||
if (_textureId[0] == 0 || _program == 0) {
|
||||
return false;
|
||||
fun draw(gl10: GL10?, width: Int, height: Int): Boolean {
|
||||
if (textureId[0] == 0 || program == 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Расчет координат с уменьшением на 20%
|
||||
float ratio = (float) width / height;
|
||||
float imageRatio = 1.0f; // Предполагаем квадратное изображение
|
||||
val ratio = width.toFloat() / height
|
||||
val imageRatio = 1.0f // Предполагаем квадратное изображение
|
||||
|
||||
float scaleX, scaleY;
|
||||
if (ratio > imageRatio) {
|
||||
val (scaleX, scaleY) = if (ratio > imageRatio) {
|
||||
// Шире, чем изображение
|
||||
scaleY = 0.8f; // Уменьшаем на 20%
|
||||
scaleX = imageRatio / ratio * 0.8f;
|
||||
val scaleY = 0.8f // Уменьшаем на 20%
|
||||
val scaleX = imageRatio / ratio * 0.8f
|
||||
scaleX to scaleY
|
||||
} else {
|
||||
// Уже, чем изображение
|
||||
scaleX = 0.8f; // Уменьшаем на 20%
|
||||
scaleY = ratio / imageRatio * 0.8f;
|
||||
val scaleX = 0.8f // Уменьшаем на 20%
|
||||
val scaleY = ratio / imageRatio * 0.8f
|
||||
scaleX to scaleY
|
||||
}
|
||||
|
||||
// Координаты вершин и текстур
|
||||
float[] vertices = {
|
||||
-scaleX, -scaleY, 0.0f, // нижний левый
|
||||
scaleX, -scaleY, 0.0f, // нижний правый
|
||||
-scaleX, scaleY, 0.0f, // верхний левый
|
||||
scaleX, scaleY, 0.0f // верхний правый
|
||||
};
|
||||
val vertices = floatArrayOf(
|
||||
-scaleX, -scaleY, 0.0f, // нижний левый
|
||||
scaleX, -scaleY, 0.0f, // нижний правый
|
||||
-scaleX, scaleY, 0.0f, // верхний левый
|
||||
scaleX, scaleY, 0.0f // верхний правый
|
||||
)
|
||||
|
||||
float[] texCoords = {
|
||||
0.0f, 1.0f, // нижний левый
|
||||
1.0f, 1.0f, // нижний правый
|
||||
0.0f, 0.0f, // верхний левый
|
||||
1.0f, 0.0f // верхний правый
|
||||
};
|
||||
val texCoords = floatArrayOf(
|
||||
0.0f, 1.0f, // нижний левый
|
||||
1.0f, 1.0f, // нижний правый
|
||||
0.0f, 0.0f, // верхний левый
|
||||
1.0f, 0.0f // верхний правый
|
||||
)
|
||||
|
||||
// Создание буферов
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4);
|
||||
bb.order(ByteOrder.nativeOrder());
|
||||
FloatBuffer vertexBuffer = bb.asFloatBuffer();
|
||||
vertexBuffer.put(vertices);
|
||||
vertexBuffer.position(0);
|
||||
val vertexBuffer = ByteBuffer
|
||||
.allocateDirect(vertices.size * 4)
|
||||
.order(ByteOrder.nativeOrder())
|
||||
.asFloatBuffer()
|
||||
.apply {
|
||||
put(vertices)
|
||||
position(0)
|
||||
}
|
||||
|
||||
bb = ByteBuffer.allocateDirect(texCoords.length * 4);
|
||||
bb.order(ByteOrder.nativeOrder());
|
||||
FloatBuffer texBuffer = bb.asFloatBuffer();
|
||||
texBuffer.put(texCoords);
|
||||
texBuffer.position(0);
|
||||
val texBuffer = ByteBuffer
|
||||
.allocateDirect(texCoords.size * 4)
|
||||
.order(ByteOrder.nativeOrder())
|
||||
.asFloatBuffer()
|
||||
.apply {
|
||||
put(texCoords)
|
||||
position(0)
|
||||
}
|
||||
|
||||
// Отрисовка с белым фоном
|
||||
GLES20.glViewport(0, 0, width, height);
|
||||
GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Белый цвет
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
GLES20.glViewport(0, 0, width, height)
|
||||
GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f) // Белый цвет
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
GLES20.glUseProgram(_program);
|
||||
GLES20.glUseProgram(program)
|
||||
|
||||
// Передача вершин
|
||||
GLES20.glVertexAttribPointer(_attPosition, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
|
||||
GLES20.glEnableVertexAttribArray(_attPosition);
|
||||
GLES20.glVertexAttribPointer(attPosition, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer)
|
||||
GLES20.glEnableVertexAttribArray(attPosition)
|
||||
|
||||
// Передача текстурных координат
|
||||
GLES20.glVertexAttribPointer(_attTexCoord, 2, GLES20.GL_FLOAT, false, 0, texBuffer);
|
||||
GLES20.glEnableVertexAttribArray(_attTexCoord);
|
||||
GLES20.glVertexAttribPointer(attTexCoord, 2, GLES20.GL_FLOAT, false, 0, texBuffer)
|
||||
GLES20.glEnableVertexAttribArray(attTexCoord)
|
||||
|
||||
// Активация текстуры
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _textureId[0]);
|
||||
GLES20.glUniform1i(_attSampler, 0);
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId[0])
|
||||
GLES20.glUniform1i(attSampler, 0)
|
||||
|
||||
// Отрисовка
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
|
||||
|
||||
// Отключение атрибутов
|
||||
GLES20.glDisableVertexAttribArray(_attPosition);
|
||||
GLES20.glDisableVertexAttribArray(_attTexCoord);
|
||||
GLES20.glDisableVertexAttribArray(attPosition)
|
||||
GLES20.glDisableVertexAttribArray(attTexCoord)
|
||||
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
public void destroy(GL10 gl10) {
|
||||
if (_textureId[0] != 0) {
|
||||
GLES20.glDeleteTextures(1, _textureId, 0);
|
||||
_textureId[0] = 0;
|
||||
fun destroy(gl10: GL10?) {
|
||||
if (textureId[0] != 0) {
|
||||
GLES20.glDeleteTextures(1, textureId, 0)
|
||||
textureId[0] = 0
|
||||
}
|
||||
if (_program != 0) {
|
||||
GLES20.glDeleteProgram(_program);
|
||||
_program = 0;
|
||||
if (program != 0) {
|
||||
GLES20.glDeleteProgram(program)
|
||||
program = 0
|
||||
}
|
||||
if (_vertexShader != 0) {
|
||||
GLES20.glDeleteShader(_vertexShader);
|
||||
_vertexShader = 0;
|
||||
if (vertexShader != 0) {
|
||||
GLES20.glDeleteShader(vertexShader)
|
||||
vertexShader = 0
|
||||
}
|
||||
if (_fragmentShader != 0) {
|
||||
GLES20.glDeleteShader(_fragmentShader);
|
||||
_fragmentShader = 0;
|
||||
}
|
||||
if (vBuffer != null) {
|
||||
vBuffer.clear();
|
||||
vBuffer = null;
|
||||
if (fragmentShader != 0) {
|
||||
GLES20.glDeleteShader(fragmentShader)
|
||||
fragmentShader = 0
|
||||
}
|
||||
vBuffer?.clear()
|
||||
vBuffer = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.ea.ironmonkey.domain
|
||||
|
||||
enum class AssetLocationType {
|
||||
EXTERNAL,
|
||||
ASSETS,
|
||||
OBB
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.ea.ironmonkey.domain
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class FSNode {
|
||||
@SerializedName("directory")
|
||||
var directory: Boolean = false
|
||||
|
||||
@SerializedName("size")
|
||||
var size: Int = 0
|
||||
}
|
||||
Reference in New Issue
Block a user