This commit is contained in:
dgis 2018-11-30 22:38:09 +00:00
parent f19dc4e0a9
commit 5edce2f915
9 changed files with 177 additions and 104 deletions

View file

@ -60,28 +60,12 @@ add_library( # Sets the name of the library.
src/main/cpp/emu48-jni.c 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 # Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this # can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries. # build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library. target_link_libraries( # Specifies the target library.
native-lib native-lib
android android
jnigraphics
# Links the target library to the log library log)
# included in the NDK.
${log-lib})

View file

@ -9,33 +9,52 @@
#include "pch.h" #include "pch.h"
JNIEXPORT jstring JNICALL JavaVM *java_machine;
Java_com_regis_cosnier_emu48_MainActivity_stringFromJNI( JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env, java_machine = vm;
jobject thisz) { return JNI_VERSION_1_6;
// std::string hello = "Hello from C++";
// return env->NewStringUTF(hello.c_str());
return (*env)->NewStringUTF(env, "Hello from JNI !");
} }
extern void emu48Start(); extern void emu48Start();
extern AAssetManager * assetManager; 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) { // https://stackoverflow.com/questions/9630134/jni-how-to-callback-from-c-or-c-to-java
void mainViewUpdateCallback() {
AndroidBitmapInfo androidBitmapInfo; if (viewToUpdate) {
void * pixels; JNIEnv *jni;
int ret; jint result = (*java_machine)->AttachCurrentThread(java_machine, &jni, NULL);
if ((ret = AndroidBitmap_getInfo(env, bitmapMainScreen, &androidBitmapInfo)) < 0) { jclass viewToUpdateClass = (*jni)->GetObjectClass(jni, viewToUpdate);
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); jmethodID midStr = (*jni)->GetMethodID(jni, viewToUpdateClass, "updateCallback", "()V");
return; (*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);
// }
// JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_start(JNIEnv *env, jobject thisz, jobject assetMgr, jobject bitmapMainScreen0, jobject view) {
// AndroidBitmap_unlockPixels(env, bitmapMainScreen);
viewToUpdate = (*env)->NewGlobalRef(env, view);
bitmapMainScreen = (*env)->NewGlobalRef(env, bitmapMainScreen0);
assetManager = AAssetManager_fromJava(env, assetMgr); assetManager = AAssetManager_fromJava(env, assetMgr);
emu48Start(); 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) {
}

View file

@ -28,6 +28,7 @@
#define LOG_TAG "NDK_NativeEmu48" #define LOG_TAG "NDK_NativeEmu48"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) #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__)) #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
extern void mainViewUpdateCallback();
#include "win32-layer.h" #include "win32-layer.h"

View file

@ -5,6 +5,10 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <pthread.h> #include <pthread.h>
#include "resource.h" #include "resource.h"
#include "win32-layer.h"
extern JavaVM *java_machine;
extern jobject bitmapMainScreen;
HANDLE hWnd; HANDLE hWnd;
LPTSTR szTitle; LPTSTR szTitle;
@ -730,7 +734,7 @@ BOOL PatBlt(HDC hdc, int x, int y, int w, int h, DWORD rop) {
return 0; return 0;
} }
BOOL BitBlt(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop) { BOOL BitBlt(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop) {
//TODO mainViewUpdateCallback();
return 0; return 0;
} }
int SetStretchBltMode(HDC hdc, int mode) { int SetStretchBltMode(HDC hdc, int mode) {
@ -738,18 +742,74 @@ int SetStretchBltMode(HDC hdc, int mode) {
return 0; 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) { 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; return 0;
} }
UINT SetDIBColorTable(HDC hdc, UINT iStart, UINT cEntries, CONST RGBQUAD *prgbq) { UINT SetDIBColorTable(HDC hdc, UINT iStart, UINT cEntries, CONST RGBQUAD *prgbq) {
//TODO //TODO
return 0; 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) { HBITMAP CreateDIBitmap( HDC hdc, CONST BITMAPINFOHEADER *pbmih, DWORD flInit, CONST VOID *pjBits, CONST BITMAPINFO *pbmi, UINT iUsage) {
HGDIOBJ newHDC = (HGDIOBJ)malloc(sizeof(_HGDIOBJ)); HGDIOBJ newHDC = (HGDIOBJ)malloc(sizeof(_HGDIOBJ));
newHDC->handleType = HGDIOBJ_TYPE_BITMAP; newHDC->handleType = HGDIOBJ_TYPE_BITMAP;

View file

@ -1,8 +1,12 @@
#pragma once
#include <stdint.h> #include <stdint.h>
#include <pthread.h> #include <pthread.h>
#include <wchar.h> #include <wchar.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <jni.h>
#include <android/bitmap.h>
#include <android/asset_manager.h> #include <android/asset_manager.h>
#ifndef __OBJC__ #ifndef __OBJC__
@ -31,7 +35,7 @@ typedef WORD *LPWORD;
typedef uint32_t DWORD; typedef uint32_t DWORD;
typedef DWORD *LPDWORD; typedef DWORD *LPDWORD;
typedef BYTE *LPBYTE; typedef BYTE *LPBYTE;
typedef unsigned short WORD; typedef uint16_t WORD;
typedef uint32_t UINT; typedef uint32_t UINT;
typedef int32_t INT; typedef int32_t INT;
typedef int INT_PTR, *PINT_PTR; typedef int INT_PTR, *PINT_PTR;
@ -39,10 +43,12 @@ typedef char CHAR;
typedef void VOID; typedef void VOID;
typedef void *LPVOID; typedef void *LPVOID;
typedef void *PVOID; typedef void *PVOID;
typedef long LONG; //typedef long LONG;
typedef int32_t LONG;
typedef LONG *PLONG; typedef LONG *PLONG;
typedef unsigned int UINT_PTR, *PUINT_PTR; 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 size_t SIZE_T;
typedef /*_W64*/ unsigned long ULONG_PTR, *PULONG_PTR; typedef /*_W64*/ unsigned long ULONG_PTR, *PULONG_PTR;
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;

View file

@ -2,10 +2,9 @@ package com.regis.cosnier.emu48;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Bundle; import android.os.Bundle;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.widget.TextView; import android.view.ViewGroup;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
@ -16,13 +15,7 @@ import android.view.MenuItem;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
private Bitmap bitmapMainScreen; private MainScreenView mainScreenView;
MainScreenView mainScreenView;
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { 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); mainScreenView = new MainScreenView(this); //, currentProject);
ViewGroup mainScreenContainer = (ViewGroup)findViewById(R.id.main_screen_container);
mainScreenContainer.addView(mainScreenView, 0);
} }
@Override @Override
@ -76,11 +60,11 @@ public class MainActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
/** @Override
* A native method that is implemented by the 'native-lib' native library, protected void onDestroy() {
* which is packaged with this application.
*/
public native String stringFromJNI();
public native void emu48Start(AssetManager mgr, Bitmap bitmapMainScreen); NativeLib.stop();
super.onDestroy();
}
} }

