From 82d836f881d632f7100b55f8246a471c21609600 Mon Sep 17 00:00:00 2001 From: Jeremy <53489032+clang-clang-clang@users.noreply.github.com> Date: Mon, 20 Nov 2023 08:53:34 +0800 Subject: [PATCH 1/2] Android: maintenance (#648) --- librtt/Rtt_Runtime.cpp | 2 +- platform/android/app/CMakeLists.txt | 2 +- platform/android/app/build.gradle.kts | 6 +- platform/android/ndk/Rtt_AndroidPlatform.cpp | 2 +- .../src/com/ansca/corona/AudioRecorder.java | 2 +- .../src/com/ansca/corona/CoronaActivity.java | 161 +++++++++--------- .../com/ansca/corona/CoronaEnvironment.java | 2 +- .../ansca/corona/CoronaSystemApiHandler.java | 18 +- .../sdk/src/com/ansca/corona/CoronaView.java | 6 +- .../com/ansca/corona/NativeToJavaBridge.java | 2 +- .../listeners/CoronaSystemApiListener.java | 2 +- .../ansca/corona/storage/FileServices.java | 22 ++- 12 files changed, 124 insertions(+), 103 deletions(-) diff --git a/librtt/Rtt_Runtime.cpp b/librtt/Rtt_Runtime.cpp index 024c52ae8..9e6698c00 100755 --- a/librtt/Rtt_Runtime.cpp +++ b/librtt/Rtt_Runtime.cpp @@ -1963,7 +1963,7 @@ Runtime::operator()() const bool isSuspended = IsSuspended(); if( wasSuspended != isSuspended && isSuspended ) { - // This condition is writtein inverse for better undrerstanding + // This condition is written inverse for better understanding // Sometimes (Splash Screen is shown) scheduled tasks can suspend Runtime // In that case (suspension state is changed and it is suspended), skip Display update } diff --git a/platform/android/app/CMakeLists.txt b/platform/android/app/CMakeLists.txt index 666b9a69b..8365ef6c5 100644 --- a/platform/android/app/CMakeLists.txt +++ b/platform/android/app/CMakeLists.txt @@ -1,2 +1,2 @@ -# This file is requiered due to Android Studio bug: if main app doesn't use NDK, project woun't use it either. +# This file is required due to Android Studio bug: if main app doesn't use NDK, project won't use it either. cmake_minimum_required(VERSION 3.4.1) diff --git a/platform/android/app/build.gradle.kts b/platform/android/app/build.gradle.kts index 44121a716..8c94bf00c 100644 --- a/platform/android/app/build.gradle.kts +++ b/platform/android/app/build.gradle.kts @@ -396,6 +396,8 @@ android.applicationVariants.all { val isRelease = (baseName == "release") val generatedAssetsDir = "$buildDir/generated/corona_assets/$baseName" val compiledLuaArchive = "$buildDir/intermediates/compiled_lua_archive/$baseName/resource.car" + // fix assets not been merge when lua file changed + val luaArchiveInMergedAssets = "$buildDir/intermediates/assets/$baseName/resource.car" val compileLuaTask = tasks.create("compileLua${baseName.capitalize()}") { description = "If required, compiles Lua and archives it into resource.car" @@ -512,9 +514,9 @@ android.applicationVariants.all { doFirst { delete(generatedAssetsDir) + delete(luaArchiveInMergedAssets) mkdir(generatedAssetsDir) - } - doFirst { + if (!file(coronaSrcDir).isDirectory) { throw InvalidUserDataException("Unable to find Solar2D project (for example platform/test/assets2/main.lua)!") } diff --git a/platform/android/ndk/Rtt_AndroidPlatform.cpp b/platform/android/ndk/Rtt_AndroidPlatform.cpp index 674d20ca0..18512bdc2 100644 --- a/platform/android/ndk/Rtt_AndroidPlatform.cpp +++ b/platform/android/ndk/Rtt_AndroidPlatform.cpp @@ -305,7 +305,7 @@ AndroidPlatform::FileExists( const char *filename ) const else { // The given file name is likely a relative path to an asset file or a URL to a local file. - // Check for its existance via Android's APIs on the Java side. + // Check for its existence via Android's APIs on the Java side. fileExists = fNativeToJavaBridge->GetRawAssetExists(filename); if (!fileExists) { diff --git a/platform/android/sdk/src/com/ansca/corona/AudioRecorder.java b/platform/android/sdk/src/com/ansca/corona/AudioRecorder.java index 26935e79e..f0c77619d 100644 --- a/platform/android/sdk/src/com/ansca/corona/AudioRecorder.java +++ b/platform/android/sdk/src/com/ansca/corona/AudioRecorder.java @@ -205,7 +205,7 @@ public void setId(long id) { } /** - * Checks if this applicaction has permission to use the microphone. + * Checks if this application has permission to use the microphone. * @return Returns true if this application has permission. Returns false if not. */ private static boolean hasPermission() { diff --git a/platform/android/sdk/src/com/ansca/corona/CoronaActivity.java b/platform/android/sdk/src/com/ansca/corona/CoronaActivity.java index 493390633..73fc0f817 100644 --- a/platform/android/sdk/src/com/ansca/corona/CoronaActivity.java +++ b/platform/android/sdk/src/com/ansca/corona/CoronaActivity.java @@ -1141,7 +1141,7 @@ public android.view.WindowInsets onApplyWindowInsets(android.view.View v, androi || mode == CoronaStatusBarSettings.LIGHT_TRANSPARENT || mode == CoronaStatusBarSettings.DARK_TRANSPARENT) { - // Unhides it if its hidden + // Unhidden it if its hidden if (myStatusBarMode == CoronaStatusBarSettings.HIDDEN) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); @@ -2095,105 +2095,98 @@ void showCoronaSplashScreen() { // whether the splash screen is in the app bundle appears to be to query the APK contents android.content.Context context = CoronaEnvironment.getApplicationContext(); android.content.res.Resources resources = context.getResources(); - com.ansca.corona.storage.FileServices fileServices; - fileServices = new com.ansca.corona.storage.FileServices(context); - boolean splashExists = fileServices.doesResourceFileExist("drawable/_corona_splash_screen.png") - || fileServices.doesResourceFileExist("drawable/_corona_splash_screen.jpg"); - // Log.v("Corona", "showCoronaSplashScreen: splashExists: " + splashExists); - if ( splashExists ) - { - final ViewManager viewManager = fCoronaRuntime.getViewManager(); - int splash_drawable_id = 0; + final ViewManager viewManager = fCoronaRuntime.getViewManager(); + // 0 is not a valid resource ID; no need for rechecking. + int splash_drawable_id = 0; - try { - // Fetch the specified resource's unique integer ID by its name. - splash_drawable_id = resources.getIdentifier("_corona_splash_screen" , "drawable", context.getPackageName()); - } - catch (Exception ex) { - Log.v("Corona", "showCoronaSplashScreen load EXCEPTION: " + ex); - } - - // Log.v("Corona", "showCoronaSplashScreen: splash_drawable_id: " + splash_drawable_id); - if ( splash_drawable_id != 0 ) - { - try { - // LinearLayout - fSplashView = new LinearLayout(this); - fSplashView.setOrientation(LinearLayout.VERTICAL); - fSplashView.setBackgroundColor(0xFF000000); + try { + // Fetch the specified resource's unique integer ID by its name. + splash_drawable_id = resources.getIdentifier("_corona_splash_screen" , "drawable", context.getPackageName()); + } + catch (Exception ex) { + Log.v("Corona", "showCoronaSplashScreen load EXCEPTION: " + ex); + } - // ImageView - ImageView imageView = new ImageView(this); - imageView.setScaleType(ImageView.ScaleType.CENTER); + // Log.v("Corona", "showCoronaSplashScreen: splash_drawable_id: " + splash_drawable_id); + if ( splash_drawable_id != 0 ) + { + try { + // LinearLayout + fSplashView = new LinearLayout(this); + fSplashView.setOrientation(LinearLayout.VERTICAL); + fSplashView.setBackgroundColor(0xFF000000); + + // ImageView + ImageView imageView = new ImageView(this); + imageView.setScaleType(ImageView.ScaleType.CENTER); + + // Resize the bitmap + android.view.Display display = + ((android.view.WindowManager)getSystemService(android.content.Context.WINDOW_SERVICE)).getDefaultDisplay(); + Bitmap d = BitmapFactory.decodeResource(resources, splash_drawable_id); + + if (display.getWidth() >= d.getWidth() && display.getHeight() >= d.getHeight()) + { + // Screen is bigger that the splash screen, we don't scale up so just display it + // Log.v("Corona", "showCoronaSplashScreen: not scaling: screen: "+ display.getWidth() +"x"+ display.getHeight() + "; original: "+ d.getWidth() +"x"+ d.getHeight()); + + imageView.setImageBitmap(d); + } + else + { + // Scaling the image ourselves avoids issues with "Bitmap too large to be uploaded into a texture" errors - // Resize the bitmap - android.view.Display display = - ((android.view.WindowManager)getSystemService(android.content.Context.WINDOW_SERVICE)).getDefaultDisplay(); - Bitmap d = BitmapFactory.decodeResource(resources, splash_drawable_id); + double widthRatio = ((double)display.getWidth() / d.getWidth()); + double heightRatio = ((double)display.getHeight() / d.getHeight()); + int nw = 0; + int nh = 0; - if (display.getWidth() >= d.getWidth() && display.getHeight() >= d.getHeight()) + // Scale by height or width, whichever is greater + if (heightRatio > widthRatio) { - // Screen is bigger that the splash screen, we don't scale up so just display it - // Log.v("Corona", "showCoronaSplashScreen: not scaling: screen: "+ display.getWidth() +"x"+ display.getHeight() + "; original: "+ d.getWidth() +"x"+ d.getHeight()); - - imageView.setImageBitmap(d); + nw = (int) ((double)d.getWidth() * widthRatio); + nh = (int) ((double)d.getHeight() * widthRatio); } else { - // Scaling the image ourselves avoids issues with "Bitmap too large to be uploaded into a texture" errors - - double widthRatio = ((double)display.getWidth() / d.getWidth()); - double heightRatio = ((double)display.getHeight() / d.getHeight()); - int nw = 0; - int nh = 0; - - // Scale by height or width, whichever is greater - if (heightRatio > widthRatio) - { - nw = (int) ((double)d.getWidth() * widthRatio); - nh = (int) ((double)d.getHeight() * widthRatio); - } - else - { - nw = (int) ((double)d.getWidth() * heightRatio); - nh = (int) ((double)d.getHeight() * heightRatio); - } + nw = (int) ((double)d.getWidth() * heightRatio); + nh = (int) ((double)d.getHeight() * heightRatio); + } - Bitmap scaled = Bitmap.createScaledBitmap(d, nw, nh, true); + Bitmap scaled = Bitmap.createScaledBitmap(d, nw, nh, true); - // Log.v("Corona", "showCoronaSplashScreen: scaling: screen: "+ display.getWidth() +"x"+ display.getHeight() + "; original: "+ d.getWidth() +"x"+ d.getHeight()+ "; scaled: "+ scaled.getWidth() +"x"+ scaled.getHeight()); - // Log.v("Corona", "showCoronaSplashScreen: new: "+ nw +"x"+ nh +"; ratio: "+ widthRatio + "x" + heightRatio); + // Log.v("Corona", "showCoronaSplashScreen: scaling: screen: "+ display.getWidth() +"x"+ display.getHeight() + "; original: "+ d.getWidth() +"x"+ d.getHeight()+ "; scaled: "+ scaled.getWidth() +"x"+ scaled.getHeight()); + // Log.v("Corona", "showCoronaSplashScreen: new: "+ nw +"x"+ nh +"; ratio: "+ widthRatio + "x" + heightRatio); - imageView.setImageBitmap(scaled); + imageView.setImageBitmap(scaled); - // On Android 2.3.3 we can help low memory devices by forcing the source bitmap to be recycled - // but only if Bitmap.createScaledBitmap() didn't return the same image - // if (android.os.Build.VERSION.SDK_INT <= 10) - // { - // if (scaled.getWidth() != d.getWidth() || scaled.getHeight() != d.getHeight()) - // { - // // We got a different bitmap back after scaling, it's safe to recycle the old one - // d.recycle(); - // } - // } - } + // On Android 2.3.3 we can help low memory devices by forcing the source bitmap to be recycled + // but only if Bitmap.createScaledBitmap() didn't return the same image + // if (android.os.Build.VERSION.SDK_INT <= 10) + // { + // if (scaled.getWidth() != d.getWidth() || scaled.getHeight() != d.getHeight()) + // { + // // We got a different bitmap back after scaling, it's safe to recycle the old one + // d.recycle(); + // } + // } + } - FrameLayout.LayoutParams layoutParams; - layoutParams = new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.FILL_PARENT, - FrameLayout.LayoutParams.FILL_PARENT, - android.view.Gravity.CENTER_HORIZONTAL | android.view.Gravity.CENTER_VERTICAL); + FrameLayout.LayoutParams layoutParams; + layoutParams = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.FILL_PARENT, + FrameLayout.LayoutParams.FILL_PARENT, + android.view.Gravity.CENTER_HORIZONTAL | android.view.Gravity.CENTER_VERTICAL); - imageView.setLayoutParams(layoutParams); + imageView.setLayoutParams(layoutParams); - fSplashView.addView(imageView); - // Make visible - viewManager.getContentView().addView(fSplashView, layoutParams); - } - catch (Exception ex) { - Log.v("Corona", "showCoronaSplashScreen display EXCEPTION: " + ex); - } + fSplashView.addView(imageView); + // Make visible + viewManager.getContentView().addView(fSplashView, layoutParams); + } + catch (Exception ex) { + Log.v("Corona", "showCoronaSplashScreen display EXCEPTION: " + ex); } } } diff --git a/platform/android/sdk/src/com/ansca/corona/CoronaEnvironment.java b/platform/android/sdk/src/com/ansca/corona/CoronaEnvironment.java index 718ad04be..772d50a5d 100644 --- a/platform/android/sdk/src/com/ansca/corona/CoronaEnvironment.java +++ b/platform/android/sdk/src/com/ansca/corona/CoronaEnvironment.java @@ -405,7 +405,7 @@ public static void setLuaErrorHandler(com.naef.jnlua.JavaFunction handler) { } /** - * Called by the C++ side of Corona when a Lua error occurrs. + * Called by the C++ side of Corona when a Lua error occurs. * Should only be invoked if JavaToNativeShim.useDefaultLuaErrorHandler() has been called, * which sets up the core code to use a custom error handler implemented on the Java side. *

diff --git a/platform/android/sdk/src/com/ansca/corona/CoronaSystemApiHandler.java b/platform/android/sdk/src/com/ansca/corona/CoronaSystemApiHandler.java index 126b77e19..4e96aa9ae 100644 --- a/platform/android/sdk/src/com/ansca/corona/CoronaSystemApiHandler.java +++ b/platform/android/sdk/src/com/ansca/corona/CoronaSystemApiHandler.java @@ -9,10 +9,11 @@ package com.ansca.corona; +import android.os.Build; import android.util.Log; import android.content.Intent; -/** The interface has all the funcations that are activity specific and aren't implemented by default. */ +/** The interface has all the functions that are activity specific and aren't implemented by default. */ public class CoronaSystemApiHandler implements com.ansca.corona.listeners.CoronaSystemApiListener { private CoronaActivity fActivity; private static final boolean DEBUG = true; @@ -111,6 +112,21 @@ else if (actionName.equals("validateResourceFile")) return false; } } + else if (actionName.equals("reportFullyDrawn")) + { + // Report to the system that app is now fully drawn, for diagnostic and optimization purposes. + // API introduced in KITKAT but has permission issue, so raise to LOLLIPOP, see https://github.com/flutter/flutter/issues/46172. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + fActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (fActivity != null) { + fActivity.reportFullyDrawn(); + } + } + }); + } + } else { // The requested action is unknown. return false; diff --git a/platform/android/sdk/src/com/ansca/corona/CoronaView.java b/platform/android/sdk/src/com/ansca/corona/CoronaView.java index 8f1a79d3f..0893790ae 100644 --- a/platform/android/sdk/src/com/ansca/corona/CoronaView.java +++ b/platform/android/sdk/src/com/ansca/corona/CoronaView.java @@ -173,7 +173,7 @@ protected Parcelable onSaveInstanceState() { } /** - * Initalizes the {@link com.ansca.corona.CoronaView CoronaView} so that it can be used. Uses the base "assets" directory as the base + * Initializes the {@link com.ansca.corona.CoronaView CoronaView} so that it can be used. Uses the base "assets" directory as the base * Corona project directory. *

* This must be the first function you call! @@ -183,10 +183,10 @@ public void init() { } /** - * Initalizes the {@link com.ansca.corona.CoronaView CoronaView} so that it can be used. + * Initializes the {@link com.ansca.corona.CoronaView CoronaView} so that it can be used. *

* This must be the first function you call! - * @param baseDir The directory of the Corona project relative to the "assests" directory. + * @param baseDir The directory of the Corona project relative to the "assets" directory. */ public void init(String baseDir) { if (Looper.myLooper() == null) { diff --git a/platform/android/sdk/src/com/ansca/corona/NativeToJavaBridge.java b/platform/android/sdk/src/com/ansca/corona/NativeToJavaBridge.java index e2dca97b7..7e3916368 100644 --- a/platform/android/sdk/src/com/ansca/corona/NativeToJavaBridge.java +++ b/platform/android/sdk/src/com/ansca/corona/NativeToJavaBridge.java @@ -146,7 +146,7 @@ protected static int callLoadClass( StringBuilder err = new StringBuilder(); if (runtime != null) { // Fetch the runtime's Lua state. - // TODO: We need to account for corountines. + // TODO: We need to account for coroutines. LuaState L = runtime.getLuaState(); if ( null == L ) { L = new com.naef.jnlua.LuaState(luaStateMemoryAddress); diff --git a/platform/android/sdk/src/com/ansca/corona/listeners/CoronaSystemApiListener.java b/platform/android/sdk/src/com/ansca/corona/listeners/CoronaSystemApiListener.java index 3b64be992..1c38c94f7 100644 --- a/platform/android/sdk/src/com/ansca/corona/listeners/CoronaSystemApiListener.java +++ b/platform/android/sdk/src/com/ansca/corona/listeners/CoronaSystemApiListener.java @@ -12,7 +12,7 @@ import android.content.Intent; import com.ansca.corona.CoronaRuntime; -/** The interface has all the funcations that are activity specific and aren't implemented by default. */ +/** The interface has all the functions that are activity specific and aren't implemented by default. */ public interface CoronaSystemApiListener{ public boolean requestSystem(CoronaRuntime runtime, String actionName, long luaStateMemoryAddress, int luaStackIndex); diff --git a/platform/android/sdk/src/com/ansca/corona/storage/FileServices.java b/platform/android/sdk/src/com/ansca/corona/storage/FileServices.java index 309874a17..f9cd3e534 100644 --- a/platform/android/sdk/src/com/ansca/corona/storage/FileServices.java +++ b/platform/android/sdk/src/com/ansca/corona/storage/FileServices.java @@ -44,6 +44,13 @@ public class FileServices extends com.ansca.corona.ApplicationContextProvider { /** Provides fast access to file entries within an APK file, which is really a zip file. */ private static ZipResourceFile sApkZipEntryReader = null; + /** + * For more efficient I/O throughput, BUFFER_SIZE at least 4KB is needed. + * For copy size 1MB and above, 64KB is recommended. + */ + private final static int BUFFER_SIZE_NORMAL = 4096; // 4KB + private final static int BUFFER_SIZE_LARGE_IO = 65536; // 64KB + private final static int BUFFER_SIZE_THRESHOLD = 1048576; // 1MB /** * Creates an object that provides easy access to the file system and this application's @@ -417,7 +424,8 @@ public void loadExpansionFiles() { // Attempt to load the expansion files. sHasAccessedExpansionFileDirectory = false; - if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { + if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED) + || android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED_READ_ONLY)) { java.io.File expansionDirectory = getExpansionFileDirectory(); if ((expansionDirectory != null) && expansionDirectory.exists()) { try { sPatchExpansionZipReader = new ZipResourceFile(getPatchExpansionFile()); } @@ -958,7 +966,7 @@ public boolean copyFile(java.io.File sourceFile, java.io.File destinationFile) { if (outputStream != null) { int byteCount = inputStream.available(); if (byteCount > 0) { - final int BUFFER_SIZE = 1024; + final int BUFFER_SIZE = byteCount > BUFFER_SIZE_THRESHOLD ? BUFFER_SIZE_LARGE_IO : BUFFER_SIZE_NORMAL; byte[] byteBuffer = new byte[BUFFER_SIZE]; while (byteCount > 0) { int bytesToCopy = BUFFER_SIZE; @@ -1020,7 +1028,7 @@ public boolean writeToFile(java.io.InputStream inputStream, java.io.File destina try { outputStream = new java.io.FileOutputStream(destinationFile); if (outputStream != null) { - final int BUFFER_SIZE = 1024; + final int BUFFER_SIZE = inputStream.available() > BUFFER_SIZE_THRESHOLD ? BUFFER_SIZE_LARGE_IO : BUFFER_SIZE_NORMAL; byte[] byteBuffer = new byte[BUFFER_SIZE]; while (true) { int bytesToCopy = BUFFER_SIZE; @@ -1112,13 +1120,15 @@ public byte[] getBytesFromFile(String filePath) { try { inputStream = openFile(filePath); if (inputStream != null) { - int byteCount = inputStream.available(); + final int byteCount = inputStream.available(); if (byteCount > 0) { bytes = new byte[byteCount]; + final int BUFFER_SIZE = byteCount > BUFFER_SIZE_THRESHOLD ? BUFFER_SIZE_LARGE_IO : BUFFER_SIZE_NORMAL; + for (int bytesCopied = 0; bytesCopied < byteCount;) { int bytesToRead = byteCount - bytesCopied; - if (bytesToRead > 1024) { - bytesToRead = 1024; + if (bytesToRead > BUFFER_SIZE) { + bytesToRead = BUFFER_SIZE; } int readBytes = inputStream.read(bytes, bytesCopied, bytesToRead); bytesCopied += readBytes; From 996f85d0d4d47b8ff5e04853858fdcea553f4917 Mon Sep 17 00:00:00 2001 From: Huynh Quoc Khanh aka Kan <70838508+Kan-Kzeit@users.noreply.github.com> Date: Mon, 20 Nov 2023 08:11:46 +0700 Subject: [PATCH 2/2] Core: adding some extensions getter method of box2D (#647) Co-authored-by: Vlad Svoka --- librtt/Rtt_DisplayObjectExtensions.cpp | 186 ++++++++++++++++++++++--- librtt/Rtt_DisplayObjectExtensions.h | 4 + 2 files changed, 168 insertions(+), 22 deletions(-) diff --git a/librtt/Rtt_DisplayObjectExtensions.cpp b/librtt/Rtt_DisplayObjectExtensions.cpp index 9cde99cd3..aa23e3f2e 100644 --- a/librtt/Rtt_DisplayObjectExtensions.cpp +++ b/librtt/Rtt_DisplayObjectExtensions.cpp @@ -268,6 +268,124 @@ DisplayObjectExtensions::resetMassData( lua_State *L ) return 0; } +int +DisplayObjectExtensions::getWorldVector(lua_State* L) +{ + DisplayObject* o = (DisplayObject*)LuaProxy::GetProxyableObject(L, 1); + + Rtt_WARN_SIM_PROXY_TYPE(L, 1, DisplayObject); + + if (o) + { + const PhysicsWorld& physics = LuaContext::GetRuntime(L)->GetPhysicsWorld(); + Real scale = physics.GetPixelsPerMeter(); + + Self* extensions = o->GetExtensions(); + b2Body* fBody = extensions->GetBody(); + + Real lx = Rtt_RealDiv(lua_tonumber(L, 2), scale); + Real ly = Rtt_RealDiv(lua_tonumber(L, 3), scale); + + b2Vec2 localVector = b2Vec2(Rtt_RealToFloat(lx), Rtt_RealToFloat(ly)); + + b2Vec2 worldVector = fBody->GetWorldVector(localVector); + + lua_pushnumber(L, worldVector.x); + lua_pushnumber(L, worldVector.y); + + return 2; + } + + return 0; +} + +int +DisplayObjectExtensions::getInertia(lua_State* L) +{ + DisplayObject* o = (DisplayObject*)LuaProxy::GetProxyableObject(L, 1); + + Rtt_WARN_SIM_PROXY_TYPE(L, 1, DisplayObject); + + if (o) + { + const PhysicsWorld& physics = LuaContext::GetRuntime(L)->GetPhysicsWorld(); + Real scale = physics.GetPixelsPerMeter(); + + Self* extensions = o->GetExtensions(); + b2Body* fBody = extensions->GetBody(); + + float32 inertia = fBody->GetInertia() * scale; + + lua_pushnumber(L, inertia); + + return 1; + } + + return 0; +} + +int +DisplayObjectExtensions::getLinearVelocityFromWorldPoint(lua_State* L) +{ + DisplayObject* o = (DisplayObject*)LuaProxy::GetProxyableObject(L, 1); + + Rtt_WARN_SIM_PROXY_TYPE(L, 1, DisplayObject); + + if (o) + { + const PhysicsWorld& physics = LuaContext::GetRuntime(L)->GetPhysicsWorld(); + Real scale = physics.GetPixelsPerMeter(); + + Self* extensions = o->GetExtensions(); + b2Body* fBody = extensions->GetBody(); + + Real wx = Rtt_RealDiv(lua_tonumber(L, 2), scale); + Real wy = Rtt_RealDiv(lua_tonumber(L, 3), scale); + + b2Vec2 worldPoint = b2Vec2(Rtt_RealToFloat(wx), Rtt_RealToFloat(wy)); + + b2Vec2 velocity = fBody->GetLinearVelocityFromWorldPoint(worldPoint); + + lua_pushnumber(L, velocity.x); + lua_pushnumber(L, velocity.y); + + return 2; + } + + return 0; +} + +int +DisplayObjectExtensions::getLinearVelocityFromLocalPoint(lua_State* L) +{ + DisplayObject* o = (DisplayObject*)LuaProxy::GetProxyableObject(L, 1); + + Rtt_WARN_SIM_PROXY_TYPE(L, 1, DisplayObject); + + if (o) + { + const PhysicsWorld& physics = LuaContext::GetRuntime(L)->GetPhysicsWorld(); + Real scale = physics.GetPixelsPerMeter(); + + Self* extensions = o->GetExtensions(); + b2Body* fBody = extensions->GetBody(); + + Real wx = Rtt_RealDiv(lua_tonumber(L, 2), scale); + Real ly = Rtt_RealDiv(lua_tonumber(L, 3), scale); + + b2Vec2 localPoint = b2Vec2(Rtt_RealToFloat(wx), Rtt_RealToFloat(ly)); + + b2Vec2 velocity = fBody->GetLinearVelocityFromLocalPoint(localPoint); + + lua_pushnumber(L, velocity.x); + lua_pushnumber(L, velocity.y); + + return 2; + } + + return 0; +} + #endif // Rtt_PHYSICS @@ -289,30 +407,34 @@ DisplayObjectExtensions::ValueForKey( lua_State *L, const MLuaProxyable& object, static const char * keys[] = { - "isAwake", // 0 - "isBodyActive", // 1 - "isBullet", // 2 - "isSleepingAllowed", // 3 - "isFixedRotation", // 4 - "angularVelocity", // 5 - "linearDamping", // 6 - "angularDamping", // 7 - "bodyType", // 8 - "setLinearVelocity", // 9 - "getLinearVelocity", // 10 - "applyForce", // 11 - "applyTorque", // 12 - "applyLinearImpulse", // 13 - "applyAngularImpulse", // 14 - "resetMassData", // 15 - "isSensor", // 16 - "mass", // 17 - "gravityScale", // 18 - "getMassWorldCenter", // 19 - "getMassLocalCenter", // 20 + "isAwake", // 0 + "isBodyActive", // 1 + "isBullet", // 2 + "isSleepingAllowed", // 3 + "isFixedRotation", // 4 + "angularVelocity", // 5 + "linearDamping", // 6 + "angularDamping", // 7 + "bodyType", // 8 + "setLinearVelocity", // 9 + "getLinearVelocity", // 10 + "applyForce", // 11 + "applyTorque", // 12 + "applyLinearImpulse", // 13 + "applyAngularImpulse", // 14 + "resetMassData", // 15 + "isSensor", // 16 + "mass", // 17 + "gravityScale", // 18 + "getMassWorldCenter", // 19 + "getMassLocalCenter", // 20 + "getWorldVector", // 21 + "getInertia", // 22 + "getLinearVelocityFromWorldPoint", // 23 + "getLinearVelocityFromLocalPoint", // 24 }; static const int numKeys = sizeof( keys ) / sizeof( const char * ); - static StringHash sHash( *LuaContext::GetAllocator( L ), keys, numKeys, 21, 24, 11, __FILE__, __LINE__ ); + static StringHash sHash( *LuaContext::GetAllocator( L ), keys, numKeys, 25, 19, 14, __FILE__, __LINE__ ); StringHash *hash = &sHash; int index = hash->Lookup( key ); @@ -435,6 +557,26 @@ DisplayObjectExtensions::ValueForKey( lua_State *L, const MLuaProxyable& object, lua_pushcfunction( L, Self::getMassLocalCenter ); } break; + case 21: + { + lua_pushcfunction(L, Self::getWorldVector ); + } + break; + case 22: + { + lua_pushcfunction(L, Self::getInertia); + } + break; + case 23: + { + lua_pushcfunction(L, Self::getLinearVelocityFromWorldPoint); + } + break; + case 24: + { + lua_pushcfunction(L, Self::getLinearVelocityFromLocalPoint); + } + break; default: { result = 0; diff --git a/librtt/Rtt_DisplayObjectExtensions.h b/librtt/Rtt_DisplayObjectExtensions.h index 277168389..14d1a9d55 100644 --- a/librtt/Rtt_DisplayObjectExtensions.h +++ b/librtt/Rtt_DisplayObjectExtensions.h @@ -54,6 +54,10 @@ class DisplayObjectExtensions : public LuaProxyVTable static int resetMassData( lua_State *L ); static int getMassWorldCenter( lua_State *L ); static int getMassLocalCenter( lua_State *L ); + static int getWorldVector( lua_State *L); + static int getInertia( lua_State *L ); + static int getLinearVelocityFromWorldPoint(lua_State *L); + static int getLinearVelocityFromLocalPoint(lua_State* L); #endif // Rtt_PHYSICS