aboutsummaryrefslogtreecommitdiff
path: root/platform/javascript
diff options
context:
space:
mode:
Diffstat (limited to 'platform/javascript')
-rw-r--r--platform/javascript/SCsub41
-rw-r--r--platform/javascript/audio_driver_javascript.cpp33
-rw-r--r--platform/javascript/audio_driver_javascript.h8
-rw-r--r--platform/javascript/audio_server_javascript.cpp204
-rw-r--r--platform/javascript/audio_server_javascript.h9
-rw-r--r--platform/javascript/detect.py143
-rw-r--r--platform/javascript/dom_keys.h2
-rw-r--r--platform/javascript/export/export.cpp29
-rw-r--r--platform/javascript/export/export.h2
-rw-r--r--platform/javascript/godot_shell.html375
-rw-r--r--platform/javascript/javascript_eval.cpp9
-rw-r--r--platform/javascript/javascript_eval.h4
-rw-r--r--platform/javascript/javascript_main.cpp59
-rw-r--r--platform/javascript/os_javascript.cpp364
-rw-r--r--platform/javascript/os_javascript.h43
-rw-r--r--platform/javascript/platform_config.h2
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 */