android: native egl surface

fps counter using imgui
restart emulator with new game in same process
This commit is contained in:
Flyinghead 2019-02-18 00:25:06 +01:00
parent b15b8de12b
commit 4c1acfeab1
21 changed files with 1052 additions and 286 deletions

View File

@ -344,8 +344,10 @@ static void rend_create_renderer()
#endif
}
static void rend_init_renderer()
void rend_init_renderer()
{
if (renderer == NULL)
rend_create_renderer();
if (!renderer->Init())
{
delete renderer;
@ -360,7 +362,7 @@ static void rend_init_renderer()
}
}
static void rend_term_renderer()
void rend_term_renderer()
{
renderer->Term();
delete renderer;
@ -371,6 +373,7 @@ static void rend_term_renderer()
fallback_renderer = NULL;
}
killtex();
gui_term();
}
void* rend_thread(void* p)

View File

@ -20,6 +20,7 @@
#include "hw/pvr/Renderer_if.h"
#include "hw/pvr/spg.h"
#include "hw/aica/dsp.h"
#include "imgread/common.h"
void FlushCache();
void LoadCustom();
@ -94,7 +95,7 @@ int64_t get_time_usec(void)
}
int GetFile(char *szFileName, char *szParse=0, u32 flags=0)
int GetFile(char *szFileName, char *szParse /* = 0 */, u32 flags /* = 0 */)
{
cfgLoadStr("config","image",szFileName,"null");
if (strcmp(szFileName,"null")==0)
@ -305,11 +306,27 @@ void dc_reset()
sh4_cpu.Reset(false);
}
static bool init_done;
int dc_init(int argc,wchar* argv[])
{
setbuf(stdin,0);
setbuf(stdout,0);
setbuf(stderr,0);
if (init_done)
{
if(ParseCommandLine(argc,argv))
{
return 69;
}
InitSettings();
LoadSettings(false);
if (DiscSwap())
LoadCustom();
dc_reset();
return 0;
}
if (!_vmem_reserve())
{
printf("Failed to alloc mem\n");
@ -394,6 +411,7 @@ int dc_init(int argc,wchar* argv[])
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
mcfg_CreateAtomisWaveControllers();
#endif
init_done = true;
dc_reset();

View File

@ -956,6 +956,7 @@ struct gl4rend : Renderer
CollectCleanup();
gl_term();
gl_free_osd_resources();
}
bool Process(TA_context* ctx) { return ProcessFrame(ctx); }

View File

@ -29,6 +29,9 @@ int fbdev = -1;
#define GL_MAJOR_VERSION 0x821B
#endif
#endif
#ifdef _ANDROID
#include <android/native_window.h> // requires ndk r5 or newer
#endif
/*
GL|ES 2
@ -407,7 +410,6 @@ GLuint fogTextureId;
// Create a basic GLES context
bool gl_init(void* wind, void* disp)
{
#if !defined(_ANDROID)
gl.setup.native_wind=(EGLNativeWindowType)wind;
gl.setup.native_disp=(EGLNativeDisplayType)disp;
@ -431,17 +433,43 @@ GLuint fogTextureId;
if (gl.setup.surface == 0)
{
EGLint pi32ConfigAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT , EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8, EGL_NONE };
EGLint pi32ConfigAttribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_NONE
};
EGLint pi32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2 , EGL_NONE };
int num_config;
EGLConfig config;
if (!eglChooseConfig(gl.setup.display, pi32ConfigAttribs, &config, 1, &num_config) || (num_config != 1))
{
// Fall back to non preserved swap buffers
EGLint pi32ConfigFallbackAttribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_NONE
};
if (!eglChooseConfig(gl.setup.display, pi32ConfigFallbackAttribs, &config, 1, &num_config) || (num_config != 1))
{
printf("EGL Error: eglChooseConfig failed\n");
return false;
}
}
#ifdef _ANDROID
EGLint format;
if (!eglGetConfigAttrib(gl.setup.display, config, EGL_NATIVE_VISUAL_ID, &format))
{
printf("eglGetConfigAttrib() returned error %d", eglGetError());
return false;
}
ANativeWindow_setBuffersGeometry((ANativeWindow *)wind, 0, 0, format);
#endif
gl.setup.surface = eglCreateWindowSurface(gl.setup.display, config, (EGLNativeWindowType)wind, NULL);
@ -460,7 +488,6 @@ GLuint fogTextureId;
if (eglCheck())
return false;
}
#endif
eglMakeCurrent(gl.setup.display, gl.setup.surface, gl.setup.surface, gl.setup.context);
@ -485,13 +512,6 @@ GLuint fogTextureId;
return true;
}
void egl_stealcntx()
{
gl.setup.context=eglGetCurrentContext();
gl.setup.display=eglGetCurrentDisplay();
gl.setup.surface=eglGetCurrentSurface(EGL_DRAW);
}
//swap buffers
void gl_swap()
{
@ -508,24 +528,37 @@ GLuint fogTextureId;
//destroy the gles context and free resources
void gl_term()
{
glDeleteProgram(gl.modvol_shader.program);
glDeleteBuffers(1, &gl.vbo.geometry);
gl.vbo.geometry = 0;
glDeleteBuffers(1, &gl.vbo.modvols);
glDeleteBuffers(1, &gl.vbo.idxs);
glDeleteBuffers(1, &gl.vbo.idxs2);
glcache.DeleteTextures(1, &fbTextureId);
fbTextureId = 0;
gl_free_osd_resources();
memset(gl.pogram_table, 0, sizeof(gl.pogram_table));
#if HOST_OS==OS_WINDOWS
ReleaseDC((HWND)gl.setup.native_wind,(HDC)gl.setup.native_disp);
#endif
#ifdef TARGET_PANDORA
#if defined(TARGET_PANDORA) || defined(_ANDROID)
eglMakeCurrent(gl.setup.display, NULL, NULL, EGL_NO_CONTEXT);
if (gl.setup.context)
if (gl.setup.context != NULL)
eglDestroyContext(gl.setup.display, gl.setup.context);
if (gl.setup.surface)
if (gl.setup.surface != NULL)
eglDestroySurface(gl.setup.display, gl.setup.surface);
#ifdef TARGET_PANDORA
if (gl.setup.display)
eglTerminate(gl.setup.display);
if (fbdev>=0)
close( fbdev );
fbdev=-1;
gl.setup.context=0;
gl.setup.surface=0;
gl.setup.display=0;
#endif
gl.setup.context = NULL;
gl.setup.surface = NULL;
gl.setup.display = NULL;
#endif
}
#else
@ -956,7 +989,6 @@ bool CompilePipelineShader( PipelineShader* s)
}
GLuint osd_tex;
GLuint osd_font;
void gl_load_osd_resources()
{
@ -964,18 +996,15 @@ void gl_load_osd_resources()
int w, h;
if (osd_tex == 0)
osd_tex = loadPNG(get_readonly_data_path("/data/buttons.png"), w, h);
if (osd_font == 0)
{
#ifdef TARGET_PANDORA
osd_font = loadPNG(get_readonly_data_path("/font2.png"), w, h);
#else
osd_font = loadPNG(get_readonly_data_path("/pixmaps/font.png"), w, h);
if (osd_font == 0)
osd_font = loadPNG(get_readonly_data_path("/font.png"), w, h);
#endif
}
}
void gl_free_osd_resources()
{
if (osd_tex != 0) {
glcache.DeleteTextures(1, &osd_tex);
osd_tex = 0;
}
}
bool gl_create_resources()
{
if (gl.vbo.geometry != 0)
@ -1289,112 +1318,6 @@ static void ClearBG()
void DrawButton2(float* xy, bool state) { DrawButton(xy,state?0:255); }
static void DrawCenteredText(float yy, float scale, int transparency, const char* text)
// Draw a centered text. Font is loaded from font2.png file. Each char is 16*16 size, so scale it down so it's not too big
// Transparency 255=opaque, 0=not visible
{
Vertex vtx;
vtx.z=1;
float w=float(strlen(text)*14)*scale;
float x=320-w/2.0f;
float y=yy;
float h=16.0f*scale;
w=14.0f*scale;
float step=32.0f/512.0f;
float step2=4.0f/512.0f;
if (transparency<0) transparency=0;
if (transparency>255) transparency=255;
for (int i=0; i<strlen(text); i++) {
int c=text[i];
float u=float(c%16);
float v=float(c/16);
vtx.col[0]=vtx.col[1]=vtx.col[2]=255;
vtx.col[3]=transparency;
vtx.x=x; vtx.y=y;
vtx.u=u*step+step2; vtx.v=v*step+step2;
*pvrrc.verts.Append()=vtx;
vtx.x=x+w; vtx.y=y;
vtx.u=u*step+step-step2; vtx.v=v*step+step2;
*pvrrc.verts.Append()=vtx;
vtx.x=x; vtx.y=y+h;
vtx.u=u*step+step2; vtx.v=v*step+step-step2;
*pvrrc.verts.Append()=vtx;
vtx.x=x+w; vtx.y=y+h;
vtx.u=u*step+step-step2; vtx.v=v*step+step-step2;
*pvrrc.verts.Append()=vtx;
x+=w;
osd_count+=4;
}
}
static void DrawRightedText(float yy, float scale, int transparency, const char* text)
// Draw a text right justified. Font is loaded from font.png file. Each char is 16*16 size, so scale it down so it's not too big
// Transparency 255=opaque, 0=not visible
{
Vertex vtx;
vtx.z=1;
float w = float(strlen(text) * 14) * scale * scale_x;
float x = scale_x / 2 * (640 + screen_width * 480 / screen_height) - w;
float y = yy * scale_y;
float h = 16.0f * scale * scale_y;
w = 14.0f * scale * scale_x;
float step=32.0f/512.0f;
float step2=4.0f/512.0f;
if (transparency<0) transparency=0;
if (transparency>255) transparency=255;
for (int i=0; i<strlen(text); i++) {
int c=text[i];
float u=float(c%16);
float v=float(c/16);
vtx.col[0]=vtx.col[1]=vtx.col[2]=255;
vtx.col[3]=transparency;
vtx.x=x; vtx.y=y;
vtx.u=u*step+step2; vtx.v=v*step+step2;
*pvrrc.verts.Append()=vtx;
vtx.x=x+w; vtx.y=y;
vtx.u=u*step+step-step2; vtx.v=v*step+step2;
*pvrrc.verts.Append()=vtx;
vtx.x=x; vtx.y=y+h;
vtx.u=u*step+step2; vtx.v=v*step+step-step2;
*pvrrc.verts.Append()=vtx;
vtx.x=x+w; vtx.y=y+h;
vtx.u=u*step+step-step2; vtx.v=v*step+step-step2;
*pvrrc.verts.Append()=vtx;
x+=w;
osd_count+=4;
}
}
#ifdef TARGET_PANDORA
char OSD_Info[128];
int OSD_Delay=0;
char OSD_Counters[256];
int OSD_Counter=0;
#endif
static float LastFPSTime;
static int lastFrameCount = 0;
static float fps = -1;
@ -1427,28 +1350,6 @@ void OSD_HOOK()
DrawButton2(vjoy_pos[12],0);
}
#endif
#ifdef TARGET_PANDORA
if (OSD_Delay) {
DrawCenteredText(400, 1.0f, (OSD_Delay<255)?OSD_Delay:255, OSD_Info);
OSD_Delay--; //*TODO* Delay should be in ms, not in ticks...
}
if (OSD_Counter) {
DrawRightedText(20, 1.0f, 255, OSD_Counters);
}
#endif
if (settings.rend.ShowFPS && osd_font) {
if (os_GetSeconds() - LastFPSTime > 0.5) {
fps = (FrameCount - lastFrameCount) / (os_GetSeconds() - LastFPSTime);
LastFPSTime = os_GetSeconds();
lastFrameCount = FrameCount;
}
if (fps >= 0) {
char text[32];
sprintf(text, "F:%.1f", fps);
DrawRightedText(460, 1.f, 196, text);
}
}
}
#define OSD_TEX_W 512
@ -1518,40 +1419,19 @@ void OSD_DRAW(GLuint shader_program)
glDrawArrays(GL_TRIANGLE_STRIP,osd_base+i*4,4);
}
#endif
if (osd_font)
if (settings.rend.ShowFPS)
{
float u=0;
float v=0;
verify(glIsProgram(shader_program));
float dc_width=640;
float dc_height=480;
float dc2s_scale_h=screen_height/480.0f;
float ds2s_offs_x=(screen_width-dc2s_scale_h*640)/2;
glcache.BindTexture(GL_TEXTURE_2D,osd_font);
glcache.UseProgram(shader_program);
glcache.Enable(GL_BLEND);
glcache.Disable(GL_DEPTH_TEST);
glcache.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glcache.DepthMask(false);
glcache.DepthFunc(GL_ALWAYS);
glcache.Disable(GL_CULL_FACE);
glcache.Disable(GL_SCISSOR_TEST);
int dfa=osd_count/4;
for (int i=0;i<dfa;i++)
glDrawArrays(GL_TRIANGLE_STRIP,osd_base+i*4,4);
double now = os_GetSeconds();
if (now - LastFPSTime >= 1.0) {
fps = (FrameCount - lastFrameCount) / (now - LastFPSTime);
LastFPSTime = now;
lastFrameCount = FrameCount;
}
if (fps >= 0) {
char text[32];
sprintf(text, "F:%.1f", fps);
gui_display_fps(text);
}
}
}
@ -2033,6 +1913,7 @@ struct glesrend : Renderer
{
if (KillTex)
killtex();
gl_term();
}
bool Process(TA_context* ctx) { return ProcessFrame(ctx); }

View File

@ -142,6 +142,7 @@ enum ModifierVolumeMode { Xor, Or, Inclusion, Exclusion, ModeCount };
bool gl_init(void* wind, void* disp);
void gl_load_osd_resources();
void gl_free_osd_resources();
void gl_swap();
bool ProcessFrame(TA_context* ctx);
void UpdateFogTexture(u8 *fog_table, GLenum texture_slot, GLint fog_image_format);

View File

@ -312,6 +312,7 @@ static void gui_display_commands()
if (ImGui::Button("Exit", ImVec2(150 * scaling, 50 * scaling)))
{
dc_resume_emu(false);
gui_state = ClosedNoResume;
}
ImGui::End();
@ -445,10 +446,12 @@ static void detect_input_popup(int index, bool analog)
static void controller_mapping_popup(GamepadDevice *gamepad)
{
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
if (ImGui::BeginPopupModal("Controller Mapping", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
{
const float width = 350 * scaling;
const float height = 450 * scaling;
const float width = screen_width / 2;
const float col0_width = ImGui::CalcTextSize("Right DPad Downxxx").x + ImGui::GetStyle().FramePadding.x * 2.0f + ImGui::GetStyle().ItemSpacing.x;
const float col1_width = width
- ImGui::GetStyle().GrabMinSize
@ -466,7 +469,7 @@ static void controller_mapping_popup(GamepadDevice *gamepad)
ImGui::BeginGroup();
ImGui::Text(" Buttons ");
ImGui::BeginChildFrame(ImGui::GetID("buttons"), ImVec2(width, height), ImGuiWindowFlags_None);
ImGui::BeginChildFrame(ImGui::GetID("buttons"), ImVec2(width, 0), ImGuiWindowFlags_None);
ImGui::Columns(3, "bindings", false);
ImGui::SetColumnWidth(0, col0_width);
ImGui::SetColumnWidth(1, col1_width);
@ -499,7 +502,7 @@ static void controller_mapping_popup(GamepadDevice *gamepad)
ImGui::BeginGroup();
ImGui::Text(" Analog Axes ");
ImGui::BeginChildFrame(ImGui::GetID("analog"), ImVec2(width, height), ImGuiWindowFlags_None);
ImGui::BeginChildFrame(ImGui::GetID("analog"), ImVec2(width, 0), ImGuiWindowFlags_None);
ImGui::Columns(3, "bindings", false);
ImGui::SetColumnWidth(0, col0_width);
ImGui::SetColumnWidth(1, col1_width);
@ -530,6 +533,7 @@ static void controller_mapping_popup(GamepadDevice *gamepad)
ImGui::EndGroup();
ImGui::EndPopup();
}
ImGui::PopStyleVar();
}
static void gui_display_settings()
{
@ -915,3 +919,28 @@ void gui_display_ui()
else if (gui_state == ClosedNoResume)
gui_state = Closed;
}
void gui_display_fps(const char *string)
{
ImGui_Impl_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
ImGui::Begin("##fps", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
ImGui::SetWindowFontScale(2);
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), string);
ImGui::End();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
void gui_term()
{
inited = false;
ImGui_ImplOpenGL3_Shutdown();
ImGui::DestroyContext();
}

View File

@ -21,6 +21,8 @@
void gui_init();
void gui_open_settings();
bool gui_is_open();
bool gui_display_ui();
void gui_display_ui();
void gui_display_fps(const char *string);
void gui_term();
extern int screen_dpi;

View File

@ -64,6 +64,12 @@
android:screenOrientation="sensorLandscape"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
</activity>
<activity
android:name="com.reicast.emulator.NativeGLActivity"
android:configChanges="orientation|navigation|screenSize|screenLayout|uiMode|keyboard|keyboardHidden"
android:screenOrientation="sensorLandscape"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
</activity>
<activity
android:name="com.dropbox.client2.android.AuthActivity"
android:configChanges="orientation|keyboard"

View File

@ -0,0 +1,69 @@
package com.reicast.emulator;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.SurfaceHolder;
import com.reicast.emulator.config.EditVJoyActivity;
import com.reicast.emulator.emu.JNIdc;
import com.reicast.emulator.emu.NativeGLView;
public class BaseNativeGLActivity extends Activity implements SurfaceHolder.Callback {
protected boolean editVjoyMode;
protected NativeGLView mView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String fileName = null;
if (getIntent().getAction().equals("com.reicast.EMULATOR"))
fileName = Uri.decode(getIntent().getData().toString());
// Create the actual GL view
try {
mView = new NativeGLView(this, fileName, editVjoyMode);
setContentView(mView);
mView.getHolder().addCallback(this);
} catch (NativeGLView.EmulatorInitFailed e) {
finish();
}
}
@Override
protected void onPause() {
super.onPause();
JNIdc.pause();
}
@Override
protected void onResume() {
super.onResume();
JNIdc.resume();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mView != null) {
mView.stop();
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
JNIdc.rendinit(holder.getSurface(), w, h);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
JNIdc.rendinit(null, 0, 0);
}
}

View File

@ -52,6 +52,7 @@ public class MainActivity extends AppCompatActivity implements
private SharedPreferences mPrefs;
private boolean hasAndroidMarket = false;
private boolean activity_paused = false;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -118,7 +119,7 @@ public class MainActivity extends AppCompatActivity implements
if (!getFilesDir().exists()) {
getFilesDir().mkdir();
}
JNIdc.initEnvironment(getApplicationContext());
JNIdc.initEnvironment((Emulator)getApplicationContext());
// When viewing a resource, pass its URI to the native code for opening
Intent intent = getIntent();
@ -224,6 +225,9 @@ public class MainActivity extends AppCompatActivity implements
}
public void onEditorSelected(Uri uri) {
if (activity_paused)
return;
activity_paused = true;
String home_directory = mPrefs.getString(Config.pref_home,
Environment.getExternalStorageDirectory().getAbsolutePath());
@ -234,6 +238,9 @@ public class MainActivity extends AppCompatActivity implements
}
public void onGameSelected(Uri uri) {
if (activity_paused)
return;
activity_paused = true;
String home_directory = mPrefs.getString(Config.pref_home,
Environment.getExternalStorageDirectory().getAbsolutePath());
@ -245,7 +252,7 @@ public class MainActivity extends AppCompatActivity implements
}
Intent intent = new Intent("com.reicast.EMULATOR",
uri, getApplicationContext(), GL2JNIActivity.class);
uri, getApplicationContext(), NativeGLActivity.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
@ -369,6 +376,8 @@ public class MainActivity extends AppCompatActivity implements
@Override
protected void onResume() {
super.onResume();
activity_paused = false;
CloudFragment cloudfragment = (CloudFragment) getSupportFragmentManager()
.findFragmentByTag("CLOUD_FRAG");
if (cloudfragment != null && cloudfragment.isVisible()) {

View File

@ -0,0 +1,138 @@
package com.reicast.emulator;
import android.Manifest;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.ViewConfiguration;
import android.view.Window;
import com.reicast.emulator.emu.JNIdc;
import com.reicast.emulator.emu.NativeGLView;
import com.reicast.emulator.periph.InputDeviceManager;
import com.reicast.emulator.periph.SipEmulator;
import tv.ouya.console.api.OuyaController;
public class NativeGLActivity extends BaseNativeGLActivity implements ActivityCompat.OnRequestPermissionsResultCallback {
public static byte[] syms;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
InputDeviceManager.getInstance().startListening(getApplicationContext());
Emulator app = (Emulator)getApplicationContext();
app.getConfigurationPrefs(prefs);
OuyaController.init(this);
JNIdc.initControllers(Emulator.maple_devices, Emulator.maple_expansion_devices);
app.loadConfigurationPrefs();
super.onCreate(savedInstanceState);
//setup mic
if (Emulator.micPluggedIn()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ActivityCompat.requestPermissions(this,
new String[]{
Manifest.permission.RECORD_AUDIO
},
0);
}
else
{
onRequestPermissionsResult(0, new String[] { Manifest.permission.RECORD_AUDIO }, new int[] { PackageManager.PERMISSION_GRANTED });
}
}
}
private boolean showMenu() {
JNIdc.guiOpenSettings();
return true;
}
private boolean processJoystickInput(MotionEvent event, int axis) {
float v = event.getAxisValue(axis);
return InputDeviceManager.getInstance().joystickAxisEvent(event.getDeviceId(), axis, (int)Math.round(v * 32767.f));
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
boolean rc = processJoystickInput(event, MotionEvent.AXIS_X);
rc |= processJoystickInput(event, MotionEvent.AXIS_Y);
rc |= processJoystickInput(event, MotionEvent.AXIS_LTRIGGER);
rc |= processJoystickInput(event, MotionEvent.AXIS_RTRIGGER);
rc |= processJoystickInput(event, MotionEvent.AXIS_RX);
rc |= processJoystickInput(event, MotionEvent.AXIS_RY);
if (rc)
return true;
}
else if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER)
{
if (mView != null) {
float scl = mView.getHeight() / 480.0f;
float tx = (mView.getWidth() - 640.0f * scl) / 2;
int xpos = Math.round((event.getX() - tx) / scl);
int ypos = Math.round(event.getY() / scl);
InputDeviceManager.getInstance().mouseEvent(xpos, ypos, event.getButtonState());
}
}
return super.onGenericMotionEvent(event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (InputDeviceManager.getInstance().joystickButtonEvent(event.getDeviceId(), keyCode, false))
return true;
return super.onKeyUp(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// FIXME
showMenu();
}
if (InputDeviceManager.getInstance().joystickButtonEvent(event.getDeviceId(), keyCode, true))
return true;
if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
return showMenu();
}
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onDestroy() {
super.onDestroy();
InputDeviceManager.getInstance().stopListening();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (permissions.length > 0 && permissions[0] == Manifest.permission.RECORD_AUDIO && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
SipEmulator sip = new SipEmulator();
sip.startRecording();
JNIdc.setupMic(sip);
}
}
}

View File

@ -2,14 +2,14 @@ package com.reicast.emulator.config;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
@ -19,15 +19,15 @@ import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import com.reicast.emulator.BaseNativeGLActivity;
import com.reicast.emulator.MainActivity;
import com.reicast.emulator.R;
import com.reicast.emulator.emu.GL2JNIView;
import com.reicast.emulator.emu.JNIdc;
import com.reicast.emulator.emu.NativeGLView;
import com.reicast.emulator.emu.OnScreenMenu;
import com.reicast.emulator.periph.VJoy;
public class EditVJoyActivity extends Activity {
GL2JNIView mView;
public class EditVJoyActivity extends BaseNativeGLActivity {
PopupWindow popUp;
LayoutParams params;
@ -51,49 +51,15 @@ public class EditVJoyActivity extends Activity {
String fileName = null;
editVjoyMode = true;
// Call parent onCreate()
super.onCreate(icicle);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (getIntent().getAction().equals("com.reicast.EMULATOR"))
fileName = Uri.decode(getIntent().getData().toString());
// Create the actual GLES view
mView = new GL2JNIView(EditVJoyActivity.this, fileName, false,
prefs.getInt(Config.pref_renderdepth, 24), 0, true);
mView.setFpsDisplay(null);
setContentView(mView);
vjoy_d_cached = VJoy.readCustomVjoyValues(getApplicationContext());
JNIdc.show_osd();
}
@Override
protected void onPause() {
super.onPause();
mView.onPause();
}
@Override
protected void onStop() {
super.onStop();
// mView.onStop();
}
@Override
protected void onResume() {
super.onResume();
mView.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
mView.onDestroy();
}
PopupWindow createVJoyPopup() {
final PopupWindow popUp = new PopupWindow(this);
int p = OnScreenMenu.getPixelsFromDp(60, this);

View File

@ -172,7 +172,7 @@ public class GL2JNIView extends GLSurfaceView
throw new EmulatorInitFailed();
}
JNIdc.query(ethd);
// FIXME JNIdc.query((ethd);
// By default, GLSurfaceView() creates a RGB_565 opaque surface.
// If we want a translucent one, we should change the surface's
@ -570,9 +570,9 @@ public class GL2JNIView extends GLSurfaceView
{
gl.glViewport(0, 0, width, height);
if (Emulator.widescreen) {
JNIdc.rendinit(width, height);
// FIXME JNIdc.rendinit(width, height);
} else {
JNIdc.rendinit(height * (4 / 3), height);
// FIXME JNIdc.rendinit(height * (4 / 3), height);
}
}
@ -652,7 +652,7 @@ public class GL2JNIView extends GLSurfaceView
Player.play();
}
JNIdc.run(this);
// FIXME JNIdc.run(this);
}
int WriteBuffer(short[] samples, int wait)

View File

@ -1,22 +1,28 @@
package com.reicast.emulator.emu;
import android.view.Surface;
import com.reicast.emulator.Emulator;
import com.reicast.emulator.periph.SipEmulator;
public final class JNIdc
{
static { System.loadLibrary("dc"); }
public static native void initEnvironment(Object emulator);
public static native void initEnvironment(Emulator emulator);
public static native void config(String dirName);
public static native String init(String fileName);
public static native void query(Object thread);
public static native void run(Object track);
public static native void query(NativeGLView.EmuThread thread);
public static native void run(NativeGLView.EmuThread thread);
public static native void pause();
public static native void resume();
public static native void stop();
public static native void destroy();
public static native int send(int cmd, int opt);
public static native int data(int cmd, byte[] data);
public static native void rendinit(int w, int y);
public static native void rendinit(Surface surface, int w, int h);
public static native boolean rendframe();
public static native void vjoy(int id,float x, float y, float w, float h);
@ -24,7 +30,7 @@ public final class JNIdc
public static native void getControllers(int[] controllers, int[][] peripherals);
public static native void initControllers(int[] controllers, int[][] peripherals);
public static native void setupMic(Object sip);
public static native void setupMic(SipEmulator sip);
public static native void diskSwap(String disk);
public static native void vmuSwap();
public static native void setupVmu(Object sip);

View File

@ -0,0 +1,614 @@
package com.reicast.emulator.emu;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;
import com.reicast.emulator.Emulator;
import com.reicast.emulator.NativeGLActivity;
import com.reicast.emulator.R;
import com.reicast.emulator.config.Config;
import com.reicast.emulator.periph.InputDeviceManager;
import com.reicast.emulator.periph.VJoy;
import java.io.UnsupportedEncodingException;
public class NativeGLView extends SurfaceView {
private static String fileName;
private EmuThread ethd;
private Handler handler = new Handler();
Vibrator vib;
private boolean editVjoyMode = false;
private int selectedVjoyElement = -1;
private ScaleGestureDetector scaleGestureDetector;
public float[][] vjoy_d_custom;
private static final float[][] vjoy = VJoy.baseVJoy();
private boolean touchVibrationEnabled;
private int vibrationDuration;
Context context;
public void restoreCustomVjoyValues(float[][] vjoy_d_cached) {
vjoy_d_custom = vjoy_d_cached;
VJoy.writeCustomVjoyValues(vjoy_d_cached, context);
resetEditMode();
requestLayout();
}
public NativeGLView(Context context) {
super(context);
}
public NativeGLView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public NativeGLView(final Context context, String newFileName, boolean editVjoyMode) {
super(context);
this.context = context;
this.editVjoyMode = editVjoyMode;
setKeepScreenOn(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setOnSystemUiVisibilityChangeListener (new OnSystemUiVisibilityChangeListener() {
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility & SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
NativeGLView.this.setSystemUiVisibility(
SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| SYSTEM_UI_FLAG_FULLSCREEN
| SYSTEM_UI_FLAG_HIDE_NAVIGATION);
requestLayout();
}
}
});
}
vib = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
DisplayMetrics dm = context.getResources().getDisplayMetrics();
JNIdc.screenDpi((int)Math.max(dm.xdpi, dm.ydpi));
JNIdc.config(prefs.getString(Config.pref_home,
Environment.getExternalStorageDirectory().getAbsolutePath()));
ethd = new EmuThread(!Emulator.nosound);
touchVibrationEnabled = prefs.getBoolean(Config.pref_touchvibe, true);
vibrationDuration = prefs.getInt(Config.pref_vibrationDuration, 20);
this.setLayerType(prefs.getInt(Config.pref_rendertype, LAYER_TYPE_HARDWARE), null);
vjoy_d_custom = VJoy.readCustomVjoyValues(context);
scaleGestureDetector = new ScaleGestureDetector(context, new OscOnScaleGestureListener());
// This is the game we are going to run
fileName = newFileName;
if (NativeGLActivity.syms != null)
JNIdc.data(1, NativeGLActivity.syms);
final String initStatus = JNIdc.init(fileName);
if (initStatus != null)
{
handler.post(new Runnable() {
public void run() {
Log.e("initialization", "dc_init: " + initStatus);
Toast.makeText(context, initStatus, Toast.LENGTH_SHORT).show();
}
});
throw new EmulatorInitFailed();
}
JNIdc.query(ethd);
// Set the renderer responsible for frame rendering
//setRenderer(rend = new GL2JNIView.Renderer(this));
handler.post(new Runnable() {
@Override
public void run() {
// FIXME STOP AT SOME POINT!!
if (ethd.getState() == Thread.State.TERMINATED)
((Activity)getContext()).finish();
else {
JNIdc.rendframe();
handler.post(this);
}
}
});
ethd.start();
}
private void reset_analog()
{
int j=11;
vjoy[j+1][0]=vjoy[j][0]+vjoy[j][2]/2-vjoy[j+1][2]/2;
vjoy[j+1][1]=vjoy[j][1]+vjoy[j][3]/2-vjoy[j+1][3]/2;
JNIdc.vjoy(j+1, vjoy[j+1][0], vjoy[j+1][1], vjoy[j+1][2], vjoy[j+1][3]);
}
int get_anal(int j, int axis)
{
return (int) (((vjoy[j+1][axis]+vjoy[j+1][axis+2]/2) - vjoy[j][axis] - vjoy[j][axis+2]/2)*254/vjoy[j][axis+2]);
}
float vbase(float p, float m, float scl)
{
return (int) ( m - (m -p)*scl);
}
float vbase(float p, float scl)
{
return (int) (p*scl );
}
public boolean isTablet() {
return (getContext().getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
>= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
super.onLayout(changed, left, top, right, bottom);
//dcpx/cm = dcpx/px * px/cm
float magic = isTablet() ? 0.8f : 0.7f;
float scl = 480.0f/getHeight() * getContext().getResources().getDisplayMetrics().density * magic;
float scl_dc = getHeight()/480.0f;
float tx = ((getWidth()-640.0f*scl_dc)/2)/scl_dc;
float a_x = -tx+ 24*scl;
float a_y=- 24*scl;
float[][] vjoy_d = VJoy.getVjoy_d(vjoy_d_custom);
for (int i=0;i<vjoy.length;i++)
{
if (vjoy_d[i][0] == 288)
vjoy[i][0] = vjoy_d[i][0];
else if (vjoy_d[i][0]-vjoy_d_custom[getElementIdFromButtonId(i)][0] < 320)
vjoy[i][0] = a_x + vbase(vjoy_d[i][0],scl);
else
vjoy[i][0] = -a_x + vbase(vjoy_d[i][0],640,scl);
vjoy[i][1] = a_y + vbase(vjoy_d[i][1],480,scl);
vjoy[i][2] = vbase(vjoy_d[i][2],scl);
vjoy[i][3] = vbase(vjoy_d[i][3],scl);
}
for (int i=0;i<VJoy.VJoyCount;i++)
JNIdc.vjoy(i,vjoy[i][0],vjoy[i][1],vjoy[i][2],vjoy[i][3]);
reset_analog();
VJoy.writeCustomVjoyValues(vjoy_d_custom, context);
}
int anal_id=-1, lt_id=-1, rt_id=-1;
public void resetEditMode() {
editLastX = 0;
editLastY = 0;
}
private static int getElementIdFromButtonId(int buttonId) {
if (buttonId <= 3)
return 0; // DPAD
else if (buttonId <= 7)
return 1; // X, Y, B, A Buttons
else if (buttonId == 8)
return 2; // Start
else if (buttonId == 9)
return 3; // Left Trigger
else if (buttonId == 10)
return 4; // Right Trigger
else if (buttonId <= 12)
return 5; // Analog
else
return 0; // DPAD diagonials
}
public static int left_trigger = 0;
public static int right_trigger = 0;
public static int[] mouse_pos = { -32768, -32768 };
public static int mouse_btns = 0;
float editLastX = 0, editLastY = 0;
@Override public boolean onTouchEvent(final MotionEvent event)
{
if (event.getSource() != InputDevice.SOURCE_TOUCHSCREEN)
// Ignore real mice, trackballs, etc.
return false;
JNIdc.show_osd();
scaleGestureDetector.onTouchEvent(event);
float ty = 0.0f;
float scl = getHeight()/480.0f;
float tx = (getWidth()-640.0f*scl)/2;
int rv = 0xFFFF;
int aid = event.getActionMasked();
int pid = event.getActionIndex();
if (!JNIdc.guiIsOpen()) {
if (editVjoyMode && selectedVjoyElement != -1 && aid == MotionEvent.ACTION_MOVE && !scaleGestureDetector.isInProgress()) {
float x = (event.getX() - tx) / scl;
float y = (event.getY() - ty) / scl;
if (editLastX != 0 && editLastY != 0) {
float deltaX = x - editLastX;
float deltaY = y - editLastY;
vjoy_d_custom[selectedVjoyElement][0] += isTablet() ? deltaX * 2 : deltaX;
vjoy_d_custom[selectedVjoyElement][1] += isTablet() ? deltaY * 2 : deltaY;
requestLayout();
}
editLastX = x;
editLastY = y;
return true;
}
for (int i = 0; i < event.getPointerCount(); i++) {
float x = (event.getX(i) - tx) / scl;
float y = (event.getY(i) - ty) / scl;
if (anal_id != event.getPointerId(i)) {
if (aid == MotionEvent.ACTION_POINTER_UP && pid == i)
continue;
for (int j = 0; j < vjoy.length; j++) {
if (x > vjoy[j][0] && x <= (vjoy[j][0] + vjoy[j][2])) {
/*
//Disable pressure sensitive R/L
//Doesn't really work properly
int pre=(int)(event.getPressure(i)*255);
if (pre>20)
{
pre-=20;
pre*=7;
}
if (pre>255) pre=255;
*/
int pre = 255;
if (y > vjoy[j][1] && y <= (vjoy[j][1] + vjoy[j][3])) {
if (vjoy[j][4] >= -2) {
if (vjoy[j][5] == 0)
if (!editVjoyMode && touchVibrationEnabled)
vib.vibrate(vibrationDuration);
vjoy[j][5] = 2;
}
if (vjoy[j][4] == -3) {
if (editVjoyMode) {
selectedVjoyElement = 5; // Analog
resetEditMode();
} else {
vjoy[j + 1][0] = x - vjoy[j + 1][2] / 2;
vjoy[j + 1][1] = y - vjoy[j + 1][3] / 2;
JNIdc.vjoy(j + 1, vjoy[j + 1][0], vjoy[j + 1][1], vjoy[j + 1][2], vjoy[j + 1][3]);
anal_id = event.getPointerId(i);
}
} else if (vjoy[j][4] != -4) {
if (vjoy[j][4] == -1) {
if (editVjoyMode) {
selectedVjoyElement = 3; // Left Trigger
resetEditMode();
} else {
left_trigger = pre;
lt_id = event.getPointerId(i);
}
} else if (vjoy[j][4] == -2) {
if (editVjoyMode) {
selectedVjoyElement = 4; // Right Trigger
resetEditMode();
} else {
right_trigger = pre;
rt_id = event.getPointerId(i);
}
} else {
if (editVjoyMode) {
selectedVjoyElement = getElementIdFromButtonId(j);
resetEditMode();
} else
rv &= ~(int) vjoy[j][4];
}
}
}
}
}
} else {
if (x < vjoy[11][0])
x = vjoy[11][0];
else if (x > (vjoy[11][0] + vjoy[11][2]))
x = vjoy[11][0] + vjoy[11][2];
if (y < vjoy[11][1])
y = vjoy[11][1];
else if (y > (vjoy[11][1] + vjoy[11][3]))
y = vjoy[11][1] + vjoy[11][3];
int j = 11;
vjoy[j + 1][0] = x - vjoy[j + 1][2] / 2;
vjoy[j + 1][1] = y - vjoy[j + 1][3] / 2;
JNIdc.vjoy(j + 1, vjoy[j + 1][0], vjoy[j + 1][1], vjoy[j + 1][2], vjoy[j + 1][3]);
}
}
for (int j = 0; j < vjoy.length; j++) {
if (vjoy[j][5] == 2)
vjoy[j][5] = 1;
else if (vjoy[j][5] == 1)
vjoy[j][5] = 0;
}
}
switch(aid)
{
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
selectedVjoyElement = -1;
reset_analog();
anal_id = -1;
rv = 0xFFFF;
right_trigger = 0;
left_trigger = 0;
lt_id = -1;
rt_id = -1;
for (int j= 0 ;j < vjoy.length; j++)
vjoy[j][5] = 0;
mouse_btns = 0;
break;
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerId(event.getActionIndex())==anal_id)
{
reset_analog();
anal_id = -1;
}
else if (event.getPointerId(event.getActionIndex())==lt_id)
{
left_trigger = 0;
lt_id = -1;
}
else if (event.getPointerId(event.getActionIndex())==rt_id)
{
right_trigger = 0;
rt_id = -1;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_DOWN:
if (event.getPointerCount() != 1)
{
mouse_btns = 0;
}
else
{
MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
event.getPointerCoords(0, pointerCoords);
mouse_pos[0] = Math.round((pointerCoords.x - tx) / scl);
mouse_pos[1] = Math.round(pointerCoords.y / scl);
mouse_btns = MotionEvent.BUTTON_PRIMARY; // Mouse left button down
}
break;
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() == 1)
{
MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
event.getPointerCoords(0, pointerCoords);
mouse_pos[0] = Math.round((pointerCoords.x - tx) / scl);
mouse_pos[1] = Math.round(pointerCoords.y / scl);
}
break;
}
if (getResources().getString(R.string.flavor).equals("naomi")) // FIXME
{
if (left_trigger != 0)
rv &= ~VJoy.key_CONT_C; // Service key/coin
}
int joyx = get_anal(11, 0);
int joyy = get_anal(11, 1);
InputDeviceManager.getInstance().virtualGamepadEvent(rv, joyx, joyy, left_trigger, right_trigger);
// Only register the mouse event if no virtual gamepad button is down
if (!editVjoyMode && rv == 0xFFFF)
InputDeviceManager.getInstance().mouseEvent(mouse_pos[0], mouse_pos[1], mouse_btns);
return(true);
}
private class OscOnScaleGestureListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (editVjoyMode && selectedVjoyElement != -1) {
vjoy_d_custom[selectedVjoyElement][2] *= detector.getScaleFactor();
requestLayout();
return true;
}
return false;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
selectedVjoyElement = -1;
}
}
class EmuThread extends Thread
{
AudioTrack Player;
long pos; //write position
long size; //size in frames
private boolean sound;
EmuThread(boolean sound) {
this.sound = sound;
}
@Override public void run()
{
if (sound) {
int min=AudioTrack.getMinBufferSize(44100,AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT);
if (2048>min)
min=2048;
Player = new AudioTrack(
AudioManager.STREAM_MUSIC,
44100,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
min,
AudioTrack.MODE_STREAM
);
size=min/4;
pos=0;
Log.i("audcfg", "Audio streaming: buffer size " + min + " samples / " + min/44100.0 + " ms");
Player.play();
}
JNIdc.run(this);
}
int WriteBuffer(short[] samples, int wait)
{
if (sound) {
int newdata=samples.length/2;
if (wait==0)
{
//user bytes = write-read
//available = size - (write - play)
long used=pos-Player.getPlaybackHeadPosition();
long avail=size-used;
//Log.i("audcfg", "u: " + used + " a: " + avail);
if (avail<newdata)
return 0;
}
pos+=newdata;
Player.write(samples, 0, samples.length);
}
return 1;
}
void showMessage(final String msg) {
handler.post(new Runnable() {
public void run() {
Log.d(context.getPackageName(), msg);
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
});
}
int coreMessage(byte[] msg) {
try {
showMessage(new String(msg, "UTF-8"));
}
catch (UnsupportedEncodingException e) {
showMessage("coreMessage: Failed to display error");
}
return 1;
}
void Die() {
showMessage("Something went wrong and reicast crashed.\nPlease report this on the reicast forums.");
((Activity) context).finish();
}
void reiosInfo(String reiosId, String reiosSoftware) {
if (fileName != null) {
String gameId = reiosId.replaceAll("[^a-zA-Z0-9]+", "").toLowerCase();
SharedPreferences mPrefs = context.getSharedPreferences(gameId, Activity.MODE_PRIVATE);
Emulator app = (Emulator) context.getApplicationContext();
app.loadGameConfiguration(gameId);
// if (context instanceof GL2JNIActivity)
// ((GL2JNIActivity) context).getPad().joystick[0] = mPrefs.getBoolean(
// Gamepad.pref_js_merged + "_A",
// ((GL2JNIActivity) context).getPad().joystick[0]);
mPrefs.edit().putString(Config.game_title, reiosSoftware.trim()).apply();
}
}
}
public void stop() {
//JNIdc.destroy();
JNIdc.stop();
try {
ethd.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@TargetApi(19)
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
requestLayout();
}
}
public static class EmulatorInitFailed extends RuntimeException {
}
}

