You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-12 13:20:55 +00:00
DisplayServerJavaScript implementation.
This commit is contained in:
2
misc/dist/html/full-size.html
vendored
2
misc/dist/html/full-size.html
vendored
@@ -169,8 +169,6 @@ $GODOT_HEAD_INCLUDE
|
|||||||
var height = window.innerHeight;
|
var height = window.innerHeight;
|
||||||
canvas.width = width * scale;
|
canvas.width = width * scale;
|
||||||
canvas.height = height * scale;
|
canvas.height = height * scale;
|
||||||
canvas.style.width = width + "px";
|
|
||||||
canvas.style.height = height + "px";
|
|
||||||
}
|
}
|
||||||
animationCallbacks.push(adjustCanvasDimensions);
|
animationCallbacks.push(adjustCanvasDimensions);
|
||||||
adjustCanvasDimensions();
|
adjustCanvasDimensions();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ Import("env")
|
|||||||
|
|
||||||
javascript_files = [
|
javascript_files = [
|
||||||
"audio_driver_javascript.cpp",
|
"audio_driver_javascript.cpp",
|
||||||
|
"display_server_javascript.cpp",
|
||||||
"http_client_javascript.cpp",
|
"http_client_javascript.cpp",
|
||||||
"javascript_eval.cpp",
|
"javascript_eval.cpp",
|
||||||
"javascript_main.cpp",
|
"javascript_main.cpp",
|
||||||
@@ -46,11 +47,21 @@ wrap_list = [
|
|||||||
js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js")
|
js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js")
|
||||||
|
|
||||||
zip_dir = env.Dir("#bin/.javascript_zip")
|
zip_dir = env.Dir("#bin/.javascript_zip")
|
||||||
out_files = [zip_dir.File("godot.js"), zip_dir.File("godot.wasm"), zip_dir.File("godot.html")]
|
binary_name = "godot.tools" if env["tools"] else "godot"
|
||||||
in_files = [js_wrapped, build[1], "#misc/dist/html/full-size.html"]
|
out_files = [
|
||||||
|
zip_dir.File(binary_name + ".js"),
|
||||||
|
zip_dir.File(binary_name + ".wasm"),
|
||||||
|
zip_dir.File(binary_name + ".html")
|
||||||
|
]
|
||||||
|
html_file = "#misc/dist/html/full-size.html"
|
||||||
|
in_files = [
|
||||||
|
js_wrapped,
|
||||||
|
build[1],
|
||||||
|
html_file
|
||||||
|
]
|
||||||
if env["threads_enabled"]:
|
if env["threads_enabled"]:
|
||||||
in_files.append(build[2])
|
in_files.append(build[2])
|
||||||
out_files.append(zip_dir.File("godot.worker.js"))
|
out_files.append(zip_dir.File(binary_name + ".worker.js"))
|
||||||
|
|
||||||
zip_files = env.InstallAs(out_files, in_files)
|
zip_files = env.InstallAs(out_files, in_files)
|
||||||
env.Zip(
|
env.Zip(
|
||||||
@@ -58,5 +69,5 @@ env.Zip(
|
|||||||
zip_files,
|
zip_files,
|
||||||
ZIPROOT=zip_dir,
|
ZIPROOT=zip_dir,
|
||||||
ZIPSUFFIX="${PROGSUFFIX}${ZIPSUFFIX}",
|
ZIPSUFFIX="${PROGSUFFIX}${ZIPSUFFIX}",
|
||||||
ZIPCOMSTR="Archving $SOURCES as $TARGET",
|
ZIPCOMSTR="Archving $SOURCES as $TARGET"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -190,19 +190,43 @@ void AudioDriverJavaScript::lock() {
|
|||||||
void AudioDriverJavaScript::unlock() {
|
void AudioDriverJavaScript::unlock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverJavaScript::finish() {
|
void AudioDriverJavaScript::finish_async() {
|
||||||
|
|
||||||
|
// Close the context, add the operation to the async_finish list in module.
|
||||||
|
int id = _driver_id;
|
||||||
|
_driver_id = 0;
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
EM_ASM({
|
EM_ASM({
|
||||||
|
var ref = Module.IDHandler.get($0);
|
||||||
|
Module.async_finish.push(new Promise(function(accept, reject) {
|
||||||
|
if (!ref) {
|
||||||
|
console.log("Ref not found!", $0, Module.IDHandler);
|
||||||
|
setTimeout(accept, 0);
|
||||||
|
} else {
|
||||||
|
const context = ref['context'];
|
||||||
|
// Disconnect script and input.
|
||||||
|
ref['script'].disconnect();
|
||||||
|
if (ref['input'])
|
||||||
|
ref['input'].disconnect();
|
||||||
|
ref = null;
|
||||||
|
context.close().then(function() {
|
||||||
|
accept();
|
||||||
|
}).catch(function(e) {
|
||||||
|
accept();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
Module.IDHandler.remove($0);
|
Module.IDHandler.remove($0);
|
||||||
}, _driver_id);
|
}, id);
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDriverJavaScript::finish() {
|
||||||
if (internal_buffer) {
|
if (internal_buffer) {
|
||||||
memdelete_arr(internal_buffer);
|
memdelete_arr(internal_buffer);
|
||||||
internal_buffer = nullptr;
|
internal_buffer = nullptr;
|
||||||
}
|
}
|
||||||
_driver_id = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error AudioDriverJavaScript::capture_start() {
|
Error AudioDriverJavaScript::capture_start() {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ public:
|
|||||||
virtual void lock();
|
virtual void lock();
|
||||||
virtual void unlock();
|
virtual void unlock();
|
||||||
virtual void finish();
|
virtual void finish();
|
||||||
|
void finish_async();
|
||||||
|
|
||||||
virtual Error capture_start();
|
virtual Error capture_start();
|
||||||
virtual Error capture_stop();
|
virtual Error capture_stop();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import os
|
|||||||
|
|
||||||
from emscripten_helpers import parse_config, run_closure_compiler, create_engine_file
|
from emscripten_helpers import parse_config, run_closure_compiler, create_engine_file
|
||||||
|
|
||||||
|
|
||||||
def is_active():
|
def is_active():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -17,12 +16,11 @@ def can_build():
|
|||||||
|
|
||||||
def get_opts():
|
def get_opts():
|
||||||
from SCons.Variables import BoolVariable
|
from SCons.Variables import BoolVariable
|
||||||
|
|
||||||
return [
|
return [
|
||||||
# eval() can be a security concern, so it can be disabled.
|
# eval() can be a security concern, so it can be disabled.
|
||||||
BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
|
BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
|
||||||
BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", False),
|
BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", False),
|
||||||
BoolVariable("use_closure_compiler", "Use closure compiler to minimize Javascript code", False),
|
BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -57,7 +55,7 @@ def configure(env):
|
|||||||
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
|
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
|
||||||
# Retain function names for backtraces at the cost of file size.
|
# Retain function names for backtraces at the cost of file size.
|
||||||
env.Append(LINKFLAGS=["--profiling-funcs"])
|
env.Append(LINKFLAGS=["--profiling-funcs"])
|
||||||
else: # 'debug'
|
else: # "debug"
|
||||||
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
|
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
|
||||||
env.Append(CCFLAGS=["-O1", "-g"])
|
env.Append(CCFLAGS=["-O1", "-g"])
|
||||||
env.Append(LINKFLAGS=["-O1", "-g"])
|
env.Append(LINKFLAGS=["-O1", "-g"])
|
||||||
@@ -150,7 +148,7 @@ def configure(env):
|
|||||||
env.Append(LIBS=["idbfs.js"])
|
env.Append(LIBS=["idbfs.js"])
|
||||||
|
|
||||||
env.Append(LINKFLAGS=["-s", "BINARYEN=1"])
|
env.Append(LINKFLAGS=["-s", "BINARYEN=1"])
|
||||||
env.Append(LINKFLAGS=["-s", "MODULARIZE=1", "-s", 'EXPORT_NAME="Godot"'])
|
env.Append(LINKFLAGS=["-s", "MODULARIZE=1", "-s", "EXPORT_NAME='Godot'"])
|
||||||
|
|
||||||
# Allow increasing memory buffer size during runtime. This is efficient
|
# Allow increasing memory buffer size during runtime. This is efficient
|
||||||
# when using WebAssembly (in comparison to asm.js) and works well for
|
# when using WebAssembly (in comparison to asm.js) and works well for
|
||||||
@@ -162,8 +160,10 @@ def configure(env):
|
|||||||
|
|
||||||
env.Append(LINKFLAGS=["-s", "INVOKE_RUN=0"])
|
env.Append(LINKFLAGS=["-s", "INVOKE_RUN=0"])
|
||||||
|
|
||||||
# callMain for manual start, FS for preloading.
|
# Allow use to take control of swapping WebGL buffers.
|
||||||
env.Append(LINKFLAGS=["-s", 'EXTRA_EXPORTED_RUNTIME_METHODS=["callMain", "FS"]'])
|
env.Append(LINKFLAGS=["-s", "OFFSCREEN_FRAMEBUFFER=1"])
|
||||||
|
|
||||||
|
# callMain for manual start, FS for preloading, PATH and ERRNO_CODES for BrowserFS.
|
||||||
|
env.Append(LINKFLAGS=["-s", "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain', 'FS', 'PATH', 'ERRNO_CODES']"])
|
||||||
# Add code that allow exiting runtime.
|
# Add code that allow exiting runtime.
|
||||||
env.Append(LINKFLAGS=['-s', 'EXIT_RUNTIME=1'])
|
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
|
||||||
|
|||||||
1181
platform/javascript/display_server_javascript.cpp
Normal file
1181
platform/javascript/display_server_javascript.cpp
Normal file
File diff suppressed because it is too large
Load Diff
187
platform/javascript/display_server_javascript.h
Normal file
187
platform/javascript/display_server_javascript.h
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* display_server_javascript.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef DISPLAY_SERVER_JAVASCRIPT_H
|
||||||
|
#define DISPLAY_SERVER_JAVASCRIPT_H
|
||||||
|
|
||||||
|
#include "servers/display_server.h"
|
||||||
|
|
||||||
|
#include <emscripten.h>
|
||||||
|
#include <emscripten/html5.h>
|
||||||
|
|
||||||
|
class DisplayServerJavaScript : public DisplayServer {
|
||||||
|
|
||||||
|
//int video_driver_index;
|
||||||
|
|
||||||
|
Vector2 windowed_size;
|
||||||
|
|
||||||
|
ObjectID window_attached_instance_id = {};
|
||||||
|
|
||||||
|
Ref<InputEventKey> deferred_key_event;
|
||||||
|
CursorShape cursor_shape = CURSOR_ARROW;
|
||||||
|
String cursors[CURSOR_MAX];
|
||||||
|
Map<CursorShape, Vector<Variant>> cursors_cache;
|
||||||
|
Point2 touches[32];
|
||||||
|
|
||||||
|
Point2i last_click_pos = Point2(-100, -100); // TODO check this again.
|
||||||
|
double last_click_ms = 0;
|
||||||
|
int last_click_button_index = -1;
|
||||||
|
|
||||||
|
static EM_BOOL fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data);
|
||||||
|
|
||||||
|
static EM_BOOL keydown_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
|
||||||
|
static EM_BOOL keypress_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
|
||||||
|
static EM_BOOL keyup_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
|
||||||
|
|
||||||
|
static EM_BOOL mousemove_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data);
|
||||||
|
static EM_BOOL mouse_button_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data);
|
||||||
|
|
||||||
|
static EM_BOOL wheel_callback(int p_event_type, const EmscriptenWheelEvent *p_event, void *p_user_data);
|
||||||
|
|
||||||
|
static EM_BOOL touch_press_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data);
|
||||||
|
static EM_BOOL touchmove_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data);
|
||||||
|
|
||||||
|
static EM_BOOL gamepad_change_callback(int p_event_type, const EmscriptenGamepadEvent *p_event, void *p_user_data);
|
||||||
|
void process_joypads();
|
||||||
|
|
||||||
|
static Vector<String> get_rendering_drivers_func();
|
||||||
|
static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
|
||||||
|
|
||||||
|
static void _dispatch_input_event(const Ref<InputEvent> &p_event);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int get_current_video_driver() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Override return type to make writing static callbacks less tedious.
|
||||||
|
static DisplayServerJavaScript *get_singleton();
|
||||||
|
|
||||||
|
WindowMode window_mode = WINDOW_MODE_WINDOWED;
|
||||||
|
|
||||||
|
String clipboard;
|
||||||
|
String canvas_id;
|
||||||
|
|
||||||
|
Callable window_event_callback;
|
||||||
|
Callable input_event_callback;
|
||||||
|
Callable input_text_callback;
|
||||||
|
|
||||||
|
// from DisplayServer
|
||||||
|
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
|
||||||
|
virtual bool has_feature(Feature p_feature) const;
|
||||||
|
virtual String get_name() const;
|
||||||
|
|
||||||
|
// cursor
|
||||||
|
virtual void cursor_set_shape(CursorShape p_shape);
|
||||||
|
virtual CursorShape cursor_get_shape() const;
|
||||||
|
virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
|
||||||
|
|
||||||
|
// mouse
|
||||||
|
virtual void mouse_set_mode(MouseMode p_mode);
|
||||||
|
virtual MouseMode mouse_get_mode() const;
|
||||||
|
|
||||||
|
// touch
|
||||||
|
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
|
||||||
|
|
||||||
|
// clipboard
|
||||||
|
virtual void clipboard_set(const String &p_text);
|
||||||
|
virtual String clipboard_get() const;
|
||||||
|
|
||||||
|
// screen
|
||||||
|
virtual int get_screen_count() const;
|
||||||
|
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
|
||||||
|
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
|
||||||
|
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
|
||||||
|
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
|
||||||
|
|
||||||
|
// windows
|
||||||
|
virtual Vector<DisplayServer::WindowID> get_window_list() const;
|
||||||
|
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
|
||||||
|
|
||||||
|
virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
|
||||||
|
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
|
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
|
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
|
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
|
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
|
virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
|
virtual void window_set_transient(WindowID p_window, WindowID p_parent);
|
||||||
|
|
||||||
|
virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
|
||||||
|
virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
|
||||||
|
virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const; // FIXME: Find clearer name for this.
|
||||||
|
|
||||||
|
virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
|
||||||
|
virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
|
||||||
|
virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
|
||||||
|
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
|
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
|
||||||
|
virtual bool can_any_window_draw() const;
|
||||||
|
|
||||||
|
// events
|
||||||
|
virtual void process_events();
|
||||||
|
|
||||||
|
// icon
|
||||||
|
virtual void set_icon(const Ref<Image> &p_icon);
|
||||||
|
|
||||||
|
// others
|
||||||
|
virtual void swap_buffers();
|
||||||
|
|
||||||
|
static void register_javascript_driver();
|
||||||
|
DisplayServerJavaScript(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
|
||||||
|
~DisplayServerJavaScript();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DISPLAY_SERVER_JAVASCRIPT_H
|
||||||
@@ -31,6 +31,7 @@ Function('return this')()['Engine'] = (function() {
|
|||||||
this.rtenv = null;
|
this.rtenv = null;
|
||||||
this.customLocale = null;
|
this.customLocale = null;
|
||||||
this.resizeCanvasOnStart = false;
|
this.resizeCanvasOnStart = false;
|
||||||
|
this.onExecute = null;
|
||||||
this.onExit = null;
|
this.onExit = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,6 +116,7 @@ Function('return this')()['Engine'] = (function() {
|
|||||||
me.rtenv['thisProgram'] = me.executableName;
|
me.rtenv['thisProgram'] = me.executableName;
|
||||||
me.rtenv['resizeCanvasOnStart'] = me.resizeCanvasOnStart;
|
me.rtenv['resizeCanvasOnStart'] = me.resizeCanvasOnStart;
|
||||||
me.rtenv['noExitRuntime'] = true;
|
me.rtenv['noExitRuntime'] = true;
|
||||||
|
me.rtenv['onExecute'] = me.onExecute;
|
||||||
me.rtenv['onExit'] = function(code) {
|
me.rtenv['onExit'] = function(code) {
|
||||||
if (me.onExit)
|
if (me.onExit)
|
||||||
me.onExit(code);
|
me.onExit(code);
|
||||||
@@ -201,6 +203,12 @@ Function('return this')()['Engine'] = (function() {
|
|||||||
stderr = printErr;
|
stderr = printErr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Engine.prototype.setOnExecute = function(onExecute) {
|
||||||
|
if (this.rtenv)
|
||||||
|
this.rtenv.onExecute = onExecute;
|
||||||
|
this.onExecute = onExecute;
|
||||||
|
}
|
||||||
|
|
||||||
Engine.prototype.setOnExit = function(onExit) {
|
Engine.prototype.setOnExit = function(onExit) {
|
||||||
this.onExit = onExit;
|
this.onExit = onExit;
|
||||||
}
|
}
|
||||||
@@ -230,6 +238,7 @@ Function('return this')()['Engine'] = (function() {
|
|||||||
Engine.prototype['setProgressFunc'] = Engine.prototype.setProgressFunc;
|
Engine.prototype['setProgressFunc'] = Engine.prototype.setProgressFunc;
|
||||||
Engine.prototype['setStdoutFunc'] = Engine.prototype.setStdoutFunc;
|
Engine.prototype['setStdoutFunc'] = Engine.prototype.setStdoutFunc;
|
||||||
Engine.prototype['setStderrFunc'] = Engine.prototype.setStderrFunc;
|
Engine.prototype['setStderrFunc'] = Engine.prototype.setStderrFunc;
|
||||||
|
Engine.prototype['setOnExecute'] = Engine.prototype.setOnExecute;
|
||||||
Engine.prototype['setOnExit'] = Engine.prototype.setOnExit;
|
Engine.prototype['setOnExit'] = Engine.prototype.setOnExit;
|
||||||
Engine.prototype['copyToFS'] = Engine.prototype.copyToFS;
|
Engine.prototype['copyToFS'] = Engine.prototype.copyToFS;
|
||||||
return Engine;
|
return Engine;
|
||||||
|
|||||||
@@ -34,22 +34,63 @@
|
|||||||
|
|
||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
|
|
||||||
|
static OS_JavaScript *os = nullptr;
|
||||||
|
|
||||||
|
void exit_callback() {
|
||||||
|
emscripten_cancel_main_loop(); // After this, we can exit!
|
||||||
|
Main::cleanup();
|
||||||
|
int exit_code = OS_JavaScript::get_singleton()->get_exit_code();
|
||||||
|
memdelete(os);
|
||||||
|
os = nullptr;
|
||||||
|
emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing.
|
||||||
|
}
|
||||||
|
|
||||||
|
void main_loop_callback() {
|
||||||
|
|
||||||
|
if (os->main_loop_iterate()) {
|
||||||
|
emscripten_cancel_main_loop(); // Cancel current loop and wait for finalize_async.
|
||||||
|
EM_ASM({
|
||||||
|
// This will contain the list of operations that need to complete before cleanup.
|
||||||
|
Module.async_finish = [];
|
||||||
|
});
|
||||||
|
os->get_main_loop()->finish();
|
||||||
|
os->finalize_async(); // Will add all the async finish functions.
|
||||||
|
EM_ASM({
|
||||||
|
Promise.all(Module.async_finish).then(function() {
|
||||||
|
Module.async_finish = [];
|
||||||
|
ccall("cleanup_after_sync", null, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" EMSCRIPTEN_KEEPALIVE void cleanup_after_sync() {
|
||||||
|
emscripten_set_main_loop(exit_callback, -1, false);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" EMSCRIPTEN_KEEPALIVE void main_after_fs_sync(char *p_idbfs_err) {
|
extern "C" EMSCRIPTEN_KEEPALIVE void main_after_fs_sync(char *p_idbfs_err) {
|
||||||
|
|
||||||
String idbfs_err = String::utf8(p_idbfs_err);
|
String idbfs_err = String::utf8(p_idbfs_err);
|
||||||
if (!idbfs_err.empty()) {
|
if (!idbfs_err.empty()) {
|
||||||
print_line("IndexedDB not available: " + idbfs_err);
|
print_line("IndexedDB not available: " + idbfs_err);
|
||||||
}
|
}
|
||||||
OS_JavaScript *os = OS_JavaScript::get_singleton();
|
|
||||||
os->set_idb_available(idbfs_err.empty());
|
os->set_idb_available(idbfs_err.empty());
|
||||||
|
// TODO: Check error return value.
|
||||||
|
Main::setup2(); // Manual second phase.
|
||||||
// Ease up compatibility.
|
// Ease up compatibility.
|
||||||
ResourceLoader::set_abort_on_missing_resources(false);
|
ResourceLoader::set_abort_on_missing_resources(false);
|
||||||
Main::start();
|
Main::start();
|
||||||
os->run_async();
|
os->get_main_loop()->init();
|
||||||
|
emscripten_resume_main_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
os = new OS_JavaScript();
|
||||||
|
Main::setup(argv[0], argc - 1, &argv[1], false);
|
||||||
|
emscripten_set_main_loop(main_loop_callback, -1, false);
|
||||||
|
emscripten_pause_main_loop(); // Will need to wait for FS sync.
|
||||||
|
|
||||||
// Sync from persistent state into memory and then
|
// Sync from persistent state into memory and then
|
||||||
// run the 'main_after_fs_sync' function.
|
// run the 'main_after_fs_sync' function.
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
@@ -62,10 +103,6 @@ int main(int argc, char *argv[]) {
|
|||||||
);
|
);
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
new OS_JavaScript(argc, argv);
|
|
||||||
// TODO: Check error return value.
|
|
||||||
Main::setup(argv[0], argc - 1, &argv[1]);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
// Continued async in main_after_fs_sync() from the syncfs() callback.
|
// Continued async in main_after_fs_sync() from the syncfs() callback.
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -35,64 +35,25 @@
|
|||||||
#include "core/input/input.h"
|
#include "core/input/input.h"
|
||||||
#include "drivers/unix/os_unix.h"
|
#include "drivers/unix/os_unix.h"
|
||||||
#include "servers/audio_server.h"
|
#include "servers/audio_server.h"
|
||||||
#include "servers/rendering/rasterizer.h"
|
|
||||||
|
|
||||||
#include <emscripten/html5.h>
|
#include <emscripten/html5.h>
|
||||||
|
|
||||||
class OS_JavaScript : public OS_Unix {
|
class OS_JavaScript : public OS_Unix {
|
||||||
|
|
||||||
VideoMode video_mode;
|
MainLoop *main_loop = nullptr;
|
||||||
Vector2 windowed_size;
|
|
||||||
bool window_maximized;
|
|
||||||
bool entering_fullscreen;
|
|
||||||
bool just_exited_fullscreen;
|
|
||||||
bool transparency_enabled;
|
|
||||||
|
|
||||||
InputDefault *input;
|
|
||||||
Ref<InputEventKey> deferred_key_event;
|
|
||||||
CursorShape cursor_shape;
|
|
||||||
String cursors[CURSOR_MAX];
|
|
||||||
Map<CursorShape, Vector<Variant>> cursors_cache;
|
|
||||||
Point2 touches[32];
|
|
||||||
|
|
||||||
Point2i last_click_pos;
|
|
||||||
double last_click_ms;
|
|
||||||
int last_click_button_index;
|
|
||||||
|
|
||||||
MainLoop *main_loop;
|
|
||||||
int video_driver_index;
|
|
||||||
AudioDriverJavaScript audio_driver_javascript;
|
AudioDriverJavaScript audio_driver_javascript;
|
||||||
|
|
||||||
bool idb_available;
|
bool finalizing = false;
|
||||||
int64_t sync_wait_time;
|
bool idb_available = false;
|
||||||
int64_t last_sync_check_time;
|
int64_t sync_wait_time = -1;
|
||||||
|
int64_t last_sync_check_time = -1;
|
||||||
static EM_BOOL fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data);
|
|
||||||
|
|
||||||
static EM_BOOL keydown_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
|
|
||||||
static EM_BOOL keypress_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
|
|
||||||
static EM_BOOL keyup_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
|
|
||||||
|
|
||||||
static EM_BOOL mousemove_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data);
|
|
||||||
static EM_BOOL mouse_button_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data);
|
|
||||||
|
|
||||||
static EM_BOOL wheel_callback(int p_event_type, const EmscriptenWheelEvent *p_event, void *p_user_data);
|
|
||||||
|
|
||||||
static EM_BOOL touch_press_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data);
|
|
||||||
static EM_BOOL touchmove_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data);
|
|
||||||
|
|
||||||
static EM_BOOL gamepad_change_callback(int p_event_type, const EmscriptenGamepadEvent *p_event, void *p_user_data);
|
|
||||||
void process_joypads();
|
|
||||||
|
|
||||||
static void main_loop_callback();
|
static void main_loop_callback();
|
||||||
|
|
||||||
static void file_access_close_callback(const String &p_file, int p_flags);
|
static void file_access_close_callback(const String &p_file, int p_flags);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int get_current_video_driver() const;
|
virtual void initialize();
|
||||||
|
|
||||||
virtual void initialize_core();
|
|
||||||
virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
|
|
||||||
|
|
||||||
virtual void set_main_loop(MainLoop *p_main_loop);
|
virtual void set_main_loop(MainLoop *p_main_loop);
|
||||||
virtual void delete_main_loop();
|
virtual void delete_main_loop();
|
||||||
@@ -105,65 +66,38 @@ public:
|
|||||||
// Override return type to make writing static callbacks less tedious.
|
// Override return type to make writing static callbacks less tedious.
|
||||||
static OS_JavaScript *get_singleton();
|
static OS_JavaScript *get_singleton();
|
||||||
|
|
||||||
virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0);
|
virtual void initialize_joypads();
|
||||||
virtual VideoMode get_video_mode(int p_screen = 0) const;
|
|
||||||
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
|
|
||||||
|
|
||||||
virtual void set_window_size(const Size2);
|
|
||||||
virtual Size2 get_window_size() const;
|
|
||||||
virtual void set_window_maximized(bool p_enabled);
|
|
||||||
virtual bool is_window_maximized() const;
|
|
||||||
virtual void set_window_fullscreen(bool p_enabled);
|
|
||||||
virtual bool is_window_fullscreen() const;
|
|
||||||
virtual Size2 get_screen_size(int p_screen = -1) const;
|
|
||||||
|
|
||||||
virtual Point2 get_mouse_position() const;
|
|
||||||
virtual int get_mouse_button_state() const;
|
|
||||||
virtual void set_cursor_shape(CursorShape p_shape);
|
|
||||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
|
||||||
virtual void set_mouse_mode(MouseMode p_mode);
|
|
||||||
virtual MouseMode get_mouse_mode() const;
|
|
||||||
|
|
||||||
virtual bool get_window_per_pixel_transparency_enabled() const;
|
|
||||||
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
|
|
||||||
|
|
||||||
virtual bool has_touchscreen_ui_hint() const;
|
virtual bool has_touchscreen_ui_hint() const;
|
||||||
|
|
||||||
virtual bool is_joy_known(int p_device);
|
|
||||||
virtual String get_joy_guid(int p_device) const;
|
|
||||||
|
|
||||||
virtual int get_video_driver_count() const;
|
|
||||||
virtual const char *get_video_driver_name(int p_driver) const;
|
|
||||||
|
|
||||||
virtual int get_audio_driver_count() const;
|
virtual int get_audio_driver_count() const;
|
||||||
virtual const char *get_audio_driver_name(int p_driver) const;
|
virtual const char *get_audio_driver_name(int p_driver) const;
|
||||||
|
|
||||||
virtual void set_clipboard(const String &p_text);
|
|
||||||
virtual String get_clipboard() const;
|
|
||||||
|
|
||||||
virtual MainLoop *get_main_loop() const;
|
virtual MainLoop *get_main_loop() const;
|
||||||
void run_async();
|
void finalize_async();
|
||||||
bool main_loop_iterate();
|
bool main_loop_iterate();
|
||||||
|
|
||||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
|
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
|
||||||
virtual Error kill(const ProcessID &p_pid);
|
virtual Error kill(const ProcessID &p_pid);
|
||||||
virtual int get_process_id() const;
|
virtual int get_process_id() const;
|
||||||
|
|
||||||
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
|
|
||||||
virtual void set_window_title(const String &p_title);
|
|
||||||
virtual void set_icon(const Ref<Image> &p_icon);
|
|
||||||
String get_executable_path() const;
|
String get_executable_path() const;
|
||||||
virtual Error shell_open(String p_uri);
|
virtual Error shell_open(String p_uri);
|
||||||
virtual String get_name() const;
|
virtual String get_name() const;
|
||||||
virtual bool can_draw() const;
|
virtual bool can_draw() const;
|
||||||
|
|
||||||
virtual String get_resource_dir() const;
|
virtual String get_cache_path() const;
|
||||||
|
virtual String get_config_path() const;
|
||||||
|
virtual String get_data_path() const;
|
||||||
virtual String get_user_data_dir() const;
|
virtual String get_user_data_dir() const;
|
||||||
|
|
||||||
void set_idb_available(bool p_idb_available);
|
void set_idb_available(bool p_idb_available);
|
||||||
virtual bool is_userfs_persistent() const;
|
virtual bool is_userfs_persistent() const;
|
||||||
|
|
||||||
OS_JavaScript(int p_argc, char *p_argv[]);
|
void resume_audio();
|
||||||
|
bool is_finalizing() { return finalizing; }
|
||||||
|
|
||||||
|
OS_JavaScript();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user