View file

@ -1,11 +1,15 @@
package com.regis.cosnier.emu48; package com.regis.cosnier.emu48;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewCompat;
import android.util.DisplayMetrics;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -16,26 +20,29 @@ import android.view.View;
import android.widget.OverScroller; import android.widget.OverScroller;
public class MainScreenView extends SurfaceView { public class MainScreenView extends SurfaceView {
protected static final String TAG = "MainScreenView"; protected static final String TAG = "MainScreenView";
private Bitmap bitmapMainScreen;
public MainScreenView(Context context) { public MainScreenView(Context context) {
super(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); * Common initialize method.
// * @param context The activity context.
// commonInitialize(context, currentProject); * @param currentProject The current project.
// } */
private void commonInitialize(Context context) {
// /**
// * Common initialize method.
// * @param context The activity context.
// * @param currentProject The current project.
// */
// private void commonInitialize(Context context, final Project currentProject) {
// //this.mContext = context; // //this.mContext = context;
// this.currentProject = currentProject; // this.currentProject = currentProject;
// //
@ -86,10 +93,10 @@ public class MainScreenView extends SurfaceView {
// this.setFocusable(true); // this.setFocusable(true);
// this.setFocusableInTouchMode(true); // this.setFocusableInTouchMode(true);
// //
// // This call is necessary, or else the // This call is necessary, or else the
// // draw method will not be called. // draw method will not be called.
// setWillNotDraw(false); setWillNotDraw(false);
// } }
// //
// @SuppressLint("ClickableViewAccessibility") // @SuppressLint("ClickableViewAccessibility")
@ -189,8 +196,7 @@ public class MainScreenView extends SurfaceView {
protected void onSizeChanged(int viewWidth, int viewHeight, int oldViewWidth, int oldViewHeight) { protected void onSizeChanged(int viewWidth, int viewHeight, int oldViewWidth, int oldViewHeight) {
super.onSizeChanged(viewWidth, viewHeight, oldViewWidth, oldViewHeight); super.onSizeChanged(viewWidth, viewHeight, oldViewWidth, oldViewHeight);
// mViewBounds.set(0.0f, 0.0f, viewWidth, viewHeight); NativeLib.resize(viewWidth, viewHeight);
// resetViewport((float)viewWidth, (float)viewHeight);
} }
@Override @Override
@ -198,7 +204,7 @@ public class MainScreenView extends SurfaceView {
//Log.d(TAG, "onDraw() mIsScaling: " + mIsScaling + ", mIsPanning: " + mIsPanning + ", mIsFlinging: " + mIsFlinging); //Log.d(TAG, "onDraw() mIsScaling: " + mIsScaling + ", mIsPanning: " + mIsPanning + ", mIsFlinging: " + mIsFlinging);
// //renderPlasma(mBitmap, System.currentTimeMillis() - mStartTime); // //renderPlasma(mBitmap, System.currentTimeMillis() - mStartTime);
// canvas.drawBitmap(bitmapMainScreen, 0, 0, null); canvas.drawBitmap(bitmapMainScreen, 0, 0, null);
// Paint paint = mVectorsCanvasRenderer.getPaint(); // Paint paint = mVectorsCanvasRenderer.getPaint();
// //
@ -254,6 +260,11 @@ public class MainScreenView extends SurfaceView {
// mRectScaleImage.top + scale * (mViewBounds.height() - currentProject.viewPanOffsetY) / currentProject.viewScaleFactor // mRectScaleImage.top + scale * (mViewBounds.height() - currentProject.viewPanOffsetY) / currentProject.viewScaleFactor
// ); // );
// canvas.drawRect(mRectScaleView, paint); // canvas.drawRect(mRectScaleView, paint);
} // }
}
void updateCallback() {
//invalidate();
postInvalidate();
} }
} }

View file

@ -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);
}

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_screen_container"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -8,14 +9,5 @@
tools:context=".MainActivity" tools:context=".MainActivity"
tools:showIn="@layout/activity_main"> tools:showIn="@layout/activity_main">
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>