mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[Git] Fix conflicts
This commit is contained in:
5
.github/workflows/ci-workflow.yml
vendored
5
.github/workflows/ci-workflow.yml
vendored
@@ -23,6 +23,7 @@ jobs:
|
||||
submodules: true
|
||||
- run: make -j2 MODEL=n0100 epsilon.dfu
|
||||
- run: make -j2 MODEL=n0100 epsilon.onboarding.dfu
|
||||
- run: make -j2 MODEL=n0100 epsilon.official.onboarding.dfu
|
||||
- run: make -j2 MODEL=n0100 epsilon.onboarding.update.dfu
|
||||
- run: make -j2 MODEL=n0100 epsilon.onboarding.beta.dfu
|
||||
- run: make -j2 MODEL=n0100 flasher.light.dfu
|
||||
@@ -42,6 +43,7 @@ jobs:
|
||||
submodules: true
|
||||
- run: make -j2 epsilon.dfu
|
||||
- run: make -j2 epsilon.onboarding.dfu
|
||||
- run: make -j2 epsilon.official.onboarding.dfu
|
||||
- run: make -j2 epsilon.onboarding.update.dfu
|
||||
- run: make -j2 epsilon.onboarding.beta.dfu
|
||||
- run: make -j2 flasher.light.dfu
|
||||
@@ -63,10 +65,11 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- run: make -j2 PLATFORM=simulator TARGET=web
|
||||
- run: make -j2 PLATFORM=simulator TARGET=web epsilon.official.js
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: epsilon-simulator-web.zip
|
||||
path: output/release/simulator/web/simulator.zip
|
||||
path: output/release/simulator/web/epsilon.zip
|
||||
- run: make -j2 PLATFORM=simulator TARGET=web test.headless.js
|
||||
build-simulator-linux:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -21,9 +21,6 @@ OMEGA_THEME ?= omega_light
|
||||
ifndef USE_LIBA
|
||||
$(error platform.mak should define USE_LIBA)
|
||||
endif
|
||||
ifndef EXE
|
||||
$(error platform.mak should define EXE, the extension for executables)
|
||||
endif
|
||||
include build/toolchain.$(TOOLCHAIN).mak
|
||||
|
||||
SFLAGS += -DDEBUG=$(DEBUG)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
TOOLCHAIN = android
|
||||
EXE = so
|
||||
|
||||
EPSILON_TELEMETRY ?= 1
|
||||
|
||||
ifdef NDK_ABI
|
||||
BUILD_DIR := $(BUILD_DIR)/$(NDK_ABI)
|
||||
ARCHS = armeabi-v7a arm64-v8a x86 x86_64
|
||||
|
||||
ifdef ARCH
|
||||
EXE = so
|
||||
BUILD_DIR := $(BUILD_DIR)/$(ARCH)
|
||||
endif
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
# Define standard compilation rules
|
||||
|
||||
.PHONY: official_authorization
|
||||
ifeq ($(ACCEPT_OFFICIAL_TOS),1)
|
||||
official_authorization:
|
||||
@echo "CAUTION: You are about to build an official NumWorks firmware. Distribution of such firmware by a third party is prohibited. Are you sure you want to proceed? Please type "yes" to confirm." && read ans && [ $${ans:-no} = yes ]
|
||||
else
|
||||
official_authorization:
|
||||
@echo "CAUTION: You are trying to build an official NumWorks firmware."
|
||||
@echo "Distribution of such firmware by a third party is prohibited."
|
||||
@echo "Please set the ACCEPT_OFFICIAL_TOS environment variable to proceed."
|
||||
@exit -1
|
||||
endif
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
AS, %.o, %.s, \
|
||||
@@ -31,6 +38,12 @@ $(eval $(call rule_for, \
|
||||
$$(CXX) $$(CXXFLAGS) $$(SFLAGS) -c $$< -o $$@ \
|
||||
))
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
CPP, %, %.inc, \
|
||||
$$(CPP) -P $$< $$@ \
|
||||
))
|
||||
|
||||
ifdef EXE
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Work around command-line length limit
|
||||
# On Msys2 the max command line is 32 000 characters. Our standard LD command
|
||||
@@ -47,6 +60,7 @@ $(eval $(call rule_for, \
|
||||
$$(LD) $$^ $$(LDFLAGS) -o $$@ \
|
||||
))
|
||||
endif
|
||||
endif
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
WINDRES, %.o, %.rc, \
|
||||
|
||||
@@ -40,18 +40,16 @@ all_official:
|
||||
$(Q) $(MAKE) MODEL=n0100 epsilon.official.onboarding.dfu
|
||||
$(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/all_official/epsilon.device.n0100.dfu
|
||||
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP"
|
||||
$(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean
|
||||
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip
|
||||
$(Q) cp output/release/simulator/web/simulator.official.zip output/all_official/simulator.web.zip
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=web clean
|
||||
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web epsilon.official.zip
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.zip output/all_official/simulator.web.zip
|
||||
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS"
|
||||
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js
|
||||
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web epsilon.official.js
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.js
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.js.mem output/all_official/epsilon.js.mem
|
||||
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS"
|
||||
$(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean
|
||||
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=web clean
|
||||
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.python.js
|
||||
$(Q) cp output/release/simulator/web/epsilon.official.js.mem output/all_official/epsilon.python.js.mem
|
||||
$(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID"
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=android clean
|
||||
$(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.signed.apk
|
||||
|
||||
3
build/targets.simulator.android.mak
Normal file
3
build/targets.simulator.android.mak
Normal file
@@ -0,0 +1,3 @@
|
||||
ifndef ARCH
|
||||
HANDY_TARGETS_EXTENSIONS += apk
|
||||
endif
|
||||
@@ -1,6 +1,3 @@
|
||||
$(BUILD_DIR)/epsilon%packed.js: EMSCRIPTEN_INIT_FILE = 0
|
||||
HANDY_TARGETS_EXTENSIONS += zip
|
||||
|
||||
$(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0
|
||||
|
||||
$(BUILD_DIR)/epsilon.packed.js: $(call object_for,$(epsilon_src))
|
||||
$(BUILD_DIR)/epsilon.official.packed.js: $(call object_for,$(epsilon_official_src))
|
||||
|
||||
@@ -13,16 +13,16 @@ NDK_TOOLCHAIN_PATH = $(NDK_PATH)/toolchains/llvm/prebuilt/$(NDK_HOST_TAG)/bin
|
||||
# is no toolchain for those archs on those API levels. Let's enforce NDK_VERSION
|
||||
# at 21 for these archs, and 16 for the others.
|
||||
|
||||
ifeq ($(NDK_ABI),armeabi-v7a)
|
||||
ifeq ($(ARCH),armeabi-v7a)
|
||||
NDK_TARGET = armv7a-linux-androideabi
|
||||
NDK_VERSION = 16
|
||||
else ifeq ($(NDK_ABI),arm64-v8a)
|
||||
else ifeq ($(ARCH),arm64-v8a)
|
||||
NDK_TARGET = aarch64-linux-android
|
||||
NDK_VERSION = 21
|
||||
else ifeq ($(NDK_ABI),x86)
|
||||
else ifeq ($(ARCH),x86)
|
||||
NDK_TARGET = i686-linux-android
|
||||
NDK_VERSION = 16
|
||||
else ifeq ($(NDK_ABI),x86_64)
|
||||
else ifeq ($(ARCH),x86_64)
|
||||
NDK_TARGET = x86_64-linux-android
|
||||
NDK_VERSION = 21
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
CC = emcc
|
||||
CXX = emcc
|
||||
LD = emcc
|
||||
CPP = cpp
|
||||
|
||||
EMSCRIPTEN_ASYNC_SYMBOLS = \
|
||||
SAFE_HEAP_LOAD \
|
||||
@@ -120,20 +121,9 @@ endif
|
||||
# Configure EMFLAGS
|
||||
EMFLAGS += -s WASM=0
|
||||
|
||||
# Since emcc 1.39.5, DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR is defautly
|
||||
# to 1 which discards old looks up to find DOM elements. However SDL relies on
|
||||
# the presence of a target "#canvas" that used to return the Module['canvas']
|
||||
# target but not anymore. It also expects the existence of Module['canvas'].
|
||||
# Until we fix the DOM of the html calling epsilon module, we use the deprecated
|
||||
# 'find_event_target'.
|
||||
# TODO: fix DOM of htmls files that uses epsilon js module
|
||||
EMFLAGS += -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0
|
||||
|
||||
# Configure LDFLAGS
|
||||
EMSCRIPTEN_MODULARIZE ?= 1
|
||||
LDFLAGS += -s MODULARIZE=$(EMSCRIPTEN_MODULARIZE) -s 'EXPORT_NAME="Epsilon"'
|
||||
EMSCRIPTEN_INIT_FILE ?= 1
|
||||
LDFLAGS += --memory-init-file $(EMSCRIPTEN_INIT_FILE)
|
||||
LDFLAGS += -s MODULARIZE=$(EMSCRIPTEN_MODULARIZE) -s 'EXPORT_NAME="Epsilon"' --memory-init-file 0
|
||||
|
||||
SFLAGS += $(EMFLAGS)
|
||||
LDFLAGS += $(EMFLAGS) -Oz -s EXPORTED_FUNCTIONS='["_main", "_IonSimulatorKeyboardKeyDown", "_IonSimulatorKeyboardKeyUp", "_IonSimulatorEventsPushEvent", "_IonSoftwareVersion", "_IonPatchLevel", "_IonDisplayForceRefresh"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["UTF8ToString"]'
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#include <escher/run_loop.h>
|
||||
#include <assert.h>
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
RunLoop::RunLoop() :
|
||||
m_time(0) {
|
||||
|
||||
@@ -11,6 +11,12 @@ $(call object_for,ion/src/simulator/shared/main.cpp) : SFLAGS += -DEPSILON_SDL_F
|
||||
|
||||
LDFLAGS += -ljnigraphics -llog
|
||||
|
||||
|
||||
# If ARCH is not defined, we will re-trigger a build for each avaialble ARCH.
|
||||
# This is used to build APKs, which needs to embbed a binary for each ARCH.
|
||||
|
||||
ifndef ARCH
|
||||
|
||||
# Android resources
|
||||
# Some android resources needs to be filtered through ImageMagick. Others are
|
||||
# simply copied over.
|
||||
@@ -27,56 +33,50 @@ $(BUILD_DIR)/app/res/%.xml: ion/src/simulator/android/src/res/%.xml | $$(@D)/.
|
||||
$(call rule_label,COPY)
|
||||
$(Q) cp $< $@
|
||||
|
||||
# Cross-ABI libepsilon.so
|
||||
# This file is loaded is loaded only once, which prevents us from tracking
|
||||
# dependencies across ABIs. As a shortcut, we simply force a re-make of
|
||||
# libepsilon.so for each ABI.
|
||||
# This rule allow us to build any executable (%) for a specified ARCH ($1)
|
||||
# We depend on a phony target to make sure this rule is always executed
|
||||
|
||||
.PHONY: force_remake
|
||||
|
||||
define rule_for_libepsilon
|
||||
$$(BUILD_DIR)/app/libs/%/lib$(1): force_remake $$$$(@D)/.
|
||||
$(Q) echo "MAKE NDK_ABI=$$*"
|
||||
$(Q) $$(MAKE) NDK_ABI=$$* $(1)
|
||||
$(Q) cp $$(BUILD_DIR)/$$*/$(1) $$@
|
||||
define rule_for_arch_executable
|
||||
.PRECIOUS: $$(BUILD_DIR)/$(1)/%.so
|
||||
$$(BUILD_DIR)/$(1)/%.so: force_remake
|
||||
$(Q) echo "MAKE ARCH=$(1) $$*.so"
|
||||
$(Q) $$(MAKE) ARCH=$(1) --silent $$*.so
|
||||
endef
|
||||
|
||||
$(eval $(call rule_for_libepsilon,epsilon.so))
|
||||
$(eval $(call rule_for_libepsilon,epsilon.official.so))
|
||||
# We need to put the .so files somewhere Gradle can pick them up.
|
||||
# We decided to use the location "app/libs/$EXECUTABLE/$ARCH/libepsilon.so"
|
||||
# This way it's easy to import the shared object from Java code (it's always
|
||||
# named libepsilon.so), and it's easy to make Gradle use a given executable by
|
||||
# simply using the jniLibs.src directive.
|
||||
define path_for_arch_jni_lib
|
||||
$$(BUILD_DIR)/app/libs/%/$(1)/libepsilon.so
|
||||
endef
|
||||
|
||||
# If NDK_ABI is not defined, we will re-trigger a build for each avaialble ABI.
|
||||
# This is used to build APKs, which needs to embbed a binary for each ABI.
|
||||
define rule_for_arch_jni_lib
|
||||
$(call path_for_arch_jni_lib,$(1)): $$(BUILD_DIR)/$(1)/%.so | $$$$(@D)/.
|
||||
$(Q) cp $$< $$@
|
||||
endef
|
||||
|
||||
ifndef NDK_ABI
|
||||
$(foreach ARCH,$(ARCHS),$(eval $(call rule_for_arch_executable,$(ARCH))))
|
||||
$(foreach ARCH,$(ARCHS),$(eval $(call rule_for_arch_jni_lib,$(ARCH))))
|
||||
|
||||
NDK_ABIS = armeabi-v7a arm64-v8a x86 x86_64
|
||||
apk_deps = $(foreach ARCH,$(ARCHS),$(call path_for_arch_jni_lib,$(ARCH)))
|
||||
apk_deps += $(subst ion/src/simulator/android/src/res,$(BUILD_DIR)/app/res,$(wildcard ion/src/simulator/android/src/res/*/*))
|
||||
apk_deps += $(addprefix $(BUILD_DIR)/app/res/,mipmap/ic_launcher.png mipmap-v26/ic_launcher_foreground.png)
|
||||
|
||||
epsilon_apk_deps = $(subst ion/src/simulator/android/src/res,$(BUILD_DIR)/app/res,$(wildcard ion/src/simulator/android/src/res/*/*))
|
||||
epsilon_apk_deps += $(addprefix $(BUILD_DIR)/app/res/,mipmap/ic_launcher.png mipmap-v26/ic_launcher_foreground.png)
|
||||
.PRECIOUS: $(apk_deps)
|
||||
|
||||
define rule_for_gradle
|
||||
.PHONY: gradle_$1_$2
|
||||
gradle_$1_$2: $$(epsilon_apk_deps) $$(patsubst %,$$(BUILD_DIR)/app/libs/%/libepsilon$2so,$(NDK_ABIS))
|
||||
$(BUILD_DIR)/%.apk: $(apk_deps)
|
||||
@echo "GRADLE ion/src/simulator/android/build.gradle"
|
||||
$(Q) ANDROID_HOME=$(ANDROID_HOME) EPSILON_VERSION=$(EPSILON_VERSION) BUILD_DIR=$(BUILD_DIR) ion/src/simulator/android/gradlew -b ion/src/simulator/android/build.gradle $1
|
||||
endef
|
||||
|
||||
$(eval $(call rule_for_gradle,assembleCodesigned,.))
|
||||
$(eval $(call rule_for_gradle,assembleRelease,.))
|
||||
$(eval $(call rule_for_gradle,assembleCodesigned,.official.))
|
||||
$(eval $(call rule_for_gradle,assembleRelease,.official.))
|
||||
$(Q) ANDROID_HOME=$(ANDROID_HOME) EPSILON_VERSION=$(EPSILON_VERSION) BUILD_DIR=$(BUILD_DIR) EPSILON_VARIANT=$* ion/src/simulator/android/gradlew -b ion/src/simulator/android/build.gradle assembleRelease
|
||||
$(Q) cp $(BUILD_DIR)/app/outputs/apk/release/android-release*.apk $@
|
||||
|
||||
DEFAULT = epsilon.apk
|
||||
|
||||
.PHONY: epsilon%signed.apk
|
||||
epsilon%signed.apk: gradle_assembleCodesigned_%
|
||||
$(warning This is a signed build.)
|
||||
|
||||
.PHONY: epsilon%apk
|
||||
epsilon%apk: gradle_assembleRelease_%
|
||||
$(warning Building without code signing. Build epsilon$*signed.apk to generate a signed version.)
|
||||
|
||||
.PHONY: epsilon_run
|
||||
epsilon_run: gradle_installDebug
|
||||
.PHONY: %_run
|
||||
%_run: $(BUILD_DIR)/%.apk
|
||||
@echo "ADB $*.apk"
|
||||
$(Q) adb install $<
|
||||
|
||||
endif
|
||||
|
||||
@@ -53,10 +53,9 @@ android {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt')
|
||||
}
|
||||
codesigned {
|
||||
initWith buildTypes.release
|
||||
signingConfig signingConfigs.environment
|
||||
if (projectVariable('SIGNING_STORE_FILE')) {
|
||||
signingConfig signingConfigs.environment
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceSets{
|
||||
@@ -64,12 +63,13 @@ android {
|
||||
manifest.srcFile 'src/AndroidManifest.xml'
|
||||
res.srcDir BUILD_DIR + '/res'
|
||||
java.srcDir 'src'
|
||||
jniLibs.srcDir BUILD_DIR + '/libs'
|
||||
jniLibs.srcDir BUILD_DIR + '/libs/' + System.getenv('EPSILON_VARIANT')
|
||||
assets.srcDir '../assets'
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ SFLAGS += -Iion/src/simulator/web/include
|
||||
# Only render the screen, not the whole calculator which will be drawn in HTML
|
||||
SFLAGS += -DEPSILON_SDL_SCREEN_ONLY=1
|
||||
|
||||
# Enable to set environment variables for a module
|
||||
LDFLAGS += --pre-js ion/src/simulator/web/preamble_env.js
|
||||
|
||||
ion_src += $(addprefix ion/src/simulator/web/, \
|
||||
callback.cpp \
|
||||
helpers.cpp \
|
||||
@@ -24,14 +27,14 @@ ion_src += ion/src/simulator/shared/dummy/telemetry_init.cpp
|
||||
ion_src += ion/src/shared/telemetry_console.cpp
|
||||
endif
|
||||
|
||||
DEFAULT = $(BUILD_DIR)/simulator.zip
|
||||
DEFAULT = epsilon.zip
|
||||
|
||||
$(BUILD_DIR)/simulator%zip: $(BUILD_DIR)/epsilon%packed.js
|
||||
$(BUILD_DIR)/epsilon%zip: $(BUILD_DIR)/epsilon%js $(BUILD_DIR)/ion/src/simulator/web/simulator.html
|
||||
@rm -rf $(basename $@)
|
||||
@mkdir -p $(basename $@)
|
||||
@cp $^ $(basename $@)/epsilon.js
|
||||
@cp $< $(basename $@)/epsilon.js
|
||||
@cp ion/src/simulator/assets/background.jpg $(basename $@)/
|
||||
@cp ion/src/simulator/web/simulator.html $(basename $@)/
|
||||
@cp $(BUILD_DIR)/ion/src/simulator/web/simulator.html $(basename $@)/
|
||||
$(call rule_label,ZIP)
|
||||
@zip -r -9 -j $@ $(basename $@) > /dev/null
|
||||
@rm -rf $(basename $@)
|
||||
|
||||
21
ion/src/simulator/web/preamble_env.js
Normal file
21
ion/src/simulator/web/preamble_env.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/* Use:
|
||||
*
|
||||
* var options = {
|
||||
canvas: ...,
|
||||
env: {
|
||||
VARIABLE_NAME: VARIABLE_VALUE
|
||||
}
|
||||
};
|
||||
Epsilon(options);
|
||||
*
|
||||
* Cf https://github.com/emscripten-core/emscripten/issues/9827
|
||||
* */
|
||||
|
||||
Module["preRun"] = function () {
|
||||
if (Module['env'] && typeof Module['env'] === 'object') {
|
||||
for (var key in Module['env']) {
|
||||
if (Module['env'].hasOwnProperty(key))
|
||||
ENV[key] = Module['env'][key];
|
||||
}
|
||||
}
|
||||
}
|
||||
54
ion/src/simulator/web/simulator-keyboard.html
Normal file
54
ion/src/simulator/web/simulator-keyboard.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<div id="keyboard">
|
||||
<div class="nav">
|
||||
<span class="left" data-key="0"></span>
|
||||
<span class="top" data-key="1"></span>
|
||||
<span class="bottom" data-key="2"></span>
|
||||
<span class="right" data-key="3"></span>
|
||||
<span class="ok" data-key="4"></span>
|
||||
<span class="back" data-key="5"></span>
|
||||
<span class="home" data-key="6"></span>
|
||||
<span class="power" data-key="7"></span>
|
||||
</div>
|
||||
<div class="functions">
|
||||
<span data-key="12"></span>
|
||||
<span data-key="13"></span>
|
||||
<span data-key="14"></span>
|
||||
<span data-key="15"></span>
|
||||
<span data-key="16"></span>
|
||||
<span data-key="17"></span>
|
||||
<span data-key="18"></span>
|
||||
<span data-key="19"></span>
|
||||
<span data-key="20"></span>
|
||||
<span data-key="21"></span>
|
||||
<span data-key="22"></span>
|
||||
<span data-key="23"></span>
|
||||
<span data-key="24"></span>
|
||||
<span data-key="25"></span>
|
||||
<span data-key="26"></span>
|
||||
<span data-key="27"></span>
|
||||
<span data-key="28"></span>
|
||||
<span data-key="29"></span>
|
||||
</div>
|
||||
<div class="digits">
|
||||
<span data-key="30"></span>
|
||||
<span data-key="31"></span>
|
||||
<span data-key="32"></span>
|
||||
<span data-key="33"></span>
|
||||
<span data-key="34"></span>
|
||||
<span data-key="36"></span>
|
||||
<span data-key="37"></span>
|
||||
<span data-key="38"></span>
|
||||
<span data-key="39"></span>
|
||||
<span data-key="40"></span>
|
||||
<span data-key="42"></span>
|
||||
<span data-key="43"></span>
|
||||
<span data-key="44"></span>
|
||||
<span data-key="45"></span>
|
||||
<span data-key="46"></span>
|
||||
<span data-key="48"></span>
|
||||
<span data-key="49"></span>
|
||||
<span data-key="50"></span>
|
||||
<span data-key="51"></span>
|
||||
<span data-key="52"></span>
|
||||
</div>
|
||||
</div>
|
||||
65
ion/src/simulator/web/simulator-setup.js
Normal file
65
ion/src/simulator/web/simulator-setup.js
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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 */
|
||||
|
||||
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 = {
|
||||
canvas: mainCanvas,
|
||||
arguments: ['--language', epsilonLanguage],
|
||||
onDisplayRefresh: function() {
|
||||
secondaryCanvasContext.drawImage(mainCanvas, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Epsilon(Module);
|
||||
|
||||
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();
|
||||
};
|
||||
}
|
||||
/* 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
|
||||
* generated in real time: instead, they are buffered and eventually fired
|
||||
* 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));
|
||||
});
|
||||
['touchend', 'mouseup'].forEach(function(type){
|
||||
span.addEventListener(type, eventHandler(Module._IonSimulatorKeyboardKeyUp));
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#define KEYBOARD #keyboard
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -65,7 +67,7 @@ a.action svg {
|
||||
max-height: 92.0vh;
|
||||
max-width: 100%;
|
||||
display: block; }
|
||||
.calculator .screen {
|
||||
.calculator #canvas {
|
||||
position: absolute;
|
||||
top: 8.5%;
|
||||
left: 16.25%;
|
||||
@@ -84,84 +86,84 @@ a.action svg {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.calculator .keyboard {
|
||||
KEYBOARD {
|
||||
position: absolute;
|
||||
top: 38.5%;
|
||||
left: 10%;
|
||||
width: 81%;
|
||||
bottom: 5%; }
|
||||
.calculator .keyboard span {
|
||||
KEYBOARD span {
|
||||
cursor: pointer;
|
||||
border-radius: 40%;
|
||||
display: block;
|
||||
float: left; }
|
||||
.calculator .keyboard span:hover {
|
||||
KEYBOARD span:hover {
|
||||
background-color: rgba(0, 0, 0, 0.1); }
|
||||
.calculator .keyboard span:active {
|
||||
KEYBOARD span:active {
|
||||
background-color: rgba(0, 0, 0, 0.2); }
|
||||
.calculator .keyboard .nav {
|
||||
KEYBOARD .nav {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 27%;
|
||||
width: 100%; }
|
||||
.calculator .keyboard .nav span {
|
||||
KEYBOARD .nav span {
|
||||
position: absolute; }
|
||||
.calculator .keyboard .nav .left {
|
||||
KEYBOARD .nav .left {
|
||||
top: 36%;
|
||||
left: 2%;
|
||||
width: 15%;
|
||||
height: 28%; }
|
||||
.calculator .keyboard .nav .right {
|
||||
KEYBOARD .nav .right {
|
||||
top: 36%;
|
||||
left: 17%;
|
||||
width: 15%;
|
||||
height: 28%; }
|
||||
.calculator .keyboard .nav .top {
|
||||
KEYBOARD .nav .top {
|
||||
top: 7%;
|
||||
left: 12%;
|
||||
width: 10%;
|
||||
height: 40%; }
|
||||
.calculator .keyboard .nav .bottom {
|
||||
KEYBOARD .nav .bottom {
|
||||
top: 53%;
|
||||
left: 12%;
|
||||
width: 10%;
|
||||
height: 40%; }
|
||||
.calculator .keyboard .nav .home {
|
||||
KEYBOARD .nav .home {
|
||||
top: 15%;
|
||||
left: 41%;
|
||||
width: 16%;
|
||||
height: 33%; }
|
||||
.calculator .keyboard .nav .power {
|
||||
KEYBOARD .nav .power {
|
||||
top: 54%;
|
||||
left: 42%;
|
||||
width: 16%;
|
||||
height: 33%; }
|
||||
.calculator .keyboard .nav .ok {
|
||||
KEYBOARD .nav .ok {
|
||||
top: 31%;
|
||||
left: 67%;
|
||||
width: 13%;
|
||||
height: 38%; }
|
||||
.calculator .keyboard .nav .back {
|
||||
KEYBOARD .nav .back {
|
||||
top: 31%;
|
||||
left: 84%;
|
||||
width: 13%;
|
||||
height: 38%; }
|
||||
.calculator .keyboard .functions {
|
||||
KEYBOARD .functions {
|
||||
position: absolute;
|
||||
top: 26.75%;
|
||||
left: 0.5%;
|
||||
width: 98%; }
|
||||
.calculator .keyboard .functions span {
|
||||
KEYBOARD .functions span {
|
||||
margin: 1.7% 1%;
|
||||
width: 14.65%;
|
||||
height: 0;
|
||||
padding-top: 10%; }
|
||||
.calculator .keyboard .digits {
|
||||
KEYBOARD .digits {
|
||||
position: absolute;
|
||||
top: 56.5%;
|
||||
left: 0.5%;
|
||||
width: 98%; }
|
||||
.calculator .keyboard .digits span {
|
||||
KEYBOARD .digits span {
|
||||
margin: 1.8% 2%;
|
||||
width: 16%;
|
||||
height: 0;
|
||||
@@ -173,61 +175,8 @@ a.action svg {
|
||||
<div class="col-calculator">
|
||||
<div class="calculator">
|
||||
<img src="background.jpg" alt="NumWorks Calculator">
|
||||
<canvas id="screen" class="screen" oncontextmenu="event.preventDefault()"></canvas>
|
||||
<div class="keyboard">
|
||||
<div class="nav">
|
||||
<span class="left" data-key="0"></span>
|
||||
<span class="top" data-key="1"></span>
|
||||
<span class="bottom" data-key="2"></span>
|
||||
<span class="right" data-key="3"></span>
|
||||
<span class="ok" data-key="4"></span>
|
||||
<span class="back" data-key="5"></span>
|
||||
<span class="home" data-key="6"></span>
|
||||
<span class="power" data-key="7"></span>
|
||||
</div>
|
||||
<div class="functions">
|
||||
<span data-key="12"></span>
|
||||
<span data-key="13"></span>
|
||||
<span data-key="14"></span>
|
||||
<span data-key="15"></span>
|
||||
<span data-key="16"></span>
|
||||
<span data-key="17"></span>
|
||||
<span data-key="18"></span>
|
||||
<span data-key="19"></span>
|
||||
<span data-key="20"></span>
|
||||
<span data-key="21"></span>
|
||||
<span data-key="22"></span>
|
||||
<span data-key="23"></span>
|
||||
<span data-key="24"></span>
|
||||
<span data-key="25"></span>
|
||||
<span data-key="26"></span>
|
||||
<span data-key="27"></span>
|
||||
<span data-key="28"></span>
|
||||
<span data-key="29"></span>
|
||||
</div>
|
||||
<div class="digits">
|
||||
<span data-key="30"></span>
|
||||
<span data-key="31"></span>
|
||||
<span data-key="32"></span>
|
||||
<span data-key="33"></span>
|
||||
<span data-key="34"></span>
|
||||
<span data-key="36"></span>
|
||||
<span data-key="37"></span>
|
||||
<span data-key="38"></span>
|
||||
<span data-key="39"></span>
|
||||
<span data-key="40"></span>
|
||||
<span data-key="42"></span>
|
||||
<span data-key="43"></span>
|
||||
<span data-key="44"></span>
|
||||
<span data-key="45"></span>
|
||||
<span data-key="46"></span>
|
||||
<span data-key="48"></span>
|
||||
<span data-key="49"></span>
|
||||
<span data-key="50"></span>
|
||||
<span data-key="51"></span>
|
||||
<span data-key="52"></span>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||
#include "simulator-keyboard.html"
|
||||
<div class="actions">
|
||||
<a id="action-fullscreen" class="action">
|
||||
<svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g fill="#434343"><path d="M5.075,6.95 L6.918,5.088 L3.938,2.062 L5.955,0.018 L0.052,0.018 L0.052,6.004 L2.098,3.928 L5.075,6.95 Z" class="si-glyph-fill"></path><path d="M16.0034788,9.916 L13.832,12.013 L10.799,8.96 L8.918,10.841 L11.957,13.897 L9.961,15.9813842 L16.0034788,15.9813842 L16.0034788,9.916 Z"></path></g></g></svg>
|
||||
@@ -239,46 +188,14 @@ a.action svg {
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-fullscreen">
|
||||
<canvas class="screen-magnified" width="320" height="240"></canvas>
|
||||
<canvas id="secondary-canvas" width="320" height="240"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<script src="epsilon.js"></script>
|
||||
<script>
|
||||
var mainCanvas = document.querySelector(".calculator .screen");
|
||||
var secondaryCanvasContext = document.querySelector(".screen-magnified").getContext("2d");
|
||||
var Module = {
|
||||
arguments: ["--language", window.navigator.language.split('-')[0]],
|
||||
canvas: mainCanvas,
|
||||
onDisplayRefresh: function() {
|
||||
secondaryCanvasContext.drawImage(mainCanvas, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
Epsilon(Module);
|
||||
#include "simulator-setup.js"
|
||||
</script>
|
||||
<script>
|
||||
function screenshot() {
|
||||
<!--toDataURL needs the canvas to be refreshed-->
|
||||
Module._IonDisplayForceRefresh();
|
||||
|
||||
var canvas = document.querySelector('.screen');
|
||||
var link = document.createElement('a');
|
||||
link.download = 'screenshot.png';
|
||||
link.href = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
|
||||
link.click();
|
||||
}
|
||||
|
||||
var spans = document.querySelectorAll(".calculator .keyboard span");
|
||||
for (var i=0; i< spans.length; i++) {
|
||||
var span = spans[i];
|
||||
span.addEventListener("mousedown", function(e) {
|
||||
Module._IonSimulatorKeyboardKeyDown(this.getAttribute("data-key"));
|
||||
});
|
||||
span.addEventListener("mouseup", function(e) {
|
||||
Module._IonSimulatorKeyboardKeyUp(this.getAttribute("data-key"));
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById("action-fullscreen").addEventListener("click", function(e){
|
||||
if (document.body.className == "fullscreen") {
|
||||
document.body.className = "";
|
||||
@@ -10,7 +10,7 @@ namespace Poincare {
|
||||
|
||||
namespace ApproximationHelper {
|
||||
template <typename T> int PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
|
||||
template <typename T> std::complex<T> NeglectRealOrImaginaryPartIfNeglectable(std::complex<T> result, std::complex<T> input1, std::complex<T> input2 = 1.0);
|
||||
template <typename T> std::complex<T> NeglectRealOrImaginaryPartIfNeglectable(std::complex<T> result, std::complex<T> input1, std::complex<T> input2 = 1.0, bool enableNullResult = true);
|
||||
|
||||
template <typename T> using ComplexCompute = Complex<T>(*)(const std::complex<T>, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
|
||||
template<typename T> Evaluation<T> Map(const ExpressionNode * expression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ComplexCompute<T> compute);
|
||||
|
||||
@@ -37,7 +37,7 @@ template <typename T> int ApproximationHelper::PositiveIntegerApproximationIfPos
|
||||
return absInt((int)scalar);
|
||||
}
|
||||
|
||||
template <typename T> std::complex<T> ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex<T> result, std::complex<T> input1, std::complex<T> input2) {
|
||||
template <typename T> std::complex<T> ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex<T> result, std::complex<T> input1, std::complex<T> input2, bool enableNullResult) {
|
||||
/* Cheat: openbsd functions (cos, sin, tan, cosh, acos, pow...) are
|
||||
* numerical implementation and thus are approximative.
|
||||
* The error epsilon is ~1E-7 on float and ~1E-15 on double. In order to avoid
|
||||
@@ -47,6 +47,9 @@ template <typename T> std::complex<T> ApproximationHelper::NeglectRealOrImaginar
|
||||
* sin(1E-15)=1E-15.
|
||||
* We can't do that for all evaluation as the user can operate on values as
|
||||
* small as 1E-308 (in double) and most results still be correct. */
|
||||
if (!enableNullResult && (result.imag() == 0.0 || result.real() == 0.0)) {
|
||||
return result;
|
||||
}
|
||||
T magnitude1 = minimalNonNullMagnitudeOfParts(input1);
|
||||
T magnitude2 = minimalNonNullMagnitudeOfParts(input2);
|
||||
T precision = 10.0*Expression::Epsilon<T>();
|
||||
@@ -126,8 +129,8 @@ template<typename T> MatrixComplex<T> ApproximationHelper::ElementWiseOnComplexM
|
||||
|
||||
template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible<float>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
|
||||
template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible<double>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
|
||||
template std::complex<float> Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable<float>(std::complex<float>,std::complex<float>,std::complex<float>);
|
||||
template std::complex<double> Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable<double>(std::complex<double>,std::complex<double>,std::complex<double>);
|
||||
template std::complex<float> Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable<float>(std::complex<float>,std::complex<float>,std::complex<float>,bool);
|
||||
template std::complex<double> Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable<double>(std::complex<double>,std::complex<double>,std::complex<double>,bool);
|
||||
template Poincare::Evaluation<float> Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute<float> compute);
|
||||
template Poincare::Evaluation<double> Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute<double> compute);
|
||||
template Poincare::Evaluation<float> Poincare::ApproximationHelper::MapReduce(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexAndComplexReduction<float> computeOnComplexes, Poincare::ApproximationHelper::ComplexAndMatrixReduction<float> computeOnComplexAndMatrix, Poincare::ApproximationHelper::MatrixAndComplexReduction<float> computeOnMatrixAndComplex, Poincare::ApproximationHelper::MatrixAndMatrixReduction<float> computeOnMatrices);
|
||||
|
||||
@@ -321,18 +321,22 @@ void Expression::defaultDeepReduceChildren(ExpressionNode::ReductionContext redu
|
||||
|
||||
Expression Expression::defaultShallowReduce() {
|
||||
Expression result;
|
||||
const int childrenCount = numberOfChildren();
|
||||
for (int i = 0; i < childrenCount; i++) {
|
||||
/* The reduction is shortcut if one child is unreal or undefined:
|
||||
* - the result is unreal if at least one child is unreal
|
||||
* - the result is undefined if at least one child is undefined but no child
|
||||
* is unreal */
|
||||
ExpressionNode::Type childIType = childAtIndex(i).type();
|
||||
if (childIType == ExpressionNode::Type::Unreal) {
|
||||
result = Unreal::Builder();
|
||||
break;
|
||||
} else if (childIType == ExpressionNode::Type::Undefined) {
|
||||
result = Undefined::Builder();
|
||||
if (sSimplificationHasBeenInterrupted) {
|
||||
result = Undefined::Builder();
|
||||
} else {
|
||||
const int childrenCount = numberOfChildren();
|
||||
for (int i = 0; i < childrenCount; i++) {
|
||||
/* The reduction is shortcut if one child is unreal or undefined:
|
||||
* - the result is unreal if at least one child is unreal
|
||||
* - the result is undefined if at least one child is undefined but no child
|
||||
* is unreal */
|
||||
ExpressionNode::Type childIType = childAtIndex(i).type();
|
||||
if (childIType == ExpressionNode::Type::Unreal) {
|
||||
result = Unreal::Builder();
|
||||
break;
|
||||
} else if (childIType == ExpressionNode::Type::Undefined) {
|
||||
result = Undefined::Builder();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result.isUninitialized()) {
|
||||
|
||||
@@ -183,7 +183,7 @@ Complex<T> PowerNode::compute(const std::complex<T> c, const std::complex<T> d,
|
||||
* so arg(c^d) = y*ln(r)+xθ.
|
||||
* We consider that arg[π] is negligeable if it is negligeable compared to
|
||||
* norm(d) = sqrt(x^2+y^2) and ln(r) = ln(norm(c)).*/
|
||||
return Complex<T>::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c, d));
|
||||
return Complex<T>::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c, d, false));
|
||||
}
|
||||
|
||||
// Layout
|
||||
|
||||
@@ -1317,6 +1317,8 @@ QUIZ_CASE(poincare_simplification_mix) {
|
||||
//assert_parsed_expression_simplify_to("log(cos(9)^ln(6), 9)", "ln(6)×log(cos(9), 9)"); // TODO: for this to work, we must know the sign of cos(9)
|
||||
assert_parsed_expression_simplify_to("(((√(6)-√(2))/4)/((√(6)+√(2))/4))+1", "-√(3)+3");
|
||||
assert_parsed_expression_simplify_to("1/√(𝐢) × (√(2)-𝐢×√(2))", "-2×𝐢"); // TODO: get rid of complex at denominator?
|
||||
|
||||
assert_expression_simplifies_approximates_to<double>("abs(√(300000.0003^23))", "9.7027409010183ᴇ62");
|
||||
}
|
||||
|
||||
QUIZ_CASE(poincare_hyperbolic_trigonometry) {
|
||||
|
||||
Reference in New Issue
Block a user