From 05e6fbbcca78f23777640e1128b1e8e09b1af8b4 Mon Sep 17 00:00:00 2001 From: Hugo Saint-Vignes Date: Wed, 3 Feb 2021 11:47:30 +0100 Subject: [PATCH 001/105] [ion/simulator/android] Fix haptic feddback type return --- ion/src/simulator/android/src/cpp/haptics_enabled.cpp | 7 +++++-- ion/src/simulator/shared/haptics.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ion/src/simulator/android/src/cpp/haptics_enabled.cpp b/ion/src/simulator/android/src/cpp/haptics_enabled.cpp index 3f2e77487..7623d5791 100644 --- a/ion/src/simulator/android/src/cpp/haptics_enabled.cpp +++ b/ion/src/simulator/android/src/cpp/haptics_enabled.cpp @@ -10,9 +10,12 @@ bool isEnabled() { JNIEnv * env = static_cast(SDL_AndroidGetJNIEnv()); jobject activity = static_cast(SDL_AndroidGetActivity()); jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity"); + // TODO : GetMethodID is relatively costly, and could be performed only once. jmethodID j_methodId = env->GetMethodID(j_class,"hapticFeedbackIsEnabled", "()Z"); - - return env->CallObjectMethod(activity, j_methodId); + if (j_methodId == 0) { + return false; + } + return (env->CallBooleanMethod(activity, j_methodId) != JNI_FALSE); } } diff --git a/ion/src/simulator/shared/haptics.cpp b/ion/src/simulator/shared/haptics.cpp index f0b61b2ea..3cd26fe66 100644 --- a/ion/src/simulator/shared/haptics.cpp +++ b/ion/src/simulator/shared/haptics.cpp @@ -25,7 +25,7 @@ void shutdown() { } void rumble() { - if (isEnabled() && sSDLHaptic) { + if (sSDLHaptic && isEnabled()) { SDL_HapticRumblePlay(sSDLHaptic, 1.0, 40); } } From 5a20d914df5a58bf205d72a16d325762504d118d Mon Sep 17 00:00:00 2001 From: Hugo Saint-Vignes Date: Wed, 3 Feb 2021 11:50:50 +0100 Subject: [PATCH 002/105] [ion/simulator/android] Fix haptic feedback memory leaks --- ion/src/simulator/android/src/cpp/haptics_enabled.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/android/src/cpp/haptics_enabled.cpp b/ion/src/simulator/android/src/cpp/haptics_enabled.cpp index 7623d5791..ea73fad07 100644 --- a/ion/src/simulator/android/src/cpp/haptics_enabled.cpp +++ b/ion/src/simulator/android/src/cpp/haptics_enabled.cpp @@ -15,7 +15,14 @@ bool isEnabled() { if (j_methodId == 0) { return false; } - return (env->CallBooleanMethod(activity, j_methodId) != JNI_FALSE); + bool result = (env->CallBooleanMethod(activity, j_methodId) != JNI_FALSE); + /* Local references are automatically deleted if a native function called from + * Java side returns. For SDL this native function is main() itself. Therefore + * references need to be manually deleted because otherwise the references + * will first be cleaned if main() returns (application exit). */ + env->DeleteLocalRef(j_class); + env->DeleteLocalRef(activity); + return result; } } From 73172f8d0c648338e899cfe58edbfb79f110b19c Mon Sep 17 00:00:00 2001 From: Hugo Saint-Vignes Date: Fri, 5 Feb 2021 17:47:29 +0100 Subject: [PATCH 003/105] [ion/simulator/android] Add assert, remove TODO Change-Id: Id818d0cd9a83727171ebe675ee50e35ef64e31d0 --- ion/src/simulator/android/src/cpp/haptics_enabled.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ion/src/simulator/android/src/cpp/haptics_enabled.cpp b/ion/src/simulator/android/src/cpp/haptics_enabled.cpp index ea73fad07..5c1fa0b74 100644 --- a/ion/src/simulator/android/src/cpp/haptics_enabled.cpp +++ b/ion/src/simulator/android/src/cpp/haptics_enabled.cpp @@ -1,6 +1,7 @@ #include "../../../shared/haptics.h" #include #include +#include namespace Ion { namespace Simulator { @@ -10,11 +11,8 @@ bool isEnabled() { JNIEnv * env = static_cast(SDL_AndroidGetJNIEnv()); jobject activity = static_cast(SDL_AndroidGetActivity()); jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity"); - // TODO : GetMethodID is relatively costly, and could be performed only once. jmethodID j_methodId = env->GetMethodID(j_class,"hapticFeedbackIsEnabled", "()Z"); - if (j_methodId == 0) { - return false; - } + assert(j_methodId != 0); bool result = (env->CallBooleanMethod(activity, j_methodId) != JNI_FALSE); /* Local references are automatically deleted if a native function called from * Java side returns. For SDL this native function is main() itself. Therefore From ba64458660eadc374b08dcafe85d481aeb7b8d84 Mon Sep 17 00:00:00 2001 From: Hugo Saint-Vignes Date: Mon, 8 Feb 2021 10:50:05 +0100 Subject: [PATCH 004/105] [ion/simulator/android] Delete JNI local references Change-Id: Idd4d6c769786fb595a357bcc3f54e67429ed1840 --- ion/src/simulator/android/src/cpp/images.cpp | 8 +++++++- ion/src/simulator/android/src/cpp/telemetry.cpp | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/android/src/cpp/images.cpp b/ion/src/simulator/android/src/cpp/images.cpp index 4b3cfd85c..75855a3a0 100644 --- a/ion/src/simulator/android/src/cpp/images.cpp +++ b/ion/src/simulator/android/src/cpp/images.cpp @@ -2,6 +2,7 @@ #include #include #include +#include SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) { JNIEnv * env = static_cast(SDL_AndroidGetJNIEnv()); @@ -13,6 +14,7 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi "retrieveBitmapAsset", "(Ljava/lang/String;)Landroid/graphics/Bitmap;" ); + assert(j_methodId != 0); jstring j_identifier = env->NewStringUTF(identifier); @@ -45,6 +47,10 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); AndroidBitmap_unlockPixels(env, j_bitmap); - + // See comment in haptics_enabled.cpp + env->DeleteLocalRef(j_bitmap); + env->DeleteLocalRef(j_identifier); + env->DeleteLocalRef(j_class); + env->DeleteLocalRef(activity); return texture; } diff --git a/ion/src/simulator/android/src/cpp/telemetry.cpp b/ion/src/simulator/android/src/cpp/telemetry.cpp index e273c73a3..54c2fb1c8 100644 --- a/ion/src/simulator/android/src/cpp/telemetry.cpp +++ b/ion/src/simulator/android/src/cpp/telemetry.cpp @@ -1,6 +1,7 @@ #include "../../../shared/telemetry.h" #include #include +#include static inline JNIEnv * AndroidJNI() { return static_cast(SDL_AndroidGetJNIEnv()); @@ -23,8 +24,10 @@ void init() { jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity"); jmethodID j_methodId = env->GetMethodID(j_class,"telemetryInit", "()V"); + assert(j_methodId != 0); env->CallVoidMethod(AndroidActivity(), j_methodId); + env->DeleteLocalRef(j_class); } void shutdown() { @@ -42,8 +45,10 @@ void reportScreen(const char * screenName) { jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity"); jmethodID j_methodId = env->GetMethodID(j_class, "telemetryScreen", "(Ljava/lang/String;)V"); + assert(j_methodId != 0); env->CallVoidMethod(AndroidActivity(), j_methodId, JS(screenName, env)); + env->DeleteLocalRef(j_class); } void reportEvent(const char * category, const char * action, const char * label) { @@ -51,8 +56,10 @@ void reportEvent(const char * category, const char * action, const char * label) jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity"); jmethodID j_methodId = env->GetMethodID(j_class, "telemetryEvent", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + assert(j_methodId != 0); env->CallVoidMethod(AndroidActivity(), j_methodId, JS(category, env), JS(action, env), JS(label, env)); + env->DeleteLocalRef(j_class); } } From bef8719ce050747cb04288b39704c92151909132 Mon Sep 17 00:00:00 2001 From: Hugo Saint-Vignes Date: Fri, 5 Feb 2021 17:10:07 +0100 Subject: [PATCH 005/105] [simulator/android] Handle getSerialNumber exception Based on SDL commit : https://github.com/spurious/SDL-mirror/commit/85c1d4079299a73b089744033546e32afc87919c Change-Id: Ie6810dae48f5944a515ee016f228ecf33edd8fc4 --- .../android/src/java/org/libsdl/app/HIDDeviceUSB.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/android/src/java/org/libsdl/app/HIDDeviceUSB.java b/ion/src/simulator/android/src/java/org/libsdl/app/HIDDeviceUSB.java index c9fc58ece..ad9b06ff4 100644 --- a/ion/src/simulator/android/src/java/org/libsdl/app/HIDDeviceUSB.java +++ b/ion/src/simulator/android/src/java/org/libsdl/app/HIDDeviceUSB.java @@ -51,7 +51,12 @@ class HIDDeviceUSB implements HIDDevice { public String getSerialNumber() { String result = null; if (Build.VERSION.SDK_INT >= 21) { - result = mDevice.getSerialNumber(); + try { + result = mDevice.getSerialNumber(); + } + catch (SecurityException exception) { + //Log.w(TAG, "App permissions mean we cannot get serial number for device " + getDeviceName() + " message: " + exception.getMessage()); + } } if (result == null) { result = ""; From 4f2ea99c85216f21126c723145fd3efa3f52b284 Mon Sep 17 00:00:00 2001 From: Hugo Saint-Vignes Date: Fri, 5 Feb 2021 17:52:32 +0100 Subject: [PATCH 006/105] build: Version 15.3.2 Change-Id: I9cf7a21e14ba042d33c06062f922d8c0191adc5c --- build/config.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config.mak b/build/config.mak index 5a2b9d319..67268b784 100644 --- a/build/config.mak +++ b/build/config.mak @@ -3,7 +3,7 @@ PLATFORM ?= device DEBUG ?= 0 -EPSILON_VERSION ?= 15.3.1 +EPSILON_VERSION ?= 15.3.2 EPSILON_APPS ?= calculation graph code statistics probability solver sequence regression settings EPSILON_I18N ?= en fr nl pt it de es EPSILON_COUNTRIES ?= WW CA DE ES FR GB IT NL PT US From fd0284756fbc7aedba28b982cbb4fbe7aaa66458 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 28 Aug 2020 19:38:04 -0400 Subject: [PATCH 007/105] [apps] Simplify locale lookup by code --- apps/Makefile | 5 +---- apps/i18n.py | 17 ++++++----------- apps/language_de_iso6391.universal.i18n | 1 - apps/language_en_iso6391.universal.i18n | 1 - apps/language_es_iso6391.universal.i18n | 1 - apps/language_fr_iso6391.universal.i18n | 1 - apps/language_it_iso6391.universal.i18n | 1 - apps/language_nl_iso6391.universal.i18n | 1 - apps/language_pt_iso6391.universal.i18n | 1 - apps/main.cpp | 2 +- 10 files changed, 8 insertions(+), 23 deletions(-) delete mode 100644 apps/language_de_iso6391.universal.i18n delete mode 100644 apps/language_en_iso6391.universal.i18n delete mode 100644 apps/language_es_iso6391.universal.i18n delete mode 100644 apps/language_fr_iso6391.universal.i18n delete mode 100644 apps/language_it_iso6391.universal.i18n delete mode 100644 apps/language_nl_iso6391.universal.i18n delete mode 100644 apps/language_pt_iso6391.universal.i18n diff --git a/apps/Makefile b/apps/Makefile index da4dc6bba..ef4ee2b76 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -65,9 +65,6 @@ language_preferences = apps/language_preferences.csv SFLAGS += -I$(BUILD_DIR) i18n_files += $(addprefix apps/language_,$(addsuffix .universal.i18n, $(EPSILON_I18N))) -ifeq ($(EPSILON_GETOPT),1) -i18n_files += $(addprefix apps/language_,$(addsuffix _iso6391.universal.i18n, $(EPSILON_I18N))) -endif i18n_files += $(call i18n_with_universal_for,shared) i18n_files += $(call i18n_with_universal_for,toolbox) @@ -77,7 +74,7 @@ $(eval $(call rule_for, \ I18N, \ apps/i18n.cpp, \ $(i18n_files), \ - $$(PYTHON) apps/i18n.py --codepoints $(code_points) --countrypreferences $(country_preferences) --languagepreferences $(language_preferences) --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --countries $$(EPSILON_COUNTRIES) --files $$^ --generateISO6391locales $$(EPSILON_GETOPT), \ + $$(PYTHON) apps/i18n.py --codepoints $(code_points) --countrypreferences $(country_preferences) --languagepreferences $(language_preferences) --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --countries $$(EPSILON_COUNTRIES) --files $$^, \ global \ )) diff --git a/apps/i18n.py b/apps/i18n.py index d03ec1ede..c1bdb41d6 100644 --- a/apps/i18n.py +++ b/apps/i18n.py @@ -23,13 +23,9 @@ parser.add_argument('--codepoints', help='the code_points.h file') parser.add_argument('--countrypreferences', help='the country_preferences.csv file') parser.add_argument('--languagepreferences', help='the language_preferences.csv file') parser.add_argument('--files', nargs='+', help='an i18n file') -parser.add_argument('--generateISO6391locales', type=int, nargs='+', help='whether to generate the ISO6391 codes for the languages (for instance "en" for english)') args = parser.parse_args() -def generate_ISO6391(): - return args.generateISO6391locales[0] == 1 - def has_glyph(glyph): return glyph in codepoints @@ -196,13 +192,6 @@ def print_header(data, path, locales, countries): lambda arg: arg.upper(), " Message::Language") - if generate_ISO6391(): - print_block_from_list(f, - "constexpr const Message LanguageISO6391Names[NumberOfLanguages] = {\n", - locales, - lambda arg: arg.upper(), - " Message::LanguageISO6391") - # Countries enumeration print_block_from_list(f, "enum class Country : uint8_t {\n", @@ -236,6 +225,12 @@ def print_header(data, path, locales, countries): f.write(line[:-2] + "),\n") f.write("};\n\n") + # Language ISO639-1 codes + f.write("constexpr const char * LanguageISO6391Codes[NumberOfLanguages] = {\n"); + for locale in locales: + f.write(" \"" + locale + "\",\n") + f.write("};\n\n") + f.write("}\n\n") f.write("#endif\n") f.close() diff --git a/apps/language_de_iso6391.universal.i18n b/apps/language_de_iso6391.universal.i18n deleted file mode 100644 index 8d811650d..000000000 --- a/apps/language_de_iso6391.universal.i18n +++ /dev/null @@ -1 +0,0 @@ -LanguageISO6391DE = "de" diff --git a/apps/language_en_iso6391.universal.i18n b/apps/language_en_iso6391.universal.i18n deleted file mode 100644 index 54972ae84..000000000 --- a/apps/language_en_iso6391.universal.i18n +++ /dev/null @@ -1 +0,0 @@ -LanguageISO6391EN = "en" diff --git a/apps/language_es_iso6391.universal.i18n b/apps/language_es_iso6391.universal.i18n deleted file mode 100644 index 615cbf978..000000000 --- a/apps/language_es_iso6391.universal.i18n +++ /dev/null @@ -1 +0,0 @@ -LanguageISO6391ES = "es" diff --git a/apps/language_fr_iso6391.universal.i18n b/apps/language_fr_iso6391.universal.i18n deleted file mode 100644 index 905e6f179..000000000 --- a/apps/language_fr_iso6391.universal.i18n +++ /dev/null @@ -1 +0,0 @@ -LanguageISO6391FR = "fr" diff --git a/apps/language_it_iso6391.universal.i18n b/apps/language_it_iso6391.universal.i18n deleted file mode 100644 index 6a72c7216..000000000 --- a/apps/language_it_iso6391.universal.i18n +++ /dev/null @@ -1 +0,0 @@ -LanguageISO6391IT = "it" diff --git a/apps/language_nl_iso6391.universal.i18n b/apps/language_nl_iso6391.universal.i18n deleted file mode 100644 index 0fef88fd0..000000000 --- a/apps/language_nl_iso6391.universal.i18n +++ /dev/null @@ -1 +0,0 @@ -LanguageISO6391NL = "nl" diff --git a/apps/language_pt_iso6391.universal.i18n b/apps/language_pt_iso6391.universal.i18n deleted file mode 100644 index 15218e760..000000000 --- a/apps/language_pt_iso6391.universal.i18n +++ /dev/null @@ -1 +0,0 @@ -LanguageISO6391PT = "pt" diff --git a/apps/main.cpp b/apps/main.cpp index 3a22fda5c..bb8776af0 100644 --- a/apps/main.cpp +++ b/apps/main.cpp @@ -36,7 +36,7 @@ void ion_main(int argc, const char * const argv[]) { continue; } for (int j = 0; j < I18n::NumberOfLanguages; j++) { - if (strcmp(requestedLanguageId, I18n::translate(I18n::LanguageISO6391Names[j])) == 0) { + if (strcmp(requestedLanguageId, I18n::LanguageISO6391Codes[j]) == 0) { GlobalPreferences::sharedGlobalPreferences()->setLanguage((I18n::Language)j); GlobalPreferences::sharedGlobalPreferences()->setCountry(I18n::DefaultCountryForLanguage[j]); break; From 784234690c408f5a93b433212531a808a5cec42c Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 3 Sep 2020 16:53:21 -0400 Subject: [PATCH 008/105] [ion/simulator] Sort Ion::Timing::msleep implementations --- ion/src/simulator/Makefile | 2 ++ ion/src/simulator/shared/dummy/timing_msleep.cpp | 4 ++++ ion/src/simulator/shared/main_headless.cpp | 4 ---- ion/src/simulator/shared/main_sdl.cpp | 5 ----- ion/src/simulator/shared/timing.cpp | 2 +- ion/src/simulator/shared/timing_msleep.cpp | 6 ++++++ 6 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 ion/src/simulator/shared/dummy/timing_msleep.cpp create mode 100644 ion/src/simulator/shared/timing_msleep.cpp diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index 473c0c7b3..8ffd83c51 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -7,6 +7,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/led.cpp \ dummy/serial_number.cpp \ dummy/stack.cpp \ + dummy/timing_msleep.cpp:+headless \ dummy/usb.cpp \ clipboard.cpp \ console_stdio.cpp:-consoledisplay \ @@ -25,6 +26,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ power.cpp \ random.cpp \ timing.cpp \ + timing_msleep.cpp:-headless \ ) ion_simulator_assets = background.jpg horizontal_arrow.png vertical_arrow.png round.png small_squircle.png large_squircle.png diff --git a/ion/src/simulator/shared/dummy/timing_msleep.cpp b/ion/src/simulator/shared/dummy/timing_msleep.cpp new file mode 100644 index 000000000..131e5abfd --- /dev/null +++ b/ion/src/simulator/shared/dummy/timing_msleep.cpp @@ -0,0 +1,4 @@ +#include + +void Ion::Timing::msleep(uint32_t ms) { +} diff --git a/ion/src/simulator/shared/main_headless.cpp b/ion/src/simulator/shared/main_headless.cpp index 8b8fec39c..803d11c17 100644 --- a/ion/src/simulator/shared/main_headless.cpp +++ b/ion/src/simulator/shared/main_headless.cpp @@ -5,7 +5,6 @@ #include "events.h" #include -#include #include #include #ifndef __WIN32__ @@ -28,9 +27,6 @@ extern "C" { char * _heap_end = _heap_start+kHeapSize; } -void Ion::Timing::msleep(uint32_t ms) { -} - int main(int argc, char * argv[]) { Ion::Simulator::Framebuffer::setActive(false); // Parse command-line arguments diff --git a/ion/src/simulator/shared/main_sdl.cpp b/ion/src/simulator/shared/main_sdl.cpp index c4085c17c..dbd4d1c1d 100644 --- a/ion/src/simulator/shared/main_sdl.cpp +++ b/ion/src/simulator/shared/main_sdl.cpp @@ -8,15 +8,10 @@ #include #include -#include #include #include #include -void Ion::Timing::msleep(uint32_t ms) { - SDL_Delay(ms); -} - int main(int argc, char * argv[]) { std::vector arguments(argv, argv + argc); diff --git a/ion/src/simulator/shared/timing.cpp b/ion/src/simulator/shared/timing.cpp index a9bf44567..cd11dcf61 100644 --- a/ion/src/simulator/shared/timing.cpp +++ b/ion/src/simulator/shared/timing.cpp @@ -1,4 +1,4 @@ -#include +#include #include static auto start = std::chrono::steady_clock::now(); diff --git a/ion/src/simulator/shared/timing_msleep.cpp b/ion/src/simulator/shared/timing_msleep.cpp new file mode 100644 index 000000000..f7ab7565e --- /dev/null +++ b/ion/src/simulator/shared/timing_msleep.cpp @@ -0,0 +1,6 @@ +#include +#include + +void Ion::Timing::msleep(uint32_t ms) { + SDL_Delay(ms); +} From 945a7b8d56d5b7a929a9b7374ce566c3f5ac7990 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 3 Sep 2020 16:59:34 -0400 Subject: [PATCH 009/105] [ion/simulator] Add a Window namespace --- ion/src/simulator/Makefile | 4 ++-- ion/src/simulator/shared/events_keyboard.cpp | 4 ++-- ion/src/simulator/shared/events_stdin.cpp | 1 - ion/src/simulator/shared/framebuffer_base.cpp | 6 +++--- ion/src/simulator/shared/keyboard_sdl.cpp | 6 +++--- ion/src/simulator/shared/layout.cpp | 6 +++--- ion/src/simulator/shared/{main.h => window.h} | 6 +++--- .../shared/{main_headless.cpp => window_headless.cpp} | 4 ++-- ion/src/simulator/shared/{main_sdl.cpp => window_sdl.cpp} | 8 ++++---- ion/src/simulator/web/helpers.cpp | 6 +++--- 10 files changed, 25 insertions(+), 26 deletions(-) rename ion/src/simulator/shared/{main.h => window.h} (63%) rename ion/src/simulator/shared/{main_headless.cpp => window_headless.cpp} (97%) rename ion/src/simulator/shared/{main_sdl.cpp => window_sdl.cpp} (96%) diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index 8ffd83c51..fec9da40c 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -21,12 +21,12 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ keyboard_dummy.cpp:+headless \ keyboard_sdl.cpp:-headless \ layout.cpp:-headless \ - main_headless.cpp:+headless \ - main_sdl.cpp:-headless \ power.cpp \ random.cpp \ timing.cpp \ timing_msleep.cpp:-headless \ + window_headless.cpp:+headless \ + window_sdl.cpp:-headless \ ) ion_simulator_assets = background.jpg horizontal_arrow.png vertical_arrow.png round.png small_squircle.png large_squircle.png diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 1087528f1..1a8c5fa2a 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -1,7 +1,7 @@ -#include "main.h" #include "platform.h" #include "layout.h" #include "events.h" +#include "window.h" #include #include @@ -183,7 +183,7 @@ Event getPlatformEvent() { while (SDL_PollEvent(&event)) { // The while is important: it'll do a fast-pass over all useless SDL events if (event.type == SDL_WINDOWEVENT) { - Ion::Simulator::Main::relayout(); + Ion::Simulator::Window::relayout(); break; } if (event.type == SDL_QUIT) { diff --git a/ion/src/simulator/shared/events_stdin.cpp b/ion/src/simulator/shared/events_stdin.cpp index 053118b23..ed6ed79b1 100644 --- a/ion/src/simulator/shared/events_stdin.cpp +++ b/ion/src/simulator/shared/events_stdin.cpp @@ -1,4 +1,3 @@ -#include "main.h" #include "platform.h" #include "framebuffer.h" #include "events.h" diff --git a/ion/src/simulator/shared/framebuffer_base.cpp b/ion/src/simulator/shared/framebuffer_base.cpp index 0eb597a5e..75e45796d 100644 --- a/ion/src/simulator/shared/framebuffer_base.cpp +++ b/ion/src/simulator/shared/framebuffer_base.cpp @@ -1,6 +1,6 @@ #include "framebuffer.h" +#include "window.h" #include -#include "main.h" /* Drawing on an SDL texture * In SDL2, drawing bitmap data happens through textures, whose data lives in @@ -23,14 +23,14 @@ static KDFrameBuffer sFrameBuffer = KDFrameBuffer(sPixels, KDSize(Ion::Display:: void pushRect(KDRect r, const KDColor * pixels) { if (sFrameBufferActive) { - Simulator::Main::setNeedsRefresh(); + Simulator::Window::setNeedsRefresh(); sFrameBuffer.pushRect(r, pixels); } } void pushRectUniform(KDRect r, KDColor c) { if (sFrameBufferActive) { - Simulator::Main::setNeedsRefresh(); + Simulator::Window::setNeedsRefresh(); sFrameBuffer.pushRectUniform(r, c); } } diff --git a/ion/src/simulator/shared/keyboard_sdl.cpp b/ion/src/simulator/shared/keyboard_sdl.cpp index 64e659df6..a0d02ab9f 100644 --- a/ion/src/simulator/shared/keyboard_sdl.cpp +++ b/ion/src/simulator/shared/keyboard_sdl.cpp @@ -1,6 +1,6 @@ -#include "main.h" -#include "platform.h" #include "layout.h" +#include "platform.h" +#include "window.h" #include #include @@ -58,7 +58,7 @@ State scan() { IonSimulatorCallbackDidScanKeyboard(); // Grab this opportunity to refresh the display if needed - Simulator::Main::refresh(); + Simulator::Window::refresh(); // Start with a "clean" state State state; diff --git a/ion/src/simulator/shared/layout.cpp b/ion/src/simulator/shared/layout.cpp index ef07451f8..df4c7ab88 100644 --- a/ion/src/simulator/shared/layout.cpp +++ b/ion/src/simulator/shared/layout.cpp @@ -1,5 +1,5 @@ #include "layout.h" -#include "main.h" +#include "window.h" #include "platform.h" #include #include @@ -239,13 +239,13 @@ void highlightKeyAt(SDL_Point * p) { } if (newHighlightedKeyIndex != sHighlightedKeyIndex) { sHighlightedKeyIndex = newHighlightedKeyIndex; - Main::setNeedsRefresh(); + Window::setNeedsRefresh(); } } void unhighlightKey() { sHighlightedKeyIndex = -1; - Main::setNeedsRefresh(); + Window::setNeedsRefresh(); } void drawHighlightedKey(SDL_Renderer * renderer) { diff --git a/ion/src/simulator/shared/main.h b/ion/src/simulator/shared/window.h similarity index 63% rename from ion/src/simulator/shared/main.h rename to ion/src/simulator/shared/window.h index 544f008f4..9af6af86a 100644 --- a/ion/src/simulator/shared/main.h +++ b/ion/src/simulator/shared/window.h @@ -1,9 +1,9 @@ -#ifndef ION_SIMULATOR_MAIN_H -#define ION_SIMULATOR_MAIN_H +#ifndef ION_SIMULATOR_WINDOW_H +#define ION_SIMULATOR_WINDOW_H namespace Ion { namespace Simulator { -namespace Main { +namespace Window { void init(); void quit(); diff --git a/ion/src/simulator/shared/main_headless.cpp b/ion/src/simulator/shared/window_headless.cpp similarity index 97% rename from ion/src/simulator/shared/main_headless.cpp rename to ion/src/simulator/shared/window_headless.cpp index 803d11c17..a8debe061 100644 --- a/ion/src/simulator/shared/main_headless.cpp +++ b/ion/src/simulator/shared/window_headless.cpp @@ -1,4 +1,4 @@ -#include "main.h" +#include "window.h" #include "display.h" #include "platform.h" #include "framebuffer.h" @@ -52,7 +52,7 @@ int main(int argc, char * argv[]) { namespace Ion { namespace Simulator { -namespace Main { +namespace Window { void init() { } diff --git a/ion/src/simulator/shared/main_sdl.cpp b/ion/src/simulator/shared/window_sdl.cpp similarity index 96% rename from ion/src/simulator/shared/main_sdl.cpp rename to ion/src/simulator/shared/window_sdl.cpp index dbd4d1c1d..437aeb291 100644 --- a/ion/src/simulator/shared/main_sdl.cpp +++ b/ion/src/simulator/shared/window_sdl.cpp @@ -1,4 +1,4 @@ -#include "main.h" +#include "window.h" #include "display.h" #include "haptics.h" #include "layout.h" @@ -25,14 +25,14 @@ int main(int argc, char * argv[]) { #if EPSILON_TELEMETRY Ion::Simulator::Telemetry::init(); #endif - Ion::Simulator::Main::init(); + Ion::Simulator::Window::init(); Ion::Simulator::Haptics::init(); ion_main(arguments.size(), &arguments[0]); // Shutdown Ion::Simulator::Haptics::shutdown(); - Ion::Simulator::Main::quit(); + Ion::Simulator::Window::quit(); #if EPSILON_TELEMETRY Ion::Simulator::Telemetry::shutdown(); #endif @@ -42,7 +42,7 @@ int main(int argc, char * argv[]) { namespace Ion { namespace Simulator { -namespace Main { +namespace Window { static SDL_Window * sWindow = nullptr; static SDL_Renderer * sRenderer = nullptr; diff --git a/ion/src/simulator/web/helpers.cpp b/ion/src/simulator/web/helpers.cpp index b3ced2b17..b6d5076c9 100644 --- a/ion/src/simulator/web/helpers.cpp +++ b/ion/src/simulator/web/helpers.cpp @@ -1,5 +1,5 @@ #include -#include "../shared/main.h" +#include "../shared/window.h" extern "C" const char * IonSoftwareVersion() { return Ion::softwareVersion(); @@ -10,6 +10,6 @@ extern "C" const char * IonPatchLevel() { } extern "C" void IonDisplayForceRefresh() { - Ion::Simulator::Main::setNeedsRefresh(); - Ion::Simulator::Main::refresh(); + Ion::Simulator::Window::setNeedsRefresh(); + Ion::Simulator::Window::refresh(); } From f10cd19616a036a4a03cec157641a6e9f419ffcc Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 3 Sep 2020 17:29:16 -0400 Subject: [PATCH 010/105] [ion/simulator] Factorize the main function --- ion/src/simulator/Makefile | 1 + ion/src/simulator/shared/main.cpp | 30 ++++++++++++++++++ ion/src/simulator/shared/window_headless.cpp | 28 +++++------------ ion/src/simulator/shared/window_sdl.cpp | 32 -------------------- 4 files changed, 39 insertions(+), 52 deletions(-) create mode 100644 ion/src/simulator/shared/main.cpp diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index fec9da40c..228a23764 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -21,6 +21,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ keyboard_dummy.cpp:+headless \ keyboard_sdl.cpp:-headless \ layout.cpp:-headless \ + main.cpp \ power.cpp \ random.cpp \ timing.cpp \ diff --git a/ion/src/simulator/shared/main.cpp b/ion/src/simulator/shared/main.cpp new file mode 100644 index 000000000..ebb823209 --- /dev/null +++ b/ion/src/simulator/shared/main.cpp @@ -0,0 +1,30 @@ +#include "haptics.h" +#include "platform.h" +#include "telemetry.h" +#include "window.h" +#include +#include + +int main(int argc, char * argv[]) { + std::vector arguments(argv, argv + argc); + + char * language = IonSimulatorGetLanguageCode(); + if (language != nullptr) { + arguments.push_back("--language"); + arguments.push_back(language); + } + +#if EPSILON_TELEMETRY + Ion::Simulator::Telemetry::init(); +#endif + Ion::Simulator::Window::init(); + Ion::Simulator::Haptics::init(); + ion_main(arguments.size(), &arguments[0]); + Ion::Simulator::Haptics::shutdown(); + Ion::Simulator::Window::quit(); +#if EPSILON_TELEMETRY + Ion::Simulator::Telemetry::shutdown(); +#endif + + return 0; +} diff --git a/ion/src/simulator/shared/window_headless.cpp b/ion/src/simulator/shared/window_headless.cpp index a8debe061..600affa65 100644 --- a/ion/src/simulator/shared/window_headless.cpp +++ b/ion/src/simulator/shared/window_headless.cpp @@ -1,18 +1,14 @@ #include "window.h" #include "display.h" -#include "platform.h" #include "framebuffer.h" #include "events.h" -#include -#include #include #ifndef __WIN32__ #include #include #endif -constexpr int kHeapSize = 131072; #ifdef NDEBUG /* TODO : Reduce stack memory cost in prime factorization to allow running * tests with the actual stack size */ @@ -21,22 +17,21 @@ constexpr int kStackSize = 32768*10; constexpr int kStackSize = 32768*10; // In DEBUG mode, we increase the stack to be able to pass the tests #endif -char heap[kHeapSize]; -extern "C" { - char * _heap_start = (char *)heap; - char * _heap_end = _heap_start+kHeapSize; -} +namespace Ion { +namespace Simulator { +namespace Window { -int main(int argc, char * argv[]) { +void init() { Ion::Simulator::Framebuffer::setActive(false); - // Parse command-line arguments + // This feature is lost for now + /* Parse command-line arguments for (int i=1; i i+1) { Ion::Simulator::Framebuffer::setActive(true); Ion::Simulator::Events::logAfter(atoi(argv[i+1])); } } - + */ #ifndef __WIN32__ // Handle signals signal(SIGABRT, Ion::Simulator::Events::dumpEventCount); @@ -45,16 +40,9 @@ int main(int argc, char * argv[]) { struct rlimit stackLimits = {kStackSize, kStackSize}; setrlimit(RLIMIT_STACK, &stackLimits); #endif - - ion_main(argc, argv); - return 0; } -namespace Ion { -namespace Simulator { -namespace Window { - -void init() { +void quit() { } void setNeedsRefresh() { diff --git a/ion/src/simulator/shared/window_sdl.cpp b/ion/src/simulator/shared/window_sdl.cpp index 437aeb291..63004387c 100644 --- a/ion/src/simulator/shared/window_sdl.cpp +++ b/ion/src/simulator/shared/window_sdl.cpp @@ -1,44 +1,12 @@ #include "window.h" #include "display.h" -#include "haptics.h" #include "layout.h" #include "platform.h" -#include "telemetry.h" #include "random.h" #include #include -#include #include -#include - -int main(int argc, char * argv[]) { - std::vector arguments(argv, argv + argc); - - char * language = IonSimulatorGetLanguageCode(); - if (language != nullptr) { - arguments.push_back("--language"); - arguments.push_back(language); - } - - // Init -#if EPSILON_TELEMETRY - Ion::Simulator::Telemetry::init(); -#endif - Ion::Simulator::Window::init(); - Ion::Simulator::Haptics::init(); - - ion_main(arguments.size(), &arguments[0]); - - // Shutdown - Ion::Simulator::Haptics::shutdown(); - Ion::Simulator::Window::quit(); -#if EPSILON_TELEMETRY - Ion::Simulator::Telemetry::shutdown(); -#endif - - return 0; -} namespace Ion { namespace Simulator { From 79985a019938b94a81f3de27bdc7262441b42aaf Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 3 Sep 2020 17:35:53 -0400 Subject: [PATCH 011/105] [ion/simulator] Proper argument parsing --- ion/src/simulator/shared/main.cpp | 72 +++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/ion/src/simulator/shared/main.cpp b/ion/src/simulator/shared/main.cpp index ebb823209..73c11883c 100644 --- a/ion/src/simulator/shared/main.cpp +++ b/ion/src/simulator/shared/main.cpp @@ -5,25 +5,71 @@ #include #include -int main(int argc, char * argv[]) { - std::vector arguments(argv, argv + argc); +/* The Args class allows parsing and editing command-line arguments + * The editing part allows us to add/remove arguments before forwarding them to + * ion_main. */ - char * language = IonSimulatorGetLanguageCode(); - if (language != nullptr) { - arguments.push_back("--language"); - arguments.push_back(language); +class Args { +public: + Args(int argc, char * argv[]) : m_arguments(argv, argv+argc) {} + bool has(const char * key) const; + const char * pop(const char * key); + void push(const char * key, const char * value) { + m_arguments.push_back(key); + m_arguments.push_back(value); + } + void push(const char * argument) { m_arguments.push_back(argument); } + int argc() const { return m_arguments.size(); } + const char * const * argv() const { return &m_arguments[0]; } +private: + std::vector::const_iterator find(const char * name) const; + std::vector m_arguments; +}; + +bool Args::has(const char * name) const { + return find(name) != m_arguments.end(); +} + +const char * Args::pop(const char * argument) { + auto nameIt = find(argument); + if (nameIt != m_arguments.end()) { + auto valueIt = std::next(nameIt); + if (valueIt != m_arguments.end()) { + const char * value = *valueIt; + m_arguments.erase(valueIt); + m_arguments.erase(nameIt); + return value; + } + m_arguments.erase(nameIt); + } + return nullptr; +} + +std::vector::const_iterator Args::find(const char * name) const { + return std::find_if( + m_arguments.begin(), m_arguments.end(), + [name](const char * s) { return strcmp(s, name) == 0; } + ); +} + +int main(int argc, char * argv[]) { + Args args(argc, argv); + + if (!args.has("--language")) { + args.push("--language", IonSimulatorGetLanguageCode()); } + using namespace Ion::Simulator; #if EPSILON_TELEMETRY - Ion::Simulator::Telemetry::init(); + Telemetry::init(); #endif - Ion::Simulator::Window::init(); - Ion::Simulator::Haptics::init(); - ion_main(arguments.size(), &arguments[0]); - Ion::Simulator::Haptics::shutdown(); - Ion::Simulator::Window::quit(); + Window::init(); + Haptics::init(); + ion_main(args.argc(), args.argv()); + Haptics::shutdown(); + Window::quit(); #if EPSILON_TELEMETRY - Ion::Simulator::Telemetry::shutdown(); + Telemetry::shutdown(); #endif return 0; From d02ce2dd167702f93e93d1fa9110467b5cce6834 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 3 Sep 2020 19:12:42 -0400 Subject: [PATCH 012/105] [ion] Sort dummy functions Dummy Ion-level functions should be in the top-level shared folder. And dummy functions for simulator headers should be in the simulator folder. --- .../shared/dummy/backlight.cpp | 0 .../{simulator => }/shared/dummy/battery.cpp | 0 .../{simulator => }/shared/dummy/display.cpp | 0 .../shared/dummy/exam_mode.cpp | 0 .../{simulator => }/shared/dummy/fcc_id.cpp | 0 ion/src/{simulator => }/shared/dummy/led.cpp | 0 .../shared/dummy/serial_number.cpp | 0 .../{simulator => }/shared/dummy/stack.cpp | 0 .../shared/dummy/timing_msleep.cpp | 0 ion/src/{simulator => }/shared/dummy/usb.cpp | 0 ion/src/simulator/Makefile | 25 +++++++++++-------- 11 files changed, 14 insertions(+), 11 deletions(-) rename ion/src/{simulator => }/shared/dummy/backlight.cpp (100%) rename ion/src/{simulator => }/shared/dummy/battery.cpp (100%) rename ion/src/{simulator => }/shared/dummy/display.cpp (100%) rename ion/src/{simulator => }/shared/dummy/exam_mode.cpp (100%) rename ion/src/{simulator => }/shared/dummy/fcc_id.cpp (100%) rename ion/src/{simulator => }/shared/dummy/led.cpp (100%) rename ion/src/{simulator => }/shared/dummy/serial_number.cpp (100%) rename ion/src/{simulator => }/shared/dummy/stack.cpp (100%) rename ion/src/{simulator => }/shared/dummy/timing_msleep.cpp (100%) rename ion/src/{simulator => }/shared/dummy/usb.cpp (100%) diff --git a/ion/src/simulator/shared/dummy/backlight.cpp b/ion/src/shared/dummy/backlight.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/backlight.cpp rename to ion/src/shared/dummy/backlight.cpp diff --git a/ion/src/simulator/shared/dummy/battery.cpp b/ion/src/shared/dummy/battery.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/battery.cpp rename to ion/src/shared/dummy/battery.cpp diff --git a/ion/src/simulator/shared/dummy/display.cpp b/ion/src/shared/dummy/display.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/display.cpp rename to ion/src/shared/dummy/display.cpp diff --git a/ion/src/simulator/shared/dummy/exam_mode.cpp b/ion/src/shared/dummy/exam_mode.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/exam_mode.cpp rename to ion/src/shared/dummy/exam_mode.cpp diff --git a/ion/src/simulator/shared/dummy/fcc_id.cpp b/ion/src/shared/dummy/fcc_id.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/fcc_id.cpp rename to ion/src/shared/dummy/fcc_id.cpp diff --git a/ion/src/simulator/shared/dummy/led.cpp b/ion/src/shared/dummy/led.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/led.cpp rename to ion/src/shared/dummy/led.cpp diff --git a/ion/src/simulator/shared/dummy/serial_number.cpp b/ion/src/shared/dummy/serial_number.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/serial_number.cpp rename to ion/src/shared/dummy/serial_number.cpp diff --git a/ion/src/simulator/shared/dummy/stack.cpp b/ion/src/shared/dummy/stack.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/stack.cpp rename to ion/src/shared/dummy/stack.cpp diff --git a/ion/src/simulator/shared/dummy/timing_msleep.cpp b/ion/src/shared/dummy/timing_msleep.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/timing_msleep.cpp rename to ion/src/shared/dummy/timing_msleep.cpp diff --git a/ion/src/simulator/shared/dummy/usb.cpp b/ion/src/shared/dummy/usb.cpp similarity index 100% rename from ion/src/simulator/shared/dummy/usb.cpp rename to ion/src/shared/dummy/usb.cpp diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index 228a23764..83140cf17 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -1,14 +1,18 @@ +ion_src += $(addprefix ion/src/shared/dummy/, \ + backlight.cpp \ + battery.cpp \ + display.cpp \ + exam_mode.cpp \ + fcc_id.cpp \ + led.cpp \ + power.cpp \ + serial_number.cpp \ + stack.cpp \ + timing_msleep.cpp:+headless \ + usb.cpp \ +) + ion_src += $(addprefix ion/src/simulator/shared/, \ - dummy/backlight.cpp \ - dummy/battery.cpp \ - dummy/display.cpp \ - dummy/exam_mode.cpp \ - dummy/fcc_id.cpp \ - dummy/led.cpp \ - dummy/serial_number.cpp \ - dummy/stack.cpp \ - dummy/timing_msleep.cpp:+headless \ - dummy/usb.cpp \ clipboard.cpp \ console_stdio.cpp:-consoledisplay \ crc32.cpp \ @@ -22,7 +26,6 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ keyboard_sdl.cpp:-headless \ layout.cpp:-headless \ main.cpp \ - power.cpp \ random.cpp \ timing.cpp \ timing_msleep.cpp:-headless \ From 90b25ecf517968182f2c137ae2b205862bc9252d Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 3 Sep 2020 19:19:24 -0400 Subject: [PATCH 013/105] [ion] Clean some dummy files --- ion/src/shared/dummy/backlight.cpp | 21 ++++++++++++++++----- ion/src/shared/dummy/display.cpp | 14 ++++++++++---- ion/src/shared/dummy/fcc_id.cpp | 1 - ion/src/shared/dummy/led.cpp | 6 ++++-- ion/src/shared/dummy/power.cpp | 13 +++++++++++++ ion/src/shared/dummy/usb.cpp | 18 ++++++++++++------ ion/src/simulator/shared/power.cpp | 7 ------- 7 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 ion/src/shared/dummy/power.cpp delete mode 100644 ion/src/simulator/shared/power.cpp diff --git a/ion/src/shared/dummy/backlight.cpp b/ion/src/shared/dummy/backlight.cpp index 657122482..651f3bf23 100644 --- a/ion/src/shared/dummy/backlight.cpp +++ b/ion/src/shared/dummy/backlight.cpp @@ -1,13 +1,24 @@ #include -uint8_t Ion::Backlight::brightness() { +namespace Ion { +namespace Backlight { + +uint8_t brightness() { return 0; } -void Ion::Backlight::setBrightness(uint8_t b) {} +void setBrightness(uint8_t b) { +} -void Ion::Backlight::init() {} +void init() { +} -bool Ion::Backlight::isInitialized() { return true; } +bool isInitialized() { + return true; +} -void Ion::Backlight::shutdown() {} +void shutdown() { +} + +} +} diff --git a/ion/src/shared/dummy/display.cpp b/ion/src/shared/dummy/display.cpp index de76e0d91..a5b075ceb 100644 --- a/ion/src/shared/dummy/display.cpp +++ b/ion/src/shared/dummy/display.cpp @@ -1,16 +1,22 @@ #include -void Ion::Display::POSTPushMulticolor(int rootNumberTiles, int tileSize) { +namespace Ion { +namespace Display { + +void POSTPushMulticolor(int rootNumberTiles, int tileSize) { } -int Ion::Display::displayUniformTilingSize10(KDColor c) { +int displayUniformTilingSize10(KDColor c) { return 0; } -int Ion::Display::displayColoredTilingSize10() { +int displayColoredTilingSize10() { return 0; } -bool Ion::Display::waitForVBlank() { +bool waitForVBlank() { return true; } + +} +} diff --git a/ion/src/shared/dummy/fcc_id.cpp b/ion/src/shared/dummy/fcc_id.cpp index 4635993d0..daf908c81 100644 --- a/ion/src/shared/dummy/fcc_id.cpp +++ b/ion/src/shared/dummy/fcc_id.cpp @@ -1,5 +1,4 @@ #include -#include const char * Ion::fccId() { return "NA"; diff --git a/ion/src/shared/dummy/led.cpp b/ion/src/shared/dummy/led.cpp index 91e0cb0b4..034d048a0 100644 --- a/ion/src/shared/dummy/led.cpp +++ b/ion/src/shared/dummy/led.cpp @@ -7,9 +7,11 @@ KDColor getColor() { return KDColorBlack; } -void setColor(KDColor c) {} +void setColor(KDColor c) { +} -void setBlinking(uint16_t period, float dutyCycle) {} +void setBlinking(uint16_t period, float dutyCycle) { +} KDColor updateColorWithPlugAndCharge() { return KDColorBlack; diff --git a/ion/src/shared/dummy/power.cpp b/ion/src/shared/dummy/power.cpp new file mode 100644 index 000000000..f95af846f --- /dev/null +++ b/ion/src/shared/dummy/power.cpp @@ -0,0 +1,13 @@ +#include + +namespace Ion { +namespace Power { + +void suspend(bool checkIfOnOffKeyReleased) { +} + +void standby() { +} + +} +} diff --git a/ion/src/shared/dummy/usb.cpp b/ion/src/shared/dummy/usb.cpp index b118ae964..ce3c0fd2c 100644 --- a/ion/src/shared/dummy/usb.cpp +++ b/ion/src/shared/dummy/usb.cpp @@ -1,21 +1,27 @@ #include -bool Ion::USB::isPlugged() { +namespace Ion { +namespace USB { + +bool isPlugged() { return false; } -bool Ion::USB::isEnumerated() { +bool isEnumerated() { return false; } -void Ion::USB::clearEnumerationInterrupt() { +void clearEnumerationInterrupt() { } -void Ion::USB::DFU(bool) { +void DFU(bool) { } -void Ion::USB::enable() { +void enable() { } -void Ion::USB::disable() { +void disable() { +} + +} } diff --git a/ion/src/simulator/shared/power.cpp b/ion/src/simulator/shared/power.cpp deleted file mode 100644 index be918d1df..000000000 --- a/ion/src/simulator/shared/power.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include - -void Ion::Power::suspend(bool checkIfOnOffKeyReleased) { -} - -void Ion::Power::standby() { -} From baf8b8cbf084fdac8028302dea41e268c2aaabf5 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 3 Sep 2020 22:57:12 -0400 Subject: [PATCH 014/105] [ion/simulator] Clean the Keyboard implementation --- ion/src/shared/dummy/keyboard.cpp | 11 +++++ ion/src/simulator/Makefile | 5 +- ion/src/simulator/shared/dummy/keyboard.cpp | 19 ++++++++ ion/src/simulator/shared/events_keyboard.cpp | 4 +- .../shared/{keyboard_sdl.cpp => keyboard.cpp} | 48 +++++++++---------- ion/src/simulator/shared/keyboard.h | 19 ++++++++ ion/src/simulator/shared/keyboard_dummy.cpp | 18 ------- ion/src/simulator/shared/platform.h | 3 -- ion/src/simulator/web/Makefile | 1 + ion/src/simulator/web/exports.cpp | 15 ++++++ ion/src/simulator/web/exports.h | 16 +++++++ 11 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 ion/src/shared/dummy/keyboard.cpp create mode 100644 ion/src/simulator/shared/dummy/keyboard.cpp rename ion/src/simulator/shared/{keyboard_sdl.cpp => keyboard.cpp} (75%) create mode 100644 ion/src/simulator/shared/keyboard.h delete mode 100644 ion/src/simulator/shared/keyboard_dummy.cpp create mode 100644 ion/src/simulator/web/exports.cpp create mode 100644 ion/src/simulator/web/exports.h diff --git a/ion/src/shared/dummy/keyboard.cpp b/ion/src/shared/dummy/keyboard.cpp new file mode 100644 index 000000000..914ce0dcf --- /dev/null +++ b/ion/src/shared/dummy/keyboard.cpp @@ -0,0 +1,11 @@ +#include + +namespace Ion { +namespace Keyboard { + +State scan() { + return State(); +} + +} +} diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index 83140cf17..af814cf74 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -4,6 +4,7 @@ ion_src += $(addprefix ion/src/shared/dummy/, \ display.cpp \ exam_mode.cpp \ fcc_id.cpp \ + keyboard.cpp:+headless \ led.cpp \ power.cpp \ serial_number.cpp \ @@ -13,6 +14,7 @@ ion_src += $(addprefix ion/src/shared/dummy/, \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ + dummy/keyboard.cpp:+headless \ clipboard.cpp \ console_stdio.cpp:-consoledisplay \ crc32.cpp \ @@ -22,8 +24,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ events_stdin.cpp:+headless \ framebuffer_base.cpp \ framebuffer_png.cpp:+headless \ - keyboard_dummy.cpp:+headless \ - keyboard_sdl.cpp:-headless \ + keyboard.cpp:-headless \ layout.cpp:-headless \ main.cpp \ random.cpp \ diff --git a/ion/src/simulator/shared/dummy/keyboard.cpp b/ion/src/simulator/shared/dummy/keyboard.cpp new file mode 100644 index 000000000..d2b2a8819 --- /dev/null +++ b/ion/src/simulator/shared/dummy/keyboard.cpp @@ -0,0 +1,19 @@ +#include "../keyboard.h" + +namespace Ion { +namespace Simulator { +namespace Keyboard { + +void keyDown(Ion::Keyboard::Key k) { +} + +void keyUp(Ion::Keyboard::Key k) { +} + +bool scanHandlesSDLKey(SDL_Scancode key) { + return false; +} + +} +} +} diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_keyboard.cpp index 1a8c5fa2a..026394050 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_keyboard.cpp @@ -1,4 +1,4 @@ -#include "platform.h" +#include "keyboard.h" #include "layout.h" #include "events.h" #include "window.h" @@ -191,7 +191,7 @@ Event getPlatformEvent() { break; } if (event.type == SDL_KEYDOWN) { - if (IonSimulatorSDLKeyDetectedByScan(event.key.keysym.scancode)) { + if (Simulator::Keyboard::scanHandlesSDLKey(event.key.keysym.scancode)) { continue; } result = eventFromSDLKeyboardEvent(event.key); diff --git a/ion/src/simulator/shared/keyboard_sdl.cpp b/ion/src/simulator/shared/keyboard.cpp similarity index 75% rename from ion/src/simulator/shared/keyboard_sdl.cpp rename to ion/src/simulator/shared/keyboard.cpp index a0d02ab9f..62f955bce 100644 --- a/ion/src/simulator/shared/keyboard_sdl.cpp +++ b/ion/src/simulator/shared/keyboard.cpp @@ -5,23 +5,8 @@ #include #include -#if EPSILON_SDL_SCREEN_ONLY static Ion::Keyboard::State sKeyboardState; -void IonSimulatorKeyboardKeyDown(int keyNumber) { - Ion::Keyboard::Key key = static_cast(keyNumber); - sKeyboardState.setKey(key); -} - -void IonSimulatorKeyboardKeyUp(int keyNumber) { - Ion::Keyboard::Key key = static_cast(keyNumber); - sKeyboardState.clearKey(key); -} -#endif - -namespace Ion { -namespace Keyboard { - class KeySDLKeyPair { public: constexpr KeySDLKeyPair(Ion::Keyboard::Key key, SDL_Scancode SDLKey) : @@ -50,6 +35,9 @@ constexpr static KeySDLKeyPair sKeyPairs[] = { constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); +namespace Ion { +namespace Keyboard { + State scan() { // We need to tell SDL to get new state from the host OS SDL_PumpEvents(); @@ -60,12 +48,8 @@ State scan() { // Grab this opportunity to refresh the display if needed Simulator::Window::refresh(); - // Start with a "clean" state - State state; -#if EPSILON_SDL_SCREEN_ONLY - // In this case, keyboard states are sent over another channel. - state = sKeyboardState; -#else + State state = sKeyboardState; +#if !EPSILON_SDL_SCREEN_ONLY // Register a key for the mouse, if any Key k = Simulator::Layout::getHighlightedKey(); if (SDL_GetMouseState(nullptr, nullptr) && SDL_BUTTON(SDL_BUTTON_LEFT)) { @@ -87,11 +71,27 @@ State scan() { } } -bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key) { - for (int i = 0; i < Ion::Keyboard::sNumberOfKeyPairs; i++) { - if (key == Ion::Keyboard::sKeyPairs[i].SDLKey()) { +namespace Ion { +namespace Simulator { +namespace Keyboard { + +void keyDown(Ion::Keyboard::Key k) { + sKeyboardState.setKey(k); +} + +void keyUp(Ion::Keyboard::Key k) { + sKeyboardState.clearKey(k); +} + +bool scanHandlesSDLKey(SDL_Scancode key) { + for (int i = 0; i < sNumberOfKeyPairs; i++) { + if (key == sKeyPairs[i].SDLKey()) { return true; } } return false; } + +} +} +} diff --git a/ion/src/simulator/shared/keyboard.h b/ion/src/simulator/shared/keyboard.h new file mode 100644 index 000000000..c722612aa --- /dev/null +++ b/ion/src/simulator/shared/keyboard.h @@ -0,0 +1,19 @@ +#ifndef ION_SIMULATOR_KEYBOARD_H +#define ION_SIMULATOR_KEYBOARD_H + +#include +#include + +namespace Ion { +namespace Simulator { +namespace Keyboard { + +void keyDown(Ion::Keyboard::Key k); +void keyUp(Ion::Keyboard::Key k); +bool scanHandlesSDLKey(SDL_Scancode key); + +} +} +} + +#endif diff --git a/ion/src/simulator/shared/keyboard_dummy.cpp b/ion/src/simulator/shared/keyboard_dummy.cpp deleted file mode 100644 index 2e4b56fe6..000000000 --- a/ion/src/simulator/shared/keyboard_dummy.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include "platform.h" - -void IonSimulatorKeyboardKeyDown(int keyNumber) { -} - -void IonSimulatorKeyboardKeyUp(int keyNumber) { -} - -namespace Ion { -namespace Keyboard { - -State scan() { - return 0; -} - -} -} diff --git a/ion/src/simulator/shared/platform.h b/ion/src/simulator/shared/platform.h index 494c83c23..38612e888 100644 --- a/ion/src/simulator/shared/platform.h +++ b/ion/src/simulator/shared/platform.h @@ -15,12 +15,9 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi char * IonSimulatorGetLanguageCode(); #if EPSILON_SDL_SCREEN_ONLY -void IonSimulatorKeyboardKeyDown(int keyNumber); -void IonSimulatorKeyboardKeyUp(int keyNumber); void IonSimulatorEventsPushEvent(int eventNumber); #endif -bool IonSimulatorSDLKeyDetectedByScan(SDL_Scancode key); void IonSimulatorCallbackDidRefresh(); void IonSimulatorCallbackDidScanKeyboard(); diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index 4032ef4df..2c0cea801 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -16,6 +16,7 @@ LDFLAGS += --pre-js ion/src/simulator/web/preamble_env.js ion_src += $(addprefix ion/src/simulator/web/, \ callback.cpp \ clipboard_helper.cpp \ + exports.cpp \ helpers.cpp \ ) diff --git a/ion/src/simulator/web/exports.cpp b/ion/src/simulator/web/exports.cpp new file mode 100644 index 000000000..6f2e0b4e8 --- /dev/null +++ b/ion/src/simulator/web/exports.cpp @@ -0,0 +1,15 @@ +#include "exports.h" +#include "../shared/keyboard.h" + +void IonSimulatorKeyboardKeyDown(int keyNumber) { + Ion::Keyboard::Key key = static_cast(keyNumber); + Ion::Simulator::Keyboard::keyDown(key); +} + +void IonSimulatorKeyboardKeyUp(int keyNumber) { + Ion::Keyboard::Key key = static_cast(keyNumber); + Ion::Simulator::Keyboard::keyUp(key); +} + +void IonSimulatorEventsPushEvent(int eventNumber) { +} diff --git a/ion/src/simulator/web/exports.h b/ion/src/simulator/web/exports.h new file mode 100644 index 000000000..e0eeb59f9 --- /dev/null +++ b/ion/src/simulator/web/exports.h @@ -0,0 +1,16 @@ +#ifndef ION_SIMULATOR_WEB_EXPORTS_H +#define ION_SIMULATOR_WEB_EXPORTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +void IonSimulatorKeyboardKeyDown(int keyNumber); +void IonSimulatorKeyboardKeyUp(int keyNumber); +void IonSimulatorEventsPushEvent(int eventNumber); + +#ifdef __cplusplus +} +#endif + +#endif From 62aafa75970d812b08e19b770688a8664f724c9a Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 3 Sep 2020 22:59:57 -0400 Subject: [PATCH 015/105] [ion] Fix a comment --- ion/src/simulator/shared/window_sdl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ion/src/simulator/shared/window_sdl.cpp b/ion/src/simulator/shared/window_sdl.cpp index 63004387c..9f1b9c5da 100644 --- a/ion/src/simulator/shared/window_sdl.cpp +++ b/ion/src/simulator/shared/window_sdl.cpp @@ -32,8 +32,8 @@ void init() { SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, #if EPSILON_SDL_SCREEN_ONLY - // When rendering the screen only, make a non-resizeable window that whose - // size matches the screen's + // When rendering the screen only, make a non-resizeable window whose size + // matches the screen's Ion::Display::Width, Ion::Display::Height, 0 // Default flags: no high-dpi, not resizeable. From cbc3951ab1d86f5fe054986d8541b179ab4f313f Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 3 Sep 2020 23:00:20 -0400 Subject: [PATCH 016/105] [ion] Add an event journal It's pretty much just two callbacks that one can hook into to get some events in or out of Ion. It adds a couple useless checks and pointers to any build and could be hidden behind a feature flag, but the extra weight is minimal. --- ion/include/ion/events.h | 9 +++++++++ ion/src/shared/events_keyboard.cpp | 28 +++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index 95ad80ff4..6c1c64d76 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -53,6 +53,15 @@ enum class ShiftAlphaStatus { // Timeout is decremented Event getEvent(int * timeout); +class Journal { +public: + virtual void pushEvent(Event e) = 0; + virtual Event popEvent() = 0; +}; + +void replayFrom(Journal * l); +void logTo(Journal * l); + ShiftAlphaStatus shiftAlphaStatus(); void setShiftAlphaStatus(ShiftAlphaStatus s); void removeShift(); diff --git a/ion/src/shared/events_keyboard.cpp b/ion/src/shared/events_keyboard.cpp index 2c7c91c56..c368b785e 100644 --- a/ion/src/shared/events_keyboard.cpp +++ b/ion/src/shared/events_keyboard.cpp @@ -50,7 +50,11 @@ void resetLongRepetition() { ComputeAndSetRepetionFactor(sEventRepetitionCount); } -Event getEvent(int * timeout) { +static Keyboard::Key keyFromState(Keyboard::State state) { + return static_cast(63 - __builtin_clzll(state)); +} + +static inline Event innerGetEvent(int * timeout) { assert(*timeout > delayBeforeRepeat); assert(*timeout > delayBetweenRepeat); int time = 0; @@ -114,5 +118,27 @@ Event getEvent(int * timeout) { } } +static Journal * sSourceJournal = nullptr; +static Journal * sDestinationJournal = nullptr; +void replayFrom(Journal * l) { sSourceJournal = l; } +void logTo(Journal * l) { sDestinationJournal = l; } + +Event getEvent(int * timeout) { + if (sSourceJournal != nullptr) { + Event e = sSourceJournal->popEvent(); + if (e == None) { + sSourceJournal = nullptr; + } else { + return e; + } + } + Event e = innerGetEvent(timeout); + if (sDestinationJournal != nullptr && e != None) { + sDestinationJournal->pushEvent(e); + } + return e; +} + + } } From d4984722cf37c5606e5882219f8eb6eb925b2216 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 4 Sep 2020 13:57:36 -0400 Subject: [PATCH 017/105] [ion/simulator] Rename the events_platform file --- ion/src/shared/dummy/events_platform.cpp | 11 ++++ ion/src/simulator/Makefile | 4 +- ion/src/simulator/shared/events.h | 9 --- ...vents_keyboard.cpp => events_platform.cpp} | 60 ------------------ ion/src/simulator/shared/events_stdin.cpp | 61 ------------------- 5 files changed, 13 insertions(+), 132 deletions(-) create mode 100644 ion/src/shared/dummy/events_platform.cpp rename ion/src/simulator/shared/{events_keyboard.cpp => events_platform.cpp} (83%) delete mode 100644 ion/src/simulator/shared/events_stdin.cpp diff --git a/ion/src/shared/dummy/events_platform.cpp b/ion/src/shared/dummy/events_platform.cpp new file mode 100644 index 000000000..a0b1c6cd8 --- /dev/null +++ b/ion/src/shared/dummy/events_platform.cpp @@ -0,0 +1,11 @@ +#include + +namespace Ion { +namespace Events { + +Event getPlatformEvent() { + return None; +} + +} +} diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index af814cf74..dff72a250 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -14,14 +14,14 @@ ion_src += $(addprefix ion/src/shared/dummy/, \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ + dummy/events_platform.cpp:+headless \ dummy/keyboard.cpp:+headless \ clipboard.cpp \ console_stdio.cpp:-consoledisplay \ crc32.cpp \ display.cpp:-headless \ events.cpp \ - events_keyboard.cpp:-headless \ - events_stdin.cpp:+headless \ + events_platform.cpp:-headless \ framebuffer_base.cpp \ framebuffer_png.cpp:+headless \ keyboard.cpp:-headless \ diff --git a/ion/src/simulator/shared/events.h b/ion/src/simulator/shared/events.h index 1770c40ba..131df3807 100644 --- a/ion/src/simulator/shared/events.h +++ b/ion/src/simulator/shared/events.h @@ -5,15 +5,6 @@ #include namespace Ion { -namespace Simulator { -namespace Events { - -void dumpEventCount(int i); -void logAfter(int numberOfEvents); - -} -} - namespace Events { static constexpr size_t sharedExternalTextBufferSize = sizeof(SDL_TextInputEvent::text); diff --git a/ion/src/simulator/shared/events_keyboard.cpp b/ion/src/simulator/shared/events_platform.cpp similarity index 83% rename from ion/src/simulator/shared/events_keyboard.cpp rename to ion/src/simulator/shared/events_platform.cpp index 026394050..072b3bc2b 100644 --- a/ion/src/simulator/shared/events_keyboard.cpp +++ b/ion/src/simulator/shared/events_platform.cpp @@ -9,60 +9,6 @@ #include #include -#if EPSILON_SDL_SCREEN_ONLY - -template -class Queue { -public: - Queue() : m_first(&m_elements[0]), m_last(&m_elements[0]) {} - int size() { - if (m_last >= m_first) { - return m_last - m_first; - } else { - return m_last - (m_first - N); - } - } - - void enqueue(T element) { - if (size() > N) { - // Queue is full - return; - } - *m_last = element; - m_last = next(m_last); - } - - T dequeue() { - if (size() <= 0) { - // Dequeueing an empty queue - return T(); - } - T e = *m_first; - m_first = next(m_first); - return e; - } - -private: - T * next(T * p) { - if (p >= m_elements + N) { - return m_elements; - } else { - return p + 1; - } - } - T * m_first; - T * m_last; - T m_elements[N]; -}; - -static Queue sEventQueue; - -void IonSimulatorEventsPushEvent(int eventNumber) { - sEventQueue.enqueue(Ion::Events::Event(eventNumber)); -} - -#endif - namespace Ion { namespace Events { @@ -172,12 +118,6 @@ static Event eventFromSDLTextInputEvent(SDL_TextInputEvent event) { } Event getPlatformEvent() { -#if EPSILON_SDL_SCREEN_ONLY - if (sEventQueue.size() > 0) { - Event event = sEventQueue.dequeue(); - return event; - } -#endif SDL_Event event; Event result = None; while (SDL_PollEvent(&event)) { diff --git a/ion/src/simulator/shared/events_stdin.cpp b/ion/src/simulator/shared/events_stdin.cpp deleted file mode 100644 index ed6ed79b1..000000000 --- a/ion/src/simulator/shared/events_stdin.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "platform.h" -#include "framebuffer.h" -#include "events.h" - -#include -#include - -#include -#include - -void IonSimulatorEventsPushEvent(int eventNumber) { -} - -static int sLogAfterNumberOfEvents = -1; -static int sEventCount = 0; - -namespace Ion { -namespace Events { - -Event getPlatformEvent() { - Ion::Events::Event event = Ion::Events::None; - while (!(event.isDefined() && event.isKeyboardEvent())) { - int c = getchar(); - if (c == EOF) { - printf("Finished processing %d events\n", sEventCount); - event = Ion::Events::Termination; - break; - } - event = Ion::Events::Event(c); - } -#if EPSILON_SIMULATOR_HAS_LIBPNG - if (sEventCount++ > sLogAfterNumberOfEvents && sLogAfterNumberOfEvents >= 0) { - char filename[32]; - sprintf(filename, "event%d.png", sEventCount); - Ion::Simulator::Framebuffer::writeToFile(filename); -#ifndef NDEBUG - printf("Event %d is %s\n", sEventCount, event.name()); -#endif - } -#endif - return event; -} - -} -} - -namespace Ion { -namespace Simulator { -namespace Events { - -void dumpEventCount(int i) { - printf("Current event index: %d\n", sEventCount); -} - -void logAfter(int numberOfEvents) { - sLogAfterNumberOfEvents = numberOfEvents; -} - -} -} -} From 1a4cb3ad37daf5f1c257d2e3f0d55e3ceaee7997 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 4 Sep 2020 14:03:18 -0400 Subject: [PATCH 018/105] [ion/simulator] Add a Journal implementation --- ion/src/simulator/android/Makefile | 1 + ion/src/simulator/ios/Makefile | 1 + ion/src/simulator/linux/Makefile | 1 + ion/src/simulator/macos/Makefile | 1 + ion/src/simulator/shared/dummy/journal.cpp | 20 +++++++++++ ion/src/simulator/shared/journal.cpp | 39 ++++++++++++++++++++++ ion/src/simulator/shared/journal.h | 19 +++++++++++ ion/src/simulator/shared/main.cpp | 2 ++ ion/src/simulator/web/Makefile | 1 + ion/src/simulator/windows/Makefile | 1 + 10 files changed, 86 insertions(+) create mode 100644 ion/src/simulator/shared/dummy/journal.cpp create mode 100644 ion/src/simulator/shared/journal.cpp create mode 100644 ion/src/simulator/shared/journal.h diff --git a/ion/src/simulator/android/Makefile b/ion/src/simulator/android/Makefile index 3ccba89a9..442aa6be9 100644 --- a/ion/src/simulator/android/Makefile +++ b/ion/src/simulator/android/Makefile @@ -5,6 +5,7 @@ ion_src += $(addprefix ion/src/simulator/android/src/cpp/, \ ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/callback.cpp \ + dummy/journal.cpp \ dummy/language.cpp \ clipboard_helper.cpp \ haptics.cpp \ diff --git a/ion/src/simulator/ios/Makefile b/ion/src/simulator/ios/Makefile index a6b114ad2..e468bb9f3 100644 --- a/ion/src/simulator/ios/Makefile +++ b/ion/src/simulator/ios/Makefile @@ -8,6 +8,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/haptics_enabled.cpp \ clipboard_helper.cpp \ haptics.cpp \ + dummy/journal.cpp \ ) ion_src += ion/src/shared/collect_registers.cpp diff --git a/ion/src/simulator/linux/Makefile b/ion/src/simulator/linux/Makefile index 1ff0ebcff..f1585a6e8 100644 --- a/ion/src/simulator/linux/Makefile +++ b/ion/src/simulator/linux/Makefile @@ -20,6 +20,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ collect_registers_x86_64.s \ collect_registers.cpp \ haptics.cpp \ + journal.cpp \ ) ifeq ($(EPSILON_TELEMETRY),1) diff --git a/ion/src/simulator/macos/Makefile b/ion/src/simulator/macos/Makefile index a465b83c2..f69dd7125 100644 --- a/ion/src/simulator/macos/Makefile +++ b/ion/src/simulator/macos/Makefile @@ -10,6 +10,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ collect_registers_x86_64.s \ collect_registers.cpp \ haptics.cpp \ + journal.cpp \ ) ifeq ($(EPSILON_TELEMETRY),1) diff --git a/ion/src/simulator/shared/dummy/journal.cpp b/ion/src/simulator/shared/dummy/journal.cpp new file mode 100644 index 000000000..4ff02f61a --- /dev/null +++ b/ion/src/simulator/shared/dummy/journal.cpp @@ -0,0 +1,20 @@ +#include "../journal.h" + +namespace Ion { +namespace Simulator { +namespace Journal { + +void init() { +} + +Ion::Events::Journal * replayJournal() { + return nullptr; +} + +Ion::Events::Journal * logJournal() { + return nullptr; +} + +} +} +} diff --git a/ion/src/simulator/shared/journal.cpp b/ion/src/simulator/shared/journal.cpp new file mode 100644 index 000000000..f6112d48c --- /dev/null +++ b/ion/src/simulator/shared/journal.cpp @@ -0,0 +1,39 @@ +#include "journal.h" +#include + +namespace Ion { +namespace Simulator { +namespace Journal { + +using Ion::Events::Event; +class Journal : public Ion::Events::Journal { +public: + void pushEvent(Event e) override { + m_eventStorage.push(e); + } + virtual Event popEvent() override { + Event e = m_eventStorage.front(); + m_eventStorage.pop(); + return e; + } +private: + std::queue m_eventStorage; +}; + +void init() { + Ion::Events::logTo(logJournal()); +} + +Ion::Events::Journal * replayJournal() { + static Journal journal; + return &journal; +} + +Ion::Events::Journal * logJournal() { + static Journal journal; + return &journal; +} + +} +} +} diff --git a/ion/src/simulator/shared/journal.h b/ion/src/simulator/shared/journal.h new file mode 100644 index 000000000..8134a49e6 --- /dev/null +++ b/ion/src/simulator/shared/journal.h @@ -0,0 +1,19 @@ +#ifndef ION_SIMULATOR_JOURNAL_H +#define ION_SIMULATOR_JOURNAL_H + +#include + +namespace Ion { +namespace Simulator { +namespace Journal { + +void init(); + +Ion::Events::Journal * replayJournal(); +Ion::Events::Journal * logJournal(); + +} +} +} + +#endif diff --git a/ion/src/simulator/shared/main.cpp b/ion/src/simulator/shared/main.cpp index 73c11883c..3f74a1dfd 100644 --- a/ion/src/simulator/shared/main.cpp +++ b/ion/src/simulator/shared/main.cpp @@ -1,4 +1,5 @@ #include "haptics.h" +#include "journal.h" #include "platform.h" #include "telemetry.h" #include "window.h" @@ -60,6 +61,7 @@ int main(int argc, char * argv[]) { } using namespace Ion::Simulator; + Journal::init(); #if EPSILON_TELEMETRY Telemetry::init(); #endif diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index 2c0cea801..8e4a01ef8 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -24,6 +24,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/language.cpp \ dummy/haptics_enabled.cpp \ haptics.cpp \ + journal.cpp \ ) ion_src += ion/src/shared/collect_registers.cpp diff --git a/ion/src/simulator/windows/Makefile b/ion/src/simulator/windows/Makefile index 70f6dc4ca..ea1b41c04 100644 --- a/ion/src/simulator/windows/Makefile +++ b/ion/src/simulator/windows/Makefile @@ -9,6 +9,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/haptics_enabled.cpp \ clipboard_helper.cpp \ haptics.cpp \ + journal.cpp \ ) ion_src += ion/src/shared/collect_registers.cpp From 37b8c56b3df835435267a7c6f1b7f57d11e6748c Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 4 Sep 2020 17:05:59 -0400 Subject: [PATCH 019/105] [ion/simulator] Clean the callbacks --- ion/src/simulator/Makefile | 6 +- ion/src/simulator/android/Makefile | 3 +- ion/src/simulator/ios/Makefile | 5 +- ion/src/simulator/macos/Makefile | 3 +- ion/src/simulator/shared/dummy/callback.cpp | 7 --- .../shared/dummy/keyboard_callback.cpp | 12 ++++ ion/src/simulator/shared/dummy/window.cpp | 24 ++++++++ .../shared/dummy/window_callback.cpp | 12 ++++ ion/src/simulator/shared/keyboard.cpp | 4 +- ion/src/simulator/shared/keyboard.h | 1 + ion/src/simulator/shared/main.cpp | 25 ++++++++ ion/src/simulator/shared/platform.h | 7 --- .../shared/{window_sdl.cpp => window.cpp} | 2 +- ion/src/simulator/shared/window.h | 2 + ion/src/simulator/shared/window_headless.cpp | 58 ------------------- ion/src/simulator/web/Makefile | 4 +- ion/src/simulator/web/exports.cpp | 21 +++++++ ion/src/simulator/web/exports.h | 3 + ion/src/simulator/web/helpers.cpp | 15 ----- .../{callback.cpp => keyboard_callback.cpp} | 16 ++--- ion/src/simulator/web/window_callback.cpp | 16 +++++ ion/src/simulator/windows/Makefile | 3 +- 22 files changed, 142 insertions(+), 107 deletions(-) delete mode 100644 ion/src/simulator/shared/dummy/callback.cpp create mode 100644 ion/src/simulator/shared/dummy/keyboard_callback.cpp create mode 100644 ion/src/simulator/shared/dummy/window.cpp create mode 100644 ion/src/simulator/shared/dummy/window_callback.cpp rename ion/src/simulator/shared/{window_sdl.cpp => window.cpp} (98%) delete mode 100644 ion/src/simulator/shared/window_headless.cpp delete mode 100644 ion/src/simulator/web/helpers.cpp rename ion/src/simulator/web/{callback.cpp => keyboard_callback.cpp} (64%) create mode 100644 ion/src/simulator/web/window_callback.cpp diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index dff72a250..5a18da565 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -3,6 +3,7 @@ ion_src += $(addprefix ion/src/shared/dummy/, \ battery.cpp \ display.cpp \ exam_mode.cpp \ + events_platform.cpp:+headless \ fcc_id.cpp \ keyboard.cpp:+headless \ led.cpp \ @@ -14,8 +15,8 @@ ion_src += $(addprefix ion/src/shared/dummy/, \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ - dummy/events_platform.cpp:+headless \ dummy/keyboard.cpp:+headless \ + dummy/window.cpp:+headless \ clipboard.cpp \ console_stdio.cpp:-consoledisplay \ crc32.cpp \ @@ -30,8 +31,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ random.cpp \ timing.cpp \ timing_msleep.cpp:-headless \ - window_headless.cpp:+headless \ - window_sdl.cpp:-headless \ + window.cpp:-headless \ ) ion_simulator_assets = background.jpg horizontal_arrow.png vertical_arrow.png round.png small_squircle.png large_squircle.png diff --git a/ion/src/simulator/android/Makefile b/ion/src/simulator/android/Makefile index 442aa6be9..952012eff 100644 --- a/ion/src/simulator/android/Makefile +++ b/ion/src/simulator/android/Makefile @@ -4,9 +4,10 @@ ion_src += $(addprefix ion/src/simulator/android/src/cpp/, \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ - dummy/callback.cpp \ dummy/journal.cpp \ + dummy/keyboard_callback.cpp \ dummy/language.cpp \ + dummy/window_callback.cpp \ clipboard_helper.cpp \ haptics.cpp \ ) diff --git a/ion/src/simulator/ios/Makefile b/ion/src/simulator/ios/Makefile index e468bb9f3..35f24e812 100644 --- a/ion/src/simulator/ios/Makefile +++ b/ion/src/simulator/ios/Makefile @@ -4,11 +4,12 @@ ion_src += $(addprefix ion/src/simulator/ios/, \ ion_src += $(addprefix ion/src/simulator/shared/, \ apple/language.m \ - dummy/callback.cpp \ dummy/haptics_enabled.cpp \ + dummy/journal.cpp \ + dummy/keyboard_callback.cpp \ + dummy/window_callback.cpp \ clipboard_helper.cpp \ haptics.cpp \ - dummy/journal.cpp \ ) ion_src += ion/src/shared/collect_registers.cpp diff --git a/ion/src/simulator/macos/Makefile b/ion/src/simulator/macos/Makefile index f69dd7125..d35c71b73 100644 --- a/ion/src/simulator/macos/Makefile +++ b/ion/src/simulator/macos/Makefile @@ -4,8 +4,9 @@ ion_src += $(addprefix ion/src/simulator/macos/, \ ion_src += $(addprefix ion/src/simulator/shared/, \ apple/language.m \ - dummy/callback.cpp \ dummy/haptics_enabled.cpp \ + dummy/keyboard_callback.cpp \ + dummy/window_callback.cpp \ clipboard_helper.cpp \ collect_registers_x86_64.s \ collect_registers.cpp \ diff --git a/ion/src/simulator/shared/dummy/callback.cpp b/ion/src/simulator/shared/dummy/callback.cpp deleted file mode 100644 index d5851e650..000000000 --- a/ion/src/simulator/shared/dummy/callback.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "../platform.h" - -void IonSimulatorCallbackDidRefresh() { -} - -void IonSimulatorCallbackDidScanKeyboard() { -} diff --git a/ion/src/simulator/shared/dummy/keyboard_callback.cpp b/ion/src/simulator/shared/dummy/keyboard_callback.cpp new file mode 100644 index 000000000..621cbd7ec --- /dev/null +++ b/ion/src/simulator/shared/dummy/keyboard_callback.cpp @@ -0,0 +1,12 @@ +#include "../keyboard.h" + +namespace Ion { +namespace Simulator { +namespace Keyboard { + +void didScan() { +} + +} +} +} diff --git a/ion/src/simulator/shared/dummy/window.cpp b/ion/src/simulator/shared/dummy/window.cpp new file mode 100644 index 000000000..1ab131edf --- /dev/null +++ b/ion/src/simulator/shared/dummy/window.cpp @@ -0,0 +1,24 @@ +#include "../window.h" + +namespace Ion { +namespace Simulator { +namespace Window { + +void init() { + Ion::Simulator::Framebuffer::setActive(false); +} + +void quit() { +} + +void setNeedsRefresh() { +} + +void relayout() { +} + +void refresh() { +} +} +} +} diff --git a/ion/src/simulator/shared/dummy/window_callback.cpp b/ion/src/simulator/shared/dummy/window_callback.cpp new file mode 100644 index 000000000..908d2027d --- /dev/null +++ b/ion/src/simulator/shared/dummy/window_callback.cpp @@ -0,0 +1,12 @@ +#include "../window.h" + +namespace Ion { +namespace Simulator { +namespace Window { + +void didRefresh() { +} + +} +} +} diff --git a/ion/src/simulator/shared/keyboard.cpp b/ion/src/simulator/shared/keyboard.cpp index 62f955bce..f99fa1961 100644 --- a/ion/src/simulator/shared/keyboard.cpp +++ b/ion/src/simulator/shared/keyboard.cpp @@ -1,5 +1,5 @@ +#include "keyboard.h" #include "layout.h" -#include "platform.h" #include "window.h" #include @@ -43,7 +43,7 @@ State scan() { SDL_PumpEvents(); // Notify callbacks in case we need to do something - IonSimulatorCallbackDidScanKeyboard(); + Simulator::Keyboard::didScan(); // Grab this opportunity to refresh the display if needed Simulator::Window::refresh(); diff --git a/ion/src/simulator/shared/keyboard.h b/ion/src/simulator/shared/keyboard.h index c722612aa..c4368282c 100644 --- a/ion/src/simulator/shared/keyboard.h +++ b/ion/src/simulator/shared/keyboard.h @@ -11,6 +11,7 @@ namespace Keyboard { void keyDown(Ion::Keyboard::Key k); void keyUp(Ion::Keyboard::Key k); bool scanHandlesSDLKey(SDL_Scancode key); +void didScan(); } } diff --git a/ion/src/simulator/shared/main.cpp b/ion/src/simulator/shared/main.cpp index 3f74a1dfd..a6c56bf0d 100644 --- a/ion/src/simulator/shared/main.cpp +++ b/ion/src/simulator/shared/main.cpp @@ -5,6 +5,10 @@ #include "window.h" #include #include +#ifndef __WIN32__ +#include +#include +#endif /* The Args class allows parsing and editing command-line arguments * The editing part allows us to add/remove arguments before forwarding them to @@ -15,6 +19,7 @@ public: Args(int argc, char * argv[]) : m_arguments(argv, argv+argc) {} bool has(const char * key) const; const char * pop(const char * key); + bool popFlag(const char * flag); void push(const char * key, const char * value) { m_arguments.push_back(key); m_arguments.push_back(value); @@ -46,6 +51,15 @@ const char * Args::pop(const char * argument) { return nullptr; } +bool Args::popFlag(const char * argument) { + auto flagIt = find(argument); + if (flagIt != m_arguments.end()) { + m_arguments.erase(flagIt); + return true; + } + return false; +} + std::vector::const_iterator Args::find(const char * name) const { return std::find_if( m_arguments.begin(), m_arguments.end(), @@ -60,6 +74,17 @@ int main(int argc, char * argv[]) { args.push("--language", IonSimulatorGetLanguageCode()); } +#ifndef __WIN32__ + if (args.popFlag("--limit-stack-usage")) { + // Limit stack usage + /* TODO : Reduce stack memory cost in prime factorization to allow running + * tests with the actual stack size */ + constexpr int kStackSize = 32768*10; + struct rlimit stackLimits = {kStackSize, kStackSize}; + setrlimit(RLIMIT_STACK, &stackLimits); + } +#endif + using namespace Ion::Simulator; Journal::init(); #if EPSILON_TELEMETRY diff --git a/ion/src/simulator/shared/platform.h b/ion/src/simulator/shared/platform.h index 38612e888..e6e13d5e0 100644 --- a/ion/src/simulator/shared/platform.h +++ b/ion/src/simulator/shared/platform.h @@ -14,13 +14,6 @@ extern "C" { SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier); char * IonSimulatorGetLanguageCode(); -#if EPSILON_SDL_SCREEN_ONLY -void IonSimulatorEventsPushEvent(int eventNumber); -#endif - -void IonSimulatorCallbackDidRefresh(); -void IonSimulatorCallbackDidScanKeyboard(); - #ifdef __cplusplus } #endif diff --git a/ion/src/simulator/shared/window_sdl.cpp b/ion/src/simulator/shared/window.cpp similarity index 98% rename from ion/src/simulator/shared/window_sdl.cpp rename to ion/src/simulator/shared/window.cpp index 9f1b9c5da..ccfc8854b 100644 --- a/ion/src/simulator/shared/window_sdl.cpp +++ b/ion/src/simulator/shared/window.cpp @@ -108,7 +108,7 @@ void refresh() { #endif SDL_RenderPresent(sRenderer); - IonSimulatorCallbackDidRefresh(); + didRefresh(); } void quit() { diff --git a/ion/src/simulator/shared/window.h b/ion/src/simulator/shared/window.h index 9af6af86a..224ad96a4 100644 --- a/ion/src/simulator/shared/window.h +++ b/ion/src/simulator/shared/window.h @@ -12,6 +12,8 @@ void setNeedsRefresh(); void refresh(); void relayout(); +void didRefresh(); + } } } diff --git a/ion/src/simulator/shared/window_headless.cpp b/ion/src/simulator/shared/window_headless.cpp deleted file mode 100644 index 600affa65..000000000 --- a/ion/src/simulator/shared/window_headless.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "window.h" -#include "display.h" -#include "framebuffer.h" -#include "events.h" - -#include -#ifndef __WIN32__ -#include -#include -#endif - -#ifdef NDEBUG -/* TODO : Reduce stack memory cost in prime factorization to allow running - * tests with the actual stack size */ -constexpr int kStackSize = 32768*10; -#else -constexpr int kStackSize = 32768*10; // In DEBUG mode, we increase the stack to be able to pass the tests -#endif - -namespace Ion { -namespace Simulator { -namespace Window { - -void init() { - Ion::Simulator::Framebuffer::setActive(false); - // This feature is lost for now - /* Parse command-line arguments - for (int i=1; i i+1) { - Ion::Simulator::Framebuffer::setActive(true); - Ion::Simulator::Events::logAfter(atoi(argv[i+1])); - } - } - */ -#ifndef __WIN32__ - // Handle signals - signal(SIGABRT, Ion::Simulator::Events::dumpEventCount); - - // Limit stack usage - struct rlimit stackLimits = {kStackSize, kStackSize}; - setrlimit(RLIMIT_STACK, &stackLimits); -#endif -} - -void quit() { -} - -void setNeedsRefresh() { -} - -void relayout() { -} - -void refresh() { -} -} -} -} diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index 8e4a01ef8..c79e47f99 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -14,10 +14,10 @@ SFLAGS += -DEPSILON_SDL_SCREEN_ONLY=1 LDFLAGS += --pre-js ion/src/simulator/web/preamble_env.js ion_src += $(addprefix ion/src/simulator/web/, \ - callback.cpp \ clipboard_helper.cpp \ exports.cpp \ - helpers.cpp \ + keyboard_callback.cpp \ + window_callback.cpp \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ diff --git a/ion/src/simulator/web/exports.cpp b/ion/src/simulator/web/exports.cpp index 6f2e0b4e8..babe1825c 100644 --- a/ion/src/simulator/web/exports.cpp +++ b/ion/src/simulator/web/exports.cpp @@ -1,5 +1,20 @@ #include "exports.h" +#include "../shared/events_journal.h" #include "../shared/keyboard.h" +#include + +const char * IonSoftwareVersion() { + return Ion::softwareVersion(); +} + +const char * IonPatchLevel() { + return Ion::patchLevel(); +} + +void IonDisplayForceRefresh() { + Ion::Simulator::Window::setNeedsRefresh(); + Ion::Simulator::Window::refresh(); +} void IonSimulatorKeyboardKeyDown(int keyNumber) { Ion::Keyboard::Key key = static_cast(keyNumber); @@ -12,4 +27,10 @@ void IonSimulatorKeyboardKeyUp(int keyNumber) { } void IonSimulatorEventsPushEvent(int eventNumber) { + Ion::Events::Journal * j = Ion::Simulator::Events::replayJournal(); + if (j != nullptr) { + Ion::Events::Event event(eventNumber); + j->pushEvent(event); + Ion::Events::replayFrom(j); + } } diff --git a/ion/src/simulator/web/exports.h b/ion/src/simulator/web/exports.h index e0eeb59f9..ee0d47e08 100644 --- a/ion/src/simulator/web/exports.h +++ b/ion/src/simulator/web/exports.h @@ -5,6 +5,9 @@ extern "C" { #endif +const char * IonSoftwareVersion(); +const char * IonPatchLevel(); +void IonDisplayForceRefresh(); void IonSimulatorKeyboardKeyDown(int keyNumber); void IonSimulatorKeyboardKeyUp(int keyNumber); void IonSimulatorEventsPushEvent(int eventNumber); diff --git a/ion/src/simulator/web/helpers.cpp b/ion/src/simulator/web/helpers.cpp deleted file mode 100644 index b6d5076c9..000000000 --- a/ion/src/simulator/web/helpers.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include "../shared/window.h" - -extern "C" const char * IonSoftwareVersion() { - return Ion::softwareVersion(); -} - -extern "C" const char * IonPatchLevel() { - return Ion::patchLevel(); -} - -extern "C" void IonDisplayForceRefresh() { - Ion::Simulator::Window::setNeedsRefresh(); - Ion::Simulator::Window::refresh(); -} diff --git a/ion/src/simulator/web/callback.cpp b/ion/src/simulator/web/keyboard_callback.cpp similarity index 64% rename from ion/src/simulator/web/callback.cpp rename to ion/src/simulator/web/keyboard_callback.cpp index 6c5254a8d..7efdc746f 100644 --- a/ion/src/simulator/web/callback.cpp +++ b/ion/src/simulator/web/keyboard_callback.cpp @@ -1,13 +1,11 @@ -#include "../shared/platform.h" +#include "../shared/keyboard.h" #include -void IonSimulatorCallbackDidRefresh() { - /* Notify JS that the display has been refreshed. - * This gives us a chance to mirror the display in fullscreen mode. */ - EM_ASM(if (typeof Module.onDisplayRefresh === "function") { Module.onDisplayRefresh(); }); -} +namespace Ion { +namespace Simulator { +namespace Keyboard { -void IonSimulatorCallbackDidScanKeyboard() { +void didScan() { /* The following call to emscripten_sleep gives the JS VM a chance to do a run * loop iteration. This in turns gives the browser an opportunity to call the * IonEventsEmscriptenPushKey function, therefore modifying the sKeyboardState @@ -17,3 +15,7 @@ void IonSimulatorCallbackDidScanKeyboard() { * puts the callback at the end of the queue of callbacks to be processed. */ emscripten_sleep(0); } + +} +} +} diff --git a/ion/src/simulator/web/window_callback.cpp b/ion/src/simulator/web/window_callback.cpp new file mode 100644 index 000000000..0688b5e78 --- /dev/null +++ b/ion/src/simulator/web/window_callback.cpp @@ -0,0 +1,16 @@ +#include "../shared/window.h" +#include + +namespace Ion { +namespace Simulator { +namespace Window { + +void didRefresh() { + /* Notify JS that the display has been refreshed. + * This gives us a chance to mirror the display in fullscreen mode. */ + EM_ASM(if (typeof Module.onDisplayRefresh === "function") { Module.onDisplayRefresh(); }); +} + +} +} +} diff --git a/ion/src/simulator/windows/Makefile b/ion/src/simulator/windows/Makefile index ea1b41c04..8456e7c20 100644 --- a/ion/src/simulator/windows/Makefile +++ b/ion/src/simulator/windows/Makefile @@ -5,8 +5,9 @@ ion_src += $(addprefix ion/src/simulator/windows/, \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ - dummy/callback.cpp \ dummy/haptics_enabled.cpp \ + dummy/keyboard_callback.cpp \ + dummy/window_callback.cpp \ clipboard_helper.cpp \ haptics.cpp \ journal.cpp \ From 0116dc2e0785edbe372b0fd1a27864e996405659 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 4 Sep 2020 21:17:36 -0400 Subject: [PATCH 020/105] [ion/simulator] Add a runtime "--headless" option We probably can ditch the static headless version --- ion/src/simulator/shared/keyboard.cpp | 7 ++++++- ion/src/simulator/shared/main.cpp | 22 +++++++++++++++------- ion/src/simulator/shared/window.cpp | 16 ++++++++++++---- ion/src/simulator/shared/window.h | 2 ++ 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/ion/src/simulator/shared/keyboard.cpp b/ion/src/simulator/shared/keyboard.cpp index f99fa1961..9a3849f4e 100644 --- a/ion/src/simulator/shared/keyboard.cpp +++ b/ion/src/simulator/shared/keyboard.cpp @@ -39,6 +39,11 @@ namespace Ion { namespace Keyboard { State scan() { + State state = sKeyboardState; + + if (Simulator::Window::isHeadless()) { + return state; + } // We need to tell SDL to get new state from the host OS SDL_PumpEvents(); @@ -48,7 +53,6 @@ State scan() { // Grab this opportunity to refresh the display if needed Simulator::Window::refresh(); - State state = sKeyboardState; #if !EPSILON_SDL_SCREEN_ONLY // Register a key for the mouse, if any Key k = Simulator::Layout::getHighlightedKey(); @@ -65,6 +69,7 @@ State scan() { state.setKey(pair.key()); } } + return state; } diff --git a/ion/src/simulator/shared/main.cpp b/ion/src/simulator/shared/main.cpp index a6c56bf0d..2bf0bd553 100644 --- a/ion/src/simulator/shared/main.cpp +++ b/ion/src/simulator/shared/main.cpp @@ -1,6 +1,7 @@ #include "haptics.h" #include "journal.h" #include "platform.h" +#include "random.h" #include "telemetry.h" #include "window.h" #include @@ -85,19 +86,26 @@ int main(int argc, char * argv[]) { } #endif + bool headless = args.popFlag("--headless"); + using namespace Ion::Simulator; - Journal::init(); + Random::init(); + if (!headless) { + Journal::init(); #if EPSILON_TELEMETRY - Telemetry::init(); + Telemetry::init(); #endif - Window::init(); - Haptics::init(); + Window::init(); + Haptics::init(); + } ion_main(args.argc(), args.argv()); - Haptics::shutdown(); - Window::quit(); + if (!headless) { + Haptics::shutdown(); + Window::quit(); #if EPSILON_TELEMETRY - Telemetry::shutdown(); + Telemetry::shutdown(); #endif + } return 0; } diff --git a/ion/src/simulator/shared/window.cpp b/ion/src/simulator/shared/window.cpp index ccfc8854b..7b25e05ab 100644 --- a/ion/src/simulator/shared/window.cpp +++ b/ion/src/simulator/shared/window.cpp @@ -2,7 +2,6 @@ #include "display.h" #include "layout.h" #include "platform.h" -#include "random.h" #include #include @@ -19,14 +18,16 @@ static bool sNeedsRefresh = false; static SDL_Rect sScreenRect; #endif +bool isHeadless() { + return sWindow == nullptr; +} + void init() { if (SDL_Init(SDL_INIT_VIDEO) != 0) { SDL_Log("Could not init video"); return; } - Random::init(); - sWindow = SDL_CreateWindow( "Epsilon", SDL_WINDOWPOS_CENTERED, @@ -67,6 +68,9 @@ void init() { } void relayout() { + if (isHeadless()) { + return; + } int windowWidth = 0; int windowHeight = 0; SDL_GetWindowSize(sWindow, &windowWidth, &windowHeight); @@ -89,7 +93,7 @@ void setNeedsRefresh() { } void refresh() { - if (!sNeedsRefresh) { + if (!sNeedsRefresh || isHeadless()) { return; } sNeedsRefresh = false; @@ -112,11 +116,15 @@ void refresh() { } void quit() { + if (isHeadless()) { + return; + } #if !EPSILON_SDL_SCREEN_ONLY Layout::quit(); #endif Display::quit(); SDL_DestroyWindow(sWindow); + sWindow = nullptr; SDL_Quit(); } diff --git a/ion/src/simulator/shared/window.h b/ion/src/simulator/shared/window.h index 224ad96a4..f2e221b85 100644 --- a/ion/src/simulator/shared/window.h +++ b/ion/src/simulator/shared/window.h @@ -8,6 +8,8 @@ namespace Window { void init(); void quit(); +bool isHeadless(); + void setNeedsRefresh(); void refresh(); void relayout(); From 09a7b9daca7ec11d62d5de6b29ab0038f5024caf Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 4 Sep 2020 21:50:04 -0400 Subject: [PATCH 021/105] [ion/simulator] Sort the platform functions --- ion/src/simulator/android/Makefile | 2 +- .../cpp/{images.cpp => platform_images.cpp} | 10 +++++++++- ion/src/simulator/ios/Makefile | 4 ++-- .../ios/{images.m => platform_images.mm} | 11 +++++++++-- ion/src/simulator/linux/Makefile | 10 +++++----- .../linux/{images.cpp => platform_images.cpp} | 12 ++++++++++-- .../{language.cpp => platform_language.cpp} | 11 +++++++++-- ion/src/simulator/macos/Makefile | 4 ++-- .../macos/{images.m => platform_images.mm} | 10 +++++++++- .../apple/{language.m => platform_language.mm} | 10 +++++++++- ion/src/simulator/shared/layout.cpp | 4 ++-- ion/src/simulator/shared/main.cpp | 6 ++++-- ion/src/simulator/shared/platform.h | 18 +++++++----------- ion/src/simulator/windows/Makefile | 6 +++--- .../{images.cpp => platform_images.cpp} | 12 ++++++++++-- .../{language.cpp => platform_language.cpp} | 11 +++++++++-- 16 files changed, 100 insertions(+), 41 deletions(-) rename ion/src/simulator/android/src/cpp/{images.cpp => platform_images.cpp} (91%) rename ion/src/simulator/ios/{images.m => platform_images.mm} (89%) rename ion/src/simulator/linux/{images.cpp => platform_images.cpp} (95%) rename ion/src/simulator/linux/{language.cpp => platform_language.cpp} (72%) rename ion/src/simulator/macos/{images.m => platform_images.mm} (90%) rename ion/src/simulator/shared/apple/{language.m => platform_language.mm} (83%) rename ion/src/simulator/windows/{images.cpp => platform_images.cpp} (91%) rename ion/src/simulator/windows/{language.cpp => platform_language.cpp} (84%) diff --git a/ion/src/simulator/android/Makefile b/ion/src/simulator/android/Makefile index 952012eff..b3634670d 100644 --- a/ion/src/simulator/android/Makefile +++ b/ion/src/simulator/android/Makefile @@ -1,6 +1,6 @@ ion_src += $(addprefix ion/src/simulator/android/src/cpp/, \ - images.cpp \ haptics_enabled.cpp \ + platform_images.cpp \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ diff --git a/ion/src/simulator/android/src/cpp/images.cpp b/ion/src/simulator/android/src/cpp/platform_images.cpp similarity index 91% rename from ion/src/simulator/android/src/cpp/images.cpp rename to ion/src/simulator/android/src/cpp/platform_images.cpp index 75855a3a0..2b7f92f29 100644 --- a/ion/src/simulator/android/src/cpp/images.cpp +++ b/ion/src/simulator/android/src/cpp/platform_images.cpp @@ -4,7 +4,11 @@ #include #include -SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) { +namespace Ion { +namespace Simulator { +namespace Platform { + +SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { JNIEnv * env = static_cast(SDL_AndroidGetJNIEnv()); jobject activity = static_cast(SDL_AndroidGetActivity()); @@ -54,3 +58,7 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi env->DeleteLocalRef(activity); return texture; } + +} +} +} diff --git a/ion/src/simulator/ios/Makefile b/ion/src/simulator/ios/Makefile index 35f24e812..6a51f63d3 100644 --- a/ion/src/simulator/ios/Makefile +++ b/ion/src/simulator/ios/Makefile @@ -1,9 +1,9 @@ ion_src += $(addprefix ion/src/simulator/ios/, \ - images.m \ + platform_images.mm \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ - apple/language.m \ + apple/platform_language.mm \ dummy/haptics_enabled.cpp \ dummy/journal.cpp \ dummy/keyboard_callback.cpp \ diff --git a/ion/src/simulator/ios/images.m b/ion/src/simulator/ios/platform_images.mm similarity index 89% rename from ion/src/simulator/ios/images.m rename to ion/src/simulator/ios/platform_images.mm index 6a68fe2c4..3d3bb70b2 100644 --- a/ion/src/simulator/ios/images.m +++ b/ion/src/simulator/ios/platform_images.mm @@ -1,9 +1,12 @@ #include "../shared/platform.h" - #include #include -SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) { +namespace Ion { +namespace Simulator { +namespace Platform { + +SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { CGImageRef cgImage = [[UIImage imageNamed:[NSString stringWithUTF8String:identifier]] CGImage]; if (cgImage == NULL) { return NULL; @@ -53,3 +56,7 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi return texture; } + +} +} +} diff --git a/ion/src/simulator/linux/Makefile b/ion/src/simulator/linux/Makefile index f1585a6e8..5425edddd 100644 --- a/ion/src/simulator/linux/Makefile +++ b/ion/src/simulator/linux/Makefile @@ -8,9 +8,9 @@ SFLAGS += -DUSING_GENERATED_CONFIG_H SFLAGS += -Iion/src/simulator/linux/include ion_src += $(addprefix ion/src/simulator/linux/, \ - images.cpp \ - language.cpp \ assets.s \ + platform_images.cpp \ + platform_language.cpp \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ @@ -32,13 +32,13 @@ LDFLAGS += -ljpeg $(eval $(call rule_for, \ INCBIN, \ - ion/src/simulator/linux/assets.s ion/src/simulator/linux/images.h, \ + ion/src/simulator/linux/assets.s ion/src/simulator/linux/platform_images.h, \ $(ion_simulator_assets_paths), \ $$(PYTHON) ion/src/simulator/linux/incbin.py $(ion_simulator_assets) -o $$@, \ global \ )) -$(call object_for,ion/src/simulator/linux/images.cpp): $(BUILD_DIR)/ion/src/simulator/linux/images.h +$(call object_for,ion/src/simulator/linux/platform_images.cpp): $(BUILD_DIR)/ion/src/simulator/linux/platform_images.h -# The header is refered to as so make sure it's findable this way +# The header is refered to as so make sure it's findable this way SFLAGS += -I$(BUILD_DIR) diff --git a/ion/src/simulator/linux/images.cpp b/ion/src/simulator/linux/platform_images.cpp similarity index 95% rename from ion/src/simulator/linux/images.cpp rename to ion/src/simulator/linux/platform_images.cpp index dbe94b123..a3ec43760 100644 --- a/ion/src/simulator/linux/images.cpp +++ b/ion/src/simulator/linux/platform_images.cpp @@ -5,7 +5,11 @@ #include #include -#include +#include + +namespace Ion { +namespace Simulator { +namespace Platform { enum class AssetFormat { JPG, @@ -95,7 +99,7 @@ bool readJPG(const unsigned char * start, size_t size, unsigned char ** bitmapDa return true; } -SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) { +SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { static constexpr const char * jpgExtension = ".jpg"; static constexpr const char * pngExtension = ".png"; @@ -161,3 +165,7 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi return texture; } + +} +} +} diff --git a/ion/src/simulator/linux/language.cpp b/ion/src/simulator/linux/platform_language.cpp similarity index 72% rename from ion/src/simulator/linux/language.cpp rename to ion/src/simulator/linux/platform_language.cpp index dd146e143..81a370de3 100644 --- a/ion/src/simulator/linux/language.cpp +++ b/ion/src/simulator/linux/platform_language.cpp @@ -1,8 +1,11 @@ #include "../shared/platform.h" - #include -char * IonSimulatorGetLanguageCode() { +namespace Ion { +namespace Simulator { +namespace Platform { + +const char * languageCode() { static char buffer[3] = {0}; char * locale = setlocale(LC_ALL, ""); if (locale[2] == '_') { @@ -12,3 +15,7 @@ char * IonSimulatorGetLanguageCode() { } return nullptr; } + +} +} +} diff --git a/ion/src/simulator/macos/Makefile b/ion/src/simulator/macos/Makefile index d35c71b73..238da5daf 100644 --- a/ion/src/simulator/macos/Makefile +++ b/ion/src/simulator/macos/Makefile @@ -1,9 +1,9 @@ ion_src += $(addprefix ion/src/simulator/macos/, \ - images.m \ + platform_images.mm \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ - apple/language.m \ + apple/platform_language.mm \ dummy/haptics_enabled.cpp \ dummy/keyboard_callback.cpp \ dummy/window_callback.cpp \ diff --git a/ion/src/simulator/macos/images.m b/ion/src/simulator/macos/platform_images.mm similarity index 90% rename from ion/src/simulator/macos/images.m rename to ion/src/simulator/macos/platform_images.mm index 03c82ab51..1cf9f61a9 100644 --- a/ion/src/simulator/macos/images.m +++ b/ion/src/simulator/macos/platform_images.mm @@ -3,7 +3,11 @@ #include #include -SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) { +namespace Ion { +namespace Simulator { +namespace Platform { + +SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { NSImage * nsImage = [NSImage imageNamed:[NSString stringWithUTF8String:identifier]]; CGImageRef cgImage = [nsImage CGImageForProposedRect:NULL context:NULL @@ -55,3 +59,7 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi return texture; } + +} +} +} diff --git a/ion/src/simulator/shared/apple/language.m b/ion/src/simulator/shared/apple/platform_language.mm similarity index 83% rename from ion/src/simulator/shared/apple/language.m rename to ion/src/simulator/shared/apple/platform_language.mm index 1fcefe08b..e765a8af9 100644 --- a/ion/src/simulator/shared/apple/language.m +++ b/ion/src/simulator/shared/apple/platform_language.mm @@ -2,7 +2,11 @@ #include -char * IonSimulatorGetLanguageCode() { +namespace Ion { +namespace Simulator { +namespace Platform { + +const char * languageCode() { static char buffer[4] = {0}; if (buffer[0] == 0) { NSString * preferredLanguage = [[NSLocale preferredLanguages] firstObject]; @@ -15,3 +19,7 @@ char * IonSimulatorGetLanguageCode() { } return buffer; } + +} +} +} diff --git a/ion/src/simulator/shared/layout.cpp b/ion/src/simulator/shared/layout.cpp index df4c7ab88..f3dffd900 100644 --- a/ion/src/simulator/shared/layout.cpp +++ b/ion/src/simulator/shared/layout.cpp @@ -202,9 +202,9 @@ static SDL_Texture * sBackgroundTexture = nullptr; static SDL_Texture * sKeyLayoutTextures[KeyLayout::NumberOfShapes]; void init(SDL_Renderer * renderer) { - sBackgroundTexture = IonSimulatorLoadImage(renderer, "background.jpg"); + sBackgroundTexture = Platform::loadImage(renderer, "background.jpg"); for (size_t i = 0; i < KeyLayout::NumberOfShapes; i++) { - sKeyLayoutTextures[i] = IonSimulatorLoadImage(renderer, KeyLayout::assetName[i]); + sKeyLayoutTextures[i] = Platform::loadImage(renderer, KeyLayout::assetName[i]); } } diff --git a/ion/src/simulator/shared/main.cpp b/ion/src/simulator/shared/main.cpp index 2bf0bd553..c05ac937c 100644 --- a/ion/src/simulator/shared/main.cpp +++ b/ion/src/simulator/shared/main.cpp @@ -4,6 +4,7 @@ #include "random.h" #include "telemetry.h" #include "window.h" +#include #include #include #ifndef __WIN32__ @@ -68,11 +69,13 @@ std::vector::const_iterator Args::find(const char * name) const { ); } +using namespace Ion::Simulator; + int main(int argc, char * argv[]) { Args args(argc, argv); if (!args.has("--language")) { - args.push("--language", IonSimulatorGetLanguageCode()); + args.push("--language", Platform::languageCode()); } #ifndef __WIN32__ @@ -88,7 +91,6 @@ int main(int argc, char * argv[]) { bool headless = args.popFlag("--headless"); - using namespace Ion::Simulator; Random::init(); if (!headless) { Journal::init(); diff --git a/ion/src/simulator/shared/platform.h b/ion/src/simulator/shared/platform.h index e6e13d5e0..ccdff6806 100644 --- a/ion/src/simulator/shared/platform.h +++ b/ion/src/simulator/shared/platform.h @@ -2,20 +2,16 @@ #define ION_SIMULATOR_PLATFORM_H #include -#include -#ifdef __cplusplus -extern "C" { -#endif +namespace Ion { +namespace Simulator { +namespace Platform { -/* Those functions should be implemented per-platform. - * They are defined as C function for easier interop. */ +SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier); +const char * languageCode(); -SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier); -char * IonSimulatorGetLanguageCode(); - -#ifdef __cplusplus } -#endif +} +} #endif diff --git a/ion/src/simulator/windows/Makefile b/ion/src/simulator/windows/Makefile index 8456e7c20..563a6fc61 100644 --- a/ion/src/simulator/windows/Makefile +++ b/ion/src/simulator/windows/Makefile @@ -1,6 +1,6 @@ ion_src += $(addprefix ion/src/simulator/windows/, \ - images.cpp \ - language.cpp \ + platform_images.cpp \ + platform_language.cpp \ resources.rc \ ) @@ -36,6 +36,6 @@ $(eval $(call rule_for, \ global \ )) -$(call object_for,ion/src/simulator/windows/images.cpp): $(BUILD_DIR)/ion/src/simulator/windows/images.h +$(call object_for,ion/src/simulator/windows/platform_images.cpp): $(BUILD_DIR)/ion/src/simulator/windows/images.h $(call object_for,ion/src/simulator/windows/resources.rc): $(BUILD_DIR)/ion/src/simulator/windows/resources_gen.rc diff --git a/ion/src/simulator/windows/images.cpp b/ion/src/simulator/windows/platform_images.cpp similarity index 91% rename from ion/src/simulator/windows/images.cpp rename to ion/src/simulator/windows/platform_images.cpp index 1bae507fa..648ddbe35 100644 --- a/ion/src/simulator/windows/images.cpp +++ b/ion/src/simulator/windows/platform_images.cpp @@ -12,7 +12,7 @@ * Note that this adds an extra runtime dependency (as compared to just SDL), * but this should not be an issue. */ -HRESULT CreateStreamOnResource(const char * name, LPSTREAM * stream) { +static inline HRESULT CreateStreamOnResource(const char * name, LPSTREAM * stream) { HINSTANCE hInstance = GetModuleHandle(0); *stream = nullptr; HRSRC hC = FindResource(hInstance, name, RT_RCDATA); @@ -36,7 +36,11 @@ HRESULT CreateStreamOnResource(const char * name, LPSTREAM * stream) { return hr; } -SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identifier) { +namespace Ion { +namespace Simulator { +namespace Platform { + +SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { Gdiplus::GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr); @@ -87,3 +91,7 @@ SDL_Texture * IonSimulatorLoadImage(SDL_Renderer * renderer, const char * identi return texture; } + +} +} +} diff --git a/ion/src/simulator/windows/language.cpp b/ion/src/simulator/windows/platform_language.cpp similarity index 84% rename from ion/src/simulator/windows/language.cpp rename to ion/src/simulator/windows/platform_language.cpp index 22d7909f8..5cc652a48 100644 --- a/ion/src/simulator/windows/language.cpp +++ b/ion/src/simulator/windows/platform_language.cpp @@ -1,8 +1,11 @@ #include "../shared/platform.h" - #include -char * IonSimulatorGetLanguageCode() { +namespace Ion { +namespace Simulator { +namespace Platform { + +const char * languageCode() { /* Per documentation, the maximum number of characters allowed for the * language string is nine, including a terminating null character. */ static char buffer[9] = {0}; @@ -19,3 +22,7 @@ char * IonSimulatorGetLanguageCode() { } return buffer; } + +} +} +} From 22b6990e635cabf5793a5fa89f77b9502b3c50e1 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 31 Aug 2020 15:41:29 -0400 Subject: [PATCH 022/105] [ion/simulator/android] Get the language directly Without using the "--language" command-line option --- ion/src/simulator/android/Makefile | 2 +- .../android/src/cpp/platform_language.cpp | 32 +++++++++++++++++++ .../numworks/calculator/EpsilonActivity.java | 11 +++---- 3 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 ion/src/simulator/android/src/cpp/platform_language.cpp diff --git a/ion/src/simulator/android/Makefile b/ion/src/simulator/android/Makefile index b3634670d..09c641f5f 100644 --- a/ion/src/simulator/android/Makefile +++ b/ion/src/simulator/android/Makefile @@ -1,12 +1,12 @@ ion_src += $(addprefix ion/src/simulator/android/src/cpp/, \ haptics_enabled.cpp \ platform_images.cpp \ + platform_language.cpp \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/journal.cpp \ dummy/keyboard_callback.cpp \ - dummy/language.cpp \ dummy/window_callback.cpp \ clipboard_helper.cpp \ haptics.cpp \ diff --git a/ion/src/simulator/android/src/cpp/platform_language.cpp b/ion/src/simulator/android/src/cpp/platform_language.cpp new file mode 100644 index 000000000..c8e4a353b --- /dev/null +++ b/ion/src/simulator/android/src/cpp/platform_language.cpp @@ -0,0 +1,32 @@ +#include "../../../shared/platform.h" +#include + +namespace Ion { +namespace Simulator { +namespace Platform { + +const char * languageCode() { + static char buffer[4] = {0}; + if (buffer[0] == 0) { + JNIEnv * env = static_cast(SDL_AndroidGetJNIEnv()); + jobject activity = static_cast(SDL_AndroidGetActivity()); + + jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity"); + jmethodID j_methodId = env->GetMethodID( + j_class, + "retrieveLanguage", + "(V)Ljava/lang/String;" + ); + + jstring j_language = static_cast(env->CallObjectMethod(activity, j_methodId)); + const char * language = env->GetStringUTFChars(j_language, nullptr); + memcpy(buffer, language, 4); + buffer[3] = 0; + env->ReleaseStringUTFChars(j_language, language); + } + return buffer; +} + +} +} +} diff --git a/ion/src/simulator/android/src/java/com/numworks/calculator/EpsilonActivity.java b/ion/src/simulator/android/src/java/com/numworks/calculator/EpsilonActivity.java index a11c8b805..213199c32 100644 --- a/ion/src/simulator/android/src/java/com/numworks/calculator/EpsilonActivity.java +++ b/ion/src/simulator/android/src/java/com/numworks/calculator/EpsilonActivity.java @@ -28,13 +28,6 @@ public class EpsilonActivity extends SDLActivity { }; } - @Override - protected String[] getArguments() { - Locale currentLocale = getResources().getConfiguration().locale; - String[] arguments = {"--language", currentLocale.getLanguage()}; - return arguments; - } - public Bitmap retrieveBitmapAsset(String identifier) { Bitmap bitmap = null; try { @@ -47,6 +40,10 @@ public class EpsilonActivity extends SDLActivity { return bitmap; } + public String retrieveLanguage() { + return getResources().getConfiguration().locale.getLanguage(); + } + public void telemetryInit() { sAnalytics = GoogleAnalytics.getInstance(this); sTracker = sAnalytics.newTracker("UA-93775823-3"); From f4905c59a24bbe9956d2225e01862f7af3d830a8 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 10 Sep 2020 16:23:33 -0400 Subject: [PATCH 023/105] [ion] Events::Journal has isEmpty --- ion/include/ion/events.h | 1 + ion/src/shared/events_keyboard.cpp | 5 ++--- ion/src/simulator/shared/journal.cpp | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index 6c1c64d76..c5a5fae5b 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -57,6 +57,7 @@ class Journal { public: virtual void pushEvent(Event e) = 0; virtual Event popEvent() = 0; + virtual bool isEmpty() = 0; }; void replayFrom(Journal * l); diff --git a/ion/src/shared/events_keyboard.cpp b/ion/src/shared/events_keyboard.cpp index c368b785e..fe0825a4b 100644 --- a/ion/src/shared/events_keyboard.cpp +++ b/ion/src/shared/events_keyboard.cpp @@ -125,11 +125,10 @@ void logTo(Journal * l) { sDestinationJournal = l; } Event getEvent(int * timeout) { if (sSourceJournal != nullptr) { - Event e = sSourceJournal->popEvent(); - if (e == None) { + if (sSourceJournal->isEmpty()) { sSourceJournal = nullptr; } else { - return e; + return sSourceJournal->popEvent(); } } Event e = innerGetEvent(timeout); diff --git a/ion/src/simulator/shared/journal.cpp b/ion/src/simulator/shared/journal.cpp index f6112d48c..8677fb40c 100644 --- a/ion/src/simulator/shared/journal.cpp +++ b/ion/src/simulator/shared/journal.cpp @@ -12,10 +12,16 @@ public: m_eventStorage.push(e); } virtual Event popEvent() override { + if (isEmpty()) { + return Ion::Events::None; + } Event e = m_eventStorage.front(); m_eventStorage.pop(); return e; } + virtual bool isEmpty() override { + return m_eventStorage.empty(); + } private: std::queue m_eventStorage; }; From a69fc679a914a44104e8a2536b667e4152dfb525 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 10 Sep 2020 16:33:46 -0400 Subject: [PATCH 024/105] [ion/simulator] Add StateFile support --- ion/src/simulator/shared/state_file.cpp | 89 +++++++++++++++++++++++++ ion/src/simulator/shared/state_file.h | 15 +++++ 2 files changed, 104 insertions(+) create mode 100644 ion/src/simulator/shared/state_file.cpp create mode 100644 ion/src/simulator/shared/state_file.h diff --git a/ion/src/simulator/shared/state_file.cpp b/ion/src/simulator/shared/state_file.cpp new file mode 100644 index 000000000..d51fde9a7 --- /dev/null +++ b/ion/src/simulator/shared/state_file.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include "journal.h" + +namespace Ion { +namespace Simulator { +namespace StateFile { + +static constexpr const char * sHeader = "NWSF"; +static constexpr int sHeaderLength = 4; +static constexpr int sVersionLength = 8; + +/* File format: * "NWSF" + "XXXXXXXX" (version) + EVENTS... */ + +static inline bool load(FILE * f) { + char buffer[sVersionLength+1]; + + // Header + buffer[sHeaderLength] = 0; + if (fread(buffer, sHeaderLength, 1, f) != 1) { + return false; + } + printf("READ\n"); + if (strcmp(buffer, sHeader) != 0) { + return false; + } + + // Software version + buffer[sVersionLength] = 0; + if (fread(buffer, sVersionLength, 1, f) != 1) { + return false; + } + if (strcmp(buffer, softwareVersion()) != 0) { + return false; + } + + // Events + Ion::Events::Journal * journal = Journal::replayJournal(); + while (fread(buffer, 1, 1, f) == 1) { + Ion::Events::Event e = Ion::Events::Event(buffer[0]); + journal->pushEvent(e); + } + Ion::Events::replayFrom(journal); + + return true; +} + +void load(const char * filename) { + FILE * f = fopen(filename, "rb"); + if (f == nullptr) { + return; + } + load(f); + fclose(f); +} + +static inline bool save(FILE * f) { + if (fwrite(sHeader, sHeaderLength, 1, f) != 1) { + return false; + } + if (fwrite(softwareVersion(), sVersionLength, 1, f) != 1) { + return false; + } + Ion::Events::Journal * journal = Journal::logJournal(); + Ion::Events::Event e; + while (!journal->isEmpty()) { + Ion::Events::Event e = journal->popEvent(); + uint8_t code = static_cast(e); + if (fwrite(&code, 1, 1, f) != 1) { + return false; + } + } + return true; +} + +void save(const char * filename) { + FILE * f = fopen(filename, "w"); + if (f == nullptr) { + return; + } + save(f); + fclose(f); +} + +} +} +} diff --git a/ion/src/simulator/shared/state_file.h b/ion/src/simulator/shared/state_file.h new file mode 100644 index 000000000..2d1686cd0 --- /dev/null +++ b/ion/src/simulator/shared/state_file.h @@ -0,0 +1,15 @@ +#ifndef ION_SIMULATOR_STATE_FILE_H +#define ION_SIMULATOR_STATE_FILE_H + +namespace Ion { +namespace Simulator { +namespace StateFile { + +void load(const char * filename); +void save(const char * filename); + +} +} +} + +#endif From 11f2b92e5d9046b5805b27dfc1da2cf00475db72 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 16:02:35 -0400 Subject: [PATCH 025/105] [ion/simulator/windows] Add an icon --- ion/src/simulator/windows/Makefile | 10 ++++++---- ion/src/simulator/windows/resources.rc | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ion/src/simulator/windows/Makefile b/ion/src/simulator/windows/Makefile index 563a6fc61..3bb4528b8 100644 --- a/ion/src/simulator/windows/Makefile +++ b/ion/src/simulator/windows/Makefile @@ -22,11 +22,14 @@ endif # RC file dependencies $(call object_for,ion/src/simulator/windows/resources.rc): WRFLAGS += -I $(BUILD_DIR) +$(call object_for,ion/src/simulator/windows/resources.rc): $(addprefix $(BUILD_DIR)/,logo.ico) -# The header of images is refered to as so make sure it's findable this way -SFLAGS += -I$(BUILD_DIR) +$(addprefix $(BUILD_DIR)/,logo.ico): ion/src/simulator/assets/logo.svg | $$(@D)/. + $(call rule_label,CONVERT) + $(Q) convert -background "#FFB734" -resize 256x256 $< $@ -LDFLAGS += -lgdiplus +# Linker flags +LDFLAGS += -lgdiplus -lcomdlg32 $(eval $(call rule_for, \ RESGEN, \ @@ -38,4 +41,3 @@ $(eval $(call rule_for, \ $(call object_for,ion/src/simulator/windows/platform_images.cpp): $(BUILD_DIR)/ion/src/simulator/windows/images.h $(call object_for,ion/src/simulator/windows/resources.rc): $(BUILD_DIR)/ion/src/simulator/windows/resources_gen.rc - diff --git a/ion/src/simulator/windows/resources.rc b/ion/src/simulator/windows/resources.rc index 9994a689a..0b35ee3b1 100644 --- a/ion/src/simulator/windows/resources.rc +++ b/ion/src/simulator/windows/resources.rc @@ -1,4 +1,5 @@ #include +400 ICON "logo.ico" 1 VERSIONINFO FILEVERSION 1,0,0,0 From cba596dde78784ba8f737adb9e9a204df2a7a465 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 16:05:07 -0400 Subject: [PATCH 026/105] [ion/simulator] Add actions --- ion/src/simulator/linux/Makefile | 7 +- ion/src/simulator/linux/platform_files.cpp | 21 ++++ ion/src/simulator/macos/Makefile | 3 + ion/src/simulator/macos/platform_files.mm | 32 +++++++ ion/src/simulator/shared/actions.cpp | 38 ++++++++ ion/src/simulator/shared/actions.h | 17 ++++ ion/src/simulator/shared/dummy/actions.cpp | 22 +++++ .../simulator/shared/dummy/platform_files.cpp | 17 ++++ ion/src/simulator/shared/dummy/state_file.cpp | 95 +++++++++++++++++++ ion/src/simulator/shared/events_platform.cpp | 9 +- ion/src/simulator/shared/main.cpp | 1 + .../shared/platform_action_modifier_ctrl.cpp | 13 +++ .../shared/platform_action_modifier_gui.cpp | 13 +++ ion/src/simulator/web/Makefile | 1 + ion/src/simulator/web/exports.cpp | 5 +- ion/src/simulator/windows/Makefile | 4 + ion/src/simulator/windows/platform_files.cpp | 51 ++++++++++ 17 files changed, 342 insertions(+), 7 deletions(-) create mode 100644 ion/src/simulator/linux/platform_files.cpp create mode 100644 ion/src/simulator/macos/platform_files.mm create mode 100644 ion/src/simulator/shared/actions.cpp create mode 100644 ion/src/simulator/shared/actions.h create mode 100644 ion/src/simulator/shared/dummy/actions.cpp create mode 100644 ion/src/simulator/shared/dummy/platform_files.cpp create mode 100644 ion/src/simulator/shared/dummy/state_file.cpp create mode 100644 ion/src/simulator/shared/platform_action_modifier_ctrl.cpp create mode 100644 ion/src/simulator/shared/platform_action_modifier_gui.cpp create mode 100644 ion/src/simulator/windows/platform_files.cpp diff --git a/ion/src/simulator/linux/Makefile b/ion/src/simulator/linux/Makefile index 5425edddd..a52e873eb 100644 --- a/ion/src/simulator/linux/Makefile +++ b/ion/src/simulator/linux/Makefile @@ -9,18 +9,23 @@ SFLAGS += -Iion/src/simulator/linux/include ion_src += $(addprefix ion/src/simulator/linux/, \ assets.s \ + platform_files.cpp \ platform_images.cpp \ platform_language.cpp \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ - dummy/callback.cpp \ dummy/haptics_enabled.cpp \ + dummy/keyboard_callback.cpp \ + dummy/window_callback.cpp \ + actions.cpp \ clipboard_helper.cpp \ collect_registers_x86_64.s \ collect_registers.cpp \ haptics.cpp \ journal.cpp \ + platform_action_modifier_ctrl.cpp \ + state_file.cpp \ ) ifeq ($(EPSILON_TELEMETRY),1) diff --git a/ion/src/simulator/linux/platform_files.cpp b/ion/src/simulator/linux/platform_files.cpp new file mode 100644 index 000000000..b866fe05c --- /dev/null +++ b/ion/src/simulator/linux/platform_files.cpp @@ -0,0 +1,21 @@ +#include "../shared/platform.h" + +namespace Ion { +namespace Simulator { +namespace Platform { + +const char * filePathForReading(const char * extension) { + return nullptr; +} + +const char * filePathForWriting(const char * extension) { + static char path[64]; + if (snprintf(path, sizeof(path), "/tmp/epsilon.%s", extension) < 0) { + return nullptr; + } + return path; +} + +} +} +} diff --git a/ion/src/simulator/macos/Makefile b/ion/src/simulator/macos/Makefile index 238da5daf..52a76b36a 100644 --- a/ion/src/simulator/macos/Makefile +++ b/ion/src/simulator/macos/Makefile @@ -1,4 +1,5 @@ ion_src += $(addprefix ion/src/simulator/macos/, \ + platform_files.mm \ platform_images.mm \ ) @@ -10,8 +11,10 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ clipboard_helper.cpp \ collect_registers_x86_64.s \ collect_registers.cpp \ + actions.cpp \ haptics.cpp \ journal.cpp \ + state_file.cpp \ ) ifeq ($(EPSILON_TELEMETRY),1) diff --git a/ion/src/simulator/macos/platform_files.mm b/ion/src/simulator/macos/platform_files.mm new file mode 100644 index 000000000..990cf3a5f --- /dev/null +++ b/ion/src/simulator/macos/platform_files.mm @@ -0,0 +1,32 @@ +#include "../shared/platform.h" +#include + +namespace Ion { +namespace Simulator { +namespace Platform { + +static const char * getPath(NSSavePanel * panel, const char * extension) { + [panel setAllowedFileTypes:[NSArray arrayWithObject:[NSString stringWithUTF8String:extension]]]; + static NSString * path = nil; + [path release]; path = nil; // Discard previous path if any + NSWindow * mainWindow = [[NSApplication sharedApplication] keyWindow]; + if ([panel runModal] == NSFileHandlingPanelOKButton) { + path = [[[panel URL] path] retain]; + } + [mainWindow makeKeyAndOrderFront:nil]; + return [path UTF8String]; +} + +const char * filePathForReading(const char * extension) { + NSOpenPanel * panel = [NSOpenPanel openPanel]; + return getPath(panel, extension); +} + +const char * filePathForWriting(const char * extension) { + NSSavePanel * panel = [NSSavePanel savePanel]; + return getPath(panel, extension); +} + +} +} +} diff --git a/ion/src/simulator/shared/actions.cpp b/ion/src/simulator/shared/actions.cpp new file mode 100644 index 000000000..81716d03f --- /dev/null +++ b/ion/src/simulator/shared/actions.cpp @@ -0,0 +1,38 @@ +#include "actions.h" +#include "framebuffer.h" +#include "platform.h" +#include "state_file.h" + +namespace Ion { +namespace Simulator { +namespace Actions { + +constexpr const char * kStateFileExtension = "nws"; + +void saveState() { + const char * path = Platform::filePathForWriting(kStateFileExtension); + if (path != nullptr) { + StateFile::save(path); + } +} + +#if 0 +void loadState() { +// We would need to be able to perform a reset for this to be callable anytime + const char * path = Platform::filePathForReading(kStateFileExtension); + if (path != nullptr) { + StateFile::load(path); + } +} +#endif + +void takeScreenshot() { + const char * path = Platform::filePathForWriting("png"); + if (path != nullptr) { +// Framebuffer::writeToFile(path); + } +} + +} +} +} diff --git a/ion/src/simulator/shared/actions.h b/ion/src/simulator/shared/actions.h new file mode 100644 index 000000000..ad5b1f3e2 --- /dev/null +++ b/ion/src/simulator/shared/actions.h @@ -0,0 +1,17 @@ +#ifndef ION_SIMULATOR_ACTIONS_H +#define ION_SIMULATOR_ACTIONS_H + +#include + +namespace Ion { +namespace Simulator { +namespace Actions { + +void saveState(); +void takeScreenshot(); + +} +} +} + +#endif diff --git a/ion/src/simulator/shared/dummy/actions.cpp b/ion/src/simulator/shared/dummy/actions.cpp new file mode 100644 index 000000000..1e9055507 --- /dev/null +++ b/ion/src/simulator/shared/dummy/actions.cpp @@ -0,0 +1,22 @@ +#include "../actions.h" + +namespace Ion { +namespace Simulator { +namespace Actions { + +bool actionForEvent(SDL_KeyboardEvent event) { + return false; +} + +void saveState() { +} + +void loadState() { +} + +void takeScreenshot() { +} + +} +} +} diff --git a/ion/src/simulator/shared/dummy/platform_files.cpp b/ion/src/simulator/shared/dummy/platform_files.cpp new file mode 100644 index 000000000..fb73fbf22 --- /dev/null +++ b/ion/src/simulator/shared/dummy/platform_files.cpp @@ -0,0 +1,17 @@ +#include "../platform.h" + +namespace Ion { +namespace Simulator { +namespace Platform { + +const char * filePathForReading(const char * extension) { + return nullptr; +} + +const char * filePathForWriting(const char * extension) { + return nullptr; +} + +} +} +} diff --git a/ion/src/simulator/shared/dummy/state_file.cpp b/ion/src/simulator/shared/dummy/state_file.cpp new file mode 100644 index 000000000..462f5a213 --- /dev/null +++ b/ion/src/simulator/shared/dummy/state_file.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include "journal.h" + +namespace Ion { +namespace Simulator { +namespace StateFile { + +static constexpr const char * sHeader = "NWSF"; +static constexpr int sHeaderLength = 4; +static constexpr int sVersionLength = 8; + +/* File format: * "NWSF" + "XXXXXXXX" (version) + EVENTS... */ + +static inline bool load(FILE * f) { + char buffer[sVersionLength+1]; + + // Header + buffer[sHeaderLength] = 0; + if (fread(buffer, sHeaderLength, 1, f) != 1) { + return false; + } + printf("READ\n"); + if (strcmp(buffer, sHeader) != 0) { + return false; + } + + // Software version + buffer[sVersionLength] = 0; + if (fread(buffer, sVersionLength, 1, f) != 1) { + return false; + } + if (strcmp(buffer, softwareVersion()) != 0) { + return false; + } + + // Events + Ion::Events::Journal * journal = Journal::replayJournal(); + while (fread(buffer, 1, 1, f) == 1) { + Ion::Events::Event e = Ion::Events::Event(buffer[0]); + journal->pushEvent(e); + } + Ion::Events::replayFrom(journal); + + return true; +} + +void load(const char * filename) { + FILE * f = nullptr; + if (strcmp(filename, "-") == 0) { + f = stdin; + } else { + f = fopen(filename, "rb"); + } + if (f == nullptr) { + return; + } + load(f); + fclose(f); +} + +static inline bool save(FILE * f) { + if (fwrite(sHeader, sHeaderLength, 1, f) != 1) { + return false; + } + if (fwrite(softwareVersion(), sVersionLength, 1, f) != 1) { + return false; + } + Ion::Events::Journal * journal = Journal::logJournal(); + Ion::Events::Event e; + while (!journal->isEmpty()) { + Ion::Events::Event e = journal->popEvent(); + uint8_t code = static_cast(e); + if (fwrite(&code, 1, 1, f) != 1) { + return false; + } + } + return true; +} + +void save(const char * filename) { + printf("Saving to \"%s\"\n", filename); + FILE * f = fopen(filename, "w"); + if (f == nullptr) { + return; + } + save(f); + fclose(f); +} + +} +} +} diff --git a/ion/src/simulator/shared/events_platform.cpp b/ion/src/simulator/shared/events_platform.cpp index 072b3bc2b..f89bd881e 100644 --- a/ion/src/simulator/shared/events_platform.cpp +++ b/ion/src/simulator/shared/events_platform.cpp @@ -1,6 +1,8 @@ +#include "actions.h" +#include "events.h" #include "keyboard.h" #include "layout.h" -#include "events.h" +#include "state_file.h" #include "window.h" #include @@ -12,7 +14,7 @@ namespace Ion { namespace Events { -static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { +static inline Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { /* If an event is detected, we want to remove the Shift modifier to mimic the * device behaviour. If no event was detected, we restore the previous * ShiftAlphaStatus. */ @@ -120,8 +122,7 @@ static Event eventFromSDLTextInputEvent(SDL_TextInputEvent event) { Event getPlatformEvent() { SDL_Event event; Event result = None; - while (SDL_PollEvent(&event)) { - // The while is important: it'll do a fast-pass over all useless SDL events + while (SDL_PollEvent(&event)) { // That "while" is important: it'll do a fast-pass over all useless SDL events if (event.type == SDL_WINDOWEVENT) { Ion::Simulator::Window::relayout(); break; diff --git a/ion/src/simulator/shared/main.cpp b/ion/src/simulator/shared/main.cpp index c05ac937c..d93cbe225 100644 --- a/ion/src/simulator/shared/main.cpp +++ b/ion/src/simulator/shared/main.cpp @@ -2,6 +2,7 @@ #include "journal.h" #include "platform.h" #include "random.h" +#include "state_file.h" #include "telemetry.h" #include "window.h" #include diff --git a/ion/src/simulator/shared/platform_action_modifier_ctrl.cpp b/ion/src/simulator/shared/platform_action_modifier_ctrl.cpp new file mode 100644 index 000000000..9f6c3a3f2 --- /dev/null +++ b/ion/src/simulator/shared/platform_action_modifier_ctrl.cpp @@ -0,0 +1,13 @@ +#include "../shared/platform.h" + +namespace Ion { +namespace Simulator { +namespace Platform { + +SDL_Keymod actionModifier() { + return static_cast(KMOD_CTRL); +} + +} +} +} diff --git a/ion/src/simulator/shared/platform_action_modifier_gui.cpp b/ion/src/simulator/shared/platform_action_modifier_gui.cpp new file mode 100644 index 000000000..b9f3021ad --- /dev/null +++ b/ion/src/simulator/shared/platform_action_modifier_gui.cpp @@ -0,0 +1,13 @@ +#include "../shared/platform.h" + +namespace Ion { +namespace Simulator { +namespace Platform { + +SDL_Keymod actionModifier() { + return KMOD_GUI; +} + +} +} +} diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index c79e47f99..5e980c274 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -21,6 +21,7 @@ ion_src += $(addprefix ion/src/simulator/web/, \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ + dummy/actions.cpp \ dummy/language.cpp \ dummy/haptics_enabled.cpp \ haptics.cpp \ diff --git a/ion/src/simulator/web/exports.cpp b/ion/src/simulator/web/exports.cpp index babe1825c..e4f32ce2b 100644 --- a/ion/src/simulator/web/exports.cpp +++ b/ion/src/simulator/web/exports.cpp @@ -1,6 +1,7 @@ #include "exports.h" -#include "../shared/events_journal.h" +#include "../shared/journal.h" #include "../shared/keyboard.h" +#include "../shared/window.h" #include const char * IonSoftwareVersion() { @@ -27,7 +28,7 @@ void IonSimulatorKeyboardKeyUp(int keyNumber) { } void IonSimulatorEventsPushEvent(int eventNumber) { - Ion::Events::Journal * j = Ion::Simulator::Events::replayJournal(); + Ion::Events::Journal * j = Ion::Simulator::Journal::replayJournal(); if (j != nullptr) { Ion::Events::Event event(eventNumber); j->pushEvent(event); diff --git a/ion/src/simulator/windows/Makefile b/ion/src/simulator/windows/Makefile index 3bb4528b8..0ebf03945 100644 --- a/ion/src/simulator/windows/Makefile +++ b/ion/src/simulator/windows/Makefile @@ -1,4 +1,5 @@ ion_src += $(addprefix ion/src/simulator/windows/, \ + platform_files.cpp \ platform_images.cpp \ platform_language.cpp \ resources.rc \ @@ -8,9 +9,12 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/haptics_enabled.cpp \ dummy/keyboard_callback.cpp \ dummy/window_callback.cpp \ + actions.cpp \ clipboard_helper.cpp \ haptics.cpp \ journal.cpp \ + platform_action_modifier_ctrl.cpp \ + state_file.cpp \ ) ion_src += ion/src/shared/collect_registers.cpp diff --git a/ion/src/simulator/windows/platform_files.cpp b/ion/src/simulator/windows/platform_files.cpp new file mode 100644 index 000000000..865f47179 --- /dev/null +++ b/ion/src/simulator/windows/platform_files.cpp @@ -0,0 +1,51 @@ +#include "../shared/platform.h" +#include +#include + +namespace Ion { +namespace Simulator { +namespace Platform { + +static OPENFILENAME * getOFN(const char * extension) { + static OPENFILENAME ofn; + memset(&ofn, 0, sizeof(ofn)); // Zero-out ofn + + static char path[PATH_MAX]; + path[0] = 0; // Reset the path + + static char filter[32]; + if (snprintf(filter, sizeof(filter), "%s%c*.%s%c%c", extension, 0, extension, 0, 0) < 0) { + /* Note: We cannot use litteral \0 in the format string, otherwise snprintf + * will think the format string is finished... */ + return nullptr; + } + + ofn.lStructSize = sizeof(ofn); + ofn.lpstrFile = path; + ofn.nMaxFile = sizeof(path); + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 1; + ofn.lpstrDefExt = extension; + + return &ofn; +} + +const char * filePathForReading(const char * extension) { + OPENFILENAME * ofn = getOFN(extension); + if (ofn != nullptr && GetOpenFileName(ofn)) { + return ofn->lpstrFile; + } + return nullptr; +} + +const char * filePathForWriting(const char * extension) { + OPENFILENAME * ofn = getOFN(extension); + if (ofn != nullptr && GetSaveFileName(ofn)) { + return ofn->lpstrFile; + } + return nullptr; +} + +} +} +} From cb3a6694a5326ed125db48e0d8b0f17383558ca4 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 16:05:42 -0400 Subject: [PATCH 027/105] [ion/simulator/macos] Register the nws file extension --- ion/src/simulator/macos/Info.plist | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ion/src/simulator/macos/Info.plist b/ion/src/simulator/macos/Info.plist index 43a8402cb..6ff8b19de 100644 --- a/ion/src/simulator/macos/Info.plist +++ b/ion/src/simulator/macos/Info.plist @@ -20,6 +20,41 @@ MacOSX + CFBundleDocumentTypes + + + CFBundleTypeName + Nacho MNDL file + CFBundleTypeRole + Editor + LSHandlerRank + Owner + LSItemContentTypes + + com.numworks.savefile + + + + UTExportedTypeDeclarations + + + UTTypeIdentifier + com.numworks.savefile + UTTypeConformsTo + + public.data + + UTTypeDescription + NumWorks save file + UTTypeTagSpecification + + public.filename-extension + + nws + + + + NSHumanReadableCopyright Copyright © 2019 NumWorks. All rights reserved. NSPrincipalClass From 3740e0f135b76259a7eefea8013be1bed286605f Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 16:06:08 -0400 Subject: [PATCH 028/105] [ion/simulator] Support headless msleep --- ion/src/simulator/shared/timing_msleep.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ion/src/simulator/shared/timing_msleep.cpp b/ion/src/simulator/shared/timing_msleep.cpp index f7ab7565e..128330a0a 100644 --- a/ion/src/simulator/shared/timing_msleep.cpp +++ b/ion/src/simulator/shared/timing_msleep.cpp @@ -1,6 +1,10 @@ #include +#include "window.h" #include void Ion::Timing::msleep(uint32_t ms) { + if (Ion::Simulator::Window::isHeadless()) { + return; + } SDL_Delay(ms); } From f37008d8d74959a0834f171b38dfd20e354e3255 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 16:38:42 -0400 Subject: [PATCH 029/105] [ion/simulator] Ignore empty cli arguments --- ion/src/simulator/shared/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ion/src/simulator/shared/main.cpp b/ion/src/simulator/shared/main.cpp index d93cbe225..c84611892 100644 --- a/ion/src/simulator/shared/main.cpp +++ b/ion/src/simulator/shared/main.cpp @@ -24,8 +24,10 @@ public: const char * pop(const char * key); bool popFlag(const char * flag); void push(const char * key, const char * value) { - m_arguments.push_back(key); - m_arguments.push_back(value); + if (key != nullptr && value != nullptr) { + m_arguments.push_back(key); + m_arguments.push_back(value); + } } void push(const char * argument) { m_arguments.push_back(argument); } int argc() const { return m_arguments.size(); } From 2cf6f15dde8422d47b54a2e232f7a177820d804f Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 16:39:08 -0400 Subject: [PATCH 030/105] [ion/simulator] Allow CTRL or GUI for common shortcuts --- ion/src/simulator/shared/events_platform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/simulator/shared/events_platform.cpp b/ion/src/simulator/shared/events_platform.cpp index f89bd881e..c69bde84a 100644 --- a/ion/src/simulator/shared/events_platform.cpp +++ b/ion/src/simulator/shared/events_platform.cpp @@ -21,7 +21,7 @@ static inline Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { Ion::Events::ShiftAlphaStatus previousShiftAlphaStatus = Ion::Events::shiftAlphaStatus(); Ion::Events::removeShift(); - if (event.keysym.mod & KMOD_CTRL) { + if (event.keysym.mod & (KMOD_CTRL|KMOD_GUI)) { switch (event.keysym.sym) { case SDLK_x: return Cut; From a4213dcca8a92d812de412b6d6fedd8f91ceedea Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 16:39:35 -0400 Subject: [PATCH 031/105] [ion/simulator] Allow "-" to designate stdin --- ion/src/simulator/shared/state_file.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/shared/state_file.cpp b/ion/src/simulator/shared/state_file.cpp index d51fde9a7..509c452cd 100644 --- a/ion/src/simulator/shared/state_file.cpp +++ b/ion/src/simulator/shared/state_file.cpp @@ -48,7 +48,12 @@ static inline bool load(FILE * f) { } void load(const char * filename) { - FILE * f = fopen(filename, "rb"); + FILE * f = nullptr; + if (strcmp(filename, "-") == 0) { + f = stdin; + } else { + f = fopen(filename, "rb"); + } if (f == nullptr) { return; } From ab1df4fbefa180de70f6e84392a0ecd2d0ddf5e9 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 16:56:30 -0400 Subject: [PATCH 032/105] [ion/simulator] Unify iOS/macOS image loading --- ion/src/simulator/ios/Makefile | 5 +- ion/src/simulator/ios/platform_images.mm | 62 ------------------- ion/src/simulator/macos/Makefile | 2 +- .../apple}/platform_images.mm | 18 ++++-- 4 files changed, 16 insertions(+), 71 deletions(-) delete mode 100644 ion/src/simulator/ios/platform_images.mm rename ion/src/simulator/{macos => shared/apple}/platform_images.mm (74%) diff --git a/ion/src/simulator/ios/Makefile b/ion/src/simulator/ios/Makefile index 6a51f63d3..efb5cd9a8 100644 --- a/ion/src/simulator/ios/Makefile +++ b/ion/src/simulator/ios/Makefile @@ -1,8 +1,5 @@ -ion_src += $(addprefix ion/src/simulator/ios/, \ - platform_images.mm \ -) - ion_src += $(addprefix ion/src/simulator/shared/, \ + apple/platform_images.mm \ apple/platform_language.mm \ dummy/haptics_enabled.cpp \ dummy/journal.cpp \ diff --git a/ion/src/simulator/ios/platform_images.mm b/ion/src/simulator/ios/platform_images.mm deleted file mode 100644 index 3d3bb70b2..000000000 --- a/ion/src/simulator/ios/platform_images.mm +++ /dev/null @@ -1,62 +0,0 @@ -#include "../shared/platform.h" -#include -#include - -namespace Ion { -namespace Simulator { -namespace Platform { - -SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { - CGImageRef cgImage = [[UIImage imageNamed:[NSString stringWithUTF8String:identifier]] CGImage]; - if (cgImage == NULL) { - return NULL; - } - size_t width = CGImageGetWidth(cgImage); - size_t height = CGImageGetHeight(cgImage); - - - size_t bytesPerPixel = 4; - size_t bytesPerRow = bytesPerPixel * width; - size_t bitsPerComponent = 8; - - size_t size = height * width * bytesPerPixel; - void * bitmapData = malloc(size); - memset(bitmapData, 0, size); - - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGContextRef context = CGBitmapContextCreate( - bitmapData, width, height, - bitsPerComponent, bytesPerRow, colorSpace, - kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big - ); - - CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); - - CGContextRelease(context); - CGColorSpaceRelease(colorSpace); - - SDL_Texture * texture = SDL_CreateTexture( - renderer, - SDL_PIXELFORMAT_ABGR8888, - SDL_TEXTUREACCESS_STATIC, - width, - height - ); - - SDL_UpdateTexture( - texture, - NULL, - bitmapData, - bytesPerPixel * width - ); - - SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); - - free(bitmapData); - - return texture; -} - -} -} -} diff --git a/ion/src/simulator/macos/Makefile b/ion/src/simulator/macos/Makefile index 52a76b36a..8fc361b7e 100644 --- a/ion/src/simulator/macos/Makefile +++ b/ion/src/simulator/macos/Makefile @@ -1,9 +1,9 @@ ion_src += $(addprefix ion/src/simulator/macos/, \ platform_files.mm \ - platform_images.mm \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ + apple/platform_images.mm \ apple/platform_language.mm \ dummy/haptics_enabled.cpp \ dummy/keyboard_callback.cpp \ diff --git a/ion/src/simulator/macos/platform_images.mm b/ion/src/simulator/shared/apple/platform_images.mm similarity index 74% rename from ion/src/simulator/macos/platform_images.mm rename to ion/src/simulator/shared/apple/platform_images.mm index 1cf9f61a9..1b68a11f3 100644 --- a/ion/src/simulator/macos/platform_images.mm +++ b/ion/src/simulator/shared/apple/platform_images.mm @@ -1,17 +1,27 @@ #include "../shared/platform.h" - #include +#include +#if TARGET_OS_MAC #include +#else +#include +#endif namespace Ion { namespace Simulator { namespace Platform { SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { + CGImageRef cgImage = NULL; +#if TARGET_OS_MAC + //http://lists.libsdl.org/pipermail/commits-libsdl.org/2016-December/001235.html + [[[NSApp windows] firstObject] setColorSpace:[NSColorSpace sRGBColorSpace]]; + NSImage * nsImage = [NSImage imageNamed:[NSString stringWithUTF8String:identifier]]; - CGImageRef cgImage = [nsImage CGImageForProposedRect:NULL - context:NULL - hints:0]; + cgImage = [nsImage CGImageForProposedRect:NULL context:NULL hints:0]; +#else + cgImage = [[UIImage imageNamed:[NSString stringWithUTF8String:identifier]] CGImage]; +#endif if (cgImage == NULL) { return NULL; } From 0587e41b3c8cb01f6fb5b1d648f46d27d53cd395 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 22:26:56 -0400 Subject: [PATCH 033/105] [ion/simulator] Support writing image files per-platform Linux uses libpng, macOS/iOS use CoreGraphics, Windows GDI+ --- ion/src/simulator/Makefile | 10 +- ion/src/simulator/linux/Makefile | 7 +- ion/src/simulator/linux/platform_images.cpp | 53 ++++++++- ion/src/simulator/macos/Makefile | 4 +- ion/src/simulator/shared/actions.cpp | 7 +- .../simulator/shared/apple/platform_images.mm | 104 +++++++++++++----- ion/src/simulator/shared/dummy/actions.cpp | 22 ---- .../simulator/shared/dummy/platform_files.cpp | 17 --- ion/src/simulator/shared/dummy/state_file.cpp | 95 ---------------- ion/src/simulator/shared/events_platform.cpp | 8 ++ .../{framebuffer_base.cpp => framebuffer.cpp} | 0 ion/src/simulator/shared/framebuffer.h | 1 - ion/src/simulator/shared/framebuffer_png.cpp | 57 ---------- ion/src/simulator/shared/main.cpp | 7 ++ ion/src/simulator/shared/platform.h | 6 + ion/src/simulator/web/Makefile | 1 - ion/src/simulator/windows/Makefile | 2 + ion/src/simulator/windows/platform_images.cpp | 72 +++++++++++- 18 files changed, 240 insertions(+), 233 deletions(-) delete mode 100644 ion/src/simulator/shared/dummy/actions.cpp delete mode 100644 ion/src/simulator/shared/dummy/platform_files.cpp delete mode 100644 ion/src/simulator/shared/dummy/state_file.cpp rename ion/src/simulator/shared/{framebuffer_base.cpp => framebuffer.cpp} (100%) delete mode 100644 ion/src/simulator/shared/framebuffer_png.cpp diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index 5a18da565..2cf5fbb82 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -23,7 +23,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ display.cpp:-headless \ events.cpp \ events_platform.cpp:-headless \ - framebuffer_base.cpp \ + framebuffer.cpp \ framebuffer_png.cpp:+headless \ keyboard.cpp:-headless \ layout.cpp:-headless \ @@ -39,3 +39,11 @@ ion_simulator_assets_paths = $(add_prefix ion/src/simulator/assets/,$(ion_simula include ion/src/simulator/$(TARGET)/Makefile include ion/src/simulator/external/Makefile + +ifeq ($(ION_SIMULATOR_FILES),1) +ion_src += $(addprefix ion/src/simulator/shared/, \ + actions.cpp \ + state_file.cpp \ +) +SFLAGS += -DION_SIMULATOR_FILES=1 +endif diff --git a/ion/src/simulator/linux/Makefile b/ion/src/simulator/linux/Makefile index a52e873eb..449ef3651 100644 --- a/ion/src/simulator/linux/Makefile +++ b/ion/src/simulator/linux/Makefile @@ -1,5 +1,6 @@ -# The following lines allow us to use our own SDL_config.h +ION_SIMULATOR_FILES = 1 +# The following lines allow us to use our own SDL_config.h # First, make sure an error is raised if we ever use the standard SDL_config.h SFLAGS += -DUSING_GENERATED_CONFIG_H # Then use our very own include dir if either SDL.h or SDL_config.h are included @@ -33,7 +34,7 @@ ion_src += ion/src/simulator/shared/dummy/telemetry_init.cpp ion_src += ion/src/shared/telemetry_console.cpp endif -LDFLAGS += -ljpeg +LDFLAGS += -ljpeg -lpng $(eval $(call rule_for, \ INCBIN, \ @@ -46,4 +47,4 @@ $(eval $(call rule_for, \ $(call object_for,ion/src/simulator/linux/platform_images.cpp): $(BUILD_DIR)/ion/src/simulator/linux/platform_images.h # The header is refered to as so make sure it's findable this way -SFLAGS += -I$(BUILD_DIR) +$(call object_for,ion/src/simulator/linux/platform_images.cpp): SFLAGS += -I$(BUILD_DIR) diff --git a/ion/src/simulator/linux/platform_images.cpp b/ion/src/simulator/linux/platform_images.cpp index a3ec43760..0fb23867b 100644 --- a/ion/src/simulator/linux/platform_images.cpp +++ b/ion/src/simulator/linux/platform_images.cpp @@ -1,9 +1,10 @@ #include "../shared/platform.h" -#include +#include #include #include -#include +#include +#include #include @@ -166,6 +167,54 @@ SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { return texture; } +class RGB888Pixel { +public: + RGB888Pixel() {} + RGB888Pixel(KDColor c) : + m_red(c.red()), + m_green(c.green()), + m_blue(c.blue()) { + } +private: + uint8_t m_red; + uint8_t m_green; + uint8_t m_blue; +}; +static_assert(sizeof(RGB888Pixel) == 3, "RGB888Pixel shall be 3 bytes long"); + +void saveImage(const KDColor * pixels, int width, int height, const char * path) { + FILE * file = fopen(path, "wb"); // Write in binary mode + + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + png_infop info = png_create_info_struct(png); + png_init_io(png, file); + + png_set_IHDR(png, info, + width, height, + 8, // Number of bits per channel + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png, info); + + RGB888Pixel * row = new RGB888Pixel[3*width]; + for (int j=0;j(row)); + } + delete row; + + png_write_end(png, NULL); + + png_free_data(png, info, PNG_FREE_ALL, -1); // -1 = all items + png_destroy_write_struct(&png, nullptr); + fclose(file); +} + } } } diff --git a/ion/src/simulator/macos/Makefile b/ion/src/simulator/macos/Makefile index 8fc361b7e..a640a6571 100644 --- a/ion/src/simulator/macos/Makefile +++ b/ion/src/simulator/macos/Makefile @@ -1,3 +1,5 @@ +ION_SIMULATOR_FILES = 1 + ion_src += $(addprefix ion/src/simulator/macos/, \ platform_files.mm \ ) @@ -11,10 +13,8 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ clipboard_helper.cpp \ collect_registers_x86_64.s \ collect_registers.cpp \ - actions.cpp \ haptics.cpp \ journal.cpp \ - state_file.cpp \ ) ifeq ($(EPSILON_TELEMETRY),1) diff --git a/ion/src/simulator/shared/actions.cpp b/ion/src/simulator/shared/actions.cpp index 81716d03f..ee8395f3f 100644 --- a/ion/src/simulator/shared/actions.cpp +++ b/ion/src/simulator/shared/actions.cpp @@ -1,4 +1,5 @@ #include "actions.h" +#include #include "framebuffer.h" #include "platform.h" #include "state_file.h" @@ -29,7 +30,11 @@ void loadState() { void takeScreenshot() { const char * path = Platform::filePathForWriting("png"); if (path != nullptr) { -// Framebuffer::writeToFile(path); + Platform::saveImage( + Framebuffer::address(), + Display::Width, Display::Height, + path + ); } } diff --git a/ion/src/simulator/shared/apple/platform_images.mm b/ion/src/simulator/shared/apple/platform_images.mm index 1b68a11f3..3d7338c04 100644 --- a/ion/src/simulator/shared/apple/platform_images.mm +++ b/ion/src/simulator/shared/apple/platform_images.mm @@ -1,4 +1,4 @@ -#include "../shared/platform.h" +#include "../platform.h" #include #include #if TARGET_OS_MAC @@ -11,42 +11,50 @@ namespace Ion { namespace Simulator { namespace Platform { +static CGContextRef createABGR8888Context(size_t width, size_t height) { + size_t bytesPerPixel = 4; + size_t bytesPerRow = bytesPerPixel * width; + size_t bitsPerComponent = 8; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate( + nullptr, // The context will allocate and take ownership of the bitmap buffer + width, height, + bitsPerComponent, bytesPerRow, colorSpace, + kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big + ); + if (colorSpace) { + CFRelease(colorSpace); + } + return context; +} + SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { - CGImageRef cgImage = NULL; + CGImageRef image = nullptr; #if TARGET_OS_MAC //http://lists.libsdl.org/pipermail/commits-libsdl.org/2016-December/001235.html [[[NSApp windows] firstObject] setColorSpace:[NSColorSpace sRGBColorSpace]]; NSImage * nsImage = [NSImage imageNamed:[NSString stringWithUTF8String:identifier]]; - cgImage = [nsImage CGImageForProposedRect:NULL context:NULL hints:0]; + image = [nsImage CGImageForProposedRect:NULL context:NULL hints:0]; #else - cgImage = [[UIImage imageNamed:[NSString stringWithUTF8String:identifier]] CGImage]; + image = [[UIImage imageNamed:[NSString stringWithUTF8String:identifier]] CGImage]; #endif - if (cgImage == NULL) { - return NULL; + if (image == nullptr) { + return nullptr; } - size_t width = CGImageGetWidth(cgImage); - size_t height = CGImageGetHeight(cgImage); - size_t bytesPerPixel = 4; - size_t bytesPerRow = bytesPerPixel * width; - size_t bitsPerComponent = 8; + size_t width = CGImageGetWidth(image); + size_t height = CGImageGetHeight(image); - size_t size = height * width * bytesPerPixel; - void * bitmapData = malloc(size); - memset(bitmapData, 0, size); + CGContextRef context = createABGR8888Context(width, height); + if (context == nullptr) { + return nullptr; + } - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGContextRef context = CGBitmapContextCreate( - bitmapData, width, height, - bitsPerComponent, bytesPerRow, colorSpace, - kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big - ); + void * argb8888Pixels = CGBitmapContextGetData(context); - CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); - - CGContextRelease(context); - CGColorSpaceRelease(colorSpace); + CGContextDrawImage(context, CGRectMake(0, 0, width, height), image); SDL_Texture * texture = SDL_CreateTexture( renderer, @@ -56,20 +64,64 @@ SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier) { height ); + size_t bytesPerPixel = 4; + SDL_UpdateTexture( texture, NULL, - bitmapData, + argb8888Pixels, bytesPerPixel * width ); SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); - free(bitmapData); + CGContextRelease(context); return texture; } +class ABGR8888Pixel { +public: + ABGR8888Pixel(KDColor c) : + m_red(c.red()), + m_green(c.green()), + m_blue(c.blue()), + m_alpha(255) { + } +private: + uint8_t m_red; + uint8_t m_green; + uint8_t m_blue; + uint8_t m_alpha; +}; +static_assert(sizeof(ABGR8888Pixel) == 4, "ARGB8888Pixel shall be 4 bytes long"); + +void saveImage(const KDColor * pixels, int width, int height, const char * path) { + CGContextRef context = createABGR8888Context(width, height); + if (context == nullptr) { + return; + } + ABGR8888Pixel * argb8888Pixels = static_cast(CGBitmapContextGetData(context)); + for (int i=0; i([NSURL fileURLWithPath:[NSString stringWithUTF8String:path]]); + + CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL); + CGImageDestinationAddImage(destination, image, nil); + CGImageDestinationFinalize(destination); + + if (destination) { + CFRelease(destination); + } + CGImageRelease(image); + CGContextRelease(context); +} + + } } } diff --git a/ion/src/simulator/shared/dummy/actions.cpp b/ion/src/simulator/shared/dummy/actions.cpp deleted file mode 100644 index 1e9055507..000000000 --- a/ion/src/simulator/shared/dummy/actions.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "../actions.h" - -namespace Ion { -namespace Simulator { -namespace Actions { - -bool actionForEvent(SDL_KeyboardEvent event) { - return false; -} - -void saveState() { -} - -void loadState() { -} - -void takeScreenshot() { -} - -} -} -} diff --git a/ion/src/simulator/shared/dummy/platform_files.cpp b/ion/src/simulator/shared/dummy/platform_files.cpp deleted file mode 100644 index fb73fbf22..000000000 --- a/ion/src/simulator/shared/dummy/platform_files.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "../platform.h" - -namespace Ion { -namespace Simulator { -namespace Platform { - -const char * filePathForReading(const char * extension) { - return nullptr; -} - -const char * filePathForWriting(const char * extension) { - return nullptr; -} - -} -} -} diff --git a/ion/src/simulator/shared/dummy/state_file.cpp b/ion/src/simulator/shared/dummy/state_file.cpp deleted file mode 100644 index 462f5a213..000000000 --- a/ion/src/simulator/shared/dummy/state_file.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include -#include -#include "journal.h" - -namespace Ion { -namespace Simulator { -namespace StateFile { - -static constexpr const char * sHeader = "NWSF"; -static constexpr int sHeaderLength = 4; -static constexpr int sVersionLength = 8; - -/* File format: * "NWSF" + "XXXXXXXX" (version) + EVENTS... */ - -static inline bool load(FILE * f) { - char buffer[sVersionLength+1]; - - // Header - buffer[sHeaderLength] = 0; - if (fread(buffer, sHeaderLength, 1, f) != 1) { - return false; - } - printf("READ\n"); - if (strcmp(buffer, sHeader) != 0) { - return false; - } - - // Software version - buffer[sVersionLength] = 0; - if (fread(buffer, sVersionLength, 1, f) != 1) { - return false; - } - if (strcmp(buffer, softwareVersion()) != 0) { - return false; - } - - // Events - Ion::Events::Journal * journal = Journal::replayJournal(); - while (fread(buffer, 1, 1, f) == 1) { - Ion::Events::Event e = Ion::Events::Event(buffer[0]); - journal->pushEvent(e); - } - Ion::Events::replayFrom(journal); - - return true; -} - -void load(const char * filename) { - FILE * f = nullptr; - if (strcmp(filename, "-") == 0) { - f = stdin; - } else { - f = fopen(filename, "rb"); - } - if (f == nullptr) { - return; - } - load(f); - fclose(f); -} - -static inline bool save(FILE * f) { - if (fwrite(sHeader, sHeaderLength, 1, f) != 1) { - return false; - } - if (fwrite(softwareVersion(), sVersionLength, 1, f) != 1) { - return false; - } - Ion::Events::Journal * journal = Journal::logJournal(); - Ion::Events::Event e; - while (!journal->isEmpty()) { - Ion::Events::Event e = journal->popEvent(); - uint8_t code = static_cast(e); - if (fwrite(&code, 1, 1, f) != 1) { - return false; - } - } - return true; -} - -void save(const char * filename) { - printf("Saving to \"%s\"\n", filename); - FILE * f = fopen(filename, "w"); - if (f == nullptr) { - return; - } - save(f); - fclose(f); -} - -} -} -} diff --git a/ion/src/simulator/shared/events_platform.cpp b/ion/src/simulator/shared/events_platform.cpp index c69bde84a..0cffa62e2 100644 --- a/ion/src/simulator/shared/events_platform.cpp +++ b/ion/src/simulator/shared/events_platform.cpp @@ -29,6 +29,14 @@ static inline Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { return Copy; case SDLK_v: return Paste; +#if ION_SIMULATOR_FILES + case SDLK_s: + Simulator::Actions::saveState(); + return None; + case SDLK_p: + Simulator::Actions::takeScreenshot(); + return None; +#endif } } if (event.keysym.mod & KMOD_ALT) { diff --git a/ion/src/simulator/shared/framebuffer_base.cpp b/ion/src/simulator/shared/framebuffer.cpp similarity index 100% rename from ion/src/simulator/shared/framebuffer_base.cpp rename to ion/src/simulator/shared/framebuffer.cpp diff --git a/ion/src/simulator/shared/framebuffer.h b/ion/src/simulator/shared/framebuffer.h index e9eed19e2..9ae419e8e 100644 --- a/ion/src/simulator/shared/framebuffer.h +++ b/ion/src/simulator/shared/framebuffer.h @@ -9,7 +9,6 @@ namespace Framebuffer { const KDColor * address(); void setActive(bool enabled); -void writeToFile(const char * filename); } } diff --git a/ion/src/simulator/shared/framebuffer_png.cpp b/ion/src/simulator/shared/framebuffer_png.cpp deleted file mode 100644 index 9582e48e1..000000000 --- a/ion/src/simulator/shared/framebuffer_png.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#if EPSILON_SIMULATOR_HAS_LIBPNG - -#include "framebuffer.h" -#include -#include -#include - -typedef struct { - uint8_t red; - uint8_t green; - uint8_t blue; -} pixel_t; - -void Ion::Simulator::Framebuffer::writeToFile(const char * filename) { - FILE * file = fopen(filename, "wb"); // Write in binary mode - //ENSURE(file != NULL, "Opening file %s", filename); - - png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - //ENSURE(png != NULL, "Allocating PNG write structure"); - - png_infop info = png_create_info_struct(png); - //ENSURE(info != NULL, "Allocating info structure"); - - png_init_io(png, file); - - png_set_IHDR(png, info, - Ion::Display::Width, Ion::Display::Height, - 8, // Number of bits per channel - PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - png_write_info(png, info); - - static_assert(sizeof(pixel_t) == 3, "pixel_t shall be 3 bytes long (RGB888 format)"); - pixel_t * row = (pixel_t *)malloc(3*Ion::Display::Width); - const KDColor * pixels = address(); - for (int j=0;j +#include namespace Ion { namespace Simulator { @@ -9,6 +10,11 @@ namespace Platform { SDL_Texture * loadImage(SDL_Renderer * renderer, const char * identifier); const char * languageCode(); +#if ION_SIMULATOR_FILES +const char * filePathForReading(const char * extension); +const char * filePathForWriting(const char * extension); +void saveImage(const KDColor * pixels, int width, int height, const char * path); +#endif } } diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index 5e980c274..c79e47f99 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -21,7 +21,6 @@ ion_src += $(addprefix ion/src/simulator/web/, \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ - dummy/actions.cpp \ dummy/language.cpp \ dummy/haptics_enabled.cpp \ haptics.cpp \ diff --git a/ion/src/simulator/windows/Makefile b/ion/src/simulator/windows/Makefile index 0ebf03945..b44499e02 100644 --- a/ion/src/simulator/windows/Makefile +++ b/ion/src/simulator/windows/Makefile @@ -1,3 +1,5 @@ +ION_SIMULATOR_FILES = 1 + ion_src += $(addprefix ion/src/simulator/windows/, \ platform_files.cpp \ platform_images.cpp \ diff --git a/ion/src/simulator/windows/platform_images.cpp b/ion/src/simulator/windows/platform_images.cpp index 648ddbe35..436cabc04 100644 --- a/ion/src/simulator/windows/platform_images.cpp +++ b/ion/src/simulator/windows/platform_images.cpp @@ -8,7 +8,7 @@ #include /* Loading images using GDI+ - * On Windows, we decompress JPEG images using GDI+ which is widely available. + * On Windows, we manipulate images using GDI+ which is widely available. * Note that this adds an extra runtime dependency (as compared to just SDL), * but this should not be an issue. */ @@ -36,14 +36,63 @@ static inline HRESULT CreateStreamOnResource(const char * name, LPSTREAM * strea return hr; } +// Helper class to init/shutdown Gdiplus using RAII +class GdiplusSession { +public: + GdiplusSession() { + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, nullptr); + } + ~GdiplusSession() { + Gdiplus::GdiplusShutdown(m_gdiplusToken); + } +private: + ULONG_PTR m_gdiplusToken; +}; + +// Helper function from MSDN +// https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-retrieving-the-class-identifier-for-an-encoder-use +int GetEncoderClsid(const WCHAR * format, CLSID * pClsid) { + UINT num = 0; // number of image encoders + UINT size = 0; // size of the image encoder array in bytes + + Gdiplus::ImageCodecInfo * pImageCodecInfo = nullptr; + Gdiplus::GetImageEncodersSize(&num, &size); + if (size == 0) { + return -1; + } + pImageCodecInfo = static_cast(malloc(size)); + if (pImageCodecInfo == nullptr) { + return -1; + } + + Gdiplus::GetImageEncoders(num, size, pImageCodecInfo); + + for (UINT i=0; iUnlockBits(bitmapData); delete bitmapData; delete image; - Gdiplus::GdiplusShutdown(gdiplusToken); return texture; } +void saveImage(const KDColor * pixels, int width, int height, const char * path) { + static_assert(sizeof(KDColor) == 2, "KDColor expected to be RGB565"); + GdiplusSession session; + + Gdiplus::Bitmap bitmap(width, height, 2*width, PixelFormat16bppRGB565, reinterpret_cast(const_cast(pixels))); + + CLSID pngClsid; + if (GetEncoderClsid(L"image/png", &pngClsid) > 0) { + wchar_t * widePath = createWideCharArray(path); + bitmap.Save(widePath, &pngClsid, nullptr); + delete[] widePath; + } +} + } } } From c2f8bbaf3cbd546e72ede9911afaf65544e3426e Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 22:33:52 -0400 Subject: [PATCH 034/105] [ion/simulator] Load nws files sent from the host OS --- ion/src/simulator/shared/events_platform.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ion/src/simulator/shared/events_platform.cpp b/ion/src/simulator/shared/events_platform.cpp index 0cffa62e2..e1f322820 100644 --- a/ion/src/simulator/shared/events_platform.cpp +++ b/ion/src/simulator/shared/events_platform.cpp @@ -150,6 +150,12 @@ Event getPlatformEvent() { result = eventFromSDLTextInputEvent(event.text); break; } +#if ION_SIMULATOR_FILES + if (event.type == SDL_DROPFILE) { + Simulator::StateFile::load(event.drop.file); + break; + } +#endif #if !EPSILON_SDL_SCREEN_ONLY if (event.type == SDL_MOUSEMOTION) { SDL_Point p; From ba3109e47a65885cd12b166154965e04a765efdd Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 14 Sep 2020 17:21:16 -0400 Subject: [PATCH 035/105] [ion/simulator] Fix the dummy language implementation --- ion/src/simulator/shared/dummy/language.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/shared/dummy/language.cpp b/ion/src/simulator/shared/dummy/language.cpp index ac672ab47..18aedef3e 100644 --- a/ion/src/simulator/shared/dummy/language.cpp +++ b/ion/src/simulator/shared/dummy/language.cpp @@ -1,5 +1,13 @@ #include "../platform.h" -char * IonSimulatorGetLanguageCode() { +namespace Ion { +namespace Simulator { +namespace Platform { + +const char * languageCode() { return nullptr; } + +} +} +} From e8f1ea6aa5d36577d1b80c947887672d39f44daf Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 14 Sep 2020 17:21:35 -0400 Subject: [PATCH 036/105] [ion/simulator/sdl] Backport an Emscripten fix for setWindowTitle See https://bugzilla.libsdl.org/show_bug.cgi?id=5133 --- .../external/sdl/src/video/emscripten/SDL_emscriptenvideo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ion/src/simulator/external/sdl/src/video/emscripten/SDL_emscriptenvideo.c b/ion/src/simulator/external/sdl/src/video/emscripten/SDL_emscriptenvideo.c index 458d67afd..e20d7a985 100644 --- a/ion/src/simulator/external/sdl/src/video/emscripten/SDL_emscriptenvideo.c +++ b/ion/src/simulator/external/sdl/src/video/emscripten/SDL_emscriptenvideo.c @@ -348,8 +348,8 @@ Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * di static void Emscripten_SetWindowTitle(_THIS, SDL_Window * window) { EM_ASM_INT({ - if (typeof Module['setWindowTitle'] !== 'undefined') { - Module['setWindowTitle'](UTF8ToString($0)); + if (typeof setWindowTitle !== 'undefined') { + setWindowTitle(UTF8ToString($0)); } return 0; }, window->title); From c3c7651ca87658ebd0517f6d636c453e4a7f803b Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 16 Sep 2020 12:04:31 -0400 Subject: [PATCH 037/105] [ion/simulator] Add Termination event when headless --- ion/src/simulator/shared/events_platform.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ion/src/simulator/shared/events_platform.cpp b/ion/src/simulator/shared/events_platform.cpp index e1f322820..8dfc68671 100644 --- a/ion/src/simulator/shared/events_platform.cpp +++ b/ion/src/simulator/shared/events_platform.cpp @@ -1,5 +1,6 @@ #include "actions.h" #include "events.h" +#include "journal.h" #include "keyboard.h" #include "layout.h" #include "state_file.h" @@ -182,6 +183,13 @@ Event getPlatformEvent() { * the subsequent ones. */ SDL_FlushEvents(0, UINT32_MAX); } + if (Simulator::Window::isHeadless()) { + if (Simulator::Journal::replayJournal() == nullptr || Simulator::Journal::replayJournal()->isEmpty()) { + /* We don't want to keep the simulator process alive if there's no chance + * we're ever going to provide it with new events to process. */ + return Termination; + } + } return result; } From b32497da23c7572e5c1da8a8008275ac50f17752 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 16 Sep 2020 12:04:56 -0400 Subject: [PATCH 038/105] [ion/simulator] Remove a useless printf --- ion/src/simulator/shared/state_file.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/ion/src/simulator/shared/state_file.cpp b/ion/src/simulator/shared/state_file.cpp index 509c452cd..35e36c8fc 100644 --- a/ion/src/simulator/shared/state_file.cpp +++ b/ion/src/simulator/shared/state_file.cpp @@ -22,7 +22,6 @@ static inline bool load(FILE * f) { if (fread(buffer, sHeaderLength, 1, f) != 1) { return false; } - printf("READ\n"); if (strcmp(buffer, sHeader) != 0) { return false; } From 80598210255dd18c0ace006d5fd315321351ff43 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 15:03:30 -0400 Subject: [PATCH 039/105] [ion/simulator] Fix libpng/libjpeg usage --- build/platform.simulator.linux.mak | 2 -- build/platform.simulator.macos.mak | 2 -- build/platform.simulator.mak | 9 --------- ion/src/simulator/linux/Makefile | 5 +++-- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/build/platform.simulator.linux.mak b/build/platform.simulator.linux.mak index 87e07660d..19e01ba1e 100644 --- a/build/platform.simulator.linux.mak +++ b/build/platform.simulator.linux.mak @@ -1,4 +1,2 @@ TOOLCHAIN = host-gcc EXE = bin - -EPSILON_SIMULATOR_HAS_LIBPNG = 1 diff --git a/build/platform.simulator.macos.mak b/build/platform.simulator.macos.mak index 5f2c492e5..bbe011e52 100644 --- a/build/platform.simulator.macos.mak +++ b/build/platform.simulator.macos.mak @@ -6,8 +6,6 @@ APPLE_PLATFORM_MIN_VERSION = 10.10 ARCHS = x86_64 -EPSILON_SIMULATOR_HAS_LIBPNG = 1 - ifdef ARCH BUILD_DIR := $(BUILD_DIR)/$(ARCH) else diff --git a/build/platform.simulator.mak b/build/platform.simulator.mak index e25beb0b8..07f1edd9e 100644 --- a/build/platform.simulator.mak +++ b/build/platform.simulator.mak @@ -8,13 +8,4 @@ TARGET ?= $(HOST) BUILD_DIR := $(BUILD_DIR)/$(TARGET) -EPSILON_SIMULATOR_HAS_LIBPNG ?= 0 - include build/platform.simulator.$(TARGET).mak - -SFLAGS += -DEPSILON_SIMULATOR_HAS_LIBPNG=$(EPSILON_SIMULATOR_HAS_LIBPNG) - -ifeq ($(EPSILON_SIMULATOR_HAS_LIBPNG),1) -SFLAGS += `libpng-config --cflags` -LDFLAGS += `libpng-config --ldflags` -endif \ No newline at end of file diff --git a/ion/src/simulator/linux/Makefile b/ion/src/simulator/linux/Makefile index 449ef3651..ca7da03fa 100644 --- a/ion/src/simulator/linux/Makefile +++ b/ion/src/simulator/linux/Makefile @@ -15,6 +15,9 @@ ion_src += $(addprefix ion/src/simulator/linux/, \ platform_language.cpp \ ) +SFLAGS += $(shell pkg-config libpng libjpeg --cflags) +LDFLAGS += $(shell pkg-config libpng libjpeg --libs) + ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/haptics_enabled.cpp \ dummy/keyboard_callback.cpp \ @@ -34,8 +37,6 @@ ion_src += ion/src/simulator/shared/dummy/telemetry_init.cpp ion_src += ion/src/shared/telemetry_console.cpp endif -LDFLAGS += -ljpeg -lpng - $(eval $(call rule_for, \ INCBIN, \ ion/src/simulator/linux/assets.s ion/src/simulator/linux/platform_images.h, \ From f578c24af1c7007fb78b767b90e413d2e78257a5 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 15:49:11 -0400 Subject: [PATCH 040/105] [ion/simulator] Used buffer I/O Avoid making a syscall for every single byte --- ion/src/simulator/shared/state_file.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ion/src/simulator/shared/state_file.cpp b/ion/src/simulator/shared/state_file.cpp index 35e36c8fc..124c806fe 100644 --- a/ion/src/simulator/shared/state_file.cpp +++ b/ion/src/simulator/shared/state_file.cpp @@ -37,8 +37,9 @@ static inline bool load(FILE * f) { // Events Ion::Events::Journal * journal = Journal::replayJournal(); - while (fread(buffer, 1, 1, f) == 1) { - Ion::Events::Event e = Ion::Events::Event(buffer[0]); + int c = 0; + while ((c = getc(f)) != EOF) { + Ion::Events::Event e = Ion::Events::Event(c); journal->pushEvent(e); } Ion::Events::replayFrom(journal); From 7c8c7f79f60ac1baaed6797c338e8893c2c0aed9 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 15:49:30 -0400 Subject: [PATCH 041/105] [ion/simulator] Don't leak file descriptors --- ion/src/simulator/shared/state_file.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/shared/state_file.cpp b/ion/src/simulator/shared/state_file.cpp index 124c806fe..57057cfe8 100644 --- a/ion/src/simulator/shared/state_file.cpp +++ b/ion/src/simulator/shared/state_file.cpp @@ -58,7 +58,9 @@ void load(const char * filename) { return; } load(f); - fclose(f); + if (f != stdin) { + fclose(f); + } } static inline bool save(FILE * f) { From 82421136412cce34741c0ba6d1be39c4e07081d2 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 15:50:14 -0400 Subject: [PATCH 042/105] [ion/simulator] Ignore invalid events in nws files --- ion/src/simulator/shared/state_file.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/shared/state_file.cpp b/ion/src/simulator/shared/state_file.cpp index 57057cfe8..9c23ba0bc 100644 --- a/ion/src/simulator/shared/state_file.cpp +++ b/ion/src/simulator/shared/state_file.cpp @@ -40,7 +40,10 @@ static inline bool load(FILE * f) { int c = 0; while ((c = getc(f)) != EOF) { Ion::Events::Event e = Ion::Events::Event(c); - journal->pushEvent(e); + if (e.isDefined() && e.isKeyboardEvent()) { + // Avoid pushing invalid events - useful when fuzzing + journal->pushEvent(e); + } } Ion::Events::replayFrom(journal); From 6d18c33068e60c3cbf091a294c28ff2e0cda04c6 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 15:52:17 -0400 Subject: [PATCH 043/105] [ion/simulator] State files can have a wildcard version --- ion/src/simulator/shared/state_file.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/shared/state_file.cpp b/ion/src/simulator/shared/state_file.cpp index 9c23ba0bc..4b6e681ae 100644 --- a/ion/src/simulator/shared/state_file.cpp +++ b/ion/src/simulator/shared/state_file.cpp @@ -11,6 +11,7 @@ namespace StateFile { static constexpr const char * sHeader = "NWSF"; static constexpr int sHeaderLength = 4; static constexpr int sVersionLength = 8; +static constexpr const char * sWildcardVersion = "**.**.**"; /* File format: * "NWSF" + "XXXXXXXX" (version) + EVENTS... */ @@ -31,7 +32,7 @@ static inline bool load(FILE * f) { if (fread(buffer, sVersionLength, 1, f) != 1) { return false; } - if (strcmp(buffer, softwareVersion()) != 0) { + if (strcmp(buffer, softwareVersion()) != 0 && strcmp(buffer, sWildcardVersion) != 0) { return false; } From 2bee7eb2678bfa0b236a086695dcac0f23524ce8 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 15:59:07 -0400 Subject: [PATCH 044/105] [ion] Make Ion::Events::Journal optional --- ion/include/ion/events.h | 2 ++ ion/src/shared/events_keyboard.cpp | 10 ++++++++++ ion/src/simulator/Makefile | 2 ++ 3 files changed, 14 insertions(+) diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h index c5a5fae5b..0d3c8b93b 100644 --- a/ion/include/ion/events.h +++ b/ion/include/ion/events.h @@ -53,6 +53,7 @@ enum class ShiftAlphaStatus { // Timeout is decremented Event getEvent(int * timeout); +#if ION_EVENTS_JOURNAL class Journal { public: virtual void pushEvent(Event e) = 0; @@ -62,6 +63,7 @@ public: void replayFrom(Journal * l); void logTo(Journal * l); +#endif ShiftAlphaStatus shiftAlphaStatus(); void setShiftAlphaStatus(ShiftAlphaStatus s); diff --git a/ion/src/shared/events_keyboard.cpp b/ion/src/shared/events_keyboard.cpp index fe0825a4b..a378ea0fb 100644 --- a/ion/src/shared/events_keyboard.cpp +++ b/ion/src/shared/events_keyboard.cpp @@ -118,6 +118,8 @@ static inline Event innerGetEvent(int * timeout) { } } +#if ION_EVENTS_JOURNAL + static Journal * sSourceJournal = nullptr; static Journal * sDestinationJournal = nullptr; void replayFrom(Journal * l) { sSourceJournal = l; } @@ -138,6 +140,14 @@ Event getEvent(int * timeout) { return e; } +#else + +Event getEvent(int * timeout) { + return innerGetEvent(timeout); +} + +#endif + } } diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index 2cf5fbb82..059bc3381 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -40,6 +40,8 @@ ion_simulator_assets_paths = $(add_prefix ion/src/simulator/assets/,$(ion_simula include ion/src/simulator/$(TARGET)/Makefile include ion/src/simulator/external/Makefile +SFLAGS += -DION_EVENTS_JOURNAL + ifeq ($(ION_SIMULATOR_FILES),1) ion_src += $(addprefix ion/src/simulator/shared/, \ actions.cpp \ From a834c954b8cb78fa59af7323dbd605034229c7c7 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 16:42:28 -0400 Subject: [PATCH 045/105] [ion/simulator] Get rid of the headless target --- .github/workflows/ci-workflow.yml | 16 +++++++------- build/targets.simulator.mak | 7 ------ build/targets.simulator.web.mak | 2 +- ion/src/shared/dummy/events_platform.cpp | 11 ---------- ion/src/shared/dummy/keyboard.cpp | 11 ---------- ion/src/shared/dummy/timing_msleep.cpp | 4 ---- ion/src/simulator/Makefile | 19 ++++++---------- ion/src/simulator/shared/dummy/keyboard.cpp | 19 ---------------- ion/src/simulator/shared/dummy/window.cpp | 24 --------------------- ion/src/simulator/shared/timing.cpp | 17 ++++++++++++++- ion/src/simulator/shared/timing_msleep.cpp | 10 --------- 11 files changed, 31 insertions(+), 109 deletions(-) delete mode 100644 ion/src/shared/dummy/events_platform.cpp delete mode 100644 ion/src/shared/dummy/keyboard.cpp delete mode 100644 ion/src/shared/dummy/timing_msleep.cpp delete mode 100644 ion/src/simulator/shared/dummy/keyboard.cpp delete mode 100644 ion/src/simulator/shared/dummy/window.cpp delete mode 100644 ion/src/simulator/shared/timing_msleep.cpp diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index ac3d0667d..2c6557347 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -74,8 +74,8 @@ jobs: - run: pacman -S --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-freetype mingw-w64-x86_64-pkg-config make mingw-w64-x86_64-python3 mingw-w64-x86_64-libjpeg-turbo mingw-w64-x86_64-libpng - run: make -j2 PLATFORM=simulator - run: make -j2 PLATFORM=simulator epsilon.official.exe - - run: make -j2 PLATFORM=simulator test.headless.exe - - run: output/release/simulator/windows/test.headless.exe + - run: make -j2 PLATFORM=simulator test.exe + - run: cmd /c output\release\simulator\windows\test.exe --headless - uses: actions/upload-artifact@master with: name: epsilon-windows.exe @@ -89,8 +89,8 @@ jobs: - uses: actions/checkout@v2 - run: make -j2 PLATFORM=simulator TARGET=web - run: make -j2 PLATFORM=simulator TARGET=web epsilon.official.zip - - run: make -j2 PLATFORM=simulator TARGET=web test.headless.js - - run: node output/release/simulator/web/test.headless.js + - run: make -j2 PLATFORM=simulator TARGET=web test.js + - run: node output/release/simulator/web/test.js --headless - uses: actions/upload-artifact@master with: name: epsilon-web.zip @@ -102,8 +102,8 @@ jobs: - uses: actions/checkout@v2 - run: make -j2 PLATFORM=simulator - run: make -j2 PLATFORM=simulator epsilon.official.bin - - run: make -j2 PLATFORM=simulator test.headless.bin - - run: output/release/simulator/linux/test.headless.bin + - run: make -j2 PLATFORM=simulator test.bin + - run: output/release/simulator/linux/test.bin --headless - uses: actions/upload-artifact@master with: name: epsilon-linux.bin @@ -116,8 +116,8 @@ jobs: - uses: actions/checkout@v2 - run: make -j2 PLATFORM=simulator - run: make -j2 PLATFORM=simulator epsilon.official.app - - run: make -j2 PLATFORM=simulator ARCH=x86_64 test.headless.bin - - run: output/release/simulator/macos/x86_64/test.headless.bin + - run: make -j2 PLATFORM=simulator ARCH=x86_64 test.bin + - run: output/release/simulator/macos/x86_64/test.bin --headless - uses: actions/upload-artifact@master with: name: epsilon-macos.zip diff --git a/build/targets.simulator.mak b/build/targets.simulator.mak index 6e6ed0fe6..55101ffc2 100644 --- a/build/targets.simulator.mak +++ b/build/targets.simulator.mak @@ -1,8 +1 @@ -# Headless targets -$(eval $(call rule_for_epsilon_flavor,headless)) -HANDY_TARGETS += epsilon.headless - -$(BUILD_DIR)/test.headless.$(EXE): $(call flavored_object_for,$(test_runner_src),headless) -HANDY_TARGETS += test.headless - -include build/targets.simulator.$(TARGET).mak diff --git a/build/targets.simulator.web.mak b/build/targets.simulator.web.mak index ead0b515e..396ec7056 100644 --- a/build/targets.simulator.web.mak +++ b/build/targets.simulator.web.mak @@ -1 +1 @@ -$(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0 +$(BUILD_DIR)/test.js: EMSCRIPTEN_MODULARIZE = 0 diff --git a/ion/src/shared/dummy/events_platform.cpp b/ion/src/shared/dummy/events_platform.cpp deleted file mode 100644 index a0b1c6cd8..000000000 --- a/ion/src/shared/dummy/events_platform.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include - -namespace Ion { -namespace Events { - -Event getPlatformEvent() { - return None; -} - -} -} diff --git a/ion/src/shared/dummy/keyboard.cpp b/ion/src/shared/dummy/keyboard.cpp deleted file mode 100644 index 914ce0dcf..000000000 --- a/ion/src/shared/dummy/keyboard.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include - -namespace Ion { -namespace Keyboard { - -State scan() { - return State(); -} - -} -} diff --git a/ion/src/shared/dummy/timing_msleep.cpp b/ion/src/shared/dummy/timing_msleep.cpp deleted file mode 100644 index 131e5abfd..000000000 --- a/ion/src/shared/dummy/timing_msleep.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include - -void Ion::Timing::msleep(uint32_t ms) { -} diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index 059bc3381..862742bd7 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -3,35 +3,28 @@ ion_src += $(addprefix ion/src/shared/dummy/, \ battery.cpp \ display.cpp \ exam_mode.cpp \ - events_platform.cpp:+headless \ fcc_id.cpp \ - keyboard.cpp:+headless \ led.cpp \ power.cpp \ serial_number.cpp \ stack.cpp \ - timing_msleep.cpp:+headless \ usb.cpp \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ - dummy/keyboard.cpp:+headless \ - dummy/window.cpp:+headless \ clipboard.cpp \ - console_stdio.cpp:-consoledisplay \ + console.cpp \ crc32.cpp \ - display.cpp:-headless \ + display.cpp \ events.cpp \ - events_platform.cpp:-headless \ + events_platform.cpp \ framebuffer.cpp \ - framebuffer_png.cpp:+headless \ - keyboard.cpp:-headless \ - layout.cpp:-headless \ + keyboard.cpp \ + layout.cpp \ main.cpp \ random.cpp \ timing.cpp \ - timing_msleep.cpp:-headless \ - window.cpp:-headless \ + window.cpp \ ) ion_simulator_assets = background.jpg horizontal_arrow.png vertical_arrow.png round.png small_squircle.png large_squircle.png diff --git a/ion/src/simulator/shared/dummy/keyboard.cpp b/ion/src/simulator/shared/dummy/keyboard.cpp deleted file mode 100644 index d2b2a8819..000000000 --- a/ion/src/simulator/shared/dummy/keyboard.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "../keyboard.h" - -namespace Ion { -namespace Simulator { -namespace Keyboard { - -void keyDown(Ion::Keyboard::Key k) { -} - -void keyUp(Ion::Keyboard::Key k) { -} - -bool scanHandlesSDLKey(SDL_Scancode key) { - return false; -} - -} -} -} diff --git a/ion/src/simulator/shared/dummy/window.cpp b/ion/src/simulator/shared/dummy/window.cpp deleted file mode 100644 index 1ab131edf..000000000 --- a/ion/src/simulator/shared/dummy/window.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "../window.h" - -namespace Ion { -namespace Simulator { -namespace Window { - -void init() { - Ion::Simulator::Framebuffer::setActive(false); -} - -void quit() { -} - -void setNeedsRefresh() { -} - -void relayout() { -} - -void refresh() { -} -} -} -} diff --git a/ion/src/simulator/shared/timing.cpp b/ion/src/simulator/shared/timing.cpp index cd11dcf61..9997bbcf4 100644 --- a/ion/src/simulator/shared/timing.cpp +++ b/ion/src/simulator/shared/timing.cpp @@ -1,9 +1,24 @@ #include +#include "window.h" #include +#include static auto start = std::chrono::steady_clock::now(); -uint64_t Ion::Timing::millis() { +namespace Ion { +namespace Timing { + +uint64_t millis() { auto elapsed = std::chrono::steady_clock::now() - start; return std::chrono::duration_cast(elapsed).count(); } + +void msleep(uint32_t ms) { + if (Simulator::Window::isHeadless()) { + return; + } + SDL_Delay(ms); +} + +} +} diff --git a/ion/src/simulator/shared/timing_msleep.cpp b/ion/src/simulator/shared/timing_msleep.cpp deleted file mode 100644 index 128330a0a..000000000 --- a/ion/src/simulator/shared/timing_msleep.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include "window.h" -#include - -void Ion::Timing::msleep(uint32_t ms) { - if (Ion::Simulator::Window::isHeadless()) { - return; - } - SDL_Delay(ms); -} From 2f2e45a6a5a39f1efe1dda1e5257c92ec05e82f0 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 20:12:54 -0400 Subject: [PATCH 046/105] [ion/simulator] Headless simulator maps Ion::Console to stdio --- ion/Makefile | 1 - ion/src/device/shared/drivers/Makefile | 2 + .../device/shared/drivers/console_display.cpp | 39 +++++++++++++++++++ .../device/shared/drivers/console_dummy.cpp | 18 +++++++++ ion/src/shared/console_display.cpp | 29 -------------- ion/src/simulator/shared/console.cpp | 31 +++++++++++++++ ion/src/simulator/shared/console_stdio.cpp | 22 ----------- kandinsky/include/kandinsky/ion_context.h | 1 + kandinsky/src/ion_context.cpp | 11 +++++- 9 files changed, 101 insertions(+), 53 deletions(-) create mode 100644 ion/src/device/shared/drivers/console_display.cpp delete mode 100644 ion/src/shared/console_display.cpp create mode 100644 ion/src/simulator/shared/console.cpp delete mode 100644 ion/src/simulator/shared/console_stdio.cpp diff --git a/ion/Makefile b/ion/Makefile index c49f13277..0e9555cff 100644 --- a/ion/Makefile +++ b/ion/Makefile @@ -25,7 +25,6 @@ initializer_list = $(shell echo $(1) | sed "s/\(.\)/'\1',/g")0 $(call object_for,ion/src/shared/platform_info.cpp): SFLAGS += -DPATCH_LEVEL="$(call initializer_list,$(PATCH_LEVEL))" -DEPSILON_VERSION="$(call initializer_list,$(EPSILON_VERSION))" ion_src += $(addprefix ion/src/shared/, \ - console_display.cpp:+consoledisplay \ console_line.cpp \ crc32_eat_byte.cpp \ decompress.cpp \ diff --git a/ion/src/device/shared/drivers/Makefile b/ion/src/device/shared/drivers/Makefile index a73470f0e..d099cca35 100644 --- a/ion/src/device/shared/drivers/Makefile +++ b/ion/src/device/shared/drivers/Makefile @@ -5,6 +5,8 @@ ion_device_src += $(addprefix ion/src/device/shared/drivers/, \ board.cpp \ clipboard.cpp \ console_uart.cpp:+consoleuart \ + console_display.cpp:+consoledisplay \ + console_dummy.cpp:-consoledisplay \ console_dummy.cpp:-consoleuart \ crc32.cpp \ display.cpp \ diff --git a/ion/src/device/shared/drivers/console_display.cpp b/ion/src/device/shared/drivers/console_display.cpp new file mode 100644 index 000000000..b85227bc7 --- /dev/null +++ b/ion/src/device/shared/drivers/console_display.cpp @@ -0,0 +1,39 @@ +#include "console.h" +#include +#include + +namespace Ion { +namespace Console { + +char readChar() { + return 0; +} + +void writeChar(char c) { + KDIonContext::putchar(c); +} + +bool transmissionDone() { + return true; +} + +} +} + +namespace Ion { +namespace Device { +namespace Console { + +void init() { +} + +void shutdown() { +} + +bool peerConnected() { + return false; +} + +} +} +} diff --git a/ion/src/device/shared/drivers/console_dummy.cpp b/ion/src/device/shared/drivers/console_dummy.cpp index 9ed1718f5..bc7eccd22 100644 --- a/ion/src/device/shared/drivers/console_dummy.cpp +++ b/ion/src/device/shared/drivers/console_dummy.cpp @@ -1,4 +1,22 @@ #include "console.h" +#include + +namespace Ion { +namespace Console { + +char readChar() { + return 0; +} + +void writeChar(char c) { +} + +bool transmissionDone() { + return true; +} + +} +} namespace Ion { namespace Device { diff --git a/ion/src/shared/console_display.cpp b/ion/src/shared/console_display.cpp deleted file mode 100644 index 8be425eb9..000000000 --- a/ion/src/shared/console_display.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include - -namespace Ion { -namespace Console { - -char readChar() { - return '\0'; -} - -static KDPoint cursor = KDPointZero; - -void writeChar(char c) { - char text[2] = {c, 0}; - KDContext * ctx = KDIonContext::sharedContext(); - cursor = ctx->drawString(text, cursor); - if (cursor.y() > Ion::Display::Height) { - cursor = KDPoint(cursor.x(), 0); - } -} - -bool transmissionDone() { - // Always true because we flush after each writeChar - return true; -} - -} -} diff --git a/ion/src/simulator/shared/console.cpp b/ion/src/simulator/shared/console.cpp new file mode 100644 index 000000000..36b4a8f98 --- /dev/null +++ b/ion/src/simulator/shared/console.cpp @@ -0,0 +1,31 @@ +#include +#include "window.h" +#include +#include + +namespace Ion { +namespace Console { + +char readChar() { + if (Simulator::Window::isHeadless()) { + return getchar(); + } else { + return 0; + } +} + +void writeChar(char c) { + if (Simulator::Window::isHeadless()) { + putchar(c); + fflush(stdout); + } else { + KDIonContext::putchar(c); + } +} + +bool transmissionDone() { + return true; +} + +} +} diff --git a/ion/src/simulator/shared/console_stdio.cpp b/ion/src/simulator/shared/console_stdio.cpp deleted file mode 100644 index e77659f71..000000000 --- a/ion/src/simulator/shared/console_stdio.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -namespace Ion { -namespace Console { - -char readChar() { - return getchar(); -} - -void writeChar(char c) { - putchar(c); - fflush(stdout); -} - -bool transmissionDone() { - // Always true because we flush after each writeChar - return true; -} - -} -} diff --git a/kandinsky/include/kandinsky/ion_context.h b/kandinsky/include/kandinsky/ion_context.h index 42eb738ad..b367a557a 100644 --- a/kandinsky/include/kandinsky/ion_context.h +++ b/kandinsky/include/kandinsky/ion_context.h @@ -6,6 +6,7 @@ class KDIonContext : public KDContext { public: static KDIonContext * sharedContext(); + static void putchar(char c); private: KDIonContext(); void pushRect(KDRect rect, const KDColor * pixels) override; diff --git a/kandinsky/src/ion_context.cpp b/kandinsky/src/ion_context.cpp index ee7fcb5af..e1eb73c14 100644 --- a/kandinsky/src/ion_context.cpp +++ b/kandinsky/src/ion_context.cpp @@ -1,5 +1,5 @@ #include -#include +#include KDIonContext * KDIonContext::sharedContext() { static KDIonContext context; @@ -23,3 +23,12 @@ void KDIonContext::pushRectUniform(KDRect rect, KDColor color) { void KDIonContext::pullRect(KDRect rect, KDColor * pixels) { Ion::Display::pullRect(rect, pixels); } + +void KDIonContext::putchar(char c) { + static KDPoint cursor = KDPointZero; + char text[2] = {c, 0}; + cursor = sharedContext()->drawString(text, cursor); + if (cursor.y() > Ion::Display::Height) { + cursor = KDPoint(cursor.x(), 0); + } +} From 543d3d540e09f6a9e4b0c6793f6b0c2c66f9fc15 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 21:23:33 -0400 Subject: [PATCH 047/105] [ion/simulator] Use shutdown instead of quit --- ion/src/simulator/shared/display.cpp | 2 +- ion/src/simulator/shared/display.h | 2 +- ion/src/simulator/shared/window.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ion/src/simulator/shared/display.cpp b/ion/src/simulator/shared/display.cpp index 28994c8ab..a540fa008 100644 --- a/ion/src/simulator/shared/display.cpp +++ b/ion/src/simulator/shared/display.cpp @@ -23,7 +23,7 @@ void init(SDL_Renderer * renderer) { ); } -void quit() { +void shutdown() { SDL_DestroyTexture(sFramebufferTexture); sFramebufferTexture = nullptr; } diff --git a/ion/src/simulator/shared/display.h b/ion/src/simulator/shared/display.h index 5b1b98170..1f8adbd80 100644 --- a/ion/src/simulator/shared/display.h +++ b/ion/src/simulator/shared/display.h @@ -9,7 +9,7 @@ namespace Simulator { namespace Display { void init(SDL_Renderer * renderer); -void quit(); +void shutdown(); void draw(SDL_Renderer * renderer, SDL_Rect * rect); diff --git a/ion/src/simulator/shared/window.cpp b/ion/src/simulator/shared/window.cpp index 7b25e05ab..f331bf863 100644 --- a/ion/src/simulator/shared/window.cpp +++ b/ion/src/simulator/shared/window.cpp @@ -122,7 +122,7 @@ void quit() { #if !EPSILON_SDL_SCREEN_ONLY Layout::quit(); #endif - Display::quit(); + Display::shutdown(); SDL_DestroyWindow(sWindow); sWindow = nullptr; SDL_Quit(); From 699cf220236f45489b1fbc7e820f3720d64b3161 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 21:31:23 -0400 Subject: [PATCH 048/105] [ion/simulator] Don't enable the framebuffer in headless mode A quick test on a state file with 64k events took 2.5 seconds to process with the framebuffer vs 1.9 without. --- ion/src/simulator/shared/display.cpp | 1 + ion/src/simulator/shared/framebuffer.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/shared/display.cpp b/ion/src/simulator/shared/display.cpp index a540fa008..798a68f0b 100644 --- a/ion/src/simulator/shared/display.cpp +++ b/ion/src/simulator/shared/display.cpp @@ -12,6 +12,7 @@ namespace Display { static SDL_Texture * sFramebufferTexture = nullptr; void init(SDL_Renderer * renderer) { + Framebuffer::setActive(true); Uint32 texturePixelFormat = SDL_PIXELFORMAT_RGB565; assert(sizeof(KDColor) == SDL_BYTESPERPIXEL(texturePixelFormat)); sFramebufferTexture = SDL_CreateTexture( diff --git a/ion/src/simulator/shared/framebuffer.cpp b/ion/src/simulator/shared/framebuffer.cpp index 75e45796d..714f3f3c8 100644 --- a/ion/src/simulator/shared/framebuffer.cpp +++ b/ion/src/simulator/shared/framebuffer.cpp @@ -14,7 +14,7 @@ * framebuffer to a PNG file. */ static KDColor sPixels[Ion::Display::Width * Ion::Display::Height]; -static bool sFrameBufferActive = true; +static bool sFrameBufferActive = false; namespace Ion { namespace Display { From 6c389c9a1d4fef24e7daa8bc12833517f5f84840 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 17 Sep 2020 21:41:49 -0400 Subject: [PATCH 049/105] [ion/simulator] Get rid of useless Ion:: prefixes --- ion/src/simulator/shared/crc32.cpp | 20 ++++++++----- ion/src/simulator/shared/events_platform.cpp | 10 +++---- ion/src/simulator/shared/framebuffer.cpp | 2 +- ion/src/simulator/shared/journal.cpp | 6 ++-- ion/src/simulator/shared/keyboard.cpp | 30 ++++++++++--------- .../shared/platform_action_modifier_ctrl.cpp | 13 -------- .../shared/platform_action_modifier_gui.cpp | 13 -------- 7 files changed, 37 insertions(+), 57 deletions(-) delete mode 100644 ion/src/simulator/shared/platform_action_modifier_ctrl.cpp delete mode 100644 ion/src/simulator/shared/platform_action_modifier_gui.cpp diff --git a/ion/src/simulator/shared/crc32.cpp b/ion/src/simulator/shared/crc32.cpp index 0fdfd3f6a..04718ea71 100644 --- a/ion/src/simulator/shared/crc32.cpp +++ b/ion/src/simulator/shared/crc32.cpp @@ -1,28 +1,32 @@ #include -uint32_t crc32Helper(const uint8_t * data, size_t length, bool wordAccess) { +namespace Ion { + +static uint32_t crc32Helper(const uint8_t * data, size_t length, bool wordAccess) { size_t uint32ByteLength = sizeof(uint32_t)/sizeof(uint8_t); uint32_t crc = 0xFFFFFFFF; size_t byteLength = (wordAccess ? length * uint32ByteLength : length); size_t wordLength = byteLength / uint32ByteLength; - for (int i = 0; i < (int)wordLength; i++) { + for (int i = 0; i < wordLength; i++) { // FIXME: Assumes little-endian byte order! for (int j = uint32ByteLength-1; j >= 0; j--) { // scan byte by byte to avoid alignment issue when building for emscripten platform - crc = Ion::crc32EatByte(crc, data[i*uint32ByteLength+j]); + crc = crc32EatByte(crc, data[i*uint32ByteLength+j]); } } - for (int i = (int) wordLength * uint32ByteLength; i < byteLength; i++) { - crc = Ion::crc32EatByte(crc, data[i]); + for (int i = wordLength * uint32ByteLength; i < byteLength; i++) { + crc = crc32EatByte(crc, data[i]); } return crc; } -uint32_t Ion::crc32Word(const uint32_t * data, size_t length) { - return crc32Helper((const uint8_t *) data, length, true); +uint32_t crc32Word(const uint32_t * data, size_t length) { + return crc32Helper(reinterpret_cast(data), length, true); } -uint32_t Ion::crc32Byte(const uint8_t * data, size_t length) { +uint32_t crc32Byte(const uint8_t * data, size_t length) { return crc32Helper(data, length, false); } + +} diff --git a/ion/src/simulator/shared/events_platform.cpp b/ion/src/simulator/shared/events_platform.cpp index 8dfc68671..8eb5b894a 100644 --- a/ion/src/simulator/shared/events_platform.cpp +++ b/ion/src/simulator/shared/events_platform.cpp @@ -19,8 +19,8 @@ static inline Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { /* If an event is detected, we want to remove the Shift modifier to mimic the * device behaviour. If no event was detected, we restore the previous * ShiftAlphaStatus. */ - Ion::Events::ShiftAlphaStatus previousShiftAlphaStatus = Ion::Events::shiftAlphaStatus(); - Ion::Events::removeShift(); + ShiftAlphaStatus previousShiftAlphaStatus = shiftAlphaStatus(); + removeShift(); if (event.keysym.mod & (KMOD_CTRL|KMOD_GUI)) { switch (event.keysym.sym) { @@ -87,7 +87,7 @@ static inline Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { return Termination; } // No event was detected, restore the previous ShiftAlphaStatus. - Ion::Events::setShiftAlphaStatus(previousShiftAlphaStatus); + setShiftAlphaStatus(previousShiftAlphaStatus); return None; } @@ -116,7 +116,7 @@ static Event eventFromSDLTextInputEvent(SDL_TextInputEvent event) { * then we press "&", transformed by eventFromSDLTextInputEvent into the * text "1". If we do not remove the Shift here, it would still be * pressed afterwards. */ - Ion::Events::removeShift(); + Events::removeShift(); Event res = sEventForASCIICharAbove32[character-32]; if (res != None) { return res; @@ -133,7 +133,7 @@ Event getPlatformEvent() { Event result = None; while (SDL_PollEvent(&event)) { // That "while" is important: it'll do a fast-pass over all useless SDL events if (event.type == SDL_WINDOWEVENT) { - Ion::Simulator::Window::relayout(); + Simulator::Window::relayout(); break; } if (event.type == SDL_QUIT) { diff --git a/ion/src/simulator/shared/framebuffer.cpp b/ion/src/simulator/shared/framebuffer.cpp index 714f3f3c8..eb5a25fff 100644 --- a/ion/src/simulator/shared/framebuffer.cpp +++ b/ion/src/simulator/shared/framebuffer.cpp @@ -19,7 +19,7 @@ static bool sFrameBufferActive = false; namespace Ion { namespace Display { -static KDFrameBuffer sFrameBuffer = KDFrameBuffer(sPixels, KDSize(Ion::Display::Width, Ion::Display::Height)); +static KDFrameBuffer sFrameBuffer = KDFrameBuffer(sPixels, KDSize(Width, Height)); void pushRect(KDRect r, const KDColor * pixels) { if (sFrameBufferActive) { diff --git a/ion/src/simulator/shared/journal.cpp b/ion/src/simulator/shared/journal.cpp index 8677fb40c..4dd532133 100644 --- a/ion/src/simulator/shared/journal.cpp +++ b/ion/src/simulator/shared/journal.cpp @@ -27,15 +27,15 @@ private: }; void init() { - Ion::Events::logTo(logJournal()); + Events::logTo(logJournal()); } -Ion::Events::Journal * replayJournal() { +Events::Journal * replayJournal() { static Journal journal; return &journal; } -Ion::Events::Journal * logJournal() { +Events::Journal * logJournal() { static Journal journal; return &journal; } diff --git a/ion/src/simulator/shared/keyboard.cpp b/ion/src/simulator/shared/keyboard.cpp index 9a3849f4e..9113c8b90 100644 --- a/ion/src/simulator/shared/keyboard.cpp +++ b/ion/src/simulator/shared/keyboard.cpp @@ -5,32 +5,34 @@ #include #include -static Ion::Keyboard::State sKeyboardState; +using namespace Ion::Keyboard; + +static State sKeyboardState; class KeySDLKeyPair { public: - constexpr KeySDLKeyPair(Ion::Keyboard::Key key, SDL_Scancode SDLKey) : + constexpr KeySDLKeyPair(Key key, SDL_Scancode SDLKey) : m_key(key), m_SDLKey(SDLKey) {} - Ion::Keyboard::Key key() const { return m_key; } + Key key() const { return m_key; } SDL_Scancode SDLKey() const { return m_SDLKey; } private: - Ion::Keyboard::Key m_key; + Key m_key; SDL_Scancode m_SDLKey; }; constexpr static KeySDLKeyPair sKeyPairs[] = { - KeySDLKeyPair(Ion::Keyboard::Key::Down, SDL_SCANCODE_DOWN), - KeySDLKeyPair(Ion::Keyboard::Key::Up, SDL_SCANCODE_UP), - KeySDLKeyPair(Ion::Keyboard::Key::Left, SDL_SCANCODE_LEFT), - KeySDLKeyPair(Ion::Keyboard::Key::Right, SDL_SCANCODE_RIGHT), - KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_LSHIFT), - KeySDLKeyPair(Ion::Keyboard::Key::Shift, SDL_SCANCODE_RSHIFT), - KeySDLKeyPair(Ion::Keyboard::Key::EXE, SDL_SCANCODE_RETURN), - KeySDLKeyPair(Ion::Keyboard::Key::Back, SDL_SCANCODE_ESCAPE), - KeySDLKeyPair(Ion::Keyboard::Key::Toolbox, SDL_SCANCODE_TAB), - KeySDLKeyPair(Ion::Keyboard::Key::Backspace, SDL_SCANCODE_BACKSPACE) + KeySDLKeyPair(Key::Down, SDL_SCANCODE_DOWN), + KeySDLKeyPair(Key::Up, SDL_SCANCODE_UP), + KeySDLKeyPair(Key::Left, SDL_SCANCODE_LEFT), + KeySDLKeyPair(Key::Right, SDL_SCANCODE_RIGHT), + KeySDLKeyPair(Key::Shift, SDL_SCANCODE_LSHIFT), + KeySDLKeyPair(Key::Shift, SDL_SCANCODE_RSHIFT), + KeySDLKeyPair(Key::EXE, SDL_SCANCODE_RETURN), + KeySDLKeyPair(Key::Back, SDL_SCANCODE_ESCAPE), + KeySDLKeyPair(Key::Toolbox, SDL_SCANCODE_TAB), + KeySDLKeyPair(Key::Backspace, SDL_SCANCODE_BACKSPACE) }; constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeySDLKeyPair); diff --git a/ion/src/simulator/shared/platform_action_modifier_ctrl.cpp b/ion/src/simulator/shared/platform_action_modifier_ctrl.cpp deleted file mode 100644 index 9f6c3a3f2..000000000 --- a/ion/src/simulator/shared/platform_action_modifier_ctrl.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "../shared/platform.h" - -namespace Ion { -namespace Simulator { -namespace Platform { - -SDL_Keymod actionModifier() { - return static_cast(KMOD_CTRL); -} - -} -} -} diff --git a/ion/src/simulator/shared/platform_action_modifier_gui.cpp b/ion/src/simulator/shared/platform_action_modifier_gui.cpp deleted file mode 100644 index b9f3021ad..000000000 --- a/ion/src/simulator/shared/platform_action_modifier_gui.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "../shared/platform.h" - -namespace Ion { -namespace Simulator { -namespace Platform { - -SDL_Keymod actionModifier() { - return KMOD_GUI; -} - -} -} -} From 497e4890b1d56e17f850c3c0f0d85fc6634329dd Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 28 Sep 2020 18:11:00 -0400 Subject: [PATCH 050/105] [ion/simulator/web] Fix the build --- build/toolchain.emscripten.mak | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/toolchain.emscripten.mak b/build/toolchain.emscripten.mak index 5de7d76cf..c8ac535a1 100644 --- a/build/toolchain.emscripten.mak +++ b/build/toolchain.emscripten.mak @@ -30,9 +30,11 @@ __ZN3Ion6Events13isShiftActiveEv \ __ZN3Ion6Events5EventC2Ei \ __ZN3Ion6Events5EventC2ENS_8Keyboard3KeyEbb \ __ZN3Ion6Events8getEventEPi \ +__ZN3Ion6EventsL13innerGetEventEPi \ __ZN3Ion6EventsL16sleepWithTimeoutEiPi \ __ZN3Ion6Timing6msleepEj \ __ZN3Ion8Keyboard4scanEv \ +__ZN3Ion9Simulator8Keyboard7didScanEv \ __ZN4Code14MenuController21openConsoleWithScriptENS_6ScriptE \ __ZN4Code14MenuController23didBecomeFirstResponderEv \ __ZN4Code14MenuController28openConsoleWithScriptAtIndexEi \ From 2703f9a50653976505c7607f645b82ce86dd84d4 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 23 Feb 2021 20:51:34 -0500 Subject: [PATCH 051/105] [build] Add prerequisite path when processing through CPP --- build/rules.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/rules.mk b/build/rules.mk index 9089cebce..30200f34d 100644 --- a/build/rules.mk +++ b/build/rules.mk @@ -14,7 +14,7 @@ $(eval $(call rule_for, \ $(eval $(call rule_for, \ CPP, %, %.inc, \ - $$(CPP) -P $$< $$@, \ + $$(CPP) $$(addprefix -I,$$(dir $$^)) -P $$< $$@, \ global \ )) From 32d591317b45c638648f40b0b1a8981bf7aa0022 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 23 Feb 2021 21:03:18 -0500 Subject: [PATCH 052/105] [simulator/web] Use specialHTMLTargets to allow picking a canvas --- ion/src/simulator/web/preamble_env.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ion/src/simulator/web/preamble_env.js b/ion/src/simulator/web/preamble_env.js index 42fc03f95..3400727ff 100644 --- a/ion/src/simulator/web/preamble_env.js +++ b/ion/src/simulator/web/preamble_env.js @@ -18,4 +18,13 @@ Module["preRun"] = function () { ENV[key] = Module['env'][key]; } } + /* When figuring up in which DOM element to draw, SDL2/emscripten looks for + * an element with an id of "canvas". That's pretty annoying because it pretty + * much prevents us from running multiple instances of Epsilon in a single web + * page even if Epsilon is built using MODULARIZE=1. + * Enters specialHTMLTargets. This is a nifty hack that allows one to override + * DOM node lookups made by Emscripten! Using this feature, we can instruct + * emscripten to use a custom element when looking for "#canvas". + * See https://github.com/emscripten-core/emscripten/pull/10659 */ + specialHTMLTargets["#canvas"] = Module.canvas; } From 1aac2a1d4d9acdbc1f22c72b077bb9d839936a78 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 23 Feb 2021 21:11:55 -0500 Subject: [PATCH 053/105] [ion/simulator/web] Use a shared layout.json file --- ion/src/simulator/shared/layout.json | 61 ++++++ ion/src/simulator/web/Makefile | 6 + ion/src/simulator/web/layout.py | 98 ++++++++++ ion/src/simulator/web/simulator-keyboard.html | 54 ------ ion/src/simulator/web/simulator-setup.js | 119 +++++++----- ion/src/simulator/web/simulator.css | 80 ++++++++ ion/src/simulator/web/simulator.html.inc | 183 ++---------------- 7 files changed, 328 insertions(+), 273 deletions(-) create mode 100644 ion/src/simulator/shared/layout.json create mode 100644 ion/src/simulator/web/layout.py delete mode 100644 ion/src/simulator/web/simulator-keyboard.html create mode 100644 ion/src/simulator/web/simulator.css diff --git a/ion/src/simulator/shared/layout.json b/ion/src/simulator/shared/layout.json new file mode 100644 index 000000000..1ec23b553 --- /dev/null +++ b/ion/src/simulator/shared/layout.json @@ -0,0 +1,61 @@ +{ + "background": [0, 0, 1160, 2220], + "screen": [192, 191, 776, 582], + "keys": { + "0": [133, 983, 140, 87], + "1": [231, 886, 87, 140], + "2": [231, 1026, 87, 140], + "3": [275, 983, 140, 87], + + "4": [745, 963, 129, 129], + "5": [898, 963, 129, 129], + + "6": [502, 908, 156, 101], + "7": [502, 1044, 156, 101], + + "12": [133, 1210, 129, 87], + "13": [286, 1210, 129, 87], + "14": [439, 1210, 129, 87], + "15": [592, 1210, 129, 87], + "16": [745, 1210, 129, 87], + "17": [898, 1210, 129, 87], + + "18": [133, 1332, 129, 87], + "19": [286, 1332, 129, 87], + "20": [439, 1332, 129, 87], + "21": [592, 1332, 129, 87], + "22": [745, 1332, 129, 87], + "23": [898, 1332, 129, 87], + + "24": [133, 1455, 129, 87], + "25": [286, 1455, 129, 87], + "26": [439, 1455, 129, 87], + "27": [592, 1455, 129, 87], + "28": [745, 1455, 129, 87], + "29": [898, 1455, 129, 87], + + "30": [133, 1578, 156, 101], + "31": [317, 1578, 156, 101], + "32": [502, 1578, 156, 101], + "33": [686, 1578, 156, 101], + "34": [871, 1578, 156, 101], + + "36": [133, 1715, 156, 101], + "37": [317, 1715, 156, 101], + "38": [502, 1715, 156, 101], + "39": [686, 1715, 156, 101], + "40": [871, 1715, 156, 101], + + "42": [133, 1851, 156, 101], + "43": [317, 1851, 156, 101], + "44": [502, 1851, 156, 101], + "45": [686, 1851, 156, 101], + "46": [871, 1851, 156, 101], + + "48": [133, 1988, 156, 101], + "49": [317, 1988, 156, 101], + "50": [502, 1988, 156, 101], + "51": [686, 1988, 156, 101], + "52": [871, 1988, 156, 101] + } +} diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index c79e47f99..6ed2f3151 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -36,6 +36,12 @@ endif DEFAULT = epsilon.zip +$(addprefix $(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css): ion/src/simulator/shared/layout.json + $(call rule_label,LAYOUT) + $(Q) $(PYTHON) ion/src/simulator/web/layout.py --html $(BUILD_DIR)/ion/src/simulator/web/calculator.html --css $(BUILD_DIR)/ion/src/simulator/web/calculator.css $< + +$(BUILD_DIR)/ion/src/simulator/web/simulator.html: $(addprefix $(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css) + $(BUILD_DIR)/epsilon%zip: $(BUILD_DIR)/epsilon%js $(BUILD_DIR)/ion/src/simulator/web/simulator.html @rm -rf $(basename $@) @mkdir -p $(basename $@) diff --git a/ion/src/simulator/web/layout.py b/ion/src/simulator/web/layout.py new file mode 100644 index 000000000..b2e9ebbda --- /dev/null +++ b/ion/src/simulator/web/layout.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +import argparse +import json + +def css_rule(selector, *declarations): + css = '' + css += selector + ' {\n' + for decl in declarations: + css += decl + css += '}\n\n' + return css + +def css_declaration(prop, value): + return " %s: %s;\n" % (prop, value) + +def css_percentage_declaration(prop, ratio): + return css_declaration(prop, "%.2f%%" % (100*ratio)) + +def css_rect_declarations(rect, ref): + css = '' + css += css_percentage_declaration("left", rect[0]/ref[2]) + css += css_percentage_declaration("top", rect[1]/ref[3]) + css += css_percentage_declaration("width", rect[2]/ref[2]) + css += css_percentage_declaration("height", rect[3]/ref[3]) + return css + +def css(layout): + background = layout["background"] + css = '' + css += css_rule( + '.calculator', + css_declaration('position', 'relative'), + ) + css += css_rule( + '.calculator-aspect-ratio', + css_percentage_declaration('padding-bottom', background[3]/background[2]) + ) + css += css_rule( + '.calculator canvas', + css_declaration('position', 'absolute'), + css_rect_declarations(layout['screen'], background) + ) + css += css_rule( + '.calculator span', + css_declaration('position', 'absolute'), + css_declaration('display', 'block'), + css_declaration('border-radius', '999px'), + css_declaration('cursor', 'pointer'), + ) + css += css_rule( + '.calculator span:hover', + css_declaration('background-color', 'rgba(0, 0, 0, 0.1)') + ) + css += css_rule( + '.calculator span:active', + css_declaration('background-color', 'rgba(0, 0, 0, 0.2)') + ) + for key,rect in layout["keys"].items(): + css += css_rule( + '.calculator span[data-key="%s"]' % key, + css_rect_declarations(rect, background) + ) + css += css_rule( + '.calculator-mirror canvas', + css_declaration('image-rendering', '-moz-crisp-edges'), + css_declaration('image-rendering', 'pixelated'), + css_declaration('-ms-interpolation-mode', 'nearest-neighbor') + ) + return css + +def html(layout): + screen = layout["screen"] + background = layout["background"] + html = '' + html += '
\n' + html += ' \n' + for key in layout["keys"]: + html += ' \n' % key + html += '
' + return html + +# Argument parsing + +parser = argparse.ArgumentParser(description='Generate HTML and CSS files from JSON layout') +parser.add_argument('file', type=str, help='a JSON layout file') +parser.add_argument('--css', type=str, help='an output HTML file') +parser.add_argument('--html', type=str, help='an output CSS file') +args = parser.parse_args() + +with open(args.file) as f: + layout = json.load(f) + if args.css: + with open(args.css, 'w') as o: + o.write(css(layout)) + if args.html: + with open(args.html, 'w') as o: + o.write(html(layout)) diff --git a/ion/src/simulator/web/simulator-keyboard.html b/ion/src/simulator/web/simulator-keyboard.html deleted file mode 100644 index 86425fc37..000000000 --- a/ion/src/simulator/web/simulator-keyboard.html +++ /dev/null @@ -1,54 +0,0 @@ -
- -
- - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - -
-
diff --git a/ion/src/simulator/web/simulator-setup.js b/ion/src/simulator/web/simulator-setup.js index d4eb18b97..a0a756eef 100644 --- a/ion/src/simulator/web/simulator-setup.js +++ b/ion/src/simulator/web/simulator-setup.js @@ -1,43 +1,75 @@ -/* To use this file you should adhere to the following conventions: - * - Main canvas has id #canvas - * - Secondary canvas (fullscreen on the side) has id #secondary-canvas - * - Calculator keyboard has id #keyboard */ +function EpsilonSetup(emModule) { + /* emModule is an optional parameter. + * In addition to the ones supported by Emscripten, here are the values that + * this object can have: + * - calculator: a DOM element containing a copy of 'calculator.html' as + * generated by 'layout.py' + * - mirrorCanvas: a DOM element where the main canvas will be mirrored + */ -var Module; - -(function () { - var mainCanvas = document.getElementById('canvas'); - var secondaryCanvasContext = document.getElementById('secondary-canvas').getContext('2d'); - var epsilonLanguage = document.documentElement.lang || window.navigator.language.split('-')[0]; - Module = { + // Configure emModule + var emModule = (typeof emModule === 'undefined') ? {} : emModule; + var calculator = emModule.calculator || document.querySelector('.calculator'); + var mainCanvas = calculator.querySelector("canvas"); + if (typeof emModule.mirrorCanvas === 'undefined') { + /* If emModule.mirrorCanvas is defined as null, don't do anything */ + emModule.mirrorCanvas = document.querySelector('.calculator-mirror canvas'); + } + var mirrorCanvasContext = emModule.mirrorCanvas ? emModule.mirrorCanvas.getContext('2d') : null; + var defaultModule = { canvas: mainCanvas, - arguments: ['--language', epsilonLanguage], - onDisplayRefresh: function() { - secondaryCanvasContext.drawImage(mainCanvas, 0, 0); + arguments: [ + '--language', + document.documentElement.lang || window.navigator.language.split('-')[0] + ], + downloadScreenshot: function() { + // toDataURL needs the canvas to be refreshed + this._IonDisplayForceRefresh(); + var link = document.createElement('a'); + link.download = 'screenshot.png'; + link.href = mainCanvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); + link.click(); + } + }; + if (mirrorCanvasContext) { + defaultModule.onDisplayRefresh = function() { + mirrorCanvasContext.drawImage(mainCanvas, 0, 0); + } + } + for (var attrname in defaultModule) { + if (!emModule.hasOwnProperty(attrname)) { + emModule[attrname] = defaultModule[attrname]; } } - Epsilon(Module); + // Load and run Epsilon + Epsilon(emModule); - document.querySelectorAll('#keyboard span').forEach(function(span){ - function eventHandler(keyHandler) { - return function(ev) { - var key = this.getAttribute('data-key'); - keyHandler(key); - /* Always prevent default action of event. - * First, this will prevent the browser from delaying that event. Indeed - * the browser would otherwise try to see if that event could have any - * other meaning (e.g. a click) and might delay it as a result. - * Second, this prevents touch events to be handled twice. Indeed, for - * backward compatibility reasons, mobile browsers usually create a fake - * mouse event after each real touch event. This allows desktop websites - * to work unmodified on mobile devices. But here we are explicitly - * handling both touch and mouse events. We therefore need to disable - * the default action of touch events, otherwise the handler would get - * called twice. */ - ev.preventDefault(); - }; - } + /* Install event handlers + * This needs to be done after loading Epsilon, otherwise the _IonSimulator* + * functions haven't been defined just yet. */ + function eventHandler(keyHandler) { + return function(ev) { + var key = this.getAttribute('data-key'); + keyHandler(key); + /* Always prevent default action of event. + * First, this will prevent the browser from delaying that event. Indeed + * the browser would otherwise try to see if that event could have any + * other meaning (e.g. a click) and might delay it as a result. + * Second, this prevents touch events to be handled twice. Indeed, for + * backward compatibility reasons, mobile browsers usually create a fake + * mouse event after each real touch event. This allows desktop websites + * to work unmodified on mobile devices. But here we are explicitly + * handling both touch and mouse events. We therefore need to disable + * the default action of touch events, otherwise the handler would get + * called twice. */ + ev.preventDefault(); + }; + } + var downHandler = eventHandler(emModule._IonSimulatorKeyboardKeyDown); + var upHandler = eventHandler(emModule._IonSimulatorKeyboardKeyUp); + + calculator.querySelectorAll('span').forEach(function(span){ /* We decide to hook both to touch and mouse events * On most mobile browsers, mouse events are generated if addition to touch * events, so this could seem pointless. But those mouse events are not @@ -45,21 +77,14 @@ var Module; * in a very rapid sequence. This prevents Epsilon from generating an event * since this quick sequence will trigger the debouncer. */ ['touchstart', 'mousedown'].forEach(function(type){ - span.addEventListener(type, eventHandler(Module._IonSimulatorKeyboardKeyDown)); + span.addEventListener(type, downHandler); }); ['touchend', 'mouseup'].forEach(function(type){ - span.addEventListener(type, eventHandler(Module._IonSimulatorKeyboardKeyUp)); + span.addEventListener(type, upHandler); }); }); -}()); - -function screenshot() { - // toDataURL needs the canvas to be refreshed - Module._IonDisplayForceRefresh(); - - var canvas = document.getElementById('canvas'); - var link = document.createElement('a'); - link.download = 'screenshot.png'; - link.href = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); - link.click(); +} + +if (typeof exports === 'object' && typeof module === 'object') { + module.exports = EpsilonSetup; } diff --git a/ion/src/simulator/web/simulator.css b/ion/src/simulator/web/simulator.css new file mode 100644 index 000000000..996203724 --- /dev/null +++ b/ion/src/simulator/web/simulator.css @@ -0,0 +1,80 @@ +body { + background: #C2C2C2; + margin: 0; + padding: 0; + text-align: center; +} + +.col-fullscreen { + display: none; + width: 60%; + float: left; +} + +.col-fullscreen canvas { + margin-top: 7%; + width: 100%; +} + +body.fullscreen .col-fullscreen { + display: block; +} + +body.fullscreen .col-calculator { + width: 35%; + float: left; +} + +a.action { + display: block; + width: 4%; + padding: 1.5% 3%; + border: 1px solid black; + border-radius: 100px; + cursor: pointer; + opacity: 0.65; +} + +a.action:hover { + opacity: 1.0; + background-color: rgba(0,0,0,0.125); +} + +a.action svg { + display: block; +} + +.calculator-container { + margin: 0 auto; + position: relative; + display: inline-block; + text-align: left; +} +.calculator-container > img { + /* Rely on the img content to set the dimensions */ + max-height: 92.0vh; + max-width: 100%; + display: block; +} + +.calculator { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.calculator-container .actions { + position: absolute; + top: 94.0vh; + text-align: center; + left: 0; + right: 0; + margin-left: 20px; /* Center the buttons - compensate the 10px margin below */ +} + +.calculator-container .actions a { + display: inline-block; + margin-right: 10px; +} diff --git a/ion/src/simulator/web/simulator.html.inc b/ion/src/simulator/web/simulator.html.inc index b2ed31818..4cc6f8c89 100644 --- a/ion/src/simulator/web/simulator.html.inc +++ b/ion/src/simulator/web/simulator.html.inc @@ -1,5 +1,3 @@ -#define KEYBOARD #keyboard - @@ -7,178 +5,17 @@ NumWorks graphing calculator - +
-
+
NumWorks Calculator - -#include "simulator-keyboard.html" +#include "calculator.html"
-
- +
+
From 2554ec666e6f6629110788a0f79d68492041b5be Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 23 Feb 2021 21:44:05 -0500 Subject: [PATCH 054/105] [build] Add a rule to build a ZIP file out of its dependencies --- build/rules.mk | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build/rules.mk b/build/rules.mk index 30200f34d..050c4b805 100644 --- a/build/rules.mk +++ b/build/rules.mk @@ -60,6 +60,12 @@ $(eval $(call rule_for, \ global \ )) +$(eval $(call rule_for, \ + ZIP, %.zip, , \ + rm -rf $$(basename $$@) && mkdir -p $$(basename $$@) && cp $$^ $$(basename $$@) && zip -r -9 -j $$@ $$(basename $$@) > /dev/null && rm -rf $$(basename $$@), \ + global \ +)) + ifdef EXE ifeq ($(OS),Windows_NT) # Work around command-line length limit From 36a40faaaf370e344b59ab16e748d638fefe9df1 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 23 Feb 2021 21:44:46 -0500 Subject: [PATCH 055/105] [build/emscripten] Silence the Emterpreter warning --- build/toolchain.emscripten.mak | 1 + 1 file changed, 1 insertion(+) diff --git a/build/toolchain.emscripten.mak b/build/toolchain.emscripten.mak index c8ac535a1..20515cf91 100644 --- a/build/toolchain.emscripten.mak +++ b/build/toolchain.emscripten.mak @@ -123,6 +123,7 @@ _msleep EMTERPRETIFY_WHITELIST = $(foreach sym,$(EMSCRIPTEN_ASYNC_SYMBOLS),"$(sym)",)END EMFLAGS = -s PRECISE_F32=1 -s EMTERPRETIFY=1 -s EMTERPRETIFY_ASYNC=1 -s EMTERPRETIFY_WHITELIST='[$(EMTERPRETIFY_WHITELIST:,END=)]' +EMFLAGS += -Wno-emterpreter # We know Emterpreter is deprecated... ifeq ($(DEBUG),1) EMFLAGS += --profiling-funcs From e8956f4293660508aabeae89dbb666fc2d5a4c80 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 23 Feb 2021 21:45:28 -0500 Subject: [PATCH 056/105] [build/simulator/web] Add a htmlpack target --- build/platform.simulator.web.mak | 2 -- build/targets.simulator.web.mak | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/build/platform.simulator.web.mak b/build/platform.simulator.web.mak index aa105edbd..0a39c53f8 100644 --- a/build/platform.simulator.web.mak +++ b/build/platform.simulator.web.mak @@ -1,4 +1,2 @@ TOOLCHAIN = emscripten EXE = js - -HANDY_TARGETS_EXTENSIONS += zip diff --git a/build/targets.simulator.web.mak b/build/targets.simulator.web.mak index 396ec7056..887f6e60b 100644 --- a/build/targets.simulator.web.mak +++ b/build/targets.simulator.web.mak @@ -1 +1,6 @@ $(BUILD_DIR)/test.js: EMSCRIPTEN_MODULARIZE = 0 + +HANDY_TARGETS += htmlpack +HANDY_TARGETS_EXTENSIONS += zip + +$(BUILD_DIR)/htmlpack.zip: $(addprefix $(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css) $(BUILD_DIR)/epsilon.js ion/src/simulator/web/simulator-setup.js From a6b13185abd203884d918594f82987b102dee835 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 25 Feb 2021 15:24:57 -0500 Subject: [PATCH 057/105] [ion/simulator] Extrude the QueueJournal class --- ion/src/simulator/shared/journal.cpp | 26 ++------------ .../simulator/shared/journal/queue_journal.h | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 23 deletions(-) create mode 100644 ion/src/simulator/shared/journal/queue_journal.h diff --git a/ion/src/simulator/shared/journal.cpp b/ion/src/simulator/shared/journal.cpp index 4dd532133..7ca951a9e 100644 --- a/ion/src/simulator/shared/journal.cpp +++ b/ion/src/simulator/shared/journal.cpp @@ -1,42 +1,22 @@ #include "journal.h" +#include "journal/queue_journal.h" #include namespace Ion { namespace Simulator { namespace Journal { -using Ion::Events::Event; -class Journal : public Ion::Events::Journal { -public: - void pushEvent(Event e) override { - m_eventStorage.push(e); - } - virtual Event popEvent() override { - if (isEmpty()) { - return Ion::Events::None; - } - Event e = m_eventStorage.front(); - m_eventStorage.pop(); - return e; - } - virtual bool isEmpty() override { - return m_eventStorage.empty(); - } -private: - std::queue m_eventStorage; -}; - void init() { Events::logTo(logJournal()); } Events::Journal * replayJournal() { - static Journal journal; + static QueueJournal journal; return &journal; } Events::Journal * logJournal() { - static Journal journal; + static QueueJournal journal; return &journal; } diff --git a/ion/src/simulator/shared/journal/queue_journal.h b/ion/src/simulator/shared/journal/queue_journal.h new file mode 100644 index 000000000..5038e6250 --- /dev/null +++ b/ion/src/simulator/shared/journal/queue_journal.h @@ -0,0 +1,35 @@ +#ifndef ION_SIMULATOR_JOURNAL_QUEUE_JOURNAL_H +#define ION_SIMULATOR_JOURNAL_QUEUE_JOURNAL_H + +#include +#include + +namespace Ion { +namespace Simulator { +namespace Journal { + +class QueueJournal : public Ion::Events::Journal { +public: + void pushEvent(Ion::Events::Event e) override { + m_eventStorage.push(e); + } + virtual Ion::Events::Event popEvent() override { + if (isEmpty()) { + return Ion::Events::None; + } + Ion::Events::Event e = m_eventStorage.front(); + m_eventStorage.pop(); + return e; + } + virtual bool isEmpty() override { + return m_eventStorage.empty(); + } +private: + std::queue m_eventStorage; +}; + +} +} +} + +#endif From c66db8c98d1190c93f946807c56a574ceb8614cd Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 25 Feb 2021 15:25:52 -0500 Subject: [PATCH 058/105] [ion] Actually send None events to the destination journal Said journal will most likely ignore it, but it gives it the opporunity to do something about it. --- ion/src/shared/events_keyboard.cpp | 2 +- ion/src/simulator/shared/journal/queue_journal.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ion/src/shared/events_keyboard.cpp b/ion/src/shared/events_keyboard.cpp index a378ea0fb..1c56952e0 100644 --- a/ion/src/shared/events_keyboard.cpp +++ b/ion/src/shared/events_keyboard.cpp @@ -134,7 +134,7 @@ Event getEvent(int * timeout) { } } Event e = innerGetEvent(timeout); - if (sDestinationJournal != nullptr && e != None) { + if (sDestinationJournal != nullptr) { sDestinationJournal->pushEvent(e); } return e; diff --git a/ion/src/simulator/shared/journal/queue_journal.h b/ion/src/simulator/shared/journal/queue_journal.h index 5038e6250..71d62cc79 100644 --- a/ion/src/simulator/shared/journal/queue_journal.h +++ b/ion/src/simulator/shared/journal/queue_journal.h @@ -11,7 +11,9 @@ namespace Journal { class QueueJournal : public Ion::Events::Journal { public: void pushEvent(Ion::Events::Event e) override { - m_eventStorage.push(e); + if (e != Ion::Events::None) { + m_eventStorage.push(e); + } } virtual Ion::Events::Event popEvent() override { if (isEmpty()) { From 2ebff40c627ae0b7a6d282cfef91903c836171e0 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 25 Feb 2021 15:32:43 -0500 Subject: [PATCH 059/105] [ion/simulator/web] Implement a custom journal with callbacks This journal adds two new callbacks: - onIonEvent - onEpsilonIdle --- ion/src/simulator/web/Makefile | 2 +- ion/src/simulator/web/journal.cpp | 58 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 ion/src/simulator/web/journal.cpp diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index 6ed2f3151..98b634e8f 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -16,6 +16,7 @@ LDFLAGS += --pre-js ion/src/simulator/web/preamble_env.js ion_src += $(addprefix ion/src/simulator/web/, \ clipboard_helper.cpp \ exports.cpp \ + journal.cpp \ keyboard_callback.cpp \ window_callback.cpp \ ) @@ -24,7 +25,6 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/language.cpp \ dummy/haptics_enabled.cpp \ haptics.cpp \ - journal.cpp \ ) ion_src += ion/src/shared/collect_registers.cpp diff --git a/ion/src/simulator/web/journal.cpp b/ion/src/simulator/web/journal.cpp new file mode 100644 index 000000000..85a988c95 --- /dev/null +++ b/ion/src/simulator/web/journal.cpp @@ -0,0 +1,58 @@ +#include "../shared/journal.h" +#include "../shared/journal/queue_journal.h" +#include + +namespace Ion { +namespace Simulator { +namespace Journal { + +using Ion::Events::Event; +using Ion::Events::None; + +class LogJournal : public Ion::Events::Journal { +public: + void pushEvent(Event e) override { + static bool lastEventWasNone = false; + if (e != None) { + EM_ASM({ + if (typeof Module.onIonEvent === "function") { + Module.onIonEvent($0); + } + }, static_cast(e)); + lastEventWasNone = true; + } else { + if (!lastEventWasNone) { + EM_ASM({ + if (typeof Module.onEpsilonIdle === "function") { + Module.onEpsilonIdle(); + } + }); + } + lastEventWasNone = true; + } + } + Event popEvent() override { + return None; + } + bool isEmpty() override { + return true; + } +}; + +void init() { + Events::logTo(logJournal()); +} + +Events::Journal * replayJournal() { + static QueueJournal journal; + return &journal; +} + +Ion::Events::Journal * logJournal() { + static LogJournal journal; + return &journal; +} + +} +} +} From 0cdfc44c6f8b67ff6d90d3c663939109c058c399 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 25 Feb 2021 15:33:46 -0500 Subject: [PATCH 060/105] [ion/simulator/web] Improve dependency tracking --- ion/src/simulator/web/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index 98b634e8f..e4fbbb274 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -36,7 +36,7 @@ endif DEFAULT = epsilon.zip -$(addprefix $(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css): ion/src/simulator/shared/layout.json +$(addprefix $(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css): ion/src/simulator/shared/layout.json ion/src/simulator/web/layout.py $(call rule_label,LAYOUT) $(Q) $(PYTHON) ion/src/simulator/web/layout.py --html $(BUILD_DIR)/ion/src/simulator/web/calculator.html --css $(BUILD_DIR)/ion/src/simulator/web/calculator.css $< From eb0ca7b1186f5d75258e33ff0219b3076b5aeba5 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 25 Feb 2021 15:43:45 -0500 Subject: [PATCH 061/105] [ion/simulator/web] Add a loader --- ion/src/simulator/web/layout.py | 39 ++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/ion/src/simulator/web/layout.py b/ion/src/simulator/web/layout.py index b2e9ebbda..9c992dcfa 100644 --- a/ion/src/simulator/web/layout.py +++ b/ion/src/simulator/web/layout.py @@ -37,7 +37,7 @@ def css(layout): css_percentage_declaration('padding-bottom', background[3]/background[2]) ) css += css_rule( - '.calculator canvas', + '.calculator canvas, .calculator .loader', css_declaration('position', 'absolute'), css_rect_declarations(layout['screen'], background) ) @@ -67,6 +67,42 @@ def css(layout): css_declaration('image-rendering', 'pixelated'), css_declaration('-ms-interpolation-mode', 'nearest-neighbor') ) + css += css_rule( + '.calculator.loading canvas', + css_declaration('display', 'none') + ) + css += css_rule( + '.calculator .loader', + css_declaration('display', 'none') + ) + css += css_rule( + '.calculator.loading .loader', + css_declaration('display', 'block'), + css_declaration('background-color', '#000'), + css_declaration('position', 'absolute') + ) + css += css_rule( + '.calculator .loader span', + css_declaration('display', 'inline-block'), + css_declaration('width', '80px'), + css_declaration('height', '80px'), + css_declaration('top', '50%'), + css_declaration('margin-top', '-40px'), + css_declaration('left', '50%'), + css_declaration('margin-left', '-40px') + ) + css += '@keyframes calculator-loader-rotation { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }\n' + css += css_rule('.calculator .loader span:after', + css_declaration('content', '" "'), + css_declaration('display', 'block'), + css_declaration('width', '64px'), + css_declaration('height', '64px'), + css_declaration('margin', '8px'), + css_declaration('border-radius', '50%'), + css_declaration('border', '6px solid #fff'), + css_declaration('border-color', '#fff transparent #fff transparent'), + css_declaration('animation', 'calculator-loader-rotation 1.2s linear infinite') + ) return css def html(layout): @@ -74,6 +110,7 @@ def html(layout): background = layout["background"] html = '' html += '
\n' + html += '
\n' html += ' \n' for key in layout["keys"]: html += ' \n' % key From 43b7f767ee3588ff1edc2d5b4c07f0f4abd9199e Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 25 Feb 2021 17:50:19 -0500 Subject: [PATCH 062/105] [ion/simulator/web] Clean the htmlpack API --- build/targets.simulator.web.mak | 2 +- ion/src/simulator/web/Makefile | 2 +- .../web/{simulator-setup.js => calculator.js} | 15 +++++++++------ ion/src/simulator/web/layout.py | 2 +- ion/src/simulator/web/simulator.html.inc | 4 ++-- 5 files changed, 14 insertions(+), 11 deletions(-) rename ion/src/simulator/web/{simulator-setup.js => calculator.js} (88%) diff --git a/build/targets.simulator.web.mak b/build/targets.simulator.web.mak index 887f6e60b..18ec0563b 100644 --- a/build/targets.simulator.web.mak +++ b/build/targets.simulator.web.mak @@ -3,4 +3,4 @@ $(BUILD_DIR)/test.js: EMSCRIPTEN_MODULARIZE = 0 HANDY_TARGETS += htmlpack HANDY_TARGETS_EXTENSIONS += zip -$(BUILD_DIR)/htmlpack.zip: $(addprefix $(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css) $(BUILD_DIR)/epsilon.js ion/src/simulator/web/simulator-setup.js +$(BUILD_DIR)/htmlpack.zip: $(addprefix $(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css) $(BUILD_DIR)/epsilon.js ion/src/simulator/web/calculator.js diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index e4fbbb274..3b60f0f8e 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -36,7 +36,7 @@ endif DEFAULT = epsilon.zip -$(addprefix $(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css): ion/src/simulator/shared/layout.json ion/src/simulator/web/layout.py +$(addprefix $(BUILD_DIR)/ion/src/simulator/web/,calculator.html calculator.css): ion/src/simulator/shared/layout.json ion/src/simulator/web/layout.py | $$(@D)/. $(call rule_label,LAYOUT) $(Q) $(PYTHON) ion/src/simulator/web/layout.py --html $(BUILD_DIR)/ion/src/simulator/web/calculator.html --css $(BUILD_DIR)/ion/src/simulator/web/calculator.css $< diff --git a/ion/src/simulator/web/simulator-setup.js b/ion/src/simulator/web/calculator.js similarity index 88% rename from ion/src/simulator/web/simulator-setup.js rename to ion/src/simulator/web/calculator.js index a0a756eef..2234f1fa6 100644 --- a/ion/src/simulator/web/simulator-setup.js +++ b/ion/src/simulator/web/calculator.js @@ -1,16 +1,16 @@ -function EpsilonSetup(emModule) { +function Calculator(emModule) { /* emModule is an optional parameter. * In addition to the ones supported by Emscripten, here are the values that * this object can have: - * - calculator: a DOM element containing a copy of 'calculator.html' as + * - element: a DOM element containing a copy of 'calculator.html' as * generated by 'layout.py' * - mirrorCanvas: a DOM element where the main canvas will be mirrored */ // Configure emModule var emModule = (typeof emModule === 'undefined') ? {} : emModule; - var calculator = emModule.calculator || document.querySelector('.calculator'); - var mainCanvas = calculator.querySelector("canvas"); + var calculatorElement = emModule.element || document.querySelector('.calculator'); + var mainCanvas = calculatorElement.querySelector("canvas"); if (typeof emModule.mirrorCanvas === 'undefined') { /* If emModule.mirrorCanvas is defined as null, don't do anything */ emModule.mirrorCanvas = document.querySelector('.calculator-mirror canvas'); @@ -22,6 +22,9 @@ function EpsilonSetup(emModule) { '--language', document.documentElement.lang || window.navigator.language.split('-')[0] ], + onEpsilonIdle: function() { + calculatorElement.classList.remove('loading'); + }, downloadScreenshot: function() { // toDataURL needs the canvas to be refreshed this._IonDisplayForceRefresh(); @@ -69,7 +72,7 @@ function EpsilonSetup(emModule) { var downHandler = eventHandler(emModule._IonSimulatorKeyboardKeyDown); var upHandler = eventHandler(emModule._IonSimulatorKeyboardKeyUp); - calculator.querySelectorAll('span').forEach(function(span){ + calculatorElement.querySelectorAll('span').forEach(function(span){ /* We decide to hook both to touch and mouse events * On most mobile browsers, mouse events are generated if addition to touch * events, so this could seem pointless. But those mouse events are not @@ -86,5 +89,5 @@ function EpsilonSetup(emModule) { } if (typeof exports === 'object' && typeof module === 'object') { - module.exports = EpsilonSetup; + module.exports = Calculator; } diff --git a/ion/src/simulator/web/layout.py b/ion/src/simulator/web/layout.py index 9c992dcfa..cac9fffd6 100644 --- a/ion/src/simulator/web/layout.py +++ b/ion/src/simulator/web/layout.py @@ -109,7 +109,7 @@ def html(layout): screen = layout["screen"] background = layout["background"] html = '' - html += '
\n' + html += '
\n' html += '
\n' html += ' \n' for key in layout["keys"]: diff --git a/ion/src/simulator/web/simulator.html.inc b/ion/src/simulator/web/simulator.html.inc index 4cc6f8c89..d5addc353 100644 --- a/ion/src/simulator/web/simulator.html.inc +++ b/ion/src/simulator/web/simulator.html.inc @@ -32,9 +32,9 @@