diff options
Diffstat (limited to 'platform/javascript')
| -rw-r--r-- | platform/javascript/SCsub | 41 | ||||
| -rw-r--r-- | platform/javascript/audio_driver_javascript.cpp | 33 | ||||
| -rw-r--r-- | platform/javascript/audio_driver_javascript.h | 8 | ||||
| -rw-r--r-- | platform/javascript/audio_server_javascript.cpp | 204 | ||||
| -rw-r--r-- | platform/javascript/audio_server_javascript.h | 9 | ||||
| -rw-r--r-- | platform/javascript/detect.py | 143 | ||||
| -rw-r--r-- | platform/javascript/dom_keys.h | 2 | ||||
| -rw-r--r-- | platform/javascript/export/export.cpp | 29 | ||||
| -rw-r--r-- | platform/javascript/export/export.h | 2 | ||||
| -rw-r--r-- | platform/javascript/godot_shell.html | 375 | ||||
| -rw-r--r-- | platform/javascript/javascript_eval.cpp | 9 | ||||
| -rw-r--r-- | platform/javascript/javascript_eval.h | 4 | ||||
| -rw-r--r-- | platform/javascript/javascript_main.cpp | 59 | ||||
| -rw-r--r-- | platform/javascript/os_javascript.cpp | 364 | ||||
| -rw-r--r-- | platform/javascript/os_javascript.h | 43 | ||||
| -rw-r--r-- | platform/javascript/platform_config.h | 2 |
16 files changed, 774 insertions, 553 deletions
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub index 59e5aa175..a20c0f7a7 100644 --- a/platform/javascript/SCsub +++ b/platform/javascript/SCsub @@ -3,35 +3,36 @@ Import('env') javascript_files = [ - "os_javascript.cpp", - "audio_driver_javascript.cpp", - "javascript_main.cpp", - "audio_server_javascript.cpp", - "javascript_eval.cpp" + "os_javascript.cpp", + "audio_driver_javascript.cpp", + "javascript_main.cpp", + "audio_server_javascript.cpp", + "javascript_eval.cpp" ] env_javascript = env.Clone() if env['target'] == "profile": - env_javascript.Append(CPPFLAGS=['-DPROFILER_ENABLED']) + env_javascript.Append(CPPFLAGS=['-DPROFILER_ENABLED']) -javascript_objects=[] +javascript_objects = [] for x in javascript_files: - javascript_objects.append( env_javascript.Object( x ) ) + javascript_objects.append(env_javascript.Object(x)) -env.Append(LINKFLAGS=["-s","EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync']\""]) -env.Append(LINKFLAGS=["--shell-file",'"platform/javascript/godot_shell.html"']) +env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync']\""]) +env.Append(LINKFLAGS=["--shell-file", '"platform/javascript/godot_shell.html"']) -build = env.Program('#bin/godot',javascript_objects,PROGSUFFIX=env["PROGSUFFIX"]+".html") +build = env.Program('#bin/godot', javascript_objects, PROGSUFFIX=env["PROGSUFFIX"] + ".html") +Depends(build, "godot_shell.html") def make_html_shell(target, source, env): - html_path = target[0].rstr() - assert html_path[:4] == 'bin/' - assert html_path[-5:] == '.html' - basename = html_path[4:-5] - with open(html_path, 'r+') as html_file: - fixed_html = html_file.read().replace('.html.mem', '.mem').replace(basename, '$GODOT_BASE') - html_file.seek(0) - html_file.truncate() - html_file.write(fixed_html) + html_path = target[0].rstr() + assert html_path[:4] == 'bin/' + assert html_path[-5:] == '.html' + basename = html_path[4:-5] + with open(html_path, 'r+') as html_file: + fixed_html = html_file.read().replace('.html.mem', '.mem').replace(basename, '$GODOT_BASE') + html_file.seek(0) + html_file.truncate() + html_file.write(fixed_html) env.AddPostAction(build, Action(make_html_shell, "Creating HTML shell file")) diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index 1b949e64f..bff01d7c3 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -27,20 +27,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "audio_driver_javascript.h" -#include <string.h> - - - - +#include <string.h> #define MAX_NUMBER_INTERFACES 3 #define MAX_NUMBER_OUTPUT_DEVICES 6 /* Structure for passing information to callback function */ - - //AudioDriverJavaScript* AudioDriverJavaScript::s_ad=NULL; const char* AudioDriverJavaScript::get_name() const { @@ -53,36 +47,45 @@ Error AudioDriverJavaScript::init(){ return OK; } + void AudioDriverJavaScript::start(){ } + int AudioDriverJavaScript::get_mix_rate() const { return 44100; } -AudioDriverSW::OutputFormat AudioDriverJavaScript::get_output_format() const{ - return OUTPUT_STEREO; +AudioDriver::SpeakerMode AudioDriverJavaScript::get_speaker_mode() const{ + + return SPEAKER_MODE_STEREO; } + void AudioDriverJavaScript::lock(){ - //if (active && mutex) - // mutex->lock(); + /* + if (active && mutex) + mutex->lock(); + */ } + void AudioDriverJavaScript::unlock() { - //if (active && mutex) - // mutex->unlock(); + /* + if (active && mutex) + mutex->unlock(); + */ } + void AudioDriverJavaScript::finish(){ } - AudioDriverJavaScript::AudioDriverJavaScript() { } diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h index c674a8566..da146fcdd 100644 --- a/platform/javascript/audio_driver_javascript.h +++ b/platform/javascript/audio_driver_javascript.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,11 +29,11 @@ #ifndef AUDIO_DRIVER_JAVASCRIPT_H #define AUDIO_DRIVER_JAVASCRIPT_H +#include "servers/audio_server.h" -#include "servers/audio/audio_server_sw.h" #include "os/mutex.h" -class AudioDriverJavaScript : public AudioDriverSW { +class AudioDriverJavaScript : public AudioDriver { public: void set_singleton(); @@ -43,7 +43,7 @@ public: virtual Error init(); virtual void start(); virtual int get_mix_rate() const ; - virtual OutputFormat get_output_format() const; + virtual SpeakerMode get_speaker_mode() const; virtual void lock(); virtual void unlock(); virtual void finish(); diff --git a/platform/javascript/audio_server_javascript.cpp b/platform/javascript/audio_server_javascript.cpp index 71a7e7726..d5940fb10 100644 --- a/platform/javascript/audio_server_javascript.cpp +++ b/platform/javascript/audio_server_javascript.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -87,7 +87,7 @@ const void* AudioServerJavascript::sample_get_data_ptr(RID p_sample) const{ return NULL; } -void AudioServerJavascript::sample_set_data(RID p_sample, const DVector<uint8_t>& p_buffer){ +void AudioServerJavascript::sample_set_data(RID p_sample, const PoolVector<uint8_t>& p_buffer){ Sample *sample = sample_owner.get(p_sample); ERR_FAIL_COND(!sample); @@ -95,7 +95,7 @@ void AudioServerJavascript::sample_set_data(RID p_sample, const DVector<uint8_t> Vector<float> buffer; buffer.resize(sample->length*chans); - DVector<uint8_t>::Read r=p_buffer.read(); + PoolVector<uint8_t>::Read r=p_buffer.read(); if (sample->format==SAMPLE_FORMAT_PCM8) { const int8_t*ptr = (const int8_t*)r.ptr(); for(int i=0;i<sample->length*chans;i++) { @@ -116,10 +116,10 @@ void AudioServerJavascript::sample_set_data(RID p_sample, const DVector<uint8_t> } -DVector<uint8_t> AudioServerJavascript::sample_get_data(RID p_sample) const{ +PoolVector<uint8_t> AudioServerJavascript::sample_get_data(RID p_sample) const{ - return DVector<uint8_t>(); + return PoolVector<uint8_t>(); } void AudioServerJavascript::sample_set_mix_rate(RID p_sample,int p_rate){ @@ -198,14 +198,15 @@ RID AudioServerJavascript::voice_create(){ voice->positional=false; voice->active=false; + /* clang-format off */ EM_ASM_( { - _as_voices[$0]=null; - _as_voice_gain[$0]=_as_audioctx.createGain(); - _as_voice_pan[$0]=_as_audioctx.createStereoPanner(); - _as_voice_gain[$0].connect(_as_voice_pan[$0]); - _as_voice_pan[$0].connect(_as_audioctx.destination); - - },voice_base); + _as_voices[$0] = null; + _as_voice_gain[$0] = _as_audioctx.createGain(); + _as_voice_pan[$0] = _as_audioctx.createStereoPanner(); + _as_voice_gain[$0].connect(_as_voice_pan[$0]); + _as_voice_pan[$0].connect(_as_audioctx.destination); + }, voice_base); + /* clang-format on */ voice_base++; @@ -227,27 +228,29 @@ void AudioServerJavascript::voice_play(RID p_voice, RID p_sample){ //create sample if not created ERR_FAIL_COND(sample->tmp_data.size()==0); sample->index=sample_base; - EM_ASM_( { - _as_samples[$0]=_as_audioctx.createBuffer($1,$2,$3); - },sample_base,sample->stereo?2:1,sample->length,sample->mix_rate); + /* clang-format off */ + EM_ASM_({ + _as_samples[$0] = _as_audioctx.createBuffer($1, $2, $3); + }, sample_base, sample->stereo ? 2 : 1, sample->length, sample->mix_rate); + /* clang-format on */ sample_base++; int chans = sample->stereo?2:1; for(int i=0;i<chans;i++) { - - + /* clang-format off */ EM_ASM_({ - _as_edited_buffer=_as_samples[$0].getChannelData($1); - },sample->index,i); - + _as_edited_buffer = _as_samples[$0].getChannelData($1); + }, sample->index, i); + /* clang-format on */ for(int j=0;j<sample->length;j++) { - + /* clang-format off */ EM_ASM_({ - _as_edited_buffer[$0]=$1; - },j,sample->tmp_data[j*chans+i]); + _as_edited_buffer[$0] = $1; + }, j, sample->tmp_data[j * chans + i]); + /* clang-format on */ } } @@ -263,26 +266,27 @@ void AudioServerJavascript::voice_play(RID p_voice, RID p_sample){ float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0); int detune = int(freq_diff*1200.0); - EM_ASM_( { - if (_as_voices[$0]!==null) { - _as_voices[$0].stop(); //stop and byebye - } - _as_voices[$0]=_as_audioctx.createBufferSource(); - _as_voices[$0].connect(_as_voice_gain[$0]); - _as_voices[$0].buffer=_as_samples[$1]; - _as_voices[$0].loopStart.value=$1; - _as_voices[$0].loopEnd.value=$2; - _as_voices[$0].loop.value=$3; - _as_voices[$0].detune.value=$6; - _as_voice_pan[$0].pan.value=$4; - _as_voice_gain[$0].gain.value=$5; - _as_voices[$0].start(); - _as_voices[$0].onended=function() { - _as_voices[$0].disconnect(_as_voice_gain[$0]); - _as_voices[$0]=null; - } - - },voice->index,sample->index,sample->mix_rate*sample->loop_begin,sample->mix_rate*sample->loop_end,sample->loop_format!=SAMPLE_LOOP_NONE,voice->pan,voice->volume*fx_volume_scale,detune); + /* clang-format off */ + EM_ASM_({ + if (_as_voices[$0] !== null) { + _as_voices[$0].stop(); //stop and byebye + } + _as_voices[$0] = _as_audioctx.createBufferSource(); + _as_voices[$0].connect(_as_voice_gain[$0]); + _as_voices[$0].buffer = _as_samples[$1]; + _as_voices[$0].loopStart.value = $1; + _as_voices[$0].loopEnd.value = $2; + _as_voices[$0].loop.value = $3; + _as_voices[$0].detune.value = $6; + _as_voice_pan[$0].pan.value = $4; + _as_voice_gain[$0].gain.value = $5; + _as_voices[$0].start(); + _as_voices[$0].onended = function() { + _as_voices[$0].disconnect(_as_voice_gain[$0]); + _as_voices[$0] = null; + } + }, voice->index, sample->index, sample->mix_rate * sample->loop_begin, sample->mix_rate * sample->loop_end, sample->loop_format != SAMPLE_LOOP_NONE, voice->pan, voice->volume * fx_volume_scale, detune); + /* clang-format on */ voice->active=true; } @@ -295,11 +299,11 @@ void AudioServerJavascript::voice_set_volume(RID p_voice, float p_volume){ voice->volume=p_volume; if (voice->active) { - EM_ASM_( { - - _as_voice_gain[$0].gain.value=$1; - - },voice->index,voice->volume*fx_volume_scale); + /* clang-format off */ + EM_ASM_({ + _as_voice_gain[$0].gain.value = $1; + }, voice->index, voice->volume * fx_volume_scale); + /* clang-format on */ } } @@ -313,11 +317,11 @@ void AudioServerJavascript::voice_set_pan(RID p_voice, float p_pan, float p_dept voice->pan_height=height; if (voice->active) { - EM_ASM_( { - - _as_voice_pan[$0].pan.value=$1; - - },voice->index,voice->pan); + /* clang-format off */ + EM_ASM_({ + _as_voice_pan[$0].pan.value = $1; + }, voice->index, voice->pan); + /* clang-format on */ } } void AudioServerJavascript::voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain){ @@ -340,11 +344,11 @@ void AudioServerJavascript::voice_set_mix_rate(RID p_voice, int p_mix_rate){ float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0); int detune = int(freq_diff*1200.0); - EM_ASM_( { - - _as_voices[$0].detune.value=$1; - - },voice->index,detune); + /* clang-format off */ + EM_ASM_({ + _as_voices[$0].detune.value = $1; + }, voice->index, detune); + /* clang-format on */ } } void AudioServerJavascript::voice_set_positional(RID p_voice, bool p_positional){ @@ -419,14 +423,15 @@ void AudioServerJavascript::voice_stop(RID p_voice){ ERR_FAIL_COND(!voice); if (voice->active) { - - EM_ASM_( { - if (_as_voices[$0]!==null) { - _as_voices[$0].stop(); - _as_voices[$0].disconnect(_as_voice_gain[$0]); - _as_voices[$0]=null; - } - },voice->index); + /* clang-format off */ + EM_ASM_({ + if (_as_voices[$0] !== null) { + _as_voices[$0].stop(); + _as_voices[$0].disconnect(_as_voice_gain[$0]); + _as_voices[$0] = null; + } + }, voice->index); + /* clang-format on */ voice->active=false; } @@ -524,22 +529,25 @@ void AudioServerJavascript::free(RID p_id){ ERR_FAIL_COND(!voice); if (voice->active) { - EM_ASM_( { - if (_as_voices[$0]!==null) { + /* clang-format off */ + EM_ASM_({ + if (_as_voices[$0] !== null) { _as_voices[$0].stop(); - _as_voices[$0].disconnect(_as_voice_gain[$0]); + _as_voices[$0].disconnect(_as_voice_gain[$0]); } - },voice->index); + }, voice->index); + /* clang-format on */ } - EM_ASM_( { + /* clang-format off */ + EM_ASM_({ delete _as_voices[$0]; _as_voice_gain[$0].disconnect(_as_voice_pan[$0]); delete _as_voice_gain[$0]; _as_voice_pan[$0].disconnect(_as_audioctx.destination); delete _as_voice_pan[$0]; - - },voice->index); + }, voice->index); + /* clang-format on */ voice_owner.free(p_id); memdelete(voice); @@ -549,10 +557,11 @@ void AudioServerJavascript::free(RID p_id){ Sample *sample = sample_owner.get(p_id); ERR_FAIL_COND(!sample); - EM_ASM_( { + /* clang-format off */ + EM_ASM_({ delete _as_samples[$0]; - - },sample->index); + }, sample->index); + /* clang-format on */ sample_owner.free(p_id); memdelete(sample); @@ -594,21 +603,20 @@ void AudioServerJavascript::mix_to_js(int p_frames) { int tomix=MIN(todo,INTERNAL_BUFFER_SIZE); driver_process_chunk(tomix); - + /* clang-format off */ EM_ASM_({ - - var data = HEAPF32.subarray($0/4, $0/4 + $2*2); + 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]; + outputData[sample + $1] = data[sample * 2 + channel]; } } - - },internal_buffer,offset,tomix); + }, internal_buffer, offset, tomix); + /* clang-format on */ todo-=tomix; offset+=tomix; @@ -617,9 +625,13 @@ void AudioServerJavascript::mix_to_js(int p_frames) { void AudioServerJavascript::init(){ - //EM_ASM( -// console.log('server is '+audio_server); -// ); + /* + // clang-format off + EM_ASM( + console.log('server is ' + audio_server); + ); + // clang-format on + */ //int latency = GLOBAL_DEF("javascript/audio_latency",16384); @@ -632,19 +644,19 @@ void AudioServerJavascript::init(){ int buffer_latency=16384; + /* clang-format off */ EM_ASM_( { - _as_script_node = _as_audioctx.createScriptProcessor($0, 0, 2); _as_script_node.connect(_as_audioctx.destination); console.log(_as_script_node.bufferSize); - _as_script_node.onaudioprocess = function(audioProcessingEvent) { // The output buffer contains the samples that will be modified and played _as_output_buffer = audioProcessingEvent.outputBuffer; audio_server_mix_function(_as_output_buffer.getChannelData(0).length); } - },buffer_latency); + }, buffer_latency); + /* clang-format on */ } @@ -811,20 +823,24 @@ AudioServerJavascript::AudioServerJavascript() { singleton=this; sample_base=1; voice_base=1; + /* clang-format off */ EM_ASM( - _as_samples={}; - _as_voices={}; - _as_voice_pan={}; - _as_voice_gain={}; + _as_samples = {}; + _as_voices = {}; + _as_voice_pan = {}; + _as_voice_gain = {}; _as_audioctx = new (window.AudioContext || window.webkitAudioContext)(); audio_server_mix_function = Module.cwrap('audio_server_mix_function', 'void', ['number']); ); + /* clang-format on */ + /* clang-format off */ webaudio_mix_rate = EM_ASM_INT_V( - return _as_audioctx.sampleRate; - ); + return _as_audioctx.sampleRate; + ); + /* clang-format on */ print_line("WEBAUDIO MIX RATE: "+itos(webaudio_mix_rate)); event_voice_scale=1.0; fx_volume_scale=1.0; diff --git a/platform/javascript/audio_server_javascript.h b/platform/javascript/audio_server_javascript.h index e27192cd9..f8c8774e4 100644 --- a/platform/javascript/audio_server_javascript.h +++ b/platform/javascript/audio_server_javascript.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,12 +29,11 @@ #ifndef AUDIO_SERVER_JAVASCRIPT_H #define AUDIO_SERVER_JAVASCRIPT_H - #include "servers/audio_server.h" class AudioServerJavascript : public AudioServer { - OBJ_TYPE(AudioServerJavascript,AudioServer); + GDCLASS(AudioServerJavascript,AudioServer); enum { INTERNAL_BUFFER_SIZE=4096, @@ -131,8 +130,8 @@ public: virtual const void* sample_get_data_ptr(RID p_sample) const; - virtual void sample_set_data(RID p_sample, const DVector<uint8_t>& p_buffer); - virtual DVector<uint8_t> sample_get_data(RID p_sample) const; + virtual void sample_set_data(RID p_sample, const PoolVector<uint8_t>& p_buffer); + virtual PoolVector<uint8_t> sample_get_data(RID p_sample) const; virtual void sample_set_mix_rate(RID p_sample,int p_rate); virtual int sample_get_mix_rate(RID p_sample) const; diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index b6a6a453b..55b05a912 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -2,104 +2,113 @@ import os import sys import string + def is_active(): - return True + return True + def get_name(): - return "JavaScript" + return "JavaScript" + def can_build(): - import os - if (not os.environ.has_key("EMSCRIPTEN_ROOT")): - return False - return True + import os + if (not os.environ.has_key("EMSCRIPTEN_ROOT")): + return False + return True + def get_opts(): - return [ - ['wasm','Compile to WebAssembly','no'], - ['javascript_eval','Enable JavaScript eval interface','yes'], - ] + return [ + ['wasm', 'Compile to WebAssembly', 'no'], + ['javascript_eval', 'Enable JavaScript eval interface', 'yes'], + ] -def get_flags(): - return [ - ('tools', 'no'), - ('builtin_zlib', 'yes'), - ('module_etc1_enabled', 'no'), - ('module_mpc_enabled', 'no'), - ('module_theora_enabled', 'no'), - ] +def get_flags(): + return [ + ('tools', 'no'), + ('module_etc1_enabled', 'no'), + ('module_mpc_enabled', 'no'), + ('module_theora_enabled', 'no'), + ] def configure(env): - env['ENV'] = os.environ; - env.use_windows_spawn_fix('javascript') + env['ENV'] = os.environ + env.use_windows_spawn_fix('javascript') - env.Append(CPPPATH=['#platform/javascript']) + env.Append(CPPPATH=['#platform/javascript']) - em_path=os.environ["EMSCRIPTEN_ROOT"] + em_path = os.environ["EMSCRIPTEN_ROOT"] - env['ENV']['PATH'] = em_path+":"+env['ENV']['PATH'] - env['CC'] = em_path+'/emcc' - env['CXX'] = em_path+'/emcc' - #env['AR'] = em_path+"/emar" - env['AR'] = em_path+"/emcc" - env['ARFLAGS'] = "-o" + env['ENV']['PATH'] = em_path + ":" + env['ENV']['PATH'] + env['CC'] = em_path + '/emcc' + env['CXX'] = em_path + '/emcc' + #env['AR'] = em_path+"/emar" + env['AR'] = em_path + "/emcc" + env['ARFLAGS'] = "-o" # env['RANLIB'] = em_path+"/emranlib" - env['RANLIB'] = em_path + "/emcc" - env['OBJSUFFIX'] = '.bc' - env['LIBSUFFIX'] = '.bc' - env['CCCOM'] = "$CC -o $TARGET $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES" - env['CXXCOM'] = "$CC -o $TARGET $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES" + env['RANLIB'] = em_path + "/emcc" + env['OBJSUFFIX'] = '.bc' + env['LIBSUFFIX'] = '.bc' + env['CCCOM'] = "$CC -o $TARGET $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES" + env['CXXCOM'] = "$CC -o $TARGET $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES" # env.Append(LIBS=['c','m','stdc++','log','GLESv1_CM','GLESv2']) # env["LINKFLAGS"]= string.split(" -g --sysroot="+ld_sysroot+" -Wl,--no-undefined -Wl,-z,noexecstack ") - if (env["target"]=="release"): - env.Append(CCFLAGS=['-O2']) - elif (env["target"]=="release_debug"): - env.Append(CCFLAGS=['-O2','-DDEBUG_ENABLED']) - elif (env["target"]=="debug"): - env.Append(CCFLAGS=['-D_DEBUG', '-Wall', '-O2', '-DDEBUG_ENABLED']) - #env.Append(CCFLAGS=['-D_DEBUG', '-Wall', '-g4', '-DDEBUG_ENABLED']) - env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC']) + if (env["target"] == "release"): + env.Append(CCFLAGS=['-O2']) + elif (env["target"] == "release_debug"): + env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + elif (env["target"] == "debug"): + env.Append(CCFLAGS=['-D_DEBUG', '-Wall', '-O2', '-DDEBUG_ENABLED']) + #env.Append(CCFLAGS=['-D_DEBUG', '-Wall', '-g4', '-DDEBUG_ENABLED']) + env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC']) - # TODO: Move that to opus module's config - if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): - env.opus_fixed_point = "yes" + # TODO: Move that to opus module's config + if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): + env.opus_fixed_point = "yes" - env.Append(CPPFLAGS=["-fno-exceptions",'-DNO_SAFE_CAST','-fno-rtti']) - env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DNO_FCNTL','-DMPC_FIXED_POINT','-DTYPED_METHOD_BIND','-DNO_THREADS']) - env.Append(CPPFLAGS=['-DGLES2_ENABLED']) - env.Append(CPPFLAGS=['-DGLES_NO_CLIENT_ARRAYS']) - env.Append(CPPFLAGS=['-s','FULL_ES2=1']) + # These flags help keep the file size down + env.Append(CPPFLAGS=["-fno-exceptions", '-DNO_SAFE_CAST', '-fno-rtti']) + env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DNO_FCNTL', '-DMPC_FIXED_POINT', '-DTYPED_METHOD_BIND', '-DNO_THREADS']) + env.Append(CPPFLAGS=['-DGLES2_ENABLED']) + env.Append(CPPFLAGS=['-DGLES_NO_CLIENT_ARRAYS']) # env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT']) - if env['wasm'] == 'yes': - env.Append(LINKFLAGS=['-s','BINARYEN=1']) - env.Append(LINKFLAGS=['-s','\'BINARYEN_METHOD="native-wasm"\'']) - env["PROGSUFFIX"]+=".webassembly" - else: - env.Append(CPPFLAGS=['-s','ASM_JS=1']) - env.Append(LINKFLAGS=['-s','ASM_JS=1']) + if env['wasm'] == 'yes': + env.Append(LINKFLAGS=['-s', 'BINARYEN=1']) + # Maximum memory size is baked into the WebAssembly binary during + # compilation, so we need to enable memory growth to allow setting + # TOTAL_MEMORY at runtime. The value set at runtime must be higher than + # what is set during compilation, check TOTAL_MEMORY in Emscripten's + # src/settings.js for the default. + env.Append(LINKFLAGS=['-s', 'ALLOW_MEMORY_GROWTH=1']) + env["PROGSUFFIX"] += ".webassembly" + else: + env.Append(CPPFLAGS=['-s', 'ASM_JS=1']) + env.Append(LINKFLAGS=['-s', 'ASM_JS=1']) + env.Append(LINKFLAGS=['--separate-asm']) - if env['javascript_eval'] == 'yes': - env.Append(CPPFLAGS=['-DJAVASCRIPT_EVAL_ENABLED']) + if env['javascript_eval'] == 'yes': + env.Append(CPPFLAGS=['-DJAVASCRIPT_EVAL_ENABLED']) - env.Append(LINKFLAGS=['-O2']) - #env.Append(LINKFLAGS=['-g4']) + env.Append(LINKFLAGS=['-O2']) + # env.Append(LINKFLAGS=['-g4']) - #print "CCCOM is:", env.subst('$CCCOM') - #print "P: ", env['p'], " Platofrm: ", env['platform'] + # print "CCCOM is:", env.subst('$CCCOM') + # print "P: ", env['p'], " Platofrm: ", env['platform'] - import methods + import methods - env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) - env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) - env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) - #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } ) + env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')}) + env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')}) + env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) + #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } ) diff --git a/platform/javascript/dom_keys.h b/platform/javascript/dom_keys.h index 282b632e9..5ef212ce4 100644 --- a/platform/javascript/dom_keys.h +++ b/platform/javascript/dom_keys.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 721aef3e5..e0ff9932c 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -40,7 +40,7 @@ #include "string.h" class EditorExportPlatformJavaScript : public EditorExportPlatform { - OBJ_TYPE( EditorExportPlatformJavaScript,EditorExportPlatform ); + GDCLASS( EditorExportPlatformJavaScript,EditorExportPlatform ); String custom_release_package; String custom_debug_package; @@ -181,9 +181,9 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t>& p_html, const St String current_line = lines[i]; current_line = current_line.replace("$GODOT_TMEM",itos((1<<(max_memory+5))*1024*1024)); current_line = current_line.replace("$GODOT_BASE",p_name); - current_line = current_line.replace("$GODOT_CANVAS_WIDTH",Globals::get_singleton()->get("display/width")); - current_line = current_line.replace("$GODOT_CANVAS_HEIGHT",Globals::get_singleton()->get("display/height")); - current_line = current_line.replace("$GODOT_HEAD_TITLE",!html_title.empty()?html_title:(String) Globals::get_singleton()->get("application/name")); + current_line = current_line.replace("$GODOT_CANVAS_WIDTH",GlobalConfig::get_singleton()->get("display/width")); + current_line = current_line.replace("$GODOT_CANVAS_HEIGHT",GlobalConfig::get_singleton()->get("display/height")); + current_line = current_line.replace("$GODOT_HEAD_TITLE",!html_title.empty()?html_title:(String) GlobalConfig::get_singleton()->get("application/name")); current_line = current_line.replace("$GODOT_HEAD_INCLUDE",html_head_include); current_line = current_line.replace("$GODOT_STYLE_FONT_FAMILY",html_font_family); current_line = current_line.replace("$GODOT_STYLE_INCLUDE",html_style_include); @@ -265,7 +265,7 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool FileAccess *f=FileAccess::open(p_path.get_base_dir()+"/data.pck",FileAccess::WRITE); if (!f) { - EditorNode::add_io_error("Could not create file for writing:\n"+p_path.basename()+"_files.js"); + EditorNode::add_io_error("Could not create file for writing:\n"+p_path.get_basename()+"_files.js"); return ERR_FILE_CANT_WRITE; } Error err = save_pack(f); @@ -307,27 +307,32 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool if (file=="godot.html") { - _fix_html(data,p_path.get_file().basename(), p_debug); + _fix_html(data,p_path.get_file().get_basename(), p_debug); file=p_path.get_file(); } if (file=="godotfs.js") { _fix_files(data,len); - file=p_path.get_file().basename()+"fs.js"; + file=p_path.get_file().get_basename()+"fs.js"; } if (file=="godot.js") { - file=p_path.get_file().basename()+".js"; + file=p_path.get_file().get_basename()+".js"; + } + + if (file=="godot.asm.js") { + + file=p_path.get_file().get_basename()+".asm.js"; } if (file=="godot.mem") { - file=p_path.get_file().basename()+".mem"; + file=p_path.get_file().get_basename()+".mem"; } if (file=="godot.wasm") { - file=p_path.get_file().basename()+".wasm"; + file=p_path.get_file().get_basename()+".wasm"; } String dst = p_path.get_base_dir().plus_file(file); @@ -372,7 +377,7 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { logo->create_from_image(img); max_memory=3; html_title=""; - html_font_family="arial,sans-serif"; + html_font_family="'Droid Sans',arial,sans-serif"; html_controls_enabled=true; pack_mode=PACK_SINGLE_FILE; } diff --git a/platform/javascript/export/export.h b/platform/javascript/export/export.h index 2105141e5..59c0a67e6 100644 --- a/platform/javascript/export/export.h +++ b/platform/javascript/export/export.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/javascript/godot_shell.html b/platform/javascript/godot_shell.html index 3170d2bb9..a8b959493 100644 --- a/platform/javascript/godot_shell.html +++ b/platform/javascript/godot_shell.html @@ -3,14 +3,14 @@ <head> <meta charset="utf-8" /> <title>$GODOT_HEAD_TITLE</title> - $GODOT_HEAD_INCLUDE +$GODOT_HEAD_INCLUDE <style type="text/css"> body { margin: 0; border: 0 none; padding: 0; text-align: center; - background-color: black; + background-color: #222226; font-family: $GODOT_STYLE_FONT_FAMILY; } @@ -71,7 +71,7 @@ margin: 0; border: 0 none; padding: 0; - background-color: #111; + background-color: #0c0c0c; } #canvas { @@ -81,6 +81,7 @@ * calculate cursor coordinates correctly */ border: 0 none; padding: 0; + color: white; } @@ -101,6 +102,8 @@ } #status { + line-height: 1.3; + cursor: pointer; visibility: visible; padding: 4px 6px; } @@ -123,7 +126,7 @@ -ms-user-select: none; } - #container:hover > #controls { + :hover > #controls { opacity: 1.0; transition: opacity 60ms ease-in-out; } @@ -135,223 +138,289 @@ margin-right: 2px; } + #controls > label > input { + vertical-align: middle; + } + #controls > label > input[type="checkbox"] { /* override user agent style */ margin-left: 0; } - label > input { - vertical-align: middle; - } - - #display-output { display: none; } + #output-toggle { display: none; } /* Debug output * ============ */ - #output { + #output-panel { display: none; - margin: 6px auto; - border: 2px groove grey; - padding: 4px; - outline: none; + max-width: $GODOT_CANVAS_WIDTHpx; + font-size: small; + margin: 6px auto 0; + padding: 0 4px 4px; text-align: left; + line-height: 2.2; + } + + #output-header { + display: flex; + justify-content: space-between; + align-items: center; + } + + #output-container { + padding: 6px; + background-color: #2c2a32; + box-shadow: inset 0 0 1px 1px #232127; + color: #bbb; + } + + #output-scroll { + line-height: 1; + height: 12em; + overflow-y: scroll; white-space: pre-wrap; font-size: small; - color: #eee; - background-color: black; font-family: "Lucida Console", Monaco, monospace; } - /* Export style include - * ==================== */ +/* Export style include + * ==================== */ + +$GODOT_STYLE_INCLUDE - $GODOT_STYLE_INCLUDE </style> </head> <body> <div id="container"> <canvas id="canvas" width="$GODOT_CANVAS_WIDTH" height="$GODOT_CANVAS_HEIGHT" onclick="canvas.ownerDocument.defaultView.focus();" oncontextmenu="event.preventDefault();"> - HTML5 canvas appears to be unsupported in the current browser.<br />Please try updating or use a different browser. + HTML5 canvas appears to be unsupported in the current browser.<br /> + Please try updating or use a different browser. </canvas> <div id="status-container"> - <span id="status" class="godot" onclick="this.style.visibility='hidden';">Loading page...</span> + <span id="status" class="godot" onclick="this.style.visibility='hidden';">Downloading page...</span> </div> <div id="controls" class="godot"> - <label id="display-output"><input id="output-toggle" type="checkbox" autocomplete="off" onchange="Presentation.setOutputVisible(this.checked);" />display output</label> + <label id="output-toggle"><input type="checkbox" checked="checked" autocomplete="off" onchange="Presentation.setOutputVisible(this.checked);" />Display Output</label> <!-- hidden until implemented - <label><input id="lock-cursor" type="checkbox" autocomplete="off" />lock cursor</label> - <label><input id="resize-canvas" type="checkbox" autocomplete="off" />resize canvas</label> + <label><input class="postRun-enable" type="checkbox" disabled="disabled" autocomplete="off" />lock cursor</label> + <label><input class="postRun-enable" type="checkbox" disabled="disabled" autocomplete="off" onchange="Presentation.setCanvasMaximized(this.checked);" />maximize</label> --> - <button id="fullscreen" class="godot" type="button" disabled="disabled" autocomplete="off" onclick="Presentation.goFullscreen();">fullscreen</button> + <button id="fullscreen" class="godot postRun-enable" type="button" disabled="disabled" autocomplete="off" onclick="Presentation.requestFullscreen();">Fullscreen</button> </div> </div> - <!-- Firefox adds extra space to textarea, but shouldn't matter too much https://bugzilla.mozilla.org/show_bug.cgi?id=33654 --> - <textarea id="output" rows="10" cols="100" readonly="readonly" style="resize:none"></textarea> + <div id="output-panel" class="godot"> + <div id="output-header"> + Output: + <button class="godot" type="button" autocomplete="off" onclick="Presentation.clearOutput();">Clear</button> + </div> + <div id="output-container"><div id="output-scroll"></div></div> + </div> + <!-- Scripts --> <script type="text/javascript">//<![CDATA[ var Presentation = (function() { var statusElement = document.getElementById("status"); - var outputElement = document.getElementById("output"); - var doneLoading = false; - - function onLoaded() { - doneLoading = true; - var fullscreenButtonElement = document.getElementById("fullscreen"); - fullscreenButtonElement.disabled = false; - } + var canvasElement = document.getElementById("canvas"); var presentation = { - statusElement: statusElement, - outputElement: outputElement, - setOutputVisible: function setOutputVisible(visible) { - outputElement.style.display = (visible?"block":"none"); + postRun: [ + function() { + var elements = document.getElementsByClassName("postRun-enable"); + Array.prototype.slice.call(elements).forEach(function(element) { + element.disabled = false; + }); + } + ], + requestFullscreen: function requestFullscreen() { + if (typeof Module !== "undefined" && Module.requestFullscreen) { + Module.requestFullscreen(false, false); + } + }, + /* + requestPointerlock: function requestPointerlock() { + if (typeof Module !== "undefined" && Module.requestPointerlock) { + Module.requestPointerlock(false, false); + } }, + setCanvasMaximized: function setCanvasMaximized(enabled) { + if (typeof Module !== "undefined" && Module.setCanvasMaximized) { + Module.setCanvasMaximized(enabled); + } + }, + */ setStatusVisible: function setStatusVisible(visible) { statusElement.style.visibility = (visible?"visible":"hidden"); }, setStatus: function setStatus(text) { - if (!text || text.length === 0) { - Presentation.setStatusVisible(false); - onLoaded(); - } else { - Presentation.setStatusVisible(true); - statusElement.innerHTML = text; + if (text.length === 0) { + // emscripten sets empty string as status after "Running..." + // per timeout, but another status may have been set by then + if (Presentation.setStatus.lastText === "Running...") + Presentation.setStatusVisible(false); + return; } + Presentation.setStatus.lastText = text; + while (statusElement.lastChild) { + statusElement.removeChild(statusElement.lastChild); + } + var lines = text.split("\n"); + lines.forEach(function(line, index) { + statusElement.appendChild(document.createTextNode(line)); + statusElement.appendChild(document.createElement("br")); + }); + var closeNote = document.createElement("span"); + closeNote.style.fontSize = "small"; + closeNote.textContent = "click to close"; + statusElement.appendChild(closeNote); + Presentation.setStatusVisible(true); + }, + isWebGLAvailable: function isWebGLAvailable() { + var context; + try { + context = canvasElement.getContext("webgl") || canvasElement.getContext("experimental-webgl"); + } catch (e) {} + return !!context; }, - goFullscreen: function goFullscreen() { - if (doneLoading) Module.requestFullScreen(false, false); - } }; + window.onerror = function(event) { presentation.setStatus("Failure during start-up\nSee JavaScript console") }; + if ($GODOT_CONTROLS_ENABLED) { // controls enabled - (function() { - var controlsElement = document.getElementById("controls"); - controlsElement.style.visibility="visible"; - })(); + document.getElementById("controls").style.visibility="visible"; } if ($GODOT_DEBUG_ENABLED) { // debugging enabled - (function() { - var outputToggleLabel = document.getElementById("display-output"); - var outputToggle = document.getElementById("output-toggle"); + var outputRoot = document.getElementById("output-panel"); + var outputElement = document.getElementById("output-scroll"); + var outputToggle = document.getElementById("output-toggle"); + const maxOutputMessages = 400; + + presentation.setOutputVisible = function setOutputVisible(visible) { + outputRoot.style.display = (visible?"block":"none"); + }; + presentation.clearOutput = function clearOutput() { + while (outputElement.firstChild) { + outputElement.firstChild.remove(); + } + }; + + presentation.setOutputVisible(true); + outputToggle.style.display = "inline"; + + presentation.print = function print(text) { + if (arguments.length > 1) { + text = Array.prototype.slice.call(arguments).join(" "); + } + if (text.length <= 0) return; + while (outputElement.childElementCount >= maxOutputMessages) { + outputElement.firstChild.remove(); + } + var msg = document.createElement("div"); + if (text.trim().startsWith("**ERROR**") + || text.startsWith("**EXCEPTION**")) { + msg.style.color = "#d44"; + } else if (text.trim().startsWith("**WARNING**")) { + msg.style.color = "#ccc000"; + } else if (text.trim().startsWith("**SCRIPT ERROR**")) { + msg.style.color = "#c6d"; + } + msg.textContent = text; + var scrollToBottom = outputElement.scrollHeight - (outputElement.clientHeight + outputElement.scrollTop) < 10; + outputElement.appendChild(msg); + if (scrollToBottom) { + outputElement.scrollTop = outputElement.scrollHeight; + } + }; - outputElement.value = ""; // clear browser cache - outputElement.style.display = "block"; - outputToggle.checked = true; - outputToggleLabel.style.display = "inline"; + presentation.postRun.push(function() { + window.onerror = function(event) { presentation.print("**EXCEPTION**:", event) }; + }); - presentation.print = function print(text) { - if (outputElement.value.length !== 0) - outputElement.value += "\n"; - outputElement.value += text; - outputElement.scrollTop = outputElement.scrollHeight; // focus on bottom - }; - })(); + } else { + presentation.postRun.push(function() { window.onerror = null; }); } return presentation; })(); // Emscripten interface - var Module = (function() { - var print = (function() { - if (typeof Presentation.print === "function") { - return function print(text) { - if (arguments.length > 1) - text = Array.prototype.slice.call(arguments).join(" "); - console.log(text); - Presentation.print(text); - }; - } else { - return function print(text) { - if (arguments.length > 1) - text = Array.prototype.slice.call(arguments).join(" "); - console.log(text); - }; + var Module = { + TOTAL_MEMORY: $GODOT_TMEM, + postRun: (function() { + if (typeof Presentation !== "undefined" && Presentation.postRun instanceof Array) { + return Presentation.postRun; } - })(); - - var canvas = (function() { - var canvasElement = document.getElementById("canvas"); - + })(), + print: function print(text) { + if (arguments.length > 1) { + text = Array.prototype.slice.call(arguments).join(" "); + } + console.log(text); + if (typeof Presentation !== "undefined" && typeof Presentation.print === "function") { + Presentation.print(text); + } + }, + printErr: function printErr(text) { + if (arguments.length > 1) { + text = Array.prototype.slice.call(arguments).join(" "); + } + console.error(text); + if (typeof Presentation !== "undefined" && typeof Presentation.print === "function") { + Presentation.print("**ERROR**:", text) + } + }, + canvas: (function() { + var canvas = document.getElementById("canvas"); // As a default initial behavior, pop up an alert when WebGL context is lost. To make your // application robust, you may want to override this behavior before shipping! // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 - canvasElement.addEventListener("webglcontextlost", function(e) { alert("WebGL context lost. Plase reload the page."); e.preventDefault(); }, false); - - return canvasElement; - })(); - - var setStatus = (function() { - if (typeof Presentation.setStatus === "function") - return function setStatus(text) { - if (!Module.setStatus.last) - Module.setStatus.last = { time: Date.now(), text: "" }; - if (text === Module.setStatus.text) - return; - var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); - var now = Date.now(); - if (m) { - if (now - Date.now() < 30) // if this is a progress update, skip it if too soon - return; - text = m[1]; - } - Presentation.setStatus(text); - }; - else - return function setStatus(text) { - if (!Module.setStatus.last) - Module.setStatus.last = { time: Date.now(), text: "" }; - if (text === Module.setStatus.text) - return; - var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); - var now = Date.now(); - if (m) { - if (now - Date.now() < 30) // if this is a progress update, skip it if too soon - return; - text = m[1]; - } - }; - })(); + canvas.addEventListener("webglcontextlost", function(e) { alert("WebGL context lost. Plase reload the page."); e.preventDefault(); }, false); + return canvas; - return { - TOTAL_MEMORY: 268435456, - preRun: [], - postRun: [], - print: print, - printErr: function printErr(text) { - if (arguments.length > 1) - text = Array.prototype.slice.call(arguments).join(" "); - if (0) { // XXX disabled for safety `if (typeof dump == "function")` - dump(text + "\n"); // fast, straight to the real console - } else { - console.error(text); - } - }, - canvas: canvas, - setStatus: setStatus, - totalDependencies: 0, - monitorRunDependencies: function monitorRunDependencies(left) { - this.totalDependencies = Math.max(this.totalDependencies, left); - Module.setStatus(left ? "Preparing... (" + (this.totalDependencies-left) + "/" + this.totalDependencies + ")" : "All downloads complete."); + })(), + setStatus: function setStatus(text) { + var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); + var now = Date.now(); + if (m) { + if (now - Date.now() < 30) // if this is a progress update, skip it if too soon + return; + text = m[1]; } - }; - })(); + if (typeof Presentation !== "undefined" && typeof Presentation.setStatus == "function") { + Presentation.setStatus(text); + } + } + }; - Presentation.setStatus("Downloading..."); + if (!Presentation.isWebGLAvailable()) { + Presentation.setStatus("WebGL appears to be unsupported in the current browser.\nPlease try updating or use a different browser."); + Presentation.preventLoading = true; + } else { + Presentation.setStatus("Downloading..."); + } - window.onerror = function(event) { - // TODO: do not warn on ok events like simulating an infinite loop or exitStatus - Module.setStatus("Exception thrown, see JavaScript console"); - Module.setStatus = function(text) { - if (text) Module.printErr("[post-exception status] " + text); - }; - }; + if (Presentation.preventLoading) { + // prevent *fs.js and Emscripten's SCRIPT placeholder from loading any files + Presentation._XHR_send = XMLHttpRequest.prototype.send; + XMLHttpRequest.prototype.send = function() {}; + Presentation._Node_appendChild = Node.prototype.appendChild; + Node.prototype.appendChild = function(node) { + if (!(node instanceof HTMLScriptElement)) { + return Presentation._Node_appendChild.call(this, node); + } + } + } //]]></script> <script type="text/javascript" src="$GODOT_BASEfs.js"></script> - {{{ SCRIPT }}} +{{{ SCRIPT }}} + <script type="text/javascript"> + if (Presentation.preventLoading) { + XMLHttpRequest.prototype.send = Presentation._XHR_send; + Node.prototype.appendChild = Presentation._Node_appendChild; + } + </script> </body> </html> diff --git a/platform/javascript/javascript_eval.cpp b/platform/javascript/javascript_eval.cpp index e642300bd..a79e5473c 100644 --- a/platform/javascript/javascript_eval.cpp +++ b/platform/javascript/javascript_eval.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -41,6 +41,7 @@ JavaScript *JavaScript::get_singleton() { Variant JavaScript::eval(const String& p_code, bool p_use_global_exec_context) { union { int i; double d; char* s; } js_data[4]; + /* clang-format off */ Variant::Type return_type = static_cast<Variant::Type>(EM_ASM_INT({ var eval_ret; @@ -49,8 +50,7 @@ Variant JavaScript::eval(const String& p_code, bool p_use_global_exec_context) { // indirect eval call grants global execution context var global_eval = eval; eval_ret = global_eval(UTF8ToString($2)); - } - else { + } else { eval_ret = eval(UTF8ToString($2)); } } catch (e) { @@ -125,6 +125,7 @@ Variant JavaScript::eval(const String& p_code, bool p_use_global_exec_context) { return 0; // NIL }, js_data, sizeof *js_data, p_code.utf8().get_data(), p_use_global_exec_context)); + /* clang-format on */ switch(return_type) { case Variant::BOOL: @@ -136,7 +137,9 @@ Variant JavaScript::eval(const String& p_code, bool p_use_global_exec_context) { case Variant::STRING: { String str = String::utf8(js_data->s); + /* clang-format off */ EM_ASM_({ _free($0); }, js_data->s); + /* clang-format on */ return str; } case Variant::VECTOR2: diff --git a/platform/javascript/javascript_eval.h b/platform/javascript/javascript_eval.h index e5f626807..679224d51 100644 --- a/platform/javascript/javascript_eval.h +++ b/platform/javascript/javascript_eval.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -35,7 +35,7 @@ class JavaScript : public Object { private: - OBJ_TYPE( JavaScript, Object ); + GDCLASS( JavaScript, Object ); static JavaScript *singleton; diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp index d9342cfe1..94320d53c 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/javascript/javascript_main.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -66,11 +66,12 @@ static void _glut_mouse_button(int button, int state, int x, int y) { if (ev.mouse_button.button_index<4) { if (ev.mouse_button.pressed) { - _mouse_button_mask|=1<<ev.mouse_button.button_index; + _mouse_button_mask |= 1 << (ev.mouse_button.button_index-1); } else { - _mouse_button_mask&=~(1<<ev.mouse_button.button_index); + _mouse_button_mask &= ~(1 << (ev.mouse_button.button_index-1)); } } + ev.mouse_button.button_mask=_mouse_button_mask; uint32_t m = glutGetModifiers(); ev.mouse_button.mod.alt=(m&GLUT_ACTIVE_ALT)!=0; @@ -79,6 +80,11 @@ static void _glut_mouse_button(int button, int state, int x, int y) { os->push_input(ev); + if (ev.mouse_button.button_index==BUTTON_WHEEL_UP || ev.mouse_button.button_index==BUTTON_WHEEL_DOWN) { + // GLUT doesn't send release events for mouse wheel, so send manually + ev.mouse_button.pressed=false; + os->push_input(ev); + } } @@ -134,10 +140,9 @@ static void _godot_draw(void) { extern "C" { -void main_after_fs_sync(int value) { +void main_after_fs_sync() { start_step=1; - printf("FS SYNCHED!\n"); } } @@ -148,13 +153,13 @@ int main(int argc, char *argv[]) { /* Initialize the window */ printf("let it go!\n"); glutInit(&argc, argv); - os = new OS_JavaScript(_gfx_init,NULL,NULL,NULL,NULL); + os = new OS_JavaScript(_gfx_init,NULL,NULL); #if 0 char *args[]={"-test","gui","-v",NULL}; Error err = Main::setup("apk",3,args); #else -// char *args[]={"-v",NULL};// -// Error err = Main::setup("",1,args); + //char *args[]={"-v",NULL};// + //Error err = Main::setup("",1,args); Error err = Main::setup("",0,NULL); #endif @@ -162,7 +167,6 @@ int main(int argc, char *argv[]) { glutMouseFunc(_glut_mouse_button); glutMotionFunc(_glut_mouse_motion); - glutMotionFunc(_glut_mouse_motion); glutPassiveMotionFunc(_glut_mouse_motion); @@ -173,26 +177,27 @@ int main(int argc, char *argv[]) { glutDisplayFunc(_godot_draw); //glutSpecialFunc(gears_special); + //mount persistent file system + /* clang-format off */ + EM_ASM( + FS.mkdir('/userfs'); + FS.mount(IDBFS, {}, '/userfs'); + // sync from persistent state into memory and then + // run the 'main_after_fs_sync' function + FS.syncfs(true, function(err) { - //mount persistent filesystem - EM_ASM( - FS.mkdir('/userfs'); - FS.mount(IDBFS, {}, '/userfs'); - - - - // sync from persisted state into memory and then - // run the 'test' function - FS.syncfs(true, function (err) { - assert(!err); - console.log("done syncinc!"); - _after_sync_cb = Module.cwrap('main_after_fs_sync', 'void',['number']); - _after_sync_cb(0); - - }); - - ); + if (err) { + Module.setStatus('Failed to load persistent data\nPlease allow (third-party) cookies'); + Module.printErr('Failed to populate IDB file system: ' + err.message); + Module.exit(); + } else { + Module.print('Successfully populated IDB file system'); + ccall('main_after_fs_sync', 'void', []); + } + }); + ); + /* clang-format on */ glutMainLoop(); diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index e802a7e9c..317a6676a 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -27,23 +27,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "os_javascript.h" + #include "drivers/gles2/rasterizer_gles2.h" #include "core/io/file_access_buffered_fa.h" #include "drivers/unix/file_access_unix.h" #include "drivers/unix/dir_access_unix.h" - #include "servers/visual/visual_server_raster.h" - #include "main/main.h" - #include "core/globals.h" -#include "emscripten.h" #include "dom_keys.h" +#include <stdlib.h> +#include <emscripten.h> + int OS_JavaScript::get_video_driver_count() const { return 1; } + const char * OS_JavaScript::get_video_driver_name(int p_driver) const { return "GLES2"; @@ -77,6 +78,59 @@ void OS_JavaScript::set_opengl_extensions(const char* p_gl_extensions) { gl_extensions=p_gl_extensions; } +static EM_BOOL _browser_resize_callback(int event_type, const EmscriptenUiEvent *ui_event, void *user_data) { + + ERR_FAIL_COND_V(event_type!=EMSCRIPTEN_EVENT_RESIZE, false); + + OS_JavaScript* os = static_cast<OS_JavaScript*>(user_data); + + // the order in which _browser_resize_callback and + // _fullscreen_change_callback are called is browser-dependent, + // so try adjusting for fullscreen in both + if (os->is_window_fullscreen() || os->is_window_maximized()) { + + OS::VideoMode vm = os->get_video_mode(); + vm.width = ui_event->windowInnerWidth; + vm.height = ui_event->windowInnerHeight; + os->set_video_mode(vm); + emscripten_set_canvas_size(ui_event->windowInnerWidth, ui_event->windowInnerHeight); + } + return false; +} + +static Size2 _windowed_size; + +static EM_BOOL _fullscreen_change_callback(int event_type, const EmscriptenFullscreenChangeEvent *event, void *user_data) { + + ERR_FAIL_COND_V(event_type!=EMSCRIPTEN_EVENT_FULLSCREENCHANGE, false); + + OS_JavaScript* os = static_cast<OS_JavaScript*>(user_data); + String id = String::utf8(event->id); + + // empty id is canvas + if (id.empty() || id=="canvas") { + + OS::VideoMode vm = os->get_video_mode(); + // this event property is the only reliable information on + // browser fullscreen state + vm.fullscreen = event->isFullscreen; + + if (event->isFullscreen) { + vm.width = event->screenWidth; + vm.height = event->screenHeight; + os->set_video_mode(vm); + emscripten_set_canvas_size(vm.width, vm.height); + } + else { + os->set_video_mode(vm); + if (!os->is_window_maximized()) { + os->set_window_size(_windowed_size); + } + } + } + return false; +} + static InputEvent _setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) { InputEvent ev; @@ -89,7 +143,9 @@ static InputEvent _setup_key_event(const EmscriptenKeyboardEvent *emscripten_eve ev.key.scancode = dom2godot_scancode(emscripten_event->keyCode); String unicode = String::utf8(emscripten_event->key); + // check if empty or multi-character (e.g. `CapsLock`) if (unicode.length()!=1) { + // might be empty as well, but better than nonsense unicode = String::utf8(emscripten_event->charValue); } if (unicode.length()==1) { @@ -151,20 +207,45 @@ void OS_JavaScript::initialize(const VideoMode& p_desired,int p_video_driver,int if (gfx_init_func) gfx_init_func(gfx_init_ud,use_gl2,p_desired.width,p_desired.height,p_desired.fullscreen); - default_videomode=p_desired; + // nothing to do here, can't fulfil fullscreen request due to + // browser security, window size is already set from HTML + video_mode=p_desired; + video_mode.fullscreen=false; + _windowed_size=get_window_size(); + + // find locale, emscripten only sets "C" + char locale_ptr[16]; + /* clang-format off */ + EM_ASM_({ + var locale = ""; + if (Module.locale) { + // best case: server-side script reads Accept-Language early and + // defines the locale to be read here + locale = Module.locale; + } else { + // no luck, use what the JS engine can tell us + // if this turns out not compatible enough, add tests for + // browserLanguage, systemLanguage and userLanguage + locale = navigator.languages ? navigator.languages[0] : navigator.language; + } + locale = locale.split('.')[0]; + stringToUTF8(locale, $0, 16); + }, locale_ptr); + /* clang-format on */ + setenv("LANG", locale_ptr, true); print_line("Init Audio"); - AudioDriverManagerSW::add_driver(&audio_driver_javascript); + AudioDriverManager::add_driver(&audio_driver_javascript); if (true) { - RasterizerGLES2 *rasterizer_gles22=memnew( RasterizerGLES2(false,false,false,false) );; + RasterizerGLES2 *rasterizer_gles22=memnew( RasterizerGLES2(false,false,false,false) ); rasterizer_gles22->set_use_framebuffers(false); //not supported by emscripten if (gl_extensions) rasterizer_gles22->set_extensions(gl_extensions); rasterizer = rasterizer_gles22; } else { -// rasterizer = memnew( RasterizerGLES1(true, false) ); + //rasterizer = memnew( RasterizerGLES1(true, false) ); } print_line("Init VS"); @@ -180,27 +261,6 @@ void OS_JavaScript::initialize(const VideoMode& p_desired,int p_video_driver,int ERR_PRINT("Initializing audio failed."); }*/ - print_line("Init SM"); - - //sample_manager = memnew( SampleManagerMallocSW ); - audio_server = memnew( AudioServerJavascript ); - - print_line("Init Mixer"); - - //audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false); - audio_server->init(); - - print_line("Init SoundServer"); - - spatial_sound_server = memnew( SpatialSoundServerSW ); - spatial_sound_server->init(); - - print_line("Init SpatialSoundServer"); - - spatial_sound_2d_server = memnew( SpatialSound2DServerSW ); - spatial_sound_2d_server->init(); - - // print_line("Init Physicsserver"); physics_server = memnew( PhysicsServerSW ); @@ -210,30 +270,27 @@ void OS_JavaScript::initialize(const VideoMode& p_desired,int p_video_driver,int input = memnew( InputDefault ); - EMSCRIPTEN_RESULT result = emscripten_set_keydown_callback(NULL, this , true, &_keydown_callback); - if (result!=EMSCRIPTEN_RESULT_SUCCESS) { - ERR_PRINTS( "Error while setting Emscripten keydown callback: Code " + itos(result) ); - } - result = emscripten_set_keypress_callback(NULL, this, true, &_keypress_callback); - if (result!=EMSCRIPTEN_RESULT_SUCCESS) { - ERR_PRINTS( "Error while setting Emscripten keypress callback: Code " + itos(result) ); - } - result = emscripten_set_keyup_callback(NULL, this, true, &_keyup_callback); - if (result!=EMSCRIPTEN_RESULT_SUCCESS) { - ERR_PRINTS( "Error while setting Emscripten keyup callback: Code " + itos(result) ); - } - result = emscripten_set_gamepadconnected_callback(NULL, true, &joy_callback_func); - if (result!=EMSCRIPTEN_RESULT_SUCCESS) { - ERR_PRINTS( "Error while setting Emscripten gamepadconnected callback: Code " + itos(result) ); - } - result = emscripten_set_gamepaddisconnected_callback(NULL, true, &joy_callback_func); - if (result!=EMSCRIPTEN_RESULT_SUCCESS) { - ERR_PRINTS( "Error while setting Emscripten gamepaddisconnected callback: Code " + itos(result) ); - } +#define EM_CHECK(ev) if (result!=EMSCRIPTEN_RESULT_SUCCESS)\ + ERR_PRINTS("Error while setting " #ev " callback: Code " + itos(result)) +#define SET_EM_CALLBACK(ev, cb) result = emscripten_set_##ev##_callback(NULL, this, true, &cb); EM_CHECK(ev) +#define SET_EM_CALLBACK_NODATA(ev, cb) result = emscripten_set_##ev##_callback(NULL, true, &cb); EM_CHECK(ev) + + EMSCRIPTEN_RESULT result; + SET_EM_CALLBACK(keydown, _keydown_callback) + SET_EM_CALLBACK(keypress, _keypress_callback) + SET_EM_CALLBACK(keyup, _keyup_callback) + SET_EM_CALLBACK(resize, _browser_resize_callback) + SET_EM_CALLBACK(fullscreenchange, _fullscreen_change_callback) + SET_EM_CALLBACK_NODATA(gamepadconnected, joy_callback_func) + SET_EM_CALLBACK_NODATA(gamepaddisconnected, joy_callback_func) + +#undef SET_EM_CALLBACK_NODATA +#undef SET_EM_CALLBACK +#undef EM_CHECK #ifdef JAVASCRIPT_EVAL_ENABLED javascript_eval = memnew(JavaScript); - Globals::get_singleton()->add_singleton(Globals::Singleton("JavaScript", javascript_eval)); + GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton("JavaScript", javascript_eval)); #endif } @@ -254,32 +311,13 @@ void OS_JavaScript::finalize() { memdelete(input); } +void OS_JavaScript::alert(const String& p_alert,const String& p_title) { -void OS_JavaScript::vprint(const char* p_format, va_list p_list, bool p_stderr) { - - if (p_stderr) { - - vfprintf(stderr,p_format,p_list); - fflush(stderr); - } else { - - vprintf(p_format,p_list); - fflush(stdout); - } -} - -void OS_JavaScript::print(const char *p_format, ... ) { - - va_list argp; - va_start(argp, p_format); - vprintf(p_format, argp ); - va_end(argp); - -} - -void OS_JavaScript::alert(const String& p_alert) { - - print("ALERT: %s\n",p_alert.utf8().get_data()); + /* clang-format off */ + EM_ASM_({ + window.alert(UTF8ToString($0)); + }, p_alert.utf8().get_data()); + /* clang-format on */ } @@ -298,17 +336,24 @@ bool OS_JavaScript::is_mouse_grab_enabled() const { //*sigh* technology has evolved so much since i was a kid.. return false; } + Point2 OS_JavaScript::get_mouse_pos() const { - return Point2(); + return input->get_mouse_pos(); } + int OS_JavaScript::get_mouse_button_state() const { - return 0; + return last_button_mask; } -void OS_JavaScript::set_window_title(const String& p_title) { +void OS_JavaScript::set_window_title(const String& p_title) { + /* clang-format off */ + EM_ASM_({ + document.title = UTF8ToString($0); + }, p_title.utf8().get_data()); + /* clang-format on */ } //interesting byt not yet @@ -317,22 +362,96 @@ void OS_JavaScript::set_window_title(const String& p_title) { void OS_JavaScript::set_video_mode(const VideoMode& p_video_mode,int p_screen) { - + video_mode = p_video_mode; } OS::VideoMode OS_JavaScript::get_video_mode(int p_screen) const { - return default_videomode; + return video_mode; +} + +Size2 OS_JavaScript::get_screen_size(int p_screen) const { + + ERR_FAIL_COND_V(p_screen!=0, Size2()); + + EmscriptenFullscreenChangeEvent ev; + EMSCRIPTEN_RESULT result = emscripten_get_fullscreen_status(&ev); + ERR_FAIL_COND_V(result!=EMSCRIPTEN_RESULT_SUCCESS, Size2()); + return Size2(ev.screenWidth, ev.screenHeight); +} + +void OS_JavaScript::set_window_size(const Size2 p_size) { + + window_maximized = false; + if (is_window_fullscreen()) { + set_window_fullscreen(false); + } + _windowed_size = p_size; + video_mode.width = p_size.x; + video_mode.height = p_size.y; + emscripten_set_canvas_size(p_size.x, p_size.y); } Size2 OS_JavaScript::get_window_size() const { - return Vector2(default_videomode.width,default_videomode.height); + int canvas[3]; + emscripten_get_canvas_size(canvas, canvas+1, canvas+2); + return Size2(canvas[0], canvas[1]); +} + +void OS_JavaScript::set_window_maximized(bool p_enabled) { + + window_maximized = p_enabled; + if (p_enabled) { + + if (is_window_fullscreen()) { + // _browser_resize callback will set canvas size + set_window_fullscreen(false); + } + else { + /* clang-format off */ + video_mode.width = EM_ASM_INT_V(return window.innerWidth); + video_mode.height = EM_ASM_INT_V(return window.innerHeight); + /* clang-format on */ + emscripten_set_canvas_size(video_mode.width, video_mode.height); + } + } + else { + set_window_size(_windowed_size); + } +} + +void OS_JavaScript::set_window_fullscreen(bool p_enable) { + + if (p_enable==is_window_fullscreen()) { + return; + } + + // only requesting changes here, if successful, canvas is resized in + // _browser_resize_callback or _fullscreen_change_callback + EMSCRIPTEN_RESULT result; + if (p_enable) { + /* clang-format off */ + EM_ASM(Module.requestFullscreen(false, false);); + /* clang-format on */ + } + else { + result = emscripten_exit_fullscreen(); + if (result!=EMSCRIPTEN_RESULT_SUCCESS) { + ERR_PRINTS("Failed to exit fullscreen: Code " + itos(result)); + } + } +} + +bool OS_JavaScript::is_window_fullscreen() const { + + return video_mode.fullscreen; } void OS_JavaScript::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const { - p_list->push_back(default_videomode); + Size2 screen = get_screen_size(); + p_list->push_back(OS::VideoMode(screen.width, screen.height, true)); } String OS_JavaScript::get_name() { @@ -372,24 +491,20 @@ bool OS_JavaScript::main_loop_iterate() { time_to_save_sync-=elapsed; - print_line("elapsed "+itos(elapsed)+" tts "+itos(time_to_save_sync)); - if (time_to_save_sync<0) { //time to sync, for real - // run 'success' - print_line("DOING SYNCH!"); + /* clang-format off */ EM_ASM( - FS.syncfs(function (err) { - assert(!err); - console.log("Synched!"); - //ccall('success', 'v'); - }); + FS.syncfs(function(err) { + if (err) { Module.printErr('Failed to save IDB file system: ' + err.message); } + }); ); + /* clang-format on */ } } - process_joysticks(); + process_joypads(); return Main::iteration(); } @@ -423,12 +538,15 @@ void OS_JavaScript::push_input(const InputEvent& p_ev) { if (ev.type==InputEvent::MOUSE_MOTION) { input->set_mouse_pos(Point2(ev.mouse_motion.x, ev.mouse_motion.y)); } + else if (ev.type==InputEvent::MOUSE_BUTTON) { + last_button_mask = ev.mouse_button.button_mask; + } input->parse_input_event(p_ev); } void OS_JavaScript::process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points) { -// print_line("ev: "+itos(p_what)+" pnt: "+itos(p_pointer)+" pointc: "+itos(p_points.size())); + //print_line("ev: "+itos(p_what)+" pnt: "+itos(p_pointer)+" pointc: "+itos(p_points.size())); switch(p_what) { case 0: { //gesture begin @@ -511,8 +629,8 @@ void OS_JavaScript::process_touch(int p_what,int p_pointer, const Vector<TouchPo ev.mouse_motion.x=p_points[0].pos.x; ev.mouse_motion.y=p_points[0].pos.y; input->set_mouse_pos(Point2(ev.mouse_motion.x,ev.mouse_motion.y)); - ev.mouse_motion.speed_x=input->get_mouse_speed().x; - ev.mouse_motion.speed_y=input->get_mouse_speed().y; + ev.mouse_motion.speed_x=input->get_last_mouse_speed().x; + ev.mouse_motion.speed_y=input->get_last_mouse_speed().y; ev.mouse_motion.relative_x=p_points[0].pos.x-last_mouse.x; ev.mouse_motion.relative_y=p_points[0].pos.y-last_mouse.y; last_mouse=p_points[0].pos; @@ -649,48 +767,42 @@ void OS_JavaScript::main_loop_request_quit() { main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST); } -void OS_JavaScript::set_display_size(Size2 p_size) { - - default_videomode.width=p_size.x; - default_videomode.height=p_size.y; -} - void OS_JavaScript::reload_gfx() { if (gfx_init_func) - gfx_init_func(gfx_init_ud,use_gl2,default_videomode.width,default_videomode.height,default_videomode.fullscreen); + gfx_init_func(gfx_init_ud,use_gl2,video_mode.width,video_mode.height,video_mode.fullscreen); if (rasterizer) rasterizer->reload_vram(); } Error OS_JavaScript::shell_open(String p_uri) { - - if (open_uri_func) - return open_uri_func(p_uri)?ERR_CANT_OPEN:OK; - return ERR_UNAVAILABLE; -}; + /* clang-format off */ + EM_ASM_({ + window.open(UTF8ToString($0), '_blank'); + }, p_uri.utf8().get_data()); + /* clang-format on */ + return OK; +} String OS_JavaScript::get_resource_dir() const { return "/"; //javascript has it's own filesystem for resources inside the APK } -String OS_JavaScript::get_locale() const { - - if (get_locale_func) - return get_locale_func(); - return OS_Unix::get_locale(); -} - - String OS_JavaScript::get_data_dir() const { - //if (get_data_dir_func) - // return get_data_dir_func(); + /* + if (get_data_dir_func) + return get_data_dir_func(); + */ return "/userfs"; - //return Globals::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir"); + //return GlobalConfig::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir"); }; +String OS_JavaScript::get_executable_path() const { + + return String(); +} void OS_JavaScript::_close_notification_funcs(const String& p_file,int p_flags) { @@ -701,7 +813,7 @@ void OS_JavaScript::_close_notification_funcs(const String& p_file,int p_flags) } } -void OS_JavaScript::process_joysticks() { +void OS_JavaScript::process_joypads() { int joy_count = emscripten_get_num_gamepads(); for (int i = 0; i < joy_count; i++) { @@ -757,24 +869,18 @@ String OS_JavaScript::get_joy_guid(int p_device) const { return input->get_joy_guid_remapped(p_device); } -OS_JavaScript::OS_JavaScript(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func) { - - - default_videomode.width=800; - default_videomode.height=600; - default_videomode.fullscreen=true; - default_videomode.resizable=false; +OS_JavaScript::OS_JavaScript(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, GetDataDirFunc p_get_data_dir_func) { gfx_init_func=p_gfx_init_func; gfx_init_ud=p_gfx_init_ud; + last_button_mask=0; main_loop=NULL; last_id=1; gl_extensions=NULL; rasterizer=NULL; + window_maximized=false; - open_uri_func=p_open_uri_func; get_data_dir_func=p_get_data_dir_func; - get_locale_func=p_get_locale_func; FileAccessUnix::close_notification_func=_close_notification_funcs; time_to_save_sync=-1; diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 5b7904805..d11494a8a 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -35,19 +35,18 @@ #include "servers/physics/physics_server_sw.h" #include "servers/spatial_sound/spatial_sound_server_sw.h" #include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h" -#include "servers/audio/audio_server_sw.h" +#include "servers/audio_server.h" #include "servers/physics_2d/physics_2d_server_sw.h" #include "servers/visual/rasterizer.h" #include "audio_server_javascript.h" #include "audio_driver_javascript.h" #include "main/input_default.h" -#include "emscripten/html5.h" #include "javascript_eval.h" +#include <emscripten/html5.h> + typedef void (*GFXInitFunc)(void *ud,bool gl2,int w, int h, bool fs); -typedef int (*OpenURIFunc)(const String&); typedef String (*GetDataDirFunc)(); -typedef String (*GetLocaleFunc)(); class OS_JavaScript : public OS_Unix { public: @@ -61,6 +60,7 @@ private: Vector<TouchPos> touch; Point2 last_mouse; + int last_button_mask; unsigned int last_id; GFXInitFunc gfx_init_func; void*gfx_init_ud; @@ -72,22 +72,17 @@ private: Rasterizer *rasterizer; VisualServer *visual_server; - AudioServerJavascript *audio_server; - //SampleManagerMallocSW *sample_manager; - SpatialSoundServerSW *spatial_sound_server; - SpatialSound2DServerSW *spatial_sound_2d_server; PhysicsServer *physics_server; Physics2DServer *physics_2d_server; AudioDriverJavaScript audio_driver_javascript; const char* gl_extensions; InputDefault *input; - VideoMode default_videomode; + bool window_maximized; + VideoMode video_mode; MainLoop * main_loop; - OpenURIFunc open_uri_func; GetDataDirFunc get_data_dir_func; - GetLocaleFunc get_locale_func; #ifdef JAVASCRIPT_EVAL_ENABLED JavaScript* javascript_eval; @@ -95,7 +90,7 @@ private: static void _close_notification_funcs(const String& p_file,int p_flags); - void process_joysticks(); + void process_joypads(); public: @@ -121,9 +116,12 @@ public: //static OS* get_singleton(); - virtual void vprint(const char* p_format, va_list p_list, bool p_stderr=false); - virtual void print(const char *p_format, ... ); - virtual void alert(const String& p_alert); + virtual void print_error(const char* p_function, const char* p_file, int p_line, const char *p_code, const char* p_rationale, ErrorType p_type) { + + OS::print_error(p_function, p_file, p_line, p_code, p_rationale, p_type); + } + + virtual void alert(const String& p_alert,const String& p_title="ALERT!"); virtual void set_mouse_show(bool p_show); @@ -140,7 +138,15 @@ public: 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 Size2 get_screen_size(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 { return window_maximized; } + virtual void set_window_fullscreen(bool p_enable); + virtual bool is_window_fullscreen() const; + virtual String get_name(); virtual MainLoop *get_main_loop() const; @@ -158,14 +164,13 @@ public: virtual bool has_touchscreen_ui_hint() const; void set_opengl_extensions(const char* p_gl_extensions); - void set_display_size(Size2 p_size); void reload_gfx(); virtual Error shell_open(String p_uri); virtual String get_data_dir() const; + String get_executable_path() const; virtual String get_resource_dir() const; - virtual String get_locale() const; void process_accelerometer(const Vector3& p_accelerometer); void process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points); @@ -175,7 +180,7 @@ public: virtual String get_joy_guid(int p_device) const; bool joy_connection_changed(int p_type, const EmscriptenGamepadEvent *p_event); - OS_JavaScript(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func); + OS_JavaScript(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, GetDataDirFunc p_get_data_dir_func); ~OS_JavaScript(); }; diff --git a/platform/javascript/platform_config.h b/platform/javascript/platform_config.h index 143f16c1f..cdef185ff 100644 --- a/platform/javascript/platform_config.h +++ b/platform/javascript/platform_config.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ |
