From 5edce2f915848c834292290d93315f10a24501e3 Mon Sep 17 00:00:00 2001 From: dgis Date: Fri, 30 Nov 2018 22:38:09 +0000 Subject: [PATCH] --- app/CMakeLists.txt | 20 +---- app/src/main/cpp/emu48-jni.c | 59 ++++++++++----- app/src/main/cpp/pch.h | 1 + app/src/main/cpp/win32-layer.c | 74 +++++++++++++++++-- app/src/main/cpp/win32-layer.h | 12 ++- .../com/regis/cosnier/emu48/MainActivity.java | 36 +++------ .../regis/cosnier/emu48/MainScreenView.java | 53 +++++++------ .../com/regis/cosnier/emu48/NativeLib.java | 16 ++++ app/src/main/res/layout/content_main.xml | 10 +-- 9 files changed, 177 insertions(+), 104 deletions(-) create mode 100644 app/src/main/java/com/regis/cosnier/emu48/NativeLib.java diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 50892f5..9150c50 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -60,28 +60,12 @@ add_library( # Sets the name of the library. src/main/cpp/emu48-jni.c ) -# Searches for a specified prebuilt library and stores the path as a -# variable. Because CMake includes system libraries in the search path by -# default, you only need to specify the name of the public NDK library -# you want to add. CMake verifies that the library exists before -# completing its build. - -find_library( # Sets the name of the path variable. - log-lib - - # Specifies the name of the NDK library that - # you want CMake to locate. - log) - # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. target_link_libraries( # Specifies the target library. native-lib - android - - # Links the target library to the log library - # included in the NDK. - ${log-lib}) \ No newline at end of file + jnigraphics + log) diff --git a/app/src/main/cpp/emu48-jni.c b/app/src/main/cpp/emu48-jni.c index c769cc2..57cc67e 100644 --- a/app/src/main/cpp/emu48-jni.c +++ b/app/src/main/cpp/emu48-jni.c @@ -9,33 +9,52 @@ #include "pch.h" -JNIEXPORT jstring JNICALL -Java_com_regis_cosnier_emu48_MainActivity_stringFromJNI( - JNIEnv *env, - jobject thisz) { -// std::string hello = "Hello from C++"; -// return env->NewStringUTF(hello.c_str()); - return (*env)->NewStringUTF(env, "Hello from JNI !"); +JavaVM *java_machine; +JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { + java_machine = vm; + return JNI_VERSION_1_6; } extern void emu48Start(); extern AAssetManager * assetManager; +static jobject viewToUpdate = NULL; +jobject bitmapMainScreen; -JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_MainActivity_emu48Start(JNIEnv *env, jobject thisz, jobject assetMgr, jobject bitmapMainScreen) { - - AndroidBitmapInfo androidBitmapInfo; - void * pixels; - int ret; - if ((ret = AndroidBitmap_getInfo(env, bitmapMainScreen, &androidBitmapInfo)) < 0) { - LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); - return; +// https://stackoverflow.com/questions/9630134/jni-how-to-callback-from-c-or-c-to-java +void mainViewUpdateCallback() { + if (viewToUpdate) { + JNIEnv *jni; + jint result = (*java_machine)->AttachCurrentThread(java_machine, &jni, NULL); + jclass viewToUpdateClass = (*jni)->GetObjectClass(jni, viewToUpdate); + jmethodID midStr = (*jni)->GetMethodID(jni, viewToUpdateClass, "updateCallback", "()V"); + (*jni)->CallVoidMethod(jni, viewToUpdate, midStr); + result = (*java_machine)->DetachCurrentThread(java_machine); } -// if ((ret = AndroidBitmap_lockPixels(env, bitmapMainScreen, &pixels)) < 0) { -// LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); -// } -// -// AndroidBitmap_unlockPixels(env, bitmapMainScreen); +} + + +JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_start(JNIEnv *env, jobject thisz, jobject assetMgr, jobject bitmapMainScreen0, jobject view) { + + viewToUpdate = (*env)->NewGlobalRef(env, view); + bitmapMainScreen = (*env)->NewGlobalRef(env, bitmapMainScreen0); assetManager = AAssetManager_fromJava(env, assetMgr); emu48Start(); } + +JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_stop(JNIEnv *env, jobject thisz) { + + if (viewToUpdate) { + (*env)->DeleteGlobalRef(env, viewToUpdate); + viewToUpdate = NULL; + } + if(bitmapMainScreen) { + (*env)->DeleteGlobalRef(env, bitmapMainScreen); + bitmapMainScreen = NULL; + } +} + + +JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_resize(JNIEnv *env, jobject thisz, jint width, jint height) { + +} \ No newline at end of file diff --git a/app/src/main/cpp/pch.h b/app/src/main/cpp/pch.h index 359482f..b2af195 100644 --- a/app/src/main/cpp/pch.h +++ b/app/src/main/cpp/pch.h @@ -28,6 +28,7 @@ #define LOG_TAG "NDK_NativeEmu48" #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) +extern void mainViewUpdateCallback(); #include "win32-layer.h" diff --git a/app/src/main/cpp/win32-layer.c b/app/src/main/cpp/win32-layer.c index bb123cb..f3d8c01 100644 --- a/app/src/main/cpp/win32-layer.c +++ b/app/src/main/cpp/win32-layer.c @@ -5,6 +5,10 @@ #include #include #include "resource.h" +#include "win32-layer.h" + +extern JavaVM *java_machine; +extern jobject bitmapMainScreen; HANDLE hWnd; LPTSTR szTitle; @@ -730,7 +734,7 @@ BOOL PatBlt(HDC hdc, int x, int y, int w, int h, DWORD rop) { return 0; } BOOL BitBlt(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop) { - //TODO + mainViewUpdateCallback(); return 0; } int SetStretchBltMode(HDC hdc, int mode) { @@ -738,18 +742,74 @@ int SetStretchBltMode(HDC hdc, int mode) { return 0; } BOOL StretchBlt(HDC hdcDest, int xDest, int yDest, int wDest, int hDest, HDC hdcSrc, int xSrc, int ySrc, int wSrc, int hSrc, DWORD rop) { - //TODO + + if(hdcDest->hdcCompatible == NULL && hdcSrc->selectedBitmap) { + // We update the main window + JNIEnv * jniEnv; + jint ret = (*java_machine)->AttachCurrentThread(java_machine, &jniEnv, NULL); + + AndroidBitmapInfo androidBitmapInfo; + if ((ret = AndroidBitmap_getInfo(jniEnv, bitmapMainScreen, &androidBitmapInfo)) < 0) { + LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); + } + + void * pixelsDestination; + if ((ret = AndroidBitmap_lockPixels(jniEnv, bitmapMainScreen, &pixelsDestination)) < 0) { + LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); + } + + HBITMAP hBitmap = hdcSrc->selectedBitmap; + + //void * pixelsSource = hBitmap->bitmapInfo->bmiColors; + void * pixelsSource = hBitmap->bitmapBits; + + int sourceWidth = hBitmap->bitmapInfoHeader->biWidth; + int sourceHeight = abs(hBitmap->bitmapInfoHeader->biHeight); + int destinationWidth = androidBitmapInfo.width; + int destinationHeight = androidBitmapInfo.height; + + //https://softwareengineering.stackexchange.com/questions/148123/what-is-the-algorithm-to-copy-a-region-of-one-bitmap-into-a-region-in-another + float src_dx = wDest / wSrc; + float src_dy = hDest / hSrc; + float src_maxx = xSrc + wSrc; + float src_maxy = ySrc + hSrc; + float dst_maxx = xDest + wDest; + float dst_maxy = yDest + hDest; + float src_cury = ySrc; + + float sourceStride = sourceWidth * 4; + float destinationStride = androidBitmapInfo.stride; + + for (float y = yDest; y < dst_maxy; y++) + { + float src_curx = xSrc; + for (float x = xDest; x < dst_maxx; x++) + { + // Point sampling - you can also impl as bilinear or other + //dst.bmp[x,y] = src.bmp[src_curx, src_cury]; + + BYTE * destinationPixel = pixelsDestination + (int)(4.0 * x + destinationStride * y); + BYTE * sourcePixel = pixelsSource + (int)(4.0 * src_curx + sourceStride * src_cury); + memcpy(destinationPixel, sourcePixel, 4); + + src_curx += src_dx; + } + + src_cury += src_dy; + } + + AndroidBitmap_unlockPixels(jniEnv, bitmapMainScreen); + + ret = (*java_machine)->DetachCurrentThread(java_machine); + + mainViewUpdateCallback(); + } return 0; } UINT SetDIBColorTable(HDC hdc, UINT iStart, UINT cEntries, CONST RGBQUAD *prgbq) { //TODO return 0; } -/* constants for CreateDIBitmap */ -#define CBM_INIT 0x04L /* initialize bitmap */ -/* DIB color table identifiers */ -#define DIB_RGB_COLORS 0 /* color table in RGBs */ -#define DIB_PAL_COLORS 1 /* color table in palette indices */ HBITMAP CreateDIBitmap( HDC hdc, CONST BITMAPINFOHEADER *pbmih, DWORD flInit, CONST VOID *pjBits, CONST BITMAPINFO *pbmi, UINT iUsage) { HGDIOBJ newHDC = (HGDIOBJ)malloc(sizeof(_HGDIOBJ)); newHDC->handleType = HGDIOBJ_TYPE_BITMAP; diff --git a/app/src/main/cpp/win32-layer.h b/app/src/main/cpp/win32-layer.h index 136d243..eb20808 100644 --- a/app/src/main/cpp/win32-layer.h +++ b/app/src/main/cpp/win32-layer.h @@ -1,8 +1,12 @@ +#pragma once + #include #include #include #include #include +#include +#include #include #ifndef __OBJC__ @@ -31,7 +35,7 @@ typedef WORD *LPWORD; typedef uint32_t DWORD; typedef DWORD *LPDWORD; typedef BYTE *LPBYTE; -typedef unsigned short WORD; +typedef uint16_t WORD; typedef uint32_t UINT; typedef int32_t INT; typedef int INT_PTR, *PINT_PTR; @@ -39,10 +43,12 @@ typedef char CHAR; typedef void VOID; typedef void *LPVOID; typedef void *PVOID; -typedef long LONG; +//typedef long LONG; +typedef int32_t LONG; typedef LONG *PLONG; typedef unsigned int UINT_PTR, *PUINT_PTR; -typedef long LONG_PTR, *PLONG_PTR; +//typedef long LONG_PTR, *PLONG_PTR; +typedef LONG LONG_PTR, *PLONG_PTR; typedef size_t SIZE_T; typedef /*_W64*/ unsigned long ULONG_PTR, *PULONG_PTR; typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; diff --git a/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java b/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java index 470ebe5..5b0b9cf 100644 --- a/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java +++ b/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java @@ -2,10 +2,9 @@ package com.regis.cosnier.emu48; import android.content.res.AssetManager; import android.graphics.Bitmap; -import android.graphics.Canvas; import android.os.Bundle; import android.util.DisplayMetrics; -import android.widget.TextView; +import android.view.ViewGroup; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; @@ -16,13 +15,7 @@ import android.view.MenuItem; public class MainActivity extends AppCompatActivity { - private Bitmap bitmapMainScreen; - MainScreenView mainScreenView; - - // Used to load the 'native-lib' library on application startup. - static { - System.loadLibrary("native-lib"); - } + private MainScreenView mainScreenView; @Override protected void onCreate(Bundle savedInstanceState) { @@ -40,18 +33,9 @@ public class MainActivity extends AppCompatActivity { } }); - // Example of a call to a native method - TextView tv = (TextView) findViewById(R.id.sample_text); - tv.setText(stringFromJNI()); - - AssetManager mgr = getResources().getAssets(); - - DisplayMetrics displayMetrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); - bitmapMainScreen = Bitmap.createBitmap(displayMetrics.widthPixels, displayMetrics.heightPixels, Bitmap.Config.ARGB_8888); - emu48Start(mgr, bitmapMainScreen); - mainScreenView = new MainScreenView(this); //, currentProject); + ViewGroup mainScreenContainer = (ViewGroup)findViewById(R.id.main_screen_container); + mainScreenContainer.addView(mainScreenView, 0); } @Override @@ -76,11 +60,11 @@ public class MainActivity extends AppCompatActivity { return super.onOptionsItemSelected(item); } - /** - * A native method that is implemented by the 'native-lib' native library, - * which is packaged with this application. - */ - public native String stringFromJNI(); + @Override + protected void onDestroy() { - public native void emu48Start(AssetManager mgr, Bitmap bitmapMainScreen); + NativeLib.stop(); + + super.onDestroy(); + } } diff --git a/app/src/main/java/com/regis/cosnier/emu48/MainScreenView.java b/app/src/main/java/com/regis/cosnier/emu48/MainScreenView.java index 1f91904..577dd66 100644 --- a/app/src/main/java/com/regis/cosnier/emu48/MainScreenView.java +++ b/app/src/main/java/com/regis/cosnier/emu48/MainScreenView.java @@ -1,11 +1,15 @@ package com.regis.cosnier.emu48; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; +import android.content.res.AssetManager; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.support.v4.view.ViewCompat; +import android.util.DisplayMetrics; import android.view.GestureDetector; import android.view.InputDevice; import android.view.KeyEvent; @@ -16,26 +20,29 @@ import android.view.View; import android.widget.OverScroller; public class MainScreenView extends SurfaceView { + protected static final String TAG = "MainScreenView"; + private Bitmap bitmapMainScreen; public MainScreenView(Context context) { super(context); - //commonInitialize(context, new Project()); + AssetManager mgr = getResources().getAssets(); + + DisplayMetrics displayMetrics = new DisplayMetrics(); + ((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + bitmapMainScreen = Bitmap.createBitmap(displayMetrics.widthPixels, displayMetrics.heightPixels, Bitmap.Config.ARGB_8888); + NativeLib.start(mgr, bitmapMainScreen, this); + + commonInitialize(context); } -// public MainScreenView(Context context, final Project currentProject) { -// super(context); -// -// commonInitialize(context, currentProject); -// } - -// /** -// * Common initialize method. -// * @param context The activity context. -// * @param currentProject The current project. -// */ -// private void commonInitialize(Context context, final Project currentProject) { + /** + * Common initialize method. + * @param context The activity context. + * @param currentProject The current project. + */ + private void commonInitialize(Context context) { // //this.mContext = context; // this.currentProject = currentProject; // @@ -86,10 +93,10 @@ public class MainScreenView extends SurfaceView { // this.setFocusable(true); // this.setFocusableInTouchMode(true); // -// // This call is necessary, or else the -// // draw method will not be called. -// setWillNotDraw(false); -// } + // This call is necessary, or else the + // draw method will not be called. + setWillNotDraw(false); + } // // @SuppressLint("ClickableViewAccessibility") @@ -189,8 +196,7 @@ public class MainScreenView extends SurfaceView { protected void onSizeChanged(int viewWidth, int viewHeight, int oldViewWidth, int oldViewHeight) { super.onSizeChanged(viewWidth, viewHeight, oldViewWidth, oldViewHeight); -// mViewBounds.set(0.0f, 0.0f, viewWidth, viewHeight); -// resetViewport((float)viewWidth, (float)viewHeight); + NativeLib.resize(viewWidth, viewHeight); } @Override @@ -198,7 +204,7 @@ public class MainScreenView extends SurfaceView { //Log.d(TAG, "onDraw() mIsScaling: " + mIsScaling + ", mIsPanning: " + mIsPanning + ", mIsFlinging: " + mIsFlinging); // //renderPlasma(mBitmap, System.currentTimeMillis() - mStartTime); -// canvas.drawBitmap(bitmapMainScreen, 0, 0, null); + canvas.drawBitmap(bitmapMainScreen, 0, 0, null); // Paint paint = mVectorsCanvasRenderer.getPaint(); // @@ -254,6 +260,11 @@ public class MainScreenView extends SurfaceView { // mRectScaleImage.top + scale * (mViewBounds.height() - currentProject.viewPanOffsetY) / currentProject.viewScaleFactor // ); // canvas.drawRect(mRectScaleView, paint); - } +// } + } + + void updateCallback() { + //invalidate(); + postInvalidate(); } } diff --git a/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java b/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java new file mode 100644 index 0000000..84299c1 --- /dev/null +++ b/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java @@ -0,0 +1,16 @@ +package com.regis.cosnier.emu48; + +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.view.View; + +public class NativeLib { + + static { + System.loadLibrary("native-lib"); + } + + public static native void start(AssetManager mgr, Bitmap bitmapMainScreen, MainScreenView view); + public static native void stop(); + public static native void resize(int width, int height); +} diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index bebda2a..e389dcc 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -1,5 +1,6 @@ - \ No newline at end of file