mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
Merge pull request #145 from kichikuou/android-upstream
Android support
This commit is contained in:
+183
@@ -0,0 +1,183 @@
|
||||
# CMakeLists.txt for Android build
|
||||
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(xsystem4 LANGUAGES C)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
cglm
|
||||
URL https://github.com/recp/cglm/archive/refs/tags/v0.9.2.tar.gz
|
||||
URL_HASH SHA1=cb8472aa8c2ab67b66378dbaf10c2c7368d4e4c3
|
||||
)
|
||||
FetchContent_Declare(
|
||||
SDL
|
||||
URL https://github.com/libsdl-org/SDL/releases/download/release-2.30.1/SDL2-2.30.1.tar.gz
|
||||
URL_HASH SHA1=9d502c495f3aa2d15446376e835a5e561ac32897
|
||||
)
|
||||
FetchContent_Declare(
|
||||
freetype
|
||||
GIT_REPOSITORY https://github.com/freetype/freetype.git
|
||||
GIT_TAG VER-2-13-2
|
||||
)
|
||||
FetchContent_MakeAvailable(cglm SDL freetype)
|
||||
|
||||
add_library(ffi STATIC IMPORTED)
|
||||
set_target_properties(ffi PROPERTIES
|
||||
IMPORTED_LOCATION ${CMAKE_STAGING_PREFIX}/lib/libffi.a
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_STAGING_PREFIX}/include)
|
||||
|
||||
find_package(SndFile REQUIRED)
|
||||
|
||||
add_subdirectory(subprojects/libsys4)
|
||||
|
||||
add_library(xsystem4 SHARED)
|
||||
|
||||
target_compile_definitions(xsystem4 PRIVATE
|
||||
_DEFAULT_SOURCE
|
||||
USE_GLES
|
||||
)
|
||||
|
||||
target_include_directories(xsystem4 PRIVATE include)
|
||||
|
||||
execute_process(
|
||||
COMMAND git rev-parse --short HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE VCS_TAG
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
configure_file(src/version.h.in version.h)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
target_sources(xsystem4 PRIVATE
|
||||
src/audio.c
|
||||
src/audio_meta.c
|
||||
src/audio_mixer.c
|
||||
src/asset_manager.c
|
||||
src/base64.c
|
||||
src/cJSON.c
|
||||
src/draw.c
|
||||
src/effect.c
|
||||
src/ffi.c
|
||||
src/font_freetype.c
|
||||
src/font_fnl.c
|
||||
src/format.c
|
||||
src/hacks.c
|
||||
src/heap.c
|
||||
src/id_pool.c
|
||||
src/input.c
|
||||
src/json.c
|
||||
src/movie_plmpeg.c
|
||||
src/msgqueue.c
|
||||
src/page.c
|
||||
src/resume.c
|
||||
src/savedata.c
|
||||
src/scene.c
|
||||
src/sprite.c
|
||||
src/swf.c
|
||||
src/system4.c
|
||||
src/text.c
|
||||
src/util.c
|
||||
src/video.c
|
||||
src/vm.c
|
||||
|
||||
src/3d/debug.c
|
||||
src/3d/model.c
|
||||
src/3d/parser.c
|
||||
src/3d/particle.c
|
||||
src/3d/reign.c
|
||||
src/3d/renderer.c
|
||||
|
||||
src/dungeon/dgn.c
|
||||
src/dungeon/dtx.c
|
||||
src/dungeon/dungeon.c
|
||||
src/dungeon/map.c
|
||||
src/dungeon/polyobj.c
|
||||
src/dungeon/renderer.c
|
||||
src/dungeon/skybox.c
|
||||
src/dungeon/tes.c
|
||||
|
||||
src/parts/construction.c
|
||||
src/parts/debug.c
|
||||
src/parts/flash.c
|
||||
src/parts/input.c
|
||||
src/parts/motion.c
|
||||
src/parts/parts.c
|
||||
src/parts/render.c
|
||||
src/parts/text.c
|
||||
src/parts/save.c
|
||||
|
||||
src/hll/ACXLoader.c
|
||||
src/hll/ADVSYS.c
|
||||
src/hll/AliceLogo.c
|
||||
src/hll/AliceLogo2.c
|
||||
src/hll/AliceLogo3.c
|
||||
src/hll/AliceLogo4.c
|
||||
src/hll/AliceLogo5.c
|
||||
src/hll/AnteaterADVEngine.c
|
||||
src/hll/BanMisc.c
|
||||
src/hll/Bitarray.c
|
||||
src/hll/CGManager.c
|
||||
src/hll/CharSpriteManager.c
|
||||
src/hll/ChipmunkSpriteEngine.c
|
||||
src/hll/ChrLoader.c
|
||||
src/hll/CommonSystemData.c
|
||||
src/hll/Confirm.c
|
||||
src/hll/Confirm2.c
|
||||
src/hll/Confirm3.c
|
||||
src/hll/CrayfishLogViewer.c
|
||||
src/hll/Cursor.c
|
||||
src/hll/Data.c
|
||||
src/hll/DataFile.c
|
||||
src/hll/DrawDungeon.c
|
||||
src/hll/DrawGraph.c
|
||||
src/hll/DrawMovie.c
|
||||
src/hll/DrawPluginManager.c
|
||||
src/hll/DrawSimpleText.c
|
||||
src/hll/File.c
|
||||
src/hll/File2.c
|
||||
src/hll/FileOperation.c
|
||||
src/hll/FillAngle.c
|
||||
src/hll/GoatGUIEngine.c
|
||||
src/hll/Gpx2Plus.c
|
||||
src/hll/GUIEngine.c
|
||||
src/hll/iarray.c
|
||||
src/hll/IbisInputEngine.c
|
||||
src/hll/InputDevice.c
|
||||
src/hll/InputString.c
|
||||
src/hll/KiwiSoundEngine.c
|
||||
src/hll/LoadCG.c
|
||||
src/hll/MainEXFile.c
|
||||
src/hll/MainSurface.c
|
||||
src/hll/MarmotModelEngine.c
|
||||
src/hll/Math.c
|
||||
src/hll/MapLoader.c
|
||||
src/hll/MenuMsg.c
|
||||
src/hll/MonsterInfo.c
|
||||
src/hll/MsgLogManager.c
|
||||
src/hll/MsgLogViewer.c
|
||||
src/hll/MsgSkip.c
|
||||
src/hll/OutputLog.c
|
||||
src/hll/PassRegister.c
|
||||
src/hll/PartsEngine.c
|
||||
src/hll/PlayDemo.c
|
||||
src/hll/PlayMovie.c
|
||||
src/hll/ReignEngine.c
|
||||
src/hll/SACT2.c
|
||||
src/hll/SengokuRanceFont.c
|
||||
src/hll/SoundFilePlayer.c
|
||||
src/hll/StoatSpriteEngine.c
|
||||
src/hll/StretchHelper.c
|
||||
src/hll/SystemService.c
|
||||
src/hll/SystemServiceEx.c
|
||||
src/hll/Timer.c
|
||||
src/hll/Toushin3Loader.c
|
||||
src/hll/VSFile.c
|
||||
)
|
||||
|
||||
target_link_libraries(xsystem4 PRIVATE
|
||||
m z SDL2 freetype ffi GLESv3 cglm SndFile::sndfile sys4)
|
||||
|
||||
target_compile_options(xsystem4 PRIVATE -Wno-unused-parameter)
|
||||
|
||||
install(TARGETS xsystem4 SDL2 freetype)
|
||||
@@ -129,8 +129,13 @@ void vm_stack_trace(void);
|
||||
_Noreturn void _vm_error(const char *fmt, ...);
|
||||
_Noreturn void vm_exit(int code);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Report the error with a message box and exit.
|
||||
#define VM_ERROR ERROR
|
||||
#else
|
||||
#define VM_ERROR(fmt, ...) \
|
||||
_vm_error("*ERROR*(%s:%s:%d): " fmt "\n", __FILE__, __func__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef VM_PRIVATE
|
||||
#include "little_endian.h"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_BITMAP_H
|
||||
#include <SDL.h>
|
||||
|
||||
#include "system4.h"
|
||||
#include "system4/hashtable.h"
|
||||
@@ -188,13 +189,33 @@ static float ft_font_size_char(struct font_size *size, uint32_t code)
|
||||
struct font *ft_font_load(const char *path)
|
||||
{
|
||||
struct font_ft *font = xcalloc(1, sizeof(struct font_ft));
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// On Android, path may be an asset name which FT_New_Face cannot read
|
||||
// directly, so use SDL_LoadFile to load the content into memory.
|
||||
size_t size;
|
||||
void *buf = SDL_LoadFile(path, &size);
|
||||
if (!buf) {
|
||||
free(font);
|
||||
return NULL;
|
||||
}
|
||||
if (FT_New_Memory_Face(ft_lib, buf, size, 0, &font->font)) {
|
||||
free(buf);
|
||||
free(font);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
if (FT_New_Face(ft_lib, path, 0, &font->font)) {
|
||||
free(font);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!font->font->charmap) {
|
||||
WARNING("Font '%s' doesn't contain unicode charmap", path);
|
||||
#ifdef __ANDROID__
|
||||
free(buf);
|
||||
#endif
|
||||
free(font);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+154
-5
@@ -18,6 +18,7 @@
|
||||
#include <time.h>
|
||||
#include <SDL.h>
|
||||
#include "system4.h"
|
||||
#include "queue.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/private.h"
|
||||
#include "input.h"
|
||||
@@ -145,6 +146,30 @@ bool keyboard_focus = true;
|
||||
#define MAX_CONTROLLERS 4
|
||||
static SDL_GameController *controllers[MAX_CONTROLLERS];
|
||||
|
||||
#ifdef __ANDROID__
|
||||
struct deferred_keyevent {
|
||||
STAILQ_ENTRY(deferred_keyevent) entry;
|
||||
SDL_Event e;
|
||||
};
|
||||
static STAILQ_HEAD(deferred_keyevent_queue, deferred_keyevent) deferred_keyevent_queue =
|
||||
STAILQ_HEAD_INITIALIZER(deferred_keyevent_queue);
|
||||
static uint32_t last_keyevent_timestamp;
|
||||
#define DEFERRED_KEY_DELAY 10
|
||||
#endif
|
||||
|
||||
// Stores a mouse button event synthesized from a touch event (valid if
|
||||
// .timestamp != 0). We defer such events to prevent games from handling
|
||||
// button down events before reading the pointer position.
|
||||
static SDL_MouseButtonEvent deferred_synthetic_mouse_event;
|
||||
#define SYNTHETIC_MOUSE_EVENT_DELAY 50
|
||||
|
||||
static uint32_t long_touch_start_timestamp;
|
||||
static SDL_FRect long_touch_finger_rect;
|
||||
#define LONG_TOUCH_DURATION 1000
|
||||
|
||||
static float scroll_gesture_y;
|
||||
#define SCROLL_GESTURE_SENSITIVITY 0.02f // 2% of screen height
|
||||
|
||||
static enum sact_keycode sdl_to_sact_button(int button)
|
||||
{
|
||||
switch (button) {
|
||||
@@ -224,6 +249,21 @@ static void mouse_event(SDL_MouseButtonEvent *e)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void synthetic_mouse_event(SDL_MouseButtonEvent *e)
|
||||
{
|
||||
if (e->state == SDL_PRESSED) {
|
||||
// Touch outside the viewport is treated as right-click.
|
||||
SDL_Point p = { .x = e->x, .y = e->y };
|
||||
if (SDL_PointInRect(&p, &sdl.viewport))
|
||||
key_state[VK_LBUTTON] = true;
|
||||
else
|
||||
key_state[VK_RBUTTON] = true;
|
||||
} else {
|
||||
key_state[VK_LBUTTON] = false;
|
||||
key_state[VK_RBUTTON] = false;
|
||||
}
|
||||
}
|
||||
|
||||
#define JOYAXIS_DEADZONE 13500
|
||||
|
||||
enum joyaxis_axis {
|
||||
@@ -475,8 +515,47 @@ void clear_editing_handler(void)
|
||||
editing_handler = NULL;
|
||||
}
|
||||
|
||||
static void fire_deferred_events(void)
|
||||
{
|
||||
uint32_t now = SDL_GetTicks();
|
||||
|
||||
// Flush the deferred mouse button event if it's older than 50ms.
|
||||
if (deferred_synthetic_mouse_event.timestamp &&
|
||||
deferred_synthetic_mouse_event.timestamp + SYNTHETIC_MOUSE_EVENT_DELAY < now) {
|
||||
synthetic_mouse_event(&deferred_synthetic_mouse_event);
|
||||
deferred_synthetic_mouse_event.timestamp = 0;
|
||||
}
|
||||
// Long touch emulates pressing the Ctrl key.
|
||||
if (long_touch_start_timestamp && long_touch_start_timestamp + LONG_TOUCH_DURATION < now) {
|
||||
key_state[VK_LBUTTON] = false;
|
||||
key_state[VK_CONTROL] = true;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Fire the deferred keyboard and text input events.
|
||||
while (!STAILQ_EMPTY(&deferred_keyevent_queue) && now >= last_keyevent_timestamp + DEFERRED_KEY_DELAY) {
|
||||
struct deferred_keyevent *ev = STAILQ_FIRST(&deferred_keyevent_queue);
|
||||
switch (ev->e.type) {
|
||||
case SDL_TEXTINPUT:
|
||||
if (input_handler)
|
||||
input_handler(ev->e.text.text);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
last_keyevent_timestamp = now;
|
||||
key_event(&ev->e.key, ev->e.type == SDL_KEYDOWN);
|
||||
break;
|
||||
}
|
||||
STAILQ_REMOVE_HEAD(&deferred_keyevent_queue, entry);
|
||||
free(ev);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void handle_events(void)
|
||||
{
|
||||
fire_deferred_events();
|
||||
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
@@ -509,18 +588,78 @@ void handle_events(void)
|
||||
case SDL_KEYDOWN:
|
||||
if (e.key.keysym.scancode == SDL_SCANCODE_F9)
|
||||
vm_stack_trace();
|
||||
key_event(&e.key, true);
|
||||
break;
|
||||
// fallthrough
|
||||
case SDL_KEYUP:
|
||||
key_event(&e.key, false);
|
||||
#ifdef __ANDROID__
|
||||
if (input_handler && e.key.timestamp < last_keyevent_timestamp + DEFERRED_KEY_DELAY) {
|
||||
// Input from virtual keyboard is sent as consecutive
|
||||
// SDL_KEYDOWN and SDL_KEYUP events. To give the game a chance
|
||||
// to see the previous key event, delay the event.
|
||||
struct deferred_keyevent *ev = xmalloc(sizeof(struct deferred_keyevent));
|
||||
ev->e = e;
|
||||
STAILQ_INSERT_TAIL(&deferred_keyevent_queue, ev, entry);
|
||||
} else {
|
||||
last_keyevent_timestamp = e.key.timestamp;
|
||||
key_event(&e.key, e.type == SDL_KEYDOWN);
|
||||
}
|
||||
#else
|
||||
key_event(&e.key, e.type == SDL_KEYDOWN);
|
||||
#endif
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
mouse_event(&e.button);
|
||||
if (e.button.which == SDL_TOUCH_MOUSEID) {
|
||||
if (deferred_synthetic_mouse_event.timestamp)
|
||||
synthetic_mouse_event(&deferred_synthetic_mouse_event);
|
||||
deferred_synthetic_mouse_event = e.button;
|
||||
} else {
|
||||
mouse_event(&e.button);
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
wheel_dir = e.wheel.y;
|
||||
break;
|
||||
case SDL_FINGERDOWN:
|
||||
if (SDL_GetNumTouchFingers(e.tfinger.touchId) >= 2) {
|
||||
// The user is about to start a multi-touch gesture.
|
||||
key_state[VK_LBUTTON] = false;
|
||||
key_state[VK_RBUTTON] = false;
|
||||
deferred_synthetic_mouse_event.timestamp = 0;
|
||||
long_touch_start_timestamp = 0;
|
||||
scroll_gesture_y = -1.0f;
|
||||
break;
|
||||
}
|
||||
long_touch_start_timestamp = e.tfinger.timestamp;
|
||||
// Movement within this rect (1% of the screen size from the touch
|
||||
// start position) will be ignored.
|
||||
long_touch_finger_rect = (SDL_FRect) {
|
||||
.x = e.tfinger.x - 0.01,
|
||||
.y = e.tfinger.y - 0.01,
|
||||
.w = 0.02,
|
||||
.h = 0.02
|
||||
};
|
||||
break;
|
||||
case SDL_FINGERMOTION:
|
||||
if (SDL_PointInFRect(&(SDL_FPoint){ e.tfinger.x, e.tfinger.y }, &long_touch_finger_rect))
|
||||
break;
|
||||
// Cancel the timer only if Ctrl emulation has not already started.
|
||||
if (!key_state[VK_CONTROL])
|
||||
long_touch_start_timestamp = 0;
|
||||
break;
|
||||
case SDL_FINGERUP:
|
||||
long_touch_start_timestamp = 0;
|
||||
key_state[VK_CONTROL] = false;
|
||||
break;
|
||||
case SDL_MULTIGESTURE:
|
||||
if (e.mgesture.numFingers == 2) {
|
||||
if (scroll_gesture_y < 0.0f)
|
||||
scroll_gesture_y = e.mgesture.y;
|
||||
float dy = scroll_gesture_y - e.mgesture.y;
|
||||
if (dy * dy > SCROLL_GESTURE_SENSITIVITY * SCROLL_GESTURE_SENSITIVITY) {
|
||||
wheel_dir = dy < 0 ? 1 : -1; // Swipe up to scroll down.
|
||||
scroll_gesture_y = e.mgesture.y;
|
||||
}
|
||||
}
|
||||
case SDL_CONTROLLERDEVICEADDED:
|
||||
if (e.cdevice.which < MAX_CONTROLLERS)
|
||||
controllers[e.cdevice.which] = SDL_GameControllerOpen(e.cdevice.which);
|
||||
@@ -533,8 +672,18 @@ void handle_events(void)
|
||||
controller_button_event(&e.cbutton);
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
if (input_handler)
|
||||
if (!input_handler) {
|
||||
break;
|
||||
#ifdef __ANDROID__
|
||||
} else if (!STAILQ_EMPTY(&deferred_keyevent_queue)) {
|
||||
// The order of key events and text events must be preserved.
|
||||
struct deferred_keyevent *ev = xmalloc(sizeof(struct deferred_keyevent));
|
||||
ev->e = e;
|
||||
STAILQ_INSERT_TAIL(&deferred_keyevent_queue, ev, entry);
|
||||
#endif
|
||||
} else {
|
||||
input_handler(e.text.text);
|
||||
}
|
||||
break;
|
||||
case SDL_TEXTEDITING:
|
||||
if (editing_handler)
|
||||
|
||||
@@ -401,11 +401,22 @@ static void windows_error_handler(const char *msg)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static void android_error_handler(const char *msg)
|
||||
{
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "xsystem4", msg, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef _WIN32
|
||||
sys_error_handler = windows_error_handler;
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
sys_error_handler = android_error_handler;
|
||||
#endif
|
||||
|
||||
initialize_instructions();
|
||||
char *ainfile;
|
||||
int err = AIN_SUCCESS;
|
||||
|
||||
+11
-4
@@ -68,11 +68,11 @@ struct texture main_surface;
|
||||
|
||||
static GLchar *read_shader_file(const char *path)
|
||||
{
|
||||
GLchar *source = file_read(path, NULL);
|
||||
GLchar *source = SDL_LoadFile(path, NULL);
|
||||
if (!source) {
|
||||
char full_path[PATH_MAX];
|
||||
snprintf(full_path, PATH_MAX, XSYS4_DATA_DIR "/%s", path);
|
||||
source = file_read(full_path, NULL);
|
||||
source = SDL_LoadFile(full_path, NULL);
|
||||
if (!source)
|
||||
ERROR("Failed to load shader file %s", full_path, strerror(errno));
|
||||
}
|
||||
@@ -98,7 +98,7 @@ GLuint gfx_load_shader_file(const char *path, GLenum type)
|
||||
glGetShaderInfoLog(shader, len, NULL, infolog);
|
||||
ERROR("Failed to compile shader %s: %s", path, infolog);
|
||||
}
|
||||
free((char*)source[1]);
|
||||
SDL_free((char*)source[1]);
|
||||
return shader;
|
||||
}
|
||||
|
||||
@@ -200,12 +200,19 @@ int gfx_init(void)
|
||||
#endif
|
||||
|
||||
sdl.format = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA32);
|
||||
uint32_t window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
|
||||
#ifdef __ANDROID__
|
||||
window_flags |= SDL_WINDOW_FULLSCREEN;
|
||||
SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight");
|
||||
#else
|
||||
window_flags |= SDL_WINDOW_RESIZABLE;
|
||||
#endif
|
||||
sdl.window = SDL_CreateWindow("XSystem4",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
config.view_width,
|
||||
config.view_height,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
||||
window_flags);
|
||||
if (!sdl.window)
|
||||
ERROR("SDL_CreateWindow failed: %s", SDL_GetError());
|
||||
|
||||
|
||||
+1
-1
Submodule subprojects/libsys4 updated: 0409f62789...9906c3c2b0
Reference in New Issue
Block a user