View File

@ -15,6 +15,7 @@ public final class InputDeviceManager implements InputManager.InputDeviceListene
public void startListening(Context applicationContext)
{
maple_port = 0;
if (applicationContext.getPackageManager().hasSystemFeature("android.hardware.touchscreen"))
joystickAdded(VIRTUAL_GAMEPAD_ID, "Virtual Gamepad", maple_port == 3 ? 3 : maple_port++);
int[] ids = InputDevice.getDeviceIds();

View File

@ -98,7 +98,7 @@ LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := dc
LOCAL_DISABLE_FORMAT_STRING_CHECKS=true
LOCAL_ASFLAGS := -fPIC -fvisibility=hidden
LOCAL_LDLIBS := -llog -lGLESv2 -lEGL -lz
LOCAL_LDLIBS := -llog -lGLESv2 -lEGL -lz -landroid
#-Wl,-Map,./res/raw/syms.mp3
LOCAL_ARM_MODE := arm

View File

@ -9,6 +9,8 @@
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <types.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include "hw/maple/maple_cfg.h"
#include "profiler/profiler.h"
@ -42,12 +44,14 @@ JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_init(JNIEnv *env,j
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_query(JNIEnv *env,jobject obj,jobject emu_thread) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_run(JNIEnv *env,jobject obj,jobject emu_thread) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pause(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_resume(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_stop(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_send(JNIEnv *env,jobject obj,jint id, jint v) __attribute__((visibility("default")));
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env,jobject obj,jint id, jbyteArray d) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinit(JNIEnv *env,jobject obj,jint w,jint h) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinit(JNIEnv *env, jobject obj, jobject surface, jint w, jint h) __attribute__((visibility("default")));
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframe(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_vjoy(JNIEnv * env, jobject obj,u32 id,float x, float y, float w, float h) __attribute__((visibility("default")));
@ -112,12 +116,16 @@ void SetApplicationPath(wchar *path);
int dc_init(int argc, wchar* argv[]);
void dc_run();
void dc_pause();
void dc_pause_emu();
void dc_resume_emu(bool continue_running);
void dc_stop();
void dc_term();
bool VramLockedWrite(u8* address);
bool rend_single_frame();
bool gles_init();
void rend_init_renderer();
void rend_term_renderer();
//extern cResetEvent rs,re;
extern int screen_width,screen_height;
@ -141,6 +149,7 @@ extern bool print_stats;
JavaVM* g_jvm;
jobject g_emulator;
jmethodID saveSettingsMid;
static ANativeWindow *g_window = 0;
void os_DoEvents()
{
@ -168,14 +177,12 @@ void UpdateVibration(u32 port, u32 value)
void *libPvr_GetRenderTarget()
{
// No X11 window in Android
return(0);
return g_window; // the surface to render to
}
void *libPvr_GetRenderSurface()
{
// No X11 display in Android
return(0);
return NULL; // default display
}
void common_linux_setup();
@ -393,9 +400,8 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_query(JNIEnv *env,job
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_run(JNIEnv *env,jobject obj,jobject emu_thread)
{
install_prof_handler(0);
jenv = env;
emu=emu_thread;
emu = env->NewGlobalRef(emu_thread);
jsamples=env->NewShortArray(SAMPLE_COUNT*2);
writemid=env->GetMethodID(env->GetObjectClass(emu),"WriteBuffer","([SI)I");
@ -403,6 +409,8 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_run(JNIEnv *env,jobje
dieMid=env->GetMethodID(env->GetObjectClass(emu),"Die","()V");
dc_run();
env->DeleteGlobalRef(emu);
}
int msgboxf(const wchar* text,unsigned int type,...) {
@ -416,10 +424,11 @@ int msgboxf(const wchar* text,unsigned int type,...) {
va_start(args, type);
vsprintf(temp, text, args);
va_end(args);
LOGE("%s", temp);
int byteCount = strlen(temp);
jbyteArray bytes = jenv->NewByteArray(byteCount);
jenv->SetByteArrayRegion(bytes, 0, byteCount, (jbyte *) temp);
jbyteArray bytes = attacher.env->NewByteArray(byteCount);
attacher.env->SetByteArrayRegion(bytes, 0, byteCount, (jbyte *) temp);
return (int)attacher.env->CallIntMethod(emu, coreMessageMid, bytes);
}
@ -441,6 +450,17 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setupVmu(JNIEnv *env,
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pause(JNIEnv *env,jobject obj)
{
dc_pause();
dc_pause_emu();
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_resume(JNIEnv *env,jobject obj)
{
dc_resume_emu(true);
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_stop(JNIEnv *env,jobject obj)
{
dc_stop();
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,jobject obj)
@ -510,25 +530,33 @@ JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env, job
return 0;
}
extern void gl_swap();
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframe(JNIEnv *env,jobject obj)
{
return (jboolean)rend_single_frame();
if (g_window == NULL)
return false;
jboolean ret = (jboolean)rend_single_frame();
if (ret)
gl_swap();
return ret;
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinit(JNIEnv * env, jobject obj, jint w,jint h)
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinit(JNIEnv * env, jobject obj, jobject surface, jint width, jint height)
{
screen_width = w;
screen_height = h;
//gles_term();
egl_stealcntx();
if (!gles_init())
die("OPENGL FAILED");
install_prof_handler(1);
if (surface != NULL)
{
g_window = ANativeWindow_fromSurface(env, surface);
rend_init_renderer();
screen_width = width;
screen_height = height;
}
else
{
rend_term_renderer();
ANativeWindow_release(g_window);
g_window = NULL;
}
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_vjoy(JNIEnv * env, jobject obj,u32 id,float x, float y, float w, float h)

View File

@ -206,7 +206,6 @@
AE2A2D7F21D6851E004B308D /* 7zFile.c in Sources */ = {isa = PBXBuildFile; fileRef = AE2A2D7321D6851D004B308D /* 7zFile.c */; };
AE2A2D8021D6851E004B308D /* 7zDec.c in Sources */ = {isa = PBXBuildFile; fileRef = AE2A2D7721D6851E004B308D /* 7zDec.c */; };
AE2A2D8321D7DB78004B308D /* CustomTexture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE2A2D8121D7DB77004B308D /* CustomTexture.cpp */; };
AE4FF4E1211588B5009BF202 /* font.png in Resources */ = {isa = PBXBuildFile; fileRef = AE4FF4E0211588B5009BF202 /* font.png */; };
AE649BB62188689000EF4A81 /* xxhash.c in Sources */ = {isa = PBXBuildFile; fileRef = AE649BB42188689000EF4A81 /* xxhash.c */; };
AE649BF3218C552500EF4A81 /* bitmath.c in Sources */ = {isa = PBXBuildFile; fileRef = AE649BCD218C552500EF4A81 /* bitmath.c */; };
AE649BF4218C552500EF4A81 /* bitreader.c in Sources */ = {isa = PBXBuildFile; fileRef = AE649BCE218C552500EF4A81 /* bitreader.c */; };
@ -669,7 +668,6 @@
AE2A2D7721D6851E004B308D /* 7zDec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = 7zDec.c; sourceTree = "<group>"; };
AE2A2D8121D7DB77004B308D /* CustomTexture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CustomTexture.cpp; sourceTree = "<group>"; };
AE2A2D8221D7DB78004B308D /* CustomTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomTexture.h; sourceTree = "<group>"; };
AE4FF4E0211588B5009BF202 /* font.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = font.png; path = ../../../linux/font.png; sourceTree = "<group>"; };
AE649BB42188689000EF4A81 /* xxhash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xxhash.c; sourceTree = "<group>"; };
AE649BB52188689000EF4A81 /* xxhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xxhash.h; sourceTree = "<group>"; };
AE649BBA218C552500EF4A81 /* all.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = all.h; sourceTree = "<group>"; };
@ -945,7 +943,6 @@
84A388B61B1CDD3E000166C0 /* Supporting Files */ = {
isa = PBXGroup;
children = (
AE4FF4E0211588B5009BF202 /* font.png */,
84A388B71B1CDD3E000166C0 /* Info.plist */,
);
name = "Supporting Files";
@ -2151,7 +2148,6 @@
84A388BB1B1CDD3E000166C0 /* Images.xcassets in Resources */,
84A388BE1B1CDD3E000166C0 /* MainMenu.xib in Resources */,
AE8C274121122E2500D4D8F4 /* Changelog.txt in Resources */,
AE4FF4E1211588B5009BF202 /* font.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -475,7 +475,6 @@ install: $(EXECUTABLE)
install -m644 man/reicast-joyconfig.1 $(DESTDIR)$(MAN_DIR)
install -m644 reicast.desktop $(DESTDIR)$(MENUENTRY_DIR)
install -m644 reicast.png $(DESTDIR)$(ICON_DIR)
install -m644 font.png $(DESTDIR)$(ICON_DIR)
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/$(EXECUTABLE_NAME)
@ -490,7 +489,6 @@ uninstall:
rm -f $(DESTDIR)$(MAN_DIR)/reicast-joyconfig.1
rm -f $(DESTDIR)$(MENUENTRY_DIR)/reicast.desktop
rm -f $(DESTDIR)$(ICON_DIR)/reicast.png
rm -f $(DESTDIR)$(ICON_DIR)/font.png
clean:
rm -f $(OBJECTS) $(EXECUTABLE) $(EXECUTABLE_STRIPPED) .map

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB