diff options
Diffstat (limited to 'platform/javascript')
-rw-r--r-- | platform/javascript/SCsub | 6 | ||||
-rw-r--r-- | platform/javascript/audio_driver_javascript.cpp | 149 | ||||
-rw-r--r-- | platform/javascript/audio_driver_javascript.h | 11 | ||||
-rw-r--r-- | platform/javascript/detect.py | 17 | ||||
-rw-r--r-- | platform/javascript/engine.js | 21 | ||||
-rw-r--r-- | platform/javascript/export/export.cpp | 2 | ||||
-rw-r--r-- | platform/javascript/javascript_main.cpp | 2 | ||||
-rw-r--r-- | platform/javascript/os_javascript.cpp | 47 |
8 files changed, 121 insertions, 134 deletions
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub index 5991075e29..98988d97fd 100644 --- a/platform/javascript/SCsub +++ b/platform/javascript/SCsub @@ -30,8 +30,8 @@ zip_files = env.InstallAs([ zip_dir.File('godot.wasm'), zip_dir.File('godot.html') ], [ - js_wrapped, - wasm, - '#misc/dist/html/default.html' + js_wrapped, + wasm, + '#misc/dist/html/default.html' ]) env.Zip('#bin/godot', zip_files, ZIPROOT=zip_dir, ZIPSUFFIX='${PROGSUFFIX}${ZIPSUFFIX}', ZIPCOMSTR='Archving $SOURCES as $TARGET') diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index 5bf345e6cd..7a6613bb32 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -32,113 +32,134 @@ #include <emscripten.h> -AudioDriverJavaScript *AudioDriverJavaScript::singleton_js = NULL; +AudioDriverJavaScript *AudioDriverJavaScript::singleton = NULL; const char *AudioDriverJavaScript::get_name() const { return "JavaScript"; } -extern "C" EMSCRIPTEN_KEEPALIVE void js_audio_driver_mix_function(int p_frames) { +extern "C" EMSCRIPTEN_KEEPALIVE void audio_driver_js_mix() { - //print_line("MIXI! "+itos(p_frames)); - AudioDriverJavaScript::singleton_js->mix_to_js(p_frames); + AudioDriverJavaScript::singleton->mix_to_js(); } -void AudioDriverJavaScript::mix_to_js(int p_frames) { +void AudioDriverJavaScript::mix_to_js() { - int todo = p_frames; - int offset = 0; + int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode()); + int sample_count = memarr_len(internal_buffer) / channel_count; + int32_t *stream_buffer = reinterpret_cast<int32_t *>(internal_buffer); + audio_server_process(sample_count, stream_buffer); + for (int i = 0; i < sample_count * channel_count; i++) { + internal_buffer[i] = float(stream_buffer[i] >> 16) / 32768.0; + } +} - while (todo) { +Error AudioDriverJavaScript::init() { - int tomix = MIN(todo, INTERNAL_BUFFER_SIZE); + /* clang-format off */ + EM_ASM({ + _audioDriver_audioContext = new (window.AudioContext || window.webkitAudioContext); + _audioDriver_scriptNode = null; + }); + /* clang-format on */ - audio_server_process(p_frames, stream_buffer); - for (int i = 0; i < tomix * internal_buffer_channels; i++) { - internal_buffer[i] = float(stream_buffer[i] >> 16) / 32768.0; + int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode()); + /* clang-format off */ + int buffer_length = EM_ASM_INT({ + var CHANNEL_COUNT = $0; + + var channelCount = _audioDriver_audioContext.destination.channelCount; + try { + // Try letting the browser recommend a buffer length. + _audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(0, 0, channelCount); + } catch (e) { + // ...otherwise, default to 4096. + _audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(4096, 0, channelCount); } + _audioDriver_scriptNode.connect(_audioDriver_audioContext.destination); - /* clang-format off */ - EM_ASM_ARGS({ - var data = HEAPF32.subarray($0 / 4, $0 / 4 + $2 * 2); - - for (var channel = 0; channel < _as_output_buffer.numberOfChannels; channel++) { - var outputData = _as_output_buffer.getChannelData(channel); - // Loop through samples - for (var sample = 0; sample < $2; sample++) { - // make output equal to the same as the input - outputData[sample + $1] = data[sample * 2 + channel]; - } - } - }, internal_buffer, offset, tomix); - /* clang-format on */ - - todo -= tomix; - offset += tomix; + return _audioDriver_scriptNode.bufferSize; + }, channel_count); + /* clang-format on */ + if (!buffer_length) { + return FAILED; } -} - -Error AudioDriverJavaScript::init() { - return OK; + if (!internal_buffer || memarr_len(internal_buffer) != buffer_length * channel_count) { + if (internal_buffer) + memdelete_arr(internal_buffer); + internal_buffer = memnew_arr(float, buffer_length *channel_count); + } + return internal_buffer ? OK : ERR_OUT_OF_MEMORY; } void AudioDriverJavaScript::start() { - internal_buffer = memnew_arr(float, INTERNAL_BUFFER_SIZE *internal_buffer_channels); - stream_buffer = memnew_arr(int32_t, INTERNAL_BUFFER_SIZE * 4); //max 4 channels - /* clang-format off */ - mix_rate = EM_ASM_INT({ - _as_audioctx = new (window.AudioContext || window.webkitAudioContext); - _as_script_node = _as_audioctx.createScriptProcessor($0, 0, $1); - _as_script_node.connect(_as_audioctx.destination); - console.log(_as_script_node.bufferSize); - var jsAudioDriverMixFunction = cwrap('js_audio_driver_mix_function', null, ['number']); - - _as_script_node.onaudioprocess = function(audioProcessingEvent) { - // The output buffer contains the samples that will be modified and played - _as_output_buffer = audioProcessingEvent.outputBuffer; - jsAudioDriverMixFunction([_as_output_buffer.getChannelData(0).length]); + EM_ASM({ + var INTERNAL_BUFFER_PTR = $0; + + var audioDriverMixFunction = cwrap('audio_driver_js_mix'); + _audioDriver_scriptNode.onaudioprocess = function(audioProcessingEvent) { + audioDriverMixFunction(); + // The output buffer contains the samples that will be modified and played. + var output = audioProcessingEvent.outputBuffer; + var input = HEAPF32.subarray( + INTERNAL_BUFFER_PTR / HEAPF32.BYTES_PER_ELEMENT, + INTERNAL_BUFFER_PTR / HEAPF32.BYTES_PER_ELEMENT + output.length * output.numberOfChannels); + + for (var channel = 0; channel < output.numberOfChannels; channel++) { + var outputData = output.getChannelData(channel); + // Loop through samples. + for (var sample = 0; sample < outputData.length; sample++) { + // Set output equal to input. + outputData[sample] = input[sample * output.numberOfChannels + channel]; + } + } }; - return _as_audioctx.sampleRate; - }, INTERNAL_BUFFER_SIZE, internal_buffer_channels); + }, internal_buffer); /* clang-format on */ } int AudioDriverJavaScript::get_mix_rate() const { - return mix_rate; + /* clang-format off */ + return EM_ASM_INT_V({ + return _audioDriver_audioContext.sampleRate; + }); + /* clang-format on */ } AudioDriver::SpeakerMode AudioDriverJavaScript::get_speaker_mode() const { - return SPEAKER_MODE_STEREO; + /* clang-format off */ + return get_speaker_mode_by_total_channels(EM_ASM_INT_V({ + return _audioDriver_audioContext.destination.channelCount; + })); + /* clang-format on */ } +// No locking, as threads are not supported. void AudioDriverJavaScript::lock() { - - /*no locking, as threads are not supported - if (active && mutex) - mutex->lock(); - */ } void AudioDriverJavaScript::unlock() { - - /*no locking, as threads are not supported - if (active && mutex) - mutex->unlock(); - */ } void AudioDriverJavaScript::finish() { + + /* clang-format off */ + EM_ASM({ + _audioDriver_audioContext = null; + _audioDriver_scriptNode = null; + }); + /* clang-format on */ + memdelete_arr(internal_buffer); + internal_buffer = NULL; } AudioDriverJavaScript::AudioDriverJavaScript() { - internal_buffer_channels = 2; - mix_rate = DEFAULT_MIX_RATE; - singleton_js = this; + singleton = this; } diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h index d78ab8eea4..a65a8ec29f 100644 --- a/platform/javascript/audio_driver_javascript.h +++ b/platform/javascript/audio_driver_javascript.h @@ -35,18 +35,11 @@ class AudioDriverJavaScript : public AudioDriver { - enum { - INTERNAL_BUFFER_SIZE = 4096, - }; - - int mix_rate; float *internal_buffer; - int internal_buffer_channels; - int32_t *stream_buffer; public: - void mix_to_js(int p_frames); - static AudioDriverJavaScript *singleton_js; + void mix_to_js(); + static AudioDriverJavaScript *singleton; virtual const char *get_name() const; diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index a48cb872ee..fc909f6619 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -1,5 +1,4 @@ import os -import string import sys @@ -39,7 +38,7 @@ def configure(env): ## Build type - if env['target'] == 'release' or env['target'] == 'profile': + if env['target'] != 'debug': # Use -Os to prioritize optimizing for reduced file size. This is # particularly valuable for the web platform because it directly # decreases download time. @@ -48,17 +47,11 @@ def configure(env): # run-time performance. env.Append(CCFLAGS=['-Os']) env.Append(LINKFLAGS=['-Os']) - if env['target'] == 'profile': + if env['target'] == 'release_debug': + env.Append(CPPDEFINES=['DEBUG_ENABLED']) + # Retain function names for backtraces at the cost of file size. env.Append(LINKFLAGS=['--profiling-funcs']) - - elif env['target'] == 'release_debug': - env.Append(CPPDEFINES=['DEBUG_ENABLED']) - env.Append(CCFLAGS=['-O2']) - env.Append(LINKFLAGS=['-O2']) - # Retain function names for backtraces at the cost of file size. - env.Append(LINKFLAGS=['--profiling-funcs']) - - elif env['target'] == 'debug': + else: env.Append(CPPDEFINES=['DEBUG_ENABLED']) env.Append(CCFLAGS=['-O1', '-g']) env.Append(LINKFLAGS=['-O1', '-g']) diff --git a/platform/javascript/engine.js b/platform/javascript/engine.js index e4839af433..c3ef5bbbb5 100644 --- a/platform/javascript/engine.js +++ b/platform/javascript/engine.js @@ -10,6 +10,7 @@ var DOWNLOAD_ATTEMPTS_MAX = 4; var basePath = null; + var wasmFilenameExtensionOverride = null; var engineLoadPromise = null; var loadingFiles = {}; @@ -129,13 +130,17 @@ this.startGame = function(mainPack) { executableName = getBaseName(mainPack); + var mainArgs = []; + if (!getPathLeaf(mainPack).endsWith('.pck')) { + mainArgs = ['--main-pack', getPathLeaf(mainPack)]; + } return Promise.all([ // Load from directory, this.init(getBasePath(mainPack)), // ...but write to root where the engine expects it. this.preloadFile(mainPack, getPathLeaf(mainPack)) ]).then( - Function.prototype.apply.bind(synchronousStart, this, []) + Function.prototype.apply.bind(synchronousStart, this, mainArgs) ); }; @@ -161,6 +166,10 @@ actualCanvas.style.padding = 0; actualCanvas.style.borderWidth = 0; actualCanvas.style.borderStyle = 'none'; + // disable right-click context menu + actualCanvas.addEventListener('contextmenu', function(ev) { + ev.preventDefault(); + }, false); // until context restoration is implemented actualCanvas.addEventListener('webglcontextlost', function(ev) { alert("WebGL context lost, please reload the page"); @@ -299,6 +308,14 @@ return !!testContext; }; + Engine.setWebAssemblyFilenameExtension = function(override) { + + if (String(override).length === 0) { + throw new Error('Invalid WebAssembly filename extension override'); + } + wasmFilenameExtensionOverride = String(override); + } + Engine.load = function(newBasePath) { if (newBasePath !== undefined) basePath = getBasePath(newBasePath); @@ -306,7 +323,7 @@ if (typeof WebAssembly !== 'object') return Promise.reject(new Error("Browser doesn't support WebAssembly")); // TODO cache/retrieve module to/from idb - engineLoadPromise = loadPromise(basePath + '.wasm').then(function(xhr) { + engineLoadPromise = loadPromise(basePath + '.' + (wasmFilenameExtensionOverride || 'wasm')).then(function(xhr) { return xhr.response; }); engineLoadPromise = engineLoadPromise.catch(function(err) { diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index d81aa25c32..9591850662 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -117,7 +117,7 @@ void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_op r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_GLOBAL_FILE, "html"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "html"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp index 54d4755bd7..68a2d72464 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/javascript/javascript_main.cpp @@ -56,8 +56,6 @@ extern "C" EMSCRIPTEN_KEEPALIVE void main_after_fs_sync(char *p_idbfs_err) { int main(int argc, char *argv[]) { - printf("let it go dude!\n"); - // sync from persistent state into memory and then // run the 'main_after_fs_sync' function /* clang-format off */ diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index a275fb7929..6c6e4d2d1c 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -167,10 +167,9 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent int mask = _input->get_mouse_button_mask(); int button_flag = 1 << (ev->get_button_index() - 1); if (ev->is_pressed()) { - // since the event is consumed, focus manually - if (!is_canvas_focused()) { - focus_canvas(); - } + // Since the event is consumed, focus manually. The containing iframe, + // if used, may not have focus yet, so focus even if already focused. + focus_canvas(); mask |= button_flag; } else if (mask & button_flag) { mask &= ~button_flag; @@ -181,7 +180,8 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent ev->set_button_mask(mask); _input->parse_input_event(ev); - // prevent selection dragging + // Prevent multi-click text selection and wheel-click scrolling anchor. + // Context menu is prevented through contextmenu event. return true; } @@ -204,7 +204,7 @@ static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *m ev->set_position(pos); ev->set_global_position(ev->get_position()); - ev->set_relative(ev->get_position() - _input->get_mouse_position()); + ev->set_relative(Vector2(mouse_event->movementX, mouse_event->movementY)); _input->set_mouse_position(ev->get_position()); ev->set_speed(_input->get_last_mouse_speed()); @@ -285,23 +285,6 @@ static EM_BOOL _touchpress_callback(int event_type, const EmscriptenTouchEvent * _input->parse_input_event(ev); } - - if (touch_event->touches[lowest_id_index].isChanged) { - - Ref<InputEventMouseButton> ev_mouse; - ev_mouse.instance(); - ev_mouse->set_button_mask(_input->get_mouse_button_mask()); - dom2godot_mod(touch_event, ev_mouse); - - const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index]; - ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY)); - ev_mouse->set_global_position(ev_mouse->get_position()); - - ev_mouse->set_button_index(BUTTON_LEFT); - ev_mouse->set_pressed(event_type == EMSCRIPTEN_EVENT_TOUCHSTART); - - _input->parse_input_event(ev_mouse); - } return true; } @@ -327,24 +310,6 @@ static EM_BOOL _touchmove_callback(int event_type, const EmscriptenTouchEvent *t _input->parse_input_event(ev); } - - if (touch_event->touches[lowest_id_index].isChanged) { - - Ref<InputEventMouseMotion> ev_mouse; - ev_mouse.instance(); - dom2godot_mod(touch_event, ev_mouse); - ev_mouse->set_button_mask(_input->get_mouse_button_mask()); - - const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index]; - ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY)); - ev_mouse->set_global_position(ev_mouse->get_position()); - - ev_mouse->set_relative(ev_mouse->get_position() - _input->get_mouse_position()); - _input->set_mouse_position(ev_mouse->get_position()); - ev_mouse->set_speed(_input->get_last_mouse_speed()); - - _input->parse_input_event(ev_mouse); - } return true; } |