summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
committerJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
commit0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch)
tree276c4d099e178eb67fbd14f61d77b05e3808e9e3 /platform
parent0e49da1687bc8192ed210947da52c9e5c5f301bb (diff)
GODOT IS OPEN SOURCE
Diffstat (limited to 'platform')
-rw-r--r--platform/android/.old/SCsub22
-rw-r--r--platform/android/.old/audio_driver_android.cpp104
-rw-r--r--platform/android/.old/audio_driver_android.h29
-rw-r--r--platform/android/.old/context_gl_android.cpp38
-rw-r--r--platform/android/.old/context_gl_android.h24
-rw-r--r--platform/android/.old/detect.py107
-rw-r--r--platform/android/.old/dir_access_jandroid.cpp217
-rw-r--r--platform/android/.old/dir_access_jandroid.h63
-rw-r--r--platform/android/.old/file_access_jandroid.cpp204
-rw-r--r--platform/android/.old/file_access_jandroid.h56
-rw-r--r--platform/android/.old/gdb.setup.base3
-rw-r--r--platform/android/.old/java/AndroidManifest.xml22
-rw-r--r--platform/android/.old/java/build.properties17
-rw-r--r--platform/android/.old/java/build.xml79
-rw-r--r--platform/android/.old/java/default.properties11
-rwxr-xr-xplatform/android/.old/java/libs/armeabi/gdbserverbin0 -> 125208 bytes
-rw-r--r--platform/android/.old/java/local.properties10
-rw-r--r--platform/android/.old/java/proguard.cfg36
-rw-r--r--platform/android/.old/java/res/drawable-hdpi/icon.pngbin0 -> 4147 bytes
-rw-r--r--platform/android/.old/java/res/drawable-ldpi/icon.pngbin0 -> 1723 bytes
-rw-r--r--platform/android/.old/java/res/drawable-mdpi/icon.pngbin0 -> 2574 bytes
-rw-r--r--platform/android/.old/java/res/values/strings.xml4
-rw-r--r--platform/android/.old/java/src/com/android/godot/Godot.java85
-rw-r--r--platform/android/.old/java/src/com/android/godot/GodotIO.java277
-rw-r--r--platform/android/.old/java/src/com/android/godot/GodotLib.java22
-rw-r--r--platform/android/.old/java/src/com/android/godot/GodotView.java319
-rw-r--r--platform/android/.old/java_glue.cpp181
-rw-r--r--platform/android/.old/java_glue.h16
-rw-r--r--platform/android/.old/os_android.cpp426
-rw-r--r--platform/android/.old/os_android.h108
-rw-r--r--platform/android/.old/platform_config.h1
-rwxr-xr-xplatform/android/.old/run_debug.sh40
-rw-r--r--platform/android/AndroidManifest.xml.template40
-rw-r--r--platform/android/SCsub66
-rw-r--r--platform/android/android_native_app_glue.c437
-rw-r--r--platform/android/android_native_app_glue.h378
-rw-r--r--platform/android/audio_driver_android.cpp393
-rw-r--r--platform/android/audio_driver_android.h105
-rw-r--r--platform/android/audio_driver_jandroid.cpp248
-rw-r--r--platform/android/audio_driver_jandroid.h82
-rw-r--r--platform/android/detect.py175
-rw-r--r--platform/android/dir_access_android.cpp189
-rw-r--r--platform/android/dir_access_android.h82
-rw-r--r--platform/android/dir_access_jandroid.cpp241
-rw-r--r--platform/android/dir_access_jandroid.h90
-rw-r--r--platform/android/export/export.cpp1229
-rw-r--r--platform/android/export/export.h3
-rw-r--r--platform/android/file_access_android.cpp187
-rw-r--r--platform/android/file_access_android.h82
-rw-r--r--platform/android/file_access_jandroid.cpp253
-rw-r--r--platform/android/file_access_jandroid.h87
-rw-r--r--platform/android/globals/global_defaults.cpp13
-rw-r--r--platform/android/globals/global_defaults.h3
-rw-r--r--platform/android/godot_android.cpp993
-rw-r--r--platform/android/java/ant.properties22
-rw-r--r--platform/android/java/build.properties17
-rw-r--r--platform/android/java/build.xml92
-rw-r--r--platform/android/java/default.properties11
-rw-r--r--platform/android/java/my-release-key.keystorebin0 -> 2218 bytes
-rw-r--r--platform/android/java/proguard-project.txt20
-rw-r--r--platform/android/java/proguard.cfg36
-rw-r--r--platform/android/java/res/drawable/icon.pngbin0 -> 91728 bytes
-rw-r--r--platform/android/java/res/values-ar/strings.xml4
-rw-r--r--platform/android/java/res/values-bg/strings.xml4
-rw-r--r--platform/android/java/res/values-ca/strings.xml4
-rw-r--r--platform/android/java/res/values-cs/strings.xml4
-rw-r--r--platform/android/java/res/values-da/strings.xml4
-rw-r--r--platform/android/java/res/values-de/strings.xml4
-rw-r--r--platform/android/java/res/values-el/strings.xml4
-rw-r--r--platform/android/java/res/values-en/strings.xml4
-rw-r--r--platform/android/java/res/values-es-rES/strings.xml4
-rw-r--r--platform/android/java/res/values-es/strings.xml4
-rw-r--r--platform/android/java/res/values-fi/strings.xml4
-rw-r--r--platform/android/java/res/values-fr/strings.xml4
-rw-r--r--platform/android/java/res/values-he/strings.xml4
-rw-r--r--platform/android/java/res/values-hi/strings.xml4
-rw-r--r--platform/android/java/res/values-hr/strings.xml4
-rw-r--r--platform/android/java/res/values-hu/strings.xml4
-rw-r--r--platform/android/java/res/values-id/strings.xml4
-rw-r--r--platform/android/java/res/values-it/strings.xml4
-rw-r--r--platform/android/java/res/values-ja/strings.xml4
-rw-r--r--platform/android/java/res/values-ko/strings.xml4
-rw-r--r--platform/android/java/res/values-lt/strings.xml4
-rw-r--r--platform/android/java/res/values-lv/strings.xml4
-rw-r--r--platform/android/java/res/values-nb/strings.xml4
-rw-r--r--platform/android/java/res/values-nl/strings.xml4
-rw-r--r--platform/android/java/res/values-pl/strings.xml4
-rw-r--r--platform/android/java/res/values-pt/strings.xml4
-rw-r--r--platform/android/java/res/values-ro/strings.xml4
-rw-r--r--platform/android/java/res/values-ru/strings.xml4
-rw-r--r--platform/android/java/res/values-sk/strings.xml4
-rw-r--r--platform/android/java/res/values-sl/strings.xml4
-rw-r--r--platform/android/java/res/values-sr/strings.xml4
-rw-r--r--platform/android/java/res/values-sv/strings.xml4
-rw-r--r--platform/android/java/res/values-th/strings.xml4
-rw-r--r--platform/android/java/res/values-tl/strings.xml4
-rw-r--r--platform/android/java/res/values-tr/strings.xml4
-rw-r--r--platform/android/java/res/values-uk/strings.xml4
-rw-r--r--platform/android/java/res/values-vi/strings.xml4
-rw-r--r--platform/android/java/res/values-zh/strings.xml4
-rw-r--r--platform/android/java/res/values/strings.xml7
-rw-r--r--platform/android/java/src/com/android/godot/Dictionary.java80
-rw-r--r--platform/android/java/src/com/android/godot/Godot.java300
-rw-r--r--platform/android/java/src/com/android/godot/GodotIO.java514
-rw-r--r--platform/android/java/src/com/android/godot/GodotLib.java63
-rw-r--r--platform/android/java/src/com/android/godot/GodotView.java378
-rw-r--r--platform/android/java_glue.cpp1153
-rw-r--r--platform/android/java_glue.h58
-rw-r--r--platform/android/logo.pngbin0 -> 1474 bytes
-rw-r--r--platform/android/os_android.cpp709
-rw-r--r--platform/android/os_android.h197
-rw-r--r--platform/android/platform_config.h29
-rw-r--r--platform/android/project.properties.template15
-rwxr-xr-xplatform/android/sign.sh9
-rw-r--r--platform/android/thread_jandroid.cpp135
-rw-r--r--platform/android/thread_jandroid.h82
-rw-r--r--platform/bb10/SCsub30
-rw-r--r--platform/bb10/audio_driver_bb10.cpp255
-rw-r--r--platform/bb10/audio_driver_bb10.h78
-rw-r--r--platform/bb10/bar/bar-descriptor.xml65
-rw-r--r--platform/bb10/bar/icon.pngbin0 -> 8188 bytes
-rw-r--r--platform/bb10/bbutil.c513
-rw-r--r--platform/bb10/bbutil.h96
-rw-r--r--platform/bb10/detect.py91
-rw-r--r--platform/bb10/export/export.cpp805
-rw-r--r--platform/bb10/export/export.h3
-rw-r--r--platform/bb10/godot_bb10.cpp48
-rw-r--r--platform/bb10/logo.pngbin0 -> 1852 bytes
-rw-r--r--platform/bb10/os_bb10.cpp630
-rw-r--r--platform/bb10/os_bb10.h157
-rw-r--r--platform/bb10/payment_service.cpp150
-rw-r--r--platform/bb10/payment_service.h69
-rw-r--r--platform/bb10/platform_config.h29
-rw-r--r--platform/iphone/Appirater.h227
-rw-r--r--platform/iphone/Appirater.m383
-rw-r--r--platform/iphone/SCsub45
-rw-r--r--platform/iphone/app_delegate.h42
-rw-r--r--platform/iphone/app_delegate.mm268
-rw-r--r--platform/iphone/audio_driver_iphone.cpp157
-rw-r--r--platform/iphone/audio_driver_iphone.h63
-rw-r--r--platform/iphone/detect.py130
-rw-r--r--platform/iphone/game_center.h68
-rw-r--r--platform/iphone/game_center.mm163
-rwxr-xr-xplatform/iphone/gl_view.h100
-rwxr-xr-xplatform/iphone/gl_view.mm457
-rw-r--r--platform/iphone/globals/global_defaults.cpp11
-rw-r--r--platform/iphone/globals/global_defaults.h3
-rw-r--r--platform/iphone/godot_iphone.cpp86
-rw-r--r--platform/iphone/in_app_store.h66
-rw-r--r--platform/iphone/in_app_store.mm264
-rw-r--r--platform/iphone/logo.pngbin0 -> 1899 bytes
-rw-r--r--platform/iphone/main.m22
-rw-r--r--platform/iphone/os_iphone.cpp507
-rw-r--r--platform/iphone/os_iphone.h193
-rw-r--r--platform/iphone/platform_config.h32
-rw-r--r--platform/iphone/rasterizer_iphone.cpp2762
-rw-r--r--platform/iphone/rasterizer_iphone.h894
-rw-r--r--platform/iphone/sem_iphone.cpp115
-rw-r--r--platform/iphone/sem_iphone.h60
-rw-r--r--platform/iphone/view_controller.h40
-rw-r--r--platform/iphone/view_controller.mm107
-rw-r--r--platform/isim/SCsub30
-rw-r--r--platform/isim/detect.py98
-rw-r--r--platform/javascript/SCsub25
-rw-r--r--platform/javascript/audio_driver_javascript.cpp91
-rw-r--r--platform/javascript/audio_driver_javascript.h56
-rw-r--r--platform/javascript/detect.py102
-rw-r--r--platform/javascript/export/export.cpp452
-rw-r--r--platform/javascript/export/export.h29
-rw-r--r--platform/javascript/javascript_main.cpp251
-rw-r--r--platform/javascript/logo.pngbin0 -> 4807 bytes
-rw-r--r--platform/javascript/os_javascript.cpp593
-rw-r--r--platform/javascript/os_javascript.h164
-rw-r--r--platform/javascript/platform_config.h29
-rw-r--r--platform/nacl/SCsub30
-rw-r--r--platform/nacl/audio_driver_nacl.cpp106
-rw-r--r--platform/nacl/audio_driver_nacl.h63
-rw-r--r--platform/nacl/context_gl_nacl.cpp67
-rw-r--r--platform/nacl/context_gl_nacl.h58
-rw-r--r--platform/nacl/detect.py71
-rw-r--r--platform/nacl/geturl_handler.cpp150
-rw-r--r--platform/nacl/geturl_handler.h115
-rw-r--r--platform/nacl/godot_module.cpp332
-rw-r--r--platform/nacl/godot_nacl.cpp80
-rw-r--r--platform/nacl/html/check_browser.js178
-rw-r--r--platform/nacl/html/godot_nacl.nmf6
-rw-r--r--platform/nacl/html/icon_128.pngbin0 -> 2255 bytes
-rw-r--r--platform/nacl/html/icon_16.pngbin0 -> 850 bytes
-rw-r--r--platform/nacl/html/index.html258
-rw-r--r--platform/nacl/html/manifest.json19
-rw-r--r--platform/nacl/logo.pngbin0 -> 2705 bytes
-rw-r--r--platform/nacl/nacl_keycodes.h422
-rw-r--r--platform/nacl/opengl_context.cpp123
-rw-r--r--platform/nacl/opengl_context.h124
-rw-r--r--platform/nacl/os_nacl.cpp529
-rw-r--r--platform/nacl/os_nacl.h156
-rw-r--r--platform/nacl/pepper_main.cpp541
-rw-r--r--platform/nacl/platform_config.h29
-rw-r--r--platform/osx/SCsub11
-rw-r--r--platform/osx/audio_driver_osx.cpp160
-rw-r--r--platform/osx/audio_driver_osx.h71
-rw-r--r--platform/osx/context_gl_osx.cpp104
-rw-r--r--platform/osx/context_gl_osx.h65
-rw-r--r--platform/osx/detect.py107
-rw-r--r--platform/osx/export/export.cpp504
-rw-r--r--platform/osx/export/export.h3
-rw-r--r--platform/osx/godot_main_osx.mm86
-rw-r--r--platform/osx/godot_osx.h37
-rw-r--r--platform/osx/godot_osx.mm215
-rw-r--r--platform/osx/logo.pngbin0 -> 1905 bytes
-rw-r--r--platform/osx/os_osx.h166
-rw-r--r--platform/osx/os_osx.mm1323
-rw-r--r--platform/osx/platform_config.h31
-rw-r--r--platform/osx/sem_osx.cpp115
-rw-r--r--platform/osx/sem_osx.h60
-rw-r--r--platform/server/SCsub8
-rw-r--r--platform/server/detect.py91
-rw-r--r--platform/server/godot_server.cpp45
-rw-r--r--platform/server/logo.h2
-rw-r--r--platform/server/logo.pngbin0 -> 2162 bytes
-rw-r--r--platform/server/os_server.cpp236
-rw-r--r--platform/server/os_server.h119
-rw-r--r--platform/server/platform_config.h30
-rw-r--r--platform/windows/SCsub13
-rw-r--r--platform/windows/context_gl_win.cpp205
-rw-r--r--platform/windows/context_gl_win.h79
-rw-r--r--platform/windows/ctxgl_procaddr.cpp186
-rw-r--r--platform/windows/ctxgl_procaddr.h38
-rw-r--r--platform/windows/detect.py208
-rw-r--r--platform/windows/export/export.cpp24
-rw-r--r--platform/windows/export/export.h3
-rw-r--r--platform/windows/godot_win.cpp207
-rw-r--r--platform/windows/key_mapping_win.cpp256
-rw-r--r--platform/windows/key_mapping_win.h51
-rw-r--r--platform/windows/lang_table.h190
-rw-r--r--platform/windows/logo.pngbin0 -> 1434 bytes
-rw-r--r--platform/windows/os_windows.cpp1732
-rw-r--r--platform/windows/os_windows.h257
-rw-r--r--platform/windows/platform_config.h35
-rw-r--r--platform/windows/stream_peer_winsock.cpp368
-rw-r--r--platform/windows/stream_peer_winsock.h90
-rw-r--r--platform/windows/tcp_server_winsock.cpp166
-rw-r--r--platform/windows/tcp_server_winsock.h55
-rw-r--r--platform/x11/SCsub13
-rw-r--r--platform/x11/context_gl_x11.cpp197
-rw-r--r--platform/x11/context_gl_x11.h76
-rw-r--r--platform/x11/detect.py146
-rw-r--r--platform/x11/export/export.cpp24
-rw-r--r--platform/x11/export/export.h4
-rw-r--r--platform/x11/godot_x11.cpp45
-rw-r--r--platform/x11/key_mapping_x11.cpp1812
-rw-r--r--platform/x11/key_mapping_x11.h55
-rw-r--r--platform/x11/logo.pngbin0 -> 2055 bytes
-rw-r--r--platform/x11/os_x11.cpp1300
-rw-r--r--platform/x11/os_x11.h203
-rw-r--r--platform/x11/platform_config.h32
256 files changed, 39296 insertions, 0 deletions
diff --git a/platform/android/.old/SCsub b/platform/android/.old/SCsub
new file mode 100644
index 0000000000..59e6d10b85
--- /dev/null
+++ b/platform/android/.old/SCsub
@@ -0,0 +1,22 @@
+Import('env')
+
+android_files = [
+
+ 'audio_driver_android.cpp',
+ 'file_access_jandroid.cpp',
+ 'dir_access_jandroid.cpp',
+ 'os_android.cpp',
+ 'java_glue.cpp'
+]
+
+#env.Depends('#core/math/vector3.h', 'vector3_psp.h')
+
+#obj = env.SharedObject('godot_android.cpp')
+
+android_objects=[]
+for x in android_files:
+ android_objects.append( env.SharedObject( x ) )
+
+prog = None
+
+env.SharedLibrary("#platform/jandroid/libgodot_android.so",[android_objects])
diff --git a/platform/android/.old/audio_driver_android.cpp b/platform/android/.old/audio_driver_android.cpp
new file mode 100644
index 0000000000..7e2d065d65
--- /dev/null
+++ b/platform/android/.old/audio_driver_android.cpp
@@ -0,0 +1,104 @@
+#include "audio_driver_android.h"
+
+AudioDriverAndroid* AudioDriverAndroid::s_ad=NULL;
+
+const char* AudioDriverAndroid::get_name() const {
+
+ return "Android";
+}
+
+#if 0
+int AudioDriverAndroid::thread_func(SceSize args, void *argp) {
+
+ AudioDriverAndroid* ad = s_ad;
+ sceAudioOutput2Reserve(AUDIO_OUTPUT_SAMPLE);
+
+ int half=0;
+ while(!ad->exit_thread) {
+
+ int16_t *ptr = &ad->outbuff[AUDIO_OUTPUT_SAMPLE*2*half];
+
+
+
+ if (!ad->active) {
+
+ for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) {
+ ptr[i]=0;
+ }
+
+ } else {
+
+ //printf("samples: %i\n",AUDIO_OUTPUT_SAMPLE);
+ ad->lock();
+
+ ad->audio_server_process(AUDIO_OUTPUT_SAMPLE,ad->outbuff_32);
+
+ ad->unlock();
+
+ const int32_t* src_buff=ad->outbuff_32;
+
+ for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) {
+
+ ptr[i]=src_buff[i]>>16;
+ }
+ }
+
+
+ /* Output 16-bit PCM STEREO data that is in pcmBuf without changing the volume */
+ sceAudioOutput2OutputBlocking(
+ SCE_AUDIO_VOLUME_0dB*3, //0db at 0x8000, that's obvious
+ ptr
+ );
+
+ if (half)
+ half=0;
+ else
+ half=1;
+
+ }
+
+ sceAudioOutput2Release();
+
+ sceKernelExitThread(SCE_KERNEL_EXIT_SUCCESS);
+ ad->thread_exited=true;
+ return SCE_KERNEL_EXIT_SUCCESS;
+
+}
+
+#endif
+Error AudioDriverAndroid::init(){
+
+ return OK;
+
+
+}
+void AudioDriverAndroid::start(){
+
+
+}
+int AudioDriverAndroid::get_mix_rate() const {
+
+ return 44100;
+}
+AudioDriverSW::OutputFormat AudioDriverAndroid::get_output_format() const{
+
+ return OUTPUT_STEREO;
+}
+void AudioDriverAndroid::lock(){
+
+
+}
+void AudioDriverAndroid::unlock() {
+
+
+}
+void AudioDriverAndroid::finish(){
+
+ }
+
+
+AudioDriverAndroid::AudioDriverAndroid()
+{
+ s_ad=this;
+}
+
diff --git a/platform/android/.old/audio_driver_android.h b/platform/android/.old/audio_driver_android.h
new file mode 100644
index 0000000000..08fbaa927e
--- /dev/null
+++ b/platform/android/.old/audio_driver_android.h
@@ -0,0 +1,29 @@
+#ifndef AUDIO_DRIVER_ANDROID_H
+#define AUDIO_DRIVER_ANDROID_H
+
+#include "servers/audio/audio_server_sw.h"
+
+class AudioDriverAndroid : public AudioDriverSW {
+
+
+ static AudioDriverAndroid* s_ad;
+
+public:
+
+ void set_singleton();
+
+ virtual const char* get_name() const;
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const ;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+
+ AudioDriverAndroid();
+};
+
+#endif // AUDIO_DRIVER_ANDROID_H
diff --git a/platform/android/.old/context_gl_android.cpp b/platform/android/.old/context_gl_android.cpp
new file mode 100644
index 0000000000..e48ed2e7f9
--- /dev/null
+++ b/platform/android/.old/context_gl_android.cpp
@@ -0,0 +1,38 @@
+#include "context_gl_android.h"
+
+#include <GLES2/gl2.h>
+#include "os/os.h"
+void ContextGLAndroid::make_current() {
+
+};
+
+int ContextGLAndroid::get_window_width() {
+
+ return OS::get_singleton()->get_default_video_mode().width;
+};
+
+int ContextGLAndroid::get_window_height() {
+
+ return OS::get_singleton()->get_default_video_mode().height;
+
+};
+
+void ContextGLAndroid::swap_buffers() {
+
+};
+
+Error ContextGLAndroid::initialize() {
+
+ return OK;
+};
+
+
+ContextGLAndroid::ContextGLAndroid() {
+
+
+};
+
+ContextGLAndroid::~ContextGLAndroid() {
+
+};
+
diff --git a/platform/android/.old/context_gl_android.h b/platform/android/.old/context_gl_android.h
new file mode 100644
index 0000000000..bf09d08ad2
--- /dev/null
+++ b/platform/android/.old/context_gl_android.h
@@ -0,0 +1,24 @@
+#ifndef CONTEXT_GL_ANDROID_H
+#define CONTEXT_GL_ANDROID_H
+
+class ContextGLAndroid : public ContextGL {
+
+ enum {
+ COMMAND_BUFFER_SIZE = 1024 * 1024,
+ };
+
+public:
+
+ virtual void make_current();
+
+ virtual int get_window_width();
+ virtual int get_window_height();
+ virtual void swap_buffers();
+
+ virtual Error initialize();
+
+ ContextGLAndroid();
+ ~ContextGLAndroid();
+};
+
+#endif // CONTEXT_GL_ANDROID_H
diff --git a/platform/android/.old/detect.py b/platform/android/.old/detect.py
new file mode 100644
index 0000000000..c29b56aed4
--- /dev/null
+++ b/platform/android/.old/detect.py
@@ -0,0 +1,107 @@
+import os
+import sys
+import string
+
+def can_build():
+
+ import os
+ if (not os.environ.has_key("ANDROID_NDK_ROOT")):
+ print("ANDROID_NDK_ROOT not present, Android disabled.")
+ return False
+ return True
+
+def get_opts():
+
+ return [
+ ('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
+ ('NDK_TOOLCHAIN', 'toolchain to use for the NDK',"arm-eabi-4.4.0"),
+ #android 2.2
+# ('NDK_PLATFORM', 'platform to use for the NDK',"android-8"),
+# ('NDK_TARGET', 'toolchain to use for the NDK',"arm-linux-androideabi-4.4.3"),
+ ]
+
+def get_flags():
+
+ return [
+ ('lua', 'no'),
+ ('tools', 'no'),
+ ('nedmalloc', 'no'),
+ ]
+
+
+
+def configure(env):
+
+
+ print("Godot Android!!!!!")
+
+ env.Append(CPPPATH=['#platform/android'])
+
+ env['OBJSUFFIX'] = ".jandroid.o"
+ env['LIBSUFFIX'] = ".jandroid.a"
+ env['PROGSUFFIX'] = ".jandroid"
+
+ gcc_path=env["ANDROID_NDK_ROOT"]+"/toolchains/"+env["NDK_TARGET"]+"/prebuilt/";
+
+ if (sys.platform.find("linux")==0):
+ gcc_path=gcc_path+"/linux-x86/bin"
+ elif (sys.platform=="darwin"):
+ gcc_path=gcc_path+"/darwin-x86/bin" #this may be wrong
+ elif (os.name=="nt"):
+ gcc_path=gcc_path+"/windows-x86/bin" #this may be wrong
+
+
+
+ env['ENV']['PATH'] = gcc_path+":"+env['ENV']['PATH']
+
+ env['CC'] = gcc_path+'/arm-linux-androideabi-gcc'
+ env['CXX'] = gcc_path+'/arm-linux-androideabi-g++'
+ env['AR'] = gcc_path+"/arm-linux-androideabi-ar"
+
+ import string
+ #include path
+ gcc_include=env["ANDROID_NDK_ROOT"]+"/platforms/"+env["NDK_PLATFORM"]+"/arch-arm/usr/include"
+ ld_sysroot=env["ANDROID_NDK_ROOT"]+"/platforms/"+env["NDK_PLATFORM"]+"/arch-arm"
+ ld_path=env["ANDROID_NDK_ROOT"]+"/platforms/"+env["NDK_PLATFORM"]+"/arch-arm/usr/lib"
+ #cxx_include=env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/system/include"
+ #env.Append(CPPPATH=[gcc_include,cxx_include])
+ env['CCFLAGS'] = string.split('-DNO_THREADS -DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -fno-exceptions -mthumb -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED ')
+
+ env.Append(LDPATH=[ld_path])
+ env.Append(LIBS=['c','m','stdc++','log','GLESv2'])
+
+ env["LINKFLAGS"]= string.split(" -g --sysroot="+ld_sysroot+" -Wl,--no-undefined -Wl,-z,noexecstack")
+ env.Append(LINKFLAGS=["-Wl,-soname,libgodot_android.so"])
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O2', '-ffast-math','-fomit-frame-pointer'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-D_DEBUG', '-g', '-Wall', '-O0', '-DDEBUG_ENABLED'])
+ env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
+
+ env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DNO_FCNTL'])
+
+ env['neon_enabled']=True
+ env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL','-DMPC_FIXED_POINT'])
+# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT'])
+ if (env['android_stl']=='yes'):
+ #env.Append(CCFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/system/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi/include"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi"])
+ env.Append(LIBS=["gnustl_static","supc++"])
+ #env.Append(CCFLAGS=["-I"+env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/stlport/stlport"])
+ #env.Append(CCFLAGS=["-I"+env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include"])
+ #env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/libs/armeabi/libstdc++.a"])
+ else:
+
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/armeabi"])
+ env.Append(LIBS=['gabi++_static'])
+ env.Append(CCFLAGS=["-fno-exceptions",'-DNO_SAFE_CAST'])
diff --git a/platform/android/.old/dir_access_jandroid.cpp b/platform/android/.old/dir_access_jandroid.cpp
new file mode 100644
index 0000000000..649a25a902
--- /dev/null
+++ b/platform/android/.old/dir_access_jandroid.cpp
@@ -0,0 +1,217 @@
+#include "dir_access_jandroid.h"
+#include "file_access_jandroid.h"
+
+jobject DirAccessJAndroid::io=NULL;
+jclass DirAccessJAndroid::cls=NULL;
+JNIEnv * DirAccessJAndroid::env=NULL;
+jmethodID DirAccessJAndroid::_dir_open=NULL;
+jmethodID DirAccessJAndroid::_dir_next=NULL;
+jmethodID DirAccessJAndroid::_dir_close=NULL;
+
+
+DirAccess *DirAccessJAndroid::create_fs() {
+
+ return memnew(DirAccessJAndroid);
+}
+
+bool DirAccessJAndroid::list_dir_begin() {
+
+ list_dir_end();
+
+ jstring js = env->NewStringUTF(current_dir.utf8().get_data());
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return true;
+
+ id=res;
+
+ return false;
+}
+
+String DirAccessJAndroid::get_next(){
+
+ ERR_FAIL_COND_V(id==0,"");
+
+ jstring str= (jstring)env->CallObjectMethod(io,_dir_next,id);
+ if (!str)
+ return "";
+
+ int sl = env->GetStringLength(str);
+ if (sl==0) {
+ env->DeleteLocalRef((jobject)str);
+ return "";
+ }
+
+ CharString cs;
+ cs.resize(sl+1);
+ env->GetStringRegion(str,0,sl,(jchar*)&cs[0]);
+ cs[sl]=0;
+
+ String ret;
+ ret.parse_utf8(&cs[0]);
+ env->DeleteLocalRef((jobject)str);
+
+ return ret;
+
+}
+bool DirAccessJAndroid::current_is_dir() const{
+
+ String sd;
+ if (current_dir=="")
+ sd=current;
+ else
+ sd=current_dir+"/"+current;
+
+ jstring js = env->NewStringUTF(sd.utf8().get_data());
+
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return false;
+
+ env->CallObjectMethod(io,_dir_close,res);
+
+
+ return true;
+}
+void DirAccessJAndroid::list_dir_end(){
+
+ if (id==0)
+ return;
+
+ env->CallObjectMethod(io,_dir_close,id);
+ id=0;
+
+
+}
+
+int DirAccessJAndroid::get_drive_count(){
+
+ return 0;
+}
+String DirAccessJAndroid::get_drive(int p_drive){
+
+ return "";
+}
+
+Error DirAccessJAndroid::change_dir(String p_dir){
+
+ p_dir=p_dir.simplify_path();
+
+ if (p_dir=="" || p_dir=="." || (p_dir==".." && current_dir==""))
+ return OK;
+
+ String new_dir;
+
+ if (p_dir.begins_with("/"))
+ new_dir=p_dir.substr(1,p_dir.length());
+ else if (p_dir.begins_with("res://"))
+ new_dir=p_dir.substr(6,p_dir.length());
+ else //relative
+ new_dir=new_dir+"/"+p_dir;
+
+//test if newdir exists
+ new_dir=new_dir.simplify_path();
+
+ jstring js = env->NewStringUTF(new_dir.utf8().get_data());
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return ERR_INVALID_PARAMETER;
+
+ env->CallObjectMethod(io,_dir_close,res);
+
+
+
+ return OK;
+}
+
+String DirAccessJAndroid::get_current_dir(){
+
+ return "/"+current_dir;
+}
+String DirAccessJAndroid::get_dir_separator() const{
+
+ return "/";
+}
+
+bool DirAccessJAndroid::file_exists(String p_file){
+
+ String sd;
+ if (current_dir=="")
+ sd=p_file;
+ else
+ sd=current_dir+"/"+p_file;
+
+ FileAccessJAndroid *f = memnew(FileAccessJAndroid);
+ bool exists = f->file_exists(sd);
+ memdelete(f);
+
+ return exists;
+}
+
+uint64_t DirAccessJAndroid::get_modified_time(String p_file){
+
+ return 0;
+}
+
+Error DirAccessJAndroid::make_dir(String p_dir){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+Error DirAccessJAndroid::rename(String p_from, String p_to){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+Error DirAccessJAndroid::remove(String p_name){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+//FileType get_file_type() const;
+size_t DirAccessJAndroid::get_space_left() {
+
+ return 0;
+}
+
+void DirAccessJAndroid::make_default() {
+
+ instance_func=create_fs;
+}
+
+void DirAccessJAndroid::setup( JNIEnv *p_env, jobject p_io) {
+
+
+ env=p_env;
+ io=p_io;
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP7");
+
+ jclass c = env->GetObjectClass(io);
+ cls = (jclass)env->NewGlobalRef(c);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP8");
+
+ _dir_open = env->GetMethodID(cls, "dir_open", "(Ljava/lang/String;)I");
+ if(_dir_open != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_open ok!!");
+ }
+ _dir_next = env->GetMethodID(cls, "dir_next", "(I)Ljava/lang/String;");
+ if(_dir_next != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_next ok!!");
+ }
+ _dir_close = env->GetMethodID(cls, "dir_close", "(I)V");
+ if(_dir_close != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_close ok!!");
+ }
+
+// (*env)->CallVoidMethod(env,obj,aMethodID, myvar);
+}
+
+
+DirAccessJAndroid::DirAccessJAndroid() {
+
+ id=0;
+}
+
+DirAccessJAndroid::~DirAccessJAndroid() {
+
+ list_dir_end();;
+}
diff --git a/platform/android/.old/dir_access_jandroid.h b/platform/android/.old/dir_access_jandroid.h
new file mode 100644
index 0000000000..80973004aa
--- /dev/null
+++ b/platform/android/.old/dir_access_jandroid.h
@@ -0,0 +1,63 @@
+#ifndef DIR_ACCESS_JANDROID_H
+#define DIR_ACCESS_JANDROID_H
+
+#include "java_glue.h"
+#include "os/dir_access.h"
+#include <stdio.h>
+
+
+class DirAccessJAndroid : public DirAccess {
+
+ //AAssetDir* aad;
+
+ static jobject io;
+ static jclass cls;
+
+ static jmethodID _dir_open;
+ static jmethodID _dir_next;
+ static jmethodID _dir_close;
+
+ static JNIEnv * env;
+
+ int id;
+
+ String current_dir;
+ String current;
+
+ static DirAccess *create_fs();
+
+public:
+
+ virtual bool list_dir_begin(); ///< This starts dir listing
+ virtual String get_next();
+ virtual bool current_is_dir() const;
+ virtual void list_dir_end(); ///<
+
+ virtual int get_drive_count();
+ virtual String get_drive(int p_drive);
+
+ virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(); ///< return current dir location
+ virtual String get_dir_separator() const ;
+
+ virtual bool file_exists(String p_file);
+ virtual uint64_t get_modified_time(String p_file);
+
+ virtual Error make_dir(String p_dir);
+
+ virtual Error rename(String p_from, String p_to);
+ virtual Error remove(String p_name);
+
+ //virtual FileType get_file_type() const;
+ size_t get_space_left();
+
+ static void make_default();
+
+ static void setup( JNIEnv *env, jobject io);
+ static void update_env( JNIEnv *p_env) { env=p_env; }
+
+ DirAccessJAndroid();
+ ~DirAccessJAndroid();
+};
+
+#endif // DIR_ACCESS_JANDROID_H
diff --git a/platform/android/.old/file_access_jandroid.cpp b/platform/android/.old/file_access_jandroid.cpp
new file mode 100644
index 0000000000..96c064f9f5
--- /dev/null
+++ b/platform/android/.old/file_access_jandroid.cpp
@@ -0,0 +1,204 @@
+#include "file_access_jandroid.h"
+#include "os/os.h"
+#include <unistd.h>
+
+jobject FileAccessJAndroid::io=NULL;
+jclass FileAccessJAndroid::cls;
+jmethodID FileAccessJAndroid::_file_open=0;
+jmethodID FileAccessJAndroid::_file_get_size=0;
+jmethodID FileAccessJAndroid::_file_seek=0;
+jmethodID FileAccessJAndroid::_file_read=0;
+jmethodID FileAccessJAndroid::_file_tell=0;
+jmethodID FileAccessJAndroid::_file_eof=0;
+jmethodID FileAccessJAndroid::_file_close=0;
+
+
+JNIEnv * FileAccessJAndroid::env=NULL;
+
+void FileAccessJAndroid::make_default() {
+
+ create_func=create_jandroid;
+}
+
+FileAccess* FileAccessJAndroid::create_jandroid() {
+
+ return memnew(FileAccessJAndroid);
+}
+
+Error FileAccessJAndroid::open(const String& p_path, int p_mode_flags) {
+
+ if (is_open())
+ close();
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+ //OS::get_singleton()->print("env: %p, io %p, fo: %p\n",env,io,_file_open);
+
+ jstring js = env->NewStringUTF(path.utf8().get_data());
+ int res = env->CallIntMethod(io,_file_open,js,p_mode_flags&WRITE?true:false);
+
+ if (res<=0)
+ return ERR_FILE_CANT_OPEN;
+ id=res;
+
+
+ return OK;
+}
+
+void FileAccessJAndroid::close() {
+
+ if (io==0)
+ return;
+
+ env->CallVoidMethod(io,_file_close,id);
+ id=0;
+
+}
+bool FileAccessJAndroid::is_open() const {
+
+ return id!=0;
+}
+
+void FileAccessJAndroid::seek(size_t p_position) {
+
+ ERR_FAIL_COND(!is_open());
+ env->CallVoidMethod(io,_file_seek,id,p_position);
+}
+void FileAccessJAndroid::seek_end(int64_t p_position) {
+
+ ERR_FAIL_COND(!is_open());
+
+ seek(get_len());
+
+}
+size_t FileAccessJAndroid::get_pos() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_tell,id);
+
+}
+size_t FileAccessJAndroid::get_len() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_get_size,id);
+
+
+}
+
+bool FileAccessJAndroid::eof_reached() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_eof,id);
+
+}
+
+uint8_t FileAccessJAndroid::get_8() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ uint8_t byte;
+ get_buffer(&byte,1);
+ return byte;
+}
+int FileAccessJAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ if (p_length==0)
+ return 0;
+
+ jbyteArray jca = (jbyteArray)env->CallObjectMethod(io,_file_read,id,p_length);
+
+ int len = env->GetArrayLength(jca);
+ env->GetByteArrayRegion(jca,0,len,(jbyte*)p_dst);
+ env->DeleteLocalRef((jobject)jca);
+
+ return len;
+
+}
+
+Error FileAccessJAndroid::get_error() const {
+
+ if (eof_reached())
+ return ERR_FILE_EOF;
+ return OK;
+}
+
+void FileAccessJAndroid::store_8(uint8_t p_dest) {
+
+
+}
+
+bool FileAccessJAndroid::file_exists(const String& p_path) {
+
+ jstring js = env->NewStringUTF(p_path.utf8().get_data());
+ int res = env->CallIntMethod(io,_file_open,js,false);
+ if (res<=0)
+ return false;
+ env->CallVoidMethod(io,_file_close,res);
+ return true;
+
+}
+
+
+void FileAccessJAndroid::setup( JNIEnv *p_env, jobject p_io) {
+
+ io=p_io;
+ env=p_env;
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP5");
+
+ jclass c = env->GetObjectClass(io);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP6");
+ cls=(jclass)env->NewGlobalRef(c);
+
+ _file_open = env->GetMethodID(cls, "file_open", "(Ljava/lang/String;Z)I");
+ if(_file_open != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_open ok!!");
+ }
+ _file_get_size = env->GetMethodID(cls, "file_get_size", "(I)I");
+ if(_file_get_size != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_get_size ok!!");
+ }
+ _file_tell = env->GetMethodID(cls, "file_tell", "(I)I");
+ if(_file_tell != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_tell ok!!");
+ }
+ _file_eof = env->GetMethodID(cls, "file_eof", "(I)Z");
+
+ if(_file_eof != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_eof ok!!");
+ }
+ _file_seek = env->GetMethodID(cls, "file_seek", "(II)V");
+ if(_file_seek != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_seek ok!!");
+ }
+ _file_read = env->GetMethodID(cls, "file_read", "(II)[B");
+ if(_file_read != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_read ok!!");
+ }
+ _file_close = env->GetMethodID(cls, "file_close", "(I)V");
+ if(_file_close != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_close ok!!");
+ }
+
+// (*env)->CallVoidMethod(env,obj,aMethodID, myvar);
+}
+
+
+FileAccessJAndroid::FileAccessJAndroid()
+{
+
+ id=0;
+}
+
+FileAccessJAndroid::~FileAccessJAndroid()
+{
+
+ if (is_open())
+ close();
+}
+
+
diff --git a/platform/android/.old/file_access_jandroid.h b/platform/android/.old/file_access_jandroid.h
new file mode 100644
index 0000000000..7b432fc4fd
--- /dev/null
+++ b/platform/android/.old/file_access_jandroid.h
@@ -0,0 +1,56 @@
+#ifndef FILE_ACCESS_JANDROID_H
+#define FILE_ACCESS_JANDROID_H
+
+#include "java_glue.h"
+#include "os/file_access.h"
+class FileAccessJAndroid : public FileAccess {
+
+ static jobject io;
+ static jclass cls;
+
+ static jmethodID _file_open;
+ static jmethodID _file_get_size;
+ static jmethodID _file_seek;
+ static jmethodID _file_tell;
+ static jmethodID _file_eof;
+ static jmethodID _file_read;
+ static jmethodID _file_close;
+
+
+ static JNIEnv * env;
+
+ int id;
+ static FileAccess* create_jandroid();
+
+
+public:
+
+ virtual Error open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+
+ virtual bool file_exists(const String& p_path); ///< return true if a file exists
+
+ static void make_default();
+
+ static void setup( JNIEnv *env, jobject io);
+ static void update_env( JNIEnv *p_env) { env=p_env; }
+ FileAccessJAndroid();
+ ~FileAccessJAndroid();
+};
+
+#endif // FILE_ACCESS_JANDROID_H
diff --git a/platform/android/.old/gdb.setup.base b/platform/android/.old/gdb.setup.base
new file mode 100644
index 0000000000..a622b1caf6
--- /dev/null
+++ b/platform/android/.old/gdb.setup.base
@@ -0,0 +1,3 @@
+set solib-search-path .
+directory ../..
+file app_process
diff --git a/platform/android/.old/java/AndroidManifest.xml b/platform/android/.old/java/AndroidManifest.xml
new file mode 100644
index 0000000000..c05a681fe3
--- /dev/null
+++ b/platform/android/.old/java/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.godot"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application android:label="@string/godot" android:icon="@drawable/icon">
+ <activity android:name="Godot"
+ android:label="@string/godot"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:configChanges="orientation|keyboardHidden">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+ <uses-feature android:glEsVersion="0x00020000"/>
+ <uses-sdk android:minSdkVersion="8"/>
+
+</manifest>
diff --git a/platform/android/.old/java/build.properties b/platform/android/.old/java/build.properties
new file mode 100644
index 0000000000..ee52d86d94
--- /dev/null
+++ b/platform/android/.old/java/build.properties
@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
diff --git a/platform/android/.old/java/build.xml b/platform/android/.old/java/build.xml
new file mode 100644
index 0000000000..6dc5eb874c
--- /dev/null
+++ b/platform/android/.old/java/build.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Godot" default="help">
+
+<!-- The local.properties file is created and updated by the 'android'
+ tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+ <property name="asset-dir" value="assets" />
+ <!-- The build.properties file can be created by you and is never touched
+ by the 'android' tool. This is the place to change some of the
+ default property values used by the Ant rules.
+ Here are some properties you may want to change/update:
+
+ source.dir
+ The name of the source directory. Default is 'src'.
+ out.dir
+ The name of the output directory. Default is 'bin'.
+
+ Properties related to the SDK location or the project target should
+ be updated using the 'android' tool with the 'update' action.
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems.
+
+ -->
+ <property file="build.properties" />
+
+ <!-- The default.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <property file="default.properties" />
+
+
+ <!-- Required pre-setup import -->
+ <import file="${sdk.dir}/tools/ant/pre_setup.xml" />
+
+
+<!-- extension targets. Uncomment the ones where you want to do custom work
+ in between standard targets -->
+<!--
+ <target name="-pre-build">
+ </target>
+ <target name="-pre-compile">
+ </target>
+
+ [This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir}]
+ <target name="-post-compile">
+ </target>
+-->
+
+ <!-- Execute the Android Setup task that will setup some properties
+ specific to the target, and import the build rules files.
+
+ The rules file is imported from
+ <SDK>/tools/ant/
+ Depending on the project type it can be either:
+ - main_rules.xml
+ - lib_rules.xml
+ - test_rules.xml
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <setup> task.
+ - customize it to your needs.
+ - Customize the whole script.
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, *after* the <setup> task
+ - disable the import of the rules by changing the setup task
+ below to <setup import="false" />.
+ - customize to your needs.
+ -->
+ <setup />
+
+</project>
diff --git a/platform/android/.old/java/default.properties b/platform/android/.old/java/default.properties
new file mode 100644
index 0000000000..e2e8061f26
--- /dev/null
+++ b/platform/android/.old/java/default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
diff --git a/platform/android/.old/java/libs/armeabi/gdbserver b/platform/android/.old/java/libs/armeabi/gdbserver
new file mode 100755
index 0000000000..39634a8147
--- /dev/null
+++ b/platform/android/.old/java/libs/armeabi/gdbserver
Binary files differ
diff --git a/platform/android/.old/java/local.properties b/platform/android/.old/java/local.properties
new file mode 100644
index 0000000000..18e2b6b0cb
--- /dev/null
+++ b/platform/android/.old/java/local.properties
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked in Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/home/red/bin/android-sdk-linux_x86
diff --git a/platform/android/.old/java/proguard.cfg b/platform/android/.old/java/proguard.cfg
new file mode 100644
index 0000000000..12dd0392c0
--- /dev/null
+++ b/platform/android/.old/java/proguard.cfg
@@ -0,0 +1,36 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
diff --git a/platform/android/.old/java/res/drawable-hdpi/icon.png b/platform/android/.old/java/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000000..8074c4c571
--- /dev/null
+++ b/platform/android/.old/java/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/platform/android/.old/java/res/drawable-ldpi/icon.png b/platform/android/.old/java/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000000..1095584ec2
--- /dev/null
+++ b/platform/android/.old/java/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/platform/android/.old/java/res/drawable-mdpi/icon.png b/platform/android/.old/java/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000000..a07c69fa5a
--- /dev/null
+++ b/platform/android/.old/java/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/platform/android/.old/java/res/values/strings.xml b/platform/android/.old/java/res/values/strings.xml
new file mode 100644
index 0000000000..f92332ad4c
--- /dev/null
+++ b/platform/android/.old/java/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot">Godot</string>
+</resources>
diff --git a/platform/android/.old/java/src/com/android/godot/Godot.java b/platform/android/.old/java/src/com/android/godot/Godot.java
new file mode 100644
index 0000000000..475caf3362
--- /dev/null
+++ b/platform/android/.old/java/src/com/android/godot/Godot.java
@@ -0,0 +1,85 @@
+package com.android.godot;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+public class Godot extends Activity
+{
+
+
+ GodotView mView;
+
+ static public GodotIO io;
+
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ io = new GodotIO(getAssets());
+ GodotLib.io=io;
+ mView = new GodotView(getApplication(),io);
+ setContentView(mView);
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override public boolean dispatchTouchEvent (MotionEvent event) {
+
+ super.onTouchEvent(event);
+ int evcount=event.getPointerCount();
+ if (evcount==0)
+ return true;
+
+ int[] arr = new int[event.getPointerCount()*3];
+
+ for(int i=0;i<event.getPointerCount();i++) {
+
+ arr[i*3+0]=(int)event.getPointerId(i);
+ arr[i*3+1]=(int)event.getX(i);
+ arr[i*3+2]=(int)event.getY(i);
+ }
+
+ //System.out.printf("gaction: %d\n",event.getAction());
+ switch(event.getAction()&MotionEvent.ACTION_MASK) {
+
+ case MotionEvent.ACTION_DOWN: {
+ GodotLib.touch(0,0,evcount,arr);
+ //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
+ } break;
+ case MotionEvent.ACTION_MOVE: {
+ GodotLib.touch(1,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+ case MotionEvent.ACTION_POINTER_UP: {
+ int pointer_idx = event.getActionIndex();
+ GodotLib.touch(4,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ int pointer_idx = event.getActionIndex();
+ GodotLib.touch(3,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP: {
+ GodotLib.touch(2,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+
+ }
+ return true;
+ }
+
+}
diff --git a/platform/android/.old/java/src/com/android/godot/GodotIO.java b/platform/android/.old/java/src/com/android/godot/GodotIO.java
new file mode 100644
index 0000000000..a673f79b8d
--- /dev/null
+++ b/platform/android/.old/java/src/com/android/godot/GodotIO.java
@@ -0,0 +1,277 @@
+
+package com.android.godot;
+import java.util.HashMap;
+
+import android.content.res.AssetManager;
+import java.io.InputStream;
+import java.io.IOException;
+
+// Wrapper for native library
+
+public class GodotIO {
+
+
+ AssetManager am;
+
+
+ /// FILES
+
+ public int last_file_id=1;
+
+ class AssetData {
+
+
+ public boolean eof=false;
+ public String path;
+ public InputStream is;
+ public int len;
+ public int pos;
+ }
+
+
+ HashMap<Integer,AssetData> streams;
+
+
+ public int file_open(String path,boolean write) {
+
+ System.out.printf("file_open: Attempt to Open %s\n",path);
+
+ if (write)
+ return -1;
+
+
+ AssetData ad = new AssetData();
+
+ try {
+ ad.is = am.open(path);
+
+ } catch (Exception e) {
+
+ System.out.printf("Exception on file_open: %s\n",e);
+ return -1;
+ }
+
+ try {
+ ad.len=ad.is.available();
+ } catch (Exception e) {
+
+ System.out.printf("Exception availabling on file_open: %s\n",e);
+ return -1;
+ }
+
+ ad.path=path;
+ ad.pos=0;
+ ++last_file_id;
+ streams.put(last_file_id,ad);
+
+ return last_file_id;
+ }
+ public int file_get_size(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return -1;
+ }
+
+ return streams.get(id).len;
+
+ }
+ public void file_seek(int id,int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return;
+ }
+ //seek sucks
+ AssetData ad = streams.get(id);
+ if (bytes>ad.len)
+ bytes=ad.len;
+ if (bytes<0)
+ bytes=0;
+
+ try {
+
+ if (bytes > (int)ad.pos) {
+ int todo=bytes-(int)ad.pos;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ ad.pos=bytes;
+ } else if (bytes<(int)ad.pos) {
+
+ ad.is=am.open(ad.path);
+
+ ad.pos=bytes;
+ int todo=bytes;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ }
+
+ ad.eof=false;
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_seek: %s\n",e);
+ return;
+ }
+
+
+ }
+
+ public int file_tell(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't tell eof for invalid file id: %d\n",id);
+ return 0;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.pos;
+ }
+ public boolean file_eof(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't check eof for invalid file id: %d\n",id);
+ return false;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.eof;
+ }
+
+ public byte[] file_read(int id, int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't read invalid file id: %d\n",id);
+ return new byte[0];
+ }
+
+
+ AssetData ad = streams.get(id);
+
+ if (ad.pos + bytes > ad.len) {
+
+ bytes=ad.len-ad.pos;
+ ad.eof=true;
+ }
+
+
+ if (bytes==0) {
+
+ return new byte[0];
+ }
+
+
+
+ byte[] buf1=new byte[bytes];
+ int r=0;
+ try {
+ r = ad.is.read(buf1);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_read: %s\n",e);
+ return new byte[bytes];
+ }
+
+ if (r==0) {
+ return new byte[0];
+ }
+
+ ad.pos+=r;
+
+ if (r<bytes) {
+
+ byte[] buf2=new byte[r];
+ for(int i=0;i<r;i++)
+ buf2[i]=buf1[i];
+ return buf2;
+ } else {
+
+ return buf1;
+ }
+
+ }
+
+ public void file_close(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_close: Can't close invalid file id: %d\n",id);
+ return;
+ }
+
+ streams.remove(id);
+
+ }
+
+
+ /// DIRECTORIES
+
+
+ class AssetDir {
+
+ public String[] files;
+ public int current;
+ }
+
+ public int last_dir_id=1;
+
+ HashMap<Integer,AssetDir> dirs;
+
+ public int dir_open(String path) {
+
+ AssetDir ad = new AssetDir();
+ ad.current=0;
+
+ try {
+ ad.files = am.list(path);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on dir_open: %s\n",e);
+ return -1;
+ }
+
+ ++last_dir_id;
+ dirs.put(last_dir_id,ad);
+
+ return last_dir_id;
+
+ }
+
+ public String dir_next(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_next: invalid dir id: %d\n",id);
+ return "";
+ }
+
+ AssetDir ad = dirs.get(id);
+ if (ad.current>=ad.files.length)
+ return "";
+ String r = ad.files[ad.current];
+ ad.current++;
+ return r;
+
+ }
+
+ public void dir_close(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_close: invalid dir id: %d\n",id);
+ return;
+ }
+
+ dirs.remove(id);
+ }
+
+
+ GodotIO(AssetManager p_am) {
+
+ am=p_am;
+ streams=new HashMap<Integer,AssetData>();
+ dirs=new HashMap<Integer,AssetDir>();
+
+
+ }
+
+
+}
diff --git a/platform/android/.old/java/src/com/android/godot/GodotLib.java b/platform/android/.old/java/src/com/android/godot/GodotLib.java
new file mode 100644
index 0000000000..2ef49a5222
--- /dev/null
+++ b/platform/android/.old/java/src/com/android/godot/GodotLib.java
@@ -0,0 +1,22 @@
+package com.android.godot;
+
+// Wrapper for native library
+
+public class GodotLib {
+
+
+ public static GodotIO io;
+
+ static {
+ System.loadLibrary("godot_android");
+ }
+
+ /**
+ * @param width the current view width
+ * @param height the current view height
+ */
+
+ public static native void init(int width, int height);
+ public static native void step();
+ public static native void touch(int what,int pointer,int howmany, int[] arr);
+}
diff --git a/platform/android/.old/java/src/com/android/godot/GodotView.java b/platform/android/.old/java/src/com/android/godot/GodotView.java
new file mode 100644
index 0000000000..c5eb3d17ad
--- /dev/null
+++ b/platform/android/.old/java/src/com/android/godot/GodotView.java
@@ -0,0 +1,319 @@
+package com.android.godot;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.content.ContextWrapper;
+
+import java.io.File;
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * A simple GLSurfaceView sub-class that demonstrate how to perform
+ * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
+ * details:
+ *
+ * - The class must use a custom context factory to enable 2.0 rendering.
+ * See ContextFactory class definition below.
+ *
+ * - The class must use a custom EGLConfigChooser to be able to select
+ * an EGLConfig that supports 2.0. This is done by providing a config
+ * specification to eglChooseConfig() that has the attribute
+ * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
+ * set. See ConfigChooser class definition below.
+ *
+ * - The class must select the surface's format, then choose an EGLConfig
+ * that matches it exactly (with regards to red/green/blue/alpha channels
+ * bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
+ */
+class GodotView extends GLSurfaceView {
+ private static String TAG = "GodotView";
+ private static final boolean DEBUG = false;
+ private static Context ctx;
+
+ private static GodotIO io;
+
+ public GodotView(Context context,GodotIO p_io) {
+ super(context);
+ ctx=context;
+ io=p_io;
+
+ init(false, 0, 0);
+ }
+
+ public GodotView(Context context, boolean translucent, int depth, int stencil) {
+ super(context);
+ init(translucent, depth, stencil);
+ }
+
+ private void init(boolean translucent, int depth, int stencil) {
+
+ /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
+ * If we want a translucent one, we should change the surface's
+ * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
+ * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
+ */
+ if (translucent) {
+ this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ /* Setup the context factory for 2.0 rendering.
+ * See ContextFactory class definition below
+ */
+ setEGLContextFactory(new ContextFactory());
+
+ /* We need to choose an EGLConfig that matches the format of
+ * our surface exactly. This is going to be done in our
+ * custom config chooser. See ConfigChooser class definition
+ * below.
+ */
+ setEGLConfigChooser( translucent ?
+ new ConfigChooser(8, 8, 8, 8, depth, stencil) :
+ new ConfigChooser(5, 6, 5, 0, depth, stencil) );
+
+ /* Set the renderer responsible for frame rendering */
+ setRenderer(new Renderer());
+ }
+
+ private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+ Log.w(TAG, "creating OpenGL ES 2.0 context");
+ checkEglError("Before eglCreateContext", egl);
+ int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ checkEglError("After eglCreateContext", egl);
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ egl.eglDestroyContext(display, context);
+ }
+ }
+
+ private static void checkEglError(String prompt, EGL10 egl) {
+ int error;
+ while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
+ Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+ }
+ }
+
+ private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+
+ public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+ mRedSize = r;
+ mGreenSize = g;
+ mBlueSize = b;
+ mAlphaSize = a;
+ mDepthSize = depth;
+ mStencilSize = stencil;
+ }
+
+ /* This EGL config specification is used to specify 2.0 rendering.
+ * We use a minimum size of 4 bits for red/green/blue, but will
+ * perform actual matching in chooseConfig() below.
+ */
+ private static int EGL_OPENGL_ES2_BIT = 4;
+ private static int[] s_configAttribs2 =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+
+ /* Get the number of minimally matching EGL configurations
+ */
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0) {
+ throw new IllegalArgumentException("No configs match configSpec");
+ }
+
+ /* Allocate then read the array of minimally matching EGL configs
+ */
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
+
+ if (DEBUG) {
+ printConfigs(egl, display, configs);
+ }
+ /* Now return the "best" one
+ */
+ return chooseConfig(egl, display, configs);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ for(EGLConfig config : configs) {
+ int d = findConfigAttrib(egl, display, config,
+ EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config,
+ EGL10.EGL_STENCIL_SIZE, 0);
+
+ // We need at least mDepthSize and mStencilSize bits
+ if (d < mDepthSize || s < mStencilSize)
+ continue;
+
+ // We want an *exact* match for red/green/blue/alpha
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+
+ if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)
+ return config;
+ }
+ return null;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+ EGLConfig config, int attribute, int defaultValue) {
+
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private void printConfigs(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ int numConfigs = configs.length;
+ Log.w(TAG, String.format("%d configurations", numConfigs));
+ for (int i = 0; i < numConfigs; i++) {
+ Log.w(TAG, String.format("Configuration %d:\n", i));
+ printConfig(egl, display, configs[i]);
+ }
+ }
+
+ private void printConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig config) {
+ int[] attributes = {
+ EGL10.EGL_BUFFER_SIZE,
+ EGL10.EGL_ALPHA_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_RED_SIZE,
+ EGL10.EGL_DEPTH_SIZE,
+ EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT,
+ EGL10.EGL_MAX_PBUFFER_PIXELS,
+ EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_NATIVE_RENDERABLE,
+ EGL10.EGL_NATIVE_VISUAL_ID,
+ EGL10.EGL_NATIVE_VISUAL_TYPE,
+ 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+ EGL10.EGL_SAMPLES,
+ EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE,
+ EGL10.EGL_TRANSPARENT_RED_VALUE,
+ EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+ EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+ 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+ 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+ 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+ 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+ EGL10.EGL_LUMINANCE_SIZE,
+ EGL10.EGL_ALPHA_MASK_SIZE,
+ EGL10.EGL_COLOR_BUFFER_TYPE,
+ EGL10.EGL_RENDERABLE_TYPE,
+ 0x3042 // EGL10.EGL_CONFORMANT
+ };
+ String[] names = {
+ "EGL_BUFFER_SIZE",
+ "EGL_ALPHA_SIZE",
+ "EGL_BLUE_SIZE",
+ "EGL_GREEN_SIZE",
+ "EGL_RED_SIZE",
+ "EGL_DEPTH_SIZE",
+ "EGL_STENCIL_SIZE",
+ "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID",
+ "EGL_LEVEL",
+ "EGL_MAX_PBUFFER_HEIGHT",
+ "EGL_MAX_PBUFFER_PIXELS",
+ "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE",
+ "EGL_NATIVE_VISUAL_ID",
+ "EGL_NATIVE_VISUAL_TYPE",
+ "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES",
+ "EGL_SAMPLE_BUFFERS",
+ "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE",
+ "EGL_TRANSPARENT_RED_VALUE",
+ "EGL_TRANSPARENT_GREEN_VALUE",
+ "EGL_TRANSPARENT_BLUE_VALUE",
+ "EGL_BIND_TO_TEXTURE_RGB",
+ "EGL_BIND_TO_TEXTURE_RGBA",
+ "EGL_MIN_SWAP_INTERVAL",
+ "EGL_MAX_SWAP_INTERVAL",
+ "EGL_LUMINANCE_SIZE",
+ "EGL_ALPHA_MASK_SIZE",
+ "EGL_COLOR_BUFFER_TYPE",
+ "EGL_RENDERABLE_TYPE",
+ "EGL_CONFORMANT"
+ };
+ int[] value = new int[1];
+ for (int i = 0; i < attributes.length; i++) {
+ int attribute = attributes[i];
+ String name = names[i];
+ if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+ Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
+ } else {
+ // Log.w(TAG, String.format(" %s: failed\n", name));
+ while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+ }
+ }
+ }
+
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ private int[] mValue = new int[1];
+ }
+
+ private static class Renderer implements GLSurfaceView.Renderer {
+
+
+ public void onDrawFrame(GL10 gl) {
+ GodotLib.step();
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+
+
+ System.out.printf("** CONTENT DIR %s\n",ctx.getFilesDir().getPath());
+ GodotLib.init(width, height);
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ // Do nothing.
+ }
+ }
+}
diff --git a/platform/android/.old/java_glue.cpp b/platform/android/.old/java_glue.cpp
new file mode 100644
index 0000000000..38dbcc104f
--- /dev/null
+++ b/platform/android/.old/java_glue.cpp
@@ -0,0 +1,181 @@
+#include "java_glue.h"
+#include "os_android.h"
+#include "main/main.h"
+#include <unistd.h>
+#include "file_access_jandroid.h"
+#include "dir_access_jandroid.h"
+
+static OS_Android *os_android=NULL;
+
+
+struct TST {
+
+ int a;
+ TST() {
+
+ a=5;
+ }
+};
+
+TST tst;
+
+struct JAndroidPointerEvent {
+
+ Vector<OS_Android::TouchPos> points;
+ int pointer;
+ int what;
+};
+
+static List<JAndroidPointerEvent> pointer_events;
+static bool initialized=false;
+static Mutex *input_mutex=NULL;
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_init(JNIEnv * env, jobject obj, jint width, jint height)
+{
+
+
+ if (initialized) // wtf
+ return;
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**INIT EVENT! - %p\n",env);
+
+
+ initialized=true;
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","***************** HELLO FROM JNI!!!!!!!!");
+
+ {
+ //setup IO Object
+
+ jclass cls = env->FindClass("com/android/godot/Godot");
+ if (cls) {
+
+ cls=(jclass)env->NewGlobalRef(cls);
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******CLASS FOUND!!!");
+ }
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP2, %p",cls);
+ jfieldID fid = env->GetStaticFieldID(cls, "io", "Lcom/android/godot/GodotIO;");
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP3 %i",fid);
+ jobject ob = env->GetStaticObjectField(cls,fid);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP4, %p",ob);
+ jobject gob = env->NewGlobalRef(ob);
+
+
+ FileAccessJAndroid::setup(env,gob);
+ DirAccessJAndroid::setup(env,gob);
+ }
+
+
+
+ os_android = new OS_Android(width,height);
+
+ char wd[500];
+ getcwd(wd,500);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","test construction %i\n",tst.a);
+ __android_log_print(ANDROID_LOG_INFO,"godot","running from dir %s\n",wd);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**SETUP");
+
+
+
+#if 0
+ char *args[]={"-test","render",NULL};
+ __android_log_print(ANDROID_LOG_INFO,"godot","pre asdasd setup...");
+ Error err = Main::setup("apk",2,args);
+#else
+ Error err = Main::setup("apk",0,NULL);
+#endif
+ if (err!=OK) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*****UNABLE TO SETUP");
+
+ return; //should exit instead and print the error
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**START");
+
+
+ if (!Main::start()) {
+
+ return; //should exit instead and print the error
+ }
+ input_mutex=Mutex::create();
+
+ os_android->main_loop_begin();
+
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj)
+{
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_ID());
+
+
+
+
+ {
+
+ FileAccessJAndroid::update_env(env);
+ DirAccessJAndroid::update_env(env);
+ }
+
+ input_mutex->lock();
+
+ while(pointer_events.size()) {
+
+ JAndroidPointerEvent jpe=pointer_events.front()->get();
+ os_android->process_touch(jpe.what,jpe.pointer,jpe.points);
+ pointer_events.pop_front();
+ }
+
+ input_mutex->unlock();
+
+
+ if (os_android->main_loop_iterate()==true) {
+
+ return; //should exit instead
+ }
+
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions) {
+
+
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**TOUCH EVENT! - %p-%i\n",env,Thread::get_caller_ID());
+
+
+
+
+
+ Vector<OS_Android::TouchPos> points;
+ for(int i=0;i<count;i++) {
+
+ jint p[3];
+ env->GetIntArrayRegion(positions,i*3,3,p);
+ OS_Android::TouchPos tp;
+ tp.pos=Point2(p[1],p[2]);
+ tp.id=p[0];
+ points.push_back(tp);
+ }
+
+ JAndroidPointerEvent jpe;
+ jpe.pointer=pointer;
+ jpe.points=points;
+ jpe.what=ev;
+
+ input_mutex->lock();
+
+ pointer_events.push_back(jpe);
+
+ input_mutex->unlock();
+ //if (os_android)
+// os_android->process_touch(ev,pointer,points);
+
+}
+
+//Main::cleanup();
+
+//return os.get_exit_code();
diff --git a/platform/android/.old/java_glue.h b/platform/android/.old/java_glue.h
new file mode 100644
index 0000000000..9940af3d7d
--- /dev/null
+++ b/platform/android/.old/java_glue.h
@@ -0,0 +1,16 @@
+#ifndef JAVA_GLUE_H
+#define JAVA_GLUE_H
+
+#include <jni.h>
+#include <android/log.h>
+
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_init(JNIEnv * env, jobject obj, jint width, jint height);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions);
+};
+
+
+
+#endif // JAVA_GLUE_H
diff --git a/platform/android/.old/os_android.cpp b/platform/android/.old/os_android.cpp
new file mode 100644
index 0000000000..ecd87a3af9
--- /dev/null
+++ b/platform/android/.old/os_android.cpp
@@ -0,0 +1,426 @@
+
+#include "os_android.h"
+#include "java_glue.h"
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "servers/visual/visual_server_raster.h"
+
+#include "file_access_jandroid.h"
+#include "dir_access_jandroid.h"
+#include "core/io/file_access_buffered_fa.h"
+#include "main/main.h"
+int OS_Android::get_video_driver_count() const {
+
+ return 1;
+}
+const char * OS_Android::get_video_driver_name(int p_driver) const {
+
+ return "GLES2";
+}
+
+OS::VideoMode OS_Android::get_default_video_mode() const {
+
+ return OS::VideoMode();
+}
+
+int OS_Android::get_audio_driver_count() const {
+
+ return 1;
+}
+const char * OS_Android::get_audio_driver_name(int p_driver) const {
+
+ return "Android";
+}
+
+void OS_Android::initialize_core() {
+
+ OS_Unix::initialize_core();
+ //FileAccessJAndroid::make_default();
+ DirAccessJAndroid::make_default();
+ FileAccessBufferedFA<FileAccessJAndroid>::make_default();
+
+
+}
+
+void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ AudioDriverManagerSW::add_driver(&audio_driver_android);
+
+ rasterizer = memnew( RasterizerGLES2 );
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ visual_server->init();
+ visual_server->cursor_set_visible(false, 0);
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+
+ audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+ audio_server->init();
+
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+
+}
+
+void OS_Android::set_main_loop( MainLoop * p_main_loop ) {
+
+
+
+ main_loop=p_main_loop;
+}
+
+void OS_Android::delete_main_loop() {
+
+ memdelete( main_loop );
+}
+
+void OS_Android::finalize() {
+
+ memdelete(input);
+
+}
+
+
+void OS_Android::vprint(const char* p_format, va_list p_list, bool p_stderr) {
+
+ __android_log_vprint(p_stderr?ANDROID_LOG_ERROR:ANDROID_LOG_INFO,"godot",p_format,p_list);
+}
+
+void OS_Android::print(const char *p_format, ... ) {
+
+ va_list argp;
+ va_start(argp, p_format);
+ __android_log_vprint(ANDROID_LOG_INFO,"godot",p_format,argp);
+ va_end(argp);
+
+}
+
+void OS_Android::alert(const String& p_alert) {
+
+ print("ALERT: %s\n",p_alert.utf8().get_data());
+}
+
+
+void OS_Android::set_mouse_show(bool p_show) {
+
+ //android has no mouse...
+}
+
+void OS_Android::set_mouse_grab(bool p_grab) {
+
+ //it really has no mouse...!
+}
+
+bool OS_Android::is_mouse_grab_enabled() const {
+
+ //*sigh* technology has evolved so much since i was a kid..
+ return false;
+}
+Point2 OS_Android::get_mouse_pos() const {
+
+ return Point2();
+}
+int OS_Android::get_mouse_button_state() const {
+
+ return 0;
+}
+void OS_Android::set_window_title(const String& p_title) {
+
+
+}
+
+//interesting byt not yet
+//void set_clipboard(const String& p_text);
+//String get_clipboard() const;
+
+void OS_Android::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+
+}
+
+OS::VideoMode OS_Android::get_video_mode(int p_screen) const {
+
+ return default_videomode;
+}
+void OS_Android::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+ p_list->push_back(default_videomode);
+}
+
+String OS_Android::get_name() {
+
+ return "Android";
+}
+
+MainLoop *OS_Android::get_main_loop() const {
+
+ return main_loop;
+}
+
+bool OS_Android::can_draw() const {
+
+ return true; //always?
+}
+
+void OS_Android::set_cursor_shape(CursorShape p_shape) {
+
+ //android really really really has no mouse.. how amazing..
+}
+
+void OS_Android::main_loop_begin() {
+
+ if (main_loop)
+ main_loop->init();
+}
+bool OS_Android::main_loop_iterate() {
+
+ if (!main_loop)
+ return false;
+ return Main::iteration();
+}
+
+void OS_Android::main_loop_end() {
+
+ if (main_loop)
+ main_loop->finish();
+
+}
+
+void OS_Android::process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points) {
+
+
+
+ switch(p_what) {
+ case 0: { //gesture begin
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=++last_id;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ main_loop->input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ main_loop->input_event(ev);
+
+ }
+ }
+
+ touch.resize(p_points.size());
+ for(int i=0;i<p_points.size();i++) {
+ touch[i].id=p_points[i].id;
+ touch[i].pos=p_points[i].pos;
+ }
+
+ {
+ //send mouse
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=++last_id;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=true;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ last_mouse=touch[0].pos;
+ main_loop->input_event(ev);
+ }
+
+
+ //send touch
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ main_loop->input_event(ev);
+ }
+
+ } break;
+ case 1: { //motion
+
+
+ if (p_points.size()) {
+ //send mouse, should look for point 0?
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_MOTION;
+ ev.ID=++last_id;
+ ev.mouse_motion.button_mask=BUTTON_MASK_LEFT;
+ 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.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;
+ main_loop->input_event(ev);
+ }
+
+ ERR_FAIL_COND(touch.size()!=p_points.size());
+
+ for(int i=0;i<touch.size();i++) {
+
+ int idx=-1;
+ for(int j=0;j<p_points.size();j++) {
+
+ if (touch[i].id==p_points[j].id) {
+ idx=j;
+ break;
+ }
+
+ }
+
+ ERR_CONTINUE(idx==-1);
+
+ if (touch[i].pos==p_points[idx].pos)
+ continue; //no move unncesearily
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_DRAG;
+ ev.ID=++last_id;
+ ev.screen_drag.index=touch[i].id;
+ ev.screen_drag.x=p_points[idx].pos.x;
+ ev.screen_drag.y=p_points[idx].pos.y;
+ ev.screen_drag.x=p_points[idx].pos.x - touch[i].pos.x;
+ ev.screen_drag.y=p_points[idx].pos.y - touch[i].pos.y;
+ main_loop->input_event(ev);
+ touch[i].pos=p_points[idx].pos;
+ }
+
+
+ } break;
+ case 2: { //release
+
+
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=++last_id;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ main_loop->input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ main_loop->input_event(ev);
+
+ }
+ }
+
+ } break;
+ case 3: { // add tuchi
+
+
+
+
+
+ ERR_FAIL_INDEX(p_pointer,p_points.size());
+
+ TouchPos tp=p_points[p_pointer];
+ touch.push_back(tp);
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=tp.id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=tp.pos.x;
+ ev.screen_touch.y=tp.pos.y;
+ main_loop->input_event(ev);
+
+ } break;
+ case 4: {
+
+
+ for(int i=0;i<touch.size();i++) {
+ if (touch[i].id==p_pointer) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=++last_id;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ main_loop->input_event(ev);
+ touch.remove(i);
+ i--;
+ }
+ }
+
+ } break;
+
+ }
+
+}
+
+OS_Android::OS_Android(int p_video_width,int p_video_height) {
+
+ default_videomode.width=p_video_width;
+ default_videomode.height=p_video_height;
+ default_videomode.fullscreen=true;
+ default_videomode.resizable=false;
+ main_loop=NULL;
+ last_id=1;
+}
+
+OS_Android::~OS_Android() {
+
+
+}
diff --git a/platform/android/.old/os_android.h b/platform/android/.old/os_android.h
new file mode 100644
index 0000000000..25ed84851a
--- /dev/null
+++ b/platform/android/.old/os_android.h
@@ -0,0 +1,108 @@
+#ifndef OS_ANDROID_H
+#define OS_ANDROID_H
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+#include "os/main_loop.h"
+#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/physics_2d/physics_2d_server_sw.h"
+#include "servers/visual/rasterizer.h"
+#include "audio_driver_android.h"
+
+class OS_Android : public OS_Unix {
+public:
+
+ struct TouchPos {
+ int id;
+ Point2 pos;
+ };
+private:
+
+ Vector<TouchPos> touch;
+
+ Point2 last_mouse;
+ unsigned int last_id;
+
+
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+// AudioDriverPSP audio_driver_psp;
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+ AudioDriverAndroid audio_driver_android;
+ InputDefault *input;
+
+ VideoMode default_videomode;
+ MainLoop * main_loop;
+public:
+
+
+ void initialize_core();
+
+ // functions used by main to initialize/deintialize the OS
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+
+
+ typedef int64_t ProcessID;
+
+ 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 set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ //virtual void set_clipboard(const String& p_text);
+ //virtual String get_clipboard() const;
+
+ virtual void set_screen_orientation(ScreenOrientation p_orientation);
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ 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 String get_name();
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ void main_loop_begin();
+ bool main_loop_iterate();
+ void main_loop_end();
+
+ void process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points);
+ OS_Android(int p_video_width,int p_video_height);
+ ~OS_Android();
+
+};
+
+#endif
diff --git a/platform/android/.old/platform_config.h b/platform/android/.old/platform_config.h
new file mode 100644
index 0000000000..dad24432a5
--- /dev/null
+++ b/platform/android/.old/platform_config.h
@@ -0,0 +1 @@
+#include <alloca.h>
diff --git a/platform/android/.old/run_debug.sh b/platform/android/.old/run_debug.sh
new file mode 100755
index 0000000000..e39193bd55
--- /dev/null
+++ b/platform/android/.old/run_debug.sh
@@ -0,0 +1,40 @@
+
+# com.android.godot
+# for this, need to push gdbserver to device
+# adb push [location]/gdbserver /data/local
+
+# run
+
+DEBUG_PORT=5039
+GDB_PATH="$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb"
+
+#kill existing previous gdbserver if exists
+adb shell killall gdbserver
+run-as com.android.godot killall com.android.godot
+run-as com.android.godot killall gdbserver
+#get data dir of the app
+adb pull /system/bin/app_process app_process
+
+DATA_DIR=`adb shell run-as com.android.godot /system/bin/sh -c pwd | tr -d '\n\r'`
+echo "DATA DIR IS $DATA_DIR"
+#start app
+adb shell am start -n com.android.godot/com.android.godot.Godot
+#get the pid of the app
+PID=`adb shell pidof com.android.godot | tr -d '\n\r'`
+echo "PID IS: $PID hoho"
+#launch gdbserver
+DEBUG_SOCKET=debug-socket
+#echo adb shell /data/local/gdbserver +debug-socket --attach $PID
+adb shell run-as com.android.godot lib/gdbserver +$DEBUG_SOCKET --attach $PID &
+sleep 2s
+#adb shell /data/local/gdbserver localhost:$DEBUG_PORT --attach $PID &
+#setup network connection
+adb forward tcp:$DEBUG_PORT localfilesystem:$DATA_DIR/$DEBUG_SOCKET
+cp gdb.setup.base gdb.setup
+echo "target remote :$DEBUG_PORT" >> gdb.setup
+#echo "file
+$GDB_PATH -x gdb.setup
+
+
+
+
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template
new file mode 100644
index 0000000000..208d24059e
--- /dev/null
+++ b/platform/android/AndroidManifest.xml.template
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.godot.game"
+ android:versionCode="1"
+ android:versionName="1.0"
+ android:installLocation="preferExternal"
+ >
+ <application android:label="@string/godot_project_name_string" android:icon="@drawable/icon">
+ <activity android:name="com.android.godot.Godot"
+ android:label="@string/godot_project_name_string"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+
+
+
+$$ADD_APPLICATION_CHUNKS$$
+
+ </application>
+ <uses-feature android:glEsVersion="0x00020000"/>
+ <uses-permission android:name="android.permission.INTERNET"></uses-permission>
+ <uses-permission android:name="android.permission.READ_CONTACTS"/>
+ <uses-permission android:name="com.android.vending.BILLING" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="11"/>
+
+</manifest>
diff --git a/platform/android/SCsub b/platform/android/SCsub
new file mode 100644
index 0000000000..327b1ffe09
--- /dev/null
+++ b/platform/android/SCsub
@@ -0,0 +1,66 @@
+import shutil
+
+Import('env')
+
+android_files = [
+
+ 'os_android.cpp',
+ 'godot_android.cpp',
+ 'file_access_android.cpp',
+ 'dir_access_android.cpp',
+ 'audio_driver_android.cpp',
+ 'file_access_jandroid.cpp',
+ 'dir_access_jandroid.cpp',
+ 'thread_jandroid.cpp',
+ 'audio_driver_jandroid.cpp',
+ 'android_native_app_glue.c',
+ 'java_glue.cpp'
+]
+
+#env.Depends('#core/math/vector3.h', 'vector3_psp.h')
+
+#obj = env.SharedObject('godot_android.cpp')
+
+env_android = env.Clone()
+if env['target'] == "profile":
+ env_android.Append(CPPFLAGS=['-DPROFILER_ENABLED'])
+
+android_objects=[]
+for x in android_files:
+ android_objects.append( env_android.SharedObject( x ) )
+
+prog = None
+
+abspath=env.Dir(".").abspath
+
+
+pp_basein = open(abspath+"/project.properties.template","rb")
+pp_baseout = open(abspath+"/java/project.properties","wb")
+pp_baseout.write( pp_basein.read() )
+refcount=1
+for x in env.android_source_modules:
+ pp_baseout.write("android.library.reference."+str(refcount)+"="+x+"\n")
+ refcount+=1
+
+
+
+pp_baseout.close()
+
+
+pp_basein = open(abspath+"/AndroidManifest.xml.template","rb")
+pp_baseout = open(abspath+"/java/AndroidManifest.xml","wb")
+manifest = pp_basein.read()
+manifest = manifest.replace("$$ADD_APPLICATION_CHUNKS$$",env.android_manifest_chunk)
+pp_baseout.write( manifest )
+
+
+for x in env.android_source_files:
+ shutil.copy(x,abspath+"/java/src/com/android/godot")
+
+for x in env.android_module_libraries:
+ shutil.copy(x,abspath+"/java/libs")
+
+
+env_android.SharedLibrary("#platform/android/libgodot_android.so",[android_objects])
+
+env.Command('#bin/libgodot_android.so', '#platform/android/libgodot_android.so', Copy('bin/libgodot_android.so', 'platform/android/libgodot_android.so'))
diff --git a/platform/android/android_native_app_glue.c b/platform/android/android_native_app_glue.c
new file mode 100644
index 0000000000..965f6284cd
--- /dev/null
+++ b/platform/android/android_native_app_glue.c
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include <jni.h>
+
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/resource.h>
+
+#include "android_native_app_glue.h"
+#include <android/log.h>
+
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
+
+static void free_saved_state(struct android_app* android_app) {
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->savedState != NULL) {
+ free(android_app->savedState);
+ android_app->savedState = NULL;
+ android_app->savedStateSize = 0;
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+int8_t android_app_read_cmd(struct android_app* android_app) {
+ int8_t cmd;
+ if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
+ switch (cmd) {
+ case APP_CMD_SAVE_STATE:
+ free_saved_state(android_app);
+ break;
+ }
+ return cmd;
+ } else {
+ LOGI("No data on command pipe!");
+ }
+ return -1;
+}
+
+static void print_cur_config(struct android_app* android_app) {
+ char lang[2], country[2];
+ AConfiguration_getLanguage(android_app->config, lang);
+ AConfiguration_getCountry(android_app->config, country);
+
+ LOGI("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
+ "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
+ "modetype=%d modenight=%d",
+ AConfiguration_getMcc(android_app->config),
+ AConfiguration_getMnc(android_app->config),
+ lang[0], lang[1], country[0], country[1],
+ AConfiguration_getOrientation(android_app->config),
+ AConfiguration_getTouchscreen(android_app->config),
+ AConfiguration_getDensity(android_app->config),
+ AConfiguration_getKeyboard(android_app->config),
+ AConfiguration_getNavigation(android_app->config),
+ AConfiguration_getKeysHidden(android_app->config),
+ AConfiguration_getNavHidden(android_app->config),
+ AConfiguration_getSdkVersion(android_app->config),
+ AConfiguration_getScreenSize(android_app->config),
+ AConfiguration_getScreenLong(android_app->config),
+ AConfiguration_getUiModeType(android_app->config),
+ AConfiguration_getUiModeNight(android_app->config));
+}
+
+void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
+ switch (cmd) {
+ case APP_CMD_INPUT_CHANGED:
+ LOGI("APP_CMD_INPUT_CHANGED\n");
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->inputQueue != NULL) {
+ AInputQueue_detachLooper(android_app->inputQueue);
+ }
+ android_app->inputQueue = android_app->pendingInputQueue;
+ if (android_app->inputQueue != NULL) {
+ LOGI("Attaching input queue to looper");
+ AInputQueue_attachLooper(android_app->inputQueue,
+ android_app->looper, LOOPER_ID_INPUT, NULL,
+ &android_app->inputPollSource);
+ }
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_INIT_WINDOW:
+ LOGI("APP_CMD_INIT_WINDOW\n");
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->window = android_app->pendingWindow;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_TERM_WINDOW:
+ LOGI("APP_CMD_TERM_WINDOW\n");
+ pthread_cond_broadcast(&android_app->cond);
+ break;
+
+ case APP_CMD_RESUME:
+ case APP_CMD_START:
+ case APP_CMD_PAUSE:
+ case APP_CMD_STOP:
+ LOGI("activityState=%d\n", cmd);
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->activityState = cmd;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_CONFIG_CHANGED:
+ LOGI("APP_CMD_CONFIG_CHANGED\n");
+ AConfiguration_fromAssetManager(android_app->config,
+ android_app->activity->assetManager);
+ print_cur_config(android_app);
+ break;
+
+ case APP_CMD_DESTROY:
+ LOGI("APP_CMD_DESTROY\n");
+ android_app->destroyRequested = 1;
+ break;
+ }
+}
+
+void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
+ switch (cmd) {
+ case APP_CMD_TERM_WINDOW:
+ LOGI("APP_CMD_TERM_WINDOW\n");
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->window = NULL;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_SAVE_STATE:
+ LOGI("APP_CMD_SAVE_STATE\n");
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->stateSaved = 1;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_RESUME:
+ free_saved_state(android_app);
+ break;
+ }
+}
+
+void app_dummy() {
+
+}
+
+static void android_app_destroy(struct android_app* android_app) {
+ LOGI("android_app_destroy!");
+ free_saved_state(android_app);
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->inputQueue != NULL) {
+ AInputQueue_detachLooper(android_app->inputQueue);
+ }
+ AConfiguration_delete(android_app->config);
+ android_app->destroyed = 1;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ // Can't touch android_app object after this.
+}
+
+static void process_input(struct android_app* app, struct android_poll_source* source) {
+ AInputEvent* event = NULL;
+ if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
+ LOGI("New input event: type=%d\n", AInputEvent_getType(event));
+ if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
+ return;
+ }
+ int32_t handled = 0;
+ if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
+ AInputQueue_finishEvent(app->inputQueue, event, handled);
+ } else {
+ LOGI("Failure reading next input event: %s\n", strerror(errno));
+ }
+}
+
+static void process_cmd(struct android_app* app, struct android_poll_source* source) {
+ int8_t cmd = android_app_read_cmd(app);
+ android_app_pre_exec_cmd(app, cmd);
+ if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
+ android_app_post_exec_cmd(app, cmd);
+}
+
+static void* android_app_entry(void* param) {
+ struct android_app* android_app = (struct android_app*)param;
+
+ android_app->config = AConfiguration_new();
+ AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
+
+ print_cur_config(android_app);
+
+ android_app->cmdPollSource.id = LOOPER_ID_MAIN;
+ android_app->cmdPollSource.app = android_app;
+ android_app->cmdPollSource.process = process_cmd;
+ android_app->inputPollSource.id = LOOPER_ID_INPUT;
+ android_app->inputPollSource.app = android_app;
+ android_app->inputPollSource.process = process_input;
+
+ ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+ ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
+ &android_app->cmdPollSource);
+ android_app->looper = looper;
+
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->running = 1;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+
+ android_main(android_app);
+
+ android_app_destroy(android_app);
+ return NULL;
+}
+
+// --------------------------------------------------------------------
+// Native activity interaction (called from main thread)
+// --------------------------------------------------------------------
+
+static struct android_app* android_app_create(ANativeActivity* activity,
+ void* savedState, size_t savedStateSize) {
+ struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
+ memset(android_app, 0, sizeof(struct android_app));
+ android_app->activity = activity;
+
+ pthread_mutex_init(&android_app->mutex, NULL);
+ pthread_cond_init(&android_app->cond, NULL);
+
+ if (savedState != NULL) {
+ android_app->savedState = malloc(savedStateSize);
+ android_app->savedStateSize = savedStateSize;
+ memcpy(android_app->savedState, savedState, savedStateSize);
+ }
+
+ int msgpipe[2];
+ if (pipe(msgpipe)) {
+ LOGI("could not create pipe: %s", strerror(errno));
+ }
+ android_app->msgread = msgpipe[0];
+ android_app->msgwrite = msgpipe[1];
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
+
+ // Wait for thread to start.
+ pthread_mutex_lock(&android_app->mutex);
+ while (!android_app->running) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+
+ return android_app;
+}
+
+static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
+ if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
+ LOGI("Failure writing android_app cmd: %s\n", strerror(errno));
+ }
+}
+
+static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->pendingInputQueue = inputQueue;
+ android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
+ while (android_app->inputQueue != android_app->pendingInputQueue) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->pendingWindow != NULL) {
+ android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
+ }
+ android_app->pendingWindow = window;
+ if (window != NULL) {
+ android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
+ }
+ while (android_app->window != android_app->pendingWindow) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app_write_cmd(android_app, cmd);
+ while (android_app->activityState != cmd) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_free(struct android_app* android_app) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app_write_cmd(android_app, APP_CMD_DESTROY);
+ while (!android_app->destroyed) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+
+ close(android_app->msgread);
+ close(android_app->msgwrite);
+ pthread_cond_destroy(&android_app->cond);
+ pthread_mutex_destroy(&android_app->mutex);
+ free(android_app);
+}
+
+static void onDestroy(ANativeActivity* activity) {
+ LOGI("Destroy: %p\n", activity);
+ android_app_free((struct android_app*)activity->instance);
+}
+
+static void onStart(ANativeActivity* activity) {
+ LOGI("Start: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
+}
+
+static void onResume(ANativeActivity* activity) {
+ LOGI("Resume: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
+}
+
+static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
+ struct android_app* android_app = (struct android_app*)activity->instance;
+ void* savedState = NULL;
+
+ LOGI("SaveInstanceState: %p\n", activity);
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->stateSaved = 0;
+ android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
+ while (!android_app->stateSaved) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+
+ if (android_app->savedState != NULL) {
+ savedState = android_app->savedState;
+ *outLen = android_app->savedStateSize;
+ android_app->savedState = NULL;
+ android_app->savedStateSize = 0;
+ }
+
+ pthread_mutex_unlock(&android_app->mutex);
+
+ return savedState;
+}
+
+static void onPause(ANativeActivity* activity) {
+ LOGI("Pause: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
+}
+
+static void onStop(ANativeActivity* activity) {
+ LOGI("Stop: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
+}
+
+static void onConfigurationChanged(ANativeActivity* activity) {
+ struct android_app* android_app = (struct android_app*)activity->instance;
+ LOGI("ConfigurationChanged: %p\n", activity);
+ android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
+}
+
+static void onLowMemory(ANativeActivity* activity) {
+ struct android_app* android_app = (struct android_app*)activity->instance;
+ LOGI("LowMemory: %p\n", activity);
+ android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
+}
+
+static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
+ LOGI("WindowFocusChanged: %p -- %d\n", activity, focused);
+ android_app_write_cmd((struct android_app*)activity->instance,
+ focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
+}
+
+static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
+ LOGI("NativeWindowCreated: %p -- %p\n", activity, window);
+ android_app_set_window((struct android_app*)activity->instance, window);
+}
+
+static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
+ LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
+ android_app_set_window((struct android_app*)activity->instance, NULL);
+}
+
+static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
+ LOGI("InputQueueCreated: %p -- %p\n", activity, queue);
+ android_app_set_input((struct android_app*)activity->instance, queue);
+}
+
+static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
+ LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue);
+ android_app_set_input((struct android_app*)activity->instance, NULL);
+}
+
+void ANativeActivity_onCreate(ANativeActivity* activity,
+ void* savedState, size_t savedStateSize) {
+ LOGI("Creating: %p\n", activity);
+ activity->callbacks->onDestroy = onDestroy;
+ activity->callbacks->onStart = onStart;
+ activity->callbacks->onResume = onResume;
+ activity->callbacks->onSaveInstanceState = onSaveInstanceState;
+ activity->callbacks->onPause = onPause;
+ activity->callbacks->onStop = onStop;
+ activity->callbacks->onConfigurationChanged = onConfigurationChanged;
+ activity->callbacks->onLowMemory = onLowMemory;
+ activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
+ activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
+ activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
+ activity->callbacks->onInputQueueCreated = onInputQueueCreated;
+ activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
+
+ activity->instance = android_app_create(activity, savedState, savedStateSize);
+}
+#endif
diff --git a/platform/android/android_native_app_glue.h b/platform/android/android_native_app_glue.h
new file mode 100644
index 0000000000..fe8684b5d2
--- /dev/null
+++ b/platform/android/android_native_app_glue.h
@@ -0,0 +1,378 @@
+/*************************************************************************/
+/* android_native_app_glue.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _ANDROID_NATIVE_APP_GLUE_H
+#define _ANDROID_NATIVE_APP_GLUE_H
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include <poll.h>
+#include <pthread.h>
+#include <sched.h>
+
+#include <android/configuration.h>
+#include <android/looper.h>
+#include <android/native_activity.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The native activity interface provided by <android/native_activity.h>
+ * is based on a set of application-provided callbacks that will be called
+ * by the Activity's main thread when certain events occur.
+ *
+ * This means that each one of this callbacks _should_ _not_ block, or they
+ * risk having the system force-close the application. This programming
+ * model is direct, lightweight, but constraining.
+ *
+ * The 'threaded_native_app' static library is used to provide a different
+ * execution model where the application can implement its own main event
+ * loop in a different thread instead. Here's how it works:
+ *
+ * 1/ The application must provide a function named "android_main()" that
+ * will be called when the activity is created, in a new thread that is
+ * distinct from the activity's main thread.
+ *
+ * 2/ android_main() receives a pointer to a valid "android_app" structure
+ * that contains references to other important objects, e.g. the
+ * ANativeActivity obejct instance the application is running in.
+ *
+ * 3/ the "android_app" object holds an ALooper instance that already
+ * listens to two important things:
+ *
+ * - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX
+ * declarations below.
+ *
+ * - input events coming from the AInputQueue attached to the activity.
+ *
+ * Each of these correspond to an ALooper identifier returned by
+ * ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT,
+ * respectively.
+ *
+ * Your application can use the same ALooper to listen to additional
+ * file-descriptors. They can either be callback based, or with return
+ * identifiers starting with LOOPER_ID_USER.
+ *
+ * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event,
+ * the returned data will point to an android_poll_source structure. You
+ * can call the process() function on it, and fill in android_app->onAppCmd
+ * and android_app->onInputEvent to be called for your own processing
+ * of the event.
+ *
+ * Alternatively, you can call the low-level functions to read and process
+ * the data directly... look at the process_cmd() and process_input()
+ * implementations in the glue to see how to do this.
+ *
+ * See the sample named "native-activity" that comes with the NDK with a
+ * full usage example. Also look at the JavaDoc of NativeActivity.
+ */
+
+struct android_app;
+
+/**
+ * Data associated with an ALooper fd that will be returned as the "outData"
+ * when that source has data ready.
+ */
+struct android_poll_source {
+ // The identifier of this source. May be LOOPER_ID_MAIN or
+ // LOOPER_ID_INPUT.
+ int32_t id;
+
+ // The android_app this ident is associated with.
+ struct android_app* app;
+
+ // Function to call to perform the standard processing of data from
+ // this source.
+ void (*process)(struct android_app* app, struct android_poll_source* source);
+};
+
+/**
+ * This is the interface for the standard glue code of a threaded
+ * application. In this model, the application's code is running
+ * in its own thread separate from the main thread of the process.
+ * It is not required that this thread be associated with the Java
+ * VM, although it will need to be in order to make JNI calls any
+ * Java objects.
+ */
+struct android_app {
+ // The application can place a pointer to its own state object
+ // here if it likes.
+ void* userData;
+
+ // Fill this in with the function to process main app commands (APP_CMD_*)
+ void (*onAppCmd)(struct android_app* app, int32_t cmd);
+
+ // Fill this in with the function to process input events. At this point
+ // the event has already been pre-dispatched, and it will be finished upon
+ // return. Return 1 if you have handled the event, 0 for any default
+ // dispatching.
+ int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
+
+ // The ANativeActivity object instance that this app is running in.
+ ANativeActivity* activity;
+
+ // The current configuration the app is running in.
+ AConfiguration* config;
+
+ // This is the last instance's saved state, as provided at creation time.
+ // It is NULL if there was no state. You can use this as you need; the
+ // memory will remain around until you call android_app_exec_cmd() for
+ // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
+ // These variables should only be changed when processing a APP_CMD_SAVE_STATE,
+ // at which point they will be initialized to NULL and you can malloc your
+ // state and place the information here. In that case the memory will be
+ // freed for you later.
+ void* savedState;
+ size_t savedStateSize;
+
+ // The ALooper associated with the app's thread.
+ ALooper* looper;
+
+ // When non-NULL, this is the input queue from which the app will
+ // receive user input events.
+ AInputQueue* inputQueue;
+
+ // When non-NULL, this is the window surface that the app can draw in.
+ ANativeWindow* window;
+
+ // Current content rectangle of the window; this is the area where the
+ // window's content should be placed to be seen by the user.
+ ARect contentRect;
+
+ // Current state of the app's activity. May be either APP_CMD_START,
+ // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
+ int activityState;
+
+ // This is non-zero when the application's NativeActivity is being
+ // destroyed and waiting for the app thread to complete.
+ int destroyRequested;
+
+ // -------------------------------------------------
+ // Below are "private" implementation of the glue code.
+
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+
+ int msgread;
+ int msgwrite;
+
+ pthread_t thread;
+
+ struct android_poll_source cmdPollSource;
+ struct android_poll_source inputPollSource;
+
+ int running;
+ int stateSaved;
+ int destroyed;
+ int redrawNeeded;
+ AInputQueue* pendingInputQueue;
+ ANativeWindow* pendingWindow;
+ ARect pendingContentRect;
+};
+
+enum {
+ /**
+ * Looper data ID of commands coming from the app's main thread, which
+ * is returned as an identifier from ALooper_pollOnce(). The data for this
+ * identifier is a pointer to an android_poll_source structure.
+ * These can be retrieved and processed with android_app_read_cmd()
+ * and android_app_exec_cmd().
+ */
+ LOOPER_ID_MAIN = 1,
+
+ /**
+ * Looper data ID of events coming from the AInputQueue of the
+ * application's window, which is returned as an identifier from
+ * ALooper_pollOnce(). The data for this identifier is a pointer to an
+ * android_poll_source structure. These can be read via the inputQueue
+ * object of android_app.
+ */
+ LOOPER_ID_INPUT = 2,
+
+ /**
+ * Start of user-defined ALooper identifiers.
+ */
+ LOOPER_ID_USER = 3,
+};
+
+enum {
+ /**
+ * Command from main thread: the AInputQueue has changed. Upon processing
+ * this command, android_app->inputQueue will be updated to the new queue
+ * (or NULL).
+ */
+ APP_CMD_INPUT_CHANGED,
+
+ /**
+ * Command from main thread: a new ANativeWindow is ready for use. Upon
+ * receiving this command, android_app->window will contain the new window
+ * surface.
+ */
+ APP_CMD_INIT_WINDOW,
+
+ /**
+ * Command from main thread: the existing ANativeWindow needs to be
+ * terminated. Upon receiving this command, android_app->window still
+ * contains the existing window; after calling android_app_exec_cmd
+ * it will be set to NULL.
+ */
+ APP_CMD_TERM_WINDOW,
+
+ /**
+ * Command from main thread: the current ANativeWindow has been resized.
+ * Please redraw with its new size.
+ */
+ APP_CMD_WINDOW_RESIZED,
+
+ /**
+ * Command from main thread: the system needs that the current ANativeWindow
+ * be redrawn. You should redraw the window before handing this to
+ * android_app_exec_cmd() in order to avoid transient drawing glitches.
+ */
+ APP_CMD_WINDOW_REDRAW_NEEDED,
+
+ /**
+ * Command from main thread: the content area of the window has changed,
+ * such as from the soft input window being shown or hidden. You can
+ * find the new content rect in android_app::contentRect.
+ */
+ APP_CMD_CONTENT_RECT_CHANGED,
+
+ /**
+ * Command from main thread: the app's activity window has gained
+ * input focus.
+ */
+ APP_CMD_GAINED_FOCUS,
+
+ /**
+ * Command from main thread: the app's activity window has lost
+ * input focus.
+ */
+ APP_CMD_LOST_FOCUS,
+
+ /**
+ * Command from main thread: the current device configuration has changed.
+ */
+ APP_CMD_CONFIG_CHANGED,
+
+ /**
+ * Command from main thread: the system is running low on memory.
+ * Try to reduce your memory use.
+ */
+ APP_CMD_LOW_MEMORY,
+
+ /**
+ * Command from main thread: the app's activity has been started.
+ */
+ APP_CMD_START,
+
+ /**
+ * Command from main thread: the app's activity has been resumed.
+ */
+ APP_CMD_RESUME,
+
+ /**
+ * Command from main thread: the app should generate a new saved state
+ * for itself, to restore from later if needed. If you have saved state,
+ * allocate it with malloc and place it in android_app.savedState with
+ * the size in android_app.savedStateSize. The will be freed for you
+ * later.
+ */
+ APP_CMD_SAVE_STATE,
+
+ /**
+ * Command from main thread: the app's activity has been paused.
+ */
+ APP_CMD_PAUSE,
+
+ /**
+ * Command from main thread: the app's activity has been stopped.
+ */
+ APP_CMD_STOP,
+
+ /**
+ * Command from main thread: the app's activity is being destroyed,
+ * and waiting for the app thread to clean up and exit before proceeding.
+ */
+ APP_CMD_DESTROY,
+};
+
+/**
+ * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
+ * app command message.
+ */
+int8_t android_app_read_cmd(struct android_app* android_app);
+
+/**
+ * Call with the command returned by android_app_read_cmd() to do the
+ * initial pre-processing of the given command. You can perform your own
+ * actions for the command after calling this function.
+ */
+void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
+
+/**
+ * Call with the command returned by android_app_read_cmd() to do the
+ * final post-processing of the given command. You must have done your own
+ * actions for the command before calling this function.
+ */
+void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
+
+/**
+ * Dummy function you can call to ensure glue code isn't stripped.
+ */
+void app_dummy();
+
+/**
+ * This is the function that application code must implement, representing
+ * the main entry to the app.
+ */
+extern void android_main(struct android_app* app);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_NATIVE_APP_GLUE_H */
+#endif
diff --git a/platform/android/audio_driver_android.cpp b/platform/android/audio_driver_android.cpp
new file mode 100644
index 0000000000..4f7b4ee348
--- /dev/null
+++ b/platform/android/audio_driver_android.cpp
@@ -0,0 +1,393 @@
+/*************************************************************************/
+/* audio_driver_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "audio_driver_android.h"
+#include <string.h>
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+
+
+
+
+#define MAX_NUMBER_INTERFACES 3
+#define MAX_NUMBER_OUTPUT_DEVICES 6
+
+/* Structure for passing information to callback function */
+
+
+void AudioDriverAndroid::_buffer_callback(
+ SLAndroidSimpleBufferQueueItf queueItf
+ /* SLuint32 eventFlags,
+ const void * pBuffer,
+ SLuint32 bufferSize,
+ SLuint32 dataUsed*/) {
+
+
+
+ if (mutex)
+ mutex->lock();
+
+ audio_server_process(buffer_size,mixdown_buffer);
+
+ if (mutex)
+ mutex->unlock();
+
+
+ const int32_t* src_buff=mixdown_buffer;
+
+ int16_t *ptr = (int16_t*)buffers[last_free];
+ last_free=(last_free+1)%BUFFER_COUNT;
+
+ for(int i=0;i<buffer_size*2;i++) {
+
+ ptr[i]=src_buff[i]>>16;
+ }
+
+ (*queueItf)->Enqueue(queueItf, ptr, 4 * buffer_size);
+
+
+#if 0
+ SLresult res;
+ CallbackCntxt *pCntxt = (CallbackCntxt*)pContext;
+ if(pCntxt->pData < (pCntxt->pDataBase + pCntxt->size))
+ {
+ res = (*queueItf)->Enqueue(queueItf, (void*) pCntxt->pData,
+ 2 * AUDIO_DATA_BUFFER_SIZE, SL_BOOLEAN_FALSE); /* Size given
+ in bytes. */
+ CheckErr(res);
+ /* Increase data pointer by buffer size */
+ pCntxt->pData += AUDIO_DATA_BUFFER_SIZE;
+ }
+ }
+#endif
+}
+
+void AudioDriverAndroid::_buffer_callbacks(
+ SLAndroidSimpleBufferQueueItf queueItf,
+ /*SLuint32 eventFlags,
+ const void * pBuffer,
+ SLuint32 bufferSize,
+ SLuint32 dataUsed,*/
+ void *pContext) {
+
+
+ AudioDriverAndroid *ad = (AudioDriverAndroid*)pContext;
+
+// ad->_buffer_callback(queueItf,eventFlags,pBuffer,bufferSize,dataUsed);
+ ad->_buffer_callback(queueItf);
+
+}
+
+
+AudioDriverAndroid* AudioDriverAndroid::s_ad=NULL;
+
+const char* AudioDriverAndroid::get_name() const {
+
+ return "Android";
+}
+
+#if 0
+int AudioDriverAndroid::thread_func(SceSize args, void *argp) {
+
+ AudioDriverAndroid* ad = s_ad;
+ sceAudioOutput2Reserve(AUDIO_OUTPUT_SAMPLE);
+
+ int half=0;
+ while(!ad->exit_thread) {
+
+ int16_t *ptr = &ad->outbuff[AUDIO_OUTPUT_SAMPLE*2*half];
+
+
+
+ if (!ad->active) {
+
+ for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) {
+ ptr[i]=0;
+ }
+
+ } else {
+
+ //printf("samples: %i\n",AUDIO_OUTPUT_SAMPLE);
+ ad->lock();
+
+ ad->audio_server_process(AUDIO_OUTPUT_SAMPLE,ad->outbuff_32);
+
+ ad->unlock();
+
+ const int32_t* src_buff=ad->outbuff_32;
+
+ for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) {
+
+ ptr[i]=src_buff[i]>>16;
+ }
+ }
+
+
+ /* Output 16-bit PCM STEREO data that is in pcmBuf without changing the volume */
+ sceAudioOutput2OutputBlocking(
+ SCE_AUDIO_VOLUME_0dB*3, //0db at 0x8000, that's obvious
+ ptr
+ );
+
+ if (half)
+ half=0;
+ else
+ half=1;
+
+ }
+
+ sceAudioOutput2Release();
+
+ sceKernelExitThread(SCE_KERNEL_EXIT_SUCCESS);
+ ad->thread_exited=true;
+ return SCE_KERNEL_EXIT_SUCCESS;
+
+}
+
+#endif
+Error AudioDriverAndroid::init(){
+
+ SLresult
+ res;
+ SLEngineOption EngineOption[] = {
+ (SLuint32) SL_ENGINEOPTION_THREADSAFE,
+ (SLuint32) SL_BOOLEAN_TRUE
+
+ };
+ res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
+ if (res!=SL_RESULT_SUCCESS) {
+
+ ERR_EXPLAIN("Could not Initialize OpenSL");
+ ERR_FAIL_V(ERR_INVALID_PARAMETER);
+ }
+ res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
+ if (res!=SL_RESULT_SUCCESS) {
+
+ ERR_EXPLAIN("Could not Realize OpenSL");
+ ERR_FAIL_V(ERR_INVALID_PARAMETER);
+ }
+
+ print_line("OpenSL Init OK!");
+
+ return OK;
+
+}
+void AudioDriverAndroid::start(){
+
+
+ mutex = Mutex::create();
+ active=false;
+
+
+ SLint32 numOutputs = 0;
+ SLuint32 deviceID = 0;
+ SLresult res;
+
+
+ buffer_size = 1024;
+
+ for(int i=0;i<BUFFER_COUNT;i++) {
+
+ buffers[i]=memnew_arr( int16_t,buffer_size*2 );
+ memset(buffers[i],0,buffer_size*4);
+ }
+
+ mixdown_buffer = memnew_arr( int32_t,buffer_size* 2);
+
+ /* Callback context for the buffer queue callback function */
+
+ /* Get the SL Engine Interface which is implicit */
+ res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
+
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Initialize arrays required[] and iidArray[] */
+ int i;
+ SLboolean required[MAX_NUMBER_INTERFACES];
+ SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
+
+#if 0
+
+ for (i=0; i<MAX_NUMBER_INTERFACES; i++)
+ {
+ required[i] = SL_BOOLEAN_FALSE;
+ iidArray[i] = SL_IID_NULL;
+ }
+ // Set arrays required[] and iidArray[] for VOLUME interface
+ required[0] = SL_BOOLEAN_TRUE;
+ iidArray[0] = SL_IID_VOLUME;
+
+ // Create Output Mix object to be used by player
+ res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 1,
+ iidArray, required);
+#else
+
+ {
+ const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
+ const SLboolean req[1] = {SL_BOOLEAN_FALSE};
+ res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
+ ids, req);
+ }
+
+
+#endif
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ // Realizing the Output Mix object in synchronous mode.
+ res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+
+ SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, BUFFER_COUNT};
+// bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
+// bufferQueue.numBuffers = BUFFER_COUNT; /* Four buffers in our buffer queue */
+ /* Setup the format of the content in the buffer queue */
+ pcm.formatType = SL_DATAFORMAT_PCM;
+ pcm.numChannels = 2;
+ pcm.samplesPerSec = SL_SAMPLINGRATE_44_1;
+ pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
+ pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
+ pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
+#ifdef BIG_ENDIAN_ENABLED
+ pcm.endianness = SL_BYTEORDER_BIGENDIAN;
+#else
+ pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
+#endif
+ audioSource.pFormat = (void *)&pcm;
+ audioSource.pLocator = (void *)&loc_bufq;
+
+
+ /* Setup the data sink structure */
+ locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
+ locator_outputmix.outputMix= OutputMix;
+ audioSink.pLocator = (void *)&locator_outputmix;
+ audioSink.pFormat = NULL;
+ /* Initialize the context for Buffer queue callbacks */
+// cntxt.pDataBase = (void*)&pcmData;
+ //cntxt.pData = cntxt.pDataBase;
+ //cntxt.size = sizeof(pcmData);
+ /* Set arrays required[] and iidArray[] for SEEK interface
+ (PlayItf is implicit) */
+ required[0] = SL_BOOLEAN_TRUE;
+ iidArray[0] = SL_IID_BUFFERQUEUE;
+ /* Create the music player */
+
+ {
+ const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND};
+ const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+
+ res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
+ &audioSource, &audioSink, 1, ids, req);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ }
+ /* Realizing the player in synchronous mode. */
+ res = (*player)->Realize(player, SL_BOOLEAN_FALSE);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Get seek and play interfaces */
+ res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE,
+ (void*)&bufferQueueItf);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Setup to receive buffer queue event callbacks */
+ res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf,
+ _buffer_callbacks, this);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Before we start set volume to -3dB (-300mB) */
+#if 0
+ res = (*OutputMix)->GetInterface(OutputMix, SL_IID_VOLUME,
+ (void*)&volumeItf);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ /* Setup the data source structure for the buffer queue */
+
+ res = (*volumeItf)->SetVolumeLevel(volumeItf, -300);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+#endif
+ last_free=0;
+#if 1
+ //fill up buffers
+ for(int i=0;i<BUFFER_COUNT;i++) {
+ /* Enqueue a few buffers to get the ball rolling */
+ res = (*bufferQueueItf)->Enqueue(bufferQueueItf, buffers[i],
+ 4 * buffer_size); /* Size given in */
+
+ }
+#endif
+
+ res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+
+#if 0
+ res = (*bufferQueueItf)->GetState(bufferQueueItf, &state);
+ ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
+ while(state.count)
+ {
+ (*bufferQueueItf)->GetState(bufferQueueItf, &state);
+ }
+ /* Make sure player is stopped */
+ res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
+ CheckErr(res);
+ /* Destroy the player */
+ (*player)->Destroy(player);
+ /* Destroy Output Mix object */
+ (*OutputMix)->Destroy(OutputMix);
+#endif
+
+ active=true;
+}
+int AudioDriverAndroid::get_mix_rate() const {
+
+ return 44100;
+}
+AudioDriverSW::OutputFormat AudioDriverAndroid::get_output_format() const{
+
+ return OUTPUT_STEREO;
+}
+void AudioDriverAndroid::lock(){
+
+ //if (active && mutex)
+ // mutex->lock();
+
+}
+void AudioDriverAndroid::unlock() {
+
+ //if (active && mutex)
+ // mutex->unlock();
+
+}
+void AudioDriverAndroid::finish(){
+
+ (*sl)->Destroy(sl);
+
+}
+
+
+AudioDriverAndroid::AudioDriverAndroid()
+{
+ s_ad=this;
+ mutex=NULL;
+}
+
+#endif
diff --git a/platform/android/audio_driver_android.h b/platform/android/audio_driver_android.h
new file mode 100644
index 0000000000..655772c772
--- /dev/null
+++ b/platform/android/audio_driver_android.h
@@ -0,0 +1,105 @@
+/*************************************************************************/
+/* audio_driver_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef AUDIO_DRIVER_ANDROID_H
+#define AUDIO_DRIVER_ANDROID_H
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include "servers/audio/audio_server_sw.h"
+#include "os/mutex.h"
+#include <SLES/OpenSLES.h>
+#include "SLES/OpenSLES_Android.h"
+class AudioDriverAndroid : public AudioDriverSW {
+
+ bool active;
+ Mutex *mutex;
+
+ enum {
+
+ BUFFER_COUNT=2
+ };
+
+
+
+
+ uint32_t buffer_size;
+ int16_t *buffers[BUFFER_COUNT];
+ int32_t *mixdown_buffer;
+ int last_free;
+
+
+ SLPlayItf playItf;
+ SLObjectItf sl;
+ SLEngineItf EngineItf;
+ SLObjectItf OutputMix;
+ SLVolumeItf volumeItf;
+ SLObjectItf player;
+ SLAndroidSimpleBufferQueueItf bufferQueueItf;
+ SLDataSource audioSource;
+ SLDataFormat_PCM pcm;
+ SLDataSink audioSink;
+ SLDataLocator_OutputMix locator_outputmix;
+ SLBufferQueueState state;
+
+ static AudioDriverAndroid* s_ad;
+
+ void _buffer_callback(
+ SLAndroidSimpleBufferQueueItf queueItf
+ /* SLuint32 eventFlags,
+ const void * pBuffer,
+ SLuint32 bufferSize,
+ SLuint32 dataUsed*/);
+
+ static void _buffer_callbacks(
+ SLAndroidSimpleBufferQueueItf queueItf,
+ /*SLuint32 eventFlags,
+ const void * pBuffer,
+ SLuint32 bufferSize,
+ SLuint32 dataUsed,*/
+ void *pContext);
+public:
+
+ void set_singleton();
+
+ virtual const char* get_name() const;
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const ;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+
+ AudioDriverAndroid();
+};
+
+#endif // AUDIO_DRIVER_ANDROID_H
+#endif
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
new file mode 100644
index 0000000000..6e3f6f9505
--- /dev/null
+++ b/platform/android/audio_driver_jandroid.cpp
@@ -0,0 +1,248 @@
+/*************************************************************************/
+/* audio_driver_jandroid.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "audio_driver_jandroid.h"
+#include "globals.h"
+#include "os/os.h"
+#include "thread_jandroid.h"
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+AudioDriverAndroid* AudioDriverAndroid::s_ad=NULL;
+
+jobject AudioDriverAndroid::io;
+jmethodID AudioDriverAndroid::_init_audio;
+jmethodID AudioDriverAndroid::_write_buffer;
+jmethodID AudioDriverAndroid::_quit;
+jmethodID AudioDriverAndroid::_pause;
+bool AudioDriverAndroid::active=false;
+jclass AudioDriverAndroid::cls;
+int AudioDriverAndroid::audioBufferFrames=0;
+int AudioDriverAndroid::mix_rate=44100;
+bool AudioDriverAndroid::quit=false;
+jobject AudioDriverAndroid::audioBuffer = NULL;
+void* AudioDriverAndroid::audioBufferPinned = NULL;
+Mutex *AudioDriverAndroid::mutex=NULL;
+int32_t* AudioDriverAndroid::audioBuffer32=NULL;
+
+
+const char* AudioDriverAndroid::get_name() const {
+
+ return "Android";
+}
+
+
+Error AudioDriverAndroid::init(){
+
+ mutex = Mutex::create();
+/*
+ // TODO: pass in/return a (Java) device ID, also whether we're opening for input or output
+ this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
+ SDL_CalculateAudioSpec(&this->spec);
+
+ if (this->spec.samples == 0) {
+ // Init failed?
+ SDL_SetError("Java-side initialization failed!");
+ return 0;
+ }
+*/
+
+// Android_JNI_SetupThread();
+
+
+ // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
+
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ int mix_rate = GLOBAL_DEF("audio/mix_rate",44100);
+
+ int latency = GLOBAL_DEF("audio/output_latency",25);
+ latency=50;
+ unsigned int buffer_size = nearest_power_of_2( latency * mix_rate / 1000 );
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_line("audio buffer size: "+itos(buffer_size));
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","Initializing audio! params: %i,%i ",mix_rate,buffer_size);
+ audioBuffer = env->CallObjectMethod(io,_init_audio, mix_rate, buffer_size);
+
+
+ ERR_FAIL_COND_V( audioBuffer == NULL, ERR_INVALID_PARAMETER);
+
+ audioBuffer = env->NewGlobalRef(audioBuffer);
+
+ jboolean isCopy = JNI_FALSE;
+ audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
+ audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer);
+ audioBuffer32 = memnew_arr(int32_t,audioBufferFrames);
+
+ return OK;
+}
+
+void AudioDriverAndroid::start(){
+ active=true;
+
+}
+
+void AudioDriverAndroid::setup( jobject p_io) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ io=p_io;
+
+ jclass c = env->GetObjectClass(io);
+ cls = (jclass)env->NewGlobalRef(c);
+
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","starting to attempt get methods");
+
+ _init_audio = env->GetMethodID(cls, "audioInit", "(II)Ljava/lang/Object;");
+ if(_init_audio != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _init_audio ok!!");
+ } else {
+ __android_log_print(ANDROID_LOG_INFO,"godot","audioinit ok!");
+ }
+
+ _write_buffer = env->GetMethodID(cls, "audioWriteShortBuffer", "([S)V");
+ if(_write_buffer != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _write_buffer ok!!");
+ }
+
+
+ _quit = env->GetMethodID(cls, "audioQuit", "()V");
+ if(_quit != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _quit ok!!");
+ }
+
+ _pause = env->GetMethodID(cls, "audioPause", "(Z)V");
+ if(_quit != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _pause ok!!");
+ }
+
+
+}
+
+void AudioDriverAndroid::thread_func(JNIEnv *env) {
+
+ jclass cls = env->FindClass("com/android/godot/Godot");
+ if (cls) {
+
+ cls=(jclass)env->NewGlobalRef(cls);
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******CLASS FOUND!!!");
+ }
+ jfieldID fid = env->GetStaticFieldID(cls, "io", "Lcom/android/godot/GodotIO;");
+ jobject ob = env->GetStaticObjectField(cls,fid);
+ jobject gob = env->NewGlobalRef(ob);
+ jclass c = env->GetObjectClass(gob);
+ jclass lcls = (jclass)env->NewGlobalRef(c);
+ _write_buffer = env->GetMethodID(lcls, "audioWriteShortBuffer", "([S)V");
+ if(_write_buffer != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _write_buffer ok!!");
+ }
+
+ while(!quit) {
+
+
+ int16_t* ptr = (int16_t*)audioBufferPinned;
+ int fc = audioBufferFrames;
+
+ if (!s_ad->active || mutex->try_lock()!=OK) {
+
+ for(int i=0;i<fc;i++) {
+ ptr[i]=0;
+ }
+
+ } else {
+
+
+ s_ad->audio_server_process(fc/2,audioBuffer32);
+
+ mutex->unlock();
+
+ for(int i=0;i<fc;i++) {
+
+ ptr[i]=audioBuffer32[i]>>16;
+ }
+
+ }
+ env->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)ptr, JNI_COMMIT);
+ env->CallVoidMethod(gob, _write_buffer, (jshortArray)audioBuffer);
+ }
+
+
+
+}
+
+int AudioDriverAndroid::get_mix_rate() const {
+
+ return mix_rate;
+}
+AudioDriverSW::OutputFormat AudioDriverAndroid::get_output_format() const{
+
+ return OUTPUT_STEREO;
+}
+void AudioDriverAndroid::lock(){
+
+ if (mutex)
+ mutex->lock();
+
+}
+void AudioDriverAndroid::unlock() {
+
+ if (mutex)
+ mutex->unlock();
+}
+void AudioDriverAndroid::finish(){
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(io, _quit);
+
+ if (audioBuffer) {
+ env->DeleteGlobalRef(audioBuffer);
+ audioBuffer = NULL;
+ audioBufferPinned = NULL;
+ }
+
+ active=false;
+}
+
+void AudioDriverAndroid::set_pause(bool p_pause) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(io, _pause,p_pause);
+
+}
+
+AudioDriverAndroid::AudioDriverAndroid()
+{
+ s_ad=this;
+ active=false;
+
+
+
+}
+
+#endif
diff --git a/platform/android/audio_driver_jandroid.h b/platform/android/audio_driver_jandroid.h
new file mode 100644
index 0000000000..f102acf154
--- /dev/null
+++ b/platform/android/audio_driver_jandroid.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* audio_driver_jandroid.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef AUDIO_DRIVER_ANDROID_H
+#define AUDIO_DRIVER_ANDROID_H
+
+#include "servers/audio/audio_server_sw.h"
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "java_glue.h"
+
+class AudioDriverAndroid : public AudioDriverSW {
+
+
+ static Mutex *mutex;
+ static AudioDriverAndroid* s_ad;
+ static jobject io;
+ static jmethodID _init_audio;
+ static jmethodID _write_buffer;
+ static jmethodID _quit;
+ static jmethodID _pause;
+ static bool active;
+ static bool quit;
+
+ static jclass cls;
+
+ static jobject audioBuffer;
+ static void* audioBufferPinned;
+ static int32_t* audioBuffer32;
+ static int audioBufferFrames;
+ static int mix_rate;
+
+
+public:
+
+ void set_singleton();
+
+ virtual const char* get_name() const;
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const ;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+ virtual void set_pause(bool p_pause);
+
+ static void setup( jobject act);
+ static void thread_func(JNIEnv *env);
+
+ AudioDriverAndroid();
+};
+
+#endif
+#endif // AUDIO_DRIVER_ANDROID_H
diff --git a/platform/android/detect.py b/platform/android/detect.py
new file mode 100644
index 0000000000..b89024a81a
--- /dev/null
+++ b/platform/android/detect.py
@@ -0,0 +1,175 @@
+import os
+import sys
+import string
+import platform
+
+def is_active():
+ return True
+
+def get_name():
+ return "Android"
+
+def can_build():
+
+ import os
+ if (not os.environ.has_key("ANDROID_NDK_ROOT")):
+ return False
+ return True
+
+def get_opts():
+
+ return [
+ ('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
+ ('NDK_TOOLCHAIN', 'toolchain to use for the NDK',"arm-eabi-4.4.0"),
+ #android 2.3
+ ('ndk_platform', 'compile for platform: (2.2,2.3)',"2.2"),
+ ('NDK_TARGET', 'toolchain to use for the NDK',"arm-linux-androideabi-4.7"),
+ ('android_stl','enable STL support in android port (for modules)','no'),
+ ('armv6','compile for older phones running arm v6 (instead of v7+neon+smp)','no')
+
+ ]
+
+def get_flags():
+
+ return [
+ ('lua', 'no'),
+ ('tools', 'no'),
+ ('nedmalloc', 'no'),
+ ('builtin_zlib', 'no'),
+ ]
+
+
+def create(env):
+ tools = env['TOOLS']
+ if "mingw" in tools:
+ tools.remove('mingw')
+ if "applelink" in tools:
+ tools.remove("applelink")
+ env.Tool('gcc')
+ return env.Clone(tools=tools);
+
+def configure(env):
+
+ if env['PLATFORM'] == 'win32':
+ import methods
+ env.Tool('gcc')
+ env['SPAWN'] = methods.win32_spawn
+
+ ndk_platform=""
+
+ if (env["ndk_platform"]=="2.2"):
+ ndk_platform="android-8"
+ else:
+ ndk_platform="android-9"
+ env.Append(CPPFLAGS=["-DANDROID_NATIVE_ACTIVITY"])
+
+ print("Godot Android!!!!!")
+
+ env.Append(CPPPATH=['#platform/android'])
+
+ env['OBJSUFFIX'] = ".android.o"
+ env['LIBSUFFIX'] = ".android.a"
+ env['PROGSUFFIX'] = ".android"
+ env['SHLIBSUFFIX'] = ".so"
+
+ gcc_path=env["ANDROID_NDK_ROOT"]+"/toolchains/"+env["NDK_TARGET"]+"/prebuilt/";
+
+ import os
+ if (sys.platform.find("linux")==0):
+ if (platform.architecture()[0]=='64bit' or os.path.isdir(gcc_path+"linux-x86_64/bin")): # check was not working
+ gcc_path=gcc_path+"/linux-x86_64/bin"
+ else:
+ gcc_path=gcc_path+"/linux-x86/bin"
+ elif (sys.platform=="darwin"):
+ gcc_path=gcc_path+"/darwin-x86_64/bin" #this may be wrong
+ env['SHLINKFLAGS'][1] = '-shared'
+ elif (os.name=="nt"):
+ gcc_path=gcc_path+"/windows/bin" #this may be wrong
+
+
+
+ env['ENV']['PATH'] = gcc_path+":"+env['ENV']['PATH']
+
+ env['CC'] = gcc_path+'/arm-linux-androideabi-gcc'
+ env['CXX'] = gcc_path+'/arm-linux-androideabi-g++'
+ env['AR'] = gcc_path+"/arm-linux-androideabi-ar"
+ env['RANLIB'] = gcc_path+"/arm-linux-androideabi-ranlib"
+ env['AS'] = gcc_path+"/arm-linux-androideabi-as"
+
+ import string
+ #include path
+ gcc_include=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/arch-arm/usr/include"
+ ld_sysroot=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/arch-arm"
+ #glue_include=env["ANDROID_NDK_ROOT"]+"/sources/android/native_app_glue"
+ ld_path=env["ANDROID_NDK_ROOT"]+"/platforms/"+ndk_platform+"/arch-arm/usr/lib"
+ env.Append(CPPPATH=[gcc_include])
+# env['CCFLAGS'] = string.split('-DNO_THREADS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -fno-exceptions -mthumb -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED ')
+ print("********* armv6", env['armv6'])
+ if env["armv6"]!="no":
+ env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_6__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=vfp -mfloat-abi=softfp -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
+ else:
+ env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_7__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
+
+ env.Append(LDPATH=[ld_path])
+# env.Append(LIBS=['c','m','stdc++','log','EGL','GLESv1_CM','GLESv2','OpenSLES','supc++','android'])
+ if (env["ndk_platform"]!="2.2"):
+ env.Append(LIBS=['EGL','OpenSLES','android'])
+ env.Append(LIBS=['c','m','stdc++','log','GLESv1_CM','GLESv2', 'z'])
+
+ env["LINKFLAGS"]= string.split(" -g --sysroot="+ld_sysroot+" -Wl,--no-undefined -Wl,-z,noexecstack ")
+ env.Append(LINKFLAGS=["-Wl,-soname,libgodot_android.so"])
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O2', '-ffast-math','-fomit-frame-pointer'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="release_debug"):
+
+ env.Append(CCFLAGS=['-O2', '-ffast-math','-DDEBUG_ENABLED'])
+ env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-O2', '-ffast-math','-fomit-frame-pointer', '-g1'])
+ env.Append(LIBPATH=['#platform/android/armeabi'])
+ env.Append(LIBS=['andprof'])
+ env['OBJSUFFIX'] = "_prof"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_prof"+env['LIBSUFFIX']
+ env['SHLIBSUFFIX'] = "_prof"+env['SHLIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-D_DEBUG', '-g1', '-Wall', '-O0', '-DDEBUG_ENABLED'])
+ env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
+
+ if env["armv6"] == "no":
+ env['neon_enabled']=True
+ env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL','-DMPC_FIXED_POINT'])
+# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT'])
+ if (env['android_stl']=='yes'):
+ #env.Append(CCFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/system/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi/include"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi"])
+ env.Append(LIBS=["gnustl_static","supc++"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
+
+ #env.Append(CCFLAGS=["-I"+env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/stlport/stlport"])
+ #env.Append(CCFLAGS=["-I"+env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include"])
+ #env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/libs/armeabi/libstdc++.a"])
+ else:
+
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/include"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/armeabi"])
+ env.Append(LIBS=['gabi++_static'])
+ env.Append(CCFLAGS=["-fno-exceptions",'-DNO_SAFE_CAST'])
+
+ 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') } )
+
diff --git a/platform/android/dir_access_android.cpp b/platform/android/dir_access_android.cpp
new file mode 100644
index 0000000000..60bde61fc4
--- /dev/null
+++ b/platform/android/dir_access_android.cpp
@@ -0,0 +1,189 @@
+/*************************************************************************/
+/* dir_access_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef ANDROID_NATIVE_ACTIVITY
+#include "dir_access_android.h"
+#include "file_access_android.h"
+
+
+
+DirAccess *DirAccessAndroid::create_fs() {
+
+ return memnew(DirAccessAndroid);
+}
+
+bool DirAccessAndroid::list_dir_begin() {
+
+ list_dir_end();
+
+ AAssetDir* aad = AAssetManager_openDir(FileAccessAndroid::asset_manager,current_dir.utf8().get_data());
+ if (!aad)
+ return true; //nothing
+
+
+ return false;
+}
+
+String DirAccessAndroid::get_next(){
+
+ const char* fn= AAssetDir_getNextFileName(aad);
+ if (!fn)
+ return "";
+ String s;
+ s.parse_utf8(fn);
+ current=s;
+ return s;
+
+
+}
+bool DirAccessAndroid::current_is_dir() const{
+
+ String sd;
+ if (current_dir=="")
+ sd=current;
+ else
+ sd=current_dir+"/"+current;
+
+ AAssetDir* aad2 = AAssetManager_openDir(FileAccessAndroid::asset_manager,sd.utf8().get_data());
+ if (aad2) {
+
+ AAssetDir_close(aad2);
+ return true;
+ }
+
+ return false;
+
+}
+void DirAccessAndroid::list_dir_end(){
+
+ if (aad==NULL)
+ return;
+
+ AAssetDir_close(aad);
+ aad=NULL;
+
+}
+
+int DirAccessAndroid::get_drive_count(){
+
+ return 0;
+}
+String DirAccessAndroid::get_drive(int p_drive){
+
+ return "";
+}
+
+Error DirAccessAndroid::change_dir(String p_dir){
+
+ p_dir=p_dir.simplify_path();
+
+ if (p_dir=="" || p_dir=="." || (p_dir==".." && current_dir==""))
+ return OK;
+
+ String new_dir;
+
+ if (p_dir.begins_with("/"))
+ new_dir=p_dir.substr(1,p_dir.length());
+ else if (p_dir.begins_with("res://"))
+ new_dir=p_dir.substr(6,p_dir.length());
+ else //relative
+ new_dir=new_dir+"/"+p_dir;
+
+//test if newdir exists
+ new_dir=new_dir.simplify_path();
+
+ AAssetDir* aad = AAssetManager_openDir(FileAccessAndroid::asset_manager,new_dir.utf8().get_data());
+ if (aad) {
+
+ current_dir=new_dir;
+ AAssetDir_close(aad);
+ return OK;
+ }
+
+ return ERR_INVALID_PARAMETER;
+}
+
+String DirAccessAndroid::get_current_dir(){
+
+ return "/"+current_dir;
+}
+
+
+bool DirAccessAndroid::file_exists(String p_file){
+
+ String sd;
+ if (current_dir=="")
+ sd=p_file;
+ else
+ sd=current_dir+"/"+p_file;
+
+ AAsset *a=AAssetManager_open(FileAccessAndroid::asset_manager,sd.utf8().get_data(),AASSET_MODE_STREAMING);
+ if (a) {
+ AAsset_close(a);
+ return true;
+ }
+
+ return false;
+}
+
+
+Error DirAccessAndroid::make_dir(String p_dir){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+Error DirAccessAndroid::rename(String p_from, String p_to){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+Error DirAccessAndroid::remove(String p_name){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+//FileType get_file_type() const;
+size_t DirAccessAndroid::get_space_left() {
+
+ return 0;
+}
+
+void DirAccessAndroid::make_default() {
+
+ instance_func=create_fs;
+}
+
+DirAccessAndroid::DirAccessAndroid() {
+
+ aad=NULL;
+}
+
+DirAccessAndroid::~DirAccessAndroid() {
+
+ list_dir_end();;
+}
+#endif
diff --git a/platform/android/dir_access_android.h b/platform/android/dir_access_android.h
new file mode 100644
index 0000000000..a6aead6eb3
--- /dev/null
+++ b/platform/android/dir_access_android.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* dir_access_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef DIR_ACCESS_ANDROID_H
+#define DIR_ACCESS_ANDROID_H
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include "os/dir_access.h"
+#include <stdio.h>
+#include <android/asset_manager.h>
+#include <android/log.h>
+#include <android_native_app_glue.h>
+
+
+
+class DirAccessAndroid : public DirAccess {
+
+ AAssetDir* aad;
+ String current_dir;
+ String current;
+
+ static DirAccess *create_fs();
+
+public:
+
+ virtual bool list_dir_begin(); ///< This starts dir listing
+ virtual String get_next();
+ virtual bool current_is_dir() const;
+ virtual void list_dir_end(); ///<
+
+ virtual int get_drive_count();
+ virtual String get_drive(int p_drive);
+
+ virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(); ///< return current dir location
+
+
+ virtual bool file_exists(String p_file);
+
+
+ virtual Error make_dir(String p_dir);
+
+ virtual Error rename(String p_from, String p_to);
+ virtual Error remove(String p_name);
+
+ //virtual FileType get_file_type() const;
+ size_t get_space_left();
+
+ static void make_default();
+
+ DirAccessAndroid();
+ ~DirAccessAndroid();
+};
+
+#endif
+#endif // DIR_ACCESS_ANDROID_H
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
new file mode 100644
index 0000000000..0c8a5785f8
--- /dev/null
+++ b/platform/android/dir_access_jandroid.cpp
@@ -0,0 +1,241 @@
+/*************************************************************************/
+/* dir_access_jandroid.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "dir_access_jandroid.h"
+#include "file_access_jandroid.h"
+#include "thread_jandroid.h"
+jobject DirAccessJAndroid::io=NULL;
+jclass DirAccessJAndroid::cls=NULL;
+jmethodID DirAccessJAndroid::_dir_open=NULL;
+jmethodID DirAccessJAndroid::_dir_next=NULL;
+jmethodID DirAccessJAndroid::_dir_close=NULL;
+
+
+DirAccess *DirAccessJAndroid::create_fs() {
+
+ return memnew(DirAccessJAndroid);
+}
+
+bool DirAccessJAndroid::list_dir_begin() {
+
+ list_dir_end();
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jstring js = env->NewStringUTF(current_dir.utf8().get_data());
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return true;
+
+ id=res;
+
+ return false;
+}
+
+String DirAccessJAndroid::get_next(){
+
+ ERR_FAIL_COND_V(id==0,"");
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring str= (jstring)env->CallObjectMethod(io,_dir_next,id);
+ if (!str)
+ return "";
+
+ int sl = env->GetStringLength(str);
+ if (sl==0) {
+ env->DeleteLocalRef((jobject)str);
+ return "";
+ }
+
+ CharString cs;
+ cs.resize(sl+1);
+ env->GetStringRegion(str,0,sl,(jchar*)&cs[0]);
+ cs[sl]=0;
+
+ String ret;
+ ret.parse_utf8(&cs[0]);
+ env->DeleteLocalRef((jobject)str);
+
+ return ret;
+
+}
+bool DirAccessJAndroid::current_is_dir() const{
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ String sd;
+ if (current_dir=="")
+ sd=current;
+ else
+ sd=current_dir+"/"+current;
+
+ jstring js = env->NewStringUTF(sd.utf8().get_data());
+
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return false;
+
+ env->CallObjectMethod(io,_dir_close,res);
+
+
+ return true;
+}
+void DirAccessJAndroid::list_dir_end(){
+
+ if (id==0)
+ return;
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallObjectMethod(io,_dir_close,id);
+ id=0;
+
+
+}
+
+int DirAccessJAndroid::get_drive_count(){
+
+ return 0;
+}
+String DirAccessJAndroid::get_drive(int p_drive){
+
+ return "";
+}
+
+Error DirAccessJAndroid::change_dir(String p_dir){
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ p_dir=p_dir.simplify_path();
+
+ if (p_dir=="" || p_dir=="." || (p_dir==".." && current_dir==""))
+ return OK;
+
+ String new_dir;
+
+ if (p_dir.begins_with("/"))
+ new_dir=p_dir.substr(1,p_dir.length());
+ else if (p_dir.begins_with("res://"))
+ new_dir=p_dir.substr(6,p_dir.length());
+ else //relative
+ new_dir=new_dir+"/"+p_dir;
+
+//test if newdir exists
+ new_dir=new_dir.simplify_path();
+
+ jstring js = env->NewStringUTF(new_dir.utf8().get_data());
+ int res = env->CallIntMethod(io,_dir_open,js);
+ if (res<=0)
+ return ERR_INVALID_PARAMETER;
+
+ env->CallObjectMethod(io,_dir_close,res);
+
+
+
+ return OK;
+}
+
+String DirAccessJAndroid::get_current_dir(){
+
+ return "/"+current_dir;
+}
+
+bool DirAccessJAndroid::file_exists(String p_file){
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ String sd;
+ if (current_dir=="")
+ sd=p_file;
+ else
+ sd=current_dir+"/"+p_file;
+
+ FileAccessJAndroid *f = memnew(FileAccessJAndroid);
+ bool exists = f->file_exists(sd);
+ memdelete(f);
+
+ return exists;
+}
+
+
+Error DirAccessJAndroid::make_dir(String p_dir){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+Error DirAccessJAndroid::rename(String p_from, String p_to){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+Error DirAccessJAndroid::remove(String p_name){
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+}
+
+//FileType get_file_type() const;
+size_t DirAccessJAndroid::get_space_left() {
+
+ return 0;
+}
+
+
+void DirAccessJAndroid::setup( jobject p_io) {
+
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ io=p_io;
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP7");
+
+ jclass c = env->GetObjectClass(io);
+ cls = (jclass)env->NewGlobalRef(c);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP8");
+
+ _dir_open = env->GetMethodID(cls, "dir_open", "(Ljava/lang/String;)I");
+ if(_dir_open != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_open ok!!");
+ }
+ _dir_next = env->GetMethodID(cls, "dir_next", "(I)Ljava/lang/String;");
+ if(_dir_next != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_next ok!!");
+ }
+ _dir_close = env->GetMethodID(cls, "dir_close", "(I)V");
+ if(_dir_close != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _dir_close ok!!");
+ }
+
+// (*env)->CallVoidMethod(env,obj,aMethodID, myvar);
+}
+
+
+DirAccessJAndroid::DirAccessJAndroid() {
+
+ id=0;
+}
+
+DirAccessJAndroid::~DirAccessJAndroid() {
+
+ list_dir_end();;
+}
+#endif
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
new file mode 100644
index 0000000000..b6e3fe393f
--- /dev/null
+++ b/platform/android/dir_access_jandroid.h
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* dir_access_jandroid.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef DIR_ACCESS_JANDROID_H
+#define DIR_ACCESS_JANDROID_H
+
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+
+#include "java_glue.h"
+#include "os/dir_access.h"
+#include <stdio.h>
+
+
+class DirAccessJAndroid : public DirAccess {
+
+ //AAssetDir* aad;
+
+ static jobject io;
+ static jclass cls;
+
+ static jmethodID _dir_open;
+ static jmethodID _dir_next;
+ static jmethodID _dir_close;
+
+ int id;
+
+ String current_dir;
+ String current;
+
+ static DirAccess *create_fs();
+
+public:
+
+ virtual bool list_dir_begin(); ///< This starts dir listing
+ virtual String get_next();
+ virtual bool current_is_dir() const;
+ virtual void list_dir_end(); ///<
+
+ virtual int get_drive_count();
+ virtual String get_drive(int p_drive);
+
+ virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(); ///< return current dir location
+
+
+ virtual bool file_exists(String p_file);
+
+ virtual Error make_dir(String p_dir);
+
+ virtual Error rename(String p_from, String p_to);
+ virtual Error remove(String p_name);
+
+ //virtual FileType get_file_type() const;
+ size_t get_space_left();
+
+
+ static void setup( jobject io);
+
+ DirAccessJAndroid();
+ ~DirAccessJAndroid();
+};
+
+#endif // DIR_ACCESS_JANDROID_H
+#endif
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
new file mode 100644
index 0000000000..a9b96a116b
--- /dev/null
+++ b/platform/android/export/export.cpp
@@ -0,0 +1,1229 @@
+#include "version.h"
+#include "export.h"
+#include "tools/editor/editor_settings.h"
+#include "tools/editor/editor_import_export.h"
+#include "tools/editor/editor_node.h"
+#include "io/zip_io.h"
+#include "io/marshalls.h"
+#include "globals.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "platform/android/logo.h"
+
+class EditorExportPlatformAndroid : public EditorExportPlatform {
+
+ OBJ_TYPE( EditorExportPlatformAndroid,EditorExportPlatform );
+
+ String custom_release_package;
+ String custom_debug_package;
+
+ int version_code;
+ String version_name;
+ String package;
+ String name;
+ String icon;
+ bool _signed;
+ int orientation;
+
+ String release_keystore;
+ String release_username;
+
+ struct APKExportData {
+
+ zipFile apk;
+ EditorProgress *ep;
+ };
+
+ struct Device {
+
+ String id;
+ String name;
+ String description;
+ };
+
+ Vector<Device> devices;
+ bool devices_changed;
+ Mutex *device_lock;
+ Thread *device_thread;
+ Ref<ImageTexture> logo;
+
+ volatile bool quit_request;
+
+
+ static void _device_poll_thread(void *ud);
+
+ String get_project_name() const;
+ void _fix_manifest(Vector<uint8_t>& p_manifest);
+ void _fix_resources(Vector<uint8_t>& p_manifest);
+ static Error save_apk_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total);
+
+protected:
+
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+ virtual String get_name() const { return "Android"; }
+ virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_ETC1; }
+ virtual Ref<Texture> get_logo() const { return logo; }
+
+
+ virtual bool poll_devices();
+ virtual int get_device_count() const;
+ virtual String get_device_name(int p_device) const;
+ virtual String get_device_info(int p_device) const;
+ virtual Error run(int p_device);
+
+ virtual bool requieres_password(bool p_debug) const { return !p_debug; }
+ virtual String get_binary_extension() const { return "apk"; }
+ virtual Error export_project(const String& p_path,bool p_debug,const String& p_password="");
+
+ virtual bool can_export(String *r_error=NULL) const;
+
+ EditorExportPlatformAndroid();
+ ~EditorExportPlatformAndroid();
+};
+
+bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant& p_value) {
+
+ String n=p_name;
+
+ if (n=="version/code")
+ version_code=p_value;
+ else if (n=="version/name")
+ version_name=p_value;
+ else if (n=="package/unique_name")
+ package=p_value;
+ else if (n=="package/name")
+ name=p_value;
+ else if (n=="package/icon")
+ icon=p_value;
+ else if (n=="package/signed")
+ _signed=p_value;
+ else if (n=="screen/orientation")
+ orientation=p_value;
+ else if (n=="keystore/release")
+ release_keystore=p_value;
+ else if (n=="keystore/release_user")
+ release_username=p_value;
+ else
+ return false;
+
+ return true;
+}
+
+bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret) const{
+
+ String n=p_name;
+
+ if (n=="version/code")
+ r_ret=version_code;
+ else if (n=="version/name")
+ r_ret=version_name;
+ else if (n=="package/unique_name")
+ r_ret=package;
+ else if (n=="package/name")
+ r_ret=name;
+ else if (n=="package/icon")
+ r_ret=icon;
+ else if (n=="package/signed")
+ r_ret=_signed;
+ else if (n=="screen/orientation")
+ r_ret=orientation;
+ else if (n=="keystore/release")
+ r_ret=release_keystore;
+ else if (n=="keystore/release_user")
+ r_ret=release_username;
+ else
+ return false;
+
+ return true;
+}
+void EditorExportPlatformAndroid::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_FILE,"apk"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_FILE,"apk"));
+ p_list->push_back( PropertyInfo( Variant::INT, "version/code", PROPERTY_HINT_RANGE,"1,65535,1"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "version/name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/unique_name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/icon",PROPERTY_HINT_FILE,"png") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "package/signed") );
+ p_list->push_back( PropertyInfo( Variant::INT, "screen/orientation",PROPERTY_HINT_ENUM,"Landscape,Portrait") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release",PROPERTY_HINT_FILE,"keystore") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release_user" ) );
+
+ //p_list->push_back( PropertyInfo( Variant::INT, "resources/pack_mode", PROPERTY_HINT_ENUM,"Copy,Single Exec.,Pack (.pck),Bundles (Optical)"));
+
+}
+
+
+static String _parse_string(const uint8_t *p_bytes,bool p_utf8) {
+
+ uint32_t offset=0;
+ uint32_t len = decode_uint16(&p_bytes[offset]);
+
+ if (p_utf8) {
+ //don't know how to read extended utf8, this will have to be for now
+ len>>=8;
+
+ }
+ offset+=2;
+ printf("len %i, unicode: %i\n",len,int(p_utf8));
+
+ if (p_utf8) {
+
+ Vector<uint8_t> str8;
+ str8.resize(len+1);
+ for(int i=0;i<len;i++) {
+ str8[i]=p_bytes[offset+i];
+ }
+ str8[len]=0;
+ String str;
+ str.parse_utf8((const char*)str8.ptr());
+ return str;
+ } else {
+
+ String str;
+ for(int i=0;i<len;i++) {
+ CharType c = decode_uint16(&p_bytes[offset+i*2]);
+ if (c==0)
+ break;
+ str += String::chr(c);
+ }
+ return str;
+ }
+
+}
+
+void EditorExportPlatformAndroid::_fix_resources(Vector<uint8_t>& p_manifest) {
+
+
+ const int UTF8_FLAG = 0x00000100;
+ print_line("*******************GORRRGLE***********************");
+
+ uint32_t header = decode_uint32(&p_manifest[0]);
+ uint32_t filesize = decode_uint32(&p_manifest[4]);
+ uint32_t string_block_len = decode_uint32(&p_manifest[16]);
+ uint32_t string_count = decode_uint32(&p_manifest[20]);
+ uint32_t string_flags = decode_uint32(&p_manifest[28]);
+ const uint32_t string_table_begins = 40;
+
+ Vector<String> string_table;
+
+ printf("stirng block len: %i\n",string_block_len);
+ printf("stirng count: %i\n",string_count);
+ printf("flags: %x\n",string_flags);
+
+ for(int i=0;i<string_count;i++) {
+
+ uint32_t offset = decode_uint32(&p_manifest[string_table_begins+i*4]);
+ offset+=string_table_begins+string_count*4;
+
+ String str = _parse_string(&p_manifest[offset],string_flags&UTF8_FLAG);
+
+ if (str.begins_with("godot-project-name")) {
+
+
+ if (str=="godot-project-name") {
+ //project name
+ str = get_project_name();
+
+ } else {
+
+ String lang = str.substr(str.find_last("-")+1,str.length()).replace("-","_");
+ String prop = "application/name_"+lang;
+ if (Globals::get_singleton()->has(prop)) {
+ str = Globals::get_singleton()->get(prop);
+ } else {
+ str = get_project_name();
+ }
+ }
+ }
+
+ string_table.push_back(str);
+
+ }
+
+ //write a new string table, but use 16 bits
+ Vector<uint8_t> ret;
+ ret.resize(string_table_begins+string_table.size()*4);
+
+ for(int i=0;i<string_table_begins;i++) {
+
+ ret[i]=p_manifest[i];
+ }
+
+ int ofs=0;
+ for(int i=0;i<string_table.size();i++) {
+
+ encode_uint32(ofs,&ret[string_table_begins+i*4]);
+ ofs+=string_table[i].length()*2+2+2;
+ }
+
+ ret.resize(ret.size()+ofs);
+ uint8_t *chars=&ret[ret.size()-ofs];
+ for(int i=0;i<string_table.size();i++) {
+
+ String s = string_table[i];
+ encode_uint16(s.length(),chars);
+ chars+=2;
+ for(int j=0;j<s.length();j++) {
+ encode_uint16(s[j],chars);
+ chars+=2;
+ }
+ encode_uint16(0,chars);
+ chars+=2;
+ }
+
+ //pad
+ while(ret.size()%4)
+ ret.push_back(0);
+
+ //change flags to not use utf8
+ encode_uint32(string_flags&~0x100,&ret[28]);
+ //change length
+ encode_uint32(ret.size()-12,&ret[16]);
+ //append the rest...
+ int rest_from = 12+string_block_len;
+ int rest_to = ret.size();
+ int rest_len = (p_manifest.size() - rest_from);
+ ret.resize(ret.size() + (p_manifest.size() - rest_from) );
+ for(int i=0;i<rest_len;i++) {
+ ret[rest_to+i]=p_manifest[rest_from+i];
+ }
+ //finally update the size
+ encode_uint32(ret.size(),&ret[4]);
+
+
+ p_manifest=ret;
+ printf("end\n");
+}
+
+String EditorExportPlatformAndroid::get_project_name() const {
+
+ String aname;
+ if (this->name!="") {
+ aname=this->name;
+ } else {
+ aname = Globals::get_singleton()->get("application/name");
+
+ }
+
+ if (aname=="") {
+ aname=_MKSTR(VERSION_NAME);
+ }
+
+ return aname;
+}
+
+
+void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
+
+
+ const int CHUNK_AXML_FILE = 0x00080003;
+ const int CHUNK_RESOURCEIDS = 0x00080180;
+ const int CHUNK_STRINGS = 0x001C0001;
+ const int CHUNK_XML_END_NAMESPACE = 0x00100101;
+ const int CHUNK_XML_END_TAG = 0x00100103;
+ const int CHUNK_XML_START_NAMESPACE = 0x00100100;
+ const int CHUNK_XML_START_TAG = 0x00100102;
+ const int CHUNK_XML_TEXT = 0x00100104;
+ const int UTF8_FLAG = 0x00000100;
+
+ Vector<String> string_table;
+
+ uint32_t ofs=0;
+
+
+ uint32_t header = decode_uint32(&p_manifest[ofs]);
+ uint32_t filesize = decode_uint32(&p_manifest[ofs+4]);
+ ofs+=8;
+
+// print_line("FILESIZE: "+itos(filesize)+" ACTUAL: "+itos(p_manifest.size()));
+
+ uint32_t string_count;
+ uint32_t styles_count;
+ uint32_t string_flags;
+ uint32_t string_data_offset;
+
+ uint32_t styles_offset;
+ uint32_t string_table_begins;
+ uint32_t string_table_ends;
+ Vector<uint8_t> stable_extra;
+
+ while(ofs < p_manifest.size()) {
+
+ uint32_t chunk = decode_uint32(&p_manifest[ofs]);
+ uint32_t size = decode_uint32(&p_manifest[ofs+4]);
+
+
+ switch(chunk) {
+
+ case CHUNK_STRINGS: {
+
+
+ int iofs=ofs+8;
+
+ uint32_t string_count=decode_uint32(&p_manifest[iofs]);
+ uint32_t styles_count=decode_uint32(&p_manifest[iofs+4]);
+ uint32_t string_flags=decode_uint32(&p_manifest[iofs+8]);
+ uint32_t string_data_offset=decode_uint32(&p_manifest[iofs+12]);
+ uint32_t styles_offset=decode_uint32(&p_manifest[iofs+16]);
+/*
+ printf("string count: %i\n",string_count);
+ printf("flags: %i\n",string_flags);
+ printf("sdata ofs: %i\n",string_data_offset);
+ printf("styles ofs: %i\n",styles_offset);
+*/
+ uint32_t st_offset=iofs+20;
+ string_table.resize(string_count);
+ uint32_t string_end=0;
+
+ string_table_begins=st_offset;
+
+
+ for(int i=0;i<string_count;i++) {
+
+ uint32_t string_at = decode_uint32(&p_manifest[st_offset+i*4]);
+ string_at+=st_offset+string_count*4;
+
+ ERR_EXPLAIN("Unimplemented, can't read utf8 string table.");
+ ERR_FAIL_COND(string_flags&UTF8_FLAG);
+
+ if (string_flags&UTF8_FLAG) {
+
+
+
+ } else {
+ uint32_t len = decode_uint16(&p_manifest[string_at]);
+ Vector<CharType> ucstring;
+ ucstring.resize(len+1);
+ for(int j=0;j<len;j++) {
+ uint16_t c=decode_uint16(&p_manifest[string_at+2+2*j]);
+ ucstring[j]=c;
+ }
+ string_end=MAX(string_at+2+2*len,string_end);
+ ucstring[len]=0;
+ string_table[i]=ucstring.ptr();
+ }
+
+
+// print_line("String "+itos(i)+": "+string_table[i]);
+ }
+
+ for(int i=string_end;i<(ofs+size);i++) {
+ stable_extra.push_back(p_manifest[i]);
+ }
+
+// printf("stable extra: %i\n",int(stable_extra.size()));
+ string_table_ends=ofs+size;
+
+// print_line("STABLE SIZE: "+itos(size)+" ACTUAL: "+itos(string_table_ends));
+
+ } break;
+ case CHUNK_XML_START_TAG: {
+
+ int iofs=ofs+8;
+ uint32_t line=decode_uint32(&p_manifest[iofs]);
+ uint32_t nspace=decode_uint32(&p_manifest[iofs+8]);
+ uint32_t name=decode_uint32(&p_manifest[iofs+12]);
+ uint32_t check=decode_uint32(&p_manifest[iofs+16]);
+
+ String tname=string_table[name];
+
+// printf("NSPACE: %i\n",nspace);
+ //printf("NAME: %i (%s)\n",name,tname.utf8().get_data());
+ //printf("CHECK: %x\n",check);
+ uint32_t attrcount=decode_uint32(&p_manifest[iofs+20]);
+ iofs+=28;
+ //printf("ATTRCOUNT: %x\n",attrcount);
+ for(int i=0;i<attrcount;i++) {
+ uint32_t attr_nspace=decode_uint32(&p_manifest[iofs]);
+ uint32_t attr_name=decode_uint32(&p_manifest[iofs+4]);
+ uint32_t attr_value=decode_uint32(&p_manifest[iofs+8]);
+ uint32_t attr_flags=decode_uint32(&p_manifest[iofs+12]);
+ uint32_t attr_resid=decode_uint32(&p_manifest[iofs+16]);
+
+
+ String value;
+ if (attr_value!=0xFFFFFFFF)
+ value=string_table[attr_value];
+ else
+ value="Res #"+itos(attr_resid);
+ String attrname = string_table[attr_name];
+ String nspace;
+ if (attr_nspace!=0xFFFFFFFF)
+ nspace=string_table[attr_nspace];
+ else
+ nspace="";
+
+ printf("ATTR %i NSPACE: %i\n",i,attr_nspace);
+ printf("ATTR %i NAME: %i (%s)\n",i,attr_name,attrname.utf8().get_data());
+ printf("ATTR %i VALUE: %i (%s)\n",i,attr_value,value.utf8().get_data());
+ printf("ATTR %i FLAGS: %x\n",i,attr_flags);
+ printf("ATTR %i RESID: %x\n",i,attr_resid);
+
+ //replace project information
+ if (tname=="manifest" && attrname=="package") {
+
+ print_line("FOUND PACKAGE");
+ string_table[attr_value]=package;
+ }
+
+ //print_line("tname: "+tname);
+ //print_line("nspace: "+nspace);
+ //print_line("attrname: "+attrname);
+ if (tname=="manifest" && /*nspace=="android" &&*/ attrname=="versionCode") {
+
+ print_line("FOUND versioncode");
+ encode_uint32(version_code,&p_manifest[iofs+16]);
+ }
+
+
+ if (tname=="manifest" && /*nspace=="android" &&*/ attrname=="versionName") {
+
+ print_line("FOUND versionname");
+ if (attr_value==0xFFFFFFFF) {
+ WARN_PRINT("Version name in a resource, should be plaintext")
+ } else
+ string_table[attr_value]=version_name;
+ }
+
+ if (tname=="activity" && /*nspace=="android" &&*/ attrname=="screenOrientation") {
+
+ print_line("FOUND screen orientation");
+ if (attr_value==0xFFFFFFFF) {
+ WARN_PRINT("Version name in a resource, should be plaintext")
+ } else {
+ string_table[attr_value]=(orientation==0?"landscape":"portrait");
+ }
+ }
+
+ if (tname=="application" && /*nspace=="android" &&*/ attrname=="label") {
+
+ print_line("FOUND application");
+ if (attr_value==0xFFFFFFFF) {
+ WARN_PRINT("Application name in a resource, should be plaintext.")
+ } else {
+
+ String aname = get_project_name();
+ string_table[attr_value]=aname;
+ }
+ }
+ if (tname=="activity" && /*nspace=="android" &&*/ attrname=="label") {
+
+ print_line("FOUND activity name");
+ if (attr_value==0xFFFFFFFF) {
+ WARN_PRINT("Activity name in a resource, should be plaintext")
+ } else {
+ String aname;
+ if (this->name!="") {
+ aname=this->name;
+ } else {
+ aname = Globals::get_singleton()->get("application/name");
+
+ }
+
+ if (aname=="") {
+ aname=_MKSTR(VERSION_NAME);
+ }
+
+ print_line("APP NAME IS..."+aname);
+ string_table[attr_value]=aname;
+ }
+ }
+
+ iofs+=20;
+ }
+
+ } break;
+ }
+ printf("chunk %x: size: %d\n",chunk,size);
+
+ ofs+=size;
+ }
+
+ printf("end\n");
+
+ //create new andriodmanifest binary
+
+ Vector<uint8_t> ret;
+ ret.resize(string_table_begins+string_table.size()*4);
+
+ for(int i=0;i<string_table_begins;i++) {
+
+ ret[i]=p_manifest[i];
+ }
+
+ ofs=0;
+ for(int i=0;i<string_table.size();i++) {
+
+ encode_uint32(ofs,&ret[string_table_begins+i*4]);
+ ofs+=string_table[i].length()*2+2+2;
+ print_line("ofs: "+itos(i)+": "+itos(ofs));
+ }
+ ret.resize(ret.size()+ofs);
+ uint8_t *chars=&ret[ret.size()-ofs];
+ for(int i=0;i<string_table.size();i++) {
+
+ String s = string_table[i];
+ print_line("savint string :"+s);
+ encode_uint16(s.length(),chars);
+ chars+=2;
+ for(int j=0;j<s.length();j++) { //include zero?
+ encode_uint16(s[j],chars);
+ chars+=2;
+ }
+ encode_uint16(0,chars);
+ chars+=2;
+
+ }
+
+
+ ret.resize(ret.size()+stable_extra.size());
+ while(ret.size()%4)
+ ret.push_back(0);
+
+ for(int i=0;i<stable_extra.size();i++) {
+
+ chars[i]=stable_extra[i];
+ }
+
+
+ uint32_t new_stable_end=ret.size();
+
+ uint32_t extra = (p_manifest.size()-string_table_ends);
+ ret.resize(new_stable_end + extra);
+ for(int i=0;i<extra;i++)
+ ret[new_stable_end+i]=p_manifest[string_table_ends+i];
+
+ while(ret.size()%4)
+ ret.push_back(0);
+ encode_uint32(ret.size(),&ret[4]); //update new file size
+
+ encode_uint32(new_stable_end-8,&ret[12]); //update new string table size
+
+ print_line("file size: "+itos(ret.size()));
+
+ p_manifest=ret;
+
+
+
+
+
+
+#if 0
+ uint32_t header[9];
+ for(int i=0;i<9;i++) {
+ header[i]=decode_uint32(&p_manifest[i*4]);
+ }
+
+ print_line("STO: "+itos(header[3]));
+ uint32_t st_offset=9*4;
+ //ERR_FAIL_COND(header[3]!=0x24)
+ uint32_t string_count=header[4];
+
+
+ string_table.resize(string_count);
+
+ for(int i=0;i<string_count;i++) {
+
+ uint32_t string_at = decode_uint32(&p_manifest[st_offset+i*4]);
+ string_at+=st_offset+string_count*4;
+ uint32_t len = decode_uint16(&p_manifest[string_at]);
+ Vector<CharType> ucstring;
+ ucstring.resize(len+1);
+ for(int j=0;j<len;j++) {
+ uint16_t c=decode_uint16(&p_manifest[string_at+2+2*j]);
+ ucstring[j]=c;
+ }
+ ucstring[len]=0;
+ string_table[i]=ucstring.ptr();
+ }
+
+
+#endif
+
+}
+
+
+
+Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total) {
+
+ APKExportData *ed=(APKExportData*)p_userdata;
+ String dst_path=p_path;
+ dst_path=dst_path.replace_first("res://","assets/");
+
+ zipOpenNewFileInZip(ed->apk,
+ dst_path.utf8().get_data(),
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION);
+
+
+ zipWriteInFileInZip(ed->apk,p_data.ptr(),p_data.size());
+ zipCloseFileInZip(ed->apk);
+ ed->ep->step("File: "+p_path,3+p_file*100/p_total);
+ return OK;
+
+}
+
+
+
+Error EditorExportPlatformAndroid::export_project(const String& p_path,bool p_debug,const String& p_password) {
+
+ String src_apk;
+
+ EditorProgress ep("export","Exporting for Android",104);
+
+ String apk_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+
+ if (p_debug) {
+
+ src_apk=custom_debug_package!=""?custom_debug_package:apk_path+"android_debug.apk";
+ } else {
+
+ src_apk=custom_release_package!=""?custom_release_package:apk_path+"android_release.apk";
+
+ }
+
+
+ FileAccess *src_f=NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+
+
+ ep.step("Creating APK",0);
+
+ unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io);
+ if (!pkg) {
+
+ EditorNode::add_io_error("Could not find template APK to export:\n"+src_apk);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(pkg);
+
+ zlib_filefunc_def io2=io;
+ FileAccess *dst_f=NULL;
+ io2.opaque=&dst_f;
+ zipFile apk=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2);
+
+
+ while(ret==UNZ_OK) {
+
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0);
+
+ String file=fname;
+
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg,data.ptr(),data.size());
+ unzCloseCurrentFile(pkg);
+
+ //write
+
+ if (file=="AndroidManifest.xml") {
+
+ _fix_manifest(data);
+ }
+
+ if (file=="resources.arsc") {
+
+ _fix_resources(data);
+ }
+
+ if (file=="res/drawable/icon.png") {
+ bool found=false;
+
+ if (this->icon!="" && this->icon.ends_with(".png")) {
+
+ FileAccess *f = FileAccess::open(this->icon,FileAccess::READ);
+ if (f) {
+
+ data.resize(f->get_len());
+ f->get_buffer(data.ptr(),data.size());
+ memdelete(f);
+ found=true;
+ }
+
+ }
+
+ if (!found) {
+
+ String appicon = Globals::get_singleton()->get("application/icon");
+ if (appicon!="" && appicon.ends_with(".png")) {
+ FileAccess*f = FileAccess::open(appicon,FileAccess::READ);
+ if (f) {
+ data.resize(f->get_len());
+ f->get_buffer(data.ptr(),data.size());
+ memdelete(f);
+ }
+ }
+ }
+ }
+
+ print_line("ADDING: "+file);
+ zipOpenNewFileInZip(apk,
+ file.utf8().get_data(),
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION);
+
+ zipWriteInFileInZip(apk,data.ptr(),data.size());
+ zipCloseFileInZip(apk);
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+
+ ep.step("Adding Files..",1);
+
+
+
+ APKExportData ed;
+ ed.ep=&ep;
+ ed.apk=apk;
+
+ Error err = export_project_files(save_apk_file,&ed,false);
+
+ zipClose(apk,NULL);
+ unzClose(pkg);
+
+ if (err) {
+ return err;
+ }
+
+
+
+ if (_signed) {
+
+
+ String jarsigner=EditorSettings::get_singleton()->get("android/jarsigner");
+ if (!FileAccess::exists(jarsigner)) {
+ EditorNode::add_io_error("'jarsigner' could not be found.\nPlease supply a path in the editor settings.\nResulting apk is unsigned.");
+ return OK;
+ }
+
+ String keystore;
+ String password;
+ String user;
+ if (p_debug) {
+ keystore=EditorSettings::get_singleton()->get("android/debug_keystore");
+ password=EditorSettings::get_singleton()->get("android/debug_keystore_pass");
+ user=EditorSettings::get_singleton()->get("android/debug_keystore_user");
+
+ ep.step("Signing Debug APK..",103);
+
+ } else {
+ keystore=release_keystore;
+ password=p_password;
+ user=release_username;
+
+ ep.step("Signing Release APK..",103);
+
+ }
+
+ if (!FileAccess::exists(keystore)) {
+ EditorNode::add_io_error("Could not find keytore, unable to export.");
+ return ERR_FILE_CANT_OPEN;
+ }
+
+ List<String> args;
+ args.push_back("-digestalg");
+ args.push_back("SHA1");
+ args.push_back("-sigalg");
+ args.push_back("MD5withRSA");
+ args.push_back("-verbose");
+ args.push_back("-keystore");
+ args.push_back(keystore);
+ args.push_back("-storepass");
+ args.push_back(password);
+ args.push_back(p_path);
+ args.push_back(user);
+ int retval;
+ int err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval);
+ if (retval) {
+ EditorNode::add_io_error("'jarsigner' returned with error #"+itos(retval));
+ return ERR_CANT_CREATE;
+ }
+
+ ep.step("Verifying APK..",104);
+
+ args.clear();
+ args.push_back("-verify");
+ args.push_back(p_path);
+ args.push_back("-verbose");
+
+ err = OS::get_singleton()->execute(jarsigner,args,true,NULL,NULL,&retval);
+ if (retval) {
+ EditorNode::add_io_error("'jarsigner' verificaiton of APK failed. Make sure to use jarsigner from Java 6.");
+ return ERR_CANT_CREATE;
+ }
+
+ }
+ return OK;
+
+}
+
+
+bool EditorExportPlatformAndroid::poll_devices() {
+
+ bool dc=devices_changed;
+ devices_changed=false;
+ return dc;
+}
+
+int EditorExportPlatformAndroid::get_device_count() const {
+
+ device_lock->lock();
+ int dc=devices.size();
+ device_lock->unlock();
+
+ return dc;
+
+}
+String EditorExportPlatformAndroid::get_device_name(int p_device) const {
+
+ ERR_FAIL_INDEX_V(p_device,devices.size(),"");
+ device_lock->lock();
+ String s=devices[p_device].name;
+ device_lock->unlock();
+ return s;
+}
+String EditorExportPlatformAndroid::get_device_info(int p_device) const {
+
+ ERR_FAIL_INDEX_V(p_device,devices.size(),"");
+ device_lock->lock();
+ String s=devices[p_device].description;
+ device_lock->unlock();
+ return s;
+}
+
+void EditorExportPlatformAndroid::_device_poll_thread(void *ud) {
+
+ EditorExportPlatformAndroid *ea=(EditorExportPlatformAndroid *)ud;
+
+
+ while(!ea->quit_request) {
+
+ String adb=EditorSettings::get_singleton()->get("android/adb");
+ if (!FileAccess::exists(adb)) {
+ OS::get_singleton()->delay_usec(3000000);
+ continue; //adb not configured
+ }
+
+ String devices;
+ List<String> args;
+ args.push_back("devices");
+ int ec;
+ Error err = OS::get_singleton()->execute(adb,args,true,NULL,&devices,&ec);
+ Vector<String> ds = devices.split("\n");
+ Vector<String> ldevices;
+ for(int i=1;i<ds.size();i++) {
+
+ String d = ds[i];
+ int dpos = d.find("device");
+ if (dpos==-1)
+ continue;
+ d=d.substr(0,dpos).strip_edges();
+// print_line("found devuce: "+d);
+ ldevices.push_back(d);
+ }
+
+ ea->device_lock->lock();
+
+ bool different=false;
+
+ if (devices.size()!=ldevices.size()) {
+
+ different=true;
+ } else {
+
+ for(int i=0;i<ea->devices.size();i++) {
+
+ if (ea->devices[i].id!=ldevices[i]) {
+ different=true;
+ break;
+ }
+ }
+ }
+
+ if (different) {
+
+
+ Vector<Device> ndevices;
+
+ for(int i=0;i<ldevices.size();i++) {
+
+ Device d;
+ d.id=ldevices[i];
+ for(int j=0;j<ea->devices.size();j++) {
+ if (ea->devices[j].id==ldevices[i]) {
+ d.description=ea->devices[j].description;
+ d.name=ea->devices[j].name;
+ }
+ }
+
+ if (d.description=="") {
+ //in the oven, request!
+ args.clear();
+ args.push_back("-s");
+ args.push_back(d.id);
+ args.push_back("shell");
+ args.push_back("cat");
+ args.push_back("/system/build.prop");
+ int ec;
+ String dp;
+
+ Error err = OS::get_singleton()->execute(adb,args,true,NULL,&dp,&ec);
+ print_line("RV: "+itos(ec));
+ Vector<String> props = dp.split("\n");
+ String vendor;
+ String device;
+ d.description+"Device ID: "+d.id+"\n";
+ for(int j=0;j<props.size();j++) {
+
+ String p = props[j];
+ if (p.begins_with("ro.product.model=")) {
+ device=p.get_slice("=",1).strip_edges();
+ } else if (p.begins_with("ro.product.brand=")) {
+ vendor=p.get_slice("=",1).strip_edges().capitalize();
+ } else if (p.begins_with("ro.build.display.id=")) {
+ d.description+="Build: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.build.version.release=")) {
+ d.description+="Release: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.product.cpu.abi=")) {
+ d.description+="CPU: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.product.manufacturer=")) {
+ d.description+="Manufacturer: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.board.platform=")) {
+ d.description+="Chipset: "+p.get_slice("=",1).strip_edges()+"\n";
+ } else if (p.begins_with("ro.opengles.version=")) {
+ uint32_t opengl = p.get_slice("=",1).to_int();
+ d.description+="OpenGL: "+itos(opengl>>16)+"."+itos((opengl>>8)&0xFF)+"."+itos((opengl)&0xFF)+"\n";
+ }
+ }
+
+ d.name=vendor+" "+device;
+// print_line("name: "+d.name);
+// print_line("description: "+d.description);
+
+ }
+
+ ndevices.push_back(d);
+
+ }
+
+ ea->devices=ndevices;
+ ea->devices_changed=true;
+ }
+
+ ea->device_lock->unlock();
+
+ OS::get_singleton()->delay_usec(3000000);
+ }
+
+}
+
+Error EditorExportPlatformAndroid::run(int p_device) {
+
+ ERR_FAIL_INDEX_V(p_device,devices.size(),ERR_INVALID_PARAMETER);
+ device_lock->lock();
+
+ EditorProgress ep("run","Running on "+devices[p_device].name,3);
+
+ String adb=EditorSettings::get_singleton()->get("android/adb");
+ if (adb=="") {
+
+ EditorNode::add_io_error("ADB executable not configured in settings, can't run.");
+ device_lock->unlock();
+ return ERR_UNCONFIGURED;
+ }
+
+ //export_temp
+ ep.step("Exporting APK",0);
+
+ String export_to=EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpexport.apk";
+ Error err = export_project(export_to,true);
+ if (err) {
+ device_lock->unlock();
+ return err;
+ }
+
+ ep.step("Uninstalling..",1);
+
+ print_line("Uninstalling previous version: "+devices[p_device].name);
+ List<String> args;
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("uninstall");
+ args.push_back(package);
+ int rv;
+ err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
+#if 0
+ if (err || rv!=0) {
+ EditorNode::add_io_error("Could not install to device.");
+ device_lock->unlock();
+ return ERR_CANT_CREATE;
+ }
+#endif
+ print_line("Installing into device (please wait..): "+devices[p_device].name);
+ ep.step("Installing to Device (please wait..)..",2);
+
+ args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("install");
+ args.push_back(export_to);
+ rv;
+ err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
+ if (err || rv!=0) {
+ EditorNode::add_io_error("Could not install to device.");
+ device_lock->unlock();
+ return ERR_CANT_CREATE;
+ }
+
+ ep.step("Running on Device..",3);
+ args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("shell");
+ args.push_back("am");
+ args.push_back("start");
+ args.push_back("-a");
+ args.push_back("android.intent.action.MAIN");
+ args.push_back("-n");
+ args.push_back(package+"/com.android.godot.Godot");
+
+ err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
+ if (err || rv!=0) {
+ EditorNode::add_io_error("Could not execute ondevice.");
+ device_lock->unlock();
+ return ERR_CANT_CREATE;
+ }
+ device_lock->unlock();
+ return OK;
+}
+
+
+EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
+
+ version_code=1;
+ version_name="1.0";
+ package="com.android.noname";
+ name="";
+ _signed=true;
+ device_lock = Mutex::create();
+ quit_request=false;
+ orientation=0;
+
+ device_thread=Thread::create(_device_poll_thread,this);
+ devices_changed=true;
+
+ Image img( _android_logo );
+ logo = Ref<ImageTexture>( memnew( ImageTexture ));
+ logo->create_from_image(img);
+}
+
+bool EditorExportPlatformAndroid::can_export(String *r_error) const {
+
+ bool valid=true;
+ String adb=EditorSettings::get_singleton()->get("android/adb");
+ String err;
+
+ if (!FileAccess::exists(adb)) {
+
+ valid=false;
+ err+="ADB executable not configured in editor settings.\n";
+ }
+
+ String js = EditorSettings::get_singleton()->get("android/jarsigner");
+
+ if (!FileAccess::exists(js)) {
+
+ valid=false;
+ err+="OpenJDK 6 jarsigner not configured in editor settings.\n";
+ }
+
+ String dk = EditorSettings::get_singleton()->get("android/debug_keystore");
+
+ if (!FileAccess::exists(dk)) {
+
+ valid=false;
+ err+="Debug Keystore not configured in editor settings.\n";
+ }
+
+
+ String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+
+ if (!FileAccess::exists(exe_path+"android_debug.apk") || !FileAccess::exists(exe_path+"android_release.apk")) {
+ valid=false;
+ err+="No export templates found.\nDownload and install export templates.\n";
+ }
+
+ if (custom_debug_package!="" && !FileAccess::exists(custom_debug_package)) {
+ valid=false;
+ err+="Custom debug package not found.\n";
+ }
+
+ if (custom_release_package!="" && !FileAccess::exists(custom_release_package)) {
+ valid=false;
+ err+="Custom release package not found.\n";
+ }
+
+ if (r_error)
+ *r_error=err;
+
+ return valid;
+}
+
+
+EditorExportPlatformAndroid::~EditorExportPlatformAndroid() {
+
+ quit_request=true;
+ Thread::wait_to_finish(device_thread);
+}
+
+
+void register_android_exporter() {
+
+ String exe_ext=OS::get_singleton()->get_name()=="Windows"?"exe":"";
+ EDITOR_DEF("android/adb","");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/adb",PROPERTY_HINT_GLOBAL_FILE,exe_ext));
+ EDITOR_DEF("android/jarsigner","");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/jarsigner",PROPERTY_HINT_GLOBAL_FILE,exe_ext));
+ EDITOR_DEF("android/debug_keystore","");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/debug_keystore",PROPERTY_HINT_GLOBAL_FILE,"keystore"));
+ EDITOR_DEF("android/debug_keystore_user","androiddebugkey");
+ EDITOR_DEF("android/debug_keystore_pass","android");
+ //EDITOR_DEF("android/release_keystore","");
+ //EDITOR_DEF("android/release_username","");
+ //EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"android/release_keystore",PROPERTY_HINT_GLOBAL_FILE,"*.keystore"));
+
+ Ref<EditorExportPlatformAndroid> exporter = Ref<EditorExportPlatformAndroid>( memnew(EditorExportPlatformAndroid) );
+ EditorImportExport::get_singleton()->add_export_platform(exporter);
+
+
+}
+
diff --git a/platform/android/export/export.h b/platform/android/export/export.h
new file mode 100644
index 0000000000..88581802b8
--- /dev/null
+++ b/platform/android/export/export.h
@@ -0,0 +1,3 @@
+
+
+void register_android_exporter();
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
new file mode 100644
index 0000000000..f1a2bf5882
--- /dev/null
+++ b/platform/android/file_access_android.cpp
@@ -0,0 +1,187 @@
+/*************************************************************************/
+/* file_access_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "file_access_android.h"
+#include "print_string.h"
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+
+AAssetManager *FileAccessAndroid::asset_manager=NULL;
+
+
+void FileAccessAndroid::make_default() {
+
+ create_func=create_android;
+}
+
+FileAccess* FileAccessAndroid::create_android() {
+
+ return memnew(FileAccessAndroid);
+}
+
+
+Error FileAccessAndroid::open(const String& p_path, int p_mode_flags) {
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+
+
+ ERR_FAIL_COND_V(p_mode_flags&FileAccess::WRITE,ERR_UNAVAILABLE); //can't write on android..
+ a=AAssetManager_open(asset_manager,path.utf8().get_data(),AASSET_MODE_STREAMING);
+ if (!a)
+ return ERR_CANT_OPEN;
+ //ERR_FAIL_COND_V(!a,ERR_FILE_NOT_FOUND);
+ len=AAsset_getLength(a);
+ pos=0;
+ eof=false;
+
+ return OK;
+}
+
+void FileAccessAndroid::close() {
+
+ if (!a)
+ return;
+ AAsset_close(a);
+ a=NULL;
+}
+bool FileAccessAndroid::is_open() const {
+
+ return a!=NULL;
+}
+
+void FileAccessAndroid::seek(size_t p_position) {
+
+ ERR_FAIL_COND(!a);
+ AAsset_seek(a,p_position,SEEK_SET);
+ pos=p_position;
+ if (pos>len) {
+ pos=len;
+ eof=true;
+ } else {
+ eof=false;
+ }
+
+}
+void FileAccessAndroid::seek_end(int64_t p_position) {
+
+ ERR_FAIL_COND(!a);
+ AAsset_seek(a,p_position,SEEK_END);
+ pos=len+p_position;
+
+}
+size_t FileAccessAndroid::get_pos() const {
+
+ return pos;
+}
+size_t FileAccessAndroid::get_len() const {
+
+ return len;
+}
+
+bool FileAccessAndroid::eof_reached() const {
+
+ return eof;
+}
+
+uint8_t FileAccessAndroid::get_8() const {
+
+
+ if (pos>=len) {
+ eof=true;
+ return 0;
+ }
+
+
+ uint8_t byte;
+ AAsset_read(a,&byte,1);
+ pos++;
+ return byte;
+
+}
+int FileAccessAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
+
+
+ off_t r = AAsset_read(a,p_dst,p_length);
+ if (r>=0) {
+ pos+=r;
+ if (pos>len) {
+ pos=len;
+ eof=true;
+ }
+ }
+ return r;
+
+}
+
+Error FileAccessAndroid::get_error() const {
+
+ return eof?ERR_FILE_EOF:OK; //not sure what else it may happen
+}
+
+void FileAccessAndroid::store_8(uint8_t p_dest) {
+
+ ERR_FAIL();
+
+}
+
+bool FileAccessAndroid::file_exists(const String& p_path) {
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+ AAsset *at=AAssetManager_open(asset_manager,path.utf8().get_data(),AASSET_MODE_STREAMING);
+
+ if (!at)
+ return false;
+
+ AAsset_close(at);
+ return true;
+
+}
+
+
+FileAccessAndroid::FileAccessAndroid() {
+ a=NULL;
+ eof=false;
+}
+
+
+FileAccessAndroid::~FileAccessAndroid()
+{
+ close();
+}
+#endif
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
new file mode 100644
index 0000000000..080ab1a6ce
--- /dev/null
+++ b/platform/android/file_access_android.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* file_access_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_ANDROID_H
+#define FILE_ACCESS_ANDROID_H
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+
+#include "os/file_access.h"
+#include <stdio.h>
+#include <android/asset_manager.h>
+#include <android/log.h>
+#include <android_native_app_glue.h>
+
+
+class FileAccessAndroid : public FileAccess {
+
+ static FileAccess* create_android();
+ mutable AAsset *a;
+ mutable size_t len;
+ mutable size_t pos;
+ mutable bool eof;
+
+public:
+
+ static AAssetManager *asset_manager;
+
+ virtual Error open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+
+ virtual bool file_exists(const String& p_path); ///< return true if a file exists
+
+
+ static void make_default();
+
+ FileAccessAndroid();
+ ~FileAccessAndroid();
+};
+
+#endif // FILE_ACCESS_ANDROID_H
+#endif
diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp
new file mode 100644
index 0000000000..e1dec4f601
--- /dev/null
+++ b/platform/android/file_access_jandroid.cpp
@@ -0,0 +1,253 @@
+/*************************************************************************/
+/* file_access_jandroid.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "file_access_jandroid.h"
+#include "os/os.h"
+#include <unistd.h>
+#include "thread_jandroid.h"
+
+jobject FileAccessJAndroid::io=NULL;
+jclass FileAccessJAndroid::cls;
+jmethodID FileAccessJAndroid::_file_open=0;
+jmethodID FileAccessJAndroid::_file_get_size=0;
+jmethodID FileAccessJAndroid::_file_seek=0;
+jmethodID FileAccessJAndroid::_file_read=0;
+jmethodID FileAccessJAndroid::_file_tell=0;
+jmethodID FileAccessJAndroid::_file_eof=0;
+jmethodID FileAccessJAndroid::_file_close=0;
+
+
+FileAccess* FileAccessJAndroid::create_jandroid() {
+
+ return memnew(FileAccessJAndroid);
+}
+
+Error FileAccessJAndroid::_open(const String& p_path, int p_mode_flags) {
+
+ if (is_open())
+ close();
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ //OS::get_singleton()->print("env: %p, io %p, fo: %p\n",env,io,_file_open);
+
+
+ jstring js = env->NewStringUTF(path.utf8().get_data());
+ int res = env->CallIntMethod(io,_file_open,js,p_mode_flags&WRITE?true:false);
+
+ env->DeleteLocalRef(js);
+
+ if (res<=0)
+ return ERR_FILE_CANT_OPEN;
+ id=res;
+
+
+ return OK;
+}
+
+void FileAccessJAndroid::close() {
+
+ if (!is_open())
+ return;
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ env->CallVoidMethod(io,_file_close,id);
+ id=0;
+
+}
+bool FileAccessJAndroid::is_open() const {
+
+ return id!=0;
+}
+
+void FileAccessJAndroid::seek(size_t p_position) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ ERR_FAIL_COND(!is_open());
+ env->CallVoidMethod(io,_file_seek,id,p_position);
+}
+void FileAccessJAndroid::seek_end(int64_t p_position) {
+
+ ERR_FAIL_COND(!is_open());
+
+ seek(get_len());
+
+}
+size_t FileAccessJAndroid::get_pos() const {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_tell,id);
+
+}
+size_t FileAccessJAndroid::get_len() const {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_get_size,id);
+
+
+}
+
+bool FileAccessJAndroid::eof_reached() const {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ ERR_FAIL_COND_V(!is_open(),0);
+ return env->CallIntMethod(io,_file_eof,id);
+
+}
+
+uint8_t FileAccessJAndroid::get_8() const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ uint8_t byte;
+ get_buffer(&byte,1);
+ return byte;
+}
+int FileAccessJAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
+
+ ERR_FAIL_COND_V(!is_open(),0);
+ if (p_length==0)
+ return 0;
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jbyteArray jca = (jbyteArray)env->CallObjectMethod(io,_file_read,id,p_length);
+
+
+ int len = env->GetArrayLength(jca);
+ env->GetByteArrayRegion(jca,0,len,(jbyte*)p_dst);
+ env->DeleteLocalRef((jobject)jca);
+
+ return len;
+
+}
+
+Error FileAccessJAndroid::get_error() const {
+
+ if (eof_reached())
+ return ERR_FILE_EOF;
+ return OK;
+}
+
+void FileAccessJAndroid::store_8(uint8_t p_dest) {
+
+
+}
+
+bool FileAccessJAndroid::file_exists(const String& p_path) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ String path=fix_path(p_path).simplify_path();
+ if (path.begins_with("/"))
+ path=path.substr(1,path.length());
+ else if (path.begins_with("res://"))
+ path=path.substr(6,path.length());
+
+ jstring js = env->NewStringUTF(path.utf8().get_data());
+ int res = env->CallIntMethod(io,_file_open,js,false);
+ if (res<=0)
+ return false;
+ env->CallVoidMethod(io,_file_close,res);
+ env->DeleteLocalRef(js);
+ return true;
+
+}
+
+
+void FileAccessJAndroid::setup( jobject p_io) {
+
+
+ io=p_io;
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP5");
+
+ jclass c = env->GetObjectClass(io);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP6");
+ cls=(jclass)env->NewGlobalRef(c);
+
+ _file_open = env->GetMethodID(cls, "file_open", "(Ljava/lang/String;Z)I");
+ if(_file_open != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_open ok!!");
+ }
+ _file_get_size = env->GetMethodID(cls, "file_get_size", "(I)I");
+ if(_file_get_size != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_get_size ok!!");
+ }
+ _file_tell = env->GetMethodID(cls, "file_tell", "(I)I");
+ if(_file_tell != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_tell ok!!");
+ }
+ _file_eof = env->GetMethodID(cls, "file_eof", "(I)Z");
+
+ if(_file_eof != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_eof ok!!");
+ }
+ _file_seek = env->GetMethodID(cls, "file_seek", "(II)V");
+ if(_file_seek != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_seek ok!!");
+ }
+ _file_read = env->GetMethodID(cls, "file_read", "(II)[B");
+ if(_file_read != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_read ok!!");
+ }
+ _file_close = env->GetMethodID(cls, "file_close", "(I)V");
+ if(_file_close != 0) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******GOT METHOD _file_close ok!!");
+ }
+
+// (*env)->CallVoidMethod(env,obj,aMethodID, myvar);
+}
+
+
+FileAccessJAndroid::FileAccessJAndroid()
+{
+
+ id=0;
+}
+
+FileAccessJAndroid::~FileAccessJAndroid()
+{
+
+ if (is_open())
+ close();
+}
+
+
+#endif
diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h
new file mode 100644
index 0000000000..3cbeab5ffc
--- /dev/null
+++ b/platform/android/file_access_jandroid.h
@@ -0,0 +1,87 @@
+/*************************************************************************/
+/* file_access_jandroid.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_JANDROID_H
+#define FILE_ACCESS_JANDROID_H
+
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "java_glue.h"
+#include "os/file_access.h"
+class FileAccessJAndroid : public FileAccess {
+
+ static jobject io;
+ static jclass cls;
+
+ static jmethodID _file_open;
+ static jmethodID _file_get_size;
+ static jmethodID _file_seek;
+ static jmethodID _file_tell;
+ static jmethodID _file_eof;
+ static jmethodID _file_read;
+ static jmethodID _file_close;
+
+ int id;
+ static FileAccess* create_jandroid();
+
+
+public:
+
+ virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+
+ virtual bool file_exists(const String& p_path); ///< return true if a file exists
+
+
+
+ static void setup( jobject io);
+
+ virtual uint64_t _get_modified_time(const String& p_file) { return 0; }
+
+ FileAccessJAndroid();
+ ~FileAccessJAndroid();
+};
+
+#endif
+
+#endif // FILE_ACCESS_JANDROID_H
diff --git a/platform/android/globals/global_defaults.cpp b/platform/android/globals/global_defaults.cpp
new file mode 100644
index 0000000000..c6f852a592
--- /dev/null
+++ b/platform/android/globals/global_defaults.cpp
@@ -0,0 +1,13 @@
+
+#include "global_defaults.h"
+#include "globals.h"
+
+
+void register_android_global_defaults() {
+
+ GLOBAL_DEF("rasterizer.Android/use_fragment_lighting",false);
+ GLOBAL_DEF("display.Android/driver","GLES2");
+ GLOBAL_DEF("rasterizer.Android/trilinear_mipmap_filter",false);
+
+ Globals::get_singleton()->set_custom_property_info("display.Android/driver",PropertyInfo(Variant::STRING,"display.Android/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2"));
+}
diff --git a/platform/android/globals/global_defaults.h b/platform/android/globals/global_defaults.h
new file mode 100644
index 0000000000..64eb26c482
--- /dev/null
+++ b/platform/android/globals/global_defaults.h
@@ -0,0 +1,3 @@
+
+
+void register_android_global_defaults(); \ No newline at end of file
diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp
new file mode 100644
index 0000000000..673ff91641
--- /dev/null
+++ b/platform/android/godot_android.cpp
@@ -0,0 +1,993 @@
+/*************************************************************************/
+/* godot_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+#include <jni.h>
+#include <errno.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+
+#include <android/sensor.h>
+#include <android/window.h>
+#include <android/log.h>
+#include <android_native_app_glue.h>
+#include "file_access_android.h"
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "os_android.h"
+#include "globals.h"
+#include "main/main.h"
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "godot", __VA_ARGS__))
+#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "godot", __VA_ARGS__))
+
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object);
+ JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
+ JNIEXPORT jstring JNICALL Java_com_android_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path);
+};
+
+class JNISingleton : public Object {
+
+ OBJ_TYPE( JNISingleton, Object );
+
+
+ struct MethodData {
+
+
+ jmethodID method;
+ Variant::Type ret_type;
+ Vector<Variant::Type> argtypes;
+ };
+
+ jobject instance;
+ Map<StringName,MethodData> method_map;
+ JNIEnv *env;
+
+public:
+
+ void update_env(JNIEnv *p_env) { env=p_env; }
+
+ virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
+
+ print_line("attempt to call "+String(p_method));
+
+ r_error.error=Variant::CallError::CALL_OK;
+
+ Map<StringName,MethodData >::Element *E=method_map.find(p_method);
+ if (!E) {
+
+ print_line("no exists");
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+
+
+ int ac = E->get().argtypes.size();
+ if (ac<p_argcount) {
+
+ print_line("fewargs");
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=ac;
+ return Variant();
+ }
+
+ if (ac>p_argcount) {
+
+ print_line("manyargs");
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument=ac;
+ return Variant();
+ }
+
+
+
+ for(int i=0;i<p_argcount;i++) {
+
+ if (!Variant::can_convert(p_args[i]->get_type(),E->get().argtypes[i])) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=i;
+ r_error.expected=E->get().argtypes[i];
+ }
+ }
+
+
+ jvalue *v=NULL;
+
+ if (p_argcount) {
+
+ v=(jvalue*)alloca( sizeof(jvalue)*p_argcount );
+ }
+
+ for(int i=0;i<p_argcount;i++) {
+
+
+ switch(E->get().argtypes[i]) {
+
+ case Variant::BOOL: {
+
+ v[i].z=*p_args[i];
+ } break;
+ case Variant::INT: {
+
+ v[i].i=*p_args[i];
+ } break;
+ case Variant::REAL: {
+
+ v[i].f=*p_args[i];
+ } break;
+ case Variant::STRING: {
+
+ String s = *p_args[i];
+ jstring jStr = env->NewStringUTF(s.utf8().get_data());
+ v[i].l=jStr;
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ DVector<String> sarray = *p_args[i];
+ jobjectArray arr = env->NewObjectArray(sarray.size(),env->FindClass("java/lang/String"),env->NewStringUTF(""));
+
+ for(int j=0;j<sarray.size();j++) {
+
+ env->SetObjectArrayElement(arr,j,env->NewStringUTF( sarray[i].utf8().get_data() ));
+ }
+ v[i].l=arr;
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ DVector<int> array = *p_args[i];
+ jintArray arr = env->NewIntArray(array.size());
+ DVector<int>::Read r = array.read();
+ env->SetIntArrayRegion(arr,0,array.size(),r.ptr());
+ v[i].l=arr;
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ DVector<float> array = *p_args[i];
+ jfloatArray arr = env->NewFloatArray(array.size());
+ DVector<float>::Read r = array.read();
+ env->SetFloatArrayRegion(arr,0,array.size(),r.ptr());
+ v[i].l=arr;
+
+ } break;
+ default: {
+
+ ERR_FAIL_V(Variant());
+ } break;
+
+ }
+ }
+
+ print_line("calling method!!");
+
+ Variant ret;
+
+ switch(E->get().ret_type) {
+
+ case Variant::NIL: {
+
+
+ print_line("call void");
+ env->CallVoidMethodA(instance,E->get().method,v);
+ } break;
+ case Variant::BOOL: {
+
+ ret = env->CallBooleanMethodA(instance,E->get().method,v);
+ print_line("call bool");
+ } break;
+ case Variant::INT: {
+
+ ret = env->CallIntMethodA(instance,E->get().method,v);
+ print_line("call int");
+ } break;
+ case Variant::REAL: {
+
+ ret = env->CallFloatMethodA(instance,E->get().method,v);
+ } break;
+ case Variant::STRING: {
+
+ jobject o = env->CallObjectMethodA(instance,E->get().method,v);
+ String singname = env->GetStringUTFChars((jstring)o, NULL );
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int stringCount = env->GetArrayLength(arr);
+ DVector<String> sarr;
+
+ for (int i=0; i<stringCount; i++) {
+ jstring string = (jstring) env->GetObjectArrayElement(arr, i);
+ const char *rawString = env->GetStringUTFChars(string, 0);
+ sarr.push_back(String(rawString));
+ }
+
+ ret=sarr;
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ jintArray arr = (jintArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int fCount = env->GetArrayLength(arr);
+ DVector<int> sarr;
+ sarr.resize(fCount);
+
+ DVector<int>::Write w = sarr.write();
+ env->GetIntArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<int>::Write();
+ ret=sarr;
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int fCount = env->GetArrayLength(arr);
+ DVector<float> sarr;
+ sarr.resize(fCount);
+
+ DVector<float>::Write w = sarr.write();
+ env->GetFloatArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<float>::Write();
+ ret=sarr;
+ } break;
+ default: {
+
+
+ print_line("failure..");
+ ERR_FAIL_V(Variant());
+ } break;
+ }
+
+ print_line("success");
+
+ return ret;
+ }
+
+
+ jobject get_instance() const {
+
+ return instance;
+ }
+ void set_instance(jobject p_instance) {
+
+ instance=p_instance;
+ }
+
+
+ void add_method(const StringName& p_name, jmethodID p_method,const Vector<Variant::Type>& p_args, Variant::Type p_ret_type) {
+
+ MethodData md;
+ md.method=p_method;
+ md.argtypes=p_args;
+ md.ret_type=p_ret_type;
+ method_map[p_name]=md;
+
+ }
+
+
+ JNISingleton() {}
+
+};
+
+//JNIEnv *JNISingleton::env=NULL;
+
+static HashMap<String,JNISingleton*> jni_singletons;
+
+
+struct engine {
+ struct android_app* app;
+ OS_Android *os;
+ JNIEnv *jni;
+
+ ASensorManager* sensorManager;
+ const ASensor* accelerometerSensor;
+ ASensorEventQueue* sensorEventQueue;
+
+ bool display_active;
+ bool requested_quit;
+ int animating;
+ EGLDisplay display;
+ EGLSurface surface;
+ EGLContext context;
+ int32_t width;
+ int32_t height;
+
+};
+
+/**
+ * Initialize an EGL context for the current display.
+ */
+static int engine_init_display(struct engine* engine,bool p_gl2) {
+ // initialize OpenGL ES and EGL
+
+ /*
+ * Here specify the attributes of the desired configuration.
+ * Below, we select an EGLConfig with at least 8 bits per color
+ * component compatible with on-screen windows
+ */
+ const EGLint gl2_attribs[] = {
+ // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_BLUE_SIZE, 4,
+ EGL_GREEN_SIZE, 4,
+ EGL_RED_SIZE, 4,
+ EGL_ALPHA_SIZE, 0,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, EGL_DONT_CARE,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+
+ const EGLint gl1_attribs[] = {
+ // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_BLUE_SIZE, 4,
+ EGL_GREEN_SIZE, 4,
+ EGL_RED_SIZE, 4,
+ EGL_ALPHA_SIZE, 0,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, EGL_DONT_CARE,
+ EGL_NONE
+ };
+
+ const EGLint *attribs=p_gl2?gl2_attribs:gl1_attribs;
+
+
+ EGLint w, h, dummy, format;
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLContext context;
+
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ eglInitialize(display, 0, 0);
+
+
+ /* Here, the application chooses the configuration it desires. In this
+ * sample, we have a very simplified selection process, where we pick
+ * the first EGLConfig that matches our criteria */
+
+ eglChooseConfig(display, attribs, &config, 1, &numConfigs);
+
+ LOGI("Num configs: %i\n",numConfigs);
+
+ /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
+ * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
+ * As soon as we picked a EGLConfig, we can safely reconfigure the
+ * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
+ eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
+
+ ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
+ //ANativeWindow_setFlags(engine->app->window, 0, 0, format|);
+
+ surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
+
+ const EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION,2,
+ EGL_NONE
+ };
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, p_gl2?context_attribs:NULL);
+
+ if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
+ LOGW("Unable to eglMakeCurrent");
+ return -1;
+ }
+
+ eglQuerySurface(display, surface, EGL_WIDTH, &w);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+ print_line("INIT VIDEO MODE: "+itos(w)+","+itos(h));
+
+ //engine->os->set_egl_extensions(eglQueryString(display,EGL_EXTENSIONS));
+ engine->os->init_video_mode(w,h);
+
+
+ engine->display = display;
+ engine->context = context;
+ engine->surface = surface;
+ engine->width = w;
+ engine->height = h;
+ engine->display_active=true;
+
+ //engine->state.angle = 0;
+
+ // Initialize GL state.
+ //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+ glEnable(GL_CULL_FACE);
+ // glShadeModel(GL_SMOOTH);
+ glDisable(GL_DEPTH_TEST);
+ LOGI("GL Version: %s - %s %s\n", glGetString(GL_VERSION),glGetString(GL_VENDOR), glGetString(GL_RENDERER));
+
+ return 0;
+}
+
+
+static void engine_draw_frame(struct engine* engine) {
+ if (engine->display == NULL) {
+ // No display.
+ return;
+ }
+
+ // Just fill the screen with a color.
+ //glClearColor(0,1,0,1);
+ //glClear(GL_COLOR_BUFFER_BIT);
+ if (engine->os && engine->os->main_loop_iterate()==true) {
+
+ engine->requested_quit=true;
+ return; //should exit instead
+ }
+
+ eglSwapBuffers(engine->display, engine->surface);
+}
+
+
+static void engine_term_display(struct engine* engine) {
+ if (engine->display != EGL_NO_DISPLAY) {
+ eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (engine->context != EGL_NO_CONTEXT) {
+ eglDestroyContext(engine->display, engine->context);
+ }
+ if (engine->surface != EGL_NO_SURFACE) {
+ eglDestroySurface(engine->display, engine->surface);
+ }
+ eglTerminate(engine->display);
+ }
+
+ engine->animating = 0;
+ engine->display = EGL_NO_DISPLAY;
+ engine->context = EGL_NO_CONTEXT;
+ engine->surface = EGL_NO_SURFACE;
+ engine->display_active=false;
+
+}
+
+/**
+ * Process the next input event.
+ */
+static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
+ struct engine* engine = (struct engine*)app->userData;
+
+ if (!engine->os)
+ return 0;
+
+ switch(AInputEvent_getType(event)) {
+
+ case AINPUT_EVENT_TYPE_KEY: {
+
+ int ac = AKeyEvent_getAction(event);
+ switch(ac) {
+
+ case AKEY_EVENT_ACTION_DOWN: {
+
+ int32_t code = AKeyEvent_getKeyCode(event);
+ if (code==AKEYCODE_BACK) {
+
+ //AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
+ if (engine->os)
+ engine->os->main_loop_request_quit();
+ return 1;
+
+ }
+
+
+ } break;
+ case AKEY_EVENT_ACTION_UP: {
+
+
+ } break;
+ }
+
+
+ } break;
+ case AINPUT_EVENT_TYPE_MOTION: {
+
+
+ Vector<OS_Android::TouchPos> touchvec;
+
+ int pc = AMotionEvent_getPointerCount(event);
+
+ touchvec.resize(pc);
+
+ for(int i=0;i<pc;i++) {
+
+ touchvec[i].pos.x=AMotionEvent_getX(event,i);
+ touchvec[i].pos.y=AMotionEvent_getY(event,i);
+ touchvec[i].id=AMotionEvent_getPointerId(event,i);
+ }
+
+
+ //System.out.printf("gaction: %d\n",event.getAction());
+ int pidx=(AMotionEvent_getAction(event)&AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)>>8;
+ switch(AMotionEvent_getAction(event)&AMOTION_EVENT_ACTION_MASK) {
+
+ case AMOTION_EVENT_ACTION_DOWN: {
+ engine->os->process_touch(0,0,touchvec);
+
+ //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
+ } break;
+ case AMOTION_EVENT_ACTION_MOVE: {
+ engine->os->process_touch(1,0,touchvec);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+ case AMOTION_EVENT_ACTION_POINTER_UP: {
+
+ engine->os->process_touch(4,pidx,touchvec);
+ //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case AMOTION_EVENT_ACTION_POINTER_DOWN: {
+ engine->os->process_touch(3,pidx,touchvec);
+ //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case AMOTION_EVENT_ACTION_CANCEL:
+ case AMOTION_EVENT_ACTION_UP: {
+ engine->os->process_touch(2,0,touchvec);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+ }
+
+ return 1;
+ } break;
+
+ }
+
+ return 0;
+}
+
+/**
+ * Process the next main command.
+ */
+
+static void _gfx_init(void *ud,bool p_gl2) {
+
+ struct engine* engine = (struct engine*)ud;
+ engine_init_display(engine,p_gl2);
+}
+
+static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
+ struct engine* engine = (struct engine*)app->userData;
+ // LOGI("**** CMD %i\n",cmd);
+ switch (cmd) {
+ case APP_CMD_SAVE_STATE:
+ // The system has asked us to save our current state. Do so.
+ //engine->app->savedState = malloc(sizeof(struct saved_state));
+ //*((struct saved_state*)engine->app->savedState) = engine->state;
+ //engine->app->savedStateSize = sizeof(struct saved_state);
+ break;
+ case APP_CMD_CONFIG_CHANGED:
+ case APP_CMD_WINDOW_RESIZED: {
+
+#if 0
+// android blows
+ if (engine->display_active) {
+
+ EGLint w,h;
+ eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
+ eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
+ engine->os->init_video_mode(w,h);
+ //print_line("RESIZED VIDEO MODE: "+itos(w)+","+itos(h));
+ engine_draw_frame(engine);
+
+ }
+#else
+
+ if (engine->display_active) {
+
+
+ EGLint w,h;
+ eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
+ eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
+ // if (w==engine->os->get_video_mode().width && h==engine->os->get_video_mode().height)
+ // break;
+
+ engine_term_display(engine);
+
+
+ }
+
+
+ engine->os->reload_gfx();
+ engine_draw_frame(engine);
+ engine->animating=1;
+
+ /*
+ EGLint w,h;
+ eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
+ eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
+ engine->os->init_video_mode(w,h);
+ //print_line("RESIZED VIDEO MODE: "+itos(w)+","+itos(h));
+
+ }*/
+
+#endif
+
+ } break;
+ case APP_CMD_INIT_WINDOW:
+ //The window is being shown, get it ready.
+ // LOGI("INIT WINDOW");
+ if (engine->app->window != NULL) {
+
+ if (engine->os==NULL) {
+
+ //do initialization here, when there's OpenGL! hackish but the only way
+ engine->os = new OS_Android(_gfx_init,engine);
+
+ // char *args[]={"-test","gui",NULL};
+ __android_log_print(ANDROID_LOG_INFO,"godot","pre asdasd setup...");
+#if 0
+ Error err = Main::setup("apk",2,args);
+#else
+ Error err = Main::setup("apk",0,NULL);
+
+ String modules = Globals::get_singleton()->get("android/modules");
+ Vector<String> mods = modules.split(",",false);
+ mods.push_back("GodotOS");
+ __android_log_print(ANDROID_LOG_INFO,"godot","mod count: %i",mods.size());
+
+ if (mods.size()) {
+
+ jclass activityClass = engine->jni->FindClass("android/app/NativeActivity");
+
+ jmethodID getClassLoader = engine->jni->GetMethodID(activityClass,"getClassLoader", "()Ljava/lang/ClassLoader;");
+
+ jobject cls = engine->jni->CallObjectMethod(app->activity->clazz, getClassLoader);
+
+ jclass classLoader = engine->jni->FindClass("java/lang/ClassLoader");
+
+ jmethodID findClass = engine->jni->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
+
+ static JNINativeMethod methods[] = {
+ {"registerSingleton", "(Ljava/lang/String;Ljava/lang/Object;)V",(void *)&Java_com_android_godot_Godot_registerSingleton},
+ {"registerMethod", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",(void *)&Java_com_android_godot_Godot_registerMethod},
+ {"getGlobal", "(Ljava/lang/String;)Ljava/lang/String;", (void *)&Java_com_android_godot_Godot_getGlobal},
+ };
+
+ jstring gstrClassName = engine->jni->NewStringUTF("com/android/godot/Godot");
+ jclass GodotClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, gstrClassName);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","godot ****^*^*?^*^*class data %x",GodotClass);
+
+ engine->jni->RegisterNatives(GodotClass,methods,sizeof(methods)/sizeof(methods[0]));
+
+ for (int i=0;i<mods.size();i++) {
+
+ String m = mods[i];
+ //jclass singletonClass = engine->jni->FindClass(m.utf8().get_data());
+
+ jstring strClassName = engine->jni->NewStringUTF(m.utf8().get_data());
+ jclass singletonClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, strClassName);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class data %x",singletonClass);
+ jmethodID initialize = engine->jni->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lcom/android/godot/Godot$SingletonBase;");
+
+
+ jobject obj = engine->jni->CallStaticObjectMethod(singletonClass,initialize,app->activity->clazz);
+ __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class instance %x",obj);
+ jobject gob = engine->jni->NewGlobalRef(obj);
+
+
+ }
+
+ }
+
+#endif
+
+
+ if (!Main::start())
+ return; //should exit instead and print the error
+
+ engine->os->main_loop_begin();
+ } else {
+ //i guess recreate resources?
+ engine->os->reload_gfx();
+ }
+
+
+ engine->animating=1;
+ engine_draw_frame(engine);
+ }
+ break;
+ case APP_CMD_TERM_WINDOW:
+ // The window is being hidden or closed, clean it up.
+ // LOGI("TERM WINDOW");
+ engine_term_display(engine);
+ break;
+ case APP_CMD_GAINED_FOCUS:
+ // When our app gains focus, we start monitoring the accelerometer.
+ if (engine->accelerometerSensor != NULL) {
+ ASensorEventQueue_enableSensor(engine->sensorEventQueue,
+ engine->accelerometerSensor);
+ // We'd like to get 60 events per second (in us).
+ ASensorEventQueue_setEventRate(engine->sensorEventQueue,
+ engine->accelerometerSensor, (1000L/60)*1000);
+
+ }
+ engine->animating = 1;
+ break;
+ case APP_CMD_LOST_FOCUS:
+ // When our app loses focus, we stop monitoring the accelerometer.
+ // This is to avoid consuming battery while not being used.
+ if (engine->accelerometerSensor != NULL) {
+ ASensorEventQueue_disableSensor(engine->sensorEventQueue,
+ engine->accelerometerSensor);
+ }
+ // Also stop animating.
+ engine->animating = 0;
+ engine_draw_frame(engine);
+ break;
+ }
+}
+
+void android_main(struct android_app* state) {
+ struct engine engine;
+ // Make sure glue isn't stripped.
+ app_dummy();
+
+ memset(&engine, 0, sizeof(engine));
+ state->userData = &engine;
+ state->onAppCmd = engine_handle_cmd;
+ state->onInputEvent = engine_handle_input;
+ engine.app = state;
+ engine.requested_quit=false;
+ engine.os=NULL;
+ engine.display_active=false;
+
+ FileAccessAndroid::asset_manager=state->activity->assetManager;
+
+ // Prepare to monitor accelerometer
+ engine.sensorManager = ASensorManager_getInstance();
+ engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
+ ASENSOR_TYPE_ACCELEROMETER);
+ engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
+ state->looper, LOOPER_ID_USER, NULL, NULL);
+
+
+ ANativeActivity_setWindowFlags(state->activity,AWINDOW_FLAG_FULLSCREEN|AWINDOW_FLAG_KEEP_SCREEN_ON,0);
+
+ state->activity->vm->AttachCurrentThread(&engine.jni, NULL);
+
+
+
+ // loop waiting for stuff to do.
+
+ while (1) {
+ // Read all pending events.
+ int ident;
+ int events;
+ struct android_poll_source* source;
+
+ // If not animating, we will block forever waiting for events.
+ // If animating, we loop until all events are read, then continue
+ // to draw the next frame of animation.
+
+ int nullmax=50;
+ while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
+ (void**)&source)) >= 0) {
+
+ // Process this event.
+
+ if (source != NULL) {
+ // LOGI("process\n");
+ source->process(state, source);
+ } else {
+ nullmax--;
+ if (nullmax<0)
+ break;
+ }
+
+ // If a sensor has data, process it now.
+ // LOGI("events\n");
+ if (ident == LOOPER_ID_USER) {
+ if (engine.accelerometerSensor != NULL) {
+ ASensorEvent event;
+ while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
+ &event, 1) > 0) {
+
+
+ if (engine.os) {
+ engine.os->process_accelerometer(Vector3(event.acceleration.x, event.acceleration.y,
+ event.acceleration.z));
+
+ }
+
+ }
+ }
+ }
+
+ // Check if we are exiting.
+ if (state->destroyRequested != 0) {
+ if (engine.os) {
+ engine.os->main_loop_request_quit();
+ }
+ state->destroyRequested=0;
+ }
+
+ if (engine.requested_quit) {
+ engine_term_display(&engine);
+ exit(0);
+ return;
+ }
+
+// LOGI("end\n");
+
+
+ }
+
+// LOGI("engine animating? %i\n",engine.animating);
+
+ if (engine.animating) {
+ //do os render
+
+ engine_draw_frame(&engine);
+ //LOGI("TERM WINDOW");
+
+ }
+ }
+
+}
+
+
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object){
+
+ String singname = env->GetStringUTFChars( name, NULL );
+ JNISingleton *s = memnew( JNISingleton );
+ s->update_env(env);
+ s->set_instance(env->NewGlobalRef(p_object));
+ jni_singletons[singname]=s;
+
+ Globals::get_singleton()->add_singleton(Globals::Singleton(singname,s));
+
+}
+
+
+static Variant::Type get_jni_type(const String& p_type) {
+
+ static struct {
+ const char *name;
+ Variant::Type type;
+ } _type_to_vtype[]={
+ {"void",Variant::NIL},
+ {"boolean",Variant::BOOL},
+ {"int",Variant::INT},
+ {"float",Variant::REAL},
+ {"java.lang.String",Variant::STRING},
+ {"[I",Variant::INT_ARRAY},
+ {"[F",Variant::REAL_ARRAY},
+ {"[java.lang.String",Variant::STRING_ARRAY},
+ {NULL,Variant::NIL}
+ };
+
+ int idx=0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type==_type_to_vtype[idx].name)
+ return _type_to_vtype[idx].type;
+
+ idx++;
+ }
+
+ return Variant::NIL;
+}
+
+
+static const char* get_jni_sig(const String& p_type) {
+
+ static struct {
+ const char *name;
+ const char *sig;
+ } _type_to_vtype[]={
+ {"void","V"},
+ {"boolean","Z"},
+ {"int","I"},
+ {"float","F"},
+ {"java.lang.String","Ljava/lang/String;"},
+ {"[I","[I"},
+ {"[F","[F"},
+ {"[java.lang.String","[Ljava/lang/String;"},
+ {NULL,"V"}
+ };
+
+ int idx=0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type==_type_to_vtype[idx].name)
+ return _type_to_vtype[idx].sig;
+
+ idx++;
+ }
+
+
+ return "";
+}
+
+JNIEXPORT jstring JNICALL Java_com_android_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path) {
+
+ String js = env->GetStringUTFChars( path, NULL );
+
+ return env->NewStringUTF(Globals::get_singleton()->get(js).operator String().utf8().get_data());
+
+
+}
+
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args){
+
+ String singname = env->GetStringUTFChars( sname, NULL );
+
+ ERR_FAIL_COND(!jni_singletons.has(singname));
+
+ JNISingleton *s = jni_singletons.get(singname);
+
+
+ String mname = env->GetStringUTFChars( name, NULL );
+ String retval = env->GetStringUTFChars( ret, NULL );
+ Vector<Variant::Type> types;
+ String cs="(";
+
+
+ int stringCount = env->GetArrayLength(args);
+
+ print_line("Singl: "+singname+" Method: "+mname+" RetVal: "+retval);
+ for (int i=0; i<stringCount; i++) {
+
+ jstring string = (jstring) env->GetObjectArrayElement(args, i);
+ const char *rawString = env->GetStringUTFChars(string, 0);
+ types.push_back(get_jni_type(String(rawString)));
+ cs+=get_jni_sig(String(rawString));
+ }
+
+ cs+=")";
+ cs+=get_jni_sig(retval);
+ jclass cls = env->GetObjectClass(s->get_instance());
+ print_line("METHOD: "+mname+" sig: "+cs);
+ jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
+ if (!mid) {
+
+ print_line("FAILED GETTING METHOID "+mname);
+ }
+
+ s->add_method(mname,mid,types,get_jni_type(retval));
+
+
+}
+
+#endif
diff --git a/platform/android/java/ant.properties b/platform/android/java/ant.properties
new file mode 100644
index 0000000000..950b8b0199
--- /dev/null
+++ b/platform/android/java/ant.properties
@@ -0,0 +1,22 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked into Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
+key.store=my-release-key.keystore
+key.alias=mykey
+
+key.store.password=123456
+key.alias.password=123456
diff --git a/platform/android/java/build.properties b/platform/android/java/build.properties
new file mode 100644
index 0000000000..ee52d86d94
--- /dev/null
+++ b/platform/android/java/build.properties
@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
diff --git a/platform/android/java/build.xml b/platform/android/java/build.xml
new file mode 100644
index 0000000000..424e2827dc
--- /dev/null
+++ b/platform/android/java/build.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Godot" default="help">
+
+ <!-- The local.properties file is created and updated by the 'android' tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+
+ <!-- The ant.properties file can be created by you. It is only edited by the
+ 'android' tool to add properties to it.
+ This is the place to change some Ant specific build properties.
+ Here are some properties you may want to change/update:
+
+ source.dir
+ The name of the source directory. Default is 'src'.
+ out.dir
+ The name of the output directory. Default is 'bin'.
+
+ For other overridable properties, look at the beginning of the rules
+ files in the SDK, at tools/ant/build.xml
+
+ Properties related to the SDK location or the project target should
+ be updated using the 'android' tool with the 'update' action.
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems.
+
+ -->
+ <property file="ant.properties" />
+
+ <!-- if sdk.dir was not set from one of the property file, then
+ get it from the ANDROID_HOME env var.
+ This must be done before we load project.properties since
+ the proguard config can use sdk.dir -->
+ <property environment="env" />
+ <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+ <isset property="env.ANDROID_HOME" />
+ </condition>
+
+ <!-- The project.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+
+ This contains project specific properties such as project target, and library
+ dependencies. Lower level build properties are stored in ant.properties
+ (or in .classpath for Eclipse projects).
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <loadproperties srcFile="project.properties" />
+
+ <!-- quick check on sdk.dir -->
+ <fail
+ message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+ unless="sdk.dir"
+ />
+
+ <!--
+ Import per project custom build rules if present at the root of the project.
+ This is the place to put custom intermediary targets such as:
+ -pre-build
+ -pre-compile
+ -post-compile (This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir})
+ -post-package
+ -post-build
+ -pre-clean
+ -->
+ <import file="custom_rules.xml" optional="true" />
+
+ <!-- Import the actual build file.
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <import> task.
+ - customize it to your needs.
+ - Customize the whole content of build.xml
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, replacing the <import> task.
+ - customize to your needs.
+
+ ***********************
+ ****** IMPORTANT ******
+ ***********************
+ In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+ in order to avoid having your file be overridden by tools such as "android update project"
+ -->
+ <!-- version-tag: 1 -->
+ <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
diff --git a/platform/android/java/default.properties b/platform/android/java/default.properties
new file mode 100644
index 0000000000..e2e8061f26
--- /dev/null
+++ b/platform/android/java/default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
diff --git a/platform/android/java/my-release-key.keystore b/platform/android/java/my-release-key.keystore
new file mode 100644
index 0000000000..410cccd865
--- /dev/null
+++ b/platform/android/java/my-release-key.keystore
Binary files differ
diff --git a/platform/android/java/proguard-project.txt b/platform/android/java/proguard-project.txt
new file mode 100644
index 0000000000..f2fe1559a2
--- /dev/null
+++ b/platform/android/java/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/platform/android/java/proguard.cfg b/platform/android/java/proguard.cfg
new file mode 100644
index 0000000000..12dd0392c0
--- /dev/null
+++ b/platform/android/java/proguard.cfg
@@ -0,0 +1,36 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
diff --git a/platform/android/java/res/drawable/icon.png b/platform/android/java/res/drawable/icon.png
new file mode 100644
index 0000000000..050a1cf930
--- /dev/null
+++ b/platform/android/java/res/drawable/icon.png
Binary files differ
diff --git a/platform/android/java/res/values-ar/strings.xml b/platform/android/java/res/values-ar/strings.xml
new file mode 100644
index 0000000000..9f3dc6d6ac
--- /dev/null
+++ b/platform/android/java/res/values-ar/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ar</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-bg/strings.xml b/platform/android/java/res/values-bg/strings.xml
new file mode 100644
index 0000000000..bd8109277e
--- /dev/null
+++ b/platform/android/java/res/values-bg/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-bg</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ca/strings.xml b/platform/android/java/res/values-ca/strings.xml
new file mode 100644
index 0000000000..494cb88468
--- /dev/null
+++ b/platform/android/java/res/values-ca/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ca</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-cs/strings.xml b/platform/android/java/res/values-cs/strings.xml
new file mode 100644
index 0000000000..30ce00f895
--- /dev/null
+++ b/platform/android/java/res/values-cs/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-cs</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-da/strings.xml b/platform/android/java/res/values-da/strings.xml
new file mode 100644
index 0000000000..4c2a1cf0f4
--- /dev/null
+++ b/platform/android/java/res/values-da/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-da</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-de/strings.xml b/platform/android/java/res/values-de/strings.xml
new file mode 100644
index 0000000000..52946d4cce
--- /dev/null
+++ b/platform/android/java/res/values-de/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-de</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-el/strings.xml b/platform/android/java/res/values-el/strings.xml
new file mode 100644
index 0000000000..181dc51762
--- /dev/null
+++ b/platform/android/java/res/values-el/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-el</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-en/strings.xml b/platform/android/java/res/values-en/strings.xml
new file mode 100644
index 0000000000..976a565013
--- /dev/null
+++ b/platform/android/java/res/values-en/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-en</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-es-rES/strings.xml b/platform/android/java/res/values-es-rES/strings.xml
new file mode 100644
index 0000000000..73f63a08f8
--- /dev/null
+++ b/platform/android/java/res/values-es-rES/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-es_ES</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-es/strings.xml b/platform/android/java/res/values-es/strings.xml
new file mode 100644
index 0000000000..07b718a641
--- /dev/null
+++ b/platform/android/java/res/values-es/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-es</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-fi/strings.xml b/platform/android/java/res/values-fi/strings.xml
new file mode 100644
index 0000000000..323d82aff1
--- /dev/null
+++ b/platform/android/java/res/values-fi/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-fi</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-fr/strings.xml b/platform/android/java/res/values-fr/strings.xml
new file mode 100644
index 0000000000..32bead2661
--- /dev/null
+++ b/platform/android/java/res/values-fr/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-fr</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-he/strings.xml b/platform/android/java/res/values-he/strings.xml
new file mode 100644
index 0000000000..f52ede2085
--- /dev/null
+++ b/platform/android/java/res/values-he/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-he</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-hi/strings.xml b/platform/android/java/res/values-hi/strings.xml
new file mode 100644
index 0000000000..8aab2a8c63
--- /dev/null
+++ b/platform/android/java/res/values-hi/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-hi</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-hr/strings.xml b/platform/android/java/res/values-hr/strings.xml
new file mode 100644
index 0000000000..caf55e2241
--- /dev/null
+++ b/platform/android/java/res/values-hr/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-hr</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-hu/strings.xml b/platform/android/java/res/values-hu/strings.xml
new file mode 100644
index 0000000000..e7f9e51226
--- /dev/null
+++ b/platform/android/java/res/values-hu/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-hu</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-id/strings.xml b/platform/android/java/res/values-id/strings.xml
new file mode 100644
index 0000000000..9e9a8b0c03
--- /dev/null
+++ b/platform/android/java/res/values-id/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-id</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-it/strings.xml b/platform/android/java/res/values-it/strings.xml
new file mode 100644
index 0000000000..1f5e5a049e
--- /dev/null
+++ b/platform/android/java/res/values-it/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-it</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ja/strings.xml b/platform/android/java/res/values-ja/strings.xml
new file mode 100644
index 0000000000..7f85f57df7
--- /dev/null
+++ b/platform/android/java/res/values-ja/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ja</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ko/strings.xml b/platform/android/java/res/values-ko/strings.xml
new file mode 100644
index 0000000000..6d27498af8
--- /dev/null
+++ b/platform/android/java/res/values-ko/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ko</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-lt/strings.xml b/platform/android/java/res/values-lt/strings.xml
new file mode 100644
index 0000000000..6e3677fde7
--- /dev/null
+++ b/platform/android/java/res/values-lt/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-lt</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-lv/strings.xml b/platform/android/java/res/values-lv/strings.xml
new file mode 100644
index 0000000000..701fc271ac
--- /dev/null
+++ b/platform/android/java/res/values-lv/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-lv</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-nb/strings.xml b/platform/android/java/res/values-nb/strings.xml
new file mode 100644
index 0000000000..73147ca1af
--- /dev/null
+++ b/platform/android/java/res/values-nb/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-nb</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-nl/strings.xml b/platform/android/java/res/values-nl/strings.xml
new file mode 100644
index 0000000000..e501928a35
--- /dev/null
+++ b/platform/android/java/res/values-nl/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-nl</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-pl/strings.xml b/platform/android/java/res/values-pl/strings.xml
new file mode 100644
index 0000000000..ea5da73b6f
--- /dev/null
+++ b/platform/android/java/res/values-pl/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-pl</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-pt/strings.xml b/platform/android/java/res/values-pt/strings.xml
new file mode 100644
index 0000000000..bdda7cd2c7
--- /dev/null
+++ b/platform/android/java/res/values-pt/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-pt</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ro/strings.xml b/platform/android/java/res/values-ro/strings.xml
new file mode 100644
index 0000000000..3686da4c19
--- /dev/null
+++ b/platform/android/java/res/values-ro/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ro</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-ru/strings.xml b/platform/android/java/res/values-ru/strings.xml
new file mode 100644
index 0000000000..954067658b
--- /dev/null
+++ b/platform/android/java/res/values-ru/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-ru</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-sk/strings.xml b/platform/android/java/res/values-sk/strings.xml
new file mode 100644
index 0000000000..37d1283124
--- /dev/null
+++ b/platform/android/java/res/values-sk/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-sk</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-sl/strings.xml b/platform/android/java/res/values-sl/strings.xml
new file mode 100644
index 0000000000..0bb249c375
--- /dev/null
+++ b/platform/android/java/res/values-sl/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-sl</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-sr/strings.xml b/platform/android/java/res/values-sr/strings.xml
new file mode 100644
index 0000000000..0e83cab1a1
--- /dev/null
+++ b/platform/android/java/res/values-sr/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-sr</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-sv/strings.xml b/platform/android/java/res/values-sv/strings.xml
new file mode 100644
index 0000000000..e3a04ac2ec
--- /dev/null
+++ b/platform/android/java/res/values-sv/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-sv</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-th/strings.xml b/platform/android/java/res/values-th/strings.xml
new file mode 100644
index 0000000000..0aa893b8bf
--- /dev/null
+++ b/platform/android/java/res/values-th/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-th</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-tl/strings.xml b/platform/android/java/res/values-tl/strings.xml
new file mode 100644
index 0000000000..e7e2af4909
--- /dev/null
+++ b/platform/android/java/res/values-tl/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-tl</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-tr/strings.xml b/platform/android/java/res/values-tr/strings.xml
new file mode 100644
index 0000000000..97af1243a6
--- /dev/null
+++ b/platform/android/java/res/values-tr/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-tr</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-uk/strings.xml b/platform/android/java/res/values-uk/strings.xml
new file mode 100644
index 0000000000..3dea6908a9
--- /dev/null
+++ b/platform/android/java/res/values-uk/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-uk</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-vi/strings.xml b/platform/android/java/res/values-vi/strings.xml
new file mode 100644
index 0000000000..a6552130b0
--- /dev/null
+++ b/platform/android/java/res/values-vi/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-vi</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values-zh/strings.xml b/platform/android/java/res/values-zh/strings.xml
new file mode 100644
index 0000000000..397e662851
--- /dev/null
+++ b/platform/android/java/res/values-zh/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-zh</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/java/res/values/strings.xml b/platform/android/java/res/values/strings.xml
new file mode 100644
index 0000000000..3a38d40599
--- /dev/null
+++ b/platform/android/java/res/values/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name</string>
+ <string name="testuf8">元気です</string>
+ <string name="testuf2">元気です元気です元気です</string>
+
+</resources>
diff --git a/platform/android/java/src/com/android/godot/Dictionary.java b/platform/android/java/src/com/android/godot/Dictionary.java
new file mode 100644
index 0000000000..4ed12f5818
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/Dictionary.java
@@ -0,0 +1,80 @@
+/*************************************************************************/
+/* Dictionary.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+
+import java.util.HashMap;
+import java.util.Set;
+
+
+public class Dictionary extends HashMap<String, Object> {
+
+ protected String[] keys_cache;
+
+ public String[] get_keys() {
+
+ String[] ret = new String[size()];
+ int i=0;
+ Set<String> keys = keySet();
+ for (String key : keys) {
+
+ ret[i] = key;
+ i++;
+ };
+
+ return ret;
+ };
+
+ public Object[] get_values() {
+
+ Object[] ret = new Object[size()];
+ int i=0;
+ Set<String> keys = keySet();
+ for (String key : keys) {
+
+ ret[i] = get(key);
+ i++;
+ };
+
+ return ret;
+ };
+
+ public void set_keys(String[] keys) {
+ keys_cache = keys;
+ };
+
+ public void set_values(Object[] vals) {
+
+ int i=0;
+ for (String key : keys_cache) {
+ put(key, vals[i]);
+ i++;
+ };
+ keys_cache = null;
+ };
+};
diff --git a/platform/android/java/src/com/android/godot/Godot.java b/platform/android/java/src/com/android/godot/Godot.java
new file mode 100644
index 0000000000..cf1545df82
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/Godot.java
@@ -0,0 +1,300 @@
+/*************************************************************************/
+/* Godot.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
+import android.view.ViewGroup.LayoutParams;
+
+
+import android.app.*;
+import android.content.*;
+import android.view.*;
+import android.view.inputmethod.InputMethodManager;
+import android.os.*;
+import android.util.Log;
+import android.graphics.*;
+import android.text.method.*;
+import android.text.*;
+import android.media.*;
+import android.hardware.*;
+import android.content.*;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.ArrayList;
+import android.provider.Settings.Secure;
+
+
+public class Godot extends Activity implements SensorEventListener
+{
+
+ static public class SingletonBase {
+
+ protected void registerClass(String p_name, String[] p_methods) {
+
+ GodotLib.singleton(p_name,this);
+
+ Class clazz = getClass();
+ Method[] methods = clazz.getDeclaredMethods();
+ for (Method method : methods) {
+ boolean found=false;
+ System.out.printf("METHOD: %s\n",method.getName());
+
+ for (String s : p_methods) {
+ System.out.printf("METHOD CMP WITH: %s\n",s);
+ if (s.equals(method.getName())) {
+ found=true;
+ System.out.printf("METHOD CMP VALID");
+ break;
+ }
+ }
+ if (!found)
+ continue;
+
+ System.out.printf("METHOD FOUND: %s\n",method.getName());
+
+ List<String> ptr = new ArrayList<String>();
+
+ Class[] paramTypes = method.getParameterTypes();
+ for (Class c : paramTypes) {
+ ptr.add(c.getName());
+ }
+
+ String[] pt = new String[ptr.size()];
+ ptr.toArray(pt);
+
+ GodotLib.method(p_name,method.getName(),method.getReturnType().getName(),pt);
+
+
+ }
+ }
+
+ public void registerMethods() {}
+ }
+
+/*
+ protected List<SingletonBase> singletons = new ArrayList<SingletonBase>();
+ protected void instanceSingleton(SingletonBase s) {
+
+ s.registerMethods();
+ singletons.add(s);
+ }
+
+*/
+
+ public GodotView mView;
+
+ private SensorManager mSensorManager;
+ private Sensor mAccelerometer;
+
+ public RelativeLayout layout;
+
+
+ static public GodotIO io;
+
+ public static void setWindowTitle(String title) {
+ //setTitle(title);
+ }
+
+ public interface ResultCallback {
+ public void callback(int requestCode, int resultCode, Intent data);
+ };
+ public ResultCallback result_callback;
+
+ @Override protected void onActivityResult (int requestCode, int resultCode, Intent data) {
+ if (result_callback != null) {
+ result_callback.callback(requestCode, resultCode, data);
+ result_callback = null;
+ };
+ };
+
+ public void onVideoInit(boolean use_gl2) {
+
+// mView = new GodotView(getApplication(),io,use_gl2);
+// setContentView(mView);
+
+ layout = new RelativeLayout(this);
+ layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
+ setContentView(layout);
+ mView = new GodotView(getApplication(),io,use_gl2, this);
+ layout.addView(mView,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
+ mView.setKeepScreenOn(true);
+
+ }
+
+ @Override protected void onCreate(Bundle icicle) {
+
+
+ super.onCreate(icicle);
+
+
+
+ Window window = getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ io = new GodotIO(this);
+ io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
+ GodotLib.io=io;
+ GodotLib.initialize(this,io.needsReloadHooks());
+ mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
+ mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
+
+ result_callback = null;
+
+ // instanceSingleton( new GodotFacebook(this) );
+
+
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ mSensorManager.unregisterListener(this);
+ GodotLib.focusout();
+
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
+ GodotLib.focusin();
+ }
+
+ @Override public void onSensorChanged(SensorEvent event) {
+ float x = event.values[0];
+ float y = event.values[1];
+ float z = event.values[2];
+ GodotLib.accelerometer(x,y,z);
+ }
+
+ @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Do something here if sensor accuracy changes.
+ }
+
+/*
+ @Override public boolean dispatchKeyEvent(KeyEvent event) {
+
+ if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
+
+ System.out.printf("** BACK REQUEST!\n");
+
+ GodotLib.quit();
+ return true;
+ }
+ System.out.printf("** OTHER KEY!\n");
+
+ return false;
+ }
+*/
+
+ @Override public void onBackPressed() {
+
+ GodotLib.quit();
+ }
+
+ public void forceQuit() {
+
+ System.exit(0);
+ }
+
+
+ //@Override public boolean dispatchTouchEvent (MotionEvent event) {
+ public boolean gotTouchEvent(MotionEvent event) {
+
+ super.onTouchEvent(event);
+ int evcount=event.getPointerCount();
+ if (evcount==0)
+ return true;
+
+ int[] arr = new int[event.getPointerCount()*3];
+
+ for(int i=0;i<event.getPointerCount();i++) {
+
+ arr[i*3+0]=(int)event.getPointerId(i);
+ arr[i*3+1]=(int)event.getX(i);
+ arr[i*3+2]=(int)event.getY(i);
+ }
+
+ //System.out.printf("gaction: %d\n",event.getAction());
+ switch(event.getAction()&MotionEvent.ACTION_MASK) {
+
+ case MotionEvent.ACTION_DOWN: {
+ GodotLib.touch(0,0,evcount,arr);
+ //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
+ } break;
+ case MotionEvent.ACTION_MOVE: {
+ GodotLib.touch(1,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+ case MotionEvent.ACTION_POINTER_UP: {
+ int pointer_idx = event.getActionIndex();
+ GodotLib.touch(4,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ int pointer_idx = event.getActionIndex();
+ GodotLib.touch(3,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP: {
+ GodotLib.touch(2,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+
+ }
+ return true;
+ }
+
+ @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
+ GodotLib.key(event.getUnicodeChar(0), false);
+ return super.onKeyUp(keyCode, event);
+ };
+
+ @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
+ GodotLib.key(event.getUnicodeChar(0), true);
+ return super.onKeyDown(keyCode, event);
+ };
+
+
+ // Audio
+
+
+}
diff --git a/platform/android/java/src/com/android/godot/GodotIO.java b/platform/android/java/src/com/android/godot/GodotIO.java
new file mode 100644
index 0000000000..1f3967cb8f
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/GodotIO.java
@@ -0,0 +1,514 @@
+/*************************************************************************/
+/* GodotIO.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+import java.util.HashMap;
+import java.util.Locale;
+import android.net.Uri;
+import android.content.Intent;
+import android.content.res.AssetManager;
+import java.io.InputStream;
+import java.io.IOException;
+import android.app.*;
+import android.content.*;
+import android.view.*;
+import android.view.inputmethod.InputMethodManager;
+import android.os.*;
+import android.util.Log;
+import android.graphics.*;
+import android.text.method.*;
+import android.text.*;
+import android.media.*;
+import android.hardware.*;
+import android.content.*;
+import android.content.pm.ActivityInfo;
+//android.os.Build
+
+// Wrapper for native library
+
+public class GodotIO {
+
+
+ AssetManager am;
+ Activity activity;
+
+ final int SCREEN_LANDSCAPE=0;
+ final int SCREEN_PORTRAIT=1;
+ final int SCREEN_REVERSE_LANDSCAPE=2;
+ final int SCREEN_REVERSE_PORTRAIT=3;
+ final int SCREEN_SENSOR_LANDSCAPE=4;
+ final int SCREEN_SENSOR_PORTRAIT=5;
+ final int SCREEN_SENSOR=6;
+
+ /////////////////////////
+ /// FILES
+ /////////////////////////
+
+ public int last_file_id=1;
+
+ class AssetData {
+
+
+ public boolean eof=false;
+ public String path;
+ public InputStream is;
+ public int len;
+ public int pos;
+ }
+
+
+ HashMap<Integer,AssetData> streams;
+
+
+ public int file_open(String path,boolean write) {
+
+ //System.out.printf("file_open: Attempt to Open %s\n",path);
+
+ if (write)
+ return -1;
+
+
+ AssetData ad = new AssetData();
+
+ try {
+ ad.is = am.open(path);
+
+ } catch (Exception e) {
+
+ //System.out.printf("Exception on file_open: %s\n",e);
+ return -1;
+ }
+
+ try {
+ ad.len=ad.is.available();
+ } catch (Exception e) {
+
+ System.out.printf("Exception availabling on file_open: %s\n",e);
+ return -1;
+ }
+
+ ad.path=path;
+ ad.pos=0;
+ ++last_file_id;
+ streams.put(last_file_id,ad);
+
+ return last_file_id;
+ }
+ public int file_get_size(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return -1;
+ }
+
+ return streams.get(id).len;
+
+ }
+ public void file_seek(int id,int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return;
+ }
+ //seek sucks
+ AssetData ad = streams.get(id);
+ if (bytes>ad.len)
+ bytes=ad.len;
+ if (bytes<0)
+ bytes=0;
+
+ try {
+
+ if (bytes > (int)ad.pos) {
+ int todo=bytes-(int)ad.pos;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ ad.pos=bytes;
+ } else if (bytes<(int)ad.pos) {
+
+ ad.is=am.open(ad.path);
+
+ ad.pos=bytes;
+ int todo=bytes;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ }
+
+ ad.eof=false;
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_seek: %s\n",e);
+ return;
+ }
+
+
+ }
+
+ public int file_tell(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't tell eof for invalid file id: %d\n",id);
+ return 0;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.pos;
+ }
+ public boolean file_eof(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't check eof for invalid file id: %d\n",id);
+ return false;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.eof;
+ }
+
+ public byte[] file_read(int id, int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't read invalid file id: %d\n",id);
+ return new byte[0];
+ }
+
+
+ AssetData ad = streams.get(id);
+
+ if (ad.pos + bytes > ad.len) {
+
+ bytes=ad.len-ad.pos;
+ ad.eof=true;
+ }
+
+
+ if (bytes==0) {
+
+ return new byte[0];
+ }
+
+
+
+ byte[] buf1=new byte[bytes];
+ int r=0;
+ try {
+ r = ad.is.read(buf1);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_read: %s\n",e);
+ return new byte[bytes];
+ }
+
+ if (r==0) {
+ return new byte[0];
+ }
+
+ ad.pos+=r;
+
+ if (r<bytes) {
+
+ byte[] buf2=new byte[r];
+ for(int i=0;i<r;i++)
+ buf2[i]=buf1[i];
+ return buf2;
+ } else {
+
+ return buf1;
+ }
+
+ }
+
+ public void file_close(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_close: Can't close invalid file id: %d\n",id);
+ return;
+ }
+
+ streams.remove(id);
+
+ }
+
+
+ /////////////////////////
+ /// DIRECTORIES
+ /////////////////////////
+
+
+ class AssetDir {
+
+ public String[] files;
+ public int current;
+ }
+
+ public int last_dir_id=1;
+
+ HashMap<Integer,AssetDir> dirs;
+
+ public int dir_open(String path) {
+
+ AssetDir ad = new AssetDir();
+ ad.current=0;
+
+ try {
+ ad.files = am.list(path);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on dir_open: %s\n",e);
+ return -1;
+ }
+
+ ++last_dir_id;
+ dirs.put(last_dir_id,ad);
+
+ return last_dir_id;
+
+ }
+
+ public String dir_next(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_next: invalid dir id: %d\n",id);
+ return "";
+ }
+
+ AssetDir ad = dirs.get(id);
+ if (ad.current>=ad.files.length)
+ return "";
+ String r = ad.files[ad.current];
+ ad.current++;
+ return r;
+
+ }
+
+ public void dir_close(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_close: invalid dir id: %d\n",id);
+ return;
+ }
+
+ dirs.remove(id);
+ }
+
+
+
+ GodotIO(Activity p_activity) {
+
+ am=p_activity.getAssets();
+ activity=p_activity;
+ streams=new HashMap<Integer,AssetData>();
+ dirs=new HashMap<Integer,AssetDir>();
+
+
+ }
+
+
+ /////////////////////////
+ // AUDIO
+ /////////////////////////
+
+ private Object buf;
+ private Thread mAudioThread;
+ private AudioTrack mAudioTrack;
+
+ public Object audioInit(int sampleRate, int desiredFrames) {
+ int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
+ int frameSize = 4;
+
+ System.out.printf("audioInit: initializing audio:\n");
+
+ //Log.v("Godot", "Godot audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ // Let the user pick a larger buffer if they really want -- but ye
+ // gods they probably shouldn't, the minimums are horrifyingly high
+ // latency already
+ desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+
+ mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
+ channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
+
+ audioStartThread();
+
+ //Log.v("Godot", "Godot audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ buf = new short[desiredFrames * 2];
+ return buf;
+ }
+
+ public void audioStartThread() {
+ mAudioThread = new Thread(new Runnable() {
+ public void run() {
+ mAudioTrack.play();
+ GodotLib.audio();
+ }
+ });
+
+ // I'd take REALTIME if I could get it!
+ mAudioThread.setPriority(Thread.MAX_PRIORITY);
+ mAudioThread.start();
+ }
+
+ public void audioWriteShortBuffer(short[] buffer) {
+ for (int i = 0; i < buffer.length; ) {
+ int result = mAudioTrack.write(buffer, i, buffer.length - i);
+ if (result > 0) {
+ i += result;
+ } else if (result == 0) {
+ try {
+ Thread.sleep(1);
+ } catch(InterruptedException e) {
+ // Nom nom
+ }
+ } else {
+ Log.w("Godot", "Godot audio: error return from write(short)");
+ return;
+ }
+ }
+ }
+
+
+
+ public void audioQuit() {
+ if (mAudioThread != null) {
+ try {
+ mAudioThread.join();
+ } catch(Exception e) {
+ Log.v("Godot", "Problem stopping audio thread: " + e);
+ }
+ mAudioThread = null;
+
+ //Log.v("Godot", "Finished waiting for audio thread");
+ }
+
+ if (mAudioTrack != null) {
+ mAudioTrack.stop();
+ mAudioTrack = null;
+ }
+ }
+
+ public void audioPause(boolean p_pause) {
+
+ if (p_pause)
+ mAudioTrack.pause();
+ else
+ mAudioTrack.play();
+ }
+
+ /////////////////////////
+ // MISCELANEOUS OS IO
+ /////////////////////////
+
+
+
+ public int openURI(String p_uri) {
+
+ try {
+ Log.v("MyApp", "TRYING TO OPEN URI: " + p_uri);
+ Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(p_uri));
+ activity.startActivity(myIntent);
+ return 0;
+ } catch (ActivityNotFoundException e) {
+
+ return 1;
+ }
+ }
+
+ public String getDataDir() {
+
+ return activity.getFilesDir().getAbsolutePath();
+ }
+
+ public String getLocale() {
+
+ return Locale.getDefault().toString();
+ }
+
+ public String getModel() {
+ return Build.MODEL;
+ }
+
+ public boolean needsReloadHooks() {
+
+ return android.os.Build.VERSION.SDK_INT < 11;
+ }
+
+ public void showKeyboard(String p_existing_text) {
+
+ InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
+ };
+
+ public void hideKeyboard() {
+
+ InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMgr.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ };
+
+ public void setScreenOrientation(int p_orientation) {
+
+ switch(p_orientation) {
+
+ case SCREEN_LANDSCAPE: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ } break;
+ case SCREEN_PORTRAIT: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ } break;
+ case SCREEN_REVERSE_LANDSCAPE: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+ } break;
+ case SCREEN_REVERSE_PORTRAIT: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
+ } break;
+ case SCREEN_SENSOR_LANDSCAPE: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
+ } break;
+ case SCREEN_SENSOR_PORTRAIT: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
+ } break;
+ case SCREEN_SENSOR: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
+ } break;
+
+ }
+ };
+
+ protected static final String PREFS_FILE = "device_id.xml";
+ protected static final String PREFS_DEVICE_ID = "device_id";
+
+ public static String unique_id="";
+ public String getUniqueID() {
+
+ return unique_id;
+ }
+
+}
diff --git a/platform/android/java/src/com/android/godot/GodotLib.java b/platform/android/java/src/com/android/godot/GodotLib.java
new file mode 100644
index 0000000000..8d002c5ebc
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/GodotLib.java
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* GodotLib.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+
+// Wrapper for native library
+
+public class GodotLib {
+
+
+ public static GodotIO io;
+
+ static {
+ System.loadLibrary("godot_android");
+ }
+
+ /**
+ * @param width the current view width
+ * @param height the current view height
+ */
+
+ public static native void initialize(Godot p_instance,boolean need_reload_hook);
+ public static native void resize(int width, int height,boolean reload);
+ public static native void newcontext();
+ public static native void quit();
+ public static native void step();
+ public static native void touch(int what,int pointer,int howmany, int[] arr);
+ public static native void accelerometer(float x, float y, float z);
+ public static native void key(int p_unicode_char, boolean p_pressed);
+ public static native void focusin();
+ public static native void focusout();
+ public static native void audio();
+ public static native void singleton(String p_name,Object p_object);
+ public static native void method(String p_sname,String p_name,String p_ret,String[] p_params);
+ public static native String getGlobal(String p_key);
+ public static native void callobject(int p_ID, String p_method, Object[] p_params);
+
+}
diff --git a/platform/android/java/src/com/android/godot/GodotView.java b/platform/android/java/src/com/android/godot/GodotView.java
new file mode 100644
index 0000000000..093757bfb0
--- /dev/null
+++ b/platform/android/java/src/com/android/godot/GodotView.java
@@ -0,0 +1,378 @@
+/*************************************************************************/
+/* GodotView.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+package com.android.godot;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.content.ContextWrapper;
+
+import java.io.File;
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * A simple GLSurfaceView sub-class that demonstrate how to perform
+ * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
+ * details:
+ *
+ * - The class must use a custom context factory to enable 2.0 rendering.
+ * See ContextFactory class definition below.
+ *
+ * - The class must use a custom EGLConfigChooser to be able to select
+ * an EGLConfig that supports 2.0. This is done by providing a config
+ * specification to eglChooseConfig() that has the attribute
+ * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
+ * set. See ConfigChooser class definition below.
+ *
+ * - The class must select the surface's format, then choose an EGLConfig
+ * that matches it exactly (with regards to red/green/blue/alpha channels
+ * bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
+ */
+class GodotView extends GLSurfaceView {
+ private static String TAG = "GodotView";
+ private static final boolean DEBUG = false;
+ private static Context ctx;
+
+ private static GodotIO io;
+ private static boolean firsttime=true;
+ private static boolean use_gl2=false;
+
+ private Godot activity;
+
+ public GodotView(Context context,GodotIO p_io,boolean p_use_gl2, Godot p_activity) {
+ super(context);
+ ctx=context;
+ io=p_io;
+ use_gl2=p_use_gl2;
+
+ activity = p_activity;
+
+ if (!p_io.needsReloadHooks()) {
+ //will only work on SDK 11+!!
+ setPreserveEGLContextOnPause(true);
+ }
+
+ init(false, 16, 0);
+ }
+
+ public GodotView(Context context, boolean translucent, int depth, int stencil) {
+ super(context);
+ init(translucent, depth, stencil);
+ }
+
+ @Override public boolean onTouchEvent (MotionEvent event) {
+
+ return activity.gotTouchEvent(event);
+ };
+
+ private void init(boolean translucent, int depth, int stencil) {
+
+ /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
+ * If we want a translucent one, we should change the surface's
+ * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
+ * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
+ */
+ if (translucent) {
+ this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ /* Setup the context factory for 2.0 rendering.
+ * See ContextFactory class definition below
+ */
+ setEGLContextFactory(new ContextFactory());
+
+ /* We need to choose an EGLConfig that matches the format of
+ * our surface exactly. This is going to be done in our
+ * custom config chooser. See ConfigChooser class definition
+ * below.
+ */
+ setEGLConfigChooser( translucent ?
+ new ConfigChooser(8, 8, 8, 8, depth, stencil) :
+ new ConfigChooser(5, 6, 5, 0, depth, stencil) );
+
+ /* Set the renderer responsible for frame rendering */
+ setRenderer(new Renderer());
+ }
+
+ private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+ if (use_gl2)
+ Log.w(TAG, "creating OpenGL ES 2.0 context :");
+ else
+ Log.w(TAG, "creating OpenGL ES 1.1 context :");
+
+ checkEglError("Before eglCreateContext", egl);
+ int[] attrib_list2 = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl2?attrib_list2:null);
+ checkEglError("After eglCreateContext", egl);
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ egl.eglDestroyContext(display, context);
+ }
+ }
+
+ private static void checkEglError(String prompt, EGL10 egl) {
+ int error;
+ while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
+ Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+ }
+ }
+
+ private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+
+ public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+ mRedSize = r;
+ mGreenSize = g;
+ mBlueSize = b;
+ mAlphaSize = a;
+ mDepthSize = depth;
+ mStencilSize = stencil;
+ }
+
+ /* This EGL config specification is used to specify 2.0 rendering.
+ * We use a minimum size of 4 bits for red/green/blue, but will
+ * perform actual matching in chooseConfig() below.
+ */
+ private static int EGL_OPENGL_ES2_BIT = 4;
+ private static int[] s_configAttribs2 =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ // EGL10.EGL_DEPTH_SIZE, 16,
+ // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+ private static int[] s_configAttribs =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ // EGL10.EGL_DEPTH_SIZE, 16,
+ // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
+ EGL10.EGL_NONE
+ };
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+
+ /* Get the number of minimally matching EGL configurations
+ */
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0) {
+ throw new IllegalArgumentException("No configs match configSpec");
+ }
+
+ /* Allocate then read the array of minimally matching EGL configs
+ */
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, configs, numConfigs, num_config);
+
+ if (DEBUG) {
+ printConfigs(egl, display, configs);
+ }
+ /* Now return the "best" one
+ */
+ return chooseConfig(egl, display, configs);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ for(EGLConfig config : configs) {
+ int d = findConfigAttrib(egl, display, config,
+ EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config,
+ EGL10.EGL_STENCIL_SIZE, 0);
+
+ // We need at least mDepthSize and mStencilSize bits
+ if (d < mDepthSize || s < mStencilSize)
+ continue;
+
+ // We want an *exact* match for red/green/blue/alpha
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+
+ if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)
+ return config;
+ }
+ return null;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+ EGLConfig config, int attribute, int defaultValue) {
+
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private void printConfigs(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ int numConfigs = configs.length;
+ Log.w(TAG, String.format("%d configurations", numConfigs));
+ for (int i = 0; i < numConfigs; i++) {
+ Log.w(TAG, String.format("Configuration %d:\n", i));
+ printConfig(egl, display, configs[i]);
+ }
+ }
+
+ private void printConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig config) {
+ int[] attributes = {
+ EGL10.EGL_BUFFER_SIZE,
+ EGL10.EGL_ALPHA_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_RED_SIZE,
+ EGL10.EGL_DEPTH_SIZE,
+ EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT,
+ EGL10.EGL_MAX_PBUFFER_PIXELS,
+ EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_NATIVE_RENDERABLE,
+ EGL10.EGL_NATIVE_VISUAL_ID,
+ EGL10.EGL_NATIVE_VISUAL_TYPE,
+ 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+ EGL10.EGL_SAMPLES,
+ EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE,
+ EGL10.EGL_TRANSPARENT_RED_VALUE,
+ EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+ EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+ 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+ 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+ 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+ 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+ EGL10.EGL_LUMINANCE_SIZE,
+ EGL10.EGL_ALPHA_MASK_SIZE,
+ EGL10.EGL_COLOR_BUFFER_TYPE,
+ EGL10.EGL_RENDERABLE_TYPE,
+ 0x3042 // EGL10.EGL_CONFORMANT
+ };
+ String[] names = {
+ "EGL_BUFFER_SIZE",
+ "EGL_ALPHA_SIZE",
+ "EGL_BLUE_SIZE",
+ "EGL_GREEN_SIZE",
+ "EGL_RED_SIZE",
+ "EGL_DEPTH_SIZE",
+ "EGL_STENCIL_SIZE",
+ "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID",
+ "EGL_LEVEL",
+ "EGL_MAX_PBUFFER_HEIGHT",
+ "EGL_MAX_PBUFFER_PIXELS",
+ "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE",
+ "EGL_NATIVE_VISUAL_ID",
+ "EGL_NATIVE_VISUAL_TYPE",
+ "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES",
+ "EGL_SAMPLE_BUFFERS",
+ "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE",
+ "EGL_TRANSPARENT_RED_VALUE",
+ "EGL_TRANSPARENT_GREEN_VALUE",
+ "EGL_TRANSPARENT_BLUE_VALUE",
+ "EGL_BIND_TO_TEXTURE_RGB",
+ "EGL_BIND_TO_TEXTURE_RGBA",
+ "EGL_MIN_SWAP_INTERVAL",
+ "EGL_MAX_SWAP_INTERVAL",
+ "EGL_LUMINANCE_SIZE",
+ "EGL_ALPHA_MASK_SIZE",
+ "EGL_COLOR_BUFFER_TYPE",
+ "EGL_RENDERABLE_TYPE",
+ "EGL_CONFORMANT"
+ };
+ int[] value = new int[1];
+ for (int i = 0; i < attributes.length; i++) {
+ int attribute = attributes[i];
+ String name = names[i];
+ if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+ Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
+ } else {
+ // Log.w(TAG, String.format(" %s: failed\n", name));
+ while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+ }
+ }
+ }
+
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ private int[] mValue = new int[1];
+ }
+
+ private static class Renderer implements GLSurfaceView.Renderer {
+
+
+ public void onDrawFrame(GL10 gl) {
+ GodotLib.step();
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+
+ GodotLib.resize(width, height,!firsttime);
+ firsttime=false;
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ GodotLib.newcontext();
+ }
+ }
+}
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
new file mode 100644
index 0000000000..9c5003cb17
--- /dev/null
+++ b/platform/android/java_glue.cpp
@@ -0,0 +1,1153 @@
+/*************************************************************************/
+/* java_glue.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#include "java_glue.h"
+#include "os_android.h"
+#include "main/main.h"
+#include <unistd.h>
+#include "file_access_jandroid.h"
+#include "dir_access_jandroid.h"
+#include "audio_driver_jandroid.h"
+#include "globals.h"
+#include "thread_jandroid.h"
+#include "core/os/keyboard.h"
+static OS_Android *os_android=NULL;
+
+
+jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_arg, bool force_jobject = false) {
+
+ jvalue v;
+
+ switch(p_type) {
+
+ case Variant::BOOL: {
+
+ if (force_jobject) {
+ jclass bclass = env->FindClass("java/lang/Boolean");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
+ jvalue val;
+ val.z = (bool)(*p_arg);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ v.l = obj;
+ } else {
+ v.z=*p_arg;
+ };
+ } break;
+ case Variant::INT: {
+
+ if (force_jobject) {
+
+ jclass bclass = env->FindClass("java/lang/Integer");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
+ jvalue val;
+ val.i = (int)(*p_arg);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ v.l = obj;
+
+ } else {
+ v.i=*p_arg;
+ };
+ } break;
+ case Variant::REAL: {
+
+ if (force_jobject) {
+
+ jclass bclass = env->FindClass("java/lang/Double");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
+ jvalue val;
+ val.d = (double)(*p_arg);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ v.l = obj;
+
+ } else {
+ v.f=*p_arg;
+ };
+ } break;
+ case Variant::STRING: {
+
+ String s = *p_arg;
+ jstring jStr = env->NewStringUTF(s.utf8().get_data());
+ v.l=jStr;
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ DVector<String> sarray = *p_arg;
+ jobjectArray arr = env->NewObjectArray(sarray.size(),env->FindClass("java/lang/String"),env->NewStringUTF(""));
+
+ for(int j=0;j<sarray.size();j++) {
+
+ env->SetObjectArrayElement(arr,j,env->NewStringUTF( sarray[j].utf8().get_data() ));
+ }
+ v.l=arr;
+
+ } break;
+
+ case Variant::DICTIONARY: {
+
+ Dictionary dict = *p_arg;
+ jclass dclass = env->FindClass("com/android/godot/Dictionary");
+ jmethodID ctor = env->GetMethodID(dclass, "<init>", "()V");
+ jobject jdict = env->NewObject(dclass, ctor);
+
+ Array keys = dict.keys();
+
+ jobjectArray jkeys = env->NewObjectArray(keys.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
+ for (int j=0; j<keys.size(); j++) {
+ env->SetObjectArrayElement(jkeys, j, env->NewStringUTF(String(keys[j]).utf8().get_data()));
+ };
+
+ jmethodID set_keys = env->GetMethodID(dclass, "set_keys", "([Ljava/lang/String;)V");
+ jvalue val;
+ val.l = jkeys;
+ env->CallVoidMethodA(jdict, set_keys, &val);
+
+ jobjectArray jvalues = env->NewObjectArray(keys.size(), env->FindClass("java/lang/Object"), NULL);
+
+ for (int j=0; j<keys.size(); j++) {
+ Variant var = dict[keys[j]];
+ val = _variant_to_jvalue(env, var.get_type(), &var, true);
+ env->SetObjectArrayElement(jvalues, j, val.l);
+ };
+
+ jmethodID set_values = env->GetMethodID(dclass, "set_values", "([Ljava/lang/Object;)V");
+ val.l = jvalues;
+ env->CallVoidMethodA(jdict, set_values, &val);
+
+ v.l = jdict;
+ } break;
+
+ case Variant::INT_ARRAY: {
+
+ DVector<int> array = *p_arg;
+ jintArray arr = env->NewIntArray(array.size());
+ DVector<int>::Read r = array.read();
+ env->SetIntArrayRegion(arr,0,array.size(),r.ptr());
+ v.l=arr;
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ DVector<float> array = *p_arg;
+ jfloatArray arr = env->NewFloatArray(array.size());
+ DVector<float>::Read r = array.read();
+ env->SetFloatArrayRegion(arr,0,array.size(),r.ptr());
+ v.l=arr;
+
+ } break;
+ default: {
+
+ v.i = 0;
+ } break;
+
+ }
+ return v;
+};
+
+String _get_class_name(JNIEnv * env, jclass cls, bool* array) {
+
+ jclass cclass = env->FindClass("java/lang/Class");
+ jmethodID getName = env->GetMethodID(cclass, "getName", "()Ljava/lang/String;");
+ jstring clsName=(jstring) env->CallObjectMethod(cls, getName);
+
+ if (array) {
+ jmethodID isArray = env->GetMethodID(cclass, "isArray", "()Z");
+ jboolean isarr = env->CallBooleanMethod(cls, isArray);
+ (*array) = isarr ? true : false;
+ }
+
+ return env->GetStringUTFChars( clsName, NULL );
+};
+
+
+Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
+
+ jclass c = env->GetObjectClass(obj);
+ bool array;
+ String name = _get_class_name(env, c, &array);
+ //print_line("name is " + name + ", array "+Variant(array));
+
+ if (name == "java.lang.String") {
+
+ return String::utf8(env->GetStringUTFChars( (jstring)obj, NULL ));
+ };
+
+
+ if (name == "[Ljava.lang.String;") {
+
+ jobjectArray arr = (jobjectArray)obj;
+ int stringCount = env->GetArrayLength(arr);
+ //print_line("String array! " + String::num(stringCount));
+ DVector<String> sarr;
+
+ for (int i=0; i<stringCount; i++) {
+ jstring string = (jstring) env->GetObjectArrayElement(arr, i);
+ const char *rawString = env->GetStringUTFChars(string, 0);
+ sarr.push_back(String(rawString));
+ }
+
+ return sarr;
+ };
+
+ if (name == "java.lang.Boolean") {
+
+ jmethodID boolValue = env->GetMethodID(c, "booleanValue", "()Z");
+ bool ret = env->CallBooleanMethod(obj, boolValue);
+ return ret;
+ };
+
+ if (name == "java.lang.Integer") {
+
+ jclass nclass = env->FindClass("java/lang/Number");
+ jmethodID intValue = env->GetMethodID(nclass, "intValue", "()I");
+ int ret = env->CallIntMethod(obj, intValue);
+ return ret;
+ };
+
+ if (name == "[I") {
+
+ jintArray arr = (jintArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ DVector<int> sarr;
+ sarr.resize(fCount);
+
+ DVector<int>::Write w = sarr.write();
+ env->GetIntArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<int>::Write();
+ return sarr;
+ };
+
+ if (name == "java.lang.Float" || name == "java.lang.Double") {
+
+ jclass nclass = env->FindClass("java/lang/Number");
+ jmethodID doubleValue = env->GetMethodID(nclass, "doubleValue", "()D");
+ double ret = env->CallDoubleMethod(obj, doubleValue);
+ return ret;
+ };
+
+ if (name == "[D") {
+
+ jdoubleArray arr = (jdoubleArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ RealArray sarr;
+ sarr.resize(fCount);
+
+ RealArray::Write w = sarr.write();
+
+ for (int i=0; i<fCount; i++) {
+
+ double n;
+ env->GetDoubleArrayRegion(arr, i, 1, &n);
+ w.ptr()[i] = n;
+
+ };
+ return sarr;
+ };
+
+ if (name == "[F") {
+
+ jfloatArray arr = (jfloatArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ RealArray sarr;
+ sarr.resize(fCount);
+
+
+ RealArray::Write w = sarr.write();
+
+ for (int i=0; i<fCount; i++) {
+
+ float n;
+ env->GetFloatArrayRegion(arr, i, 1, &n);
+ w.ptr()[i] = n;
+
+ };
+ return sarr;
+ };
+
+
+ if (name == "[Ljava.lang.Object;") {
+
+ jobjectArray arr = (jobjectArray)obj;
+ int objCount = env->GetArrayLength(arr);
+ Array varr;
+
+ for (int i=0; i<objCount; i++) {
+ jobject jobj = env->GetObjectArrayElement(arr, i);
+ Variant v = _jobject_to_variant(env, jobj);
+ varr.push_back(v);
+ }
+
+ return varr;
+ };
+
+ if (name == "com.android.godot.Dictionary") {
+
+ Dictionary ret;
+ jclass oclass = c;
+ jmethodID get_keys = env->GetMethodID(oclass, "get_keys", "()[Ljava/lang/String;");
+ jobjectArray arr = (jobjectArray)env->CallObjectMethod(obj, get_keys);
+
+ StringArray keys = _jobject_to_variant(env, arr);
+
+ jmethodID get_values = env->GetMethodID(oclass, "get_values", "()[Ljava/lang/Object;");
+ arr = (jobjectArray)env->CallObjectMethod(obj, get_values);
+
+ Array vals = _jobject_to_variant(env, arr);
+
+ //print_line("adding " + String::num(keys.size()) + " to Dictionary!");
+ for (int i=0; i<keys.size(); i++) {
+
+ ret[keys[i]] = vals[i];
+ };
+
+ return ret;
+ };
+
+ return Variant();
+};
+
+class JNISingleton : public Object {
+
+ OBJ_TYPE( JNISingleton, Object );
+
+
+ struct MethodData {
+
+
+ jmethodID method;
+ Variant::Type ret_type;
+ Vector<Variant::Type> argtypes;
+ };
+
+ jobject instance;
+ Map<StringName,MethodData> method_map;
+
+public:
+
+ virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
+
+ //print_line("attempt to call "+String(p_method));
+
+ r_error.error=Variant::CallError::CALL_OK;
+
+ Map<StringName,MethodData >::Element *E=method_map.find(p_method);
+ if (!E) {
+
+ print_line("no exists");
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+
+
+ int ac = E->get().argtypes.size();
+ if (ac<p_argcount) {
+
+ print_line("fewargs");
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=ac;
+ return Variant();
+ }
+
+ if (ac>p_argcount) {
+
+ print_line("manyargs");
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument=ac;
+ return Variant();
+ }
+
+
+
+ for(int i=0;i<p_argcount;i++) {
+
+ if (!Variant::can_convert(p_args[i]->get_type(),E->get().argtypes[i])) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=i;
+ r_error.expected=E->get().argtypes[i];
+ }
+ }
+
+
+ jvalue *v=NULL;
+
+ if (p_argcount) {
+
+ v=(jvalue*)alloca( sizeof(jvalue)*p_argcount );
+ }
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ //print_line("argcount "+String::num(p_argcount));
+ for(int i=0;i<p_argcount;i++) {
+
+ v[i] = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
+ }
+
+ //print_line("calling method!!");
+
+ Variant ret;
+
+ switch(E->get().ret_type) {
+
+ case Variant::NIL: {
+
+
+ //print_line("call void");
+ env->CallVoidMethodA(instance,E->get().method,v);
+ } break;
+ case Variant::BOOL: {
+
+ ret = env->CallBooleanMethodA(instance,E->get().method,v);
+ //print_line("call bool");
+ } break;
+ case Variant::INT: {
+
+ ret = env->CallIntMethodA(instance,E->get().method,v);
+ //print_line("call int");
+ } break;
+ case Variant::REAL: {
+
+ ret = env->CallFloatMethodA(instance,E->get().method,v);
+ } break;
+ case Variant::STRING: {
+
+ jobject o = env->CallObjectMethodA(instance,E->get().method,v);
+ String singname = env->GetStringUTFChars((jstring)o, NULL );
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ ret = _jobject_to_variant(env, arr);
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ jintArray arr = (jintArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int fCount = env->GetArrayLength(arr);
+ DVector<int> sarr;
+ sarr.resize(fCount);
+
+ DVector<int>::Write w = sarr.write();
+ env->GetIntArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<int>::Write();
+ ret=sarr;
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance,E->get().method,v);
+
+ int fCount = env->GetArrayLength(arr);
+ DVector<float> sarr;
+ sarr.resize(fCount);
+
+ DVector<float>::Write w = sarr.write();
+ env->GetFloatArrayRegion(arr,0,fCount,w.ptr());
+ w = DVector<float>::Write();
+ ret=sarr;
+ } break;
+
+ case Variant::DICTIONARY: {
+
+ //print_line("call dictionary");
+ jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
+ ret = _jobject_to_variant(env, obj);
+
+ } break;
+ default: {
+
+
+ print_line("failure..");
+ ERR_FAIL_V(Variant());
+ } break;
+ }
+
+ //print_line("success");
+
+ return ret;
+ }
+
+
+ jobject get_instance() const {
+
+ return instance;
+ }
+ void set_instance(jobject p_instance) {
+
+ instance=p_instance;
+ }
+
+
+ void add_method(const StringName& p_name, jmethodID p_method,const Vector<Variant::Type>& p_args, Variant::Type p_ret_type) {
+
+ MethodData md;
+ md.method=p_method;
+ md.argtypes=p_args;
+ md.ret_type=p_ret_type;
+ method_map[p_name]=md;
+
+ }
+
+
+ JNISingleton() {}
+
+};
+
+
+struct TST {
+
+ int a;
+ TST() {
+
+ a=5;
+ }
+};
+
+TST tst;
+
+struct JAndroidPointerEvent {
+
+ Vector<OS_Android::TouchPos> points;
+ int pointer;
+ int what;
+};
+
+static List<JAndroidPointerEvent> pointer_events;
+static List<InputEvent> key_events;
+static bool initialized=false;
+static Mutex *input_mutex=NULL;
+static Mutex *suspend_mutex=NULL;
+static int step=0;
+static bool resized=false;
+static bool resized_reload=false;
+static bool quit_request=false;
+static Size2 new_size;
+static Vector3 accelerometer;
+static HashMap<String,JNISingleton*> jni_singletons;
+static jobject godot_io;
+
+typedef void (*GFXInitFunc)(void *ud,bool gl2);
+
+static jmethodID _on_video_init=0;
+static jobject _godot_instance;
+
+static jmethodID _openURI=0;
+static jmethodID _getDataDir=0;
+static jmethodID _getLocale=0;
+static jmethodID _getModel=0;
+static jmethodID _showKeyboard=0;
+static jmethodID _hideKeyboard=0;
+static jmethodID _setScreenOrientation=0;
+static jmethodID _getUniqueID=0;
+
+
+static void _gfx_init_func(void* ud, bool gl2) {
+
+}
+
+
+static int _open_uri(const String& p_uri) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
+ return env->CallIntMethod(godot_io,_openURI,jStr) ;
+}
+
+static String _get_data_dir() {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s =(jstring)env->CallObjectMethod(godot_io,_getDataDir);
+ return String(env->GetStringUTFChars( s, NULL ));
+}
+
+static String _get_locale() {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s =(jstring)env->CallObjectMethod(godot_io,_getLocale);
+ return String(env->GetStringUTFChars( s, NULL ));
+}
+
+static String _get_model() {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s =(jstring)env->CallObjectMethod(godot_io,_getModel);
+ return String(env->GetStringUTFChars( s, NULL ));
+}
+
+static String _get_unique_id() {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+ jstring s =(jstring)env->CallObjectMethod(godot_io,_getUniqueID);
+ return String(env->GetStringUTFChars( s, NULL ));
+}
+
+static void _show_vk(const String& p_existing) {
+
+ JNIEnv* env = ThreadAndroid::get_env();
+ jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
+ env->CallVoidMethod(godot_io, _showKeyboard, jStr);
+};
+
+static void _set_screen_orient(int p_orient) {
+
+ JNIEnv* env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_io, _setScreenOrientation, p_orient );
+};
+
+static void _hide_vk() {
+
+ JNIEnv* env = ThreadAndroid::get_env();
+ env->CallVoidMethod(godot_io, _hideKeyboard);
+};
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook) {
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**INIT EVENT! - %p\n",env);
+
+
+ initialized=true;
+ _godot_instance=activity;
+
+ JavaVM *jvm;
+ env->GetJavaVM(&jvm);
+
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","***************** HELLO FROM JNI!!!!!!!!");
+
+ {
+ //setup IO Object
+
+ jclass cls = env->FindClass("com/android/godot/Godot");
+ if (cls) {
+
+ cls=(jclass)env->NewGlobalRef(cls);
+ __android_log_print(ANDROID_LOG_INFO,"godot","*******CLASS FOUND!!!");
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP2, %p",cls);
+ jfieldID fid = env->GetStaticFieldID(cls, "io", "Lcom/android/godot/GodotIO;");
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP3 %i",fid);
+ jobject ob = env->GetStaticObjectField(cls,fid);
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP4, %p",ob);
+ jobject gob = env->NewGlobalRef(ob);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","STEP4.5, %p",gob);
+ godot_io=gob;
+
+ _on_video_init = env->GetMethodID(cls, "onVideoInit", "(Z)V");
+
+ jclass clsio = env->FindClass("com/android/godot/Godot");
+ if (cls) {
+ jclass c = env->GetObjectClass(gob);
+ _openURI = env->GetMethodID(c,"openURI","(Ljava/lang/String;)I");
+ _getDataDir = env->GetMethodID(c,"getDataDir","()Ljava/lang/String;");
+ _getLocale = env->GetMethodID(c,"getLocale","()Ljava/lang/String;");
+ _getModel = env->GetMethodID(c,"getModel","()Ljava/lang/String;");
+ _getUniqueID = env->GetMethodID(c,"getUniqueID","()Ljava/lang/String;");
+ _showKeyboard = env->GetMethodID(c,"showKeyboard","(Ljava/lang/String;)V");
+ _hideKeyboard = env->GetMethodID(c,"hideKeyboard","()V");
+ _setScreenOrientation = env->GetMethodID(c,"setScreenOrientation","(I)V");
+ }
+
+ ThreadAndroid::make_default(jvm);
+ FileAccessJAndroid::setup(gob);
+ DirAccessJAndroid::setup(gob);
+ AudioDriverAndroid::setup(gob);
+ }
+
+
+
+ os_android = new OS_Android(_gfx_init_func,env,_open_uri,_get_data_dir,_get_locale, _get_model,_show_vk, _hide_vk,_set_screen_orient,_get_unique_id);
+ os_android->set_need_reload_hooks(p_need_reload_hook);
+
+ char wd[500];
+ getcwd(wd,500);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","test construction %i\n",tst.a);
+ __android_log_print(ANDROID_LOG_INFO,"godot","running from dir %s\n",wd);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**SETUP");
+
+
+#if 0
+ char *args[]={"-test","render",NULL};
+ __android_log_print(ANDROID_LOG_INFO,"godot","pre asdasd setup...");
+ Error err = Main::setup("apk",2,args,false);
+#else
+ Error err = Main::setup("apk",0,NULL,false);
+#endif
+
+ if (err!=OK) {
+ __android_log_print(ANDROID_LOG_INFO,"godot","*****UNABLE TO SETUP");
+
+ return; //should exit instead and print the error
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","*****SETUP OK");
+
+ //video driver is determined here, because once initialized, it cant be changed
+ String vd = Globals::get_singleton()->get("display/driver");
+
+
+ if (vd.to_upper()=="GLES1")
+ env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean)false);
+ else
+ env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean)true);
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","**START");
+
+ input_mutex=Mutex::create();
+ suspend_mutex=Mutex::create();
+
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_resize(JNIEnv * env, jobject obj, jint width, jint height, jboolean reload) {
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","^_^_^_^_^ resize %lld, %i, %i\n",Thread::get_caller_ID(),width,height);
+ if (os_android)
+ os_android->set_display_size(Size2(width,height));
+
+ /*input_mutex->lock();
+ resized=true;
+ if (reload)
+ resized_reload=true;
+ new_size=Size2(width,height);
+ input_mutex->unlock();*/
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_newcontext(JNIEnv * env, jobject obj) {
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","^_^_^_^_^ newcontext %lld\n",Thread::get_caller_ID());
+ if (os_android && step > 0) {
+
+ os_android->reload_gfx();
+ }
+
+}
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_quit(JNIEnv * env, jobject obj) {
+
+ input_mutex->lock();
+ quit_request=true;
+ input_mutex->unlock();
+
+}
+
+static void _initialize_java_modules() {
+
+
+ String modules = Globals::get_singleton()->get("android/modules");
+ Vector<String> mods = modules.split(",",false);
+ __android_log_print(ANDROID_LOG_INFO,"godot","mod count: %i",mods.size());
+
+ if (mods.size()) {
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jclass activityClass = env->FindClass("com/android/godot/Godot");
+
+ jmethodID getClassLoader = env->GetMethodID(activityClass,"getClassLoader", "()Ljava/lang/ClassLoader;");
+
+ jobject cls = env->CallObjectMethod(_godot_instance, getClassLoader);
+
+ jclass classLoader = env->FindClass("java/lang/ClassLoader");
+
+ jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
+ for (int i=0;i<mods.size();i++) {
+
+ String m = mods[i];
+ //jclass singletonClass = env->FindClass(m.utf8().get_data());
+
+ print_line("LOADING MODULE: "+m);
+ jstring strClassName = env->NewStringUTF(m.utf8().get_data());
+ jclass singletonClass = (jclass)env->CallObjectMethod(cls, findClass, strClassName);
+
+ if (!singletonClass) {
+
+ ERR_EXPLAIN("Couldn't find singleton for class: "+m);
+ ERR_CONTINUE(!singletonClass);
+ }
+
+ __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class data %x",singletonClass);
+ jmethodID initialize = env->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lcom/android/godot/Godot$SingletonBase;");
+
+ jobject obj = env->CallStaticObjectMethod(singletonClass,initialize,_godot_instance);
+ __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class instance %x",obj);
+ jobject gob = env->NewGlobalRef(obj);
+
+
+ }
+
+ }
+
+}
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj)
+{
+
+
+ ThreadAndroid::setup_thread();
+
+ //__android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_ID());
+
+
+ suspend_mutex->lock();
+ input_mutex->lock();
+ //first time step happens, initialize
+ if (step == 0) {
+ // ugly hack to initialize the rest of the engine
+ // because of the way android forces you to do everything with threads
+
+ _initialize_java_modules();
+
+ Main::setup2();
+ ++step;
+ suspend_mutex->unlock();
+ input_mutex->unlock();
+ return;
+ };
+ if (step == 1) {
+ if (!Main::start()) {
+
+ input_mutex->unlock();
+ suspend_mutex->lock();
+ return; //should exit instead and print the error
+ }
+
+ os_android->main_loop_begin();
+ ++step;
+ }
+
+ while(pointer_events.size()) {
+
+ JAndroidPointerEvent jpe=pointer_events.front()->get();
+ os_android->process_touch(jpe.what,jpe.pointer,jpe.points);
+
+ pointer_events.pop_front();
+ }
+
+ while (key_events.size()) {
+
+ InputEvent event = key_events.front()->get();
+ os_android->process_event(event);
+
+ key_events.pop_front();
+ };
+
+ if (quit_request) {
+
+ os_android->main_loop_request_quit();
+ quit_request=false;
+ }
+
+
+ input_mutex->unlock();
+
+ os_android->process_accelerometer(accelerometer);
+
+ if (os_android->main_loop_iterate()==true) {
+
+ jclass cls = env->FindClass("com/android/godot/Godot");
+ jmethodID _finish = env->GetMethodID(cls, "forceQuit", "()V");
+ env->CallVoidMethod(_godot_instance, _finish);
+ __android_log_print(ANDROID_LOG_INFO,"godot","**FINISH REQUEST!!! - %p-%i\n",env,Thread::get_caller_ID());
+
+ }
+
+ suspend_mutex->unlock();
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions) {
+
+
+
+ //__android_log_print(ANDROID_LOG_INFO,"godot","**TOUCH EVENT! - %p-%i\n",env,Thread::get_caller_ID());
+
+
+ Vector<OS_Android::TouchPos> points;
+ for(int i=0;i<count;i++) {
+
+ jint p[3];
+ env->GetIntArrayRegion(positions,i*3,3,p);
+ OS_Android::TouchPos tp;
+ tp.pos=Point2(p[1],p[2]);
+ tp.id=p[0];
+ points.push_back(tp);
+ }
+
+ JAndroidPointerEvent jpe;
+ jpe.pointer=pointer;
+ jpe.points=points;
+ jpe.what=ev;
+
+ input_mutex->lock();
+
+ pointer_events.push_back(jpe);
+
+ input_mutex->unlock();
+ //if (os_android)
+// os_android->process_touch(ev,pointer,points);
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_key(JNIEnv * env, jobject obj, jint ev, jint p_unicode_char, jboolean p_pressed) {
+
+ InputEvent ievent;
+ ievent.type = InputEvent::KEY;
+ ievent.device = 0;
+ int val = p_unicode_char;
+ ievent.key.scancode = val;
+ ievent.key.unicode = val;
+ if (val == 61448) {
+ ievent.key.scancode = KEY_BACKSPACE;
+ ievent.key.unicode = KEY_BACKSPACE;
+ };
+ if (val == 61453) {
+ ievent.key.scancode = KEY_ENTER;
+ ievent.key.unicode = KEY_ENTER;
+ };
+
+ input_mutex->lock();
+ key_events.push_back(ievent);
+ input_mutex->unlock();
+};
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z) {
+
+ input_mutex->lock();
+ accelerometer=Vector3(x,y,z);
+ input_mutex->unlock();
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusin(JNIEnv * env, jobject obj){
+
+ if (!suspend_mutex)
+ return;
+ suspend_mutex->lock();
+
+ if (os_android && step > 0)
+ os_android->main_loop_focusin();
+
+ suspend_mutex->unlock();
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusout(JNIEnv * env, jobject obj){
+
+ if (!suspend_mutex)
+ return;
+ suspend_mutex->lock();
+
+ if (os_android && step > 0)
+ os_android->main_loop_focusout();
+
+ suspend_mutex->unlock();
+
+}
+
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_audio(JNIEnv * env, jobject obj) {
+
+ ThreadAndroid::setup_thread();
+ AudioDriverAndroid::thread_func(env);
+
+
+}
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_singleton(JNIEnv * env, jobject obj, jstring name,jobject p_object){
+
+ String singname = env->GetStringUTFChars( name, NULL );
+ JNISingleton *s = memnew( JNISingleton );
+ s->set_instance(env->NewGlobalRef(p_object));
+ jni_singletons[singname]=s;
+
+ Globals::get_singleton()->add_singleton(Globals::Singleton(singname,s));
+ Globals::get_singleton()->set(singname,s);
+
+}
+
+
+static Variant::Type get_jni_type(const String& p_type) {
+
+ static struct {
+ const char *name;
+ Variant::Type type;
+ } _type_to_vtype[]={
+ {"void",Variant::NIL},
+ {"boolean",Variant::BOOL},
+ {"int",Variant::INT},
+ {"float",Variant::REAL},
+ {"double", Variant::REAL},
+ {"java.lang.String",Variant::STRING},
+ {"[I",Variant::INT_ARRAY},
+ {"[F",Variant::REAL_ARRAY},
+ {"[java.lang.String",Variant::STRING_ARRAY},
+ {"com.android.godot.Dictionary", Variant::DICTIONARY},
+ {NULL,Variant::NIL}
+ };
+
+ int idx=0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type==_type_to_vtype[idx].name)
+ return _type_to_vtype[idx].type;
+
+ idx++;
+ }
+
+ return Variant::NIL;
+}
+
+
+static const char* get_jni_sig(const String& p_type) {
+
+ print_line("getting sig for " + p_type);
+ static struct {
+ const char *name;
+ const char *sig;
+ } _type_to_vtype[]={
+ {"void","V"},
+ {"boolean","Z"},
+ {"int","I"},
+ {"float","F"},
+ {"double","D"},
+ {"java.lang.String","Ljava/lang/String;"},
+ {"com.android.godot.Dictionary", "Lcom/android/godot/Dictionary;"},
+ {"[I","[I"},
+ {"[F","[F"},
+ {"[java.lang.String","[Ljava/lang/String;"},
+ {NULL,"V"}
+ };
+
+ int idx=0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type==_type_to_vtype[idx].name)
+ return _type_to_vtype[idx].sig;
+
+ idx++;
+ }
+
+
+ return "Ljava/lang/Object;";
+}
+
+JNIEXPORT jstring JNICALL Java_com_android_godot_GodotLib_getGlobal(JNIEnv * env, jobject obj, jstring path) {
+
+ String js = env->GetStringUTFChars( path, NULL );
+
+ return env->NewStringUTF(Globals::get_singleton()->get(js).operator String().utf8().get_data());
+
+
+}
+
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_method(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args){
+
+ String singname = env->GetStringUTFChars( sname, NULL );
+
+ ERR_FAIL_COND(!jni_singletons.has(singname));
+
+ JNISingleton *s = jni_singletons.get(singname);
+
+
+ String mname = env->GetStringUTFChars( name, NULL );
+ String retval = env->GetStringUTFChars( ret, NULL );
+ Vector<Variant::Type> types;
+ String cs="(";
+
+
+ int stringCount = env->GetArrayLength(args);
+
+ print_line("Singl: "+singname+" Method: "+mname+" RetVal: "+retval);
+ for (int i=0; i<stringCount; i++) {
+
+ jstring string = (jstring) env->GetObjectArrayElement(args, i);
+ const char *rawString = env->GetStringUTFChars(string, 0);
+ types.push_back(get_jni_type(String(rawString)));
+ cs+=get_jni_sig(String(rawString));
+ }
+
+ cs+=")";
+ cs+=get_jni_sig(retval);
+ jclass cls = env->GetObjectClass(s->get_instance());
+ print_line("METHOD: "+mname+" sig: "+cs);
+ jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
+ if (!mid) {
+
+ print_line("FAILED GETTING METHOID "+mname);
+ }
+
+ s->add_method(mname,mid,types,get_jni_type(retval));
+
+
+}
+
+JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) {
+
+ String str_method = env->GetStringUTFChars( method, NULL );
+
+ Object* obj = ObjectDB::get_instance(ID);
+ ERR_FAIL_COND(!obj);
+
+ int count = env->GetArrayLength(params);
+ Variant* vlist = (Variant*)alloca(sizeof(Variant) * count);
+ Variant** vptr = (Variant**)alloca(sizeof(Variant*) * count);
+ for (int i=0; i<count; i++) {
+
+ jobject obj = env->GetObjectArrayElement(params, i);
+ Variant v = _jobject_to_variant(env, obj);
+ memnew_placement(&vlist[i], Variant);
+ vlist[i] = v;
+ vptr[i] = &vlist[i];
+ };
+
+ Variant::CallError err;
+ obj->call(str_method, (const Variant**)vptr, count, err);
+ // something
+};
+
+
+//Main::cleanup();
+
+//return os.get_exit_code();
+#endif
diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h
new file mode 100644
index 0000000000..7a0666f63d
--- /dev/null
+++ b/platform/android/java_glue.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* java_glue.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef ANDROID_NATIVE_ACTIVITY
+
+#ifndef JAVA_GLUE_H
+#define JAVA_GLUE_H
+
+#include <jni.h>
+#include <android/log.h>
+
+
+extern "C" {
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_resize(JNIEnv * env, jobject obj, jint width, jint height, jboolean reload);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_newcontext(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_quit(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_key(JNIEnv * env, jobject obj, jint ev, jint p_unicode_char, jboolean p_pressed);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_audio(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusin(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusout(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_singleton(JNIEnv * env, jobject obj, jstring name,jobject p_object);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_method(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
+ JNIEXPORT jstring JNICALL Java_com_android_godot_GodotLib_getGlobal(JNIEnv * env, jobject obj, jstring path);
+ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env, jobject obj, jint ID, jstring method, jobjectArray params);
+};
+
+
+#endif
+#endif // JAVA_GLUE_H
diff --git a/platform/android/logo.png b/platform/android/logo.png
new file mode 100644
index 0000000000..a7e2c6f130
--- /dev/null
+++ b/platform/android/logo.png
Binary files differ
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
new file mode 100644
index 0000000000..9d9da3750e
--- /dev/null
+++ b/platform/android/os_android.cpp
@@ -0,0 +1,709 @@
+/*************************************************************************/
+/* os_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "os_android.h"
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "drivers/gles1/rasterizer_gles1.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"
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+#include "file_access_android.h"
+#include "dir_access_android.h"
+#else
+#include "file_access_jandroid.h"
+#include "dir_access_jandroid.h"
+#endif
+
+int OS_Android::get_video_driver_count() const {
+
+ return 2;
+}
+const char * OS_Android::get_video_driver_name(int p_driver) const {
+
+ return p_driver==0?"GLES2":"GLES1";
+}
+
+OS::VideoMode OS_Android::get_default_video_mode() const {
+
+ return OS::VideoMode();
+}
+
+int OS_Android::get_audio_driver_count() const {
+
+ return 1;
+}
+
+const char * OS_Android::get_audio_driver_name(int p_driver) const {
+
+ return "Android";
+}
+
+void OS_Android::initialize_core() {
+
+ OS_Unix::initialize_core();
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+
+ FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
+ FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
+ //FileAccessBufferedFA<FileAccessUnix>::make_default();
+ DirAccess::make_default<DirAccessAndroid>(DirAccess::ACCESS_RESOURCES);
+ DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
+ DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
+
+#else
+
+ FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid> >(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
+ FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
+ //FileAccessBufferedFA<FileAccessUnix>::make_default();
+ DirAccess::make_default<DirAccessJAndroid>(DirAccess::ACCESS_RESOURCES);
+ DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
+ DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
+
+#endif
+
+}
+
+void OS_Android::set_opengl_extensions(const char* p_gl_extensions) {
+
+ ERR_FAIL_COND(!p_gl_extensions);
+ gl_extensions=p_gl_extensions;
+}
+
+void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+
+ use_gl2=p_video_driver!=1;
+
+
+ if (gfx_init_func)
+ gfx_init_func(gfx_init_ud,use_gl2);
+
+ AudioDriverManagerSW::add_driver(&audio_driver_android);
+
+
+ if (use_gl2) {
+ RasterizerGLES2 *rasterizer_gles22=memnew( RasterizerGLES2(false,use_reload_hooks,false,use_reload_hooks ) );
+ if (gl_extensions)
+ rasterizer_gles22->set_extensions(gl_extensions);
+ rasterizer = rasterizer_gles22;
+ } else {
+ rasterizer = memnew( RasterizerGLES1(use_reload_hooks, use_reload_hooks) );
+
+ }
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ visual_server->init();
+ visual_server->cursor_set_visible(false, 0);
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+
+ audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+ audio_server->init();
+
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+}
+
+void OS_Android::set_main_loop( MainLoop * p_main_loop ) {
+
+ main_loop=p_main_loop;
+ input->set_main_loop(p_main_loop);
+#if 0
+
+ print_line("preGS");
+ FileAccess *f=memnew( FileAccessAndroid );
+ print("made f %p\n",f);
+ Error err = f->open("AndroidManifest.xml",FileAccess::READ);
+ if (err) {
+
+ print("************NO FILE!!\n");
+ } else {
+ print("************YES FILE!!\n");
+ }
+ f->close();
+ print_line("end");
+
+
+ AAssetDir* aad = AAssetManager_openDir(FileAccessAndroid::asset_manager,".");
+
+ if (aad) {
+
+ print_line("DIR OPEN OK");
+
+ const char *fn= AAssetDir_getNextFileName(aad);
+
+ while(fn) {
+
+ print_line("FNAME: "+String(fn));
+ fn= AAssetDir_getNextFileName(aad);
+ }
+
+ AAssetDir_close(aad);
+ } else {
+
+ print_line("DIR NO OPEN");
+ }
+
+#endif
+
+}
+
+void OS_Android::delete_main_loop() {
+
+ memdelete( main_loop );
+}
+
+void OS_Android::finalize() {
+
+ memdelete(input);
+}
+
+
+void OS_Android::vprint(const char* p_format, va_list p_list, bool p_stderr) {
+
+ __android_log_vprint(p_stderr?ANDROID_LOG_ERROR:ANDROID_LOG_INFO,"godot",p_format,p_list);
+}
+
+void OS_Android::print(const char *p_format, ... ) {
+
+ va_list argp;
+ va_start(argp, p_format);
+ __android_log_vprint(ANDROID_LOG_INFO,"godot",p_format,argp);
+ va_end(argp);
+
+}
+
+void OS_Android::alert(const String& p_alert) {
+
+ print("ALERT: %s\n",p_alert.utf8().get_data());
+}
+
+
+void OS_Android::set_mouse_show(bool p_show) {
+
+ //android has no mouse...
+}
+
+void OS_Android::set_mouse_grab(bool p_grab) {
+
+ //it really has no mouse...!
+}
+
+bool OS_Android::is_mouse_grab_enabled() const {
+
+ //*sigh* technology has evolved so much since i was a kid..
+ return false;
+}
+Point2 OS_Android::get_mouse_pos() const {
+
+ return Point2();
+}
+int OS_Android::get_mouse_button_state() const {
+
+ return 0;
+}
+void OS_Android::set_window_title(const String& p_title) {
+
+
+}
+
+//interesting byt not yet
+//void set_clipboard(const String& p_text);
+//String get_clipboard() const;
+
+void OS_Android::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+
+}
+
+OS::VideoMode OS_Android::get_video_mode(int p_screen) const {
+
+ return default_videomode;
+}
+void OS_Android::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+ p_list->push_back(default_videomode);
+}
+
+String OS_Android::get_name() {
+
+ return "Android";
+}
+
+MainLoop *OS_Android::get_main_loop() const {
+
+ return main_loop;
+}
+
+bool OS_Android::can_draw() const {
+
+ return true; //always?
+}
+
+void OS_Android::set_cursor_shape(CursorShape p_shape) {
+
+ //android really really really has no mouse.. how amazing..
+}
+
+void OS_Android::main_loop_begin() {
+
+ if (main_loop)
+ main_loop->init();
+}
+bool OS_Android::main_loop_iterate() {
+
+ if (!main_loop)
+ return false;
+ return Main::iteration();
+}
+
+void OS_Android::main_loop_end() {
+
+ if (main_loop)
+ main_loop->finish();
+
+}
+
+void OS_Android::main_loop_focusout() {
+
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+ audio_driver_android.set_pause(true);
+
+}
+
+void OS_Android::main_loop_focusin(){
+
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+ audio_driver_android.set_pause(false);
+
+}
+
+
+void OS_Android::process_event(InputEvent p_event) {
+
+ p_event.ID = last_id++;
+ input->parse_input_event(p_event);
+};
+
+
+void OS_Android::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()));
+
+ switch(p_what) {
+ case 0: { //gesture begin
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=last_id++;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ input->parse_input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+
+ }
+ }
+
+ touch.resize(p_points.size());
+ for(int i=0;i<p_points.size();i++) {
+ touch[i].id=p_points[i].id;
+ touch[i].pos=p_points[i].pos;
+ }
+
+ {
+ //send mouse
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=last_id++;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=true;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ last_mouse=touch[0].pos;
+ input->parse_input_event(ev);
+ }
+
+
+ //send touch
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+ }
+
+ } break;
+ case 1: { //motion
+
+
+ if (p_points.size()) {
+ //send mouse, should look for point 0?
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_MOTION;
+ ev.ID=last_id++;
+ ev.mouse_motion.button_mask=BUTTON_MASK_LEFT;
+ 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.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;
+ input->parse_input_event(ev);
+ }
+
+ ERR_FAIL_COND(touch.size()!=p_points.size());
+
+ for(int i=0;i<touch.size();i++) {
+
+ int idx=-1;
+ for(int j=0;j<p_points.size();j++) {
+
+ if (touch[i].id==p_points[j].id) {
+ idx=j;
+ break;
+ }
+
+ }
+
+ ERR_CONTINUE(idx==-1);
+
+ if (touch[i].pos==p_points[idx].pos)
+ continue; //no move unncesearily
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_DRAG;
+ ev.ID=last_id++;
+ ev.screen_drag.index=touch[i].id;
+ ev.screen_drag.x=p_points[idx].pos.x;
+ ev.screen_drag.y=p_points[idx].pos.y;
+ ev.screen_drag.relative_x=p_points[idx].pos.x - touch[i].pos.x;
+ ev.screen_drag.relative_y=p_points[idx].pos.y - touch[i].pos.y;
+ input->parse_input_event(ev);
+ touch[i].pos=p_points[idx].pos;
+ }
+
+
+ } break;
+ case 2: { //release
+
+
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=last_id++;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ input->parse_input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+
+ }
+ touch.clear();
+ }
+
+ } break;
+ case 3: { // add tuchi
+
+
+
+
+
+ ERR_FAIL_INDEX(p_pointer,p_points.size());
+
+ TouchPos tp=p_points[p_pointer];
+ touch.push_back(tp);
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=tp.id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=tp.pos.x;
+ ev.screen_touch.y=tp.pos.y;
+ input->parse_input_event(ev);
+
+ } break;
+ case 4: {
+
+
+ for(int i=0;i<touch.size();i++) {
+ if (touch[i].id==p_pointer) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+ touch.remove(i);
+ i--;
+ }
+ }
+
+ } break;
+
+ }
+
+}
+
+void OS_Android::process_accelerometer(const Vector3& p_accelerometer) {
+
+ input->set_accelerometer(p_accelerometer);
+}
+
+bool OS_Android::has_touchscreen_ui_hint() const {
+
+ return true;
+}
+
+bool OS_Android::has_virtual_keyboard() const {
+
+ return true;
+};
+
+void OS_Android::show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect) {
+
+ if (show_virtual_keyboard_func) {
+ show_virtual_keyboard_func(p_existing_text);
+ } else {
+
+ ERR_PRINT("Virtual keyboard not available");
+ };
+};
+
+void OS_Android::hide_virtual_keyboard() {
+
+ if (hide_virtual_keyboard_func) {
+
+ hide_virtual_keyboard_func();
+ } else {
+
+ ERR_PRINT("Virtual keyboard not available");
+ };
+};
+
+
+void OS_Android::init_video_mode(int p_video_width,int p_video_height) {
+
+ default_videomode.width=p_video_width;
+ default_videomode.height=p_video_height;
+ default_videomode.fullscreen=true;
+ default_videomode.resizable=false;
+}
+
+void OS_Android::main_loop_request_quit() {
+
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+}
+
+void OS_Android::set_display_size(Size2 p_size) {
+
+ default_videomode.width=p_size.x;
+ default_videomode.height=p_size.y;
+}
+
+void OS_Android::reload_gfx() {
+
+ if (gfx_init_func)
+ gfx_init_func(gfx_init_ud,use_gl2);
+ if (rasterizer)
+ rasterizer->reload_vram();
+}
+
+Error OS_Android::shell_open(String p_uri) {
+
+ if (open_uri_func)
+ return open_uri_func(p_uri)?ERR_CANT_OPEN:OK;
+ return ERR_UNAVAILABLE;
+};
+
+String OS_Android::get_resource_dir() const {
+
+ return "/"; //android has it's own filesystem for resources inside the APK
+}
+
+String OS_Android::get_locale() const {
+
+ if (get_locale_func)
+ return get_locale_func();
+ return OS_Unix::get_locale();
+}
+
+String OS_Android::get_model_name() const {
+
+ if (get_model_func)
+ return get_model_func();
+ return OS_Unix::get_model_name();
+}
+
+
+void OS_Android::set_need_reload_hooks(bool p_needs_them) {
+
+ use_reload_hooks=p_needs_them;
+}
+
+String OS_Android::get_data_dir() const {
+
+ if (get_data_dir_func)
+ return get_data_dir_func();
+ return ".";
+ //return Globals::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
+};
+
+
+void OS_Android::set_screen_orientation(ScreenOrientation p_orientation) {
+
+
+ if (set_screen_orientation_func)
+ set_screen_orientation_func(p_orientation);
+}
+
+
+String OS_Android::get_unique_ID() const {
+
+ if (get_unique_id_func)
+ return get_unique_id_func();
+ return OS::get_unique_ID();
+}
+
+
+OS_Android::OS_Android(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,GetModelFunc p_get_model_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient,GetUniqueIDFunc p_get_unique_id) {
+
+
+ default_videomode.width=800;
+ default_videomode.height=600;
+ default_videomode.fullscreen=true;
+ default_videomode.resizable=false;
+
+ gfx_init_func=p_gfx_init_func;
+ gfx_init_ud=p_gfx_init_ud;
+ main_loop=NULL;
+ last_id=1;
+ gl_extensions=NULL;
+ rasterizer=NULL;
+ use_gl2=false;
+
+ open_uri_func=p_open_uri_func;
+ get_data_dir_func=p_get_data_dir_func;
+ get_locale_func=p_get_locale_func;
+ get_model_func=p_get_model_func;
+ get_unique_id_func=p_get_unique_id;
+
+ show_virtual_keyboard_func = p_show_vk;
+ hide_virtual_keyboard_func = p_hide_vk;
+
+ set_screen_orientation_func=p_screen_orient;
+ use_reload_hooks=false;
+
+}
+
+OS_Android::~OS_Android() {
+
+
+}
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
new file mode 100644
index 0000000000..93c672927e
--- /dev/null
+++ b/platform/android/os_android.h
@@ -0,0 +1,197 @@
+/*************************************************************************/
+/* os_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef OS_ANDROID_H
+#define OS_ANDROID_H
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+#include "os/main_loop.h"
+#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/physics_2d/physics_2d_server_sw.h"
+#include "servers/visual/rasterizer.h"
+
+
+#ifdef ANDROID_NATIVE_ACTIVITY
+#include "audio_driver_android.h"
+#include <android/sensor.h>
+#include <android/log.h>
+#include <android_native_app_glue.h>
+
+#else
+#include "audio_driver_jandroid.h"
+
+#endif
+
+typedef void (*GFXInitFunc)(void *ud,bool gl2);
+typedef int (*OpenURIFunc)(const String&);
+typedef String (*GetDataDirFunc)();
+typedef String (*GetLocaleFunc)();
+typedef String (*GetModelFunc)();
+typedef String (*GetUniqueIDFunc)();
+typedef void (*ShowVirtualKeyboardFunc)(const String&);
+typedef void (*HideVirtualKeyboardFunc)();
+typedef void (*SetScreenOrientationFunc)(int);
+
+class OS_Android : public OS_Unix {
+public:
+
+ struct TouchPos {
+ int id;
+ Point2 pos;
+ };
+
+private:
+
+ Vector<TouchPos> touch;
+
+ Point2 last_mouse;
+ unsigned int last_id;
+ GFXInitFunc gfx_init_func;
+ void*gfx_init_ud;
+
+ bool use_gl2;
+ bool use_reload_hooks;
+
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+ AudioDriverAndroid audio_driver_android;
+ const char* gl_extensions;
+
+ InputDefault *input;
+ VideoMode default_videomode;
+ MainLoop * main_loop;
+
+ OpenURIFunc open_uri_func;
+ GetDataDirFunc get_data_dir_func;
+ GetLocaleFunc get_locale_func;
+ GetModelFunc get_model_func;
+ ShowVirtualKeyboardFunc show_virtual_keyboard_func;
+ HideVirtualKeyboardFunc hide_virtual_keyboard_func;
+ SetScreenOrientationFunc set_screen_orientation_func;
+ GetUniqueIDFunc get_unique_id_func;
+
+public:
+
+ // functions used by main to initialize/deintialize the OS
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
+ virtual void initialize_core();
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+
+
+ typedef int64_t ProcessID;
+
+ 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 set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ //virtual void set_clipboard(const String& p_text);
+ //virtual String get_clipboard() const;
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ 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 String get_name();
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ void main_loop_begin();
+ bool main_loop_iterate();
+ void main_loop_request_quit();
+ void main_loop_end();
+ void main_loop_focusout();
+ void main_loop_focusin();
+
+ virtual bool has_touchscreen_ui_hint() const;
+
+ virtual bool has_virtual_keyboard() const;
+ virtual void show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect=Rect2());
+ virtual void hide_virtual_keyboard();
+
+ void set_opengl_extensions(const char* p_gl_extensions);
+ void set_display_size(Size2 p_size);
+
+ void reload_gfx();
+
+ void set_need_reload_hooks(bool p_needs_them);
+ virtual void set_screen_orientation(ScreenOrientation p_orientation);
+
+ virtual Error shell_open(String p_uri);
+ virtual String get_data_dir() const;
+ virtual String get_resource_dir() const;
+ virtual String get_locale() const;
+ virtual String get_model_name() const;
+
+ virtual String get_unique_ID() const;
+
+
+ void process_accelerometer(const Vector3& p_accelerometer);
+ void process_touch(int p_what,int p_pointer, const Vector<TouchPos>& p_points);
+ void process_event(InputEvent p_event);
+ void init_video_mode(int p_video_width,int p_video_height);
+ OS_Android(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,GetModelFunc p_get_model_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient,GetUniqueIDFunc p_get_unique_id);
+ ~OS_Android();
+
+};
+
+#endif
diff --git a/platform/android/platform_config.h b/platform/android/platform_config.h
new file mode 100644
index 0000000000..38fc934ae4
--- /dev/null
+++ b/platform/android/platform_config.h
@@ -0,0 +1,29 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <alloca.h>
diff --git a/platform/android/project.properties.template b/platform/android/project.properties.template
new file mode 100644
index 0000000000..72bea9659c
--- /dev/null
+++ b/platform/android/project.properties.template
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+#android.library=true
+target=android-13
diff --git a/platform/android/sign.sh b/platform/android/sign.sh
new file mode 100755
index 0000000000..830da05a37
--- /dev/null
+++ b/platform/android/sign.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+jarsigner -digestalg SHA1 -sigalg MD5withRSA -verbose -keystore my-release-key.keystore "$1" reduz
+
+echo ""
+echo ""
+echo "Checking if APK is verified..."
+jarsigner -verify "$1" -verbose -certs
+
diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp
new file mode 100644
index 0000000000..ec6bef89a0
--- /dev/null
+++ b/platform/android/thread_jandroid.cpp
@@ -0,0 +1,135 @@
+/*************************************************************************/
+/* thread_jandroid.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "thread_jandroid.h"
+
+#include "os/memory.h"
+
+Thread::ID ThreadAndroid::get_ID() const {
+
+ return id;
+}
+
+Thread* ThreadAndroid::create_thread_jandroid() {
+
+ return memnew( ThreadAndroid );
+}
+
+void *ThreadAndroid::thread_callback(void *userdata) {
+
+ ThreadAndroid *t=reinterpret_cast<ThreadAndroid*>(userdata);
+ setup_thread();
+ t->id=(ID)pthread_self();
+ t->callback(t->user);
+ return NULL;
+}
+
+Thread* ThreadAndroid::create_func_jandroid(ThreadCreateCallback p_callback,void *p_user,const Settings&) {
+
+ ThreadAndroid *tr= memnew(ThreadAndroid);
+ tr->callback=p_callback;
+ tr->user=p_user;
+ pthread_attr_init(&tr->pthread_attr);
+ pthread_attr_setdetachstate(&tr->pthread_attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&tr->pthread, &tr->pthread_attr, thread_callback, tr);
+
+ return tr;
+}
+Thread::ID ThreadAndroid::get_thread_ID_func_jandroid() {
+
+ return (ID)pthread_self();
+}
+void ThreadAndroid::wait_to_finish_func_jandroid(Thread* p_thread) {
+
+ ThreadAndroid *tp=static_cast<ThreadAndroid*>(p_thread);
+ ERR_FAIL_COND(!tp);
+ ERR_FAIL_COND(tp->pthread==0);
+
+ pthread_join(tp->pthread,NULL);
+ tp->pthread=0;
+}
+
+void ThreadAndroid::_thread_destroyed(void* value) {
+
+ /* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
+ JNIEnv *env = (JNIEnv*) value;
+ if (env != NULL) {
+ java_vm->DetachCurrentThread();
+ pthread_setspecific(jvm_key, NULL);
+ }
+
+}
+
+pthread_key_t ThreadAndroid::jvm_key;
+JavaVM* ThreadAndroid::java_vm=NULL;
+
+void ThreadAndroid::setup_thread() {
+
+ if (pthread_getspecific(jvm_key))
+ return; //already setup
+ JNIEnv *env;
+ java_vm->AttachCurrentThread(&env, NULL);
+ pthread_setspecific(jvm_key, (void*) env);
+
+}
+
+void ThreadAndroid::make_default(JavaVM* p_java_vm) {
+
+ java_vm=p_java_vm;
+ create_func=create_func_jandroid;
+ get_thread_ID_func=get_thread_ID_func_jandroid;
+ wait_to_finish_func=wait_to_finish_func_jandroid;
+ pthread_key_create(&jvm_key, _thread_destroyed);
+ setup_thread();
+
+}
+
+JNIEnv *ThreadAndroid::get_env() {
+
+ if (!pthread_getspecific(jvm_key)) {
+ setup_thread();
+ }
+
+ JNIEnv *env=NULL;
+ int status = java_vm->AttachCurrentThread(&env, NULL);
+ return env;
+}
+
+
+ThreadAndroid::ThreadAndroid() {
+
+ pthread=0;
+}
+
+
+ThreadAndroid::~ThreadAndroid() {
+
+}
+
+
diff --git a/platform/android/thread_jandroid.h b/platform/android/thread_jandroid.h
new file mode 100644
index 0000000000..38b4be01ec
--- /dev/null
+++ b/platform/android/thread_jandroid.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* thread_jandroid.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef THREAD_POSIX_H
+#define THREAD_POSIX_H
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+
+#include <sys/types.h>
+#include <pthread.h>
+#include "os/thread.h"
+#include <jni.h>
+
+class ThreadAndroid : public Thread {
+
+ pthread_t pthread;
+ pthread_attr_t pthread_attr;
+ ThreadCreateCallback callback;
+ void *user;
+ ID id;
+
+ static Thread* create_thread_jandroid();
+
+
+ static void *thread_callback(void *userdata);
+
+ static Thread* create_func_jandroid(ThreadCreateCallback p_callback,void *,const Settings&);
+ static ID get_thread_ID_func_jandroid();
+ static void wait_to_finish_func_jandroid(Thread* p_thread);
+
+ static void _thread_destroyed(void* value);
+ ThreadAndroid();
+
+ static pthread_key_t jvm_key;
+ static JavaVM* java_vm;
+public:
+
+
+
+
+ virtual ID get_ID() const;
+
+ static void make_default(JavaVM* p_java_vm);
+ static void setup_thread();
+ static JNIEnv *get_env();
+
+
+ ~ThreadAndroid();
+
+};
+
+
+
+#endif
diff --git a/platform/bb10/SCsub b/platform/bb10/SCsub
new file mode 100644
index 0000000000..2e8ef47005
--- /dev/null
+++ b/platform/bb10/SCsub
@@ -0,0 +1,30 @@
+Import('env')
+
+bb10_lib = [
+
+ 'bbutil.c',
+ 'os_bb10.cpp',
+ 'audio_driver_bb10.cpp',
+ 'godot_bb10.cpp',
+ 'payment_service.cpp',
+]
+
+env_bps = env.Clone()
+if env['bb10_payment_service'] == "yes":
+ env_bps.Append(CPPFLAGS=['-DPAYMENT_SERVICE_ENABLED'])
+
+if env['bb10_lgles_override'] == "yes":
+ env_bps.Append(CPPFLAGS=['-DBB10_LGLES_OVERRIDE'])
+
+
+prog = None
+if env["target"]=="release":
+ prog = env_bps.Program('#platform/bb10/godot_bb10_opt', bb10_lib)
+else:
+ prog = env_bps.Program('#platform/bb10/godot_bb10', bb10_lib)
+
+import os
+fname = os.path.basename(str(prog[0]))
+
+env.Command('#bin/'+fname, prog, Copy('bin/'+fname, prog[0]))
+
diff --git a/platform/bb10/audio_driver_bb10.cpp b/platform/bb10/audio_driver_bb10.cpp
new file mode 100644
index 0000000000..ac6a008a00
--- /dev/null
+++ b/platform/bb10/audio_driver_bb10.cpp
@@ -0,0 +1,255 @@
+/*************************************************************************/
+/* audio_driver_bb10.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "audio_driver_bb10.h"
+
+#include <errno.h>
+
+Error AudioDriverBB10::init() {
+ return init(NULL);
+};
+
+Error AudioDriverBB10::init(const char* p_name) {
+
+ active=false;
+ thread_exited=false;
+ exit_thread=false;
+ pcm_open = false;
+ samples_in = NULL;
+ samples_out = NULL;
+
+ mix_rate = 44100;
+ output_format = OUTPUT_STEREO;
+
+ char* dev_name;
+ if (p_name == NULL) {
+ dev_name = "pcmPreferred";
+ } else {
+ dev_name = (char *) p_name;
+ }
+ printf("******** reconnecting to device %s\n", dev_name);
+ int card, dev;
+ int ret = snd_pcm_open_name(&pcm_handle, dev_name, SND_PCM_OPEN_PLAYBACK);
+ ERR_FAIL_COND_V(ret < 0, FAILED);
+ pcm_open = true;
+
+ snd_pcm_channel_info_t cinfo;
+ zeromem(&cinfo, sizeof (cinfo));
+ cinfo.channel = SND_PCM_CHANNEL_PLAYBACK;
+ snd_pcm_plugin_info(pcm_handle, &cinfo);
+
+ printf("rates %i, %i, %i, %i, %i\n", cinfo.rates, cinfo.rates & SND_PCM_RATE_44100, cinfo.rates & SND_PCM_RATE_32000, cinfo.rates & SND_PCM_RATE_22050, cinfo.max_rate);
+
+ mix_rate = cinfo.max_rate;
+
+ printf("formats %i, %i, %i\n", cinfo.formats, cinfo.formats & SND_PCM_FMT_S16_BE, cinfo.formats & SND_PCM_FMT_S16_LE);
+ ERR_FAIL_COND_V(!(cinfo.formats & SND_PCM_FMT_S16_LE), FAILED);
+
+ printf("voices %i\n", cinfo.max_voices);
+ output_format = cinfo.max_voices >= 2 ? OUTPUT_STEREO : OUTPUT_MONO;
+
+ snd_pcm_channel_params_t cp;
+ zeromem(&cp, sizeof(cp));
+ cp.mode = SND_PCM_MODE_BLOCK;
+ cp.channel = SND_PCM_CHANNEL_PLAYBACK;
+ cp.start_mode = SND_PCM_START_DATA;
+ cp.stop_mode = SND_PCM_STOP_STOP;
+ //cp.buf.block.frag_size = cinfo.max_fragment_size;
+ cp.buf.block.frag_size = 512;
+ cp.buf.block.frags_max = 1;
+ cp.buf.block.frags_min = 1;
+ cp.format.interleave = 1;
+ cp.format.rate = mix_rate;
+ cp.format.voices = output_format == OUTPUT_MONO ? 1 : 2;
+ cp.format.format = SND_PCM_SFMT_S16_LE;
+
+ ret = snd_pcm_plugin_params(pcm_handle, &cp);
+ printf("ret is %i, %i\n", ret, cp.why_failed);
+ ERR_FAIL_COND_V(ret < 0, FAILED);
+
+ ret = snd_pcm_plugin_prepare(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
+ ERR_FAIL_COND_V(ret < 0, FAILED);
+
+ snd_mixer_group_t group;
+ zeromem(&group, sizeof(group));
+ snd_pcm_channel_setup_t setup;
+ zeromem(&setup, sizeof(setup));
+ setup.channel = SND_PCM_CHANNEL_PLAYBACK;
+ setup.mode = SND_PCM_MODE_BLOCK;
+ setup.mixer_gid = &group.gid;
+ ret = snd_pcm_plugin_setup(pcm_handle, &setup);
+ ERR_FAIL_COND_V(ret < 0, FAILED);
+
+ pcm_frag_size = setup.buf.block.frag_size;
+ pcm_max_frags = 1;
+
+ sample_buf_count = pcm_frag_size * pcm_max_frags / 2;
+ printf("sample count %i, %i, %i\n", sample_buf_count, pcm_frag_size, pcm_max_frags);
+ samples_in = memnew_arr(int32_t, sample_buf_count);
+ samples_out = memnew_arr(int16_t, sample_buf_count);
+
+ thread = Thread::create(AudioDriverBB10::thread_func, this);
+
+ return OK;
+};
+
+void AudioDriverBB10::thread_func(void* p_udata) {
+
+ AudioDriverBB10* ad = (AudioDriverBB10*)p_udata;
+
+ int channels = (ad->output_format == OUTPUT_MONO ? 1 : 2);
+ int frame_count = ad->sample_buf_count / channels;
+ int bytes_out = frame_count * channels * 2;
+
+ while (!ad->exit_thread) {
+
+
+ if (!ad->active) {
+
+ for (int i=0; i < ad->sample_buf_count; i++) {
+
+ ad->samples_out[i] = 0;
+ };
+ } else {
+
+ ad->lock();
+
+ ad->audio_server_process(frame_count, ad->samples_in);
+
+ ad->unlock();
+
+ for(int i=0;i<frame_count*channels;i++) {
+
+ ad->samples_out[i]=ad->samples_in[i]>>16;
+ }
+ };
+
+
+ int todo = bytes_out;
+ int total = 0;
+
+ while (todo) {
+
+ uint8_t* src = (uint8_t*)ad->samples_out;
+ int wrote = snd_pcm_plugin_write(ad->pcm_handle, (void*)(src + total), todo);
+ if (wrote < 0) {
+ // error?
+ break;
+ };
+ total += wrote;
+ todo -= wrote;
+ if (wrote < todo) {
+ if (ad->thread_exited) {
+ break;
+ };
+ printf("pcm_write underrun %i, errno %i\n", (int)ad->thread_exited, errno);
+ snd_pcm_channel_status_t status;
+ zeromem(&status, sizeof(status));
+ // put in non-blocking mode
+ snd_pcm_nonblock_mode(ad->pcm_handle, 1);
+ status.channel = SND_PCM_CHANNEL_PLAYBACK;
+ int ret = snd_pcm_plugin_status(ad->pcm_handle, &status);
+ //printf("status return %i, %i, %i, %i, %i\n", ret, errno, status.status, SND_PCM_STATUS_READY, SND_PCM_STATUS_UNDERRUN);
+ snd_pcm_nonblock_mode(ad->pcm_handle, 0);
+ if (ret < 0) {
+ break;
+ };
+ if (status.status == SND_PCM_STATUS_READY ||
+ status.status == SND_PCM_STATUS_UNDERRUN) {
+ snd_pcm_plugin_prepare(ad->pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
+ } else {
+ break;
+ };
+ };
+ };
+ };
+
+ snd_pcm_plugin_flush (ad->pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
+
+ ad->thread_exited=true;
+ printf("**************** audio thread exit\n");
+};
+
+void AudioDriverBB10::start() {
+
+ active = true;
+};
+
+int AudioDriverBB10::get_mix_rate() const {
+
+ return mix_rate;
+};
+
+AudioDriverSW::OutputFormat AudioDriverBB10::get_output_format() const {
+
+ return output_format;
+};
+void AudioDriverBB10::lock() {
+
+ if (!thread)
+ return;
+ mutex->lock();
+};
+void AudioDriverBB10::unlock() {
+
+ if (!thread)
+ return;
+ mutex->unlock();
+};
+
+void AudioDriverBB10::finish() {
+
+ if (!thread)
+ return;
+
+ exit_thread = true;
+ Thread::wait_to_finish(thread);
+
+ if (pcm_open)
+ snd_pcm_close(pcm_handle);
+
+ if (samples_in) {
+ memdelete_arr(samples_in);
+ memdelete_arr(samples_out);
+ };
+
+ memdelete(thread);
+ thread = NULL;
+};
+
+AudioDriverBB10::AudioDriverBB10() {
+
+ mutex = Mutex::create();
+};
+
+AudioDriverBB10::~AudioDriverBB10() {
+
+ memdelete(mutex);
+ mutex = NULL;
+};
+
diff --git a/platform/bb10/audio_driver_bb10.h b/platform/bb10/audio_driver_bb10.h
new file mode 100644
index 0000000000..98b99107d4
--- /dev/null
+++ b/platform/bb10/audio_driver_bb10.h
@@ -0,0 +1,78 @@
+/*************************************************************************/
+/* audio_driver_bb10.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "servers/audio/audio_server_sw.h"
+
+#include "core/os/thread.h"
+#include "core/os/mutex.h"
+
+#include <sys/asoundlib.h>
+
+class AudioDriverBB10 : public AudioDriverSW {
+
+ Thread* thread;
+ Mutex* mutex;
+
+ snd_pcm_t* pcm_handle;
+
+ int32_t* samples_in;
+ int16_t* samples_out;
+ int sample_buf_count;
+
+ static void thread_func(void* p_udata);
+
+ int mix_rate;
+ OutputFormat output_format;
+
+ int pcm_frag_size;
+ int pcm_max_frags;
+
+ bool active;
+ bool thread_exited;
+ mutable bool exit_thread;
+ bool pcm_open;
+
+public:
+
+ const char* get_name() const {
+ return "BB10";
+ };
+
+ virtual Error init();
+ virtual Error init(const char* p_name);
+ virtual void start();
+ virtual int get_mix_rate() const;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+ AudioDriverBB10();
+ ~AudioDriverBB10();
+};
+
diff --git a/platform/bb10/bar/bar-descriptor.xml b/platform/bb10/bar/bar-descriptor.xml
new file mode 100644
index 0000000000..df5d34e077
--- /dev/null
+++ b/platform/bb10/bar/bar-descriptor.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<qnx xmlns="http://www.qnx.com/schemas/application/1.0">
+
+<!-- BlackBerry® 10 application descriptor file.
+
+ Specifies parameters for identifying, installing, and launching native applications on BlackBerry® 10 OS.
+-->
+
+ <!-- A universally unique application identifier. Must be unique across all BlackBerry applications.
+ Using a reverse DNS-style name as the id is recommended. (Eg. com.example.ExampleApplication.) Required. -->
+ <id>com.godot.game</id>
+
+ <!-- The name that is displayed in the BlackBerry application installer.
+ May have multiple values for each language. See samples or xsd schema file. Optional. -->
+ <name>Godot Game</name>
+
+ <!-- A string value of the format <0-999>.<0-999>.<0-999> that represents application version which can be used to check for application upgrade.
+ Values can also be 1-part or 2-part. It is not necessary to have a 3-part value.
+ An updated version of application must have a versionNumber value higher than the previous version. Required. -->
+ <versionNumber>0.0.1</versionNumber>
+
+ <!-- Fourth digit segment of the package version. First three segments are taken from the
+ <versionNumber> element. Must be an integer from 0 to 2^16-1 -->
+ <buildId>0</buildId>
+
+ <!-- Description, displayed in the BlackBerry application installer.
+ May have multiple values for each language. See samples or xsd schema file. Optional. -->
+ <description>Game made with Godot Engine</description>
+
+ <!-- Name of author which is used for signing. Must match the developer name of your development certificate. -->
+ <author>You Name or Company</author>
+ <authorId>authorIDherePlease</authorId>
+
+ <!-- Unique author ID assigned by signing authority. Required if using debug tokens. -->
+ <!-- <authorId>ABC1234YjsnUk235h</authorId> -->
+
+ <initialWindow>
+ <aspectRatio>landscape</aspectRatio>
+ <autoOrients>false</autoOrients>
+ <systemChrome>none</systemChrome>
+ <transparent>false</transparent>
+ </initialWindow>
+
+ <!-- The category where the application appears. Either core.games or core.media. -->
+ <category>core.games</category>
+ <permission>read_device_identifying_information</permission>
+ <permission>access_internet</permission>
+ <asset path="assets">assets</asset>
+ <configuration name="Device-Debug">
+ <platformArchitecture>armle-v7</platformArchitecture>
+ <asset path="godot_bb10.qnx.armle" entry="true" type="Qnx/Elf">godot_bb10.qnx.armle</asset>
+ </configuration>
+ <configuration name="Device-Release">
+ <platformArchitecture>armle-v7</platformArchitecture>
+ <asset path="godot_bb10_opt.qnx.armle" entry="true" type="Qnx/Elf">godot_bb10_opt.qnx.armle</asset>
+ </configuration>
+ <!-- The icon for the application. -->
+ <icon>
+ <image>icon.png</image>
+ </icon>
+
+ <!-- Ensure that shared libraries in the package are found at run-time. -->
+ <env var="LD_LIBRARY_PATH" value="app/native/lib:/usr/lib/qt4/lib"/>
+
+</qnx>
diff --git a/platform/bb10/bar/icon.png b/platform/bb10/bar/icon.png
new file mode 100644
index 0000000000..a837c8009a
--- /dev/null
+++ b/platform/bb10/bar/icon.png
Binary files differ
diff --git a/platform/bb10/bbutil.c b/platform/bb10/bbutil.c
new file mode 100644
index 0000000000..fce52c5b81
--- /dev/null
+++ b/platform/bb10/bbutil.c
@@ -0,0 +1,513 @@
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/keycodes.h>
+#include <time.h>
+
+#include "bbutil.h"
+
+EGLDisplay egl_disp;
+EGLSurface egl_surf;
+
+static EGLConfig egl_conf;
+static EGLContext egl_ctx;
+
+static screen_context_t screen_ctx;
+static screen_window_t screen_win;
+static screen_display_t screen_disp;
+
+
+static void
+bbutil_egl_perror(const char *msg) {
+ static const char *errmsg[] = {
+ "function succeeded",
+ "EGL is not initialized, or could not be initialized, for the specified display",
+ "cannot access a requested resource",
+ "failed to allocate resources for the requested operation",
+ "an unrecognized attribute or attribute value was passed in an attribute list",
+ "an EGLConfig argument does not name a valid EGLConfig",
+ "an EGLContext argument does not name a valid EGLContext",
+ "the current surface of the calling thread is no longer valid",
+ "an EGLDisplay argument does not name a valid EGLDisplay",
+ "arguments are inconsistent",
+ "an EGLNativePixmapType argument does not refer to a valid native pixmap",
+ "an EGLNativeWindowType argument does not refer to a valid native window",
+ "one or more argument values are invalid",
+ "an EGLSurface argument does not name a valid surface configured for rendering",
+ "a power management event has occurred",
+ };
+
+ fprintf(stderr, "%s: %s\n", msg, errmsg[eglGetError() - EGL_SUCCESS]);
+}
+EGLConfig bbutil_choose_config(EGLDisplay egl_disp, enum RENDERING_API api) {
+ EGLConfig egl_conf = (EGLConfig)0;
+ EGLConfig *egl_configs;
+ EGLint egl_num_configs;
+ EGLint val;
+ EGLBoolean rc;
+ EGLint i;
+
+ rc = eglGetConfigs(egl_disp, NULL, 0, &egl_num_configs);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglGetConfigs");
+ return egl_conf;
+ }
+ if (egl_num_configs == 0) {
+ fprintf(stderr, "eglGetConfigs: could not find a configuration\n");
+ return egl_conf;
+ }
+
+ egl_configs = malloc(egl_num_configs * sizeof(*egl_configs));
+ if (egl_configs == NULL) {
+ fprintf(stderr, "could not allocate memory for %d EGL configs\n", egl_num_configs);
+ return egl_conf;
+ }
+
+ rc = eglGetConfigs(egl_disp, egl_configs,
+ egl_num_configs, &egl_num_configs);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglGetConfigs");
+ free(egl_configs);
+ return egl_conf;
+ }
+
+ for (i = 0; i < egl_num_configs; i++) {
+ eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_SURFACE_TYPE, &val);
+ if (!(val & EGL_WINDOW_BIT)) {
+ continue;
+ }
+
+ eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_RENDERABLE_TYPE, &val);
+ if (!(val & api)) {
+ continue;
+ }
+
+ eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_DEPTH_SIZE, &val);
+ if ((api & (GL_ES_1|GL_ES_2)) && (val == 0)) {
+ continue;
+ }
+
+ eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_RED_SIZE, &val);
+ if (val != 8) {
+ continue;
+ }
+ eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_GREEN_SIZE, &val);
+ if (val != 8) {
+ continue;
+ }
+
+ eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_BLUE_SIZE, &val);
+ if (val != 8) {
+ continue;
+ }
+
+ eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_BUFFER_SIZE, &val);
+ if (val != 32) {
+ continue;
+ }
+
+ egl_conf = egl_configs[i];
+ break;
+ }
+
+ free(egl_configs);
+
+ if (egl_conf == (EGLConfig)0) {
+ fprintf(stderr, "bbutil_choose_config: could not find a matching configuration\n");
+ }
+
+ return egl_conf;
+}
+
+int
+bbutil_init_egl(screen_context_t ctx, enum RENDERING_API api) {
+ int usage;
+ int format = SCREEN_FORMAT_RGBX8888;
+ int nbuffers = 2;
+ EGLint interval = 1;
+ int rc;
+ EGLint attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+
+ if (api == GL_ES_1) {
+ usage = SCREEN_USAGE_OPENGL_ES1 | SCREEN_USAGE_ROTATION;
+ } else if (api == GL_ES_2) {
+ usage = SCREEN_USAGE_OPENGL_ES2 | SCREEN_USAGE_ROTATION;
+ } else if (api == VG) {
+ usage = SCREEN_USAGE_OPENVG | SCREEN_USAGE_ROTATION;
+ } else {
+ fprintf(stderr, "invalid api setting\n");
+ return EXIT_FAILURE;
+ }
+
+ //Simple egl initialization
+ screen_ctx = ctx;
+
+ egl_disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (egl_disp == EGL_NO_DISPLAY) {
+ bbutil_egl_perror("eglGetDisplay");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = eglInitialize(egl_disp, NULL, NULL);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglInitialize");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ if ((api == GL_ES_1) || (api == GL_ES_2)) {
+ rc = eglBindAPI(EGL_OPENGL_ES_API);
+ } else if (api == VG) {
+ rc = eglBindAPI(EGL_OPENVG_API);
+ }
+
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglBindApi");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ egl_conf = bbutil_choose_config(egl_disp, api);
+ if (egl_conf == (EGLConfig)0) {
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ if (api == GL_ES_2) {
+ egl_ctx = eglCreateContext(egl_disp, egl_conf, EGL_NO_CONTEXT, attributes);
+ } else {
+ egl_ctx = eglCreateContext(egl_disp, egl_conf, EGL_NO_CONTEXT, NULL);
+ }
+
+ if (egl_ctx == EGL_NO_CONTEXT) {
+ bbutil_egl_perror("eglCreateContext");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_create_window(&screen_win, screen_ctx);
+ if (rc) {
+ perror("screen_create_window");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_FORMAT, &format);
+ if (rc) {
+ perror("screen_set_window_property_iv(SCREEN_PROPERTY_FORMAT)");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_USAGE, &usage);
+ if (rc) {
+ perror("screen_set_window_property_iv(SCREEN_PROPERTY_USAGE)");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_DISPLAY, (void **)&screen_disp);
+ if (rc) {
+ perror("screen_get_window_property_pv");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ int screen_resolution[2];
+
+ rc = screen_get_display_property_iv(screen_disp, SCREEN_PROPERTY_SIZE, screen_resolution);
+ if (rc) {
+ perror("screen_get_display_property_iv");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ int angle = atoi(getenv("ORIENTATION"));
+
+ screen_display_mode_t screen_mode;
+ rc = screen_get_display_property_pv(screen_disp, SCREEN_PROPERTY_MODE, (void**)&screen_mode);
+ if (rc) {
+ perror("screen_get_display_property_pv");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ int size[2];
+ rc = screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, size);
+ if (rc) {
+ perror("screen_get_window_property_iv");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ int buffer_size[2] = {size[0], size[1]};
+
+ if ((angle == 0) || (angle == 180)) {
+ if (((screen_mode.width > screen_mode.height) && (size[0] < size[1])) ||
+ ((screen_mode.width < screen_mode.height) && (size[0] > size[1]))) {
+ buffer_size[1] = size[0];
+ buffer_size[0] = size[1];
+ }
+ } else if ((angle == 90) || (angle == 270)){
+ if (((screen_mode.width > screen_mode.height) && (size[0] > size[1])) ||
+ ((screen_mode.width < screen_mode.height && size[0] < size[1]))) {
+ buffer_size[1] = size[0];
+ buffer_size[0] = size[1];
+ }
+ } else {
+ fprintf(stderr, "Navigator returned an unexpected orientation angle.\n");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, buffer_size);
+ if (rc) {
+ perror("screen_set_window_property_iv");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ROTATION, &angle);
+ if (rc) {
+ perror("screen_set_window_property_iv");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_create_window_buffers(screen_win, nbuffers);
+ if (rc) {
+ perror("screen_create_window_buffers");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_create_window_group(screen_win, get_window_group_id());
+ if (rc) {
+ perror("screen_create_window_group");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+ /* if (screen_create_window_group(screen_win, get_window_group_id()) != 0) goto fail; */
+
+ int idle_mode = SCREEN_IDLE_MODE_KEEP_AWAKE;
+ screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_IDLE_MODE, &idle_mode);
+
+ egl_surf = eglCreateWindowSurface(egl_disp, egl_conf, screen_win, NULL);
+ if (egl_surf == EGL_NO_SURFACE) {
+ bbutil_egl_perror("eglCreateWindowSurface");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = eglMakeCurrent(egl_disp, egl_surf, egl_surf, egl_ctx);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglMakeCurrent");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ rc = eglSwapInterval(egl_disp, interval);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglSwapInterval");
+ bbutil_terminate();
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+int
+bbutil_init_gl2d() {
+#if 0
+ EGLint surface_width, surface_height;
+
+ if ((egl_disp == EGL_NO_DISPLAY) || (egl_surf == EGL_NO_SURFACE) ){
+ return EXIT_FAILURE;
+ }
+
+ eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width);
+ eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height);
+
+ glShadeModel(GL_SMOOTH);
+
+ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+
+ glViewport(0, 0, surface_width, surface_height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ glOrthof(0.0f, (float)(surface_width) / (float)(surface_height), 0.0f, 1.0f, -1.0f, 1.0f);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+#endif
+
+ return EXIT_SUCCESS;
+}
+
+int
+bbutil_init(screen_context_t ctx, enum RENDERING_API api) {
+ if (EXIT_SUCCESS != bbutil_init_egl(ctx, api)) {
+ return EXIT_FAILURE;
+ }
+
+ if ((GL_ES_1 == api) && (EXIT_SUCCESS != bbutil_init_gl2d())) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+int bbutil_is_flipped() {
+
+ int ret;
+ screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_FLIP, &ret);
+ return ret;
+};
+
+int bbutil_get_rotation() {
+
+ int ret;
+ screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_ROTATION, &ret);
+ return ret;
+};
+
+
+void
+bbutil_terminate() {
+ //Typical EGL cleanup
+ if (egl_disp != EGL_NO_DISPLAY) {
+ eglMakeCurrent(egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (egl_surf != EGL_NO_SURFACE) {
+ eglDestroySurface(egl_disp, egl_surf);
+ egl_surf = EGL_NO_SURFACE;
+ }
+ if (egl_ctx != EGL_NO_CONTEXT) {
+ eglDestroyContext(egl_disp, egl_ctx);
+ egl_ctx = EGL_NO_CONTEXT;
+ }
+ if (screen_win != NULL) {
+ screen_destroy_window(screen_win);
+ screen_win = NULL;
+ }
+ eglTerminate(egl_disp);
+ egl_disp = EGL_NO_DISPLAY;
+ }
+ eglReleaseThread();
+}
+
+void
+bbutil_swap() {
+ int rc = eglSwapBuffers(egl_disp, egl_surf);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglSwapBuffers");
+ }
+}
+
+void
+bbutil_clear() {
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+char *
+get_window_group_id()
+{
+ static char s_window_group_id[16] = "";
+
+ if (s_window_group_id[0] == '\0') {
+ snprintf(s_window_group_id, sizeof(s_window_group_id), "%d", getpid());
+ }
+
+ return s_window_group_id;
+}
+
+
+int bbutil_rotate_screen_surface(int angle) {
+ int rc, rotation, skip = 1, temp;;
+ EGLint interval = 1;
+ int size[2];
+
+ if ((angle != 0) && (angle != 90) && (angle != 180) && (angle != 270)) {
+ fprintf(stderr, "Invalid angle\n");
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_ROTATION, &rotation);
+ if (rc) {
+ perror("screen_set_window_property_iv");
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, size);
+ if (rc) {
+ perror("screen_set_window_property_iv");
+ return EXIT_FAILURE;
+ }
+
+ switch (angle - rotation) {
+ case -270:
+ case -90:
+ case 90:
+ case 270:
+ temp = size[0];
+ size[0] = size[1];
+ size[1] = temp;
+ skip = 0;
+ break;
+ }
+
+ if (!skip) {
+ rc = eglMakeCurrent(egl_disp, NULL, NULL, NULL);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglMakeCurrent");
+ return EXIT_FAILURE;
+ }
+
+ rc = eglDestroySurface(egl_disp, egl_surf);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglMakeCurrent");
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_SOURCE_SIZE, size);
+ if (rc) {
+ perror("screen_set_window_property_iv");
+ return EXIT_FAILURE;
+ }
+
+ rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, size);
+ if (rc) {
+ perror("screen_set_window_property_iv");
+ return EXIT_FAILURE;
+ }
+ egl_surf = eglCreateWindowSurface(egl_disp, egl_conf, screen_win, NULL);
+ if (egl_surf == EGL_NO_SURFACE) {
+ bbutil_egl_perror("eglCreateWindowSurface");
+ return EXIT_FAILURE;
+ }
+
+ rc = eglMakeCurrent(egl_disp, egl_surf, egl_surf, egl_ctx);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglMakeCurrent");
+ return EXIT_FAILURE;
+ }
+
+ rc = eglSwapInterval(egl_disp, interval);
+ if (rc != EGL_TRUE) {
+ bbutil_egl_perror("eglSwapInterval");
+ return EXIT_FAILURE;
+ }
+ }
+
+ rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ROTATION, &angle);
+ if (rc) {
+ perror("screen_set_window_property_iv");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/platform/bb10/bbutil.h b/platform/bb10/bbutil.h
new file mode 100644
index 0000000000..8df513cb7d
--- /dev/null
+++ b/platform/bb10/bbutil.h
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* bbutil.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef _UTILITY_H_INCLUDED
+#define _UTILITY_H_INCLUDED
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <screen/screen.h>
+#include <sys/platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern EGLDisplay egl_disp;
+extern EGLSurface egl_surf;
+
+enum RENDERING_API {GL_ES_1 = EGL_OPENGL_ES_BIT, GL_ES_2 = EGL_OPENGL_ES2_BIT, VG = EGL_OPENVG_BIT};
+
+/**
+ * Initializes EGL, GL and loads a default font
+ *
+ * \param libscreen context that will be used for EGL setup
+ * \return EXIT_SUCCESS if initialization succeeded otherwise EXIT_FAILURE
+ */
+int bbutil_init(screen_context_t ctx, enum RENDERING_API api);
+
+/**
+ * Initializes EGL
+ *
+ * \param libscreen context that will be used for EGL setup
+ * \return EXIT_SUCCESS if initialization succeeded otherwise EXIT_FAILURE
+ */
+int bbutil_init_egl(screen_context_t ctx, enum RENDERING_API api);
+
+/**
+ * Initializes GL 1.1 for simple 2D rendering. GL2 initialization will be added at a later point.
+ *
+ * \return EXIT_SUCCESS if initialization succeeded otherwise EXIT_FAILURE
+ */
+int bbutil_init_gl2d();
+
+int bbutil_is_flipped();
+int bbutil_get_rotation();
+
+char *get_window_group_id();
+
+int bbutil_rotate_screen_surface(int angle);
+
+/**
+ * Terminates EGL
+ */
+void bbutil_terminate();
+
+/**
+ * Swaps default bbutil window surface to the screen
+ */
+void bbutil_swap();
+
+/**
+ * Clears the screen of any existing text.
+ * NOTE: must be called after a successful return from bbutil_init() or bbutil_init_egl() call
+ */
+void bbutil_clear();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/platform/bb10/detect.py b/platform/bb10/detect.py
new file mode 100644
index 0000000000..22940c0f2d
--- /dev/null
+++ b/platform/bb10/detect.py
@@ -0,0 +1,91 @@
+import os
+import sys
+import string
+import methods
+
+
+def is_active():
+ return True
+
+def get_name():
+ return "BlackBerry 10"
+
+def can_build():
+
+ import os
+ if (not os.environ.has_key("QNX_TARGET")):
+ return False
+ return True
+
+def get_opts():
+
+ return [
+ ('QNX_HOST', 'path to qnx host', os.environ.get("QNX_HOST", 0)),
+ ('QNX_TARGET', 'path to qnx target', os.environ.get("QNX_TARGET", 0)),
+ ('QNX_CONFIGURATION', 'path to qnx configuration', os.environ.get("QNX_CONFIGURATION", 0)),
+ ('qnx_target', 'Qnx target (armle or x86', 'armle'),
+ ('bb10_payment_service', 'Enable Payment Service for BlackBerry10', 'yes'),
+ ('bb10_lgles_override', 'Force legacy GLES (1.1) on iOS', 'no'),
+ ('bb10_exceptions', 'Use exceptions when compiling on bb10', 'no'),
+ ]
+
+def get_flags():
+
+ return [
+ ('lua', 'no'),
+ ('tools', 'no'),
+ ('nedmalloc', 'no'),
+ ]
+
+def configure(env):
+
+ if env['PLATFORM'] == 'win32':
+ env.Tool('mingw')
+ env['SPAWN'] = methods.win32_spawn
+
+ env['qnx_target_ver'] = env['qnx_target']
+ if env['qnx_target'] == "armle":
+ env['qnx_prefix'] = 'ntoarmv7'
+ env['qnx_target_ver'] = 'armle-v7'
+ else:
+ env['qnx_prefix'] = 'ntox86'
+
+ env['OBJSUFFIX'] = ".qnx.${qnx_target}.o"
+ env['LIBSUFFIX'] = ".qnx.${qnx_target}.a"
+ env['PROGSUFFIX'] = ".qnx.${qnx_target}"
+ print("PROGSUFFIX: "+env['PROGSUFFIX']+" target: "+env['qnx_target'])
+
+ env.PrependENVPath('PATH', env['QNX_CONFIGURATION'] + '/bin')
+ env.PrependENVPath('PATH', env['QNX_CONFIGURATION'] + '/usr/bin')
+ env['ENV']['QNX_HOST'] = env['QNX_HOST']
+ env['ENV']['QNX_TARGET'] = env['QNX_TARGET']
+ env['ENV']['QNX_CONFIGURATION'] = env['QNX_CONFIGURATION']
+
+ env['CC'] = '$qnx_prefix-gcc'
+ env['CXX'] = '$qnx_prefix-g++'
+ env['AR'] = '$qnx_prefix-ar'
+ env['RANLIB'] = '$qnx_prefix-ranlib'
+
+ env.Append(CPPPATH = ['#platform/bb10'])
+ env.Append(LIBPATH = ['#platform/bb10/lib/$qnx_target', '#platform/bb10/lib/$qnx_target_ver'])
+ env.Append(CCFLAGS = string.split('-DBB10_ENABLED -DUNIX_ENABLED -DGLES2_ENABLED -DGLES1_ENABLED -D_LITTLE_ENDIAN -DNO_THREADS -DNO_FCNTL'))
+ if env['bb10_exceptions']=="yes":
+ env.Append(CCFLAGS = ['-fexceptions'])
+ else:
+ env.Append(CCFLAGS = ['-fno-exceptions'])
+
+ #env.Append(LINKFLAGS = string.split()
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O3','-DRELEASE_BUILD'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-g', '-O0','-DDEBUG_ENABLED', '-D_DEBUG'])
+ env.Append(LINKFLAGS=['-g'])
+
+ env.Append(LIBS=['bps', 'pps', 'screen', 'socket', 'EGL', 'GLESv2', 'GLESv1_CM', 'm', 'asound'])
+
diff --git a/platform/bb10/export/export.cpp b/platform/bb10/export/export.cpp
new file mode 100644
index 0000000000..0a19e71f08
--- /dev/null
+++ b/platform/bb10/export/export.cpp
@@ -0,0 +1,805 @@
+#include "version.h"
+#include "export.h"
+#include "tools/editor/editor_settings.h"
+#include "tools/editor/editor_import_export.h"
+#include "tools/editor/editor_node.h"
+#include "io/zip_io.h"
+#include "io/marshalls.h"
+#include "globals.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "platform/bb10/logo.h"
+#include "io/xml_parser.h"
+
+#define MAX_DEVICES 5
+
+class EditorExportPlatformBB10 : public EditorExportPlatform {
+
+ OBJ_TYPE( EditorExportPlatformBB10,EditorExportPlatform );
+
+ String custom_package;
+
+ int version_code;
+ String version_name;
+ String package;
+ String name;
+ String category;
+ String description;
+ String author_name;
+ String author_id;
+ String icon;
+
+
+
+ struct Device {
+
+ int index;
+ String name;
+ String description;
+ };
+
+ Vector<Device> devices;
+ bool devices_changed;
+ Mutex *device_lock;
+ Thread *device_thread;
+ Ref<ImageTexture> logo;
+
+ volatile bool quit_request;
+
+
+ static void _device_poll_thread(void *ud);
+
+ void _fix_descriptor(Vector<uint8_t>& p_manifest);
+protected:
+
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+ virtual String get_name() const { return "BlackBerry 10"; }
+ virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_ETC1; }
+ virtual Ref<Texture> get_logo() const { return logo; }
+
+
+ virtual bool poll_devices();
+ virtual int get_device_count() const;
+ virtual String get_device_name(int p_device) const;
+ virtual String get_device_info(int p_device) const;
+ virtual Error run(int p_device);
+
+ virtual bool requieres_password(bool p_debug) const { return !p_debug; }
+ virtual String get_binary_extension() const { return "bar"; }
+ virtual Error export_project(const String& p_path,bool p_debug,const String& p_password="");
+
+ virtual bool can_export(String *r_error=NULL) const;
+
+ EditorExportPlatformBB10();
+ ~EditorExportPlatformBB10();
+};
+
+bool EditorExportPlatformBB10::_set(const StringName& p_name, const Variant& p_value) {
+
+ String n=p_name;
+
+ if (n=="version/code")
+ version_code=p_value;
+ else if (n=="version/name")
+ version_name=p_value;
+ else if (n=="package/unique_name")
+ package=p_value;
+ else if (n=="package/category")
+ category=p_value;
+ else if (n=="package/name")
+ name=p_value;
+ else if (n=="package/description")
+ description=p_value;
+ else if (n=="package/icon")
+ icon=p_value;
+ else if (n=="package/custom_template")
+ custom_package=p_value;
+ else if (n=="release/author")
+ author_name=p_value;
+ else if (n=="release/author_id")
+ author_id=p_value;
+ else
+ return false;
+
+ return true;
+}
+
+bool EditorExportPlatformBB10::_get(const StringName& p_name,Variant &r_ret) const{
+
+ String n=p_name;
+
+ if (n=="version/code")
+ r_ret=version_code;
+ else if (n=="version/name")
+ r_ret=version_name;
+ else if (n=="package/unique_name")
+ r_ret=package;
+ else if (n=="package/category")
+ r_ret=category;
+ else if (n=="package/name")
+ r_ret=name;
+ else if (n=="package/description")
+ r_ret=description;
+ else if (n=="package/icon")
+ r_ret=icon;
+ else if (n=="package/custom_template")
+ r_ret=custom_package;
+ else if (n=="release/author")
+ r_ret=author_name;
+ else if (n=="release/author_id")
+ r_ret=author_id;
+ else
+ return false;
+
+ return true;
+}
+void EditorExportPlatformBB10::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ p_list->push_back( PropertyInfo( Variant::INT, "version/code", PROPERTY_HINT_RANGE,"1,65535,1"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "version/name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/unique_name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/category") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/description",PROPERTY_HINT_MULTILINE_TEXT) );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/icon",PROPERTY_HINT_FILE,"png") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "package/custom_template", PROPERTY_HINT_FILE,"zip"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "release/author") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "release/author_id") );
+
+ //p_list->push_back( PropertyInfo( Variant::INT, "resources/pack_mode", PROPERTY_HINT_ENUM,"Copy,Single Exec.,Pack (.pck),Bundles (Optical)"));
+
+}
+
+void EditorExportPlatformBB10::_fix_descriptor(Vector<uint8_t>& p_descriptor) {
+
+ String fpath = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp_bar-settings.xml");
+ {
+ FileAccessRef f = FileAccess::open(fpath,FileAccess::WRITE);
+ f->store_buffer(p_descriptor.ptr(),p_descriptor.size());
+ }
+
+ Ref<XMLParser> parser = memnew( XMLParser );
+ Error err = parser->open(fpath);
+ ERR_FAIL_COND(err!=OK);
+
+ String txt;
+ err = parser->read();
+ Vector<String> depth;
+
+ while(err!=ERR_FILE_EOF) {
+
+ ERR_FAIL_COND(err!=OK);
+
+ switch(parser->get_node_type()) {
+
+ case XMLParser::NODE_NONE: {
+ print_line("???");
+ } break;
+ case XMLParser::NODE_ELEMENT: {
+ String e="<";
+ e+=parser->get_node_name();
+ for(int i=0;i<parser->get_attribute_count();i++) {
+ e+=" ";
+ e+=parser->get_attribute_name(i)+"=\"";
+ e+=parser->get_attribute_value(i)+"\" ";
+ }
+
+
+
+ if (parser->is_empty()) {
+ e+="/";
+ } else {
+ depth.push_back(parser->get_node_name());
+ }
+
+ e+=">";
+ txt+=e;
+
+ } break;
+ case XMLParser::NODE_ELEMENT_END: {
+
+ txt+="</"+parser->get_node_name()+">";
+ if (depth.size() && depth[depth.size()-1]==parser->get_node_name()) {
+ depth.resize(depth.size()-1);
+ }
+
+
+ } break;
+ case XMLParser::NODE_TEXT: {
+ if (depth.size()==2 && depth[0]=="qnx" && depth[1]=="id") {
+
+ txt+=package;
+ } else if (depth.size()==2 && depth[0]=="qnx" && depth[1]=="name") {
+
+ String aname;
+ if (this->name!="") {
+ aname=this->name;
+ } else {
+ aname = Globals::get_singleton()->get("application/name");
+
+ }
+
+ if (aname=="") {
+ aname=_MKSTR(VERSION_NAME);
+ }
+
+ txt+=aname;
+
+ } else if (depth.size()==2 && depth[0]=="qnx" && depth[1]=="versionNumber") {
+ txt+=itos(version_code);
+ } else if (depth.size()==2 && depth[0]=="qnx" && depth[1]=="description") {
+ txt+=description;
+ } else if (depth.size()==2 && depth[0]=="qnx" && depth[1]=="author") {
+ txt+=author_name;
+ } else if (depth.size()==2 && depth[0]=="qnx" && depth[1]=="authorId") {
+ txt+=author_id;
+ } else if (depth.size()==2 && depth[0]=="qnx" && depth[1]=="category") {
+ txt+=category;
+ } else {
+ txt+=parser->get_node_data();
+ }
+ } break;
+ case XMLParser::NODE_COMMENT: {
+ txt+="<!--"+parser->get_node_name()+"-->";
+ } break;
+ case XMLParser::NODE_CDATA: {
+ //ignore
+ //print_line("cdata");
+ } break;
+ case XMLParser::NODE_UNKNOWN: {
+ //ignore
+ txt+="<"+parser->get_node_name()+">";
+ } break;
+ }
+
+ err = parser->read();
+ }
+
+
+ CharString cs = txt.utf8();
+ p_descriptor.resize(cs.length());
+ for(int i=0;i<cs.length();i++)
+ p_descriptor[i]=cs[i];
+
+}
+
+
+
+Error EditorExportPlatformBB10::export_project(const String& p_path,bool p_debug,const String& p_password) {
+
+
+ EditorProgress ep("export","Exporting for BlackBerry 10",104);
+
+ String template_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+
+ String src_template=custom_package!=""?custom_package:template_path.plus_file("bb10.zip");
+
+
+ FileAccess *src_f=NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ ep.step("Creating FileSystem for BAR",0);
+
+ unzFile pkg = unzOpen2(src_template.utf8().get_data(), &io);
+ if (!pkg) {
+
+ EditorNode::add_io_error("Could not find template zip to export:\n"+src_template);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ da->change_dir(EditorSettings::get_singleton()->get_settings_path());
+
+
+ if (da->change_dir("tmp")!=OK) {
+ da->make_dir("tmp");
+ if (da->change_dir("tmp")!=OK)
+ return ERR_CANT_CREATE;
+ }
+
+ if (da->change_dir("bb10_export")!=OK) {
+ da->make_dir("bb10_export");
+ if (da->change_dir("bb10_export")!=OK) {
+ return ERR_CANT_CREATE;
+ }
+ }
+
+
+ String bar_dir = da->get_current_dir();
+ if (bar_dir.ends_with("/")) {
+ bar_dir=bar_dir.substr(0,bar_dir.length()-1);
+ }
+
+ //THIS IS SUPER, SUPER DANGEROUS!!!!
+ //CAREFUL WITH THIS CODE, MIGHT DELETE USERS HARD DRIVE OR HOME DIR
+ //EXTRA CHECKS ARE IN PLACE EVERYWERE TO MAKE SURE NOTHING BAD HAPPENS BUT STILL....
+ //BE SUPER CAREFUL WITH THIS PLEASE!!!
+ //BLACKBERRY THIS IS YOUR FAULT FOR NOT MAKING A BETTER WAY!!
+
+ if (bar_dir.ends_with("bb10_export")) {
+ Error err = da->erase_contents_recursive();
+ if (err!=OK) {
+ EditorNode::add_io_error("Can't ensure that dir is empty:\n"+bar_dir);
+ ERR_FAIL_COND_V(err!=OK,err);
+ }
+
+ } else {
+ print_line("ARE YOU CRAZY??? THIS IS A SERIOUS BUG HERE!!!");
+ ERR_FAIL_V(ERR_OMFG_THIS_IS_VERY_VERY_BAD);
+ }
+
+
+ ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(pkg);
+
+
+
+ while(ret==UNZ_OK) {
+
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0);
+
+ String file=fname;
+
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg,data.ptr(),data.size());
+ unzCloseCurrentFile(pkg);
+
+ //write
+
+ if (file=="bar-descriptor.xml") {
+
+ _fix_descriptor(data);
+ }
+
+ if (file=="icon.png") {
+ bool found=false;
+
+ if (this->icon!="" && this->icon.ends_with(".png")) {
+
+ FileAccess *f = FileAccess::open(this->icon,FileAccess::READ);
+ if (f) {
+
+ data.resize(f->get_len());
+ f->get_buffer(data.ptr(),data.size());
+ memdelete(f);
+ found=true;
+ }
+
+ }
+
+ if (!found) {
+
+ String appicon = Globals::get_singleton()->get("application/icon");
+ if (appicon!="" && appicon.ends_with(".png")) {
+ FileAccess*f = FileAccess::open(appicon,FileAccess::READ);
+ if (f) {
+ data.resize(f->get_len());
+ f->get_buffer(data.ptr(),data.size());
+ memdelete(f);
+ }
+ }
+ }
+ }
+
+
+ if (file.find("/")) {
+
+ da->make_dir_recursive(file.get_base_dir());
+ }
+
+ FileAccessRef wf = FileAccess::open(bar_dir.plus_file(file),FileAccess::WRITE);
+ wf->store_buffer(data.ptr(),data.size());
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+ ep.step("Finding Files..",1);
+
+ Vector<StringName> files=get_dependencies(false);
+
+ ep.step("Adding Files..",2);
+
+ da->change_dir(bar_dir);
+ da->make_dir("assets");
+ Error err = da->change_dir("assets");
+ ERR_FAIL_COND_V(err,err);
+
+ String asset_dir=da->get_current_dir();
+ if (!asset_dir.ends_with("/"))
+ asset_dir+="/";
+
+ for(int i=0;i<files.size();i++) {
+
+ String fname=files[i];
+ Vector<uint8_t> data = get_exported_file(fname);
+ /*
+ FileAccess *f=FileAccess::open(files[i],FileAccess::READ);
+ if (!f) {
+ EditorNode::add_io_error("Couldn't read: "+String(files[i]));
+ }
+ ERR_CONTINUE(!f);
+ data.resize(f->get_len());
+ f->get_buffer(data.ptr(),data.size());
+*/
+ String dst_path=fname;
+ dst_path=dst_path.replace_first("res://",asset_dir);
+
+ da->make_dir_recursive(dst_path.get_base_dir());
+
+ ep.step("Adding File: "+String(files[i]).get_file(),3+i*100/files.size());
+
+ FileAccessRef fr = FileAccess::open(dst_path,FileAccess::WRITE);
+ fr->store_buffer(data.ptr(),data.size());
+ }
+
+
+ ep.step("Creating BAR Package..",104);
+
+ String bb_packager=EditorSettings::get_singleton()->get("blackberry/host_tools");
+ bb_packager=bb_packager.plus_file("blackberry-nativepackager");
+ if (OS::get_singleton()->get_name()=="Windows")
+ bb_packager+=".exe";
+
+
+ if (!FileAccess::exists(bb_packager)) {
+ EditorNode::add_io_error("Can't find packager:\n"+bb_packager);
+ return ERR_CANT_OPEN;
+ }
+
+ List<String> args;
+ args.push_back("-package");
+ args.push_back(p_path);
+ if (p_debug) {
+
+ String debug_token=EditorSettings::get_singleton()->get("blackberry/debug_token");
+ if (!FileAccess::exists(debug_token)) {
+ EditorNode::add_io_error("Debug token not found!");
+ } else {
+ args.push_back("-debugToken");
+ args.push_back(debug_token);
+ }
+ args.push_back("-devMode");
+ args.push_back("-configuration");
+ args.push_back("Device-Debug");
+ } else {
+
+ args.push_back("-configuration");
+ args.push_back("Device-Release");
+ }
+ args.push_back(bar_dir.plus_file("bar-descriptor.xml"));
+
+ int ec;
+
+ err = OS::get_singleton()->execute(bb_packager,args,true,NULL,NULL,&ec);
+
+ if (err!=OK)
+ return err;
+ if (ec!=0)
+ return ERR_CANT_CREATE;
+
+ return OK;
+
+}
+
+
+bool EditorExportPlatformBB10::poll_devices() {
+
+ bool dc=devices_changed;
+ devices_changed=false;
+ return dc;
+}
+
+int EditorExportPlatformBB10::get_device_count() const {
+
+ device_lock->lock();
+ int dc=devices.size();
+ device_lock->unlock();
+
+ return dc;
+
+}
+String EditorExportPlatformBB10::get_device_name(int p_device) const {
+
+ ERR_FAIL_INDEX_V(p_device,devices.size(),"");
+ device_lock->lock();
+ String s=devices[p_device].name;
+ device_lock->unlock();
+ return s;
+}
+String EditorExportPlatformBB10::get_device_info(int p_device) const {
+
+ ERR_FAIL_INDEX_V(p_device,devices.size(),"");
+ device_lock->lock();
+ String s=devices[p_device].description;
+ device_lock->unlock();
+ return s;
+}
+
+void EditorExportPlatformBB10::_device_poll_thread(void *ud) {
+
+ EditorExportPlatformBB10 *ea=(EditorExportPlatformBB10 *)ud;
+
+ while(!ea->quit_request) {
+
+ String bb_deploy=EditorSettings::get_singleton()->get("blackberry/host_tools");
+ bb_deploy=bb_deploy.plus_file("blackberry-deploy");
+ bool windows = OS::get_singleton()->get_name()=="Windows";
+ if (windows)
+ bb_deploy+=".exe";
+
+ if (!FileAccess::exists(bb_deploy)) {
+ OS::get_singleton()->delay_usec(3000000);
+ continue; //adb not configured
+ }
+
+ Vector<Device> devices;
+
+
+ for (int i=0;i<MAX_DEVICES;i++) {
+
+ String host = EditorSettings::get_singleton()->get("blackberry/device_"+itos(i+1)+"/host");
+ if (host==String())
+ continue;
+ String pass = EditorSettings::get_singleton()->get("blackberry/device_"+itos(i+1)+"/password");
+ if (pass==String())
+ continue;
+
+ List<String> args;
+ args.push_back("-listDeviceInfo");
+ args.push_back(host);
+ args.push_back("-password");
+ args.push_back(pass);
+
+
+ int ec;
+ String dp;
+
+ Error err = OS::get_singleton()->execute(bb_deploy,args,true,NULL,&dp,&ec);
+
+ if (err==OK && ec==0) {
+
+ Device dev;
+ dev.index=i;
+ String descr;
+ Vector<String> ls=dp.split("\n");
+
+ for(int i=0;i<ls.size();i++) {
+
+ String l = ls[i].strip_edges();
+ if (l.begins_with("modelfullname::")) {
+ dev.name=l.get_slice("::",1);
+ descr+="Model: "+dev.name+"\n";
+ }
+ if (l.begins_with("modelnumber::")) {
+ String s = l.get_slice("::",1);
+ dev.name+=" ("+s+")";
+ descr+="Model Number: "+s+"\n";
+ }
+ if (l.begins_with("scmbundle::"))
+ descr+="OS Version: "+l.get_slice("::",1)+"\n";
+ if (l.begins_with("[n]debug_token_expiration::"))
+ descr+="Debug Token Expires:: "+l.get_slice("::",1)+"\n";
+
+ }
+
+ dev.description=descr;
+ devices.push_back(dev);
+ }
+
+ }
+
+ bool changed=false;
+
+
+ ea->device_lock->lock();
+
+ if (ea->devices.size()!=devices.size()) {
+ changed=true;
+ } else {
+
+ for(int i=0;i<ea->devices.size();i++) {
+
+ if (ea->devices[i].index!=devices[i].index) {
+ changed=true;
+ break;
+ }
+ }
+ }
+
+ if (changed) {
+
+ ea->devices=devices;
+ ea->devices_changed=true;
+ }
+
+ ea->device_lock->unlock();
+
+ OS::get_singleton()->delay_usec(3000000);
+
+ }
+
+}
+
+Error EditorExportPlatformBB10::run(int p_device) {
+
+ ERR_FAIL_INDEX_V(p_device,devices.size(),ERR_INVALID_PARAMETER);
+
+ String bb_deploy=EditorSettings::get_singleton()->get("blackberry/host_tools");
+ bb_deploy=bb_deploy.plus_file("blackberry-deploy");
+ if (OS::get_singleton()->get_name()=="Windows")
+ bb_deploy+=".exe";
+
+ if (!FileAccess::exists(bb_deploy)) {
+ EditorNode::add_io_error("Blackberry Deploy not found:\n"+bb_deploy);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+
+ device_lock->lock();
+
+
+ EditorProgress ep("run","Running on "+devices[p_device].name,3);
+
+ //export_temp
+ ep.step("Exporting APK",0);
+
+ String export_to=EditorSettings::get_singleton()->get_settings_path().plus_file("/tmp/tmpexport.bar");
+ Error err = export_project(export_to,true);
+ if (err) {
+ device_lock->unlock();
+ return err;
+ }
+#if 0
+ ep.step("Uninstalling..",1);
+
+ print_line("Uninstalling previous version: "+devices[p_device].name);
+ List<String> args;
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("uninstall");
+ args.push_back(package);
+ int rv;
+ err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
+
+ if (err || rv!=0) {
+ EditorNode::add_io_error("Could not install to device.");
+ device_lock->unlock();
+ return ERR_CANT_CREATE;
+ }
+
+ print_line("Installing into device (please wait..): "+devices[p_device].name);
+
+#endif
+ ep.step("Installing to Device (please wait..)..",2);
+
+ List<String> args;
+ args.clear();
+ args.push_back("-installApp");
+ args.push_back("-launchApp");
+ args.push_back("-device");
+ int idx = devices[p_device].index;
+ String host = EditorSettings::get_singleton()->get("blackberry/device_"+itos(p_device+1)+"/host");
+ String pass = EditorSettings::get_singleton()->get("blackberry/device_"+itos(p_device+1)+"/password");
+ args.push_back(host);
+ args.push_back("-password");
+ args.push_back(pass);
+ args.push_back(export_to);
+
+ int rv;
+ err = OS::get_singleton()->execute(bb_deploy,args,true,NULL,NULL,&rv);
+ if (err || rv!=0) {
+ EditorNode::add_io_error("Could not install to device.");
+ device_lock->unlock();
+ return ERR_CANT_CREATE;
+ }
+
+ device_lock->unlock();
+ return OK;
+
+
+}
+
+
+EditorExportPlatformBB10::EditorExportPlatformBB10() {
+
+ version_code=1;
+ version_name="1.0";
+ package="com.godot.noname";
+ category="core.games";
+ name="";
+ author_name="Cert. Name";
+ author_id="Cert. ID";
+ description="Game made with Godot Engine";
+
+ device_lock = Mutex::create();
+ quit_request=false;
+
+ device_thread=Thread::create(_device_poll_thread,this);
+ devices_changed=true;
+
+ Image img( _bb10_logo );
+ logo = Ref<ImageTexture>( memnew( ImageTexture ));
+ logo->create_from_image(img);
+}
+
+bool EditorExportPlatformBB10::can_export(String *r_error) const {
+
+ bool valid=true;
+ String bb_deploy=EditorSettings::get_singleton()->get("blackberry/host_tools");
+ String err;
+
+ if (!FileAccess::exists(bb_deploy.plus_file("blackberry-deploy"))) {
+
+ valid=false;
+ err+="Blackberry host tools not configured in editor settings.\n";
+ }
+
+ String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+
+ if (!FileAccess::exists(exe_path+"bb10.zip")) {
+ valid=false;
+ err+="No export template found.\nDownload and install export templates.\n";
+ }
+
+ String debug_token=EditorSettings::get_singleton()->get("blackberry/debug_token");
+
+ if (!FileAccess::exists(debug_token)) {
+ valid=false;
+ err+="No debug token set, will not be able to test on device.\n";
+ }
+
+
+ if (custom_package!="" && !FileAccess::exists(custom_package)) {
+ valid=false;
+ err+="Custom release package not found.\n";
+ }
+
+ if (r_error)
+ *r_error=err;
+
+ return valid;
+}
+
+
+EditorExportPlatformBB10::~EditorExportPlatformBB10() {
+
+ quit_request=true;
+ Thread::wait_to_finish(device_thread);
+}
+
+
+void register_bb10_exporter() {
+
+ EDITOR_DEF("blackberry/host_tools","");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"blackberry/host_tools",PROPERTY_HINT_GLOBAL_DIR));
+ EDITOR_DEF("blackberry/debug_token","");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"blackberry/debug_token",PROPERTY_HINT_GLOBAL_FILE,"bar"));
+ EDITOR_DEF("blackberry/device_1/host","");
+ EDITOR_DEF("blackberry/device_1/password","");
+ EDITOR_DEF("blackberry/device_2/host","");
+ EDITOR_DEF("blackberry/device_2/password","");
+ EDITOR_DEF("blackberry/device_3/host","");
+ EDITOR_DEF("blackberry/device_3/password","");
+ EDITOR_DEF("blackberry/device_4/host","");
+ EDITOR_DEF("blackberry/device_4/password","");
+ EDITOR_DEF("blackberry/device_5/host","");
+ EDITOR_DEF("blackberry/device_5/password","");
+
+ Ref<EditorExportPlatformBB10> exporter = Ref<EditorExportPlatformBB10>( memnew(EditorExportPlatformBB10) );
+ EditorImportExport::get_singleton()->add_export_platform(exporter);
+
+
+}
+
diff --git a/platform/bb10/export/export.h b/platform/bb10/export/export.h
new file mode 100644
index 0000000000..06c7a681be
--- /dev/null
+++ b/platform/bb10/export/export.h
@@ -0,0 +1,3 @@
+
+
+void register_bb10_exporter();
diff --git a/platform/bb10/godot_bb10.cpp b/platform/bb10/godot_bb10.cpp
new file mode 100644
index 0000000000..f7e154d647
--- /dev/null
+++ b/platform/bb10/godot_bb10.cpp
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* godot_bb10.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "main/main.h"
+#include "os_bb10.h"
+
+#include <unistd.h>
+
+int main(int argc, char* argv[]) {
+
+ OSBB10 os;
+
+ Error err = Main::setup(argv[0],argc-1,&argv[1]);
+ if (err!=OK)
+ return 255;
+
+ if (Main::start())
+ os.run(); // it is actually the OS that decides how to run
+ Main::cleanup();
+
+ return os.get_exit_code();
+}
+
diff --git a/platform/bb10/logo.png b/platform/bb10/logo.png
new file mode 100644
index 0000000000..d0fb1966ae
--- /dev/null
+++ b/platform/bb10/logo.png
Binary files differ
diff --git a/platform/bb10/os_bb10.cpp b/platform/bb10/os_bb10.cpp
new file mode 100644
index 0000000000..ff43a68b1d
--- /dev/null
+++ b/platform/bb10/os_bb10.cpp
@@ -0,0 +1,630 @@
+/*************************************************************************/
+/* os_bb10.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "os_bb10.h"
+
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "drivers/gles1/rasterizer_gles1.h"
+#include "servers/visual/visual_server_raster.h"
+#include "core/os/dir_access.h"
+
+#include "core/globals.h"
+#include "main/main.h"
+#include "bbutil.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <assert.h>
+#include "core/os/keyboard.h"
+
+#include "bps/bps.h"
+#include "bps/screen.h"
+#include "bps/navigator.h"
+#include "bps/accelerometer.h"
+#include "bps/orientation.h"
+#include "bps/virtualkeyboard.h"
+#include "bps/audiodevice.h"
+
+#ifdef BB10_SCORELOOP_ENABLED
+#include "modules/scoreloop/scoreloop_bb10.h"
+#endif
+
+static char launch_dir[512];
+char* launch_dir_ptr;
+
+int OSBB10::get_video_driver_count() const {
+
+ return 1;
+}
+const char * OSBB10::get_video_driver_name(int p_driver) const {
+
+ return "GLES2";
+}
+
+OS::VideoMode OSBB10::get_default_video_mode() const {
+
+ return OS::VideoMode();
+}
+
+int OSBB10::get_audio_driver_count() const {
+
+ return 1;
+}
+const char * OSBB10::get_audio_driver_name(int p_driver) const {
+
+ return "BB10";
+}
+
+void OSBB10::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ data_dir = getenv("HOME");
+
+ //Create a screen context that will be used to create an EGL surface to to receive libscreen events
+ screen_create_context(&screen_cxt,0);
+
+ //Initialize BPS library
+ bps_initialize();
+
+ //Use utility code to initialize EGL for 2D rendering with GL ES 1.1
+ enum RENDERING_API api = GL_ES_2;
+ #ifdef BB10_LGLES_OVERRIDE
+ api = GL_ES_1;
+ #endif
+ if (EXIT_SUCCESS != bbutil_init(screen_cxt, api)) {
+ bbutil_terminate();
+ screen_destroy_context(screen_cxt);
+ return;
+ };
+
+ EGLint surface_width, surface_height;
+
+ eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width);
+ eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height);
+ printf("screen size: %ix%i\n", surface_width, surface_height);
+ VideoMode mode;
+ mode.width = surface_width;
+ mode.height = surface_height;
+ mode.fullscreen = true;
+ mode.resizable = false;
+ set_video_mode(mode);
+
+ //Signal BPS library that navigator and screen events will be requested
+ screen_request_events(screen_cxt);
+ navigator_request_events(0);
+ virtualkeyboard_request_events(0);
+ audiodevice_request_events(0);
+
+ #ifdef DEBUG_ENABLED
+ bps_set_verbosity(3);
+ #endif
+
+ accel_supported = accelerometer_is_supported();
+ if (accel_supported)
+ accelerometer_set_update_frequency(FREQ_40_HZ);
+ pitch = 0;
+ roll = 0;
+
+ #ifdef BB10_LGLES_OVERRIDE
+ rasterizer = memnew( RasterizerGLES1(false) );
+ #else
+ rasterizer = memnew( RasterizerGLES2(false, false) );
+ #endif
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ visual_server->init();
+ visual_server->cursor_set_visible(false, 0);
+
+ audio_driver = memnew(AudioDriverBB10);
+ audio_driver->set_singleton();
+ audio_driver->init(NULL);
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+ audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+ audio_server->init();
+
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+ #ifdef PAYMENT_SERVICE_ENABLED
+ payment_service = memnew(PaymentService);
+ Globals::get_singleton()->add_singleton(Globals::Singleton("InAppStore", payment_service));
+ #endif
+
+}
+
+void OSBB10::set_main_loop( MainLoop * p_main_loop ) {
+
+ input->set_main_loop(p_main_loop);
+ main_loop=p_main_loop;
+}
+
+void OSBB10::delete_main_loop() {
+
+ memdelete( main_loop );
+ main_loop = NULL;
+}
+
+void OSBB10::finalize() {
+
+ if(main_loop)
+ memdelete(main_loop);
+ main_loop=NULL;
+
+ spatial_sound_server->finish();
+ memdelete(spatial_sound_server);
+ spatial_sound_2d_server->finish();
+ memdelete(spatial_sound_2d_server);
+
+ //if (debugger_connection_console) {
+// memdelete(debugger_connection_console);
+//}
+
+ audio_server->finish();
+ memdelete(audio_server);
+ memdelete(sample_manager);
+
+ visual_server->finish();
+ memdelete(visual_server);
+ memdelete(rasterizer);
+
+ physics_server->finish();
+ memdelete(physics_server);
+
+ physics_2d_server->finish();
+ memdelete(physics_2d_server);
+
+ #ifdef PAYMENT_SERVICE_ENABLED
+ memdelete(payment_service);
+ #endif
+
+ memdelete(input);
+
+ bbutil_terminate();
+ screen_destroy_context(screen_cxt);
+
+ bps_shutdown();
+}
+
+void OSBB10::set_mouse_show(bool p_show) {
+
+ //android has no mouse...
+}
+
+void OSBB10::set_mouse_grab(bool p_grab) {
+
+ //it really has no mouse...!
+}
+
+bool OSBB10::is_mouse_grab_enabled() const {
+
+ //*sigh* technology has evolved so much since i was a kid..
+ return false;
+}
+Point2 OSBB10::get_mouse_pos() const {
+
+ return Point2();
+}
+int OSBB10::get_mouse_button_state() const {
+
+ return 0;
+}
+void OSBB10::set_window_title(const String& p_title) {
+
+
+}
+
+//interesting byt not yet
+//void set_clipboard(const String& p_text);
+//String get_clipboard() const;
+
+void OSBB10::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+ default_videomode = p_video_mode;
+}
+
+OS::VideoMode OSBB10::get_video_mode(int p_screen) const {
+
+ return default_videomode;
+}
+void OSBB10::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+ p_list->push_back(default_videomode);
+}
+
+String OSBB10::get_name() {
+
+ return "BlackBerry 10";
+}
+
+MainLoop *OSBB10::get_main_loop() const {
+
+ return main_loop;
+}
+
+bool OSBB10::can_draw() const {
+
+ return !minimized;
+}
+
+void OSBB10::set_cursor_shape(CursorShape p_shape) {
+
+ //android really really really has no mouse.. how amazing..
+}
+
+void OSBB10::handle_screen_event(bps_event_t *event) {
+
+ screen_event_t screen_event = screen_event_get_event(event);
+
+ int screen_val;
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &screen_val);
+
+ int pos[2];
+
+ switch (screen_val) {
+ case SCREEN_EVENT_MTOUCH_TOUCH:
+ case SCREEN_EVENT_MTOUCH_RELEASE: {
+
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_POSITION, pos);
+
+ InputEvent ievent;
+ ievent.type = InputEvent::SCREEN_TOUCH;
+ ievent.ID = ++last_id;
+ ievent.device = 0;
+ ievent.screen_touch.pressed = (screen_val == SCREEN_EVENT_MTOUCH_TOUCH);
+ ievent.screen_touch.x = pos[0];
+ ievent.screen_touch.y = pos[1];
+ Point2 mpos(ievent.screen_touch.x, ievent.screen_touch.y);
+
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pos[0]);
+ ievent.screen_touch.index = pos[0];
+
+ last_touch_x[pos[0]] = ievent.screen_touch.x;
+ last_touch_y[pos[0]] = ievent.screen_touch.y;
+
+ input->parse_input_event( ievent );
+
+ if (ievent.screen_touch.index == 0) {
+
+ InputEvent ievent;
+ ievent.type = InputEvent::MOUSE_BUTTON;
+ ievent.ID = ++last_id;
+ ievent.device = 0;
+ ievent.mouse_button.pressed = (screen_val == SCREEN_EVENT_MTOUCH_TOUCH);
+ ievent.mouse_button.button_index = BUTTON_LEFT;
+ ievent.mouse_button.doubleclick = 0;
+ ievent.mouse_button.x = ievent.mouse_button.global_x = mpos.x;
+ ievent.mouse_button.y = ievent.mouse_button.global_y = mpos.y;
+ input->parse_input_event( ievent );
+ };
+
+
+ } break;
+ case SCREEN_EVENT_MTOUCH_MOVE: {
+
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_POSITION, pos);
+
+ InputEvent ievent;
+ ievent.type = InputEvent::SCREEN_DRAG;
+ ievent.ID = ++last_id;
+ ievent.device = 0;
+ ievent.screen_drag.x = pos[0];
+ ievent.screen_drag.y = pos[1];
+
+ /*
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION, pos);
+ ievent.screen_drag.relative_x = ievent.screen_drag.x - pos[0];
+ ievent.screen_drag.relative_y = ievent.screen_drag.y - pos[1];
+ */
+
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pos[0]);
+ ievent.screen_drag.index = pos[0];
+
+
+ ievent.screen_drag.relative_x = ievent.screen_drag.x - last_touch_x[ievent.screen_drag.index];
+ ievent.screen_drag.relative_y = ievent.screen_drag.y - last_touch_y[ievent.screen_drag.index];
+
+ last_touch_x[ievent.screen_drag.index] = ievent.screen_drag.x;
+ last_touch_y[ievent.screen_drag.index] = ievent.screen_drag.y;
+
+ Point2 mpos(ievent.screen_drag.x, ievent.screen_drag.y);
+ Point2 mrel(ievent.screen_drag.relative_x, ievent.screen_drag.relative_y);
+
+ input->parse_input_event( ievent );
+
+ if (ievent.screen_touch.index == 0) {
+
+ InputEvent ievent;
+ ievent.type = InputEvent::MOUSE_MOTION;
+ ievent.ID = ++last_id;
+ ievent.device = 0;
+ ievent.mouse_motion.x = ievent.mouse_motion.global_x = mpos.x;
+ ievent.mouse_motion.y = ievent.mouse_motion.global_y = mpos.y;
+ input->set_mouse_pos(Point2(ievent.mouse_motion.x,ievent.mouse_motion.y));
+ ievent.mouse_motion.speed_x=input->get_mouse_speed().x;
+ ievent.mouse_motion.speed_y=input->get_mouse_speed().y;
+ ievent.mouse_motion.relative_x = mrel.x;
+ ievent.mouse_motion.relative_y = mrel.y;
+ ievent.mouse_motion.button_mask = 1; // pressed
+
+ input->parse_input_event( ievent );
+ };
+ } break;
+
+ case SCREEN_EVENT_KEYBOARD: {
+
+ InputEvent ievent;
+ ievent.type = InputEvent::KEY;
+ ievent.ID = ++last_id;
+ ievent.device = 0;
+ int val = 0;
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SCAN, &val);
+ ievent.key.scancode = val;
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &val);
+ ievent.key.unicode = val;
+ if (val == 61448) {
+ ievent.key.scancode = KEY_BACKSPACE;
+ ievent.key.unicode = KEY_BACKSPACE;
+ };
+ if (val == 61453) {
+ ievent.key.scancode = KEY_ENTER;
+ ievent.key.unicode = KEY_ENTER;
+ };
+
+ int flags;
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
+ ievent.key.pressed = flags & 1; // bit 1 is pressed apparently
+
+ int mod;
+ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
+
+ input->parse_input_event( ievent );
+ } break;
+
+ default:
+ break;
+
+ }
+};
+
+void OSBB10::handle_accelerometer() {
+
+ if (!accel_supported)
+ return;
+
+ if (!fullscreen)
+ return;
+
+ double force_x, force_y, force_z;
+ accelerometer_read_forces(&force_x, &force_y, &force_z);
+ Vector3 accel = Vector3(force_x, flip_accelerometer ? force_y : -force_y, force_z);
+ input->set_accelerometer(accel);
+ // rotate 90 degrees
+ //input->set_accelerometer(Vector3(force_y, flip_accelerometer?force_x:(-force_x), force_z));
+};
+
+
+void OSBB10::_resize(bps_event_t* event) {
+
+ int angle = navigator_event_get_orientation_angle(event);
+ bbutil_rotate_screen_surface(angle);
+
+ EGLint surface_width, surface_height;
+ eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width);
+ eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height);
+
+ VideoMode mode;
+ mode.width = surface_width;
+ mode.height = surface_height;
+ mode.fullscreen = true;
+ mode.resizable = false;
+ set_video_mode(mode);
+};
+
+void OSBB10::process_events() {
+
+ handle_accelerometer();
+
+ bps_event_t *event = NULL;
+
+ do {
+ int rc = bps_get_event(&event, 0);
+ assert(rc == BPS_SUCCESS);
+
+ if (!event) break;
+
+ #ifdef BB10_SCORELOOP_ENABLED
+ ScoreloopBB10* sc = Globals::get_singleton()->get_singleton_object("Scoreloop")->cast_to<ScoreloopBB10>();
+ if (sc->handle_event(event))
+ continue;
+ #endif
+
+ #ifdef PAYMENT_SERVICE_ENABLED
+ if (payment_service->handle_event(event))
+ continue;
+ #endif
+
+ int domain = bps_event_get_domain(event);
+ if (domain == screen_get_domain()) {
+
+ handle_screen_event(event);
+
+ } else if (domain == navigator_get_domain()) {
+
+ if (NAVIGATOR_EXIT == bps_event_get_code(event)) {
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+ bps_event_destroy(event);
+ exit(0);
+ return;
+ /*
+ } else if (bps_event_get_code(event) == NAVIGATOR_ORIENTATION_CHECK) {
+
+ int angle = navigator_event_get_orientation_angle(event);
+ navigator_orientation_check_response(event, false);
+
+ } else if (bps_event_get_code(event) == NAVIGATOR_ORIENTATION) {
+
+ _resize(event);
+ */
+ } else if (bps_event_get_code(event) == NAVIGATOR_WINDOW_STATE) {
+
+ int state = navigator_event_get_window_state(event);
+ bool was_fullscreen = fullscreen;
+ minimized = state == NAVIGATOR_WINDOW_INVISIBLE;
+ fullscreen = state == NAVIGATOR_WINDOW_FULLSCREEN;
+ set_low_processor_usage_mode(!fullscreen);
+ if (fullscreen != was_fullscreen) {
+ if (fullscreen) {
+ audio_server->set_fx_global_volume_scale(fullscreen_mixer_volume);
+ audio_server->set_stream_global_volume_scale(fullscreen_stream_volume);
+ } else {
+ fullscreen_mixer_volume = audio_server->get_fx_global_volume_scale();
+ fullscreen_stream_volume = audio_server->get_stream_global_volume_scale();
+ audio_server->set_fx_global_volume_scale(0);
+ audio_server->set_stream_global_volume_scale(0);
+ };
+ };
+ };
+ } else if (domain == audiodevice_get_domain()) {
+
+ const char * audiodevice_path = audiodevice_event_get_path(event);
+ printf("************* got audiodevice event, path %s\n", audiodevice_path);
+ audio_driver->finish();
+ audio_driver->init(audiodevice_path);
+ audio_driver->start();
+ };
+
+ //bps_event_destroy(event);
+ } while (event);
+};
+
+bool OSBB10::has_virtual_keyboard() const {
+
+ return true;
+};
+
+void OSBB10::show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect) {
+
+ virtualkeyboard_show();
+};
+
+void OSBB10::hide_virtual_keyboard() {
+
+ virtualkeyboard_hide();
+};
+
+void OSBB10::run() {
+
+ if (!main_loop)
+ return;
+
+ main_loop->init();
+
+ int flip = bbutil_is_flipped();
+ int rot = bbutil_get_rotation();
+ flip_accelerometer = rot == 90;
+ printf("**************** rot is %i, flip %i\n", rot, (int)flip_accelerometer);
+ /*
+ orientation_direction_t orientation;
+ int angle;
+ orientation_get(&orientation, &angle);
+ printf("******************** orientation %i, %i, %i\n", orientation, ORIENTATION_BOTTOM_UP, ORIENTATION_TOP_UP);
+ if (orientation == ORIENTATION_BOTTOM_UP) {
+ flip_accelerometer = true;
+ };
+ */
+
+
+ while (true) {
+
+ process_events(); // get rid of pending events
+ if (Main::iteration()==true)
+ break;
+ bbutil_swap();
+ //#ifdef DEBUG_ENABLED
+ fflush(stdout);
+ //#endif
+ };
+
+ main_loop->finish();
+
+};
+
+bool OSBB10::has_touchscreen_ui_hint() const {
+
+ return true;
+}
+
+Error OSBB10::shell_open(String p_uri) {
+
+ char* msg = NULL;
+ int ret = navigator_invoke(p_uri.utf8().get_data(), &msg);
+
+ return ret == BPS_SUCCESS ? OK : FAILED;
+};
+
+String OSBB10::get_data_dir() const {
+
+ return data_dir;
+};
+
+
+OSBB10::OSBB10() {
+
+ main_loop=NULL;
+ last_id=1;
+ minimized = false;
+ fullscreen = true;
+ flip_accelerometer = true;
+ fullscreen_mixer_volume = 1;
+ fullscreen_stream_volume = 1;
+
+
+ printf("godot bb10!\n");
+ getcwd(launch_dir, sizeof(launch_dir));
+ printf("launch dir %s\n", launch_dir);
+ chdir("app/native/assets");
+ launch_dir_ptr = launch_dir;
+}
+
+OSBB10::~OSBB10() {
+
+
+}
+
diff --git a/platform/bb10/os_bb10.h b/platform/bb10/os_bb10.h
new file mode 100644
index 0000000000..28149c15b5
--- /dev/null
+++ b/platform/bb10/os_bb10.h
@@ -0,0 +1,157 @@
+/*************************************************************************/
+/* os_bb10.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef OS_BB10_H
+#define OS_BB10_H
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+#include "os/main_loop.h"
+#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/physics_2d/physics_2d_server_sw.h"
+#include "servers/visual/rasterizer.h"
+#include "audio_driver_bb10.h"
+#include "payment_service.h"
+
+#include <screen/screen.h>
+#include <sys/platform.h>
+#include "bps/event.h"
+
+#include <stdint.h>
+
+class OSBB10 : public OS_Unix {
+
+ unsigned int last_id;
+
+ screen_context_t screen_cxt;
+ float fullscreen_mixer_volume;
+ float fullscreen_stream_volume;
+
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+// AudioDriverPSP audio_driver_psp;
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+ AudioDriverBB10* audio_driver;
+
+#ifdef PAYMENT_SERVICE_ENABLED
+ PaymentService* payment_service;
+#endif
+
+ VideoMode default_videomode;
+ MainLoop * main_loop;
+
+ void process_events();
+
+ void _resize(bps_event_t *event);
+ void handle_screen_event(bps_event_t *event);
+ void handle_accelerometer();
+
+ int last_touch_x[16];
+ int last_touch_y[16];
+
+ bool accel_supported;
+ float pitch;
+ float roll;
+
+ bool minimized;
+ bool fullscreen;
+ bool flip_accelerometer;
+ String data_dir;
+
+ InputDefault *input;
+public:
+
+ // functions used by main to initialize/deintialize the OS
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual String get_data_dir() const;
+
+ virtual int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+
+ typedef int64_t ProcessID;
+
+ static OS* get_singleton();
+
+ virtual void set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ //virtual void set_clipboard(const String& p_text);
+ //virtual String get_clipboard() const;
+
+
+ virtual bool has_virtual_keyboard() const;
+ virtual void show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect);
+ virtual void hide_virtual_keyboard();
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ 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 String get_name();
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ virtual bool has_touchscreen_ui_hint() const;
+
+ virtual Error shell_open(String p_uri);
+
+ void run();
+
+ OSBB10();
+ ~OSBB10();
+
+};
+
+#endif
+
diff --git a/platform/bb10/payment_service.cpp b/platform/bb10/payment_service.cpp
new file mode 100644
index 0000000000..f6ffffd831
--- /dev/null
+++ b/platform/bb10/payment_service.cpp
@@ -0,0 +1,150 @@
+/*************************************************************************/
+/* payment_service.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef PAYMENT_SERVICE_ENABLED
+
+#include "payment_service.h"
+
+#include "bbutil.h"
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+extern char* launch_dir_ptr;
+
+void PaymentService::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("request_product_info"),&PaymentService::request_product_info);
+ ObjectTypeDB::bind_method(_MD("purchase"),&PaymentService::purchase);
+
+ ObjectTypeDB::bind_method(_MD("get_pending_event_count"),&PaymentService::get_pending_event_count);
+ ObjectTypeDB::bind_method(_MD("pop_pending_event"),&PaymentService::pop_pending_event);
+};
+
+Error PaymentService::request_product_info(Variant p_params) {
+
+ return ERR_UNAVAILABLE;
+};
+
+Error PaymentService::purchase(Variant p_params) {
+
+ Dictionary params = p_params;
+ ERR_FAIL_COND_V((!params.has("product_id")) && (!params.has("product_sku")), ERR_INVALID_PARAMETER);
+
+ char* id = NULL;
+ char* sku = NULL;
+
+ CharString p_id = params.has("product_id")?String(params["product_id"]).ascii():CharString();
+ CharString p_sku = params.has("product_sku")?String(params["product_sku"]).ascii():CharString();
+ unsigned int request_id;
+ chdir(launch_dir_ptr);
+ int ret = paymentservice_purchase_request(params.has("product_sku") ? NULL : p_id.get_data(),
+ params.has("product_sku") ? p_sku.get_data() : NULL,
+ NULL, NULL, NULL, NULL, get_window_group_id(), &request_id);
+ chdir("app/native");
+
+ if (ret != BPS_SUCCESS) {
+ int eret = errno;
+ printf("purchase error %i, %x, %i, %x\n", ret, ret, eret, eret);
+ ERR_FAIL_V((Error)eret);
+ return (Error)eret;
+ };
+ return OK;
+};
+
+
+bool PaymentService::handle_event(bps_event_t* p_event) {
+
+ if (bps_event_get_domain(p_event) != paymentservice_get_domain()) {
+ return false;
+ };
+
+ Dictionary dict;
+ int res = paymentservice_event_get_response_code(p_event);
+ if (res == SUCCESS_RESPONSE) {
+ dict["result"] = "ok";
+
+ res = bps_event_get_code(p_event);
+ if (res == PURCHASE_RESPONSE) {
+ dict["type"] = "purchase";
+ const char* pid = paymentservice_event_get_digital_good_id(p_event, 0);
+ dict["product_id"] = String(pid?pid:"");
+ };
+
+ } else {
+ const char* desc = paymentservice_event_get_error_text(p_event);
+ if (strcmp(desc, "alreadyPurchased") == 0) {
+ dict["result"] = "ok";
+ } else {
+ dict["result"] = "error";
+ dict["error_description"] = paymentservice_event_get_error_text(p_event);
+ dict["error_code"] = paymentservice_event_get_error_id(p_event);
+ printf("error code is %i\n", paymentservice_event_get_error_id(p_event));
+ printf("error description is %s\n", paymentservice_event_get_error_text(p_event));
+ };
+ dict["product_id"] = "";
+ };
+
+ res = bps_event_get_code(p_event);
+ if (res == PURCHASE_RESPONSE) {
+ dict["type"] = "purchase";
+ };
+
+ printf("********** adding event with result %ls\n", String(dict["result"]).c_str());
+ pending_events.push_back(dict);
+
+ return true;
+};
+
+int PaymentService::get_pending_event_count() {
+ return pending_events.size();
+};
+
+Variant PaymentService::pop_pending_event() {
+
+ Variant front = pending_events.front()->get();
+ pending_events.pop_front();
+
+ return front;
+};
+
+PaymentService::PaymentService() {
+
+ paymentservice_request_events(0);
+#ifdef DEBUG_ENABLED
+ paymentservice_set_connection_mode(true);
+#else
+ paymentservice_set_connection_mode(false);
+#endif
+};
+
+PaymentService::~PaymentService() {
+
+};
+
+
+#endif
diff --git a/platform/bb10/payment_service.h b/platform/bb10/payment_service.h
new file mode 100644
index 0000000000..09eda11d2e
--- /dev/null
+++ b/platform/bb10/payment_service.h
@@ -0,0 +1,69 @@
+/*************************************************************************/
+/* payment_service.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef PAYMENT_SERVICE_ENABLED
+
+#ifndef PAYMENT_SERVICE_H
+#define PAYMENT_SERVICE_H
+
+#include <bps/bps.h>
+#include <bps/event.h>
+#include <bps/paymentservice.h>
+
+#include "core/object.h"
+
+class PaymentService : public Object {
+
+ OBJ_TYPE(PaymentService, Object);
+
+ static void _bind_methods();
+
+ List<Variant> pending_events;
+
+public:
+
+ Error request_product_info(Variant p_params);
+ Error purchase(Variant p_params);
+
+ int get_pending_event_count();
+ Variant pop_pending_event();
+
+ bool handle_event(bps_event_t* p_event);
+
+ PaymentService();
+ ~PaymentService();
+};
+
+
+
+#endif
+
+
+#endif
+
+
diff --git a/platform/bb10/platform_config.h b/platform/bb10/platform_config.h
new file mode 100644
index 0000000000..38fc934ae4
--- /dev/null
+++ b/platform/bb10/platform_config.h
@@ -0,0 +1,29 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <alloca.h>
diff --git a/platform/iphone/Appirater.h b/platform/iphone/Appirater.h
new file mode 100644
index 0000000000..d11b2f7793
--- /dev/null
+++ b/platform/iphone/Appirater.h
@@ -0,0 +1,227 @@
+/*************************************************************************/
+/* Appirater.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+ This file is part of Appirater.
+
+ Copyright (c) 2010, Arash Payan
+ All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ */
+/*
+ * Appirater.h
+ * appirater
+ *
+ * Created by Arash Payan on 9/5/09.
+ * http://arashpayan.com
+ * Copyright 2010 Arash Payan. All rights reserved.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+extern NSString *const kAppiraterFirstUseDate;
+extern NSString *const kAppiraterUseCount;
+extern NSString *const kAppiraterSignificantEventCount;
+extern NSString *const kAppiraterCurrentVersion;
+extern NSString *const kAppiraterRatedCurrentVersion;
+extern NSString *const kAppiraterDeclinedToRate;
+
+/*
+ Place your Apple generated software id here.
+ */
+#define APPIRATER_APP_ID 301377083
+
+/*
+ Your app's name.
+ */
+#define APPIRATER_APP_NAME [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey]
+
+/*
+ This is the message your users will see once they've passed the day+launches
+ threshold.
+ */
+#define APPIRATER_MESSAGE [NSString stringWithFormat:@"If you enjoy using %@, would you mind taking a moment to rate it? It won't take more than a minute. Thanks for your support!", APPIRATER_APP_NAME]
+
+/*
+ This is the title of the message alert that users will see.
+ */
+#define APPIRATER_MESSAGE_TITLE [NSString stringWithFormat:@"Rate %@", APPIRATER_APP_NAME]
+
+/*
+ The text of the button that rejects reviewing the app.
+ */
+#define APPIRATER_CANCEL_BUTTON @"No, Thanks"
+
+/*
+ Text of button that will send user to app review page.
+ */
+#define APPIRATER_RATE_BUTTON [NSString stringWithFormat:@"Rate %@", APPIRATER_APP_NAME]
+
+/*
+ Text for button to remind the user to review later.
+ */
+#define APPIRATER_RATE_LATER @"Remind me later"
+
+/*
+ Users will need to have the same version of your app installed for this many
+ days before they will be prompted to rate it.
+ */
+#define APPIRATER_DAYS_UNTIL_PROMPT 30 // double
+
+/*
+ An example of a 'use' would be if the user launched the app. Bringing the app
+ into the foreground (on devices that support it) would also be considered
+ a 'use'. You tell Appirater about these events using the two methods:
+ [Appirater appLaunched:]
+ [Appirater appEnteredForeground:]
+
+ Users need to 'use' the same version of the app this many times before
+ before they will be prompted to rate it.
+ */
+#define APPIRATER_USES_UNTIL_PROMPT 20 // integer
+
+/*
+ A significant event can be anything you want to be in your app. In a
+ telephone app, a significant event might be placing or receiving a call.
+ In a game, it might be beating a level or a boss. This is just another
+ layer of filtering that can be used to make sure that only the most
+ loyal of your users are being prompted to rate you on the app store.
+ If you leave this at a value of -1, then this won't be a criteria
+ used for rating. To tell Appirater that the user has performed
+ a significant event, call the method:
+ [Appirater userDidSignificantEvent:];
+ */
+#define APPIRATER_SIG_EVENTS_UNTIL_PROMPT -1 // integer
+
+/*
+ Once the rating alert is presented to the user, they might select
+ 'Remind me later'. This value specifies how long (in days) Appirater
+ will wait before reminding them.
+ */
+#define APPIRATER_TIME_BEFORE_REMINDING 1 // double
+
+/*
+ 'YES' will show the Appirater alert everytime. Useful for testing how your message
+ looks and making sure the link to your app's review page works.
+ */
+#define APPIRATER_DEBUG NO
+
+@interface Appirater : NSObject <UIAlertViewDelegate> {
+
+ UIAlertView *ratingAlert;
+}
+
+@property(nonatomic, retain) UIAlertView *ratingAlert;
+
+/*
+ DEPRECATED: While still functional, it's better to use
+ appLaunched:(BOOL)canPromptForRating instead.
+
+ Calls [Appirater appLaunched:YES]. See appLaunched: for details of functionality.
+ */
++ (void)appLaunched:(int)p_app_id;
+
+/*
+ Tells Appirater that the app has launched, and on devices that do NOT
+ support multitasking, the 'uses' count will be incremented. You should
+ call this method at the end of your application delegate's
+ application:didFinishLaunchingWithOptions: method.
+
+ If the app has been used enough to be rated (and enough significant events),
+ you can suppress the rating alert
+ by passing NO for canPromptForRating. The rating alert will simply be postponed
+ until it is called again with YES for canPromptForRating. The rating alert
+ can also be triggered by appEnteredForeground: and userDidSignificantEvent:
+ (as long as you pass YES for canPromptForRating in those methods).
+ */
++ (void)appLaunched:(BOOL)canPromptForRating app_id:(int)p_app_id;
+
+/*
+ Tells Appirater that the app was brought to the foreground on multitasking
+ devices. You should call this method from the application delegate's
+ applicationWillEnterForeground: method.
+
+ If the app has been used enough to be rated (and enough significant events),
+ you can suppress the rating alert
+ by passing NO for canPromptForRating. The rating alert will simply be postponed
+ until it is called again with YES for canPromptForRating. The rating alert
+ can also be triggered by appLaunched: and userDidSignificantEvent:
+ (as long as you pass YES for canPromptForRating in those methods).
+ */
++ (void)appEnteredForeground:(BOOL)canPromptForRating;
+
+/*
+ Tells Appirater that the user performed a significant event. A significant
+ event is whatever you want it to be. If you're app is used to make VoIP
+ calls, then you might want to call this method whenever the user places
+ a call. If it's a game, you might want to call this whenever the user
+ beats a level boss.
+
+ If the user has performed enough significant events and used the app enough,
+ you can suppress the rating alert by passing NO for canPromptForRating. The
+ rating alert will simply be postponed until it is called again with YES for
+ canPromptForRating. The rating alert can also be triggered by appLaunched:
+ and appEnteredForeground: (as long as you pass YES for canPromptForRating
+ in those methods).
+ */
++ (void)userDidSignificantEvent:(BOOL)canPromptForRating;
+
+/*
+ Tells Appirater to open the App Store page where the user can specify a
+ rating for the app. Also records the fact that this has happened, so the
+ user won't be prompted again to rate the app.
+
+ The only case where you should call this directly is if your app has an
+ explicit "Rate this app" command somewhere. In all other cases, don't worry
+ about calling this -- instead, just call the other functions listed above,
+ and let Appirater handle the bookkeeping of deciding when to ask the user
+ whether to rate the app.
+ */
++ (void)rateApp;
+
+@end
diff --git a/platform/iphone/Appirater.m b/platform/iphone/Appirater.m
new file mode 100644
index 0000000000..d9144eda3e
--- /dev/null
+++ b/platform/iphone/Appirater.m
@@ -0,0 +1,383 @@
+#ifdef APPIRATER_ENABLED
+
+/*
+ This file is part of Appirater.
+
+ Copyright (c) 2010, Arash Payan
+ All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ */
+/*
+ * Appirater.m
+ * appirater
+ *
+ * Created by Arash Payan on 9/5/09.
+ * http://arashpayan.com
+ * Copyright 2010 Arash Payan. All rights reserved.
+ */
+
+#import "Appirater.h"
+#import <SystemConfiguration/SCNetworkReachability.h>
+#include <netinet/in.h>
+
+NSString *const kAppiraterFirstUseDate = @"kAppiraterFirstUseDate";
+NSString *const kAppiraterUseCount = @"kAppiraterUseCount";
+NSString *const kAppiraterSignificantEventCount = @"kAppiraterSignificantEventCount";
+NSString *const kAppiraterCurrentVersion = @"kAppiraterCurrentVersion";
+NSString *const kAppiraterRatedCurrentVersion = @"kAppiraterRatedCurrentVersion";
+NSString *const kAppiraterDeclinedToRate = @"kAppiraterDeclinedToRate";
+NSString *const kAppiraterReminderRequestDate = @"kAppiraterReminderRequestDate";
+
+NSString *templateReviewURL = @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APP_ID";
+
+static int app_id = 0;
+
+@interface Appirater (hidden)
+- (BOOL)connectedToNetwork;
++ (Appirater*)sharedInstance;
+- (void)showRatingAlert;
+- (BOOL)ratingConditionsHaveBeenMet;
+- (void)incrementUseCount;
+@end
+
+@implementation Appirater (hidden)
+
+- (BOOL)connectedToNetwork {
+ // Create zero addy
+ struct sockaddr_in zeroAddress;
+ bzero(&zeroAddress, sizeof(zeroAddress));
+ zeroAddress.sin_len = sizeof(zeroAddress);
+ zeroAddress.sin_family = AF_INET;
+
+ // Recover reachability flags
+ SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
+ SCNetworkReachabilityFlags flags;
+
+ BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
+ CFRelease(defaultRouteReachability);
+
+ if (!didRetrieveFlags)
+ {
+ NSLog(@"Error. Could not recover network reachability flags");
+ return NO;
+ }
+
+ BOOL isReachable = flags & kSCNetworkFlagsReachable;
+ BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
+ BOOL nonWiFi = flags & kSCNetworkReachabilityFlagsTransientConnection;
+
+ NSURL *testURL = [NSURL URLWithString:@"http://www.apple.com/"];
+ NSURLRequest *testRequest = [NSURLRequest requestWithURL:testURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0];
+ NSURLConnection *testConnection = [[NSURLConnection alloc] initWithRequest:testRequest delegate:self];
+
+ return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO;
+}
+
++ (Appirater*)sharedInstance {
+ static Appirater *appirater = nil;
+ if (appirater == nil)
+ {
+ @synchronized(self) {
+ if (appirater == nil) {
+ appirater = [[Appirater alloc] init];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive) name:@"UIApplicationWillResignActiveNotification" object:nil];
+ }
+ }
+ }
+
+ return appirater;
+}
+
+- (void)showRatingAlert {
+ UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:APPIRATER_MESSAGE_TITLE
+ message:APPIRATER_MESSAGE
+ delegate:self
+ cancelButtonTitle:APPIRATER_CANCEL_BUTTON
+ otherButtonTitles:APPIRATER_RATE_BUTTON, APPIRATER_RATE_LATER, nil] autorelease];
+ self.ratingAlert = alertView;
+ [alertView show];
+}
+
+- (BOOL)ratingConditionsHaveBeenMet {
+ if (APPIRATER_DEBUG)
+ return YES;
+
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+
+ NSDate *dateOfFirstLaunch = [NSDate dateWithTimeIntervalSince1970:[userDefaults doubleForKey:kAppiraterFirstUseDate]];
+ NSTimeInterval timeSinceFirstLaunch = [[NSDate date] timeIntervalSinceDate:dateOfFirstLaunch];
+ NSTimeInterval timeUntilRate = 60 * 60 * 24 * APPIRATER_DAYS_UNTIL_PROMPT;
+ if (timeSinceFirstLaunch < timeUntilRate)
+ return NO;
+
+ // check if the app has been used enough
+ int useCount = [userDefaults integerForKey:kAppiraterUseCount];
+ if (useCount <= APPIRATER_USES_UNTIL_PROMPT)
+ return NO;
+
+ // check if the user has done enough significant events
+ int sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount];
+ if (sigEventCount <= APPIRATER_SIG_EVENTS_UNTIL_PROMPT)
+ return NO;
+
+ // has the user previously declined to rate this version of the app?
+ if ([userDefaults boolForKey:kAppiraterDeclinedToRate])
+ return NO;
+
+ // has the user already rated the app?
+ if ([userDefaults boolForKey:kAppiraterRatedCurrentVersion])
+ return NO;
+
+ // if the user wanted to be reminded later, has enough time passed?
+ NSDate *reminderRequestDate = [NSDate dateWithTimeIntervalSince1970:[userDefaults doubleForKey:kAppiraterReminderRequestDate]];
+ NSTimeInterval timeSinceReminderRequest = [[NSDate date] timeIntervalSinceDate:reminderRequestDate];
+ NSTimeInterval timeUntilReminder = 60 * 60 * 24 * APPIRATER_TIME_BEFORE_REMINDING;
+ if (timeSinceReminderRequest < timeUntilReminder)
+ return NO;
+
+ return YES;
+}
+
+- (void)incrementUseCount {
+ // get the app's version
+ NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey];
+
+ // get the version number that we've been tracking
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+ NSString *trackingVersion = [userDefaults stringForKey:kAppiraterCurrentVersion];
+ if (trackingVersion == nil)
+ {
+ trackingVersion = version;
+ [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
+ }
+
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER Tracking version: %@", trackingVersion);
+
+ if ([trackingVersion isEqualToString:version])
+ {
+ // check if the first use date has been set. if not, set it.
+ NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterFirstUseDate];
+ if (timeInterval == 0)
+ {
+ timeInterval = [[NSDate date] timeIntervalSince1970];
+ [userDefaults setDouble:timeInterval forKey:kAppiraterFirstUseDate];
+ }
+
+ // increment the use count
+ int useCount = [userDefaults integerForKey:kAppiraterUseCount];
+ useCount++;
+ [userDefaults setInteger:useCount forKey:kAppiraterUseCount];
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER Use count: %d", useCount);
+ }
+ else
+ {
+ // it's a new version of the app, so restart tracking
+ [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
+ [userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterFirstUseDate];
+ [userDefaults setInteger:1 forKey:kAppiraterUseCount];
+ [userDefaults setInteger:0 forKey:kAppiraterSignificantEventCount];
+ [userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion];
+ [userDefaults setBool:NO forKey:kAppiraterDeclinedToRate];
+ [userDefaults setDouble:0 forKey:kAppiraterReminderRequestDate];
+ }
+
+ [userDefaults synchronize];
+}
+
+- (void)incrementSignificantEventCount {
+ // get the app's version
+ NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey];
+
+ // get the version number that we've been tracking
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+ NSString *trackingVersion = [userDefaults stringForKey:kAppiraterCurrentVersion];
+ if (trackingVersion == nil)
+ {
+ trackingVersion = version;
+ [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
+ }
+
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER Tracking version: %@", trackingVersion);
+
+ if ([trackingVersion isEqualToString:version])
+ {
+ // check if the first use date has been set. if not, set it.
+ NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterFirstUseDate];
+ if (timeInterval == 0)
+ {
+ timeInterval = [[NSDate date] timeIntervalSince1970];
+ [userDefaults setDouble:timeInterval forKey:kAppiraterFirstUseDate];
+ }
+
+ // increment the significant event count
+ int sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount];
+ sigEventCount++;
+ [userDefaults setInteger:sigEventCount forKey:kAppiraterSignificantEventCount];
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER Significant event count: %d", sigEventCount);
+ }
+ else
+ {
+ // it's a new version of the app, so restart tracking
+ [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
+ [userDefaults setDouble:0 forKey:kAppiraterFirstUseDate];
+ [userDefaults setInteger:0 forKey:kAppiraterUseCount];
+ [userDefaults setInteger:1 forKey:kAppiraterSignificantEventCount];
+ [userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion];
+ [userDefaults setBool:NO forKey:kAppiraterDeclinedToRate];
+ [userDefaults setDouble:0 forKey:kAppiraterReminderRequestDate];
+ }
+
+ [userDefaults synchronize];
+}
+
+@end
+
+
+@interface Appirater ()
+- (void)hideRatingAlert;
+@end
+
+@implementation Appirater
+
+@synthesize ratingAlert;
+
+- (void)incrementAndRate:(NSNumber*)_canPromptForRating {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [self incrementUseCount];
+
+ if ([_canPromptForRating boolValue] == YES &&
+ [self ratingConditionsHaveBeenMet] &&
+ [self connectedToNetwork])
+ {
+ [self performSelectorOnMainThread:@selector(showRatingAlert) withObject:nil waitUntilDone:NO];
+ }
+
+ [pool release];
+}
+
+- (void)incrementSignificantEventAndRate:(NSNumber*)_canPromptForRating {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [self incrementSignificantEventCount];
+
+ if ([_canPromptForRating boolValue] == YES &&
+ [self ratingConditionsHaveBeenMet] &&
+ [self connectedToNetwork])
+ {
+ [self performSelectorOnMainThread:@selector(showRatingAlert) withObject:nil waitUntilDone:NO];
+ }
+
+ [pool release];
+}
+
++ (void)appLaunched:(int)p_app_id {
+ app_id = p_app_id;
+ [Appirater appLaunched:YES];
+}
+
++ (void)appLaunched:(BOOL)canPromptForRating app_id:(int)p_app_id {
+ app_id = p_app_id;
+ NSNumber *_canPromptForRating = [[NSNumber alloc] initWithBool:canPromptForRating];
+ [NSThread detachNewThreadSelector:@selector(incrementAndRate:)
+ toTarget:[Appirater sharedInstance]
+ withObject:_canPromptForRating];
+ [_canPromptForRating release];
+}
+
+- (void)hideRatingAlert {
+ if (self.ratingAlert.visible) {
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER Hiding Alert");
+ [self.ratingAlert dismissWithClickedButtonIndex:-1 animated:NO];
+ }
+}
+
++ (void)appWillResignActive {
+ if (APPIRATER_DEBUG)
+ NSLog(@"APPIRATER appWillResignActive");
+ [[Appirater sharedInstance] hideRatingAlert];
+}
+
++ (void)appEnteredForeground:(BOOL)canPromptForRating {
+ NSNumber *_canPromptForRating = [[NSNumber alloc] initWithBool:canPromptForRating];
+ [NSThread detachNewThreadSelector:@selector(incrementAndRate:)
+ toTarget:[Appirater sharedInstance]
+ withObject:_canPromptForRating];
+ [_canPromptForRating release];
+}
+
++ (void)userDidSignificantEvent:(BOOL)canPromptForRating {
+ NSNumber *_canPromptForRating = [[NSNumber alloc] initWithBool:canPromptForRating];
+ [NSThread detachNewThreadSelector:@selector(incrementSignificantEventAndRate:)
+ toTarget:[Appirater sharedInstance]
+ withObject:_canPromptForRating];
+ [_canPromptForRating release];
+}
+
++ (void)rateApp {
+#if TARGET_IPHONE_SIMULATOR
+ NSLog(@"APPIRATER NOTE: iTunes App Store is not supported on the iOS simulator. Unable to open App Store page.");
+#else
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+ NSString *reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%d", app_id]];
+ [userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion];
+ [userDefaults synchronize];
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:reviewURL]];
+#endif
+}
+
+- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+
+ switch (buttonIndex) {
+ case 0:
+ {
+ // they don't want to rate it
+ [userDefaults setBool:YES forKey:kAppiraterDeclinedToRate];
+ [userDefaults synchronize];
+ break;
+ }
+ case 1:
+ {
+ // they want to rate it
+ [Appirater rateApp];
+ break;
+ }
+ case 2:
+ // remind them later
+ [userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterReminderRequestDate];
+ [userDefaults synchronize];
+ break;
+ default:
+ break;
+ }
+}
+
+@end
+
+#endif
diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub
new file mode 100644
index 0000000000..0113f75697
--- /dev/null
+++ b/platform/iphone/SCsub
@@ -0,0 +1,45 @@
+Import('env')
+
+iphone_lib = [
+
+ 'os_iphone.cpp',
+ #'rasterizer_iphone.cpp',
+ 'audio_driver_iphone.cpp',
+ 'sem_iphone.cpp',
+ 'gl_view.mm',
+ 'main.m',
+ 'app_delegate.mm',
+ 'view_controller.mm',
+ 'game_center.mm',
+ 'in_app_store.mm',
+ 'Appirater.m',
+]
+
+#env.Depends('#core/math/vector3.h', 'vector3_psp.h')
+
+#iphone_lib = env.Library('iphone', iphone_lib)
+
+env_ios = env.Clone();
+
+
+if env['ios_gles22_override'] == "yes":
+ env_ios.Append(CPPFLAGS=['-DGLES2_OVERRIDE'])
+
+if env['ios_GLES1_override'] == "yes":
+ env_ios.Append(CPPFLAGS=['-DGLES1_OVERRIDE'])
+
+if env['ios_appirater'] == "yes":
+ env_ios.Append(CPPFLAGS=['-DAPPIRATER_ENABLED'])
+
+
+obj = env_ios.Object('godot_iphone.cpp')
+
+prog = None
+if env["target"]=="release":
+ prog = env_ios.Program('#bin/godot_opt', [obj] + iphone_lib)
+ #action = "dsymutil "+File(prog)[0].path+" -o ../build/script_exec/build/Debug-iphoneos/script_exec.app.dSYM"
+ #env.AddPostAction(prog, action)
+else:
+ prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)
+ action = "dsymutil "+File(prog)[0].path+" -o bin/godot.iphone.dSYM"
+ env.AddPostAction(prog, action)
diff --git a/platform/iphone/app_delegate.h b/platform/iphone/app_delegate.h
new file mode 100644
index 0000000000..db641b1f78
--- /dev/null
+++ b/platform/iphone/app_delegate.h
@@ -0,0 +1,42 @@
+/*************************************************************************/
+/* app_delegate.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#import <UIKit/UIKit.h>
+#import "gl_view.h"
+#import "view_controller.h"
+
+@interface AppDelegate : NSObject <UIApplicationDelegate, UIAccelerometerDelegate, GLViewDelegate> {
+ UIWindow *window;
+ ViewController* view_controller;
+ UIAccelerationValue accel[3];
+ UIAccelerationValue last_accel[3];
+};
+
++ (ViewController*)getViewController;
+
+@end
diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm
new file mode 100644
index 0000000000..f80a855ef0
--- /dev/null
+++ b/platform/iphone/app_delegate.mm
@@ -0,0 +1,268 @@
+/*************************************************************************/
+/* app_delegate.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#import "app_delegate.h"
+#import "gl_view.h"
+
+#include "os_iphone.h"
+#include "core/globals.h"
+#include "main/main.h"
+
+#ifdef FACEBOOK_ENABLED
+#include "modules/FacebookScorer_ios/FacebookScorer.h"
+#endif
+
+#define kFilteringFactor 0.1
+#define kRenderingFrequency 30
+#define kAccelerometerFrequency 100.0 // Hz
+
+#ifdef APPIRATER_ENABLED
+#import "Appirater.h"
+#endif
+
+Error _shell_open(String p_uri) {
+ NSString* url = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()];
+
+ if (![[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:url]])
+ return ERR_CANT_OPEN;
+
+ printf("opening url %ls\n", p_uri.c_str());
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
+ [url release];
+ return OK;
+};
+
+@implementation AppDelegate
+
+extern int gargc;
+extern char** gargv;
+extern int iphone_main(int, int, int, char**);
+extern void iphone_finish();
+
+static ViewController* mainViewController = nil;
++ (ViewController*) getViewController
+{
+ return mainViewController;
+}
+
+static int frame_count = 0;
+- (void)drawView:(GLView*)view; {
+
+ switch (frame_count) {
+
+ case 0: {
+
+ int backingWidth;
+ int backingHeight;
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
+
+ iphone_main(backingWidth, backingHeight, gargc, gargv);
+
+ OS::VideoMode vm;
+ vm.fullscreen = true;
+ vm.width = backingWidth;
+ vm.height = backingHeight;
+ vm.resizable = false;
+ OS::get_singleton()->set_video_mode(vm);
+
+ if (!OS::get_singleton()) {
+ exit(0);
+ };
+ ++frame_count;
+
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *documentsDirectory = [paths objectAtIndex:0];
+ //NSString *documentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
+ OSIPhone::get_singleton()->set_data_dir(String::utf8([documentsDirectory UTF8String]));
+
+ NSString *locale_code = [[[NSLocale preferredLanguages] objectAtIndex:0] substringToIndex:2];
+ OSIPhone::get_singleton()->set_locale(String::utf8([locale_code UTF8String]));
+
+ NSString* uuid;
+ if ([[UIDevice currentDevice]respondsToSelector:@selector(identifierForVendor)]) {
+ uuid = [UIDevice currentDevice].identifierForVendor.UUIDString;
+ }else{
+ // return [UIDevice currentDevice]. uniqueIdentifier
+ uuid = [[UIDevice currentDevice] performSelector:@selector(uniqueIdentifier)];
+ }
+
+ OSIPhone::get_singleton()->set_unique_ID(String::utf8([uuid UTF8String]));
+
+ }; // break;
+/*
+ case 1: {
+ ++frame_count;
+ } break;
+*/
+ case 1: {
+
+ Main::setup2();
+ ++frame_count;
+
+ } break;
+/*
+ case 3: {
+ ++frame_count;
+ } break;
+*/
+ case 2: {
+
+ Main::start();
+ ++frame_count;
+
+ #ifdef APPIRATER_ENABLED
+ int aid = Globals::get_singleton()->get("ios/app_id");
+ [Appirater appLaunched:YES app_id:aid];
+ #endif
+
+ }; // break; fallthrough
+
+ default: {
+
+ if (OSIPhone::get_singleton()) {
+ OSIPhone::get_singleton()->update_accelerometer(accel[0], accel[1], accel[2]);
+ bool quit_request = OSIPhone::get_singleton()->iterate();
+ };
+
+ };
+
+ };
+};
+
+- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
+
+ printf("****************** did receive memory warning!\n");
+};
+
+- (void)applicationDidFinishLaunching:(UIApplication*)application {
+
+ printf("**************** app delegate init\n");
+ CGRect rect = [[UIScreen mainScreen] bounds];
+
+ application.statusBarHidden = YES;
+ // disable idle timer
+ application.idleTimerDisabled = YES;
+
+ //Create a full-screen window
+ window = [[UIWindow alloc] initWithFrame:rect];
+ //window.autoresizesSubviews = YES;
+ //[window setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth];
+
+ //Create the OpenGL ES view and add it to the window
+ GLView *glView = [[GLView alloc] initWithFrame:rect];
+ printf("glview is %p\n", glView);
+ //[window addSubview:glView];
+ glView.delegate = self;
+ //glView.autoresizesSubviews = YES;
+ //[glView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth];
+
+ view_controller = [[ViewController alloc] init];
+ view_controller.view = glView;
+ window.rootViewController = view_controller;
+
+ glView.animationInterval = 1.0 / kRenderingFrequency;
+ [glView startAnimation];
+
+ //Show the window
+ [window makeKeyAndVisible];
+
+ //Configure and start accelerometer
+ last_accel[0] = 0;
+ last_accel[1] = 0;
+ last_accel[2] = 0;
+ [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kAccelerometerFrequency)];
+ [[UIAccelerometer sharedAccelerometer] setDelegate:self];
+
+ //OSIPhone::screen_width = rect.size.width - rect.origin.x;
+ //OSIPhone::screen_height = rect.size.height - rect.origin.y;
+
+ mainViewController = view_controller;
+};
+
+- (void)applicationWillTerminate:(UIApplication*)application {
+
+ printf("********************* will terminate\n");
+ iphone_finish();
+};
+
+- (void)applicationDidEnterBackground:(UIApplication *)application
+{
+ printf("********************* did enter background\n");
+ [view_controller.view stopAnimation];
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application
+{
+ printf("********************* did enter foreground\n");
+ [view_controller.view startAnimation];
+}
+
+- (void) applicationWillResignActive:(UIApplication *)application
+{
+ printf("********************* will resign active\n");
+ [view_controller.view stopAnimation]; // FIXME: pause seems to be recommended elsewhere
+}
+
+- (void) applicationDidBecomeActive:(UIApplication *)application
+{
+ printf("********************* did become active\n");
+ [view_controller.view startAnimation]; // FIXME: resume seems to be recommended elsewhere
+}
+
+- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration {
+ //Use a basic low-pass filter to only keep the gravity in the accelerometer values
+ accel[0] = acceleration.x; // * kFilteringFactor + accel[0] * (1.0 - kFilteringFactor);
+ accel[1] = acceleration.y; // * kFilteringFactor + accel[1] * (1.0 - kFilteringFactor);
+ accel[2] = acceleration.z; // * kFilteringFactor + accel[2] * (1.0 - kFilteringFactor);
+}
+
+- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
+#ifdef FACEBOOK_ENABLED
+ return [[[FacebookScorer sharedInstance] facebook] handleOpenURL:url];
+#else
+ return false;
+#endif
+}
+
+// For 4.2+ support
+- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
+#ifdef FACEBOOK_ENABLED
+ return [[[FacebookScorer sharedInstance] facebook] handleOpenURL:url];
+#else
+ return false;
+#endif
+}
+
+- (void)dealloc
+{
+ [window release];
+ [super dealloc];
+}
+
+@end
diff --git a/platform/iphone/audio_driver_iphone.cpp b/platform/iphone/audio_driver_iphone.cpp
new file mode 100644
index 0000000000..d39b8f3c4d
--- /dev/null
+++ b/platform/iphone/audio_driver_iphone.cpp
@@ -0,0 +1,157 @@
+/*************************************************************************/
+/* audio_driver_iphone.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "audio_driver_iphone.h"
+
+Error AudioDriverIphone::init() {
+
+ active = false;
+ channels = 2;
+
+ AudioStreamBasicDescription strdesc;
+ strdesc.mFormatID = kAudioFormatLinearPCM;
+ strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
+ strdesc.mChannelsPerFrame = channels;
+ strdesc.mSampleRate = 44100;
+ strdesc.mFramesPerPacket = 1;
+ strdesc.mBitsPerChannel = 16;
+ strdesc.mBytesPerFrame =
+ strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
+ strdesc.mBytesPerPacket =
+ strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
+
+ OSStatus result = noErr;
+ AURenderCallbackStruct callback;
+ AudioComponentDescription desc;
+ AudioComponent comp = NULL;
+ const AudioUnitElement output_bus = 0;
+ const AudioUnitElement bus = output_bus;
+ const AudioUnitScope scope = kAudioUnitScope_Input;
+
+ zeromem(&desc, sizeof(desc));
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentSubType = kAudioUnitSubType_RemoteIO; /* !!! FIXME: ? */
+ comp = AudioComponentFindNext(NULL, &desc);
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+
+ result = AudioComponentInstanceNew(comp, &audio_unit);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+ ERR_FAIL_COND_V(comp == NULL, FAILED);
+
+ result = AudioUnitSetProperty(audio_unit,
+ kAudioUnitProperty_StreamFormat,
+ scope, bus, &strdesc, sizeof(strdesc));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ zeromem(&callback, sizeof(AURenderCallbackStruct));
+ callback.inputProc = &AudioDriverIphone::output_callback;
+ callback.inputProcRefCon = this;
+ result = AudioUnitSetProperty(audio_unit,
+ kAudioUnitProperty_SetRenderCallback,
+ scope, bus, &callback, sizeof(callback));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ result = AudioUnitInitialize(audio_unit);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ result = AudioOutputUnitStart(audio_unit);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ const int samples = 1024;
+ samples_in = memnew_arr(int32_t, samples); // whatever
+ buffer_frames = samples / channels;
+
+ return FAILED;
+};
+
+OSStatus AudioDriverIphone::output_callback(void *inRefCon,
+ AudioUnitRenderActionFlags * ioActionFlags,
+ const AudioTimeStamp * inTimeStamp,
+ UInt32 inBusNumber, UInt32 inNumberFrames,
+ AudioBufferList * ioData) {
+
+
+ AudioBuffer *abuf;
+ AudioDriverIphone* ad = (AudioDriverIphone*)inRefCon;
+
+ if (!ad->active) {
+ for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
+ abuf = &ioData->mBuffers[i];
+ zeromem(abuf->mData, abuf->mDataByteSize);
+ };
+ return 0;
+ };
+
+ int frames_left;
+
+ for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
+
+ abuf = &ioData->mBuffers[i];
+ frames_left = inNumberFrames;
+ int16_t* out = (int16_t*)abuf->mData;
+
+ while (frames_left) {
+
+ int frames = MIN(frames_left, ad->buffer_frames);
+ ad->lock();
+ ad->audio_server_process(frames, ad->samples_in);
+ ad->unlock();
+
+ for(int i = 0; i < frames * ad->channels; i++) {
+
+ out[i] = ad->samples_in[i]>>16;
+ }
+
+ frames_left -= frames;
+ out += frames * ad->channels;
+ };
+ };
+
+ return 0;
+};
+
+void AudioDriverIphone::start() {
+ active = true;
+};
+
+int AudioDriverIphone::get_mix_rate() const {
+ return 44100;
+};
+
+AudioDriverSW::OutputFormat AudioDriverIphone::get_output_format() const {
+ return OUTPUT_STEREO;
+};
+
+void AudioDriverIphone::lock() {};
+void AudioDriverIphone::unlock() {};
+
+void AudioDriverIphone::finish() {
+
+ memdelete_arr(samples_in);
+};
+
diff --git a/platform/iphone/audio_driver_iphone.h b/platform/iphone/audio_driver_iphone.h
new file mode 100644
index 0000000000..eec54d9ee3
--- /dev/null
+++ b/platform/iphone/audio_driver_iphone.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* audio_driver_iphone.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "servers/audio/audio_server_sw.h"
+
+#include <AudioUnit/AudioUnit.h>
+
+class AudioDriverIphone : public AudioDriverSW {
+
+ AudioComponentInstance audio_unit;
+ bool active;
+
+ int channels;
+ int32_t* samples_in;
+ int buffer_frames;
+
+ static OSStatus output_callback(void *inRefCon,
+ AudioUnitRenderActionFlags * ioActionFlags,
+ const AudioTimeStamp * inTimeStamp,
+ UInt32 inBusNumber, UInt32 inNumberFrames,
+ AudioBufferList * ioData);
+
+
+public:
+
+ const char* get_name() const {
+ return "IPhone";
+ };
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+};
+
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
new file mode 100644
index 0000000000..ed935839d8
--- /dev/null
+++ b/platform/iphone/detect.py
@@ -0,0 +1,130 @@
+import os
+import sys
+
+
+def is_active():
+ return True
+
+def get_name():
+ return "iOS"
+
+def can_build():
+
+ import sys
+ if sys.platform == 'darwin':
+ return True
+
+ return False
+
+def get_opts():
+
+ return [
+ ('IPHONEPLATFORM', 'name of the iphone platform', 'iPhoneOS'),
+ ('IPHONEPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'),
+ ('IPHONESDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/'),
+ ('game_center', 'Support for game center', 'yes'),
+ ('store_kit', 'Support for in-app store', 'yes'),
+ ('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
+ ('ios_GLES1_override', 'Force legacy GLES (1.1) on iOS', 'no'),
+ ('ios_appirater', 'Enable Appirater', 'no'),
+ ('ios_exceptions', 'Use exceptions when compiling on playbook', 'no'),
+ ]
+
+def get_flags():
+
+ return [
+ ('lua', 'no'),
+ ('tools', 'yes'),
+ ('nedmalloc', 'no'),
+ ('webp', 'yes'),
+ ('module_FacebookScorer_ios_enabled', 'no'),
+ ]
+
+
+
+def configure(env):
+
+ env.Append(CPPPATH=['#platform/iphone', '#platform/iphone/include'])
+
+ env['OBJSUFFIX'] = ".iphone.o"
+ env['LIBSUFFIX'] = ".iphone.a"
+ env['PROGSUFFIX'] = ".iphone"
+
+ env['ENV']['PATH'] = env['IPHONEPATH']+"/Developer/usr/bin/:"+env['ENV']['PATH']
+
+# env['CC'] = '$IPHONEPATH/Developer/usr/bin/gcc'
+# env['CXX'] = '$IPHONEPATH/Developer/usr/bin/g++'
+ env['CC'] = '$IPHONEPATH/usr/bin/clang'
+ env['CXX'] = '$IPHONEPATH/usr/bin/clang++'
+ env['AR'] = 'ar'
+
+ import string
+ #env['CCFLAGS'] = string.split('-arch armv7 -Wall -fno-strict-aliasing -fno-common -D__IPHONE_OS_VERSION_MIN_REQUIRED=20000 -isysroot $IPHONESDK -fvisibility=hidden -mmacosx-version-min=10.5 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\" -DNO_THUMB')
+ env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -isysroot $IPHONESDK')
+
+
+#/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ fno-objc-arc -arch armv7 -fmessage-length=0 -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -v -Os -ffast-math -DSTOREKIT_ENABLED -DIPHONE_ENABLED -DUNIX_ENABLED -DGLES2_ENABLED -DNO_THREADS -DMODULE_GRIDMAP_ENABLED -DMUSEPACK_ENABLED -DOLD_SCENE_FORMAT_ENABLED -DSQUIRREL_ENABLED -DVORBIS_ENABLED -DTHEORA_ENABLED -DPNG_ENABLED -DDDS_ENABLED -DPVR_ENABLED -DJPG_ENABLED -DSPEEX_ENABLED -DTOOLS_ENABLED -DGDSCRIPT_ENABLED -DMINIZIP_ENABLED -DXML_ENABLED -Icore -Icore/math -Itools -Idrivers -I. -Iplatform/iphone -Iplatform/iphone/include -Iplatform/iphone/scoreloop/SDKs -I/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenGLES.framework/Headers -Iscript/squirrel/src -Iscript/vorbis script/gdscript/gd_script.cpp
+#/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -x objective-c -arch armv7 -fmessage-length=0 -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -std=gnu99 -fobjc-arc -Wno-trigraphs -fpascal-strings -Os -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -iquote /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-generated-files.hmap -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-own-target-headers.hmap -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-all-target-headers.hmap -iquote /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-project-headers.hmap -I/Users/red/test2/build/Release-iphoneos/include -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/DerivedSources/armv7 -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/DerivedSources -F/Users/red/test2/build/Release-iphoneos -DNS_BLOCK_ASSERTIONS=1 -include /var/folders/LX/LXYXHTeSHSqbkhuPJRIsuE+++TI/-Caches-/com.apple.Xcode.501/SharedPrecompiledHeaders/test2-Prefix-dvdhnltoisfpmyalexovdrmfyeky/test2-Prefix.pch -MMD -MT dependencies -MF /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/Objects-normal/armv7/main.d -c /Users/red/test2/test2/main.m -o /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/Objects-normal/armv7/main.o
+
+
+
+
+
+ env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=4.3',
+ '-isysroot', '$IPHONESDK',
+ #'-mmacosx-version-min=10.5',
+ '-framework', 'Foundation',
+ '-framework', 'UIKit',
+ '-framework', 'CoreGraphics',
+ '-framework', 'OpenGLES',
+ '-framework', 'QuartzCore',
+ '-framework', 'CoreAudio',
+ '-framework', 'AudioToolbox',
+ '-framework', 'SystemConfiguration',
+ '-framework', 'Security',
+ '-framework', 'AdSupport',
+ ])
+
+ if env['game_center'] == 'yes':
+ env.Append(CPPFLAGS=['-fblocks', '-DGAME_CENTER_ENABLED'])
+ env.Append(LINKFLAGS=['-framework', 'GameKit'])
+
+ if env['store_kit'] == 'yes':
+ env.Append(CPPFLAGS=['-DSTOREKIT_ENABLED'])
+ env.Append(LINKFLAGS=['-framework', 'StoreKit'])
+
+ env.Append(CPPPATH = ['$IPHONESDK/usr/include', '$IPHONESDK/System/Library/Frameworks/OpenGLES.framework/Headers', '$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers'])
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-Os', '-ffast-math', '-DNS_BLOCK_ASSERTIONS=1','-Wall'])
+ env.Append(LINKFLAGS=['-Os', '-ffast-math'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-Wall', '-O0', '-DDEBUG_ENABLED'])
+ env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-g','-pg', '-Os', '-ffast-math'])
+ env.Append(LINKFLAGS=['-pg'])
+
+
+ env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate'
+ env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES1_ENABLED', '-DMPC_FIXED_POINT'])
+ if env['ios_exceptions'] == 'yes':
+ env.Append(CPPFLAGS=['-fexceptions'])
+ else:
+ env.Append(CPPFLAGS=['-fno-exceptions'])
+ #env['neon_enabled']=True
+ env['S_compiler'] = '$IPHONEPATH/Developer/usr/bin/gcc'
+
+ if env['lua'] == "yes":
+ env.Append(CCFLAGS=['-DLUA_USE_FLOAT'])
+
+
+# /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c-header -arch armv7s -fmessage-length=0 -std=gnu99 -fobjc-arc -Wno-trigraphs -fpascal-strings -Os -Wno-missing-field-initializers -Wno-missing-prototypes -Wreturn-type -Wno-implicit-atomic-properties -Wno-receiver-is-weak -Wduplicate-method-match -Wformat -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-shorten-64-to-32 -Wpointer-sign -Wno-newline-eof -Wno-selector -Wno-strict-selector-match -Wno-undeclared-selector -Wno-deprecated-implementations -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk -Wprotocol -Wdeprecated-declarations -g -fvisibility=hidden -Wno-sign-conversion "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -iquote /Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-generated-files.hmap -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-own-target-headers.hmap -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-all-target-headers.hmap -iquote /Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-project-headers.hmap -I/Users/lucasgondolo/test/build/Release-iphoneos/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/DerivedSources/armv7s -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/DerivedSources -F/Users/lucasgondolo/test/build/Release-iphoneos -DNS_BLOCK_ASSERTIONS=1 --serialize-diagnostics /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.dia -c /Users/lucasgondolo/test/test/test-Prefix.pch -o /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.pth -MMD -MT dependencies -MF /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.d
+
diff --git a/platform/iphone/game_center.h b/platform/iphone/game_center.h
new file mode 100644
index 0000000000..58a040eb6d
--- /dev/null
+++ b/platform/iphone/game_center.h
@@ -0,0 +1,68 @@
+/*************************************************************************/
+/* game_center.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef GAME_CENTER_ENABLED
+
+#ifndef GAME_CENTER_H
+#define GAME_CENTER_H
+
+#include "core/object.h"
+
+class GameCenter : public Object {
+
+ OBJ_TYPE(GameCenter, Object);
+
+ static GameCenter* instance;
+ static void _bind_methods();
+
+ List<Variant> pending_events;
+
+ bool connected;
+
+public:
+
+ Error connect();
+ bool is_connected();
+
+ Error post_score(Variant p_score);
+
+ Error award_achievement(Variant p_params);
+
+ int get_pending_event_count();
+ Variant pop_pending_event();
+
+ static GameCenter* get_singleton();
+
+ GameCenter();
+ ~GameCenter();
+};
+
+
+#endif
+
+#endif
diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm
new file mode 100644
index 0000000000..d517ddd105
--- /dev/null
+++ b/platform/iphone/game_center.mm
@@ -0,0 +1,163 @@
+/*************************************************************************/
+/* game_center.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef GAME_CENTER_ENABLED
+
+#include "game_center.h"
+
+extern "C" {
+#import <GameKit/GameKit.h>
+};
+
+GameCenter* GameCenter::instance = NULL;
+
+void GameCenter::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("connect"),&GameCenter::connect);
+ ObjectTypeDB::bind_method(_MD("is_connected"),&GameCenter::is_connected);
+
+ ObjectTypeDB::bind_method(_MD("post_score"),&GameCenter::post_score);
+ ObjectTypeDB::bind_method(_MD("award_achievement"),&GameCenter::award_achievement);
+
+ ObjectTypeDB::bind_method(_MD("get_pending_event_count"),&GameCenter::get_pending_event_count);
+ ObjectTypeDB::bind_method(_MD("pop_pending_event"),&GameCenter::pop_pending_event);
+};
+
+
+Error GameCenter::connect() {
+
+ GKLocalPlayer* player = [GKLocalPlayer localPlayer];
+ [player authenticateWithCompletionHandler:^(NSError* error) {
+
+ Dictionary ret;
+ ret["type"] = "authentication";
+ if (player.isAuthenticated) {
+ ret["result"] = "ok";
+ GameCenter::get_singleton()->connected = true;
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ ret["error_description"] = [error.localizedDescription UTF8String];
+ GameCenter::get_singleton()->connected = false;
+ };
+
+ pending_events.push_back(ret);
+ }];
+ return OK;
+};
+
+bool GameCenter::is_connected() {
+ return connected;
+};
+
+Error GameCenter::post_score(Variant p_score) {
+
+ Dictionary params = p_score;
+ ERR_FAIL_COND_V(!params.has("score") || !params.has("category"), ERR_INVALID_PARAMETER);
+ float score = params["score"];
+ String category = params["category"];
+
+ NSString* cat_str = [[[NSString alloc] initWithUTF8String:category.utf8().get_data()] autorelease];
+ GKScore* reporter = [[[GKScore alloc] initWithCategory:cat_str] autorelease];
+ reporter.value = score;
+
+ [reporter reportScoreWithCompletionHandler:^(NSError* error) {
+
+ Dictionary ret;
+ ret["type"] = "post_score";
+ if (error == nil) {
+ ret["result"] = "ok";
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ ret["error_description"] = [error.localizedDescription UTF8String];
+ };
+
+ pending_events.push_back(ret);
+ }];
+
+ return OK;
+};
+
+Error GameCenter::award_achievement(Variant p_params) {
+
+ Dictionary params = p_params;
+ ERR_FAIL_COND_V(!params.has("name") || !params.has("progress"), ERR_INVALID_PARAMETER);
+ String name = params["name"];
+ float progress = params["progress"];
+
+ NSString* name_str = [[[NSString alloc] initWithUTF8String:name.utf8().get_data()] autorelease];
+ GKAchievement* achievement = [[[GKAchievement alloc] initWithIdentifier: name_str] autorelease];
+ ERR_FAIL_COND_V(!achievement, FAILED);
+
+ achievement.percentComplete = progress;
+ [achievement reportAchievementWithCompletionHandler:^(NSError* error) {
+
+ Dictionary ret;
+ ret["type"] = "award_achievement";
+ if (error == nil) {
+ ret["result"] = "ok";
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ };
+
+ pending_events.push_back(ret);
+ }];
+
+ return OK;
+};
+
+int GameCenter::get_pending_event_count() {
+
+ return pending_events.size();
+};
+
+Variant GameCenter::pop_pending_event() {
+
+ Variant front = pending_events.front()->get();
+ pending_events.pop_front();
+
+ return front;
+};
+
+GameCenter* GameCenter::get_singleton() {
+ return instance;
+};
+
+GameCenter::GameCenter() {
+ ERR_FAIL_COND(instance != NULL);
+ instance = this;
+ connected = false;
+};
+
+
+GameCenter::~GameCenter() {
+
+};
+
+#endif
diff --git a/platform/iphone/gl_view.h b/platform/iphone/gl_view.h
new file mode 100755
index 0000000000..0d95af9ab1
--- /dev/null
+++ b/platform/iphone/gl_view.h
@@ -0,0 +1,100 @@
+/*************************************************************************/
+/* gl_view.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#import <UIKit/UIKit.h>
+#import <OpenGLES/EAGL.h>
+#import <OpenGLES/ES1/gl.h>
+#import <OpenGLES/ES1/glext.h>
+
+@protocol GLViewDelegate;
+
+@interface GLView : UIView<UIKeyInput>
+{
+ @private
+ // The pixel dimensions of the backbuffer
+ GLint backingWidth;
+ GLint backingHeight;
+
+ EAGLContext *context;
+
+ // OpenGL names for the renderbuffer and framebuffers used to render to this view
+ GLuint viewRenderbuffer, viewFramebuffer;
+
+ // OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist)
+ GLuint depthRenderbuffer;
+
+ // An animation timer that, when animation is started, will periodically call -drawView at the given rate.
+ NSTimer *animationTimer;
+ NSTimeInterval animationInterval;
+
+ // Delegate to do our drawing, called by -drawView, which can be called manually or via the animation timer.
+ id<GLViewDelegate> delegate;
+
+ // Flag to denote that the -setupView method of a delegate has been called.
+ // Resets to NO whenever the delegate changes.
+ BOOL delegateSetup;
+ BOOL active;
+ float screen_scale;
+}
+
+@property(nonatomic, assign) id<GLViewDelegate> delegate;
+
+-(void)startAnimation;
+-(void)stopAnimation;
+-(void)drawView;
+
+- (BOOL)canBecomeFirstResponder;
+
+- (void)open_keyboard;
+- (void)hide_keyboard;
+- (void)deleteBackward;
+- (BOOL)hasText;
+- (void)insertText:(NSString *)p_text;
+
+- (id)initGLES;
+- (BOOL)createFramebuffer;
+- (void)destroyFramebuffer;
+
+@property NSTimeInterval animationInterval;
+
+@end
+
+@protocol GLViewDelegate<NSObject>
+
+@required
+
+// Draw with OpenGL ES
+-(void)drawView:(GLView*)view;
+
+@optional
+
+// Called whenever you need to do some initialization before rendering.
+-(void)setupView:(GLView*)view;
+
+@end
diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm
new file mode 100755
index 0000000000..07f5b39fac
--- /dev/null
+++ b/platform/iphone/gl_view.mm
@@ -0,0 +1,457 @@
+/*************************************************************************/
+/* gl_view.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#import <QuartzCore/QuartzCore.h>
+#import <OpenGLES/EAGLDrawable.h>
+#include "os_iphone.h"
+#include "core/os/keyboard.h"
+
+#import "gl_view.h"
+
+/*
+@interface GLView (private)
+
+- (id)initGLES;
+- (BOOL)createFramebuffer;
+- (void)destroyFramebuffer;
+@end
+*/
+
+int gl_view_base_fb;
+static String keyboard_text;
+static GLView* _instance = NULL;
+
+void _show_keyboard(String p_existing) {
+ keyboard_text = p_existing;
+ printf("instance on show is %p\n", _instance);
+ [_instance open_keyboard];
+};
+
+void _hide_keyboard() {
+ printf("instance on hide is %p\n", _instance);
+ [_instance hide_keyboard];
+ keyboard_text = "";
+};
+
+@implementation GLView
+
+@synthesize animationInterval;
+
+static const int max_touches = 8;
+static UITouch* touches[max_touches];
+
+static void init_touches() {
+
+ for (int i=0; i<max_touches; i++) {
+ touches[i] = NULL;
+ };
+};
+
+static int get_touch_id(UITouch* p_touch) {
+
+ int first = -1;
+ for (int i=0; i<max_touches; i++) {
+ if (first == -1 && touches[i] == NULL) {
+ first = i;
+ continue;
+ };
+ if (touches[i] == p_touch)
+ return i;
+ };
+
+ if (first != -1) {
+ touches[first] = p_touch;
+ return first;
+ };
+
+ return -1;
+};
+
+static int remove_touch(UITouch* p_touch) {
+
+ int remaining = 0;
+ for (int i=0; i<max_touches; i++) {
+
+ if (touches[i] == NULL)
+ continue;
+ if (touches[i] == p_touch)
+ touches[i] = NULL;
+ else
+ ++remaining;
+ };
+ return remaining;
+};
+
+static int get_first_id(UITouch* p_touch) {
+
+ for (int i=0; i<max_touches; i++) {
+
+ if (touches[i] != NULL)
+ return i;
+ };
+ return -1;
+};
+
+static void clear_touches() {
+
+ for (int i=0; i<max_touches; i++) {
+
+ touches[i] = NULL;
+ };
+};
+
+// Implement this to override the default layer class (which is [CALayer class]).
+// We do this so that our view will be backed by a layer that is capable of OpenGL ES rendering.
++ (Class) layerClass
+{
+ return [CAEAGLLayer class];
+}
+
+//The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
+- (id)initWithCoder:(NSCoder*)coder
+{
+ active = FALSE;
+ if((self = [super initWithCoder:coder]))
+ {
+ self = [self initGLES];
+ }
+ return self;
+}
+
+-(id)initGLES
+{
+ // Get our backing layer
+ CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer;
+
+ // Configure it so that it is opaque, does not retain the contents of the backbuffer when displayed, and uses RGBA8888 color.
+ eaglLayer.opaque = YES;
+ eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking,
+ kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
+ nil];
+
+ // Create our EAGLContext, and if successful make it current and create our framebuffer.
+#ifdef GLES1_OVERRIDE
+ context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
+#else
+ context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+#endif
+
+ if(!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer])
+ {
+ [self release];
+ return nil;
+ }
+
+ // Default the animation interval to 1/60th of a second.
+ animationInterval = 1.0 / 60.0;
+ return self;
+}
+
+-(id<GLViewDelegate>)delegate
+{
+ return delegate;
+}
+
+// Update the delegate, and if it needs a -setupView: call, set our internal flag so that it will be called.
+-(void)setDelegate:(id<GLViewDelegate>)d
+{
+ delegate = d;
+ delegateSetup = ![delegate respondsToSelector:@selector(setupView:)];
+}
+
+// If our view is resized, we'll be asked to layout subviews.
+// This is the perfect opportunity to also update the framebuffer so that it is
+// the same size as our display area.
+-(void)layoutSubviews
+{
+ [EAGLContext setCurrentContext:context];
+ [self destroyFramebuffer];
+ [self createFramebuffer];
+ [self drawView];
+}
+
+- (BOOL)createFramebuffer
+{
+ // Generate IDs for a framebuffer object and a color renderbuffer
+ UIScreen* mainscr = [UIScreen mainScreen];
+ if (mainscr.currentMode.size.width == 640 || mainscr.currentMode.size.width == 960) // modern iphone, can go to 640x960
+ self.contentScaleFactor = 2.0;
+
+ glGenFramebuffersOES(1, &viewFramebuffer);
+ glGenRenderbuffersOES(1, &viewRenderbuffer);
+
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
+ // This call associates the storage for the current render buffer with the EAGLDrawable (our CAEAGLLayer)
+ // allowing us to draw into a buffer that will later be rendered to screen whereever the layer is (which corresponds with our view).
+ [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
+
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
+
+ // For this sample, we also need a depth buffer, so we'll create and attach one via another renderbuffer.
+ glGenRenderbuffersOES(1, &depthRenderbuffer);
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
+ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
+
+ if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
+ {
+ NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
+ return NO;
+ }
+
+ if (OS::get_singleton()) {
+ OS::VideoMode vm;
+ vm.fullscreen = true;
+ vm.width = backingWidth;
+ vm.height = backingHeight;
+ vm.resizable = false;
+ OS::get_singleton()->set_video_mode(vm);
+ OSIPhone::get_singleton()->set_base_framebuffer(viewFramebuffer);
+ };
+ gl_view_base_fb = viewFramebuffer;
+
+ return YES;
+}
+
+// Clean up any buffers we have allocated.
+- (void)destroyFramebuffer
+{
+ glDeleteFramebuffersOES(1, &viewFramebuffer);
+ viewFramebuffer = 0;
+ glDeleteRenderbuffersOES(1, &viewRenderbuffer);
+ viewRenderbuffer = 0;
+
+ if(depthRenderbuffer)
+ {
+ glDeleteRenderbuffersOES(1, &depthRenderbuffer);
+ depthRenderbuffer = 0;
+ }
+}
+
+- (void)startAnimation
+{
+ if (active)
+ return;
+ active = TRUE;
+ printf("start animation!\n");
+ animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
+}
+
+- (void)stopAnimation
+{
+ if (!active)
+ return;
+ active = FALSE;
+ printf("******** stop animation!\n");
+ [animationTimer invalidate];
+ animationTimer = nil;
+ clear_touches();
+}
+
+- (void)setAnimationInterval:(NSTimeInterval)interval
+{
+ animationInterval = interval;
+
+ if(animationTimer)
+ {
+ [self stopAnimation];
+ [self startAnimation];
+ }
+}
+
+// Updates the OpenGL view when the timer fires
+- (void)drawView
+{
+ if (!active) {
+ printf("draw view not active!\n");
+ return;
+ };
+
+ // Make sure that you are drawing to the current context
+ [EAGLContext setCurrentContext:context];
+
+ // If our drawing delegate needs to have the view setup, then call -setupView: and flag that it won't need to be called again.
+ if(!delegateSetup)
+ {
+ [delegate setupView:self];
+ delegateSetup = YES;
+ }
+
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
+
+ [delegate drawView:self];
+
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
+ [context presentRenderbuffer:GL_RENDERBUFFER_OES];
+
+ GLenum err = glGetError();
+ if(err)
+ NSLog(@"%x error", err);
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ NSArray* tlist = [[event allTouches] allObjects];
+ for (unsigned int i=0; i< [tlist count]; i++) {
+
+ if ( [touches containsObject:[tlist objectAtIndex:i]] ) {
+
+ UITouch* touch = [tlist objectAtIndex:i];
+ if (touch.phase != UITouchPhaseBegan)
+ continue;
+ int tid = get_touch_id(touch);
+ ERR_FAIL_COND(tid == -1);
+ CGPoint touchPoint = [touch locationInView:self];
+ OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1, tid == 0);
+ };
+ };
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
+{
+
+ NSArray* tlist = [[event allTouches] allObjects];
+ for (unsigned int i=0; i< [tlist count]; i++) {
+
+ if ( [touches containsObject:[tlist objectAtIndex:i]] ) {
+
+ UITouch* touch = [tlist objectAtIndex:i];
+ if (touch.phase != UITouchPhaseMoved)
+ continue;
+ int tid = get_touch_id(touch);
+ ERR_FAIL_COND(tid == -1);
+ int first = get_first_id(touch);
+ CGPoint touchPoint = [touch locationInView:self];
+ CGPoint prev_point = [touch previousLocationInView:self];
+ OSIPhone::get_singleton()->mouse_move(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, first == tid);
+ };
+ };
+
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ NSArray* tlist = [[event allTouches] allObjects];
+ for (unsigned int i=0; i< [tlist count]; i++) {
+
+ if ( [touches containsObject:[tlist objectAtIndex:i]] ) {
+
+ UITouch* touch = [tlist objectAtIndex:i];
+ if (touch.phase != UITouchPhaseEnded)
+ continue;
+ int tid = get_touch_id(touch);
+ ERR_FAIL_COND(tid == -1);
+ int rem = remove_touch(touch);
+ CGPoint touchPoint = [touch locationInView:self];
+ OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false, rem == 0);
+ };
+ };
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
+
+ OSIPhone::get_singleton()->touches_cancelled();
+ clear_touches();
+};
+
+- (BOOL)canBecomeFirstResponder {
+ return YES;
+};
+
+
+- (void)open_keyboard {
+ //keyboard_text = p_existing;
+ [self becomeFirstResponder];
+};
+
+- (void)hide_keyboard {
+ //keyboard_text = p_existing;
+ [self resignFirstResponder];
+};
+
+- (void)deleteBackward {
+ if (keyboard_text.length())
+ keyboard_text.erase(keyboard_text.length() - 1, 1);
+ OSIPhone::get_singleton()->key(KEY_BACKSPACE, true);
+};
+
+- (BOOL)hasText {
+ return keyboard_text.length() ? YES : NO;
+};
+
+- (void)insertText:(NSString *)p_text {
+ String character;
+ character.parse_utf8([p_text UTF8String]);
+ keyboard_text = keyboard_text + character;
+ OSIPhone::get_singleton()->key(character[0] == 10 ? KEY_ENTER : character[0] , true);
+ printf("inserting text with character %i\n", character[0]);
+};
+
+
+// When created via code however, we get initWithFrame
+-(id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+ _instance = self;
+ printf("after init super %p\n", self);
+ if(self != nil)
+ {
+ self = [self initGLES];
+ printf("after init gles %p\n", self);
+ }
+ init_touches();
+ self. multipleTouchEnabled = YES;
+
+ //self.autoresizesSubviews = YES;
+ //[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth];
+
+ return self;
+}
+
+// Stop animating and release resources when they are no longer needed.
+- (void)dealloc
+{
+ [self stopAnimation];
+
+ if([EAGLContext currentContext] == context)
+ {
+ [EAGLContext setCurrentContext:nil];
+ }
+
+ [context release];
+ context = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/platform/iphone/globals/global_defaults.cpp b/platform/iphone/globals/global_defaults.cpp
new file mode 100644
index 0000000000..63463ab366
--- /dev/null
+++ b/platform/iphone/globals/global_defaults.cpp
@@ -0,0 +1,11 @@
+
+#include "global_defaults.h"
+#include "globals.h"
+
+
+void register_iphone_global_defaults() {
+
+ GLOBAL_DEF("rasterizer.iOS/use_fragment_lighting",false);
+ GLOBAL_DEF("display.iOS/driver","GLES2");
+ Globals::get_singleton()->set_custom_property_info("display.iOS/driver",PropertyInfo(Variant::STRING,"display.iOS/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2"));
+}
diff --git a/platform/iphone/globals/global_defaults.h b/platform/iphone/globals/global_defaults.h
new file mode 100644
index 0000000000..25f1ae687e
--- /dev/null
+++ b/platform/iphone/globals/global_defaults.h
@@ -0,0 +1,3 @@
+
+
+void register_iphone_global_defaults(); \ No newline at end of file
diff --git a/platform/iphone/godot_iphone.cpp b/platform/iphone/godot_iphone.cpp
new file mode 100644
index 0000000000..eb3f17736a
--- /dev/null
+++ b/platform/iphone/godot_iphone.cpp
@@ -0,0 +1,86 @@
+/*************************************************************************/
+/* godot_iphone.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "os_iphone.h"
+#include "main/main.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+static OSIPhone* os = NULL;
+
+extern "C" {
+int add_path(int p_argc, char** p_args);
+};
+
+int iphone_main(int width, int height, int argc, char** argv) {
+
+ int len = strlen(argv[0]);
+
+ while (len--){
+ if (argv[0][len] == '/') break;
+ }
+
+ if (len>=0) {
+ char path[512];
+ memcpy(path, argv[0], len>sizeof(path)?sizeof(path):len);
+ path[len]=0;
+ printf("Path: %s\n", path);
+ chdir(path);
+ }
+
+ printf("godot_iphone %s\n", argv[0]);
+ char cwd[512];
+ getcwd(cwd, sizeof(cwd));
+ printf("cwd %s\n", cwd);
+ os = new OSIPhone(width, height);
+
+ char* fargv[64];
+ for (int i=0; i<argc; i++) {
+ fargv[i] = argv[i];
+ };
+ fargv[argc] = NULL;
+ argc = add_path(argc, fargv);
+
+ printf("os created\n");
+ Error err = Main::setup(fargv[0], argc - 1, &fargv[1], false);
+ printf("setup %i\n", err);
+ if (err!=OK)
+ return 255;
+
+ return 0;
+};
+
+
+void iphone_finish() {
+
+ printf("iphone_finish\n");
+ Main::cleanup();
+ delete os;
+};
diff --git a/platform/iphone/in_app_store.h b/platform/iphone/in_app_store.h
new file mode 100644
index 0000000000..dba1a1a5a1
--- /dev/null
+++ b/platform/iphone/in_app_store.h
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* in_app_store.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef STOREKIT_ENABLED
+
+#ifndef IN_APP_STORE_H
+#define IN_APP_STORE_H
+
+#include "core/object.h"
+
+class InAppStore : public Object {
+
+ OBJ_TYPE(InAppStore, Object);
+
+ static InAppStore* instance;
+ static void _bind_methods();
+
+ List<Variant> pending_events;
+
+public:
+
+ Error request_product_info(Variant p_params);
+ Error purchase(Variant p_params);
+
+ int get_pending_event_count();
+ Variant pop_pending_event();
+
+ void _post_event(Variant p_event);
+ void _record_purchase(String product_id);
+
+ static InAppStore* get_singleton();
+
+ InAppStore();
+ ~InAppStore();
+};
+
+#endif
+
+
+#endif
+
diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm
new file mode 100644
index 0000000000..316e619e11
--- /dev/null
+++ b/platform/iphone/in_app_store.mm
@@ -0,0 +1,264 @@
+/*************************************************************************/
+/* in_app_store.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef STOREKIT_ENABLED
+
+#include "in_app_store.h"
+
+extern "C" {
+#import <StoreKit/StoreKit.h>
+};
+
+@interface SKProduct (LocalizedPrice)
+@property (nonatomic, readonly) NSString *localizedPrice;
+@end
+
+//----------------------------------//
+// SKProduct extension
+//----------------------------------//
+@implementation SKProduct (LocalizedPrice)
+- (NSString *)localizedPrice
+{
+ NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
+ [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
+ [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
+ [numberFormatter setLocale:self.priceLocale];
+ NSString *formattedString = [numberFormatter stringFromNumber:self.price];
+ [numberFormatter release];
+ return formattedString;
+}
+@end
+
+
+InAppStore* InAppStore::instance = NULL;
+
+void InAppStore::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("request_product_info"),&InAppStore::request_product_info);
+ ObjectTypeDB::bind_method(_MD("purchase"),&InAppStore::purchase);
+
+ ObjectTypeDB::bind_method(_MD("get_pending_event_count"),&InAppStore::get_pending_event_count);
+ ObjectTypeDB::bind_method(_MD("pop_pending_event"),&InAppStore::pop_pending_event);
+};
+
+@interface ProductsDelegate : NSObject<SKProductsRequestDelegate> {
+
+};
+
+@end
+
+@implementation ProductsDelegate
+
+- (void)productsRequest:(SKProductsRequest*)request didReceiveResponse:(SKProductsResponse*)response {
+
+ NSArray* products = response.products;
+ Dictionary ret;
+ ret["type"] = "product_info";
+ ret["result"] = "ok";
+ StringArray titles;
+ StringArray descriptions;
+ RealArray prices;
+ StringArray ids;
+ StringArray localized_prices;
+
+ for (int i=0; i<[products count]; i++) {
+
+ SKProduct* product = [products objectAtIndex:i];
+
+ const char* str = [product.localizedTitle UTF8String];
+ titles.push_back(String::utf8(str != NULL ? str : ""));
+
+ str = [product.localizedDescription UTF8String];
+ descriptions.push_back(String::utf8(str != NULL ? str : ""));
+ prices.push_back([product.price doubleValue]);
+ ids.push_back(String::utf8([product.productIdentifier UTF8String]));
+ localized_prices.push_back(String::utf8([product.localizedPrice UTF8String]));
+ };
+ ret["titles"] = titles;
+ ret["descriptions"] = descriptions;
+ ret["prices"] = prices;
+ ret["ids"] = ids;
+ ret["localized_prices"] = localized_prices;
+
+ StringArray invalid_ids;
+
+ for (NSString* ipid in response.invalidProductIdentifiers) {
+
+ invalid_ids.push_back(String::utf8([ipid UTF8String]));
+ };
+ ret["invalid_ids"] = invalid_ids;
+
+ InAppStore::get_singleton()->_post_event(ret);
+
+ [request release];
+};
+
+@end
+
+Error InAppStore::request_product_info(Variant p_params) {
+
+ Dictionary params = p_params;
+ ERR_FAIL_COND_V(!params.has("product_ids"), ERR_INVALID_PARAMETER);
+
+ StringArray pids = params["product_ids"];
+ printf("************ request product info! %i\n", pids.size());
+
+ NSMutableArray* array = [[[NSMutableArray alloc] initWithCapacity:pids.size()] autorelease];
+ for (int i=0; i<pids.size(); i++) {
+ printf("******** adding %ls to product list\n", pids[i].c_str());
+ NSString* pid = [[[NSString alloc] initWithUTF8String:pids[i].utf8().get_data()] autorelease];
+ [array addObject:pid];
+ };
+
+ NSSet* products = [[[NSSet alloc] initWithArray:array] autorelease];
+ SKProductsRequest* request = [[SKProductsRequest alloc] initWithProductIdentifiers:products];
+
+ ProductsDelegate *delegate = [[ProductsDelegate alloc] init];
+
+ request.delegate = delegate;
+ [request start];
+
+ return OK;
+};
+
+@interface TransObserver : NSObject<SKPaymentTransactionObserver> {
+
+};
+@end
+
+@implementation TransObserver
+
+- (void)paymentQueue:(SKPaymentQueue*)queue updatedTransactions:(NSArray*) transactions {
+
+ printf("transactions updated!\n");
+ for (SKPaymentTransaction* transaction in transactions) {
+
+ switch (transaction.transactionState) {
+
+ case SKPaymentTransactionStatePurchased: {
+ printf("status purchased!\n");
+ String pid = String::utf8([transaction.payment.productIdentifier UTF8String]);
+ InAppStore::get_singleton()->_record_purchase(pid);
+ Dictionary ret;
+ ret["type"] = "purchase";
+ ret["result"] = "ok";
+ ret["product_id"] = pid;
+ InAppStore::get_singleton()->_post_event(ret);
+ [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
+ } break;
+ case SKPaymentTransactionStateFailed: {
+ printf("status transaction failed!\n");
+ String pid = String::utf8([transaction.payment.productIdentifier UTF8String]);
+ Dictionary ret;
+ ret["type"] = "purchase";
+ ret["result"] = "error";
+ ret["product_id"] = pid;
+ InAppStore::get_singleton()->_post_event(ret);
+ [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
+ } break;
+ case SKPaymentTransactionStateRestored: {
+ printf("status transaction restored!\n");
+ String pid = String::utf8([transaction.originalTransaction.payment.productIdentifier UTF8String]);
+ InAppStore::get_singleton()->_record_purchase(pid);
+ [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
+ } break;
+
+ default:
+ printf("status default %i!\n", (int)transaction.transactionState);
+
+ break;
+ };
+ };
+};
+
+@end
+
+
+Error InAppStore::purchase(Variant p_params) {
+
+ ERR_FAIL_COND_V(![SKPaymentQueue canMakePayments], ERR_UNAVAILABLE);
+ if (![SKPaymentQueue canMakePayments])
+ return ERR_UNAVAILABLE;
+
+ printf("purchasing!\n");
+ Dictionary params = p_params;
+ ERR_FAIL_COND_V(!params.has("product_id"), ERR_INVALID_PARAMETER);
+
+ NSString *pid = [[[NSString alloc] initWithUTF8String:String(params["product_id"]).utf8().get_data()] autorelease];
+ SKPayment *payment = [SKPayment paymentWithProductIdentifier:pid];
+ SKPaymentQueue* defq = [SKPaymentQueue defaultQueue];
+ [defq addPayment:payment];
+ printf("purchase sent!\n");
+
+ return OK;
+};
+
+
+int InAppStore::get_pending_event_count() {
+ return pending_events.size();
+};
+
+Variant InAppStore::pop_pending_event() {
+
+ Variant front = pending_events.front()->get();
+ pending_events.pop_front();
+
+ return front;
+};
+
+void InAppStore::_post_event(Variant p_event) {
+
+ pending_events.push_back(p_event);
+};
+
+void InAppStore::_record_purchase(String product_id) {
+
+ String skey = "purchased/"+product_id;
+ NSString* key = [[[NSString alloc] initWithUTF8String:skey.utf8().get_data()] autorelease];
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:key];
+ [[NSUserDefaults standardUserDefaults] synchronize];
+};
+
+InAppStore* InAppStore::get_singleton() {
+
+ return instance;
+};
+
+InAppStore::InAppStore() {
+ ERR_FAIL_COND(instance != NULL);
+ instance = this;
+
+ TransObserver* observer = [[TransObserver alloc] init];
+ [[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
+};
+
+InAppStore::~InAppStore() {
+
+};
+
+
+#endif
diff --git a/platform/iphone/logo.png b/platform/iphone/logo.png
new file mode 100644
index 0000000000..d1851d7a5e
--- /dev/null
+++ b/platform/iphone/logo.png
Binary files differ
diff --git a/platform/iphone/main.m b/platform/iphone/main.m
new file mode 100644
index 0000000000..055e6a63c8
--- /dev/null
+++ b/platform/iphone/main.m
@@ -0,0 +1,22 @@
+#import <UIKit/UIKit.h>
+#import "app_delegate.h"
+#include <stdio.h>
+
+int gargc;
+char** gargv;
+
+int main(int argc, char *argv[])
+{
+ printf("*********** main.m\n");
+ gargc = argc;
+ gargv = argv;
+
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ AppDelegate* app = [AppDelegate alloc];
+ printf("running app main\n");
+ UIApplicationMain(argc, argv, nil, @"AppDelegate");
+ printf("main done, pool release\n");
+ [pool release];
+ return 0;
+}
+
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
new file mode 100644
index 0000000000..3b3b30cb86
--- /dev/null
+++ b/platform/iphone/os_iphone.cpp
@@ -0,0 +1,507 @@
+/*************************************************************************/
+/* os_iphone.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef IPHONE_ENABLED
+
+#include "os_iphone.h"
+
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "drivers/gles1/rasterizer_gles1.h"
+
+#include "servers/visual/visual_server_raster.h"
+#include "servers/visual/visual_server_wrap_mt.h"
+
+#include "main/main.h"
+#include "audio_driver_iphone.h"
+
+#include "core/os/dir_access.h"
+#include "core/globals.h"
+
+#include "sem_iphone.h"
+
+int OSIPhone::get_video_driver_count() const {
+
+ return 1;
+};
+
+const char * OSIPhone::get_video_driver_name(int p_driver) const {
+
+ return "openglES";
+};
+
+OSIPhone* OSIPhone::get_singleton() {
+
+ return (OSIPhone*)OS::get_singleton();
+};
+
+
+OS::VideoMode OSIPhone::get_default_video_mode() const {
+
+ return video_mode;
+};
+
+uint8_t OSIPhone::get_orientations() const {
+
+ return supported_orientations;
+};
+
+extern int gl_view_base_fb; // from gl_view.mm
+
+void OSIPhone::set_data_dir(String p_dir) {
+
+ DirAccess* da = DirAccess::open(p_dir);
+
+ data_dir = da->get_current_dir();
+
+ memdelete(da);
+};
+
+void OSIPhone::set_unique_ID(String p_ID) {
+
+ unique_ID = p_ID;
+};
+
+String OSIPhone::get_unique_ID() const {
+
+ return unique_ID;
+};
+
+void OSIPhone::initialize_core() {
+
+ OS_Unix::initialize_core();
+ SemaphoreIphone::make_default();
+};
+
+void OSIPhone::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ supported_orientations = 0;
+ supported_orientations |= ((GLOBAL_DEF("video_mode/allow_horizontal", true)?1:0) << LandscapeLeft);
+ supported_orientations |= ((GLOBAL_DEF("video_mode/allow_horizontal_flipped", false)?1:0) << LandscapeRight);
+ supported_orientations |= ((GLOBAL_DEF("video_mode/allow_vertical", false)?1:0) << PortraitDown);
+ supported_orientations |= ((GLOBAL_DEF("video_mode/allow_vertical_flipped", false)?1:0) << PortraitUp);
+
+#ifdef GLES1_OVERRIDE
+ rasterizer = memnew( RasterizerGLES1 );
+#else
+ rasterizer_gles22 = memnew( RasterizerGLES2(false, false, false) );
+ rasterizer = rasterizer_gles22;
+ rasterizer_gles22->set_base_framebuffer(gl_view_base_fb);
+#endif
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
+
+ visual_server = memnew(VisualServerWrapMT(visual_server, false));
+ };
+ visual_server->init();
+
+ visual_server->init();
+ visual_server->cursor_set_visible(false, 0);
+
+ audio_driver = memnew(AudioDriverIphone);
+ audio_driver->set_singleton();
+ audio_driver->init();
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+ audio_server->init();
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+ /*
+#ifdef IOS_SCORELOOP_ENABLED
+ scoreloop = memnew(ScoreloopIOS);
+ Globals::get_singleton()->add_singleton(Globals::Singleton("Scoreloop", scoreloop));
+ scoreloop->connect();
+#endif
+ */
+
+#ifdef GAME_CENTER_ENABLED
+ game_center = memnew(GameCenter);
+ Globals::get_singleton()->add_singleton(Globals::Singleton("GameCenter", game_center));
+ game_center->connect();
+#endif
+
+#ifdef STOREKIT_ENABLED
+ store_kit = memnew(InAppStore);
+ Globals::get_singleton()->add_singleton(Globals::Singleton("InAppStore", store_kit));
+#endif
+};
+
+MainLoop *OSIPhone::get_main_loop() const {
+
+ return main_loop;
+};
+
+
+void OSIPhone::set_main_loop( MainLoop * p_main_loop ) {
+
+ main_loop = p_main_loop;
+
+ if (main_loop) {
+ input->set_main_loop(p_main_loop);
+ main_loop->init();
+ }
+};
+
+
+bool OSIPhone::iterate() {
+
+ if (!main_loop)
+ return true;
+
+ if (main_loop) {
+ for (int i=0; i<event_count; i++) {
+
+ input->parse_input_event(event_queue[i]);
+ };
+ };
+ event_count = 0;
+
+ return Main::iteration();
+};
+
+void OSIPhone::key(uint32_t p_key, bool p_pressed) {
+
+ InputEvent ev;
+ ev.type = InputEvent::KEY;
+ ev.ID = ++last_event_id;
+ ev.key.echo = false;
+ ev.key.pressed = p_pressed;
+ ev.key.scancode = p_key;
+ ev.key.unicode = p_key;
+ queue_event(ev);
+};
+
+void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick, bool p_use_as_mouse) {
+
+ InputEvent ev;
+ ev.type = InputEvent::SCREEN_TOUCH;
+ ev.ID = ++last_event_id;
+ ev.screen_touch.index=p_idx;
+ ev.screen_touch.pressed=p_pressed;
+ ev.screen_touch.x=p_x;
+ ev.screen_touch.y=p_y;
+ queue_event(ev);
+
+ if (p_use_as_mouse) {
+
+ InputEvent ev;
+ ev.type = InputEvent::MOUSE_BUTTON;
+ ev.device = 0;
+ ev.mouse_button.pointer_index = p_idx;
+ ev.ID = ++last_event_id;
+
+ // swaped it for tilted screen
+ //ev.mouse_button.x = ev.mouse_button.global_x = video_mode.height - p_y;
+ //ev.mouse_button.y = ev.mouse_button.global_y = p_x;
+ ev.mouse_button.x = ev.mouse_button.global_x = p_x;
+ ev.mouse_button.y = ev.mouse_button.global_y = p_y;
+
+ ev.mouse_button.button_index = BUTTON_LEFT;
+ ev.mouse_button.doubleclick = p_doubleclick;
+ ev.mouse_button.pressed = p_pressed;
+
+ mouse_list.pressed[p_idx] = p_pressed;
+
+ queue_event(ev);
+ };
+};
+
+void OSIPhone::mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_DRAG;
+ ev.ID = ++last_event_id;
+ ev.screen_drag.index=p_idx;
+ ev.screen_drag.x=p_x;
+ ev.screen_drag.y=p_y;
+ ev.screen_drag.relative_x = p_x - p_prev_x;
+ ev.screen_drag.relative_y = p_y - p_prev_y;
+ queue_event(ev);
+
+ if (p_use_as_mouse) {
+ InputEvent ev;
+ ev.type = InputEvent::MOUSE_MOTION;
+ ev.device = 0;
+ ev.mouse_motion.pointer_index = p_idx;
+ ev.ID = ++last_event_id;
+
+ if (true) { // vertical
+
+ ev.mouse_motion.x = ev.mouse_button.global_x = p_x;
+ ev.mouse_motion.y = ev.mouse_button.global_y = p_y;
+ ev.mouse_motion.relative_x = ev.mouse_motion.x - p_prev_x;
+ ev.mouse_motion.relative_y = ev.mouse_motion.y - p_prev_y;
+
+ } else { // horizontal?
+ ev.mouse_motion.x = ev.mouse_button.global_x = video_mode.height - p_y;
+ ev.mouse_motion.y = ev.mouse_button.global_y = p_x;
+ ev.mouse_motion.relative_x = ev.mouse_motion.x - (video_mode.height - p_prev_x);
+ ev.mouse_motion.relative_y = ev.mouse_motion.y - p_prev_x;
+ };
+
+ 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.button_mask = 1; // pressed
+
+ queue_event(ev);
+ };
+};
+
+void OSIPhone::queue_event(const InputEvent& p_event) {
+
+ ERR_FAIL_INDEX( event_count, MAX_EVENTS );
+
+ event_queue[event_count++] = p_event;
+};
+
+void OSIPhone::touches_cancelled() {
+
+ for (int i=0; i<MAX_MOUSE_COUNT; i++) {
+
+ if (mouse_list.pressed[i]) {
+
+ // send a mouse_up outside the screen
+ mouse_button(i, -1, -1, false, false, false);
+ };
+ };
+};
+
+static const float ACCEL_RANGE = 1;
+
+void OSIPhone::update_accelerometer(float p_x, float p_y, float p_z) {
+
+ input->set_accelerometer(Vector3(p_x / (float)ACCEL_RANGE, p_y / (float)ACCEL_RANGE, -p_z / (float)ACCEL_RANGE));
+
+ /*
+ if (p_x != last_accel.x) {
+ //printf("updating accel x %f\n", p_x);
+ InputEvent ev;
+ ev.type = InputEvent::JOYSTICK_MOTION;
+ ev.device = 0;
+ ev.joy_motion.axis = JOY_ANALOG_0_X;
+ ev.joy_motion.axis_value = (p_x / (float)ACCEL_RANGE);
+ ev.ID = ++last_event_id;
+ last_accel.x = p_x;
+ queue_event(ev);
+ };
+ if (p_y != last_accel.y) {
+ //printf("updating accel y %f\n", p_y);
+ InputEvent ev;
+ ev.type = InputEvent::JOYSTICK_MOTION;
+ ev.device = 0;
+ ev.joy_motion.axis = JOY_ANALOG_0_Y;
+ ev.joy_motion.axis_value = (p_y / (float)ACCEL_RANGE);
+ ev.ID = ++last_event_id;
+ last_accel.y = p_y;
+ queue_event(ev);
+ };
+ if (p_z != last_accel.z) {
+ //printf("updating accel z %f\n", p_z);
+ InputEvent ev;
+ ev.type = InputEvent::JOYSTICK_MOTION;
+ ev.device = 0;
+ ev.joy_motion.axis = JOY_ANALOG_1_X;
+ ev.joy_motion.axis_value = ( (1.0 - p_z) / (float)ACCEL_RANGE);
+ ev.ID = ++last_event_id;
+ last_accel.z = p_z;
+ queue_event(ev);
+ };
+ */
+};
+
+
+
+void OSIPhone::delete_main_loop() {
+
+ if (main_loop) {
+ main_loop->finish();
+ memdelete(main_loop);
+ };
+
+ main_loop = NULL;
+};
+
+void OSIPhone::finalize() {
+
+ if(main_loop) // should not happen?
+ memdelete(main_loop);
+
+ visual_server->finish();
+ memdelete(visual_server);
+ memdelete(rasterizer);
+
+ physics_server->finish();
+ memdelete(physics_server);
+
+ physics_2d_server->finish();
+ memdelete(physics_2d_server);
+
+ spatial_sound_server->finish();
+ memdelete(spatial_sound_server);
+
+ memdelete(input);
+
+ spatial_sound_2d_server->finish();
+ memdelete(spatial_sound_2d_server);
+
+};
+
+void OSIPhone::set_mouse_show(bool p_show) { };
+void OSIPhone::set_mouse_grab(bool p_grab) { };
+
+bool OSIPhone::is_mouse_grab_enabled() const {
+
+ return true;
+};
+
+Point2 OSIPhone::get_mouse_pos() const {
+
+ return Point2();
+};
+
+int OSIPhone::get_mouse_button_state() const {
+
+ return mouse_list.pressed[0];
+};
+
+void OSIPhone::set_window_title(const String& p_title) { };
+
+void OSIPhone::set_video_mode(const VideoMode& p_video_mode, int p_screen) {
+
+ video_mode = p_video_mode;
+};
+
+OS::VideoMode OSIPhone::get_video_mode(int p_screen) const {
+
+ return video_mode;
+};
+
+void OSIPhone::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
+
+ p_list->push_back(video_mode);
+};
+
+bool OSIPhone::can_draw() const {
+
+ return true;
+};
+
+int OSIPhone::set_base_framebuffer(int p_fb) {
+
+ if (rasterizer_gles22) {
+ rasterizer_gles22->set_base_framebuffer(p_fb);
+ };
+ return 0;
+};
+
+bool OSIPhone::has_virtual_keyboard() const {
+ return true;
+};
+
+extern void _show_keyboard(String p_existing);
+extern void _hide_keyboard();
+extern Error _shell_open(String p_uri);
+
+void OSIPhone::show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect) {
+ _show_keyboard(p_existing_text);
+};
+
+void OSIPhone::hide_virtual_keyboard() {
+ _hide_keyboard();
+};
+
+Error OSIPhone::shell_open(String p_uri) {
+ return _shell_open(p_uri);
+};
+
+
+void OSIPhone::set_cursor_shape(CursorShape p_shape) {
+
+
+};
+
+String OSIPhone::get_data_dir() const {
+
+ return data_dir;
+};
+
+String OSIPhone::get_name() {
+
+ return "iOS";
+};
+
+bool OSIPhone::has_touchscreen_ui_hint() const {
+
+ return true;
+}
+
+void OSIPhone::set_locale(String p_locale)
+{
+ locale_code = p_locale;
+}
+
+String OSIPhone::get_locale() const {
+ return locale_code;
+}
+
+OSIPhone::OSIPhone(int width, int height) {
+
+ rasterizer_gles22 = NULL;
+ main_loop = NULL;
+ visual_server = NULL;
+ rasterizer = NULL;
+
+ VideoMode vm;
+ vm.fullscreen = true;
+ vm.width = width;
+ vm.height = height;
+ vm.resizable = false;
+ set_video_mode(vm);
+ event_count = 0;
+ last_event_id = 0;
+};
+
+OSIPhone::~OSIPhone() {
+
+}
+
+#endif
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
new file mode 100644
index 0000000000..a8ccba02b5
--- /dev/null
+++ b/platform/iphone/os_iphone.h
@@ -0,0 +1,193 @@
+/*************************************************************************/
+/* os_iphone.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef IPHONE_ENABLED
+
+#ifndef OS_IPHONE_H
+#define OS_IPHONE_H
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+
+#include "servers/visual_server.h"
+#include "servers/visual/rasterizer.h"
+#include "servers/physics/physics_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/audio/sample_manager_sw.h"
+#include "servers/spatial_sound/spatial_sound_server_sw.h"
+#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "game_center.h"
+#include "in_app_store.h"
+
+class AudioDriverIphone;
+class RasterizerGLES2;
+
+class OSIPhone : public OS_Unix {
+
+public:
+
+ enum Orientations {
+ PortraitDown,
+ PortraitUp,
+ LandscapeLeft,
+ LandscapeRight,
+ };
+private:
+
+ enum {
+ MAX_MOUSE_COUNT = 8,
+ MAX_EVENTS = 64,
+ };
+
+ uint8_t supported_orientations;
+
+ Rasterizer *rasterizer;
+
+ RasterizerGLES2* rasterizer_gles22;
+
+ VisualServer *visual_server;
+ PhysicsServer* physics_server;
+ Physics2DServer *physics_2d_server;
+
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+ AudioDriverIphone* audio_driver;
+
+#ifdef GAME_CENTER_ENABLED
+ GameCenter* game_center;
+#endif
+#ifdef STOREKIT_ENABLED
+ InAppStore* store_kit;
+#endif
+
+ MainLoop *main_loop;
+
+ VideoMode video_mode;
+
+
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual void initialize_core();
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual MainLoop *get_main_loop() const;
+
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+
+ struct MouseList {
+
+ bool pressed[MAX_MOUSE_COUNT];
+ MouseList() {
+ for (int i=0; i<MAX_MOUSE_COUNT; i++)
+ pressed[i] = false;
+ };
+ };
+
+ MouseList mouse_list;
+
+ Vector3 last_accel;
+
+ InputEvent event_queue[MAX_EVENTS];
+ int event_count;
+ int last_event_id;
+ void queue_event(const InputEvent& p_event);
+
+ String data_dir;
+ String unique_ID;
+ String locale_code;
+
+ InputDefault *input;
+
+public:
+
+ bool iterate();
+
+ uint8_t get_orientations() const;
+
+ void mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick, bool p_use_as_mouse);
+ void mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse);
+ void touches_cancelled();
+ void key(uint32_t p_key, bool p_pressed);
+
+ int set_base_framebuffer(int p_fb);
+
+ void update_accelerometer(float p_x, float p_y, float p_z);
+
+ static OSIPhone* get_singleton();
+
+ virtual void set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ 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 bool can_draw() const;
+
+ virtual bool has_virtual_keyboard() const;
+ virtual void show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect=Rect2());
+ virtual void hide_virtual_keyboard();
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ virtual bool has_touchscreen_ui_hint() const;
+
+ void set_data_dir(String p_dir);
+
+ virtual String get_name();
+
+ Error shell_open(String p_uri);
+
+ String get_data_dir() const;
+
+ void set_locale(String p_locale);
+ String get_locale() const;
+
+ void set_unique_ID(String p_ID);
+ String get_unique_ID() const;
+
+ OSIPhone(int width, int height);
+ ~OSIPhone();
+};
+
+#endif // OS_IPHONE_H
+
+#endif
diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h
new file mode 100644
index 0000000000..df50d30f40
--- /dev/null
+++ b/platform/iphone/platform_config.h
@@ -0,0 +1,32 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <alloca.h>
+#define GLES2_INCLUDE_H <ES2/gl.h>
+#define GLES1_INCLUDE_H <ES1/gl.h>
+
diff --git a/platform/iphone/rasterizer_iphone.cpp b/platform/iphone/rasterizer_iphone.cpp
new file mode 100644
index 0000000000..4674a5143c
--- /dev/null
+++ b/platform/iphone/rasterizer_iphone.cpp
@@ -0,0 +1,2762 @@
+/*************************************************************************/
+/* rasterizer_iphone.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef IPHONE_ENABLED
+
+#include "rasterizer_iphone.h"
+#include "os/os.h"
+#include "globals.h"
+#include <stdio.h>
+
+_FORCE_INLINE_ static void _gl_load_transform(const Transform& tr) {
+
+ GLfloat matrix[16]={ /* build a 16x16 matrix */
+ tr.basis.elements[0][0],
+ tr.basis.elements[1][0],
+ tr.basis.elements[2][0],
+ 0,
+ tr.basis.elements[0][1],
+ tr.basis.elements[1][1],
+ tr.basis.elements[2][1],
+ 0,
+ tr.basis.elements[0][2],
+ tr.basis.elements[1][2],
+ tr.basis.elements[2][2],
+ 0,
+ tr.origin.x,
+ tr.origin.y,
+ tr.origin.z,
+ 1
+ };
+
+ glLoadMatrixf(matrix);
+};
+
+_FORCE_INLINE_ static void _gl_mult_transform(const Transform& tr) {
+
+ GLfloat matrix[16]={ /* build a 16x16 matrix */
+ tr.basis.elements[0][0],
+ tr.basis.elements[1][0],
+ tr.basis.elements[2][0],
+ 0,
+ tr.basis.elements[0][1],
+ tr.basis.elements[1][1],
+ tr.basis.elements[2][1],
+ 0,
+ tr.basis.elements[0][2],
+ tr.basis.elements[1][2],
+ tr.basis.elements[2][2],
+ 0,
+ tr.origin.x,
+ tr.origin.y,
+ tr.origin.z,
+ 1
+ };
+
+ glMultMatrixf(matrix);
+};
+
+static const GLenum prim_type[]={GL_POINTS,GL_LINES,GL_TRIANGLES,GL_TRIANGLE_FAN};
+
+static void _draw_primitive(int p_points, const float *p_vertices, const float *p_normals, const float* p_colors, const float *p_uvs,const Plane *p_tangents=NULL,int p_instanced=1) {
+
+ ERR_FAIL_COND(!p_vertices);
+ ERR_FAIL_COND(p_points <1 || p_points>4);
+
+ GLenum type = prim_type[p_points - 1];
+
+
+ if (!p_colors) {
+ glColor4f(1, 1, 1, 1);
+ };
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)p_vertices);
+
+ if (p_normals) {
+
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glNormalPointer(GL_FLOAT, 0, (GLvoid*)p_normals);
+ };
+
+ if (p_colors) {
+ glEnableClientState(GL_COLOR_ARRAY);
+ glColorPointer(4,GL_FLOAT, 0, p_colors);
+ };
+
+ if (p_uvs) {
+
+ glClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, p_uvs);
+ };
+
+ glDrawArrays( type, 0, p_points);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+};
+
+
+/* TEXTURE API */
+
+static Image _get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,int &r_gl_components,bool &r_has_alpha_cache) {
+
+ r_has_alpha_cache=false;
+ Image image=p_image;
+
+ switch(p_format) {
+
+ case Image::FORMAT_GRAYSCALE: {
+ r_gl_components=1;
+ r_gl_format=GL_LUMINANCE;
+
+ } break;
+ case Image::FORMAT_INTENSITY: {
+
+ image.convert(Image::FORMAT_RGBA);
+ r_gl_components=4;
+ r_gl_format=GL_RGBA;
+ r_has_alpha_cache=true;
+ } break;
+ case Image::FORMAT_GRAYSCALE_ALPHA: {
+
+ image.convert(Image::FORMAT_RGBA);
+ r_gl_components=4;
+ r_gl_format=GL_RGBA;
+ r_has_alpha_cache=true;
+ } break;
+
+ case Image::FORMAT_INDEXED: {
+
+ image.convert(Image::FORMAT_RGB);
+ r_gl_components=3;
+ r_gl_format=GL_RGB;
+
+ } break;
+
+ case Image::FORMAT_INDEXED_ALPHA: {
+
+ image.convert(Image::FORMAT_RGBA);
+ r_gl_components=4;
+ r_gl_format=GL_RGB;
+ r_has_alpha_cache=true;
+
+ } break;
+ case Image::FORMAT_RGB: {
+
+ r_gl_components=3; r_gl_format=GL_RGB;
+ } break;
+ case Image::FORMAT_RGBA: {
+
+ r_gl_components=4;
+ r_gl_format=GL_RGBA;
+ r_has_alpha_cache=true;
+ } break;
+ default: {
+
+ ERR_FAIL_V(Image());
+ }
+ }
+
+ return image;
+}
+
+RID RasterizerIPhone::texture_create() {
+
+ Texture *texture = memnew(Texture);
+ ERR_FAIL_COND_V(!texture,RID());
+ glGenTextures(1, &texture->tex_id);
+ texture->active=false;
+
+ return texture_owner.make_rid( texture );
+
+}
+
+void RasterizerIPhone::texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags) {
+
+ bool has_alpha_cache;
+ int components;
+ GLenum format;
+
+ Texture *texture = texture_owner.get( p_texture );
+ ERR_FAIL_COND(!texture);
+ texture->width=p_width;
+ texture->height=p_height;
+ texture->format=p_format;
+ texture->flags=p_flags;
+ //texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+ texture->target = GL_TEXTURE_2D;
+
+ _get_gl_image_and_format(Image(),texture->format,texture->flags,format,components,has_alpha_cache);
+
+ texture->gl_components_cache=components;
+ texture->gl_format_cache=format;
+ texture->format_has_alpha=has_alpha_cache;
+ texture->has_alpha=false; //by default it doesn't have alpha unless something with alpha is blitteds
+
+ glBindTexture(texture->target, texture->tex_id);
+
+ if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS) {
+ glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
+ }
+
+
+ if (texture->target==GL_TEXTURE_2D) {
+ glTexImage2D(texture->target, 0, format, texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE,NULL);
+ }
+
+ /*
+ else {
+ //cubemappor
+ for (int i=0;i<6;i++)
+ glTexImage2D(_cube_side_enum[i], 0, format, texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE,NULL);
+ }
+ */
+
+ glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
+
+ if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
+
+ glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
+ if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS) {
+ //glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
+ };
+ }
+
+
+
+ if (texture->flags&VS::TEXTURE_FLAG_REPEAT /* && texture->target != GL_TEXTURE_CUBE_MAP*/) {
+
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ } else {
+
+ //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
+ glTexParameterf( texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ }
+
+ texture->active=true;
+}
+
+void RasterizerIPhone::texture_blit_rect(RID p_texture,int p_x,int p_y, const Image& p_image,VS::CubeMapSide p_cube_side) {
+
+ Texture * texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND(!texture);
+ ERR_FAIL_COND(!texture->active);
+ ERR_FAIL_COND(texture->format != p_image.get_format() );
+
+ int components;
+ GLenum format;
+ bool alpha;
+
+ Image img = _get_gl_image_and_format(p_image, p_image.get_format(),texture->flags,format,components,alpha);
+
+ if (img.detect_alpha())
+ texture->has_alpha=true;
+
+ GLenum blit_target = GL_TEXTURE_2D; //(texture->target == GL_TEXTURE_CUBE_MAP)?_cube_side_enum[p_cube_side]:GL_TEXTURE_2D;
+
+ DVector<uint8_t>::Read read = img.get_data().read();
+
+ glBindTexture(texture->target, texture->tex_id);
+ glTexSubImage2D( blit_target, 0, p_x,p_y,img.get_width(),img.get_height(),format,GL_UNSIGNED_BYTE,read.ptr() );
+
+ //glGenerateMipmap( texture->target );
+}
+
+Image RasterizerIPhone::texture_get_rect(RID p_texture,int p_x,int p_y,int p_width, int p_height,VS::CubeMapSide p_cube_side) const {
+
+
+ return Image();
+}
+void RasterizerIPhone::texture_set_flags(RID p_texture,uint32_t p_flags) {
+
+ Texture *texture = texture_owner.get( p_texture );
+ ERR_FAIL_COND(!texture);
+
+ glBindTexture(texture->target, texture->tex_id);
+ uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP;
+ texture->flags=p_flags|cube; // can't remove a cube from being a cube
+
+ if (texture->flags&VS::TEXTURE_FLAG_REPEAT /*&& texture->target != GL_TEXTURE_CUBE_MAP*/) {
+
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ } else {
+ //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
+ glTexParameterf( texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+
+ }
+
+
+ if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
+
+ glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
+ if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS)
+ glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
+
+ } else {
+
+ glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // nearest
+ }
+}
+uint32_t RasterizerIPhone::texture_get_flags(RID p_texture) const {
+
+ Texture * texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND_V(!texture,0);
+
+ return texture->flags;
+
+}
+Image::Format RasterizerIPhone::texture_get_format(RID p_texture) const {
+
+ Texture * texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND_V(!texture,Image::FORMAT_GRAYSCALE);
+
+ return texture->format;
+}
+uint32_t RasterizerIPhone::texture_get_width(RID p_texture) const {
+
+ Texture * texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND_V(!texture,0);
+
+ return texture->width;
+}
+uint32_t RasterizerIPhone::texture_get_height(RID p_texture) const {
+
+ Texture * texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND_V(!texture,0);
+
+ return texture->height;
+}
+
+bool RasterizerIPhone::texture_has_alpha(RID p_texture) const {
+
+ Texture * texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND_V(!texture,0);
+
+ return texture->has_alpha;
+
+}
+
+/* SHADER API */
+
+RID RasterizerIPhone::shader_create() {
+
+ return RID();
+}
+
+void RasterizerIPhone::shader_node_add(RID p_shader,VS::ShaderNodeType p_type,int p_id) {
+
+
+}
+void RasterizerIPhone::shader_node_remove(RID p_shader,int p_id) {
+
+
+}
+void RasterizerIPhone::shader_node_change_type(RID p_shader, int p_id, VS::ShaderNodeType p_type) {
+
+
+}
+void RasterizerIPhone::shader_node_set_param(RID p_shader, int p_id, const Variant& p_value) {
+
+
+}
+
+void RasterizerIPhone::shader_get_node_list(RID p_shader,List<int> *p_node_list) const {
+
+
+}
+VS::ShaderNodeType RasterizerIPhone::shader_node_get_type(RID p_shader,int p_id) const {
+
+
+ return VS::NODE_ADD;
+}
+Variant RasterizerIPhone::shader_node_get_param(RID p_shader,int p_id) const {
+
+ return Variant();
+}
+
+void RasterizerIPhone::shader_connect(RID p_shader,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+
+
+}
+bool RasterizerIPhone::shader_is_connected(RID p_shader,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const {
+
+ return false;
+}
+
+void RasterizerIPhone::shader_disconnect(RID p_shader,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+
+
+}
+
+void RasterizerIPhone::shader_get_connections(RID p_shader,List<VS::ShaderConnection> *p_connections) const {
+
+
+}
+
+void RasterizerIPhone::shader_clear(RID p_shader) {
+
+
+}
+
+/* COMMON MATERIAL API */
+
+void RasterizerIPhone::material_set_param(RID p_material, const StringName& p_param, const Variant& p_value) {
+
+
+}
+Variant RasterizerIPhone::material_get_param(RID p_material, const StringName& p_param) const {
+
+ return Variant();
+}
+void RasterizerIPhone::material_get_param_list(RID p_material, List<String> *p_param_list) const {
+
+
+}
+
+void RasterizerIPhone::material_set_flag(RID p_material, VS::MaterialFlag p_flag,bool p_enabled) {
+
+
+}
+bool RasterizerIPhone::material_get_flag(RID p_material,VS::MaterialFlag p_flag) const {
+
+ return false;
+}
+
+void RasterizerIPhone::material_set_blend_mode(RID p_material,VS::MaterialBlendMode p_mode) {
+
+
+}
+VS::MaterialBlendMode RasterizerIPhone::material_get_blend_mode(RID p_material) const {
+
+ return VS::MATERIAL_BLEND_MODE_ADD;
+}
+
+void RasterizerIPhone::material_set_line_width(RID p_material,float p_line_width) {
+
+
+}
+float RasterizerIPhone::material_get_line_width(RID p_material) const {
+
+ return 0;
+}
+
+/* FIXED MATERIAL */
+
+RID RasterizerIPhone::material_create() {
+
+ return material_owner.make_rid( memnew( Material ) );
+}
+
+void RasterizerIPhone::fixed_material_set_parameter(RID p_material, VS::FixedMaterialParam p_parameter, const Variant& p_value) {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND(!m);
+ ERR_FAIL_INDEX(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX);
+
+ m->parameters[p_parameter] = p_value;
+}
+Variant RasterizerIPhone::fixed_material_get_parameter(RID p_material,VS::FixedMaterialParam p_parameter) const {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND_V(!m, Variant());
+ ERR_FAIL_INDEX_V(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX, Variant());
+
+ return m->parameters[p_parameter];
+}
+
+void RasterizerIPhone::fixed_material_set_texture(RID p_material,VS::FixedMaterialParam p_parameter, RID p_texture) {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND(!m);
+ ERR_FAIL_INDEX(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX);
+
+ m->textures[p_parameter] = p_texture;
+}
+RID RasterizerIPhone::fixed_material_get_texture(RID p_material,VS::FixedMaterialParam p_parameter) const {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND_V(!m, RID());
+ ERR_FAIL_INDEX_V(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX, Variant());
+
+ return m->textures[p_parameter];
+}
+
+void RasterizerIPhone::fixed_material_set_detail_blend_mode(RID p_material,VS::MaterialBlendMode p_mode) {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND(!m);
+
+ m->detail_blend_mode = p_mode;
+}
+VS::MaterialBlendMode RasterizerIPhone::fixed_material_get_detail_blend_mode(RID p_material) const {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND_V(!m, VS::MATERIAL_BLEND_MODE_MIX);
+
+ return m->detail_blend_mode;
+}
+
+void RasterizerIPhone::fixed_material_set_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter, VS::FixedMaterialTexCoordMode p_mode) {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND(!m);
+ ERR_FAIL_INDEX(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX);
+
+ m->texcoord_mode[p_parameter] = p_mode;
+}
+VS::FixedMaterialTexCoordMode RasterizerIPhone::fixed_material_get_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter) const {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND_V(!m, VS::FIXED_MATERIAL_TEXCOORD_TEXGEN);
+ ERR_FAIL_INDEX_V(p_parameter, VisualServer::FIXED_MATERIAL_PARAM_MAX, VS::FIXED_MATERIAL_TEXCOORD_UV);
+
+ return m->texcoord_mode[p_parameter]; // for now
+}
+
+void RasterizerIPhone::fixed_material_set_texgen_mode(RID p_material,VS::FixedMaterialTexGenMode p_mode) {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND(!m);
+
+ m->texgen_mode = p_mode;
+};
+
+VS::FixedMaterialTexGenMode RasterizerIPhone::fixed_material_get_texgen_mode(RID p_material) const {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND_V(!m, VS::FIXED_MATERIAL_TEXGEN_SPHERE);
+
+ return m->texgen_mode;
+};
+
+
+void RasterizerIPhone::fixed_material_set_uv_transform(RID p_material,const Transform& p_transform) {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND(!m);
+
+ m->uv_transform = p_transform;
+}
+Transform RasterizerIPhone::fixed_material_get_uv_transform(RID p_material) const {
+
+ Material *m=material_owner.get( p_material );
+ ERR_FAIL_COND_V(!m, Transform());
+
+ return m->uv_transform;
+}
+
+/* SHADER MATERIAL */
+
+RID RasterizerIPhone::shader_material_create() const {
+
+ return RID();
+}
+
+void RasterizerIPhone::shader_material_set_vertex_shader(RID p_material,RID p_shader,bool p_owned) {
+
+
+}
+RID RasterizerIPhone::shader_material_get_vertex_shader(RID p_material) const {
+
+ return RID();
+}
+
+void RasterizerIPhone::shader_material_set_fragment_shader(RID p_material,RID p_shader,bool p_owned) {
+
+
+}
+RID RasterizerIPhone::shader_material_get_fragment_shader(RID p_material) const {
+
+ return RID();
+}
+
+
+/* MESH API */
+
+RID RasterizerIPhone::mesh_create() {
+
+
+ return mesh_owner.make_rid( memnew( Mesh ) );
+}
+
+void RasterizerIPhone::mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,uint32_t p_format,int p_array_len,int p_index_array_len) {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND(!mesh);
+
+ ERR_FAIL_COND((p_format&VS::ARRAY_FORMAT_VERTEX)==0); // mandatory
+ ERR_FAIL_COND( p_array_len<=0 );
+ ERR_FAIL_COND( p_index_array_len==0 );
+ ERR_FAIL_INDEX( p_primitive, VS::PRIMITIVE_MAX );
+
+ Surface *surface = memnew( Surface );
+ ERR_FAIL_COND( !surface );
+
+ int total_elem_size=0;
+
+ bool use_VBO=true; //glGenBuffersARB!=NULL; // TODO detect if it's in there
+ if (p_format&VS::ARRAY_FORMAT_WEIGHTS) {
+
+ use_VBO=false;
+ }
+
+
+ for (int i=0;i<VS::ARRAY_MAX;i++) {
+
+
+ Surface::ArrayData&ad=surface->array[i];
+ ad.size=0;
+ ad.configured=false;
+ ad.ofs=0;
+ int elem_size=0;
+ int elem_count=0;
+
+ if (!(p_format&(1<<i))) // no array
+ continue;
+
+
+ switch(i) {
+
+ case VS::ARRAY_VERTEX:
+ case VS::ARRAY_NORMAL: {
+
+ elem_size=3*sizeof(GLfloat); // vertex
+ elem_count=3;
+ } break;
+ case VS::ARRAY_TANGENT: {
+ elem_size=4*sizeof(GLfloat); // vertex
+ elem_count=4;
+
+ } break;
+ case VS::ARRAY_COLOR: {
+
+ elem_size=4; /* RGBA */
+ elem_count=4;
+ } break;
+ case VS::ARRAY_TEX_UV: {
+ elem_size=2*sizeof(GLfloat);
+ elem_count=2;
+
+ } break;
+ case VS::ARRAY_WEIGHTS:
+ case VS::ARRAY_BONES: {
+
+ elem_size=VS::ARRAY_WEIGHTS_SIZE*sizeof(GLfloat);
+ elem_count=VS::ARRAY_WEIGHTS_SIZE;
+
+ } break;
+ case VS::ARRAY_INDEX: {
+
+ if (p_index_array_len<=0) {
+ ERR_PRINT("p_index_array_len==NO_INDEX_ARRAY");
+ break;
+ }
+ /* determine wether using 8 or 16 bits indices */
+ if (p_index_array_len>(1<<8)) {
+
+ elem_size=2;
+ } else {
+ elem_size=1;
+ }
+
+ if (use_VBO) {
+
+ glGenBuffers(1,&surface->index_id);
+ ERR_FAIL_COND(surface->index_id==0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER,p_index_array_len*elem_size,NULL,GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind
+ } else {
+ surface->index_array_local = (uint8_t*)memalloc(p_index_array_len*elem_size);
+ };
+
+ surface->index_array_len=p_index_array_len; // only way it can exist
+ ad.ofs=0;
+ ad.size=elem_size;
+ ad.configured=false;
+ ad.components=1;
+
+ continue;
+ } break;
+ default: {
+ ERR_FAIL( );
+ }
+ }
+
+ ad.ofs=total_elem_size;
+ ad.size=elem_size;
+ ad.components=elem_count;
+ total_elem_size+=elem_size;
+ ad.configured=false;
+ }
+
+ surface->stride=total_elem_size;
+ surface->array_len=p_array_len;
+ surface->format=p_format;
+ surface->primitive=p_primitive;
+
+
+ /* bind the bigass buffers */
+ if (use_VBO) {
+
+ glGenBuffers(1,&surface->vertex_id);
+ ERR_FAIL_COND(surface->vertex_id==0);
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+ glBufferData(GL_ARRAY_BUFFER,surface->array_len*surface->stride,NULL,GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+ } else {
+ surface->array_local = (uint8_t*)memalloc(surface->array_len*surface->stride);
+ };
+
+ mesh->surfaces.push_back(surface);
+}
+
+Error RasterizerIPhone::mesh_surface_set_array(RID p_mesh, int p_surface,VS::ArrayType p_type,const Variant& p_array) {
+
+ ERR_FAIL_INDEX_V(p_type, VS::ARRAY_MAX, ERR_INVALID_PARAMETER );
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND_V(!mesh,ERR_INVALID_PARAMETER);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), ERR_INVALID_PARAMETER );
+ Surface *surface = mesh->surfaces[p_surface];
+ ERR_FAIL_COND_V( !surface, ERR_INVALID_PARAMETER );
+
+ ERR_FAIL_COND_V( surface->array[p_type].size==0, ERR_INVALID_PARAMETER );
+
+ Surface::ArrayData &a=surface->array[p_type];
+
+ switch(p_type) {
+
+ case VS::ARRAY_INDEX: {
+ ERR_FAIL_COND_V( surface->index_array_len<=0, ERR_INVALID_DATA );
+ ERR_FAIL_COND_V( p_array.get_type() != Variant::INT_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<int> indices = p_array;
+ ERR_FAIL_COND_V( indices.size() == 0, ERR_INVALID_PARAMETER );
+ ERR_FAIL_COND_V( indices.size() != surface->index_array_len, ERR_INVALID_PARAMETER );
+
+ /* determine wether using 16 or 32 bits indices */
+
+ if (surface->index_array_local == 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+ };
+
+ DVector<int>::Read read = indices.read();
+ const int *src=read.ptr();
+
+ for (int i=0;i<surface->index_array_len;i++) {
+
+ if (surface->index_array_local) {
+
+ if (a.size<=(1<<8)) {
+ uint8_t v=src[i];
+
+ copymem(&surface->array_local[i*a.size], &v, a.size);
+ } else {
+ uint16_t v=src[i];
+
+ copymem(&surface->array_local[i*a.size], &v, a.size);
+ }
+
+ } else {
+ if (a.size<=(1<<8)) {
+ uint8_t v=src[i];
+
+ glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, i*a.size, a.size, &v );
+ } else {
+ uint16_t v=src[i];
+
+ glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, i*a.size, a.size, &v );
+
+ }
+ };
+ }
+ if (surface->index_array_local == 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
+ };
+ a.configured=true;
+ return OK;
+ } break;
+ case VS::ARRAY_VERTEX:
+ case VS::ARRAY_NORMAL: {
+
+ ERR_FAIL_COND_V( p_array.get_type() != Variant::VECTOR3_ARRAY, ERR_INVALID_PARAMETER );
+
+
+ DVector<Vector3> array = p_array;
+ ERR_FAIL_COND_V( array.size() != surface->array_len, ERR_INVALID_PARAMETER );
+
+ if (surface->array_local == 0) {
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+ };
+
+ DVector<Vector3>::Read read = array.read();
+ const Vector3* src=read.ptr();
+
+ // setting vertices means regenerating the AABB
+ if (p_type==VS::ARRAY_VERTEX)
+ surface->aabb=AABB();
+
+ for (int i=0;i<surface->array_len;i++) {
+
+
+ GLfloat vector[3]={ src[i].x, src[i].y, src[i].z };
+
+ if (surface->array_local == 0) {
+ glBufferSubData( GL_ARRAY_BUFFER, a.ofs+i*surface->stride, a.size , vector );
+ } else {
+ copymem(&surface->array_local[a.ofs+i*surface->stride], vector, a.size);
+ }
+
+ if (p_type==VS::ARRAY_VERTEX) {
+
+ if (i==0) {
+
+ surface->aabb=AABB(src[i],Vector3());
+ } else {
+
+ surface->aabb.expand_to( src[i] );
+ }
+ }
+ }
+
+ if (surface->array_local == 0) {
+ glBindBuffer(GL_ARRAY_BUFFER,0);
+ };
+
+ } break;
+ case VS::ARRAY_TANGENT: {
+
+ ERR_FAIL_COND_V( p_array.get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<real_t> array = p_array;
+
+ ERR_FAIL_COND_V( array.size() != surface->array_len*4, ERR_INVALID_PARAMETER );
+
+ if (surface->array_local == 0) {
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+ };
+
+
+ DVector<real_t>::Read read = array.read();
+ const real_t* src = read.ptr();
+
+ for (int i=0;i<surface->array_len;i++) {
+
+ GLfloat xyzw[4]={
+ src[i*4+0],
+ src[i*4+1],
+ src[i*4+2],
+ src[i*4+3]
+ };
+
+ if (surface->array_local == 0) {
+
+ glBufferSubData( GL_ARRAY_BUFFER, a.ofs+i*surface->stride, a.size , xyzw );
+ } else {
+
+ copymem(&surface->array_local[a.ofs+i*surface->stride], xyzw, a.size);
+ };
+
+ }
+
+ if (surface->array_local == 0) {
+ glBindBuffer(GL_ARRAY_BUFFER,0);
+ };
+ } break;
+ case VS::ARRAY_COLOR: {
+
+ ERR_FAIL_COND_V( p_array.get_type() != Variant::COLOR_ARRAY, ERR_INVALID_PARAMETER );
+
+
+ DVector<Color> array = p_array;
+
+ ERR_FAIL_COND_V( array.size() != surface->array_len, ERR_INVALID_PARAMETER );
+
+ if (surface->array_local == 0)
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+
+
+ DVector<Color>::Read read = array.read();
+ const Color* src = read.ptr();
+ surface->has_alpha_cache=false;
+
+ for (int i=0;i<surface->array_len;i++) {
+
+ if (src[i].a<0.98) // tolerate alpha a bit, for crappy exporters
+ surface->has_alpha_cache=true;
+ uint8_t colors[4]={ src[i].r * 255.0 , src[i].g * 255.0, src[i].b * 255.0, src[i].a * 255.0 };
+ // I'm not sure if this is correct, endianness-wise, i should re-check the GL spec
+
+ if (surface->array_local == 0)
+ glBufferSubData( GL_ARRAY_BUFFER, a.ofs+i*surface->stride, a.size , colors );
+ else
+ copymem(&surface->array_local[a.ofs+i*surface->stride], colors, a.size);
+
+ }
+
+ if (surface->array_local == 0)
+ glBindBuffer(GL_ARRAY_BUFFER,0);
+
+
+ } break;
+ case VS::ARRAY_TEX_UV: {
+
+ ERR_FAIL_COND_V( p_array.get_type() != Variant::VECTOR3_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<Vector3> array = p_array;
+
+ ERR_FAIL_COND_V( array.size() != surface->array_len , ERR_INVALID_PARAMETER);
+
+ if (surface->array_local == 0)
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+
+ DVector<Vector3>::Read read = array.read();
+
+ const Vector3 * src=read.ptr();
+
+ for (int i=0;i<surface->array_len;i++) {
+
+ GLfloat uv[2]={ src[i].x , src[i].y };
+
+ if (surface->array_local == 0)
+ glBufferSubData( GL_ARRAY_BUFFER, a.ofs+i*surface->stride, a.size , uv );
+ else
+ copymem(&surface->array_local[a.ofs+i*surface->stride], uv, a.size);
+
+ }
+
+ if (surface->array_local == 0)
+ glBindBuffer(GL_ARRAY_BUFFER,0);
+
+ } break;
+ case VS::ARRAY_BONES:
+ case VS::ARRAY_WEIGHTS: {
+
+
+ ERR_FAIL_COND_V( p_array.get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<real_t> array = p_array;
+
+ ERR_FAIL_COND_V( array.size() != surface->array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER );
+
+ if (surface->array_local == 0)
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+
+ DVector<real_t>::Read read = array.read();
+
+ const real_t * src = read.ptr();
+
+ for (int i=0;i<surface->array_len;i++) {
+
+ GLfloat data[VS::ARRAY_WEIGHTS_SIZE];
+ for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++)
+ data[j]=src[i*VS::ARRAY_WEIGHTS_SIZE+j];
+
+ if (surface->array_local == 0)
+ glBufferSubData( GL_ARRAY_BUFFER, a.ofs+i*surface->stride, a.size , data );
+ else
+ copymem(&surface->array_local[a.ofs+i*surface->stride], data, a.size);
+
+
+ }
+
+ if (surface->array_local == 0)
+ glBindBuffer(GL_ARRAY_BUFFER,0);
+ } break;
+ default: { ERR_FAIL_V(ERR_INVALID_PARAMETER);}
+ }
+
+ a.configured=true;
+
+ return OK;
+}
+Variant RasterizerIPhone::mesh_surface_get_array(RID p_mesh, int p_surface,VS::ArrayType p_type) const {
+
+ return Variant();
+}
+
+void RasterizerIPhone::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material,bool p_owned) {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_INDEX(p_surface, mesh->surfaces.size() );
+ Surface *surface = mesh->surfaces[p_surface];
+ ERR_FAIL_COND( !surface);
+
+ if (surface->material_owned && surface->material.is_valid())
+ free(surface->material);
+
+ surface->material_owned=p_owned;
+
+ surface->material=p_material;
+}
+
+RID RasterizerIPhone::mesh_surface_get_material(RID p_mesh, int p_surface) const {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND_V(!mesh,RID());
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RID() );
+ Surface *surface = mesh->surfaces[p_surface];
+ ERR_FAIL_COND_V( !surface, RID() );
+
+ return surface->material;
+}
+
+int RasterizerIPhone::mesh_surface_get_array_len(RID p_mesh, int p_surface) const {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND_V(!mesh,-1);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 );
+ Surface *surface = mesh->surfaces[p_surface];
+ ERR_FAIL_COND_V( !surface, -1 );
+
+ return surface->array_len;
+}
+int RasterizerIPhone::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND_V(!mesh,-1);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), -1 );
+ Surface *surface = mesh->surfaces[p_surface];
+ ERR_FAIL_COND_V( !surface, -1 );
+
+ return surface->index_array_len;
+}
+uint32_t RasterizerIPhone::mesh_surface_get_format(RID p_mesh, int p_surface) const {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND_V(!mesh,0);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0 );
+ Surface *surface = mesh->surfaces[p_surface];
+ ERR_FAIL_COND_V( !surface, 0 );
+
+ return surface->format;
+}
+VS::PrimitiveType RasterizerIPhone::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND_V(!mesh,VS::PRIMITIVE_POINTS);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), VS::PRIMITIVE_POINTS );
+ Surface *surface = mesh->surfaces[p_surface];
+ ERR_FAIL_COND_V( !surface, VS::PRIMITIVE_POINTS );
+
+ return surface->primitive;
+}
+
+void RasterizerIPhone::mesh_erase_surface(RID p_mesh,int p_index) {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_INDEX(p_index, mesh->surfaces.size() );
+ Surface *surface = mesh->surfaces[p_index];
+ ERR_FAIL_COND( !surface);
+
+ memdelete( mesh->surfaces[p_index] );
+ mesh->surfaces.remove(p_index);
+
+}
+int RasterizerIPhone::mesh_get_surface_count(RID p_mesh) const {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND_V(!mesh,-1);
+
+ return mesh->surfaces.size();
+}
+
+AABB RasterizerIPhone::mesh_get_aabb(RID p_mesh) const {
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND_V(!mesh,AABB());
+
+ AABB aabb;
+
+ for (int i=0;i<mesh->surfaces.size();i++) {
+
+ if (i==0)
+ aabb=mesh->surfaces[i]->aabb;
+ else
+ aabb.merge_with(mesh->surfaces[i]->aabb);
+ }
+
+ return aabb;
+}
+
+/* MULTIMESH API */
+
+RID RasterizerIPhone::multimesh_create() {
+
+ return RID();
+}
+
+void RasterizerIPhone::multimesh_set_instance_count(RID p_multimesh,int p_count) {
+
+
+}
+int RasterizerIPhone::multimesh_get_instance_count(RID p_multimesh) const {
+
+ return 0;
+}
+
+void RasterizerIPhone::multimesh_set_mesh(RID p_multimesh,RID p_mesh) {
+
+
+}
+void RasterizerIPhone::multimesh_set_aabb(RID p_multimesh,const AABB& p_aabb) {
+
+
+}
+void RasterizerIPhone::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform) {
+
+
+}
+void RasterizerIPhone::multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color) {
+
+
+}
+
+RID RasterizerIPhone::multimesh_get_mesh(RID p_multimesh) const {
+
+ return RID();
+}
+AABB RasterizerIPhone::multimesh_get_aabb(RID p_multimesh) const {
+
+ return AABB();
+}
+
+Transform RasterizerIPhone::multimesh_instance_get_transform(RID p_multimesh,int p_index) const {
+
+ return Transform();
+}
+Color RasterizerIPhone::multimesh_instance_get_color(RID p_multimesh,int p_index) const {
+
+ return Color();
+}
+
+/* POLY API */
+
+RID RasterizerIPhone::poly_create() {
+
+ return RID();
+}
+void RasterizerIPhone::poly_set_material(RID p_poly, RID p_material,bool p_owned) {
+
+
+}
+void RasterizerIPhone::poly_add_primitive(RID p_poly, const Vector<Vector3>& p_points,const Vector<Vector3>& p_normals,const Vector<Color>& p_colors,const Vector<Vector3>& p_uvs) {
+
+
+}
+void RasterizerIPhone::poly_clear(RID p_poly) {
+
+
+}
+
+AABB RasterizerIPhone::poly_get_aabb(RID p_poly) const {
+
+ return AABB();
+}
+
+
+/* PARTICLES API */
+
+RID RasterizerIPhone::particles_create() {
+
+ return RID();
+}
+
+void RasterizerIPhone::particles_set_amount(RID p_particles, int p_amount) {
+
+
+}
+int RasterizerIPhone::particles_get_amount(RID p_particles) const {
+
+ return 0;
+}
+
+void RasterizerIPhone::particles_set_emitting(RID p_particles, bool p_emitting) {
+
+
+}
+
+bool RasterizerIPhone::particles_is_emitting(RID p_particles) const {
+
+ return false;
+}
+
+void RasterizerIPhone::particles_set_visibility_aabb(RID p_particles, const AABB& p_visibility) {
+
+
+}
+AABB RasterizerIPhone::particles_get_visibility_aabb(RID p_particles) const {
+
+ return AABB();
+}
+
+void RasterizerIPhone::particles_set_emission_half_extents(RID p_particles, const Vector3& p_half_extents) {
+
+
+}
+Vector3 RasterizerIPhone::particles_get_emission_half_extents(RID p_particles) const {
+
+ return Vector3();
+}
+
+void RasterizerIPhone::particles_set_gravity_normal(RID p_particles, const Vector3& p_normal) {
+
+
+}
+Vector3 RasterizerIPhone::particles_get_gravity_normal(RID p_particles) const {
+
+ return Vector3();
+}
+
+void RasterizerIPhone::particles_set_variable(RID p_particles, VS::ParticleVariable p_variable,float p_value) {
+
+
+}
+float RasterizerIPhone::particles_get_variable(RID p_particles, VS::ParticleVariable p_variable) const {
+
+ return 0;
+}
+
+void RasterizerIPhone::particles_set_randomness(RID p_particles, VS::ParticleVariable p_variable,float p_randomness) {
+
+
+}
+float RasterizerIPhone::particles_get_randomness(RID p_particles, VS::ParticleVariable p_variable) const {
+
+ return 0;
+}
+
+void RasterizerIPhone::particles_set_color_phase_pos(RID p_particles, int p_phase, float p_pos) {
+
+
+}
+float RasterizerIPhone::particles_get_color_phase_pos(RID p_particles, int p_phase) const {
+
+ return 0;
+}
+
+void RasterizerIPhone::particles_set_color_phases(RID p_particles, int p_phases) {
+
+
+}
+int RasterizerIPhone::particles_get_color_phases(RID p_particles) const {
+
+ return 0;
+}
+
+void RasterizerIPhone::particles_set_color_phase_color(RID p_particles, int p_phase, const Color& p_color) {
+
+
+}
+Color RasterizerIPhone::particles_get_color_phase_color(RID p_particles, int p_phase) const {
+
+ return Color();
+}
+
+void RasterizerIPhone::particles_set_attractors(RID p_particles, int p_attractors) {
+
+
+}
+int RasterizerIPhone::particles_get_attractors(RID p_particles) const {
+
+ return 0;
+}
+
+void RasterizerIPhone::particles_set_attractor_pos(RID p_particles, int p_attractor, const Vector3& p_pos) {
+
+
+}
+Vector3 RasterizerIPhone::particles_get_attractor_pos(RID p_particles,int p_attractor) const {
+
+ return Vector3();
+}
+
+void RasterizerIPhone::particles_set_attractor_strength(RID p_particles, int p_attractor, float p_force) {
+
+
+}
+float RasterizerIPhone::particles_get_attractor_strength(RID p_particles,int p_attractor) const {
+
+ return 0;
+}
+
+void RasterizerIPhone::particles_set_material(RID p_particles, RID p_material,bool p_owned) {
+
+
+}
+
+RID RasterizerIPhone::particles_get_material(RID p_particles) const {
+
+ return RID();
+}
+
+AABB RasterizerIPhone::particles_get_aabb(RID p_particles) const {
+
+ return AABB();
+}
+/* BEAM API */
+
+RID RasterizerIPhone::beam_create() {
+
+ return RID();
+}
+
+void RasterizerIPhone::beam_set_point_count(RID p_beam, int p_count) {
+
+
+}
+int RasterizerIPhone::beam_get_point_count(RID p_beam) const {
+
+ return 0;
+}
+void RasterizerIPhone::beam_clear(RID p_beam) {
+
+
+}
+
+void RasterizerIPhone::beam_set_point(RID p_beam,int p_point,Vector3& p_pos) {
+
+
+}
+Vector3 RasterizerIPhone::beam_get_point(RID p_beam,int p_point) const {
+
+ return Vector3();
+}
+
+void RasterizerIPhone::beam_set_primitive(RID p_beam,VS::BeamPrimitive p_primitive) {
+
+
+}
+
+VS::BeamPrimitive RasterizerIPhone::beam_get_primitive(RID p_beam) const {
+
+ return VS::BEAM_CUBIC;
+}
+
+void RasterizerIPhone::beam_set_material(RID p_beam, RID p_material) {
+
+
+}
+RID RasterizerIPhone::beam_get_material(RID p_beam) const {
+
+ return RID();
+}
+
+AABB RasterizerIPhone::beam_get_aabb(RID p_particles) const {
+
+ return AABB();
+}
+/* SKELETON API */
+
+RID RasterizerIPhone::skeleton_create() {
+
+ Skeleton *skeleton = memnew( Skeleton );
+ ERR_FAIL_COND_V(!skeleton,RID());
+ return skeleton_owner.make_rid( skeleton );
+}
+void RasterizerIPhone::skeleton_resize(RID p_skeleton,int p_bones) {
+
+ Skeleton *skeleton = skeleton_owner.get( p_skeleton );
+ ERR_FAIL_COND(!skeleton);
+ if (p_bones == skeleton->bones.size()) {
+ return;
+ };
+ ERR_FAIL_COND( p_bones<0 || p_bones>256);
+
+ skeleton->bones.resize(p_bones);
+
+}
+int RasterizerIPhone::skeleton_get_bone_count(RID p_skeleton) const {
+
+ Skeleton *skeleton = skeleton_owner.get( p_skeleton );
+ ERR_FAIL_COND_V(!skeleton, -1);
+ return skeleton->bones.size();
+}
+void RasterizerIPhone::skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform) {
+
+ Skeleton *skeleton = skeleton_owner.get( p_skeleton );
+ ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_INDEX( p_bone, skeleton->bones.size() );
+
+ skeleton->bones[p_bone] = p_transform;
+}
+Transform RasterizerIPhone::skeleton_bone_get_transform(RID p_skeleton,int p_bone) {
+
+ Skeleton *skeleton = skeleton_owner.get( p_skeleton );
+ ERR_FAIL_COND_V(!skeleton, Transform());
+ ERR_FAIL_INDEX_V( p_bone, skeleton->bones.size(), Transform() );
+
+ // something
+ return skeleton->bones[p_bone];
+}
+
+
+/* LIGHT API */
+
+RID RasterizerIPhone::light_create(VS::LightType p_type) {
+
+ Light *light = memnew( Light );
+ light->type=p_type;
+ return light_owner.make_rid(light);
+}
+
+VS::LightType RasterizerIPhone::light_get_type(RID p_light) const {
+
+ Light *light = light_owner.get(p_light);
+ ERR_FAIL_COND_V(!light,VS::LIGHT_OMNI);
+ return light->type;
+}
+
+void RasterizerIPhone::light_set_color(RID p_light,VS::LightColor p_type, const Color& p_color) {
+
+ Light *light = light_owner.get(p_light);
+ ERR_FAIL_COND(!light);
+ ERR_FAIL_INDEX( p_type, 3 );
+ light->colors[p_type]=p_color;
+}
+Color RasterizerIPhone::light_get_color(RID p_light,VS::LightColor p_type) const {
+
+ Light *light = light_owner.get(p_light);
+ ERR_FAIL_COND_V(!light, Color());
+ ERR_FAIL_INDEX_V( p_type, 3, Color() );
+ return light->colors[p_type];
+}
+
+void RasterizerIPhone::light_set_shadow(RID p_light,bool p_enabled) {
+
+ Light *light = light_owner.get(p_light);
+ ERR_FAIL_COND(!light);
+ light->shadow_enabled=p_enabled;
+}
+
+bool RasterizerIPhone::light_has_shadow(RID p_light) const {
+
+ Light *light = light_owner.get(p_light);
+ ERR_FAIL_COND_V(!light,false);
+ return light->shadow_enabled;
+}
+
+void RasterizerIPhone::light_set_volumetric(RID p_light,bool p_enabled) {
+
+ Light *light = light_owner.get(p_light);
+ ERR_FAIL_COND(!light);
+ light->volumetric_enabled=p_enabled;
+
+}
+bool RasterizerIPhone::light_is_volumetric(RID p_light) const {
+
+ Light *light = light_owner.get(p_light);
+ ERR_FAIL_COND_V(!light,false);
+ return light->volumetric_enabled;
+}
+
+void RasterizerIPhone::light_set_projector(RID p_light,RID p_texture) {
+
+ Light *light = light_owner.get(p_light);
+ ERR_FAIL_COND(!light);
+ light->projector=p_texture;
+}
+RID RasterizerIPhone::light_get_projector(RID p_light) const {
+
+ Light *light = light_owner.get(p_light);
+ ERR_FAIL_COND_V(!light,RID());
+ return light->projector;
+}
+
+void RasterizerIPhone::light_set_var(RID p_light, VS::LightParam p_var, float p_value) {
+
+ Light * light = light_owner.get( p_light );
+ ERR_FAIL_COND(!light);
+ ERR_FAIL_INDEX( p_var, VS::LIGHT_PARAM_MAX );
+
+ light->vars[p_var]=p_value;
+}
+float RasterizerIPhone::light_get_var(RID p_light, VS::LightParam p_var) const {
+
+ Light * light = light_owner.get( p_light );
+ ERR_FAIL_COND_V(!light,0);
+
+ ERR_FAIL_INDEX_V( p_var, VS::LIGHT_PARAM_MAX,0 );
+
+ return light->vars[p_var];
+}
+
+AABB RasterizerIPhone::light_get_aabb(RID p_light) const {
+
+ Light *light = light_owner.get( p_light );
+ ERR_FAIL_COND_V(!light,AABB());
+
+ switch( light->type ) {
+
+ case VS::LIGHT_SPOT: {
+
+ float len=light->vars[VS::LIGHT_PARAM_RADIUS];
+ float size=Math::tan(Math::deg2rad(light->vars[VS::LIGHT_PARAM_SPOT_ANGLE]))*len;
+ return AABB( Vector3( -size,-size,-len ), Vector3( size*2, size*2, len ) );
+ } break;
+ case VS::LIGHT_OMNI: {
+
+ float r = light->vars[VS::LIGHT_PARAM_RADIUS];
+ return AABB( -Vector3(r,r,r), Vector3(r,r,r)*2 );
+ } break;
+ case VS::LIGHT_DIRECTIONAL: {
+
+ return AABB();
+ } break;
+ default: {}
+ }
+
+ ERR_FAIL_V( AABB() );
+}
+
+
+RID RasterizerIPhone::light_instance_create(RID p_light) {
+
+ Light *light = light_owner.get( p_light );
+ ERR_FAIL_COND_V(!light, RID());
+
+ LightInstance *light_instance = memnew( LightInstance );
+
+ light_instance->light=p_light;
+ light_instance->base=light;
+ light_instance->last_pass=0;
+
+ return light_instance_owner.make_rid( light_instance );
+}
+void RasterizerIPhone::light_instance_set_transform(RID p_light_instance,const Transform& p_transform) {
+
+ LightInstance *lighti = light_instance_owner.get( p_light_instance );
+ ERR_FAIL_COND(!lighti);
+ lighti->transform=p_transform;
+
+}
+
+void RasterizerIPhone::light_instance_set_active_hint(RID p_light_instance) {
+
+ LightInstance *lighti = light_instance_owner.get( p_light_instance );
+ ERR_FAIL_COND(!lighti);
+ lighti->last_pass=frame;
+
+}
+bool RasterizerIPhone::light_instance_has_shadow(RID p_light_instance) const {
+
+ return false;
+}
+bool RasterizerIPhone::light_instance_assign_shadow(RID p_light_instance) {
+
+ return false;
+}
+Rasterizer::ShadowType RasterizerIPhone::light_instance_get_shadow_type(RID p_light_instance) const {
+
+ return Rasterizer::SHADOW_CUBE;
+}
+int RasterizerIPhone::light_instance_get_shadow_passes(RID p_light_instance) const {
+
+ return 0;
+}
+void RasterizerIPhone::light_instance_set_pssm_split_info(RID p_light_instance, int p_split, float p_near,float p_far, const CameraMatrix& p_camera, const Transform& p_transform) {
+
+
+}
+
+/* PARTICLES INSTANCE */
+
+RID RasterizerIPhone::particles_instance_create(RID p_particles) {
+
+ return RID();
+}
+void RasterizerIPhone::particles_instance_set_transform(RID p_particles_instance,const Transform& p_transform) {
+
+
+}
+
+/* RENDER API */
+/* all calls (inside begin/end shadow) are always warranted to be in the following order: */
+
+static GLfloat rtri; // Angle For The Triangle ( NEW )
+static GLfloat rquad; // Angle For The Quad ( NEW )
+
+void RasterizerIPhone::begin_frame() {
+
+ window_size = Size2( OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height );
+
+ double time = (OS::get_singleton()->get_ticks_usec()/1000); // get msec
+ time/=1000.0; // make secs
+ time_delta=time-last_time;
+ last_time=time;
+ frame++;
+ glClearColor(0,0,1,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* nehe ?*/
+
+ #if 0
+ glViewport(0,0,window_size.width,window_size.height); // Reset The Current Viewport
+
+ glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
+ glLoadIdentity(); // Reset The Projection Matrix
+
+ // Calculate The Aspect Ratio Of The Window
+ gluPerspective(45.0f,(GLfloat)window_size.width/(GLfloat)window_size.height,0.1f,100.0f);
+
+ glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
+ glLoadIdentity(); // Reset The Modelview Matrix
+
+
+
+ glShadeModel(GL_SMOOTH); // Enable Smooth Shading
+ glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
+ glClearDepth(1.0f); // Depth Buffer Setup
+ glEnable(GL_DEPTH_TEST); // Enables Depth Testing
+ glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
+ glLoadIdentity(); // Reset The Current Modelview Matrix
+ glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
+ glRotatef(rtri,0.0f,1.0f,0.0f); // Rotate The Triangle On The Y axis ( NEW )
+ glBegin(GL_TRIANGLES); // Start Drawing A Triangle
+ glColor3f(1.0f,0.0f,0.0f); // Red
+ glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Front)
+ glColor3f(0.0f,1.0f,0.0f); // Green
+ glVertex3f(-1.0f,-1.0f, 1.0f); // Left Of Triangle (Front)
+ glColor3f(0.0f,0.0f,1.0f); // Blue
+ glVertex3f( 1.0f,-1.0f, 1.0f); // Right Of Triangle (Front)
+ glColor3f(1.0f,0.0f,0.0f); // Red
+ glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Right)
+ glColor3f(0.0f,0.0f,1.0f); // Blue
+ glVertex3f( 1.0f,-1.0f, 1.0f); // Left Of Triangle (Right)
+ glColor3f(0.0f,1.0f,0.0f); // Green
+ glVertex3f( 1.0f,-1.0f, -1.0f); // Right Of Triangle (Right)
+ glColor3f(1.0f,0.0f,0.0f); // Red
+ glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Back)
+ glColor3f(0.0f,1.0f,0.0f); // Green
+ glVertex3f( 1.0f,-1.0f, -1.0f); // Left Of Triangle (Back)
+ glColor3f(0.0f,0.0f,1.0f); // Blue
+ glVertex3f(-1.0f,-1.0f, -1.0f); // Right Of Triangle (Back)
+ glColor3f(1.0f,0.0f,0.0f); // Red
+ glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Left)
+ glColor3f(0.0f,0.0f,1.0f); // Blue
+ glVertex3f(-1.0f,-1.0f,-1.0f); // Left Of Triangle (Left)
+ glColor3f(0.0f,1.0f,0.0f); // Green
+ glVertex3f(-1.0f,-1.0f, 1.0f); // Right Of Triangle (Left)
+ glEnd(); // Done Drawing The Pyramid
+
+ glLoadIdentity(); // Reset The Current Modelview Matrix
+ glTranslatef(1.5f,0.0f,-7.0f); // Move Right 1.5 Units And Into The Screen 7.0
+ glRotatef(rquad,1.0f,1.0f,1.0f); // Rotate The Quad On The X axis ( NEW )
+ glBegin(GL_QUADS); // Draw A Quad
+ glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
+ glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Top)
+ glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Top)
+ glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Quad (Top)
+ glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right Of The Quad (Top)
+ glColor3f(1.0f,0.5f,0.0f); // Set The Color To Orange
+ glVertex3f( 1.0f,-1.0f, 1.0f); // Top Right Of The Quad (Bottom)
+ glVertex3f(-1.0f,-1.0f, 1.0f); // Top Left Of The Quad (Bottom)
+ glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Bottom)
+ glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Bottom)
+ glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
+ glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Front)
+ glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Front)
+ glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Front)
+ glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Front)
+ glColor3f(1.0f,1.0f,0.0f); // Set The Color To Yellow
+ glVertex3f( 1.0f,-1.0f,-1.0f); // Top Right Of The Quad (Back)
+ glVertex3f(-1.0f,-1.0f,-1.0f); // Top Left Of The Quad (Back)
+ glVertex3f(-1.0f, 1.0f,-1.0f); // Bottom Left Of The Quad (Back)
+ glVertex3f( 1.0f, 1.0f,-1.0f); // Bottom Right Of The Quad (Back)
+ glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
+ glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Left)
+ glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Left)
+ glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Left)
+ glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Left)
+ glColor3f(1.0f,0.0f,1.0f); // Set The Color To Violet
+ glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Right)
+ glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Right)
+ glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Right)
+ glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Right)
+ glEnd(); // Done Drawing The Quad
+
+ rtri+=0.2f; // Increase The Rotation Variable For The Triangle ( NEW )
+ rquad-=0.15f; // Decrease The Rotation Variable For The Quad ( NEW )
+
+ #endif
+
+}
+
+void RasterizerIPhone::set_viewport(const VS::ViewportRect& p_viewport) {
+
+
+ viewport=p_viewport;
+ canvas_transform=Transform();
+ canvas_transform.translate(-(viewport.width / 2.0f), -(viewport.height / 2.0f), 0.0f);
+ canvas_transform.scale( Vector3( 2.0f / viewport.width, -2.0f / viewport.height, 1.0f ) );
+
+ glViewport( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height );
+}
+
+void RasterizerIPhone::begin_scene(RID p_fx,VS::ScenarioDebugMode p_debug) {
+
+ opaque_render_list.clear();
+ alpha_render_list.clear();
+ light_instance_count=0;
+ scene_fx = p_fx.is_valid() ? fx_owner.get(p_fx) : NULL;
+};
+
+void RasterizerIPhone::begin_shadow_map( RID p_light_instance, int p_shadow_pass ) {
+
+
+}
+
+void RasterizerIPhone::set_camera(const Transform& p_world,const CameraMatrix& p_projection) {
+
+ camera_transform=p_world;
+ camera_transform_inverse=camera_transform.inverse();
+ camera_projection=p_projection;
+ camera_plane = Plane( camera_transform.origin, camera_transform.basis.get_axis(2) );
+ camera_z_near=camera_projection.get_z_near();
+camera_z_far=camera_projection.get_z_far();
+ camera_projection.get_viewport_size(camera_vp_size.x,camera_vp_size.y);
+}
+
+void RasterizerIPhone::add_light( RID p_light_instance ) {
+
+#define LIGHT_FADE_TRESHOLD 0.05
+
+ ERR_FAIL_COND( light_instance_count >= MAX_LIGHTS );
+
+ LightInstance *li = light_instance_owner.get(p_light_instance);
+ ERR_FAIL_COND(!li);
+
+ /* make light hash */
+
+ // actually, not really a hash, but helps to sort the lights
+ // and avoid recompiling redudant shader versions
+
+ li->hash_aux=li->base->type;
+
+ if (li->base->shadow_enabled)
+ li->hash_aux|=(1<<3);
+
+ if (li->base->projector.is_valid())
+ li->hash_aux|=(1<<4);
+
+ if (li->base->shadow_enabled && li->base->volumetric_enabled)
+ li->hash_aux|=(1<<5);
+
+ switch(li->base->type) {
+
+ case VisualServer::LIGHT_DIRECTIONAL: {
+
+ Vector3 dir = li->transform.basis.get_axis(2);
+ li->light_vector.x=dir.x;
+ li->light_vector.y=dir.y;
+ li->light_vector.z=dir.z;
+
+ } break;
+ case VisualServer::LIGHT_OMNI: {
+
+ float radius = li->base->vars[VisualServer::LIGHT_PARAM_RADIUS];
+ if (radius==0)
+ radius=0.0001;
+ li->linear_att=(1/LIGHT_FADE_TRESHOLD)/radius;
+ li->light_vector.x=li->transform.origin.x;
+ li->light_vector.y=li->transform.origin.y;
+ li->light_vector.z=li->transform.origin.z;
+
+ } break;
+ case VisualServer::LIGHT_SPOT: {
+
+ float radius = li->base->vars[VisualServer::LIGHT_PARAM_RADIUS];
+ if (radius==0)
+ radius=0.0001;
+ li->linear_att=(1/LIGHT_FADE_TRESHOLD)/radius;
+ li->light_vector.x=li->transform.origin.x;
+ li->light_vector.y=li->transform.origin.y;
+ li->light_vector.z=li->transform.origin.z;
+ Vector3 dir = -li->transform.basis.get_axis(2);
+ li->spot_vector.x=dir.x;
+ li->spot_vector.y=dir.y;
+ li->spot_vector.z=dir.z;
+
+ } break;
+ }
+
+ light_instances[light_instance_count++]=li;
+}
+
+void RasterizerIPhone::_add_geometry( const Geometry* p_geometry, const Transform& p_world, uint32_t p_vertex_format, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides,const Skeleton* p_skeleton, GeometryOwner *p_owner) {
+
+ Material *m=NULL;
+
+ if (p_geometry->material.is_valid())
+ m=material_owner.get( p_geometry->material );
+
+ if (!m) {
+ m=material_owner.get( default_material );
+ }
+
+ ERR_FAIL_COND(!m);
+
+ LightInstance *lights[RenderList::MAX_LIGHTS];
+ int light_count=0;
+
+ RenderList *render_list=&opaque_render_list;
+ if (p_geometry->has_alpha || m->detail_blend_mode!=VS::MATERIAL_BLEND_MODE_MIX) {
+ render_list = &alpha_render_list;
+ };
+
+ if (!m->flags[VS::MATERIAL_FLAG_UNSHADED]) {
+
+ light_count=p_light_count;
+ for(int i=0;i<light_count;i++) {
+ lights[i]=light_instance_owner.get( p_light_instances[i] );
+ }
+ }
+
+ render_list->add_element( p_geometry, m, p_world, lights, light_count, p_material_overrides,p_skeleton, camera_plane.distance(p_world.origin), p_owner );
+}
+
+void RasterizerIPhone::add_mesh( RID p_mesh, const Transform* p_world, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides, RID p_skeleton) {
+
+ Mesh *mesh = mesh_owner.get(p_mesh);
+
+ int ssize = mesh->surfaces.size();
+
+ for (int i=0;i<ssize;i++) {
+
+ Surface *s = mesh->surfaces[i];
+ Skeleton *sk = p_skeleton.is_valid()?skeleton_owner.get(p_skeleton):NULL;
+
+ _add_geometry(s,*p_world,s->format,p_light_instances,p_light_count,p_material_overrides,sk,NULL);
+ }
+
+ mesh->last_pass=frame;
+}
+
+void RasterizerIPhone::add_multimesh( RID p_multimesh, const Transform* p_world, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides) {
+
+
+}
+
+void RasterizerIPhone::add_poly( RID p_poly, const Transform* p_world, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides) {
+
+ Poly *p = poly_owner.get(p_poly);
+ if (!p->primitives.empty()) {
+ const Poly::Primitive *pp = &p->primitives[0];
+
+ uint32_t format=VisualServer::ARRAY_FORMAT_VERTEX;
+
+ if (!pp->normals.empty())
+ format|=VisualServer::ARRAY_FORMAT_NORMAL;
+ if (!pp->colors.empty())
+ format|=VisualServer::ARRAY_FORMAT_COLOR;
+ if (!pp->uvs.empty())
+ format|=VisualServer::ARRAY_TEX_UV;
+
+ _add_geometry(p,*p_world,format,p_light_instances,p_light_count,p_material_overrides,NULL, NULL);
+ }
+}
+
+void RasterizerIPhone::add_beam( RID p_beam, const Transform* p_world, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides) {
+
+
+}
+
+void RasterizerIPhone::add_particles( RID p_particle_instance, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides) {
+
+
+}
+
+void RasterizerIPhone::_setup_material(const Geometry *p_geometry,const Material *p_material) {
+
+ if (p_material->flags[VS::MATERIAL_FLAG_DOUBLE_SIDED])
+ glDisable(GL_CULL_FACE);
+ else {
+ glEnable(GL_CULL_FACE);
+ glCullFace( (p_material->flags[VS::MATERIAL_FLAG_INVERT_FACES])?GL_FRONT:GL_BACK);
+ }
+
+ glEnable(GL_COLOR_MATERIAL); /* unused, unless color array */
+ //glColorMaterial( GL_FRONT_AND_BACK, GL_DIFFUSE );
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+
+ ///ambient @TODO offer global ambient group option
+ float ambient_rgba[4]={
+ 1,
+ 1,
+ 1,
+ 1.0
+ };
+ glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient_rgba);
+
+ ///diffuse
+ const Color &diffuse_color=p_material->parameters[VS::FIXED_MATERIAL_PARAM_DIFFUSE];
+ float diffuse_rgba[4]={
+ (float)diffuse_color.r,
+ (float)diffuse_color.g,
+ (float)diffuse_color.b,
+ (float)diffuse_color.a
+ };
+
+ glColor4f( diffuse_rgba[0],diffuse_rgba[1],diffuse_rgba[2],diffuse_rgba[3]);
+
+ glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse_rgba);
+
+ //specular
+
+ const Color &specular_color=p_material->parameters[VS::FIXED_MATERIAL_PARAM_SPECULAR];
+ float specular_rgba[4]={
+ (float)specular_color.r,
+ (float)specular_color.g,
+ (float)specular_color.b,
+ 1.0
+ };
+
+ glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,specular_rgba);
+
+ const Color &emission_color=p_material->parameters[VS::FIXED_MATERIAL_PARAM_EMISSION];
+ float emission_rgba[4]={
+ (float)emission_color.r,
+ (float)emission_color.g,
+ (float)emission_color.b,
+ 1.0
+ };
+
+ glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,emission_rgba);
+
+ glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,p_material->parameters[VS::FIXED_MATERIAL_PARAM_SPECULAR_EXP]);
+
+ if (p_material->flags[VS::MATERIAL_FLAG_UNSHADED]) {
+ glDisable(GL_LIGHTING);
+ } else {
+ glEnable(GL_LIGHTING);
+ glDisable(GL_LIGHTING);
+ }
+
+ //depth test?
+ /*
+ if (p_material->flags[VS::MATERIAL_FLAG_WIREFRAME])
+ glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
+ else
+ glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
+ */
+ if (p_material->textures[VS::FIXED_MATERIAL_PARAM_DIFFUSE]) {
+
+ Texture *texture = texture_owner.get( p_material->textures[VS::FIXED_MATERIAL_PARAM_DIFFUSE] );
+ ERR_FAIL_COND(!texture);
+ glActiveTexture(GL_TEXTURE0);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture( GL_TEXTURE_2D,texture->tex_id );
+ };
+};
+
+void RasterizerIPhone::_setup_light(LightInstance* p_instance, int p_idx) {
+
+ Light* ld = p_instance->base;
+
+ int glid = GL_LIGHT0 + p_idx;
+ glLightfv(glid , GL_AMBIENT, ld->colors[VS::LIGHT_COLOR_AMBIENT].components );
+ glLightfv(glid, GL_DIFFUSE, ld->colors[VS::LIGHT_COLOR_DIFFUSE].components );
+ glLightfv(glid, GL_SPECULAR, ld->colors[VS::LIGHT_COLOR_SPECULAR].components );
+
+
+
+ switch(ld->type) {
+
+ case VS::LIGHT_DIRECTIONAL: {
+ /* This doesnt have attenuation */
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ Vector3 v(0.0,0.0,-1.0); // directional lights point up by default
+ v = p_instance->transform.get_basis().xform( v );
+ v = camera_transform_inverse.get_basis().xform( v );
+ v.normalize(); // this sucks, so it will be optimized at some point
+ v = -v;
+ float lightpos[4]={v.x,v.y,v.z,0.0};
+
+ glLightfv(glid,GL_POSITION,lightpos); //at modelview
+
+ glPopMatrix();
+
+ } break;
+ case VS::LIGHT_OMNI: {
+
+ glLightf(glid,GL_SPOT_CUTOFF,180.0);
+ glLightf(glid,GL_CONSTANT_ATTENUATION, ld->vars[VS::LIGHT_PARAM_ATTENUATION]);
+ glLightf(glid,GL_LINEAR_ATTENUATION, ld->vars[VS::LIGHT_PARAM_RADIUS]);
+ glLightf(glid,GL_QUADRATIC_ATTENUATION, ld->vars[VS::LIGHT_PARAM_ENERGY]); // wut?
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ Vector3 pos = p_instance->transform.get_origin();
+ pos = camera_transform_inverse.xform(pos);
+ float lightpos[4]={pos.x,pos.y,pos.z,1.0};
+ glLightfv(glid,GL_POSITION,lightpos); //at modelview
+
+ glPopMatrix();
+
+ } break;
+ case VS::LIGHT_SPOT: {
+
+ glLightf(glid,GL_SPOT_CUTOFF, ld->vars[VS::LIGHT_PARAM_SPOT_ANGLE]);
+ glLightf(glid,GL_SPOT_EXPONENT, ld->vars[VS::LIGHT_PARAM_SPOT_ATTENUATION]);
+ glLightf(glid,GL_CONSTANT_ATTENUATION, ld->vars[VS::LIGHT_PARAM_ATTENUATION]);
+ glLightf(glid,GL_LINEAR_ATTENUATION, ld->vars[VS::LIGHT_PARAM_RADIUS]);
+ glLightf(glid,GL_QUADRATIC_ATTENUATION, ld->vars[VS::LIGHT_PARAM_ENERGY]); // wut?
+
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ Vector3 v(0.0,0.0,-1.0); // directional lights point up by default
+ v = p_instance->transform.get_basis().xform( v );
+ v = camera_transform_inverse.get_basis().xform( v );
+ v.normalize(); // this sucks, so it will be optimized at some point
+ float lightdir[4]={v.x, v.y, v.z, 1.0};
+ glLightfv(glid,GL_SPOT_DIRECTION,lightdir); //at modelview
+
+ v = p_instance->transform.get_origin();
+ v = camera_transform_inverse.xform(v);
+ float lightpos[4]={v.x,v.y,v.z,1.0};
+ glLightfv(glid,GL_POSITION,lightpos); //at modelview
+
+
+ glPopMatrix();
+
+
+ } break;
+ default: break;
+ }
+};
+
+void RasterizerIPhone::_setup_lights(LightInstance **p_lights,int p_light_count) {
+
+ for (int i=0; i<MAX_LIGHTS; i++) {
+
+ if (i<p_light_count) {
+ glEnable(GL_LIGHT0 + i);
+ _setup_light(p_lights[i], i);
+ } else {
+ glDisable(GL_LIGHT0 + i);
+ }
+ }
+}
+
+static const int gl_client_states[] = {
+
+ GL_VERTEX_ARRAY,
+ GL_NORMAL_ARRAY,
+ -1, // ARRAY_TANGENT
+ GL_COLOR_ARRAY,
+ GL_TEXTURE_COORD_ARRAY, // ARRAY_TEX_UV
+ GL_TEXTURE_COORD_ARRAY, // ARRAY_TEX_UV2
+ -1, // ARRAY_BONES
+ -1, // ARRAY_WEIGHTS
+ -1, // ARRAY_INDEX
+};
+
+void RasterizerIPhone::_setup_geometry(const Geometry *p_geometry, const Material* p_material) {
+
+
+ switch(p_geometry->type) {
+
+ case Geometry::GEOMETRY_SURFACE: {
+
+ Surface *surf = (Surface*)p_geometry;
+ uint8_t *base=0;
+ bool use_VBO = (surf->array_local==0);
+
+ if (!use_VBO) {
+
+ base = surf->array_local;
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ } else {
+
+ glBindBuffer(GL_ARRAY_BUFFER, surf->vertex_id);
+ };
+
+ const Surface::ArrayData* a=surf->array;
+ for (int i=0;i<VS::ARRAY_MAX;i++) {
+
+ const Surface::ArrayData& ad=surf->array[i];
+ if (ad.size==0) {
+ if (gl_client_states[i] != -1) {
+ glDisableClientState(gl_client_states[i]);
+ };
+ continue; // this one is disabled.
+ }
+ ERR_CONTINUE( !ad.configured );
+
+ if (gl_client_states[i] != -1) {
+ glEnableClientState(gl_client_states[i]);
+ };
+
+ switch (i) {
+
+ case VS::ARRAY_VERTEX:
+ if (!use_VBO)
+ glVertexPointer(3,GL_FLOAT,surf->stride,(GLvoid*)&base[a->ofs]);
+ else
+ if (surf->array[VS::ARRAY_BONES].size)
+ glVertexPointer(3, GL_FLOAT, 0, skinned_buffer);
+ else
+ glVertexPointer(3,GL_FLOAT,surf->stride,(GLvoid*)a->ofs);
+ break;
+
+ case VS::ARRAY_NORMAL:
+ if (use_VBO)
+ glNormalPointer(GL_FLOAT,surf->stride,(GLvoid*)a->ofs);
+ else
+ glNormalPointer(GL_FLOAT,surf->stride,(GLvoid*)&base[a->ofs]);
+ break;
+ case VS::ARRAY_TANGENT:
+ break;
+ case VS::ARRAY_COLOR:
+ if (use_VBO)
+ glColorPointer(4,GL_UNSIGNED_BYTE,surf->stride,(GLvoid*)a->ofs);
+ else
+ glColorPointer(4,GL_UNSIGNED_BYTE,surf->stride,(GLvoid*)&base[a->ofs]);
+ break;
+ case VS::ARRAY_TEX_UV:
+ case VS::ARRAY_TEX_UV2:
+ if (use_VBO)
+ glTexCoordPointer(2,GL_FLOAT,surf->stride,(GLvoid*)a->ofs);
+ else
+ glTexCoordPointer(2,GL_FLOAT,surf->stride,&base[a->ofs]);
+ break;
+ case VS::ARRAY_BONES:
+ case VS::ARRAY_WEIGHTS:
+ case VS::ARRAY_INDEX:
+ break;
+ };
+ }
+
+
+ // process skeleton here
+
+ } break;
+
+ default: break;
+
+ };
+};
+
+static const GLenum gl_primitive[]={
+ GL_POINTS,
+ GL_LINES,
+ GL_LINE_STRIP,
+ GL_LINE_LOOP,
+ GL_TRIANGLES,
+ GL_TRIANGLE_STRIP,
+ GL_TRIANGLE_FAN
+};
+
+void RasterizerIPhone::_render(const Geometry *p_geometry,const Material *p_material, const Skeleton* p_skeleton) {
+
+
+ switch(p_geometry->type) {
+
+ case Geometry::GEOMETRY_SURFACE: {
+
+
+ Surface *s = (Surface*)p_geometry;
+
+ if (s->index_array_len>0) {
+
+ if (s->index_array_local) {
+
+ glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->index_array_len>(1<<8))?GL_UNSIGNED_SHORT:GL_UNSIGNED_BYTE, s->index_array_local);
+
+ } else {
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,s->index_id);
+ glDrawElements(gl_primitive[s->primitive],s->index_array_len, (s->index_array_len>(1<<8))?GL_UNSIGNED_SHORT:GL_UNSIGNED_BYTE,0);
+ }
+
+
+ } else {
+
+ glDrawArrays(gl_primitive[s->primitive],0,s->array_len);
+
+ };
+ } break;
+
+ default: break;
+ };
+};
+
+void RasterizerIPhone::_render_list_forward(RenderList *p_render_list) {
+
+ const Material *prev_material=NULL;
+ uint64_t prev_light_hash=0;
+ const Skeleton *prev_skeleton=NULL;
+ const Geometry *prev_geometry=NULL;
+ const ParamOverrideMap* prev_overrides=NULL; // make it diferent than NULL
+
+ Geometry::Type prev_geometry_type=Geometry::GEOMETRY_INVALID;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(&camera_projection.matrix[0][0]);
+
+ for (int i=0;i<p_render_list->element_count;i++) {
+
+ RenderList::Element *e = p_render_list->elements[i];
+ const Material *material = e->material;
+ uint64_t light_hash = e->light_hash;
+ const Skeleton *skeleton = e->skeleton;
+ const Geometry *geometry = e->geometry;
+ const ParamOverrideMap* material_overrides=e->material_overrides;
+
+ if (material!=prev_material || geometry->type!=prev_geometry_type) {
+ _setup_material(e->geometry,material);
+ //_setup_material_overrides(e->material,NULL,material_overrides);
+ //_setup_material_skeleton(material,skeleton);
+ } else {
+
+ if (material_overrides != prev_overrides) {
+
+ //_setup_material_overrides(e->material,prev_overrides,material_overrides);
+ }
+
+ if (prev_skeleton!=skeleton) {
+ //_setup_material_skeleton(material,skeleton);
+ };
+ }
+
+ if (geometry!=prev_geometry || geometry->type!=prev_geometry_type) {
+
+ _setup_geometry(geometry, material);
+ };
+
+ if (i==0 || light_hash!=prev_light_hash)
+ _setup_lights(e->lights,e->light_count);
+
+ glMatrixMode(GL_MODELVIEW);
+ _gl_load_transform(camera_transform_inverse);
+ _gl_mult_transform(e->transform);
+
+ _render(geometry, material, skeleton);
+
+ prev_material=material;
+ prev_skeleton=skeleton;
+ prev_geometry=geometry;
+ prev_light_hash=e->light_hash;
+ prev_geometry_type=geometry->type;
+ prev_overrides=material_overrides;
+ }
+};
+
+void RasterizerIPhone::end_scene() {
+
+ glEnable(GL_BLEND);
+ glDepthMask(GL_FALSE);
+
+ opaque_render_list.sort_mat_light();
+ _render_list_forward(&opaque_render_list);
+
+ glDisable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+
+ alpha_render_list.sort_z();
+ _render_list_forward(&alpha_render_list);
+
+
+}
+void RasterizerIPhone::end_shadow_map() {
+
+
+}
+
+void RasterizerIPhone::end_frame() {
+
+ //ContextGL::get_singleton()->swap_buffers();
+}
+
+/* CANVAS API */
+
+void RasterizerIPhone::canvas_begin() {
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glLineWidth(1.0);
+ glDisable(GL_LIGHTING);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+}
+void RasterizerIPhone::canvas_set_transparency(float p_transparency) {
+
+
+}
+
+void RasterizerIPhone::canvas_set_rect(const Rect2& p_rect, bool p_clip) {
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glScalef(2.0 / window_size.x, -2.0 / window_size.y, 0);
+ glTranslatef((-(window_size.x / 2.0)) + p_rect.pos.x, (-(window_size.y / 2.0)) + p_rect.pos.y, 0);
+
+ if (p_clip) {
+
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(viewport.x+p_rect.pos.x,viewport.y+ (viewport.height-(p_rect.pos.y+p_rect.size.height)),
+ p_rect.size.width,p_rect.size.height);
+ } else {
+
+ glDisable(GL_SCISSOR_TEST);
+ }
+
+
+}
+void RasterizerIPhone::canvas_draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width) {
+
+ glColor4f(1, 1, 1, 1);
+
+ float verts[6]={
+ p_from.x,p_from.y,0,
+ p_to.x,p_to.y,0
+ };
+
+ float colors[]={
+ p_color.r, p_color.g, p_color.b, p_color.a,
+ p_color.r, p_color.g, p_color.b, p_color.a,
+ };
+ glLineWidth(p_width);
+ _draw_primitive(2,verts,0,colors,0);
+}
+
+static void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size ) {
+
+ float texcoords[]= {
+ p_src_region.pos.x/p_tex_size.width,
+ p_src_region.pos.y/p_tex_size.height,
+
+ (p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width,
+ p_src_region.pos.y/p_tex_size.height,
+
+ (p_src_region.pos.x+p_src_region.size.width)/p_tex_size.width,
+ (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height,
+
+ p_src_region.pos.x/p_tex_size.width,
+ (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height,
+ };
+
+ float coords[]= {
+ p_rect.pos.x, p_rect.pos.y, 0,
+ p_rect.pos.x+p_rect.size.width, p_rect.pos.y, 0,
+ p_rect.pos.x+p_rect.size.width, p_rect.pos.y+p_rect.size.height, 0,
+ p_rect.pos.x,p_rect.pos.y+p_rect.size.height, 0
+ };
+
+ _draw_primitive(4,coords,0,0,texcoords);
+}
+
+static void _draw_quad(const Rect2& p_rect) {
+
+ float coords[]= {
+ p_rect.pos.x,p_rect.pos.y, 0,
+ p_rect.pos.x+p_rect.size.width,p_rect.pos.y, 0,
+ p_rect.pos.x+p_rect.size.width,p_rect.pos.y+p_rect.size.height, 0,
+ p_rect.pos.x,p_rect.pos.y+p_rect.size.height, 0
+ };
+
+ _draw_primitive(4,coords,0,0,0);
+
+}
+
+void RasterizerIPhone::canvas_draw_rect(const Rect2& p_rect, bool p_region, const Rect2& p_source,bool p_tile,RID p_texture,const Color& p_modulate) {
+
+ glColor4f(p_modulate.r, p_modulate.g, p_modulate.b, p_modulate.a);
+
+ if ( p_texture.is_valid() ) {
+
+ glEnable(GL_TEXTURE_2D);
+ Texture *texture = texture_owner.get( p_texture );
+ ERR_FAIL_COND(!texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture( GL_TEXTURE_2D,texture->tex_id );
+
+ if (!p_region) {
+
+ Rect2 region = Rect2(0,0,texture->width,texture->height);
+ _draw_textured_quad(p_rect,region,region.size);
+
+ } else {
+
+ _draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height) );
+
+ }
+ } else {
+
+ _draw_quad( p_rect );
+
+ }
+
+
+}
+void RasterizerIPhone::canvas_draw_style_box(const Rect2& p_rect, RID p_texture,const float *p_margin, bool p_draw_center) {
+
+ glColor4f(1, 1, 1, 1);
+
+ Texture *texture = texture_owner.get( p_texture );
+ ERR_FAIL_COND(!texture);
+
+ glEnable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture( GL_TEXTURE_2D,texture->tex_id );
+
+
+ /* CORNERS */
+
+ _draw_textured_quad( // top left
+ Rect2( p_rect.pos, Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_TOP])),
+ Rect2( Point2(), Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_TOP])),
+ Size2( texture->width, texture->height ) );
+
+ _draw_textured_quad( // top right
+ Rect2( Point2( p_rect.pos.x + p_rect.size.width - p_margin[MARGIN_RIGHT], p_rect.pos.y), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_TOP])),
+ Rect2( Point2(texture->width-p_margin[MARGIN_RIGHT],0), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_TOP])),
+ Size2( texture->width, texture->height ) );
+
+
+ _draw_textured_quad( // bottom left
+ Rect2( Point2(p_rect.pos.x,p_rect.pos.y + p_rect.size.height - p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_BOTTOM])),
+ Rect2( Point2(0,texture->height-p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_LEFT],p_margin[MARGIN_BOTTOM])),
+ Size2( texture->width, texture->height ) );
+
+ _draw_textured_quad( // bottom right
+ Rect2( Point2( p_rect.pos.x + p_rect.size.width - p_margin[MARGIN_RIGHT], p_rect.pos.y + p_rect.size.height - p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_BOTTOM])),
+ Rect2( Point2(texture->width-p_margin[MARGIN_RIGHT],texture->height-p_margin[MARGIN_BOTTOM]), Size2(p_margin[MARGIN_RIGHT],p_margin[MARGIN_BOTTOM])),
+ Size2( texture->width, texture->height ) );
+
+ Rect2 rect_center( p_rect.pos+Point2( p_margin[MARGIN_LEFT], p_margin[MARGIN_TOP]), Size2( p_rect.size.width - p_margin[MARGIN_LEFT] - p_margin[MARGIN_RIGHT], p_rect.size.height - p_margin[MARGIN_TOP] - p_margin[MARGIN_BOTTOM] ));
+
+ Rect2 src_center( Point2( p_margin[MARGIN_LEFT], p_margin[MARGIN_TOP]), Size2( texture->width - p_margin[MARGIN_LEFT] - p_margin[MARGIN_RIGHT], texture->height - p_margin[MARGIN_TOP] - p_margin[MARGIN_BOTTOM] ));
+
+
+ _draw_textured_quad( // top
+ Rect2( Point2(rect_center.pos.x,p_rect.pos.y),Size2(rect_center.size.width,p_margin[MARGIN_TOP])),
+ Rect2( Point2(p_margin[MARGIN_LEFT],0), Size2(src_center.size.width,p_margin[MARGIN_TOP])),
+ Size2( texture->width, texture->height ) );
+
+ _draw_textured_quad( // bottom
+ Rect2( Point2(rect_center.pos.x,rect_center.pos.y+rect_center.size.height),Size2(rect_center.size.width,p_margin[MARGIN_BOTTOM])),
+ Rect2( Point2(p_margin[MARGIN_LEFT],src_center.pos.y+src_center.size.height), Size2(src_center.size.width,p_margin[MARGIN_BOTTOM])),
+ Size2( texture->width, texture->height ) );
+
+ _draw_textured_quad( // left
+ Rect2( Point2(p_rect.pos.x,rect_center.pos.y),Size2(p_margin[MARGIN_LEFT],rect_center.size.height)),
+ Rect2( Point2(0,p_margin[MARGIN_TOP]), Size2(p_margin[MARGIN_LEFT],src_center.size.height)),
+ Size2( texture->width, texture->height ) );
+
+ _draw_textured_quad( // right
+ Rect2( Point2(rect_center.pos.x+rect_center.size.width,rect_center.pos.y),Size2(p_margin[MARGIN_RIGHT],rect_center.size.height)),
+ Rect2( Point2(src_center.pos.x+src_center.size.width,p_margin[MARGIN_TOP]), Size2(p_margin[MARGIN_RIGHT],src_center.size.height)),
+ Size2( texture->width, texture->height ) );
+
+ if (p_draw_center) {
+
+ _draw_textured_quad(
+ rect_center,
+ src_center,
+ Size2( texture->width, texture->height ));
+ }
+
+}
+void RasterizerIPhone::canvas_draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture) {
+
+ ERR_FAIL_COND(p_points.size()<1);
+ float verts[12];
+ float uvs[8];
+ float colors[16];
+
+ glColor4f(1, 1, 1, 1);
+
+ int idx = 0;
+ for(int i=0;i<p_points.size();i++) {
+
+ verts[idx++]=p_points[i].x;
+ verts[idx++]=p_points[i].y;
+ verts[idx++]=0;
+ }
+
+ idx = 0;
+ for(int i=0;i<p_uvs.size();i++) {
+
+ uvs[idx++] = p_uvs[i].x;
+ uvs[idx++] = p_uvs[i].y;
+ }
+
+ idx = 0;
+ for (int i=0; i<p_colors.size(); i++) {
+
+ colors[idx++] = p_colors[i].r;
+ colors[idx++] = p_colors[i].g;
+ colors[idx++] = p_colors[i].b;
+ colors[idx++] = p_colors[i].a;
+ };
+
+ if (p_texture.is_valid()) {
+ glEnable(GL_TEXTURE_2D);
+ Texture *texture = texture_owner.get( p_texture );
+ if (texture) {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture( GL_TEXTURE_2D,texture->tex_id );
+ }
+ }
+
+ _draw_primitive(p_points.size(),&verts[0],NULL,p_colors.size()?&colors[0]:NULL,p_uvs.size()?uvs:NULL);
+
+}
+
+/* FX */
+
+RID RasterizerIPhone::fx_create() {
+
+ return RID();
+}
+void RasterizerIPhone::fx_get_effects(RID p_fx,List<String> *p_effects) const {
+
+
+}
+void RasterizerIPhone::fx_set_active(RID p_fx,const String& p_effect, bool p_active) {
+
+
+}
+bool RasterizerIPhone::fx_is_active(RID p_fx,const String& p_effect) const {
+
+ return false;
+}
+void RasterizerIPhone::fx_get_effect_params(RID p_fx,const String& p_effect,List<PropertyInfo> *p_params) const {
+
+
+}
+Variant RasterizerIPhone::fx_get_effect_param(RID p_fx,const String& p_effect,const String& p_param) const {
+
+ return Variant();
+}
+void RasterizerIPhone::fx_set_effect_param(RID p_fx,const String& p_effect, const String& p_param, const Variant& p_pvalue) {
+
+
+}
+
+/*MISC*/
+
+bool RasterizerIPhone::is_texture(const RID& p_rid) const {
+
+ return texture_owner.owns(p_rid);
+}
+bool RasterizerIPhone::is_material(const RID& p_rid) const {
+
+ return material_owner.owns(p_rid);
+}
+bool RasterizerIPhone::is_mesh(const RID& p_rid) const {
+
+ return mesh_owner.owns(p_rid);
+}
+bool RasterizerIPhone::is_multimesh(const RID& p_rid) const {
+
+ return false;
+}
+bool RasterizerIPhone::is_poly(const RID& p_rid) const {
+
+ return poly_owner.owns(p_rid);
+}
+bool RasterizerIPhone::is_particles(const RID &p_beam) const {
+
+ return false;
+}
+
+bool RasterizerIPhone::is_beam(const RID &p_beam) const {
+
+ return false;
+}
+
+bool RasterizerIPhone::is_light(const RID& p_rid) const {
+
+ return light_owner.owns(p_rid);
+}
+bool RasterizerIPhone::is_light_instance(const RID& p_rid) const {
+
+ return light_instance_owner.owns(p_rid);
+}
+bool RasterizerIPhone::is_particles_instance(const RID& p_rid) const {
+
+ return false;
+}
+bool RasterizerIPhone::is_skeleton(const RID& p_rid) const {
+
+ return skeleton_owner.owns(p_rid);
+}
+bool RasterizerIPhone::is_fx(const RID& p_rid) const {
+
+ return fx_owner.owns(p_rid);
+}
+bool RasterizerIPhone::is_shader(const RID& p_rid) const {
+
+ return false;
+}
+
+void RasterizerIPhone::free(const RID& p_rid) const {
+
+ if (texture_owner.owns(p_rid)) {
+
+ // delete the texture
+ Texture *texture = texture_owner.get(p_rid);
+
+ glDeleteTextures( 1,&texture->tex_id );
+
+ texture_owner.free(p_rid);
+ memdelete(texture);
+
+ } else if (material_owner.owns(p_rid)) {
+
+ Material *material = material_owner.get( p_rid );
+ ERR_FAIL_COND(!material);
+
+ material_owner.free(p_rid);
+ memdelete(material);
+
+ } else if (mesh_owner.owns(p_rid)) {
+
+ Mesh *mesh = mesh_owner.get(p_rid);
+ ERR_FAIL_COND(!mesh);
+ for (int i=0;i<mesh->surfaces.size();i++) {
+
+ Surface *surface = mesh->surfaces[i];
+ if (surface->array_local != 0) {
+ memfree(surface->array_local);
+ };
+ if (surface->index_array_local != 0) {
+ memfree(surface->index_array_local);
+ };
+
+ if (surface->vertex_id)
+ glDeleteBuffers(1,&surface->vertex_id);
+ if (surface->index_id)
+ glDeleteBuffers(1,&surface->index_id);
+
+ memdelete( surface );
+ };
+
+ mesh->surfaces.clear();
+
+ mesh_owner.free(p_rid);
+ memdelete(mesh);
+
+ } else if (skeleton_owner.owns(p_rid)) {
+
+ Skeleton *skeleton = skeleton_owner.get( p_rid );
+ ERR_FAIL_COND(!skeleton)
+
+ skeleton_owner.free(p_rid);
+ memdelete(skeleton);
+
+ } else if (light_owner.owns(p_rid)) {
+
+ Light *light = light_owner.get( p_rid );
+ ERR_FAIL_COND(!light)
+
+ light_owner.free(p_rid);
+ memdelete(light);
+
+ } else if (light_instance_owner.owns(p_rid)) {
+
+ LightInstance *light_instance = light_instance_owner.get( p_rid );
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance_owner.free(p_rid);
+ memdelete( light_instance );
+
+ } else if (fx_owner.owns(p_rid)) {
+
+ FX *fx = fx_owner.get( p_rid );
+ ERR_FAIL_COND(!fx);
+
+ fx_owner.free(p_rid);
+ memdelete( fx );
+
+ };
+}
+
+void RasterizerIPhone::init() {
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+ glFrontFace(GL_CW);
+
+ glEnable(GL_TEXTURE_2D);
+}
+
+void RasterizerIPhone::finish() {
+
+}
+
+ int RasterizerIPhone::get_render_info(VS::RenderInfo p_info) {
+
+ return false;
+}
+
+RasterizerIPhone::RasterizerIPhone() {
+
+ frame = 0;
+};
+
+RasterizerIPhone::~RasterizerIPhone() {
+
+};
+
+
+#endif
diff --git a/platform/iphone/rasterizer_iphone.h b/platform/iphone/rasterizer_iphone.h
new file mode 100644
index 0000000000..41dbbdaa5a
--- /dev/null
+++ b/platform/iphone/rasterizer_iphone.h
@@ -0,0 +1,894 @@
+/*************************************************************************/
+/* rasterizer_iphone.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef IPHONE_ENABLED
+
+#ifndef RASTERIZER_IPHONE_H
+#define RASTERIZER_IPHONE_H
+
+#include "servers/visual/rasterizer.h"
+
+#include "image.h"
+#include "rid.h"
+#include "servers/visual_server.h"
+#include "list.h"
+#include "map.h"
+#include "camera_matrix.h"
+#include "sort.h"
+#include <ES1/gl.h>
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class RasterizerIPhone : public Rasterizer {
+
+ enum {
+ SKINNED_BUFFER_SIZE = 1024 * 128, // 10k vertices
+ MAX_LIGHTS = 8,
+ };
+
+ uint8_t skinned_buffer[SKINNED_BUFFER_SIZE];
+
+ struct Texture {
+
+ uint32_t flags;
+ int width,height;
+ Image::Format format;
+
+ GLenum target;
+ GLenum gl_format_cache;
+ int gl_components_cache;
+ bool has_alpha;
+ bool format_has_alpha;
+
+ bool active;
+ GLuint tex_id;
+ bool mipmap_dirty;
+
+ Texture() {
+
+ flags=width=height=0;
+ tex_id=0;
+ format=Image::FORMAT_GRAYSCALE;
+ gl_components_cache=0;
+ format_has_alpha=false;
+ has_alpha=false;
+ active=false;
+ mipmap_dirty=true;
+ }
+
+ ~Texture() {
+
+ if (tex_id!=0) {
+
+ glDeleteTextures(1,&tex_id);
+ }
+ }
+ };
+
+ mutable RID_Owner<Texture> texture_owner;
+
+ struct Material {
+
+ bool flags[VS::MATERIAL_FLAG_MAX];
+ Variant parameters[VisualServer::FIXED_MATERIAL_PARAM_MAX];
+ RID textures[VisualServer::FIXED_MATERIAL_PARAM_MAX];
+
+ Transform uv_transform;
+ VS::FixedMaterialTexCoordMode texcoord_mode[VisualServer::FIXED_MATERIAL_PARAM_MAX];
+
+ VS::MaterialBlendMode detail_blend_mode;
+
+ VS::FixedMaterialTexGenMode texgen_mode;
+
+ Material() {
+
+ flags[VS::MATERIAL_FLAG_VISIBLE]=true;
+ flags[VS::MATERIAL_FLAG_DOUBLE_SIDED]=false;
+ flags[VS::MATERIAL_FLAG_INVERT_FACES]=false;
+ flags[VS::MATERIAL_FLAG_UNSHADED]=false;
+ flags[VS::MATERIAL_FLAG_WIREFRAME]=false;
+
+ parameters[VS::FIXED_MATERIAL_PARAM_DIFFUSE] = Color(0.8, 0.8, 0.8);
+ parameters[VS::FIXED_MATERIAL_PARAM_SPECULAR_EXP] = 12;
+
+ for (int i=0; i<VisualServer::FIXED_MATERIAL_PARAM_MAX; i++) {
+ texcoord_mode[i] = VS::FIXED_MATERIAL_TEXCOORD_UV;
+ };
+ detail_blend_mode = VS::MATERIAL_BLEND_MODE_MIX;
+ texgen_mode = VS::FIXED_MATERIAL_TEXGEN_SPHERE;
+ }
+ };
+ mutable RID_Owner<Material> material_owner;
+
+
+ struct Geometry {
+
+ enum Type {
+ GEOMETRY_INVALID,
+ GEOMETRY_SURFACE,
+ GEOMETRY_POLY,
+ GEOMETRY_PARTICLES,
+ GEOMETRY_BEAM,
+ GEOMETRY_DETAILER,
+ };
+
+ Type type;
+ RID material;
+ bool has_alpha;
+ bool material_owned;
+
+ Vector3 scale;
+ Vector3 uv_scale;
+
+ Geometry() : scale(1, 1, 1) { has_alpha=false; material_owned = false; }
+ virtual ~Geometry() {};
+ };
+
+ struct GeometryOwner {
+
+ virtual ~GeometryOwner() {}
+ };
+
+
+ struct Surface : public Geometry {
+
+ struct ArrayData {
+
+ uint32_t ofs,size;
+ bool configured;
+ int components;
+ ArrayData() { ofs=0; size=0; configured=false; }
+ };
+
+ ArrayData array[VS::ARRAY_MAX];
+ // support for vertex array objects
+ GLuint array_object_id;
+ // support for vertex buffer object
+ GLuint vertex_id; // 0 means, unconfigured
+ GLuint index_id; // 0 means, unconfigured
+ // no support for the above, array in localmem.
+ uint8_t *array_local;
+ uint8_t *index_array_local;
+
+ AABB aabb;
+
+ int array_len;
+ int index_array_len;
+
+ VS::PrimitiveType primitive;
+
+ uint32_t format;
+
+ int stride;
+
+ bool active;
+
+ Point2 uv_min;
+ Point2 uv_max;
+
+ bool has_alpha_cache;
+
+ Surface() {
+
+ array_len=0;
+ type=GEOMETRY_SURFACE;
+ primitive=VS::PRIMITIVE_POINTS;
+ index_array_len=VS::NO_INDEX_ARRAY;
+ format=0;
+ stride=0;
+
+ array_local = index_array_local = 0;
+ vertex_id = index_id = 0;
+
+ active=false;
+ }
+
+ ~Surface() {
+
+ }
+ };
+
+
+ struct Mesh {
+
+ bool active;
+ Vector<Surface*> surfaces;
+
+ mutable uint64_t last_pass;
+ Mesh() {
+ last_pass=0;
+ active=false;
+ }
+ };
+ mutable RID_Owner<Mesh> mesh_owner;
+
+ struct Poly : public Geometry {
+
+ struct Primitive {
+
+ Vector<Vector3> vertices;
+ Vector<Vector3> normals;
+ Vector<Vector3> uvs;
+ Vector<Color> colors;
+
+ };
+
+ AABB aabb;
+ List<Primitive> primitives;
+ Poly() {
+
+ type=GEOMETRY_POLY;
+ }
+ };
+
+ mutable RID_Owner<Poly> poly_owner;
+
+
+ struct Skeleton {
+
+ Vector<Transform> bones;
+
+ };
+
+ mutable RID_Owner<Skeleton> skeleton_owner;
+
+
+ struct Light {
+
+ VS::LightType type;
+ float vars[VS::LIGHT_PARAM_MAX];
+ Color colors[3];
+ bool shadow_enabled;
+ RID projector;
+ bool volumetric_enabled;
+ Color volumetric_color;
+
+
+ Light() {
+
+ vars[VS::LIGHT_PARAM_SPOT_ATTENUATION]=1;
+ vars[VS::LIGHT_PARAM_SPOT_ANGLE]=45;
+ vars[VS::LIGHT_PARAM_ATTENUATION]=1.0;
+ vars[VS::LIGHT_PARAM_ENERGY]=1.0;
+ vars[VS::LIGHT_PARAM_RADIUS]=1.0;
+ colors[VS::LIGHT_COLOR_AMBIENT]=Color(0,0,0);
+ colors[VS::LIGHT_COLOR_DIFFUSE]=Color(1,1,1);
+ colors[VS::LIGHT_COLOR_SPECULAR]=Color(1,1,1);
+ shadow_enabled=false;
+ volumetric_enabled=false;
+ }
+ };
+
+ struct ShadowBuffer;
+
+ struct LightInstance {
+
+ struct SplitInfo {
+
+ CameraMatrix camera;
+ Transform transform;
+ float near;
+ float far;
+ };
+
+ RID light;
+ Light *base;
+ uint64_t last_pass;
+ Transform transform;
+
+
+ CameraMatrix projection;
+ Vector<SplitInfo> splits;
+
+ Vector3 light_vector;
+ Vector3 spot_vector;
+ float linear_att;
+
+ uint64_t hash_aux;
+ };
+ mutable RID_Owner<Light> light_owner;
+ mutable RID_Owner<LightInstance> light_instance_owner;
+
+ LightInstance *light_instances[MAX_LIGHTS];
+ int light_instance_count;
+
+ struct RenderList {
+
+ enum {
+ MAX_ELEMENTS=4096,
+ MAX_LIGHTS=4
+ };
+
+ struct Element {
+
+ float depth;
+ const Skeleton *skeleton;
+ Transform transform;
+ LightInstance* lights[MAX_LIGHTS];
+ int light_count;
+ const Geometry *geometry;
+ const Material *material;
+ uint64_t light_hash;
+ GeometryOwner *owner;
+ const ParamOverrideMap* material_overrides;
+ };
+
+
+ Element _elements[MAX_ELEMENTS];
+ Element *elements[MAX_ELEMENTS];
+ int element_count;
+
+ void clear() {
+
+ element_count=0;
+ }
+
+ struct SortZ {
+
+ _FORCE_INLINE_ bool operator()(const Element* A, const Element* B ) const {
+
+ return A->depth > B->depth;
+ }
+ };
+
+ void sort_z() {
+
+ SortArray<Element*,SortZ> sorter;
+ sorter.sort(elements,element_count);
+ }
+
+ struct SortSkel {
+
+ _FORCE_INLINE_ bool operator()(const Element* A, const Element* B ) const {
+
+ if (A->geometry < B->geometry)
+ return true;
+ else if (A->geometry > B->geometry)
+ return false;
+ else return (!A->skeleton && B->skeleton);
+ }
+ };
+
+ void sort_skel() {
+
+ SortArray<Element*,SortSkel> sorter;
+ sorter.sort(elements,element_count);
+ }
+
+ struct SortMat {
+
+ _FORCE_INLINE_ bool operator()(const Element* A, const Element* B ) const {
+
+ if (A->geometry == B->geometry) {
+
+ if (A->material == B->material) {
+
+
+ return (A->material_overrides < B->material_overrides);
+ } else {
+
+ return (A->material < B->material);
+ }
+ } else {
+
+ return (A->geometry < B->geometry);
+ }
+ }
+ };
+
+ void sort_mat() {
+
+ SortArray<Element*,SortMat> sorter;
+ sorter.sort(elements,element_count);
+ }
+
+ struct SortMatLight {
+
+ _FORCE_INLINE_ bool operator()(const Element* A, const Element* B ) const {
+
+ if (A->geometry == B->geometry) {
+
+ if (A->material == B->material) {
+
+ if (A->light_hash == B->light_hash)
+ return (A->material_overrides < B->material_overrides);
+ else
+ return A->light_hash<B->light_hash;
+ } else {
+
+ return (A->material < B->material);
+ }
+ } else {
+
+ return (A->geometry < B->geometry);
+ }
+ }
+ };
+
+ void sort_mat_light() {
+
+ SortArray<Element*,SortMatLight> sorter;
+ sorter.sort(elements,element_count);
+ }
+
+ struct LISort {
+
+ _FORCE_INLINE_ bool operator ()(const LightInstance *A, const LightInstance *B) const {
+
+ return (A->hash_aux < B->hash_aux);
+ }
+ };
+
+ _FORCE_INLINE_ void add_element( const Geometry *p_geometry, const Material* p_material,const Transform& p_transform, LightInstance **p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides, const Skeleton *p_skeleton, float p_depth, GeometryOwner *p_owner=NULL) {
+
+
+ ERR_FAIL_COND( element_count >= MAX_ELEMENTS );
+ Element *e = elements[element_count++];
+
+ e->geometry=p_geometry;
+ e->material=p_material;
+ e->transform=p_transform;
+ e->skeleton=p_skeleton;
+ e->light_hash=0;
+ e->light_count=p_light_count;
+ e->owner=p_owner;
+ e->material_overrides=p_material_overrides;
+
+ if (e->light_count>0) {
+
+ SortArray<LightInstance*,LISort> light_sort;
+ light_sort.sort(p_light_instances,p_light_count);
+ //@TODO OPTIOMIZE
+
+ for (int i=0;i<p_light_count;i++) {
+
+ e->lights[i]=p_light_instances[i];
+
+ if (i==0)
+ e->light_hash=hash_djb2_one_64( make_uint64_t(e->lights[i]) );
+ else
+ e->light_hash=hash_djb2_one_64( make_uint64_t(e->lights[i]),e->light_hash);
+ }
+
+ }
+
+ }
+
+ RenderList() {
+
+ for (int i=0;i<MAX_ELEMENTS;i++)
+ elements[i]=&_elements[i]; // assign elements
+ }
+ };
+
+ RenderList opaque_render_list;
+ RenderList alpha_render_list;
+
+ RID default_material;
+
+ struct FX {
+
+ bool bgcolor_active;
+ Color bgcolor;
+
+ bool skybox_active;
+ RID skybox_cubemap;
+
+ bool antialias_active;
+ float antialias_tolerance;
+
+ bool glow_active;
+ int glow_passes;
+ float glow_attenuation;
+ float glow_bloom;
+
+ bool ssao_active;
+ float ssao_attenuation;
+ float ssao_radius;
+ float ssao_max_distance;
+ float ssao_range_max;
+ float ssao_range_min;
+ bool ssao_only;
+
+ bool fog_active;
+ float fog_distance;
+ float fog_attenuation;
+ Color fog_color_near;
+ Color fog_color_far;
+ bool fog_bg;
+
+ bool toon_active;
+ float toon_treshold;
+ float toon_soft;
+
+ bool edge_active;
+ Color edge_color;
+ float edge_size;
+
+ FX();
+
+ };
+ mutable RID_Owner<FX> fx_owner;
+
+
+ FX *scene_fx;
+ CameraMatrix camera_projection;
+ Transform camera_transform;
+ Transform camera_transform_inverse;
+ float camera_z_near;
+ float camera_z_far;
+ Size2 camera_vp_size;
+
+ Plane camera_plane;
+
+ void _add_geometry( const Geometry* p_geometry, const Transform& p_world, uint32_t p_vertex_format, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides,const Skeleton* p_skeleton,GeometryOwner *p_owner);
+ void _render_list_forward(RenderList *p_render_list);
+
+ void _setup_light(LightInstance* p_instance, int p_idx);
+ void _setup_lights(LightInstance **p_lights,int p_light_count);
+ void _setup_material(const Geometry *p_geometry,const Material *p_material);
+
+ void _setup_geometry(const Geometry *p_geometry, const Material* p_material);
+ void _render(const Geometry *p_geometry,const Material *p_material, const Skeleton* p_skeleton);
+
+
+ /*********/
+ /* FRAME */
+ /*********/
+
+ Size2 window_size;
+ VS::ViewportRect viewport;
+ Transform canvas_transform;
+ double last_time;
+ double time_delta;
+ uint64_t frame;
+
+public:
+
+ /* TEXTURE API */
+
+ virtual RID texture_create();
+ virtual void texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags=VS::TEXTURE_FLAGS_DEFAULT);
+ virtual void texture_blit_rect(RID p_texture,int p_x,int p_y, const Image& p_image,VS::CubeMapSide p_cube_side=VS::CUBEMAP_LEFT);
+ virtual Image texture_get_rect(RID p_texture,int p_x,int p_y,int p_width, int p_height,VS::CubeMapSide p_cube_side=VS::CUBEMAP_LEFT) const;
+ virtual void texture_set_flags(RID p_texture,uint32_t p_flags);
+ virtual uint32_t texture_get_flags(RID p_texture) const;
+ virtual Image::Format texture_get_format(RID p_texture) const;
+ virtual uint32_t texture_get_width(RID p_texture) const;
+ virtual uint32_t texture_get_height(RID p_texture) const;
+ virtual bool texture_has_alpha(RID p_texture) const;
+
+ /* SHADER API */
+
+ virtual RID shader_create();
+
+ virtual void shader_node_add(RID p_shader,VS::ShaderNodeType p_type,int p_id);
+ virtual void shader_node_remove(RID p_shader,int p_id);
+ virtual void shader_node_change_type(RID p_shader, int p_id, VS::ShaderNodeType p_type);
+ virtual void shader_node_set_param(RID p_shader, int p_id, const Variant& p_value);
+
+ virtual void shader_get_node_list(RID p_shader,List<int> *p_node_list) const;
+ virtual VS::ShaderNodeType shader_node_get_type(RID p_shader,int p_id) const;
+ virtual Variant shader_node_get_param(RID p_shader,int p_id) const;
+
+ virtual void shader_connect(RID p_shader,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+ virtual bool shader_is_connected(RID p_shader,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const;
+ virtual void shader_disconnect(RID p_shader,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+
+ virtual void shader_get_connections(RID p_shader,List<VS::ShaderConnection> *p_connections) const;
+
+ virtual void shader_clear(RID p_shader);
+
+ /* COMMON MATERIAL API */
+
+ virtual void material_set_param(RID p_material, const StringName& p_param, const Variant& p_value);
+ virtual Variant material_get_param(RID p_material, const StringName& p_param) const;
+ virtual void material_get_param_list(RID p_material, List<String> *p_param_list) const;
+
+ virtual void material_set_flag(RID p_material, VS::MaterialFlag p_flag,bool p_enabled);
+ virtual bool material_get_flag(RID p_material,VS::MaterialFlag p_flag) const;
+
+ virtual void material_set_blend_mode(RID p_material,VS::MaterialBlendMode p_mode);
+ virtual VS::MaterialBlendMode material_get_blend_mode(RID p_material) const;
+
+ virtual void material_set_line_width(RID p_material,float p_line_width);
+ virtual float material_get_line_width(RID p_material) const;
+
+ /* FIXED MATERIAL */
+
+ virtual RID material_create();
+
+ virtual void fixed_material_set_parameter(RID p_material, VS::FixedMaterialParam p_parameter, const Variant& p_value);
+ virtual Variant fixed_material_get_parameter(RID p_material,VS::FixedMaterialParam p_parameter) const;
+
+ virtual void fixed_material_set_texture(RID p_material,VS::FixedMaterialParam p_parameter, RID p_texture);
+ virtual RID fixed_material_get_texture(RID p_material,VS::FixedMaterialParam p_parameter) const;
+
+ virtual void fixed_material_set_detail_blend_mode(RID p_material,VS::MaterialBlendMode p_mode);
+ virtual VS::MaterialBlendMode fixed_material_get_detail_blend_mode(RID p_material) const;
+
+ virtual void fixed_material_set_texgen_mode(RID p_material,VS::FixedMaterialTexGenMode p_mode);
+ virtual VS::FixedMaterialTexGenMode fixed_material_get_texgen_mode(RID p_material) const;
+
+ virtual void fixed_material_set_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter, VS::FixedMaterialTexCoordMode p_mode);
+ virtual VS::FixedMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter) const;
+
+ virtual void fixed_material_set_uv_transform(RID p_material,const Transform& p_transform);
+ virtual Transform fixed_material_get_uv_transform(RID p_material) const;
+
+ /* SHADER MATERIAL */
+
+ virtual RID shader_material_create() const;
+
+ virtual void shader_material_set_vertex_shader(RID p_material,RID p_shader,bool p_owned=false);
+ virtual RID shader_material_get_vertex_shader(RID p_material) const;
+
+ virtual void shader_material_set_fragment_shader(RID p_material,RID p_shader,bool p_owned=false);
+ virtual RID shader_material_get_fragment_shader(RID p_material) const;
+
+
+ /* MESH API */
+
+ virtual RID mesh_create();
+
+ virtual void mesh_add_surface(RID p_mesh,VS::PrimitiveType p_primitive,uint32_t p_format,int p_array_len,int p_index_array_len=VS::NO_INDEX_ARRAY);
+
+ virtual Error mesh_surface_set_array(RID p_mesh, int p_surface,VS::ArrayType p_type,const Variant& p_array) ;
+ virtual Variant mesh_surface_get_array(RID p_mesh, int p_surface,VS::ArrayType p_type) const;
+
+ virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material,bool p_owned=false);
+ virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const;
+
+ virtual int mesh_surface_get_array_len(RID p_mesh, int p_surface) const;
+ virtual int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const;
+ virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const;
+ virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const;
+
+ virtual void mesh_erase_surface(RID p_mesh,int p_index);
+ virtual int mesh_get_surface_count(RID p_mesh) const;
+
+ virtual AABB mesh_get_aabb(RID p_mesh) const;
+
+ /* MULTIMESH API */
+
+ virtual RID multimesh_create();
+
+ virtual void multimesh_set_instance_count(RID p_multimesh,int p_count);
+ virtual int multimesh_get_instance_count(RID p_multimesh) const;
+
+ virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh);
+ virtual void multimesh_set_aabb(RID p_multimesh,const AABB& p_aabb);
+ virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform);
+ virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color);
+
+ virtual RID multimesh_get_mesh(RID p_multimesh) const;
+ virtual AABB multimesh_get_aabb(RID p_multimesh) const;;
+
+ virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const;
+ virtual Color multimesh_instance_get_color(RID p_multimesh,int p_index) const;
+
+ /* POLY API */
+
+ virtual RID poly_create();
+ virtual void poly_set_material(RID p_poly, RID p_material,bool p_owned=false);
+ virtual void poly_add_primitive(RID p_poly, const Vector<Vector3>& p_points,const Vector<Vector3>& p_normals,const Vector<Color>& p_colors,const Vector<Vector3>& p_uvs);
+ virtual void poly_clear(RID p_poly);
+
+ virtual AABB poly_get_aabb(RID p_poly) const;
+
+
+ /* PARTICLES API */
+
+ virtual RID particles_create();
+
+ virtual void particles_set_amount(RID p_particles, int p_amount);
+ virtual int particles_get_amount(RID p_particles) const;
+
+ virtual void particles_set_emitting(RID p_particles, bool p_emitting);
+ virtual bool particles_is_emitting(RID p_particles) const;
+
+ virtual void particles_set_visibility_aabb(RID p_particles, const AABB& p_visibility);
+ virtual AABB particles_get_visibility_aabb(RID p_particles) const;
+
+ virtual void particles_set_emission_half_extents(RID p_particles, const Vector3& p_half_extents);
+ virtual Vector3 particles_get_emission_half_extents(RID p_particles) const;
+
+ virtual void particles_set_gravity_normal(RID p_particles, const Vector3& p_normal);
+ virtual Vector3 particles_get_gravity_normal(RID p_particles) const;
+
+ virtual void particles_set_variable(RID p_particles, VS::ParticleVariable p_variable,float p_value);
+ virtual float particles_get_variable(RID p_particles, VS::ParticleVariable p_variable) const;
+
+ virtual void particles_set_randomness(RID p_particles, VS::ParticleVariable p_variable,float p_randomness);
+ virtual float particles_get_randomness(RID p_particles, VS::ParticleVariable p_variable) const;
+
+ virtual void particles_set_color_phase_pos(RID p_particles, int p_phase, float p_pos);
+ virtual float particles_get_color_phase_pos(RID p_particles, int p_phase) const;
+
+ virtual void particles_set_color_phases(RID p_particles, int p_phases);
+ virtual int particles_get_color_phases(RID p_particles) const;
+
+ virtual void particles_set_color_phase_color(RID p_particles, int p_phase, const Color& p_color);
+ virtual Color particles_get_color_phase_color(RID p_particles, int p_phase) const;
+
+ virtual void particles_set_attractors(RID p_particles, int p_attractors);
+ virtual int particles_get_attractors(RID p_particles) const;
+
+ virtual void particles_set_attractor_pos(RID p_particles, int p_attractor, const Vector3& p_pos);
+ virtual Vector3 particles_get_attractor_pos(RID p_particles,int p_attractor) const;
+
+ virtual void particles_set_attractor_strength(RID p_particles, int p_attractor, float p_force);
+ virtual float particles_get_attractor_strength(RID p_particles,int p_attractor) const;
+
+ virtual void particles_set_material(RID p_particles, RID p_material,bool p_owned=false);
+ virtual RID particles_get_material(RID p_particles) const;
+
+ virtual AABB particles_get_aabb(RID p_particles) const;
+ /* BEAM API */
+
+ virtual RID beam_create();
+
+ virtual void beam_set_point_count(RID p_beam, int p_count);
+ virtual int beam_get_point_count(RID p_beam) const;
+ virtual void beam_clear(RID p_beam);
+
+ virtual void beam_set_point(RID p_beam,int p_point,Vector3& p_pos);
+ virtual Vector3 beam_get_point(RID p_beam,int p_point) const;
+
+ virtual void beam_set_primitive(RID p_beam,VS::BeamPrimitive p_primitive);
+ virtual VS::BeamPrimitive beam_get_primitive(RID p_beam) const;
+
+ virtual void beam_set_material(RID p_beam, RID p_material);
+ virtual RID beam_get_material(RID p_beam) const;
+
+ virtual AABB beam_get_aabb(RID p_particles) const;
+ /* SKELETON API */
+
+ virtual RID skeleton_create();
+ virtual void skeleton_resize(RID p_skeleton,int p_bones);
+ virtual int skeleton_get_bone_count(RID p_skeleton) const;
+ virtual void skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform);
+ virtual Transform skeleton_bone_get_transform(RID p_skeleton,int p_bone);
+
+
+ /* LIGHT API */
+
+ virtual RID light_create(VS::LightType p_type);
+ virtual VS::LightType light_get_type(RID p_light) const;
+
+ virtual void light_set_color(RID p_light,VS::LightColor p_type, const Color& p_color);
+ virtual Color light_get_color(RID p_light,VS::LightColor p_type) const;
+
+ virtual void light_set_shadow(RID p_light,bool p_enabled);
+ virtual bool light_has_shadow(RID p_light) const;
+
+ virtual void light_set_volumetric(RID p_light,bool p_enabled);
+ virtual bool light_is_volumetric(RID p_light) const;
+
+ virtual void light_set_projector(RID p_light,RID p_texture);
+ virtual RID light_get_projector(RID p_light) const;
+
+ virtual void light_set_var(RID p_light, VS::LightParam p_var, float p_value);
+ virtual float light_get_var(RID p_light, VS::LightParam p_var) const;
+
+ virtual AABB light_get_aabb(RID p_poly) const;
+
+
+ virtual RID light_instance_create(RID p_light);
+ virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform);
+
+ virtual void light_instance_set_active_hint(RID p_light_instance);
+ virtual bool light_instance_has_shadow(RID p_light_instance) const;
+ virtual bool light_instance_assign_shadow(RID p_light_instance);
+ virtual ShadowType light_instance_get_shadow_type(RID p_light_instance) const;
+ virtual int light_instance_get_shadow_passes(RID p_light_instance) const;
+ virtual void light_instance_set_pssm_split_info(RID p_light_instance, int p_split, float p_near,float p_far, const CameraMatrix& p_camera, const Transform& p_transform);
+
+ /* PARTICLES INSTANCE */
+
+ virtual RID particles_instance_create(RID p_particles);
+ virtual void particles_instance_set_transform(RID p_particles_instance,const Transform& p_transform);
+
+ /* RENDER API */
+ /* all calls (inside begin/end shadow) are always warranted to be in the following order: */
+
+ virtual void begin_frame();
+
+ virtual void set_viewport(const VS::ViewportRect& p_viewport);
+
+ virtual void begin_scene(RID p_fx=RID(),VS::ScenarioDebugMode p_debug=VS::SCENARIO_DEBUG_DISABLED);
+ virtual void begin_shadow_map( RID p_light_instance, int p_shadow_pass );
+
+ virtual void set_camera(const Transform& p_world,const CameraMatrix& p_projection);
+
+ virtual void add_light( RID p_light_instance ); ///< all "add_light" calls happen before add_geometry calls
+
+ typedef Map<StringName,Variant> ParamOverrideMap;
+
+ virtual void add_mesh( RID p_mesh, const Transform* p_world, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides = NULL, RID p_skeleton=RID());
+ virtual void add_multimesh( RID p_multimesh, const Transform* p_world, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides = NULL);
+ virtual void add_poly( RID p_poly, const Transform* p_world, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides = NULL);
+ virtual void add_beam( RID p_beam, const Transform* p_world, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides = NULL);
+ virtual void add_particles( RID p_particle_instance, const RID* p_light_instances, int p_light_count, const ParamOverrideMap* p_material_overrides = NULL);
+
+ virtual void end_scene();
+ virtual void end_shadow_map();
+
+ virtual void end_frame();
+
+ /* CANVAS API */
+
+ virtual void canvas_begin();
+ virtual void canvas_set_transparency(float p_transparency);
+ virtual void canvas_set_rect(const Rect2& p_rect, bool p_clip);;
+ virtual void canvas_draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width);
+ virtual void canvas_draw_rect(const Rect2& p_rect, bool p_region, const Rect2& p_source,bool p_tile,RID p_texture,const Color& p_modulate);
+ virtual void canvas_draw_style_box(const Rect2& p_rect, RID p_texture,const float *p_margins, bool p_draw_center=true);
+ virtual void canvas_draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture);
+
+ /* FX */
+
+ virtual RID fx_create();
+ virtual void fx_get_effects(RID p_fx,List<String> *p_effects) const;
+ virtual void fx_set_active(RID p_fx,const String& p_effect, bool p_active);
+ virtual bool fx_is_active(RID p_fx,const String& p_effect) const;
+ virtual void fx_get_effect_params(RID p_fx,const String& p_effect,List<PropertyInfo> *p_params) const;
+ virtual Variant fx_get_effect_param(RID p_fx,const String& p_effect,const String& p_param) const;
+ virtual void fx_set_effect_param(RID p_fx,const String& p_effect, const String& p_param, const Variant& p_pvalue);
+
+ /*MISC*/
+
+ virtual bool is_texture(const RID& p_rid) const;
+ virtual bool is_material(const RID& p_rid) const;
+ virtual bool is_mesh(const RID& p_rid) const;
+ virtual bool is_multimesh(const RID& p_rid) const;
+ virtual bool is_poly(const RID& p_rid) const;
+ virtual bool is_particles(const RID &p_beam) const;
+ virtual bool is_beam(const RID &p_beam) const;
+
+ virtual bool is_light(const RID& p_rid) const;
+ virtual bool is_light_instance(const RID& p_rid) const;
+ virtual bool is_particles_instance(const RID& p_rid) const;
+ virtual bool is_skeleton(const RID& p_rid) const;
+ virtual bool is_fx(const RID& p_rid) const;
+ virtual bool is_shader(const RID& p_rid) const;
+
+ virtual void free(const RID& p_rid) const;
+
+ virtual void init();
+ virtual void finish();
+
+ virtual int get_render_info(VS::RenderInfo p_info);
+
+ RasterizerIPhone();
+ virtual ~RasterizerIPhone();
+};
+
+#endif
+#endif
diff --git a/platform/iphone/sem_iphone.cpp b/platform/iphone/sem_iphone.cpp
new file mode 100644
index 0000000000..5afaa7b308
--- /dev/null
+++ b/platform/iphone/sem_iphone.cpp
@@ -0,0 +1,115 @@
+/*************************************************************************/
+/* sem_iphone.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "sem_iphone.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+void cgsem_init(cgsem_t *cgsem)
+{
+ int flags, fd, i;
+
+ pipe(cgsem->pipefd);
+
+ /* Make the pipes FD_CLOEXEC to allow them to close should we call
+ * execv on restart. */
+ for (i = 0; i < 2; i++) {
+ fd = cgsem->pipefd[i];
+ flags = fcntl(fd, F_GETFD, 0);
+ flags |= FD_CLOEXEC;
+ fcntl(fd, F_SETFD, flags);
+ }
+}
+
+void cgsem_post(cgsem_t *cgsem)
+{
+ const char buf = 1;
+
+ write(cgsem->pipefd[1], &buf, 1);
+}
+
+void cgsem_wait(cgsem_t *cgsem)
+{
+ char buf;
+
+ read(cgsem->pipefd[0], &buf, 1);
+}
+
+void cgsem_destroy(cgsem_t *cgsem)
+{
+ close(cgsem->pipefd[1]);
+ close(cgsem->pipefd[0]);
+}
+
+
+#include "os/memory.h"
+#include <errno.h>
+
+
+Error SemaphoreIphone::wait() {
+
+ cgsem_wait(&sem);
+ return OK;
+}
+
+Error SemaphoreIphone::post() {
+
+ cgsem_post(&sem);
+
+ return OK;
+}
+int SemaphoreIphone::get() const {
+
+ return 0;
+}
+
+
+Semaphore *SemaphoreIphone::create_semaphore_iphone() {
+
+ return memnew( SemaphoreIphone );
+}
+
+void SemaphoreIphone::make_default() {
+
+ create_func=create_semaphore_iphone;
+}
+
+SemaphoreIphone::SemaphoreIphone() {
+
+ cgsem_init(&sem);
+}
+
+
+SemaphoreIphone::~SemaphoreIphone() {
+
+ cgsem_destroy(&sem);
+}
+
+
+
diff --git a/platform/iphone/sem_iphone.h b/platform/iphone/sem_iphone.h
new file mode 100644
index 0000000000..7a57b5dd99
--- /dev/null
+++ b/platform/iphone/sem_iphone.h
@@ -0,0 +1,60 @@
+/*************************************************************************/
+/* sem_iphone.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef SEM_IPHONE_H
+#define SEM_IPHONE_H
+
+struct cgsem {
+ int pipefd[2];
+};
+
+typedef struct cgsem cgsem_t;
+
+#include "os/semaphore.h"
+
+class SemaphoreIphone : public Semaphore {
+
+ mutable cgsem_t sem;
+
+ static Semaphore *create_semaphore_iphone();
+
+public:
+
+ virtual Error wait();
+ virtual Error post();
+ virtual int get() const;
+
+ static void make_default();
+ SemaphoreIphone();
+
+ ~SemaphoreIphone();
+
+};
+
+
+#endif
diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h
new file mode 100644
index 0000000000..ac94d7ed3a
--- /dev/null
+++ b/platform/iphone/view_controller.h
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* view_controller.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#import <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController {
+
+};
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:
+ (UIInterfaceOrientation)p_orientation;
+
+- (void)didReceiveMemoryWarning;
+
+@end
diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm
new file mode 100644
index 0000000000..8af20358b9
--- /dev/null
+++ b/platform/iphone/view_controller.mm
@@ -0,0 +1,107 @@
+/*************************************************************************/
+/* view_controller.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#import "view_controller.h"
+
+#include "os_iphone.h"
+
+extern "C" {
+
+int add_path(int p_argc, char** p_args) {
+
+ NSString* str = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_path"];
+ if (!str)
+ return p_argc;
+
+ p_args[p_argc++] = "-path";
+ [str retain]; // memory leak lol (maybe make it static here and delete it in ViewController destructor? @todo
+ p_args[p_argc++] = (char*)[str cString];
+ p_args[p_argc] = NULL;
+
+ return p_argc;
+};
+
+};
+
+@interface ViewController ()
+
+@end
+
+@implementation ViewController
+
+- (void)didReceiveMemoryWarning {
+
+ printf("*********** did receive memory warning!\n");
+};
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)p_orientation {
+
+ if (/*OSIPhone::get_singleton() == NULL*/TRUE) {
+
+ printf("checking on info.plist\n");
+ NSArray* arr = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"];
+ switch(p_orientation) {
+
+ case UIInterfaceOrientationLandscapeLeft:
+ return [arr indexOfObject:@"UIInterfaceOrientationLandscapeLeft"] != NSNotFound ? YES : NO;
+
+ case UIInterfaceOrientationLandscapeRight:
+ return [arr indexOfObject:@"UIInterfaceOrientationLandscapeRight"] != NSNotFound ? YES : NO;
+
+ case UIInterfaceOrientationPortrait:
+ return [arr indexOfObject:@"UIInterfaceOrientationPortrait"] != NSNotFound ? YES : NO;
+
+ case UIInterfaceOrientationPortraitUpsideDown:
+ return [arr indexOfObject:@"UIInterfaceOrientationPortraitUpsideDown"] != NSNotFound ? YES : NO;
+
+ default:
+ return NO;
+ }
+ };
+
+ uint8_t supported = OSIPhone::get_singleton()->get_orientations();
+ switch(p_orientation) {
+
+ case UIInterfaceOrientationLandscapeLeft:
+ return supported & (1<<OSIPhone::LandscapeLeft) ? YES : NO;
+
+ case UIInterfaceOrientationLandscapeRight:
+ return supported & (1<<OSIPhone::LandscapeRight) ? YES : NO;
+
+ case UIInterfaceOrientationPortrait:
+ return supported & (1<<OSIPhone::PortraitDown) ? YES : NO;
+
+ case UIInterfaceOrientationPortraitUpsideDown:
+ return supported & (1<<OSIPhone::PortraitUp) ? YES : NO;
+
+ default:
+ return NO;
+ }
+};
+
+@end
diff --git a/platform/isim/SCsub b/platform/isim/SCsub
new file mode 100644
index 0000000000..6fb568465e
--- /dev/null
+++ b/platform/isim/SCsub
@@ -0,0 +1,30 @@
+Import('env')
+
+iphone_lib = [
+
+ '#platform/iphone/os_iphone.cpp',
+ #'#platform/iphone/rasterizer_iphone.cpp',
+ '#platform/iphone/audio_driver_iphone.cpp',
+ '#platform/iphone/gl_view.mm',
+ '#platform/iphone/main.m',
+ '#platform/iphone/app_delegate.mm',
+ '#platform/iphone/view_controller.mm',
+ '#platform/iphone/scoreloop_ios.mm',
+]
+
+
+#env.Depends('#core/math/vector3.h', 'vector3_psp.h')
+
+#iphone_lib = env.Library('iphone', iphone_lib)
+
+obj = env.Object('#platform/iphone/godot_iphone.cpp')
+
+prog = None
+if env["target"]=="release":
+ prog = env.Program('#bin/godot_iphone_opt', [obj] + iphone_lib)
+ #action = "dsymutil "+File(prog)[0].path+" -o ../build/script_exec/build/Debug-iphoneos/script_exec.app.dSYM"
+ #env.AddPostAction(prog, action)
+else:
+ prog = env.Program('#bin/godot', [obj] + iphone_lib)
+ #action = "dsymutil "+File(prog)[0].path+" -o ../build/script_exec/build/Debug-iphoneos/script_exec.app.dSYM"
+ #env.AddPostAction(prog, action)
diff --git a/platform/isim/detect.py b/platform/isim/detect.py
new file mode 100644
index 0000000000..8deabbf311
--- /dev/null
+++ b/platform/isim/detect.py
@@ -0,0 +1,98 @@
+import os
+import sys
+
+
+def is_active():
+ return False
+
+def get_name():
+ return "iSIM"
+
+
+def can_build():
+
+ import sys
+ if sys.platform == 'darwin':
+ return True
+
+ return False
+
+def get_opts():
+
+ return [
+ ('ISIMPLATFORM', 'name of the iphone platform', 'iPhoneSimulator'),
+ ('ISIMPATH', 'the path to iphone toolchain', '/Developer/Platforms/${ISIMPLATFORM}.platform'),
+ ('ISIMSDK', 'path to the iphone SDK', '$ISIMPATH/Developer/SDKs/${ISIMPLATFORM}4.3.sdk'),
+ ]
+
+def get_flags():
+
+ return [
+ ('lua', 'no'),
+ ('tools', 'yes'),
+ ('nedmalloc', 'no'),
+ ]
+
+
+
+def configure(env):
+
+ env.Append(CPPPATH=['#platform/iphone'])
+
+ env['OBJSUFFIX'] = ".isim.o"
+ env['LIBSUFFIX'] = ".isim.a"
+ env['PROGSUFFIX'] = ".isim"
+
+ env['ENV']['PATH'] = env['ISIMPATH']+"/Developer/usr/bin/:"+env['ENV']['PATH']
+
+ env['CC'] = '$ISIMPATH/Developer/usr/bin/gcc'
+ env['CXX'] = '$ISIMPATH/Developer/usr/bin/g++'
+ env['AR'] = 'ar'
+
+ import string
+ env['CCFLAGS'] = string.split('-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fasm-blocks -Wall -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $ISIMSDK -mmacosx-version-min=10.6 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"')
+
+ env.Append(LINKFLAGS=['-arch', 'i386',
+ #'-miphoneos-version-min=2.2.1',
+ '-isysroot', '$ISIMSDK',
+ '-mmacosx-version-min=10.6',
+ '-Xlinker',
+ '-objc_abi_version',
+ '-Xlinker', '2',
+ '-framework', 'Foundation',
+ '-framework', 'UIKit',
+ '-framework', 'IOKit',
+ '-framework', 'CoreGraphics',
+ '-framework', 'OpenGLES',
+ '-framework', 'QuartzCore',
+ '-framework', 'AudioToolbox',
+ '-F$ISIMSDK',
+ ])
+
+ env.Append(CPPPATH = ['$ISIMSDK/System/Library/Frameworks/OpenGLES.framework/Headers'])
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O3', '-ffast-math'])
+ env.Append(LINKFLAGS=['-O3', '-ffast-math'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-DDEBUG', '-D_DEBUG', '-gdwarf-2', '-Wall', '-O0', '-DDEBUG_ENABLED'])
+ env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-g','-pg'])
+ env.Append(LINKFLAGS=['-pg'])
+
+
+ env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
+ env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate'
+ env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-fno-exceptions'])
+
+ if env['lua'] == "yes":
+ env.Append(CCFLAGS=['-DLUA_USE_FLOAT'])
+
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
new file mode 100644
index 0000000000..fd1bb39e90
--- /dev/null
+++ b/platform/javascript/SCsub
@@ -0,0 +1,25 @@
+Import('env')
+
+javascript_files = [
+ "os_javascript.cpp",
+ "audio_driver_javascript.cpp",
+ "javascript_main.cpp"
+]
+
+#env.Depends('#core/math/vector3.h', 'vector3_psp.h')
+
+#obj = env.SharedObject('godot_javascript.cpp')
+
+env_javascript = env.Clone()
+if env['target'] == "profile":
+ env_javascript.Append(CPPFLAGS=['-DPROFILER_ENABLED'])
+
+javascript_objects=[]
+for x in javascript_files:
+ javascript_objects.append( env_javascript.Object( x ) )
+
+prog = None
+
+#env_javascript.SharedLibrary("#platform/javascript/libgodot_javascript.so",[javascript_objects])
+
+env.Program('#bin/godot.html', javascript_objects)
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
new file mode 100644
index 0000000000..2a77806fb3
--- /dev/null
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* audio_driver_javascript.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "audio_driver_javascript.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 {
+
+ return "JavaScript";
+}
+
+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;
+}
+void AudioDriverJavaScript::lock(){
+
+ //if (active && mutex)
+ // mutex->lock();
+
+}
+void AudioDriverJavaScript::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
new file mode 100644
index 0000000000..9fe93c56ac
--- /dev/null
+++ b/platform/javascript/audio_driver_javascript.h
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* audio_driver_javascript.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef AUDIO_DRIVER_JAVASCRIPT_H
+#define AUDIO_DRIVER_JAVASCRIPT_H
+
+
+#include "servers/audio/audio_server_sw.h"
+#include "os/mutex.h"
+
+class AudioDriverJavaScript : public AudioDriverSW {
+public:
+
+ void set_singleton();
+
+ virtual const char* get_name() const;
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const ;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+
+ AudioDriverJavaScript();
+};
+
+
+#endif
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
new file mode 100644
index 0000000000..da92c0869b
--- /dev/null
+++ b/platform/javascript/detect.py
@@ -0,0 +1,102 @@
+import os
+import sys
+import string
+
+def is_active():
+ return True
+
+def get_name():
+ return "JavaScript"
+
+def can_build():
+
+ import os
+ if (not os.environ.has_key("EMSCRIPTEN_ROOT")):
+ return False
+ return True
+
+def get_opts():
+
+ return [
+ ['compress','Compress JS Executable','no']
+ ]
+
+def get_flags():
+
+ return [
+ ('lua', 'no'),
+ ('tools', 'no'),
+ ('nedmalloc', 'no'),
+ ('theora', 'no'),
+ ('tools', 'no'),
+ ('nedmalloc', 'no'),
+ ('vorbis', 'yes'),
+ ('musepack', 'no'),
+ ('squirrel', 'no'),
+ ('squish', 'no'),
+ ('speex', 'no'),
+ ('old_scenes', 'no'),
+# ('default_gui_theme', 'no'),
+
+ #('builtin_zlib', 'no'),
+ ]
+
+
+
+def configure(env):
+
+
+ env.Append(CPPPATH=['#platform/android'])
+
+ env['OBJSUFFIX'] = ".js.o"
+ env['LIBSUFFIX'] = ".js.a"
+ env['PROGSUFFIX'] = ".html"
+
+ 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['RANLIB'] = em_path+"/emranlib"
+
+# 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'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="release_debug"):
+
+ env.Append(CCFLAGS=['-O2','-DDEBUG_ENABLED'])
+ env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-D_DEBUG', '-Wall', '-O2', '-DDEBUG_ENABLED'])
+ env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
+
+ env.Append(CPPFLAGS=["-fno-exceptions",'-DNO_SAFE_CAST','-fno-rtti'])
+ env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-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','ASM_JS=1'])
+ env.Append(CPPFLAGS=['-s','FULL_ES2=1'])
+# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT'])
+ if (env["compress"]=="yes"):
+ lzma_binpath = em_path+"/third_party/lzma.js/lzma-native"
+ lzma_decoder = em_path+"/third_party/lzma.js/lzma-decoder.js"
+ lzma_dec = "LZMA.decompress"
+
+ env.Append(LINKFLAGS=['--compression',lzma_binpath+","+lzma_decoder+","+lzma_dec])
+
+ env.Append(LINKFLAGS=['-s','ASM_JS=1'])
+ env.Append(LINKFLAGS=['-O2'])
+
+
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
new file mode 100644
index 0000000000..a81fabe085
--- /dev/null
+++ b/platform/javascript/export/export.cpp
@@ -0,0 +1,452 @@
+/*************************************************************************/
+/* export.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "version.h"
+#include "export.h"
+#include "tools/editor/editor_settings.h"
+#include "tools/editor/editor_import_export.h"
+#include "tools/editor/editor_node.h"
+#include "io/zip_io.h"
+#include "io/marshalls.h"
+#include "globals.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "platform/javascript/logo.h"
+#include "string.h"
+class EditorExportPlatformJavaScript : public EditorExportPlatform {
+
+ OBJ_TYPE( EditorExportPlatformJavaScript,EditorExportPlatform );
+
+ String custom_release_package;
+ String custom_debug_package;
+
+ enum PackMode {
+ PACK_SINGLE_FILE,
+ PACK_MULTIPLE_FILES
+ };
+
+
+ PackMode pack_mode;
+
+ bool show_run;
+
+ int max_memory;
+ int version_code;
+
+ Ref<ImageTexture> logo;
+
+ static Error save_pack_file_js(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total);
+
+protected:
+
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+ virtual String get_name() const { return "HTML5"; }
+ virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_BC; }
+ virtual Ref<Texture> get_logo() const { return logo; }
+
+
+ virtual bool poll_devices() { return show_run?true:false;}
+ virtual int get_device_count() const { return show_run?1:0; };
+ virtual String get_device_name(int p_device) const { return "Run in Browser"; }
+ virtual String get_device_info(int p_device) const { return "Run exported HTML in the system's default browser."; }
+ virtual Error run(int p_device);
+
+ virtual bool requieres_password(bool p_debug) const { return false; }
+ virtual String get_binary_extension() const { return "html"; }
+ virtual Error export_project(const String& p_path,bool p_debug,const String& p_password="");
+
+ virtual bool can_export(String *r_error=NULL) const;
+
+ EditorExportPlatformJavaScript();
+ ~EditorExportPlatformJavaScript();
+};
+
+bool EditorExportPlatformJavaScript::_set(const StringName& p_name, const Variant& p_value) {
+
+ String n=p_name;
+
+ if (n=="custom_package/debug")
+ custom_debug_package=p_value;
+ else if (n=="custom_package/release")
+ custom_release_package=p_value;
+ else if (n=="browser/enable_run")
+ show_run=p_value;
+ else if (n=="options/memory_size")
+ max_memory=p_value;
+ else if (n=="options/pack_mode")
+ pack_mode=PackMode(int(p_value));
+ else
+ return false;
+
+ return true;
+}
+
+bool EditorExportPlatformJavaScript::_get(const StringName& p_name,Variant &r_ret) const{
+
+ String n=p_name;
+
+ if (n=="custom_package/debug")
+ r_ret=custom_debug_package;
+ else if (n=="custom_package/release")
+ r_ret=custom_release_package;
+ else if (n=="browser/enable_run")
+ r_ret=show_run;
+ else if (n=="options/memory_size")
+ r_ret=max_memory;
+ else if (n=="options/pack_mode")
+ r_ret=pack_mode;
+ else
+ return false;
+
+ return true;
+}
+void EditorExportPlatformJavaScript::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_FILE,"zip"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_FILE,"zip"));
+ p_list->push_back( PropertyInfo( Variant::INT, "options/pack_mode",PROPERTY_HINT_ENUM,"Single File, Multiple Files"));
+ p_list->push_back( PropertyInfo( Variant::INT, "options/memory_size",PROPERTY_HINT_ENUM,"32mb,64mb,128mb,256mb,512mb,1024mb"));
+ p_list->push_back( PropertyInfo( Variant::BOOL, "browser/enable_run"));
+
+ //p_list->push_back( PropertyInfo( Variant::INT, "resources/pack_mode", PROPERTY_HINT_ENUM,"Copy,Single Exec.,Pack (.pck),Bundles (Optical)"));
+
+}
+
+
+static const char* files_pre=""\
+"var Module;\n"\
+"if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');\n"\
+"if (!Module.expectedDataFileDownloads) {\n"\
+" Module.expectedDataFileDownloads = 0;\n"\
+" Module.finishedDataFileDownloads = 0;\n"\
+"}\n"\
+"Module.expectedDataFileDownloads++;\n"\
+"(function() {\n"\
+"\n"\
+" function runWithFS() {\n"\
+"function assert(check, msg) {\n"\
+" if (!check) throw msg + new Error().stack;\n"\
+"} \n";
+
+static const char* files_post=""\
+"}\n"\
+"if (Module['calledRun']) {\n"\
+" runWithFS();\n"\
+"} else {\n"\
+" if (!Module['preRun']) Module['preRun'] = [];\n"\
+" Module[\"preRun\"].push(runWithFS); // FS is not initialized yet, wait for it\n"\
+"}\n"\
+"})();";
+
+
+static void _fix_html(Vector<uint8_t>& html,const String& name,int max_memory) {
+
+
+ String str;
+ String strnew;
+ str.parse_utf8((const char*)html.ptr(),html.size());
+ Vector<String> lines=str.split("\n");
+ for(int i=0;i<lines.size();i++) {
+ if (lines[i].find("godot.js")!=-1) {
+ strnew+="<script type=\"text/javascript\" src=\""+name+"_files.js\"></script>\n";
+ strnew+="<script async type=\"text/javascript\" src=\""+name+".js\"></script>\n";
+ } else if (lines[i].find("var Module")!=-1) {
+ strnew+=lines[i];
+ strnew+="TOTAL_MEMORY:"+itos(max_memory*1024*1024)+",";
+ } else {
+ strnew+=lines[i]+"\n";
+ }
+ }
+
+ CharString cs = strnew.utf8();
+ html.resize(cs.size());
+ for(int i=9;i<cs.size();i++) {
+ html[i]=cs[i];
+ }
+}
+
+
+struct JSExportData {
+
+ EditorProgress *ep;
+ FileAccess *f;
+
+};
+
+
+static void store_file_buffer(FileAccess*f,const String& p_path,const Vector<uint8_t>& p_data) {
+
+
+ String pre = "Module['FS_createDataFile']('/', '"+p_path.replace("res://","")+"',[";
+ CharString cs = pre.utf8();
+ f->store_buffer((const uint8_t*)cs.ptr(),cs.length());
+ for(int i=0;i<p_data.size();i++) {
+
+
+ uint8_t c=',';
+ if (i>0)
+ f->store_buffer(&c,1);
+
+ uint8_t str[4];
+ uint8_t d = p_data[i];
+ if (d<10) {
+ str[0]='0'+d;
+ str[1]=0;
+ f->store_buffer(str,1);
+ } else if (d<100) {
+
+ str[0]='0'+d/10;
+ str[1]='0'+d%10;
+ str[2]=0;
+ f->store_buffer(str,2);
+
+ } else {
+ str[0]='0'+d/100;
+ str[1]='0'+(d/10)%10;
+ str[2]='0'+d%10;
+ str[3]=0;
+ f->store_buffer(str,3);
+ }
+ }
+ String post = "],true,true);\n";
+ cs = post.utf8();
+ f->store_buffer((const uint8_t*)cs.ptr(),cs.length());
+}
+
+
+Error EditorExportPlatformJavaScript::save_pack_file_js(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total) {
+
+ JSExportData *ed=(JSExportData*)p_userdata;
+
+ FileAccess *f=(FileAccess *)p_userdata;
+ store_file_buffer(ed->f,p_path,p_data);
+ ed->ep->step("File: "+p_path,3+p_file*100/p_total);
+ return OK;
+
+}
+
+Error EditorExportPlatformJavaScript::export_project(const String& p_path,bool p_debug,const String& p_password) {
+
+
+ String src_template;
+
+ EditorProgress ep("export","Exporting for javascript",104);
+
+ String template_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+
+ if (p_debug) {
+
+ src_template=custom_debug_package!=""?custom_debug_package:template_path+"javascript_debug.zip";
+ } else {
+
+ src_template=custom_release_package!=""?custom_release_package:template_path+"javascript_release.zip";
+
+ }
+
+
+ FileAccess *src_f=NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ ep.step("Exporting to HTML5",0);
+
+ unzFile pkg = unzOpen2(src_template.utf8().get_data(), &io);
+ if (!pkg) {
+
+ EditorNode::add_io_error("Could not find template HTML5 to export:\n"+src_template);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(pkg);
+
+
+ while(ret==UNZ_OK) {
+
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0);
+
+ String file=fname;
+
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg,data.ptr(),data.size());
+ unzCloseCurrentFile(pkg);
+
+ //write
+
+ if (file=="godot.html") {
+
+ _fix_html(data,p_path.get_file().basename(),1<<(max_memory+5));
+ file=p_path.get_file();
+ }
+ if (file=="godot.js") {
+
+ //_fix_godot(data);
+ file=p_path.get_file().basename()+".js";
+ }
+
+ String dst = p_path.get_base_dir().plus_file(file);
+ FileAccess *f=FileAccess::open(dst,FileAccess::WRITE);
+ if (!f) {
+ EditorNode::add_io_error("Could not create file for writing:\n"+dst);
+ unzClose(pkg);
+ return ERR_FILE_CANT_WRITE;
+ }
+ f->store_buffer(data.ptr(),data.size());
+ memdelete(f);
+
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+
+ ep.step("Finding Files..",1);
+
+ Vector<String> remaps;
+
+ FileAccess *f=FileAccess::open(p_path.basename()+"_files.js",FileAccess::WRITE);
+ if (!f) {
+ EditorNode::add_io_error("Could not create file for writing:\n"+p_path.basename()+"_files.js");
+ return ERR_FILE_CANT_WRITE;
+ }
+
+ f->store_buffer((const uint8_t*)files_pre,strlen(files_pre));
+
+ if (pack_mode==PACK_SINGLE_FILE) {
+
+ String ftmp = EditorSettings::get_singleton()->get_settings_path()+"/tmp/webpack.pck";
+ FileAccess *f2 = FileAccess::open(ftmp,FileAccess::WRITE);
+ if (!f2) {
+ memdelete(f);
+ return ERR_CANT_CREATE;
+ }
+ Error err = save_pack(f2,false);
+ memdelete(f2);
+ if (err) {
+ memdelete(f);
+ return ERR_CANT_CREATE;
+ }
+
+ Vector<uint8_t> data = FileAccess::get_file_as_array(ftmp);
+ store_file_buffer(f,"data.pck",data);
+
+
+ } else {
+ JSExportData ed;
+ ed.ep=&ep;
+ ed.f=f;
+
+ Error err =export_project_files(save_pack_file_js,&ed,false);
+ if (err)
+ return err;
+ }
+ f->store_buffer((const uint8_t*)files_post,strlen(files_post));
+ memdelete(f);
+
+
+ return OK;
+
+}
+
+
+Error EditorExportPlatformJavaScript::run(int p_device) {
+
+ String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmp_export.html";
+ Error err = export_project(path,true,"");
+ if (err)
+ return err;
+
+ OS::get_singleton()->shell_open(path);
+
+ return OK;
+}
+
+
+EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
+
+ show_run=false;
+ Image img( _javascript_logo );
+ logo = Ref<ImageTexture>( memnew( ImageTexture ));
+ logo->create_from_image(img);
+ max_memory=3;
+ pack_mode=PACK_SINGLE_FILE;
+}
+
+bool EditorExportPlatformJavaScript::can_export(String *r_error) const {
+
+
+ bool valid=true;
+ String err;
+ String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+
+ if (!FileAccess::exists(exe_path+"javascript_debug.zip") || !FileAccess::exists(exe_path+"javascript_release.zip")) {
+ valid=false;
+ err+="No export templates found.\nDownload and install export templates.\n";
+ }
+
+ if (custom_debug_package!="" && !FileAccess::exists(custom_debug_package)) {
+ valid=false;
+ err+="Custom debug package not found.\n";
+ }
+
+ if (custom_release_package!="" && !FileAccess::exists(custom_release_package)) {
+ valid=false;
+ err+="Custom release package not found.\n";
+ }
+
+ if (r_error)
+ *r_error=err;
+
+ return valid;
+}
+
+
+EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() {
+
+}
+
+
+void register_javascript_exporter() {
+
+
+ Ref<EditorExportPlatformJavaScript> exporter = Ref<EditorExportPlatformJavaScript>( memnew(EditorExportPlatformJavaScript) );
+ EditorImportExport::get_singleton()->add_export_platform(exporter);
+
+
+}
+
diff --git a/platform/javascript/export/export.h b/platform/javascript/export/export.h
new file mode 100644
index 0000000000..2b575c9149
--- /dev/null
+++ b/platform/javascript/export/export.h
@@ -0,0 +1,29 @@
+/*************************************************************************/
+/* export.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+void register_javascript_exporter();
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
new file mode 100644
index 0000000000..81485bab8e
--- /dev/null
+++ b/platform/javascript/javascript_main.cpp
@@ -0,0 +1,251 @@
+/*************************************************************************/
+/* javascript_main.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <GL/glut.h>
+#include "os_javascript.h"
+#include "main/main.h"
+#include "io/resource_loader.h"
+#include "os/keyboard.h"
+OS_JavaScript *os=NULL;
+
+static void _gfx_init(void *ud,bool gl2,int w, int h,bool fs) {
+
+ glutInitWindowSize(w, h);
+ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+ glutCreateWindow("godot");
+
+}
+
+
+static void _glut_skey(bool pressed,int key) {
+
+ InputEvent ev;
+ ev.type=InputEvent::KEY;
+ ev.key.pressed=pressed;
+ switch(key) {
+ case GLUT_KEY_F1: ev.key.scancode=KEY_F1; break;
+ case GLUT_KEY_F2: ev.key.scancode=KEY_F2; break;
+ case GLUT_KEY_F3: ev.key.scancode=KEY_F3; break;
+ case GLUT_KEY_F4: ev.key.scancode=KEY_F4; break;
+ case GLUT_KEY_F5: ev.key.scancode=KEY_F5; break;
+ case GLUT_KEY_F6: ev.key.scancode=KEY_F6; break;
+ case GLUT_KEY_F7: ev.key.scancode=KEY_F7; break;
+ case GLUT_KEY_F8: ev.key.scancode=KEY_F8; break;
+ case GLUT_KEY_F9: ev.key.scancode=KEY_F9; break;
+ case GLUT_KEY_F10: ev.key.scancode=KEY_F10; break;
+ case GLUT_KEY_F11: ev.key.scancode=KEY_F11; break;
+ case GLUT_KEY_F12: ev.key.scancode=KEY_F12; break;
+ case GLUT_KEY_LEFT: ev.key.scancode=KEY_LEFT; break;
+ case GLUT_KEY_UP: ev.key.scancode=KEY_UP; break;
+ case GLUT_KEY_RIGHT: ev.key.scancode=KEY_RIGHT; break;
+ case GLUT_KEY_DOWN: ev.key.scancode=KEY_DOWN; break;
+ case GLUT_KEY_PAGE_UP: ev.key.scancode=KEY_PAGEUP; break;
+ case GLUT_KEY_PAGE_DOWN: ev.key.scancode=KEY_PAGEDOWN; break;
+ case GLUT_KEY_HOME: ev.key.scancode=KEY_HOME; break;
+ case GLUT_KEY_END: ev.key.scancode=KEY_END; break;
+ case GLUT_KEY_INSERT: ev.key.scancode=KEY_INSERT; break;
+ }
+
+
+ uint32_t m = glutGetModifiers();
+ ev.key.mod.alt=(m&GLUT_ACTIVE_ALT)!=0;
+ ev.key.mod.shift=(m&GLUT_ACTIVE_SHIFT)!=0;
+ ev.key.mod.control=(m&GLUT_ACTIVE_CTRL)!=0;
+
+ os->push_input(ev);
+}
+
+static void _glut_skey_up(int key, int x, int y) {
+
+ _glut_skey(false,key);
+}
+
+static void _glut_skey_down(int key, int x, int y) {
+
+ _glut_skey(true,key);
+}
+
+static void _glut_key(bool pressed,unsigned char key) {
+
+ InputEvent ev;
+ ev.type=InputEvent::KEY;
+ ev.key.pressed=pressed;
+ switch(key) {
+ case '\n': ev.key.scancode=KEY_RETURN; break;
+ case 0x1b: ev.key.scancode=KEY_ESCAPE; break;
+ case 8: ev.key.scancode=KEY_BACKSPACE; break;
+ case 0x7f: ev.key.scancode=KEY_DELETE; break;
+ case 0x20: ev.key.scancode=KEY_SPACE; ev.key.unicode=key; break;
+ default: {
+ ev.key.unicode=key;
+ }
+ }
+
+
+ uint32_t m = glutGetModifiers();
+ ev.key.mod.alt=(m&GLUT_ACTIVE_ALT)!=0;
+ ev.key.mod.shift=(m&GLUT_ACTIVE_SHIFT)!=0;
+ ev.key.mod.control=(m&GLUT_ACTIVE_CTRL)!=0;
+
+ os->push_input(ev);
+
+}
+
+static void _glut_key_up(unsigned char key, int x, int y) {
+
+ _glut_key(false,key);
+}
+
+static void _glut_key_down(unsigned char key, int x, int y) {
+
+ _glut_key(true,key);
+}
+
+static uint32_t _mouse_button_mask=0;
+
+static void _glut_mouse_button(int button, int state, int x, int y) {
+
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ switch(button) {
+ case GLUT_LEFT_BUTTON: ev.mouse_button.button_index=BUTTON_LEFT; break;
+ case GLUT_MIDDLE_BUTTON: ev.mouse_button.button_index=BUTTON_MIDDLE; break;
+ case GLUT_RIGHT_BUTTON: ev.mouse_button.button_index=BUTTON_RIGHT; break;
+ case 3: ev.mouse_button.button_index=BUTTON_WHEEL_UP; break;
+ case 4: ev.mouse_button.button_index=BUTTON_WHEEL_DOWN; break;
+ }
+
+
+ ev.mouse_button.pressed=state==GLUT_DOWN;
+ ev.mouse_button.x=x;
+ ev.mouse_button.y=y;
+ ev.mouse_button.global_x=x;
+ ev.mouse_button.global_y=y;
+
+ if (ev.mouse_button.button_index<4) {
+ if (ev.mouse_button.pressed) {
+ _mouse_button_mask|=1<<ev.mouse_button.button_index;
+ } else {
+ _mouse_button_mask&=~(1<<ev.mouse_button.button_index);
+ }
+ }
+
+ uint32_t m = glutGetModifiers();
+ ev.mouse_button.mod.alt=(m&GLUT_ACTIVE_ALT)!=0;
+ ev.mouse_button.mod.shift=(m&GLUT_ACTIVE_SHIFT)!=0;
+ ev.mouse_button.mod.control=(m&GLUT_ACTIVE_CTRL)!=0;
+
+ os->push_input(ev);
+
+}
+
+
+static int _glut_prev_x=0;
+static int _glut_prev_y=0;
+
+static void _glut_mouse_motion(int x, int y) {
+
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_MOTION;
+ ev.mouse_motion.button_mask=_mouse_button_mask;
+ ev.mouse_motion.x=x;
+ ev.mouse_motion.y=y;
+ ev.mouse_motion.global_x=x;
+ ev.mouse_motion.global_y=y;
+ ev.mouse_motion.relative_x=x-_glut_prev_x;
+ ev.mouse_motion.relative_y=y-_glut_prev_y;
+ _glut_prev_x=x;
+ _glut_prev_y=y;
+
+ uint32_t m = glutGetModifiers();
+ ev.mouse_motion.mod.alt=(m&GLUT_ACTIVE_ALT)!=0;
+ ev.mouse_motion.mod.shift=(m&GLUT_ACTIVE_SHIFT)!=0;
+ ev.mouse_motion.mod.control=(m&GLUT_ACTIVE_CTRL)!=0;
+
+ os->push_input(ev);
+
+}
+
+static void _gfx_idle() {
+
+ glutPostRedisplay();
+}
+
+static void _godot_draw(void) {
+
+ os->main_loop_iterate();
+ glutSwapBuffers();
+}
+
+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);
+#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);
+ Error err = Main::setup("",0,NULL);
+
+#endif
+ ResourceLoader::set_abort_on_missing_resources(false); //ease up compatibility
+ Main::start();
+
+ glutSpecialUpFunc(_glut_skey_up);
+ glutSpecialFunc(_glut_skey_down);
+ glutKeyboardUpFunc(_glut_key_up);
+ glutKeyboardFunc(_glut_key_down);
+ glutMouseFunc(_glut_mouse_button);
+ glutMotionFunc(_glut_mouse_motion);
+ glutMotionFunc(_glut_mouse_motion);
+ glutPassiveMotionFunc(_glut_mouse_motion);
+
+
+
+ /* Set up glut callback functions */
+ glutIdleFunc (_gfx_idle);
+// glutReshapeFunc(gears_reshape);
+ glutDisplayFunc(_godot_draw);
+ //glutSpecialFunc(gears_special);
+ os->main_loop_begin();
+
+ glutMainLoop();
+
+ return 0;
+}
+
+
+/*
+ *
+ *09] <azakai|2__> reduz: yes, define TOTAL_MEMORY on Module. for example var Module = { TOTAL_MEMORY: 12345.. }; before the main
+ *
+ */
diff --git a/platform/javascript/logo.png b/platform/javascript/logo.png
new file mode 100644
index 0000000000..07e0a41292
--- /dev/null
+++ b/platform/javascript/logo.png
Binary files differ
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
new file mode 100644
index 0000000000..c131a7e84b
--- /dev/null
+++ b/platform/javascript/os_javascript.cpp
@@ -0,0 +1,593 @@
+/*************************************************************************/
+/* os_javascript.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#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"
+
+int OS_JavaScript::get_video_driver_count() const {
+
+ return 1;
+}
+const char * OS_JavaScript::get_video_driver_name(int p_driver) const {
+
+ return "GLES2";
+}
+
+OS::VideoMode OS_JavaScript::get_default_video_mode() const {
+
+ return OS::VideoMode();
+}
+
+int OS_JavaScript::get_audio_driver_count() const {
+
+ return 1;
+}
+
+const char * OS_JavaScript::get_audio_driver_name(int p_driver) const {
+
+ return "JavaScript";
+}
+
+void OS_JavaScript::initialize_core() {
+
+ OS_Unix::initialize_core();
+ FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix> >(FileAccess::ACCESS_RESOURCES);
+
+}
+
+void OS_JavaScript::set_opengl_extensions(const char* p_gl_extensions) {
+
+ ERR_FAIL_COND(!p_gl_extensions);
+ gl_extensions=p_gl_extensions;
+}
+
+void OS_JavaScript::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ print_line("Init OS");
+
+ 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;
+
+ print_line("Init Audio");
+
+ AudioDriverManagerSW::add_driver(&audio_driver_javascript);
+
+ if (true) {
+ 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) );
+ }
+
+ print_line("Init VS");
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ visual_server->init();
+ visual_server->cursor_set_visible(false, 0);
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ print_line("Init SM");
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+
+ 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 );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+}
+
+void OS_JavaScript::set_main_loop( MainLoop * p_main_loop ) {
+
+ main_loop=p_main_loop;
+ input->set_main_loop(p_main_loop);
+
+}
+
+void OS_JavaScript::delete_main_loop() {
+
+ memdelete( main_loop );
+}
+
+void OS_JavaScript::finalize() {
+
+ memdelete(input);
+}
+
+
+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());
+}
+
+
+void OS_JavaScript::set_mouse_show(bool p_show) {
+
+ //javascript has no mouse...
+}
+
+void OS_JavaScript::set_mouse_grab(bool p_grab) {
+
+ //it really has no mouse...!
+}
+
+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();
+}
+int OS_JavaScript::get_mouse_button_state() const {
+
+ return 0;
+}
+void OS_JavaScript::set_window_title(const String& p_title) {
+
+
+}
+
+//interesting byt not yet
+//void set_clipboard(const String& p_text);
+//String get_clipboard() const;
+
+void OS_JavaScript::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+
+}
+
+OS::VideoMode OS_JavaScript::get_video_mode(int p_screen) const {
+
+ return default_videomode;
+}
+void OS_JavaScript::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+ p_list->push_back(default_videomode);
+}
+
+String OS_JavaScript::get_name() {
+
+ return "HTML5";
+}
+
+MainLoop *OS_JavaScript::get_main_loop() const {
+
+ return main_loop;
+}
+
+bool OS_JavaScript::can_draw() const {
+
+ return true; //always?
+}
+
+void OS_JavaScript::set_cursor_shape(CursorShape p_shape) {
+
+ //javascript really really really has no mouse.. how amazing..
+}
+
+void OS_JavaScript::main_loop_begin() {
+
+ if (main_loop)
+ main_loop->init();
+}
+bool OS_JavaScript::main_loop_iterate() {
+
+ if (!main_loop)
+ return false;
+ return Main::iteration();
+}
+
+void OS_JavaScript::main_loop_end() {
+
+ if (main_loop)
+ main_loop->finish();
+
+}
+
+void OS_JavaScript::main_loop_focusout() {
+
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+ //audio_driver_javascript.set_pause(true);
+
+}
+
+void OS_JavaScript::main_loop_focusin(){
+
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+ //audio_driver_javascript.set_pause(false);
+
+}
+
+void OS_JavaScript::push_input(const InputEvent& p_ev) {
+
+ InputEvent ev = p_ev;
+ ev.ID=last_id++;
+ 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()));
+
+ switch(p_what) {
+ case 0: { //gesture begin
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=last_id++;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ input->parse_input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+
+ }
+ }
+
+ touch.resize(p_points.size());
+ for(int i=0;i<p_points.size();i++) {
+ touch[i].id=p_points[i].id;
+ touch[i].pos=p_points[i].pos;
+ }
+
+ {
+ //send mouse
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=last_id++;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=true;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ last_mouse=touch[0].pos;
+ input->parse_input_event(ev);
+ }
+
+
+ //send touch
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+ }
+
+ } break;
+ case 1: { //motion
+
+
+ if (p_points.size()) {
+ //send mouse, should look for point 0?
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_MOTION;
+ ev.ID=last_id++;
+ ev.mouse_motion.button_mask=BUTTON_MASK_LEFT;
+ 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.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;
+ input->parse_input_event(ev);
+ }
+
+ ERR_FAIL_COND(touch.size()!=p_points.size());
+
+ for(int i=0;i<touch.size();i++) {
+
+ int idx=-1;
+ for(int j=0;j<p_points.size();j++) {
+
+ if (touch[i].id==p_points[j].id) {
+ idx=j;
+ break;
+ }
+
+ }
+
+ ERR_CONTINUE(idx==-1);
+
+ if (touch[i].pos==p_points[idx].pos)
+ continue; //no move unncesearily
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_DRAG;
+ ev.ID=last_id++;
+ ev.screen_drag.index=touch[i].id;
+ ev.screen_drag.x=p_points[idx].pos.x;
+ ev.screen_drag.y=p_points[idx].pos.y;
+ ev.screen_drag.relative_x=p_points[idx].pos.x - touch[i].pos.x;
+ ev.screen_drag.relative_y=p_points[idx].pos.y - touch[i].pos.y;
+ input->parse_input_event(ev);
+ touch[i].pos=p_points[idx].pos;
+ }
+
+
+ } break;
+ case 2: { //release
+
+
+
+ if (touch.size()) {
+ //end all if exist
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.ID=last_id++;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.button_mask=BUTTON_MASK_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=touch[0].pos.x;
+ ev.mouse_button.y=touch[0].pos.y;
+ ev.mouse_button.global_x=touch[0].pos.x;
+ ev.mouse_button.global_y=touch[0].pos.y;
+ input->parse_input_event(ev);
+
+
+ for(int i=0;i<touch.size();i++) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+
+ }
+ touch.clear();
+ }
+
+ } break;
+ case 3: { // add tuchi
+
+
+
+
+
+ ERR_FAIL_INDEX(p_pointer,p_points.size());
+
+ TouchPos tp=p_points[p_pointer];
+ touch.push_back(tp);
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=tp.id;
+ ev.screen_touch.pressed=true;
+ ev.screen_touch.x=tp.pos.x;
+ ev.screen_touch.y=tp.pos.y;
+ input->parse_input_event(ev);
+
+ } break;
+ case 4: {
+
+
+ for(int i=0;i<touch.size();i++) {
+ if (touch[i].id==p_pointer) {
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.ID=last_id++;
+ ev.screen_touch.index=touch[i].id;
+ ev.screen_touch.pressed=false;
+ ev.screen_touch.x=touch[i].pos.x;
+ ev.screen_touch.y=touch[i].pos.y;
+ input->parse_input_event(ev);
+ touch.remove(i);
+ i--;
+ }
+ }
+
+ } break;
+
+ }
+
+}
+
+void OS_JavaScript::process_accelerometer(const Vector3& p_accelerometer) {
+
+ input->set_accelerometer(p_accelerometer);
+}
+
+bool OS_JavaScript::has_touchscreen_ui_hint() const {
+
+ return true;
+}
+
+void OS_JavaScript::main_loop_request_quit() {
+
+ if (main_loop)
+ 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);
+ 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;
+};
+
+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();
+ return "/";
+ //return Globals::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
+};
+
+
+
+
+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;
+
+ gfx_init_func=p_gfx_init_func;
+ gfx_init_ud=p_gfx_init_ud;
+ main_loop=NULL;
+ last_id=1;
+ gl_extensions=NULL;
+ rasterizer=NULL;
+
+ open_uri_func=p_open_uri_func;
+ get_data_dir_func=p_get_data_dir_func;
+ get_locale_func=p_get_locale_func;
+
+
+}
+
+OS_JavaScript::~OS_JavaScript() {
+
+
+}
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
new file mode 100644
index 0000000000..dfc93d3ff0
--- /dev/null
+++ b/platform/javascript/os_javascript.h
@@ -0,0 +1,164 @@
+/*************************************************************************/
+/* os_javascript.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef OS_JAVASCRIPT_H
+#define OS_JAVASCRIPT_H
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+#include "os/main_loop.h"
+#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/physics_2d/physics_2d_server_sw.h"
+#include "servers/visual/rasterizer.h"
+
+#include "audio_driver_javascript.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:
+
+ struct TouchPos {
+ int id;
+ Point2 pos;
+ };
+
+private:
+
+ Vector<TouchPos> touch;
+
+ Point2 last_mouse;
+ unsigned int last_id;
+ GFXInitFunc gfx_init_func;
+ void*gfx_init_ud;
+
+ bool use_gl2;
+
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+ AudioServerSW *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;
+ MainLoop * main_loop;
+
+ OpenURIFunc open_uri_func;
+ GetDataDirFunc get_data_dir_func;
+ GetLocaleFunc get_locale_func;
+
+public:
+
+ // functions used by main to initialize/deintialize the OS
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
+ virtual void initialize_core();
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+
+
+ typedef int64_t ProcessID;
+
+ 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 set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ //virtual void set_clipboard(const String& p_text);
+ //virtual String get_clipboard() const;
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ 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 String get_name();
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ void main_loop_begin();
+ bool main_loop_iterate();
+ void main_loop_request_quit();
+ void main_loop_end();
+ void main_loop_focusout();
+ void main_loop_focusin();
+
+ 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;
+ 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);
+ void push_input(const InputEvent& p_ev);
+ 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();
+
+};
+
+#endif
diff --git a/platform/javascript/platform_config.h b/platform/javascript/platform_config.h
new file mode 100644
index 0000000000..38fc934ae4
--- /dev/null
+++ b/platform/javascript/platform_config.h
@@ -0,0 +1,29 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <alloca.h>
diff --git a/platform/nacl/SCsub b/platform/nacl/SCsub
new file mode 100644
index 0000000000..ac01752dbb
--- /dev/null
+++ b/platform/nacl/SCsub
@@ -0,0 +1,30 @@
+Import('env')
+
+nacl_lib = [
+
+ 'os_nacl.cpp',
+ 'audio_driver_nacl.cpp',
+ 'godot_nacl.cpp',
+ #'pepper_main.cpp',
+ 'opengl_context.cpp',
+ 'godot_module.cpp',
+ 'geturl_handler.cpp',
+]
+
+nacl_posix = [
+
+ '#drivers/unix/thread_posix.cpp',
+ '#drivers/unix/mutex_posix.cpp',
+ '#drivers/unix/semaphore_posix.cpp',
+]
+
+posix_lib = []
+for f in nacl_posix:
+ posix_lib.append(env.Object(f, CPPFLAGS = env['CPPFLAGS']+['-DUNIX_ENABLED'], OBJSUFFIX = '.posix'+env['OBJSUFFIX']))
+
+prog = env.Program('#bin/godot_nacl', nacl_lib + posix_lib)
+
+if (env['nacl_arch'] == 'i686'):
+ env.Alias("nacl_32", prog)
+if (env['nacl_arch'] == 'x86_64'):
+ env.Alias("nacl_64", prog)
diff --git a/platform/nacl/audio_driver_nacl.cpp b/platform/nacl/audio_driver_nacl.cpp
new file mode 100644
index 0000000000..8f1861eee3
--- /dev/null
+++ b/platform/nacl/audio_driver_nacl.cpp
@@ -0,0 +1,106 @@
+/*************************************************************************/
+/* audio_driver_nacl.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "audio_driver_nacl.h"
+
+#include "ppapi/cpp/instance.h"
+
+extern pp::Instance* godot_instance;
+
+const char* AudioDriverNacl::get_name() const {
+
+ return "Nacl";
+}
+
+void AudioDriverNacl::output_callback(void* samples, uint32_t buffer_size, void* data) {
+
+ AudioDriverNacl* ad = (AudioDriverNacl*)data;
+ int16_t* out = (int16_t*)samples;
+
+ ad->lock();
+ ad->audio_server_process(ad->sample_frame_count_, ad->samples_in);
+ ad->unlock();
+
+ for (int i=0; i<ad->sample_count; i++) {
+
+ out[i] = ad->samples_in[i]>>16;
+ };
+
+};
+
+Error AudioDriverNacl::init(){
+
+ int frame_size = 4096;
+ sample_frame_count_ = pp::AudioConfig::RecommendSampleFrameCount(godot_instance,PP_AUDIOSAMPLERATE_44100, frame_size);
+ sample_count = sample_frame_count_ * 2;
+
+ audio_ = pp::Audio(godot_instance,
+ pp::AudioConfig(godot_instance,
+ PP_AUDIOSAMPLERATE_44100,
+ sample_frame_count_),
+ &AudioDriverNacl::output_callback,
+ this);
+
+ samples_in = memnew_arr(int32_t, sample_frame_count_ * 2);
+
+ return OK;
+}
+void AudioDriverNacl::start(){
+
+ audio_.StartPlayback();
+}
+int AudioDriverNacl::get_mix_rate() const {
+
+ return 44100;
+}
+AudioDriverSW::OutputFormat AudioDriverNacl::get_output_format() const{
+
+ return OUTPUT_STEREO;
+}
+void AudioDriverNacl::lock(){
+
+}
+void AudioDriverNacl::unlock() {
+
+
+}
+void AudioDriverNacl::finish(){
+
+ audio_.StopPlayback();
+}
+
+
+AudioDriverNacl::AudioDriverNacl() {
+}
+
+AudioDriverNacl::~AudioDriverNacl() {
+
+ memdelete_arr(samples_in);
+}
+
+
diff --git a/platform/nacl/audio_driver_nacl.h b/platform/nacl/audio_driver_nacl.h
new file mode 100644
index 0000000000..4a45d0bb4b
--- /dev/null
+++ b/platform/nacl/audio_driver_nacl.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* audio_driver_nacl.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef AUDIO_DRIVER_NACL_H
+#define AUDIO_DRIVER_NACL_H
+
+#include "servers/audio/audio_server_sw.h"
+
+#include "ppapi/cpp/audio.h"
+
+class AudioDriverNacl : public AudioDriverSW {
+
+ static void output_callback(void* samples, uint32_t buffer_size, void* data);
+
+ int32_t* samples_in;
+ int sample_frame_count_;
+ int sample_count;
+ pp::Audio audio_;
+
+public:
+
+ virtual const char* get_name() const;
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const ;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+
+ AudioDriverNacl();
+ ~AudioDriverNacl();
+};
+
+#endif // AUDIO_DRIVER_NACL_H
+
diff --git a/platform/nacl/context_gl_nacl.cpp b/platform/nacl/context_gl_nacl.cpp
new file mode 100644
index 0000000000..70cf01a16e
--- /dev/null
+++ b/platform/nacl/context_gl_nacl.cpp
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* context_gl_nacl.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "context_gl_nacl.h"
+
+#include <nacl/npapi.h>
+#include <nacl/npruntime.h>
+#include <nacl/npapi_extensions.h>
+#include <nacl/npupp.h>
+#include <pgl/pgl.h>
+#include <GLES2/gl2.h>
+
+void ContextGLNacl::make_current() {
+
+};
+
+int ContextGLNacl::get_window_width() {
+
+};
+
+int ContextGLNacl::get_window_height() {
+
+};
+
+void ContextGLNacl::swap_buffers() {
+
+};
+
+Error ContextGLNacl::initialize() {
+
+};
+
+
+ContextGLNacl::ContextGLNacl() {
+
+
+};
+
+ContextGLNacl::~ContextGLNacl() {
+
+};
+
diff --git a/platform/nacl/context_gl_nacl.h b/platform/nacl/context_gl_nacl.h
new file mode 100644
index 0000000000..a5cf7a728c
--- /dev/null
+++ b/platform/nacl/context_gl_nacl.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* context_gl_nacl.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CONTEXT_GL_NACL_H
+#define CONTEXT_GL_NACL_H
+
+#include "drivers/gl_context/context_gl.h"
+
+class NPDevice;
+
+class ContextGLNacl : public ContextGL {
+
+ enum {
+ COMMAND_BUFFER_SIZE = 1024 * 1024,
+ };
+
+ NPDevice* device3d_;
+
+public:
+
+ virtual void make_current();
+
+ virtual int get_window_width();
+ virtual int get_window_height();
+ virtual void swap_buffers();
+
+ virtual Error initialize();
+
+ ContextGLNacl();
+ ~ContextGLNacl();
+};
+
+#endif // CONTEXT_GL_NACL_H
diff --git a/platform/nacl/detect.py b/platform/nacl/detect.py
new file mode 100644
index 0000000000..f8849cfd25
--- /dev/null
+++ b/platform/nacl/detect.py
@@ -0,0 +1,71 @@
+import os
+import sys
+
+def is_active():
+ return True
+
+def get_name():
+ return "NaCl"
+
+def can_build():
+
+ import os
+ if not os.environ.has_key("NACLPATH"):
+ return False
+ return True
+
+def get_opts():
+
+ return [
+ ('NACLPATH', 'the path to nacl', os.environ.get("NACLPATH", 0)),
+ ('nacl_arch', 'The architecture for Nacl build (can be i686 or x86_64', 'i686'),
+ ]
+
+def get_flags():
+
+ return [
+ ('nedmalloc', 'no'),
+ ('tools', 'no'),
+ ]
+
+
+
+def configure(env):
+
+ env.Append(CPPPATH=['#platform/nacl'])
+
+ env['OBJSUFFIX'] = ".nacl.${nacl_arch}.o"
+ env['LIBSUFFIX'] = ".nacl.${nacl_arch}.a"
+ env['PROGSUFFIX'] = ".${nacl_arch}.nexe"
+
+ env['ENV']['PATH'] = env['ENV']['PATH']+":"+env['NACLPATH']+"/toolchain/linux_x86_newlib/bin"
+
+ env['CC'] = '${nacl_arch}-nacl-gcc'
+ env['CXX'] = '${nacl_arch}-nacl-g++'
+ env['AR'] = '${nacl_arch}-nacl-ar'
+
+ env.Append(CCFLAGS=['-fexceptions', '-Wno-long-long', '-pthread', '-DXP_UNIX'])
+
+ env.Append(CPPPATH=env['NACLPATH'])
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O2','-ffast-math','-fomit-frame-pointer', '-ffunction-sections', '-fdata-sections', '-fno-default-inline'])
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-g', '-O0', '-Wall','-DDEBUG_ENABLED'])
+
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-g','-pg'])
+ env.Append(LINKFLAGS=['-pg'])
+
+ env.Append(CCFLAGS=['-DNACL_ENABLED', '-DGLES2_ENABLED'])
+
+ env.Append(LIBFLAGS=['m32'])
+ env.Append(LIBS=env.Split('ppapi ppapi_cpp pthread srpc ppapi_gles22'))
+
+ import methods
+ env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
diff --git a/platform/nacl/geturl_handler.cpp b/platform/nacl/geturl_handler.cpp
new file mode 100644
index 0000000000..4873d691ce
--- /dev/null
+++ b/platform/nacl/geturl_handler.cpp
@@ -0,0 +1,150 @@
+/*************************************************************************/
+/* geturl_handler.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "geturl_handler.h"
+
+#include "core/os/copymem.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/var.h"
+
+void GetURLHandler::Start() {
+ pp::CompletionCallback cc =
+ cc_factory_.NewCallback(&GetURLHandler::OnOpen);
+ url_loader_.Open(url_request_, cc);
+}
+
+void GetURLHandler::OnOpen(int32_t result) {
+ if (result != PP_OK) {
+ status = STATUS_ERROR;
+ return;
+ }
+ // Here you would process the headers. A real program would want to at least
+ // check the HTTP code and potentially cancel the request.
+ // pp::URLResponseInfo response = loader_.GetResponseInfo();
+
+ // Start streaming.
+ ReadBody();
+}
+
+void GetURLHandler::AppendDataBytes(const char* buffer, int32_t num_bytes) {
+ if (num_bytes <= 0)
+ return;
+ // Make sure we don't get a buffer overrun.
+ num_bytes = std::min(READ_BUFFER_SIZE, num_bytes);
+ int ofs = data.size();
+ data.resize(ofs + num_bytes);
+ copymem(&data[ofs], buffer, num_bytes);
+}
+
+void GetURLHandler::OnRead(int32_t result) {
+ if (result == PP_OK) {
+ // Streaming the file is complete.
+ status = STATUS_COMPLETED;
+ instance_->HandleMessage("package_finished");
+ instance_->HandleMessage(0);
+ printf("completed!\n");
+ } else if (result > 0) {
+ // The URLLoader just filled "result" number of bytes into our buffer.
+ // Save them and perform another read.
+ AppendDataBytes(buffer_, result);
+ ReadBody();
+ } else {
+ // A read error occurred.
+ status = STATUS_ERROR;
+ ERR_FAIL_COND(result < 0);
+ }
+}
+
+void GetURLHandler::ReadBody() {
+ // Note that you specifically want an "optional" callback here. This will
+ // allow ReadBody() to return synchronously, ignoring your completion
+ // callback, if data is available. For fast connections and large files,
+ // reading as fast as we can will make a large performance difference
+ // However, in the case of a synchronous return, we need to be sure to run
+ // the callback we created since the loader won't do anything with it.
+ pp::CompletionCallback cc =
+ cc_factory_.NewOptionalCallback(&GetURLHandler::OnRead);
+ int32_t result = PP_OK;
+ do {
+ result = url_loader_.ReadResponseBody(buffer_, sizeof(buffer_), cc);
+ // Handle streaming data directly. Note that we *don't* want to call
+ // OnRead here, since in the case of result > 0 it will schedule
+ // another call to this function. If the network is very fast, we could
+ // end up with a deeply recursive stack.
+ if (result > 0) {
+ AppendDataBytes(buffer_, result);
+ }
+ } while (result > 0);
+
+ if (result != PP_OK_COMPLETIONPENDING) {
+ // Either we reached the end of the stream (result == PP_OK) or there was
+ // an error. We want OnRead to get called no matter what to handle
+ // that case, whether the error is synchronous or asynchronous. If the
+ // result code *is* COMPLETIONPENDING, our callback will be called
+ // asynchronously.
+ cc.Run(result);
+ }
+}
+
+GetURLHandler::Status GetURLHandler::get_status() const {
+
+ return status;
+};
+
+Vector<uint8_t> GetURLHandler::get_data() const {
+
+ return data;
+};
+
+int GetURLHandler::get_bytes_read() const {
+
+ return data.size();
+};
+
+GetURLHandler::GetURLHandler(pp::Instance* instance,
+ const String& url)
+ : instance_(instance),
+ url_(url),
+ url_request_(instance),
+ url_loader_(instance),
+ cc_factory_(this) {
+ url_request_.SetURL(std::string(url.utf8().get_data()));
+ url_request_.SetMethod("GET");
+ status = STATUS_NONE;
+ printf("url handler for url %ls!\n", url.c_str());
+}
+
+GetURLHandler::~GetURLHandler() {
+}
+
+
diff --git a/platform/nacl/geturl_handler.h b/platform/nacl/geturl_handler.h
new file mode 100644
index 0000000000..44086ae7c1
--- /dev/null
+++ b/platform/nacl/geturl_handler.h
@@ -0,0 +1,115 @@
+/*************************************************************************/
+/* geturl_handler.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef EXAMPLES_GETURL_GETURL_HANDLER_H_
+#define EXAMPLES_GETURL_GETURL_HANDLER_H_
+
+#include "core/ustring.h"
+#include "core/vector.h"
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/url_loader.h"
+#include "ppapi/cpp/url_request_info.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/utility/completion_callback_factory.h"
+
+#define READ_BUFFER_SIZE 32768
+
+// GetURLHandler is used to download data from |url|. When download is
+// finished or when an error occurs, it posts a message back to the browser
+// with the results encoded in the message as a string and self-destroys.
+//
+// EXAMPLE USAGE:
+// GetURLHandler* handler* = GetURLHandler::Create(instance,url);
+// handler->Start();
+//
+class GetURLHandler {
+
+public:
+
+ enum Status {
+
+ STATUS_NONE,
+ STATUS_IN_PROGRESS,
+ STATUS_COMPLETED,
+ STATUS_ERROR,
+ };
+
+private:
+
+ Status status;
+
+ // Callback fo the pp::URLLoader::Open().
+ // Called by pp::URLLoader when response headers are received or when an
+ // error occurs (in response to the call of pp::URLLoader::Open()).
+ // Look at <ppapi/c/ppb_url_loader.h> and
+ // <ppapi/cpp/url_loader.h> for more information about pp::URLLoader.
+ void OnOpen(int32_t result);
+
+ // Callback fo the pp::URLLoader::ReadResponseBody().
+ // |result| contains the number of bytes read or an error code.
+ // Appends data from this->buffer_ to this->url_response_body_.
+ void OnRead(int32_t result);
+
+ // Reads the response body (asynchronously) into this->buffer_.
+ // OnRead() will be called when bytes are received or when an error occurs.
+ void ReadBody();
+
+ // Append data bytes read from the URL onto the internal buffer. Does
+ // nothing if |num_bytes| is 0.
+ void AppendDataBytes(const char* buffer, int32_t num_bytes);
+
+ pp::Instance* instance_; // Weak pointer.
+ String url_; // URL to be downloaded.
+ pp::URLRequestInfo url_request_;
+ pp::URLLoader url_loader_; // URLLoader provides an API to download URLs.
+ char buffer_[READ_BUFFER_SIZE]; // Temporary buffer for reads.
+ Vector<uint8_t> data; // Contains accumulated downloaded data.
+ pp::CompletionCallbackFactory<GetURLHandler> cc_factory_;
+ bool complete;
+
+ GetURLHandler(const GetURLHandler&);
+ void operator=(const GetURLHandler&);
+
+public:
+ // Creates instance of GetURLHandler on the heap.
+ // GetURLHandler objects shall be created only on the heap (they
+ // self-destroy when all data is in).
+ // Initiates page (URL) download.
+ void Start();
+
+ Status get_status() const;
+ Vector<uint8_t> get_data() const;
+
+ int get_bytes_read() const;
+
+ GetURLHandler(pp::Instance* instance_, const String& url);
+ ~GetURLHandler();
+};
+
+#endif // EXAMPLES_GETURL_GETURL_HANDLER_H_
+
diff --git a/platform/nacl/godot_module.cpp b/platform/nacl/godot_module.cpp
new file mode 100644
index 0000000000..b5a049d9bf
--- /dev/null
+++ b/platform/nacl/godot_module.cpp
@@ -0,0 +1,332 @@
+/*************************************************************************/
+/* godot_module.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "opengl_context.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/gles2/gl2ext_ppapi.h"
+
+#include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/size.h"
+#include "ppapi/cpp/var.h"
+#include "geturl_handler.h"
+
+#include "core/variant.h"
+#include "os_nacl.h"
+
+extern int nacl_main(int argc, const char** argn, const char** argv);
+extern void nacl_cleanup();
+
+static String pkg_url;
+
+pp::Instance* godot_instance = NULL;
+
+struct StateData {
+ int arg_count;
+ Array args;
+ String method;
+};
+
+extern OSNacl* os_nacl;
+
+class GodotInstance : public pp::Instance {
+
+ enum State {
+ STATE_METHOD,
+ STATE_PARAM_COUNT,
+ STATE_PARAMS,
+ STATE_CALL,
+ };
+
+ State state;
+ StateData* sd;
+ SharedOpenGLContext opengl_context_;
+ int width;
+ int height;
+
+ #define MAX_ARGS 64
+ uint32_t init_argc;
+ char* init_argn[MAX_ARGS];
+ char* init_argv[MAX_ARGS];
+
+ bool package_loaded;
+ GetURLHandler* package_pending;
+
+public:
+ explicit GodotInstance(PP_Instance instance) : pp::Instance(instance) {
+ printf("GodotInstance!\n");
+ state = STATE_METHOD;
+ RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_KEYBOARD | PP_INPUTEVENT_CLASS_WHEEL | PP_INPUTEVENT_CLASS_TOUCH);
+ sd = NULL;
+ package_pending = NULL;
+ package_loaded = false;
+ godot_instance = this;
+ }
+ virtual ~GodotInstance() {
+
+ nacl_cleanup();
+ }
+
+ /// Called by the browser to handle the postMessage() call in Javascript.
+ /// Detects which method is being called from the message contents, and
+ /// calls the appropriate function. Posts the result back to the browser
+ /// asynchronously.
+ /// @param[in] var_message The message posted by the browser. The possible
+ /// messages are 'fortyTwo' and 'reverseText:Hello World'. Note that
+ /// the 'reverseText' form contains the string to reverse following a ':'
+ /// separator.
+ virtual void HandleMessage(const pp::Var& var_message);
+
+ bool HandleInputEvent(const pp::InputEvent& event);
+
+ bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
+
+ printf("******* init! %i, %p, %p\n", argc, argn, argv);
+ fflush(stdout);
+ if (opengl_context_ == NULL) {
+ opengl_context_.reset(new OpenGLContext(this));
+ };
+ opengl_context_->InvalidateContext(this);
+ opengl_context_->ResizeContext(pp::Size(0, 0));
+ int current = opengl_context_->MakeContextCurrent(this);
+ printf("current is %i\n", current);
+
+ os_nacl = new OSNacl;
+
+ pkg_url = "";
+ for (uint32_t i=0; i<argc; i++) {
+ if (strcmp(argn[i], "package") == 0) {
+ pkg_url = argv[i];
+ };
+ };
+
+ sd = memnew(StateData);
+
+ if (pkg_url == "") {
+ nacl_main(argc, argn, argv);
+ } else {
+ printf("starting package %ls\n", pkg_url.c_str());
+ init_argc = MIN(argc, MAX_ARGS-1);
+ for (uint32_t i=0; i<argc; i++) {
+
+ int nlen = strlen(argn[i]);
+ init_argn[i] = (char*)memalloc(nlen+1);
+ strcpy(init_argn[i], argn[i]);
+ init_argn[i+1] = NULL;
+
+ int len = strlen(argv[i]);
+ init_argv[i] = (char*)memalloc(len+1);
+ strcpy(init_argv[i], argv[i]);
+ init_argv[i+1] = NULL;
+ };
+ package_pending = memnew(GetURLHandler(this, pkg_url));
+ package_pending->Start();
+ };
+ return true;
+ };
+
+ // Called whenever the in-browser window changes size.
+ virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
+
+ if (position.size().width() == width &&
+ position.size().height() == height)
+ return; // Size didn't change, no need to update anything.
+
+ if (opengl_context_ == NULL) {
+ opengl_context_.reset(new OpenGLContext(this));
+ };
+ opengl_context_->InvalidateContext(this);
+ opengl_context_->ResizeContext(position.size());
+ if (!opengl_context_->MakeContextCurrent(this))
+ return;
+
+ width = position.size().width();
+ height = position.size().height();
+ // init gl here?
+ OS::VideoMode vm;
+ vm.width = width;
+ vm.height = height;
+ vm.resizable = false;
+ vm.fullscreen = true;
+ OS::get_singleton()->set_video_mode(vm, 0);
+
+ DrawSelf();
+ };
+
+ // Called to draw the contents of the module's browser area.
+ void DrawSelf() {
+
+ if (opengl_context_ == NULL)
+ return;
+
+ opengl_context_->FlushContext();
+ };
+};
+
+static Variant to_variant(const pp::Var& p_var) {
+
+ if (p_var.is_undefined() || p_var.is_null())
+ return Variant();
+ if (p_var.is_bool())
+ return Variant(p_var.AsBool());
+ if (p_var.is_double())
+ return Variant(p_var.AsDouble());
+ if (p_var.is_int())
+ return Variant((int64_t)p_var.AsInt());
+ if (p_var.is_string())
+ return Variant(String::utf8(p_var.AsString().c_str()));
+
+ return Variant();
+};
+
+void GodotInstance::HandleMessage(const pp::Var& var_message) {
+
+ switch (state) {
+
+ case STATE_METHOD: {
+
+ ERR_FAIL_COND(!var_message.is_string());
+ sd->method = var_message.AsString().c_str();
+ state = STATE_PARAM_COUNT;
+ } break;
+ case STATE_PARAM_COUNT: {
+
+ ERR_FAIL_COND(!var_message.is_number());
+ sd->arg_count = var_message.AsInt();
+ state = sd->arg_count>0?STATE_PARAMS:STATE_CALL;
+
+ } break;
+ case STATE_PARAMS: {
+
+ Variant p = to_variant(var_message);
+ sd->args.push_back(p);
+ if (sd->args.size() >= sd->arg_count)
+ state = STATE_CALL;
+ } break;
+ default:
+ break;
+ };
+
+ if (state == STATE_CALL) {
+
+ // call
+ state = STATE_METHOD;
+
+
+ if (sd->method == "package_finished") {
+
+ GetURLHandler::Status status = package_pending->get_status();
+ printf("status is %i, %i, %i\n", status, GetURLHandler::STATUS_ERROR, GetURLHandler::STATUS_COMPLETED);
+ if (status == GetURLHandler::STATUS_ERROR) {
+ printf("Error fetching package!\n");
+ };
+ if (status == GetURLHandler::STATUS_COMPLETED) {
+
+ OSNacl* os = (OSNacl*)OS::get_singleton();
+ os->add_package(pkg_url, package_pending->get_data());
+ };
+ memdelete(package_pending);
+ package_pending = NULL;
+
+ package_loaded = true;
+
+ opengl_context_->MakeContextCurrent(this);
+ nacl_main(init_argc, (const char**)init_argn, (const char**)init_argv);
+ for (uint32_t i=0; i<init_argc; i++) {
+ memfree(init_argn[i]);
+ memfree(init_argv[i]);
+ };
+ };
+
+ if (sd->method == "get_package_status") {
+
+ if (package_loaded) {
+ // post "loaded"
+ PostMessage("loaded");
+ } else if (package_pending == NULL) {
+ // post "none"
+ PostMessage("none");
+ } else {
+ // post package_pending->get_bytes_read();
+ PostMessage(package_pending->get_bytes_read());
+ };
+ };
+ };
+}
+
+bool GodotInstance::HandleInputEvent(const pp::InputEvent& event) {
+
+ OSNacl* os = (OSNacl*)OS::get_singleton();
+ os->handle_event(event);
+ return true;
+};
+
+class GodotModule : public pp::Module {
+ public:
+ GodotModule() : pp::Module() {}
+ virtual ~GodotModule() {
+ glTerminatePPAPI();
+ }
+
+ /// Create and return a GodotInstance object.
+ /// @param[in] instance a handle to a plug-in instance.
+ /// @return a newly created GodotInstance.
+ /// @note The browser is responsible for calling @a delete when done.
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ printf("CreateInstance! %x\n", instance);
+ return new GodotInstance(instance);
+ }
+
+ /// Called by the browser when the module is first loaded and ready to run.
+ /// This is called once per module, not once per instance of the module on
+ /// the page.
+ virtual bool Init() {
+ printf("GodotModule::init!\n");
+ return glInitializePPAPI(get_browser_interface());
+ }
+};
+
+namespace pp {
+/// Factory function called by the browser when the module is first loaded.
+/// The browser keeps a singleton of this module. It calls the
+/// CreateInstance() method on the object you return to make instances. There
+/// is one instance per <embed> tag on the page. This is the main binding
+/// point for your NaCl module with the browser.
+/// @return new GodotModule.
+/// @note The browser is responsible for deleting returned @a Module.
+Module* CreateModule() {
+ printf("CreateModule!\n");
+ return new GodotModule();
+}
+} // namespace pp
diff --git a/platform/nacl/godot_nacl.cpp b/platform/nacl/godot_nacl.cpp
new file mode 100644
index 0000000000..753f4124f8
--- /dev/null
+++ b/platform/nacl/godot_nacl.cpp
@@ -0,0 +1,80 @@
+/*************************************************************************/
+/* godot_nacl.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "os_nacl.h"
+#include "main/main.h"
+
+#include <stdio.h>
+#include <string.h>
+
+OSNacl* os_nacl = NULL;
+
+int nacl_main(int argc, const char** argn, const char** argv) {
+
+ // os is created in GodotModule::Init for the nacl module
+ printf("called with %i args, %p, %p\n", argc, argn, argv);
+ char* nargv[64];
+ int nargc = 1;
+ nargv[0] = (char*)argv[0];
+ for (int i=1; i<argc; i++) {
+
+ printf("arg %i is %s, %s\n", i, argn[i], argv[i]);
+ if (strncmp(argn[i], "arg", 3) == 0) {
+
+ printf("using arg %i, %s\n", nargc, argv[i]);
+ nargv[nargc++] = (char*)argv[i];
+ };
+ };
+ printf("total %i\n", nargc);
+ nargv[nargc] = 0;
+
+ printf("godot_nacl\n");
+ for (int i=0; i<argc; i++) {
+ printf("arg %i: %s\n", i, argv[i]);
+ };
+
+ printf("os created\n");
+ Error err = Main::setup("", nargc-1, &nargv[1]);
+ printf("setup %i\n", err);
+ if (err!=OK)
+ return 255;
+
+ printf("calling start\n");
+ Main::start();
+
+ return 0;
+};
+
+
+void nacl_cleanup() {
+
+ Main::cleanup();
+ delete os_nacl;
+};
+
+
diff --git a/platform/nacl/html/check_browser.js b/platform/nacl/html/check_browser.js
new file mode 100644
index 0000000000..9636ad0384
--- /dev/null
+++ b/platform/nacl/html/check_browser.js
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2011 The Native Client Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**
+ * @fileoverview This file provides a BrowserChecker Javascript class.
+ * Users can create a BrowserChecker object, invoke checkBrowser(|version|),
+ * and then use getIsValidBrowser() and getBrowserSupportStatus()
+ * to determine if the browser version is greater than |version|
+ * and if the Native Client plugin is found.
+ */
+
+// Create a namespace object
+var browser_version = browser_version || {};
+
+/**
+ * Class to provide checking for version and NativeClient.
+ * @param {integer} arg1 An argument that indicates major version of Chrome we
+ * require, such as 14.
+ */
+
+/**
+ * Constructor for the BrowserChecker. Sets the major version of
+ * Chrome that is required to |minChromeVersion|.
+ * @param minChromeVersion The earliest major version of chrome that
+ * is supported. If the Chrome browser version is less than
+ * |minChromeVersion| then |isValidBrowswer| will be set to false.
+ * @param opt_maxChromeVersion Ignored. Retained for backwards compatibility.
+ * @param appVersion The application version string.
+ * @param plugins The plugins that exist in the browser.
+ * @constructor
+ */
+browser_version.BrowserChecker = function(minChromeVersion,
+ appVersion, plugins,
+ opt_maxChromeVersion) {
+ /**
+ * Version specified by the user. This class looks to see if the browser
+ * version is >= |minChromeVersion_|.
+ * @type {integer}
+ * @private
+ */
+ this.minChromeVersion_ = minChromeVersion;
+
+ /**
+ * List of Browser plugin objects.
+ * @type {Ojbect array}
+ * @private
+ */
+ this.plugins_ = plugins;
+
+ /**
+ * Application version string from the Browser.
+ * @type {integer}
+ * @private
+ */
+ this.appVersion_ = appVersion;
+
+ /**
+ * Flag used to indicate if the browser has Native Client and is if the
+ * browser version is recent enough.
+ * @type {boolean}
+ * @private
+ */
+ this.isValidBrowser_ = false;
+
+ /**
+ * Actual major version of Chrome -- found by querying the browser.
+ * @type {integer}
+ * @private
+ */
+ this.chromeVersion_ = null;
+
+ /**
+ * Browser support status. This allows the user to get a detailed status
+ * rather than using this.browserSupportMessage.
+ */
+ this.browserSupportStatus_ =
+ browser_version.BrowserChecker.StatusValues.UNKNOWN;
+}
+
+/**
+ * The values used for BrowserChecker status to indicate success or
+ * a specific error.
+ * @enum {id}
+ */
+browser_version.BrowserChecker.StatusValues = {
+ UNKNOWN: 0,
+ NACL_ENABLED: 1,
+ UNKNOWN_BROWSER: 2,
+ CHROME_VERSION_TOO_OLD: 3,
+ NACL_NOT_ENABLED: 4,
+ NOT_USING_SERVER: 5
+};
+
+/**
+ * Determines if the plugin with name |name| exists in the browser.
+ * @param {string} name The name of the plugin.
+ * @param {Object array} plugins The plugins in this browser.
+ * @return {bool} |true| if the plugin is found.
+ */
+browser_version.BrowserChecker.prototype.pluginExists = function(name,
+ plugins) {
+ for (var index=0; index < plugins.length; index++) {
+ var plugin = this.plugins_[index];
+ var plugin_name = plugin['name'];
+ // If the plugin is not found, you can use the Javascript console
+ // to see the names of the plugins that were found when debugging.
+ if (plugin_name.indexOf(name) != -1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Returns browserSupportStatus_ which indicates if the browser supports
+ * Native Client. Values are defined as literals in
+ * browser_version.BrowserChecker.StatusValues.
+ * @ return {int} Level of NaCl support.
+ */
+browser_version.BrowserChecker.prototype.getBrowserSupportStatus = function() {
+ return this.browserSupportStatus_;
+}
+
+/**
+ * Returns isValidBrowser (true/false) to indicate if the browser supports
+ * Native Client.
+ * @ return {bool} If this browser has NativeClient and correct version.
+ */
+browser_version.BrowserChecker.prototype.getIsValidBrowser = function() {
+ return this.isValidBrowser_;
+}
+
+/**
+ * Checks to see if this browser can support Native Client applications.
+ * For Chrome browsers, checks to see if the "Native Client" plugin is
+ * enabled.
+ */
+browser_version.BrowserChecker.prototype.checkBrowser = function() {
+ var versionPatt = /Chrome\/(\d+)\.(\d+)\.(\d+)\.(\d+)/;
+ var result = this.appVersion_.match(versionPatt);
+
+ // |result| stores the Chrome version number.
+ if (!result) {
+ this.isValidBrowser_ = false;
+ this.browserSupportStatus_ =
+ browser_version.BrowserChecker.StatusValues.UNKNOWN_BROWSER;
+ } else {
+ this.chromeVersion_ = result[1];
+ // We know we have Chrome, check version and/or plugin named Native Client
+ if (this.chromeVersion_ >= this.minChromeVersion_) {
+ var found_nacl = this.pluginExists('Native Client', this.plugins_);
+ if (found_nacl) {
+ this.isValidBrowser_ = true;
+ this.browserSupportStatus_ =
+ browser_version.BrowserChecker.StatusValues.NACL_ENABLED;
+ } else {
+ this.isValidBrowser_ = false;
+ this.browserSupportStatus_ =
+ browser_version.BrowserChecker.StatusValues.NACL_NOT_ENABLED;
+ }
+ } else {
+ // We are in a version that is less than |minChromeVersion_|
+ this.isValidBrowser_ = false;
+ this.browserSupportStatus_ =
+ browser_version.BrowserChecker.StatusValues.CHROME_VERSION_TOO_OLD;
+ }
+ }
+ var my_protocol = window.location.protocol;
+ if (my_protocol.indexOf('file') == 0) {
+ this.isValidBrowser_ = false;
+ this.browserSupportStatus_ =
+ browser_version.BrowserChecker.StatusValues.NOT_USING_SERVER;
+ }
+}
+
diff --git a/platform/nacl/html/godot_nacl.nmf b/platform/nacl/html/godot_nacl.nmf
new file mode 100644
index 0000000000..eca039ec1e
--- /dev/null
+++ b/platform/nacl/html/godot_nacl.nmf
@@ -0,0 +1,6 @@
+{
+ "program": {
+ "x86-64": {"url": "godot_nacl.x86_64.nexe"},
+ "x86-32": {"url": "godot_nacl.i686.nexe"}
+ }
+}
diff --git a/platform/nacl/html/icon_128.png b/platform/nacl/html/icon_128.png
new file mode 100644
index 0000000000..1793aa7e7a
--- /dev/null
+++ b/platform/nacl/html/icon_128.png
Binary files differ
diff --git a/platform/nacl/html/icon_16.png b/platform/nacl/html/icon_16.png
new file mode 100644
index 0000000000..09de19e418
--- /dev/null
+++ b/platform/nacl/html/icon_16.png
Binary files differ
diff --git a/platform/nacl/html/index.html b/platform/nacl/html/index.html
new file mode 100644
index 0000000000..e8be6f69b9
--- /dev/null
+++ b/platform/nacl/html/index.html
@@ -0,0 +1,258 @@
+<!DOCTYPE html>
+<html>
+ <!--
+ Copyright (c) 2011 The Native Client Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+ -->
+<head>
+ <title>Load Progress Example</title>
+ <script type="text/javascript" src="check_browser.js"></script>
+ <script type="text/javascript">
+ // Check for Native Client support in the browser before the DOM loads.
+ var isValidBrowser = false;
+ var browserSupportStatus = 0;
+ var checker = new browser_version.BrowserChecker(
+ 14, // Minumum Chrome version.
+ navigator["appVersion"],
+ navigator["plugins"]);
+ checker.checkBrowser();
+
+ loadProgressModule = null; // Global application object.
+ statusText = 'NO-STATUS';
+
+ isValidBrowser = checker.getIsValidBrowser();
+ browserSupportStatus = checker.getBrowserSupportStatus();
+
+ // Handler that gets called when the NaCl module starts loading. This
+ // event is always triggered when an <EMBED> tag has a MIME type of
+ // application/x-nacl.
+ function moduleDidStartLoad() {
+ appendToEventLog('loadstart');
+ }
+
+ // Progress event handler. |event| contains a couple of interesting
+ // properties that are used in this example:
+ // total The size of the NaCl module in bytes. Note that this value
+ // is 0 until |lengthComputable| is true. In particular, this
+ // value is 0 for the first 'progress' event.
+ // loaded The number of bytes loaded so far.
+ // lengthComputable A boolean indicating that the |total| field
+ // represents a valid length.
+ //
+ // event The ProgressEvent that triggered this handler.
+ function moduleLoadProgress(event) {
+ var loadPercent = 0.0;
+ var loadPercentString;
+ if (event.lengthComputable && event.total > 0) {
+ loadPercent = event.loaded / event.total * 100.0;
+ loadPercentString = loadPercent + '%';
+ } else {
+ // The total length is not yet known.
+ loadPercent = -1.0;
+ loadPercentString = 'Computing...';
+ }
+ //appendToEventLog('progress: ' + loadPercentString + ' (' + event.loaded + ' of ' + event.total + ' bytes)');
+ updateStatus("Loading module : "+ Math.floor(event.loaded / event.total * 100.0) + "% complete");
+ }
+
+ // Handler that gets called if an error occurred while loading the NaCl
+ // module. Note that the event does not carry any meaningful data about
+ // the error, you have to check lastError on the <EMBED> element to find
+ // out what happened.
+ function moduleLoadError() {
+ appendToEventLog('error: ' + loadProgressModule.lastError);
+ }
+
+ // Handler that gets called if the NaCl module load is aborted.
+ function moduleLoadAbort() {
+ appendToEventLog('abort');
+ }
+
+ // When the NaCl module has loaded indicate success.
+ function moduleDidLoad() {
+ loadProgressModule = document.getElementById('load_progress');
+ appendToEventLog('load');
+ updateStatus('SUCCESS');
+ }
+
+ function check_dl_status() {
+ var module = document.getElementById('load_progress');
+ module.postMessage("get_package_status");
+ module.postMessage(0);
+ };
+
+ // Handler that gets called when the NaCl module loading has completed.
+ // You will always get one of these events, regardless of whether the NaCl
+ // module loaded successfully or not. For example, if there is an error
+ // during load, you will get an 'error' event and a 'loadend' event. Note
+ // that if the NaCl module loads successfully, you will get both a 'load'
+ // event and a 'loadend' event.
+ function moduleDidEndLoad() {
+ appendToEventLog('loadend');
+ var lastError = event.target.lastError;
+ if (lastError == undefined || lastError.length == 0) {
+ lastError = '&lt;none&gt;';
+ window.setTimeout(check_dl_status, 1000);
+ }
+ appendToEventLog('lastError: ' + lastError);
+ }
+
+
+ // Handle a message coming from the NaCl module.
+ function handleMessage(message_event) {
+ var data = message_event.data;
+ if (data == "loaded") {
+ updateStatus("Data Loaded!");
+ } else if (data == "none") {
+ // nothing
+ updateStatus("Downloading package: connecting");
+ window.setTimeout(check_dl_status, 1000);
+ } else {
+ updateStatus("Downloading package: " + data + " bytes");
+ window.setTimeout(check_dl_status, 1000);
+ };
+ }
+
+ // Set the global status message. Updates the 'status_field' element with
+ // the new text.
+ // opt_message The message text. If this is null or undefined, then
+ // attempt to set the element with id 'status_field' to the value of
+ // |statusText|.
+ function updateStatus(opt_message) {
+ if (opt_message)
+ statusText = opt_message;
+ var statusField = document.getElementById('status_field');
+ if (statusField) {
+ statusField.innerHTML = statusText;
+ }
+ }
+
+ // Append an event name to the 'event_log_field' element. Event names
+ // are separated by a <br> tag so they get listed one per line.
+ // logMessage The message to append to the log.
+ function appendToEventLog(logMessage) {
+ var eventLogField = document.getElementById('event_log_field');
+ if (eventLogField.innerHTML.length == 0) {
+ eventLogField.innerHTML = logMessage;
+ } else {
+ eventLogField.innerHTML = eventLogField.innerHTML +
+ '<br />' +
+ logMessage;
+ }
+ }
+
+ </script>
+</head>
+<body bgcolor=#000000>
+
+<font color=#FFFFFF>
+
+<h1>Native Client Load Event Example</h1>
+
+<h2>Status</h2>
+<div id="status_field">NO-STATUS</div>
+
+<div id="listener">
+ <script type="text/javascript">
+ var listener = document.getElementById('listener');
+ listener.addEventListener('loadstart', moduleDidStartLoad, true);
+ listener.addEventListener('progress', moduleLoadProgress, true);
+ listener.addEventListener('error', moduleLoadError, true);
+ listener.addEventListener('abort', moduleLoadAbort, true);
+ listener.addEventListener('load', moduleDidLoad, true);
+ listener.addEventListener('loadend', moduleDidEndLoad, true);
+ listener.addEventListener('message', handleMessage, true);
+
+ switch (browserSupportStatus) {
+ case browser_version.BrowserChecker.StatusValues.NACL_ENABLED:
+ appendToEventLog('Native Client plugin enabled.');
+ break;
+ case browser_version.BrowserChecker.StatusValues.UNKNOWN_BROWSER:
+ updateStatus('UNKNOWN BROWSER');
+ break;
+ case browser_version.BrowserChecker.StatusValues.CHROME_VERSION_TOO_OLD:
+ appendToEventLog(
+ 'Chrome too old: You must use Chrome version 14 or later.');
+ updateStatus('NEED CHROME 14 OR LATER');
+ break;
+ case browser_version.BrowserChecker.StatusValues.NACL_NOT_ENABLED:
+ appendToEventLog(
+ 'NaCl disabled: Native Client is not enabled.<br>' +
+ 'Please go to <b>chrome://plugins</b> and enable Native Client ' +
+ 'plugin.');
+ updateStatus('NaCl NOT ENABLED');
+ break;
+ case browser_version.BrowserChecker.StatusValues.NOT_USING_SERVER:
+ appendToEventLog(
+ 'file: URL detected, please use a web server to host Native ' +
+ 'Client applications.');
+ updateStatus('NaCl NOT ENABLED');
+ default:
+ appendToEventLog('Unknown error: Unable to detect browser and/or ' +
+ 'Native Client support.');
+ updateStatus('UNKNOWN ERROR');
+ break;
+ }
+ </script>
+
+ <!-- Load the published .nexe. This includes the 'src' attribute which
+ shows how to load multi-architecture modules. Each entry in the "nexes"
+ object in the .nmf manifest file is a key-value pair: the key is the runtime
+ ('x86-32', 'x86-64', etc.); the value is a URL for the desired NaCl module.
+ To load the debug versions of your .nexes, set the 'src' attribute to the
+ _dbg.nmf version of the manifest file.
+
+ Note: The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
+ and a 'message' event listener attached. This wrapping method is used
+ instead of attaching the event listeners directly to the <EMBED> element to
+ ensure that the listeners are active before the NaCl module 'load' event
+ fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or
+ pp::Instance.PostMessage() (in C++) from within the initialization code in
+ your NaCl module.
+ -->
+ <embed name="nacl_module"
+ id="load_progress"
+ width=1024 height=600
+ src="godot_nacl.nmf"
+ type="application/x-nacl"
+ package="data.pcz"
+ arg1="-path" arg2="."
+ no_arg1="-test" no_arg2="gui" />
+
+ <script type="text/javascript">
+ loadProgressModule = document.getElementById('load_progress');
+ // Futher diagnose NaCl loading.
+ if (loadProgressModule == null ||
+ typeof loadProgressModule.readyState == 'undefined') {
+ switch (browserSupportStatus) {
+ case browser_version.BrowserChecker.StatusValues.NACL_ENABLED:
+ // The NaCl plugin is enabled and running, it's likely that the flag
+ // isn't set.
+ appendToEventLog(
+ 'NaCl flag disabled: The Native Client flag is not enabled.<br>' +
+ 'Please go to <b>chrome://flags</b> enable Native Client and ' +
+ 'relaunch your browser. See also: ' +
+ '<a href="http://code.google.com/chrome/nativeclient/docs/' +
+ 'running.html">Running Web Applications that Use Native Client' +
+ '</a>');
+ updateStatus('NaCl NOT ENABLED');
+ break;
+ case browser_version.BrowserChecker.StatusValues.UNKNOWN_BROWSER:
+ appendToEventLog('Native Client applications are not supported by ' +
+ 'this browser.');
+ break;
+ default:
+ appendToEventLog('Unknown error when loading Native Client ' +
+ 'application.');
+ }
+ }
+ </script>
+</div>
+
+<h2>Event Log</h2>
+<div id="event_log_field">event log?</div>
+
+</body>
+</html>
+
diff --git a/platform/nacl/html/manifest.json b/platform/nacl/html/manifest.json
new file mode 100644
index 0000000000..6e271507a9
--- /dev/null
+++ b/platform/nacl/html/manifest.json
@@ -0,0 +1,19 @@
+{
+ "name": "Capsuleman's Castle Adventure",
+ "description": "Capsuleman's Castle Adventure",
+ "version": "1",
+ "app": {
+ "launch": {
+ "local_path": "index.html"
+ }
+ },
+ "icons": {
+ "16": "icon_16.png",
+ "128": "icon_128.png"
+ },
+ "permissions": [
+ "unlimitedStorage",
+ "notifications",
+ "experimental"
+ ]
+}
diff --git a/platform/nacl/logo.png b/platform/nacl/logo.png
new file mode 100644
index 0000000000..aac72c01b2
--- /dev/null
+++ b/platform/nacl/logo.png
Binary files differ
diff --git a/platform/nacl/nacl_keycodes.h b/platform/nacl/nacl_keycodes.h
new file mode 100644
index 0000000000..1cbf379078
--- /dev/null
+++ b/platform/nacl/nacl_keycodes.h
@@ -0,0 +1,422 @@
+/*************************************************************************/
+/* nacl_keycodes.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com. All rights reserved.
+ * Copyright (C) 2008, 2009 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR
+ * PROFITS, OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BASE_KEYBOARD_CODES_POSIX_H_
+#define BASE_KEYBOARD_CODES_POSIX_H_
+#pragma once
+
+#include "core/os/keyboard.h"
+
+enum {
+ VKEY_BACK = 0x08,
+ VKEY_TAB = 0x09,
+ VKEY_CLEAR = 0x0C,
+ VKEY_RETURN = 0x0D,
+ VKEY_SHIFT = 0x10,
+ VKEY_CONTROL = 0x11,
+ VKEY_MENU = 0x12,
+ VKEY_PAUSE = 0x13,
+ VKEY_CAPITAL = 0x14,
+ VKEY_KANA = 0x15,
+ VKEY_HANGUL = 0x15,
+ VKEY_JUNJA = 0x17,
+ VKEY_FINAL = 0x18,
+ VKEY_HANJA = 0x19,
+ VKEY_KANJI = 0x19,
+ VKEY_ESCAPE = 0x1B,
+ VKEY_CONVERT = 0x1C,
+ VKEY_NONCONVERT = 0x1D,
+ VKEY_ACCEPT = 0x1E,
+ VKEY_MODECHANGE = 0x1F,
+ VKEY_SPACE = 0x20,
+ VKEY_PRIOR = 0x21,
+ VKEY_NEXT = 0x22,
+ VKEY_END = 0x23,
+ VKEY_HOME = 0x24,
+ VKEY_LEFT = 0x25,
+ VKEY_UP = 0x26,
+ VKEY_RIGHT = 0x27,
+ VKEY_DOWN = 0x28,
+ VKEY_SELECT = 0x29,
+ VKEY_PRINT = 0x2A,
+ VKEY_EXECUTE = 0x2B,
+ VKEY_SNAPSHOT = 0x2C,
+ VKEY_INSERT = 0x2D,
+ VKEY_DELETE = 0x2E,
+ VKEY_HELP = 0x2F,
+ VKEY_0 = 0x30,
+ VKEY_1 = 0x31,
+ VKEY_2 = 0x32,
+ VKEY_3 = 0x33,
+ VKEY_4 = 0x34,
+ VKEY_5 = 0x35,
+ VKEY_6 = 0x36,
+ VKEY_7 = 0x37,
+ VKEY_8 = 0x38,
+ VKEY_9 = 0x39,
+ VKEY_A = 0x41,
+ VKEY_B = 0x42,
+ VKEY_C = 0x43,
+ VKEY_D = 0x44,
+ VKEY_E = 0x45,
+ VKEY_F = 0x46,
+ VKEY_G = 0x47,
+ VKEY_H = 0x48,
+ VKEY_I = 0x49,
+ VKEY_J = 0x4A,
+ VKEY_K = 0x4B,
+ VKEY_L = 0x4C,
+ VKEY_M = 0x4D,
+ VKEY_N = 0x4E,
+ VKEY_O = 0x4F,
+ VKEY_P = 0x50,
+ VKEY_Q = 0x51,
+ VKEY_R = 0x52,
+ VKEY_S = 0x53,
+ VKEY_T = 0x54,
+ VKEY_U = 0x55,
+ VKEY_V = 0x56,
+ VKEY_W = 0x57,
+ VKEY_X = 0x58,
+ VKEY_Y = 0x59,
+ VKEY_Z = 0x5A,
+ VKEY_LWIN = 0x5B,
+ VKEY_COMMAND = VKEY_LWIN, // Provide the Mac name for convenience.
+ VKEY_RWIN = 0x5C,
+ VKEY_APPS = 0x5D,
+ VKEY_SLEEP = 0x5F,
+ VKEY_NUMPAD0 = 0x60,
+ VKEY_NUMPAD1 = 0x61,
+ VKEY_NUMPAD2 = 0x62,
+ VKEY_NUMPAD3 = 0x63,
+ VKEY_NUMPAD4 = 0x64,
+ VKEY_NUMPAD5 = 0x65,
+ VKEY_NUMPAD6 = 0x66,
+ VKEY_NUMPAD7 = 0x67,
+ VKEY_NUMPAD8 = 0x68,
+ VKEY_NUMPAD9 = 0x69,
+ VKEY_MULTIPLY = 0x6A,
+ VKEY_ADD = 0x6B,
+ VKEY_SEPARATOR = 0x6C,
+ VKEY_SUBTRACT = 0x6D,
+ VKEY_DECIMAL = 0x6E,
+ VKEY_DIVIDE = 0x6F,
+ VKEY_F1 = 0x70,
+ VKEY_F2 = 0x71,
+ VKEY_F3 = 0x72,
+ VKEY_F4 = 0x73,
+ VKEY_F5 = 0x74,
+ VKEY_F6 = 0x75,
+ VKEY_F7 = 0x76,
+ VKEY_F8 = 0x77,
+ VKEY_F9 = 0x78,
+ VKEY_F10 = 0x79,
+ VKEY_F11 = 0x7A,
+ VKEY_F12 = 0x7B,
+ VKEY_F13 = 0x7C,
+ VKEY_F14 = 0x7D,
+ VKEY_F15 = 0x7E,
+ VKEY_F16 = 0x7F,
+ VKEY_F17 = 0x80,
+ VKEY_F18 = 0x81,
+ VKEY_F19 = 0x82,
+ VKEY_F20 = 0x83,
+ VKEY_F21 = 0x84,
+ VKEY_F22 = 0x85,
+ VKEY_F23 = 0x86,
+ VKEY_F24 = 0x87,
+ VKEY_NUMLOCK = 0x90,
+ VKEY_SCROLL = 0x91,
+ VKEY_LSHIFT = 0xA0,
+ VKEY_RSHIFT = 0xA1,
+ VKEY_LCONTROL = 0xA2,
+ VKEY_RCONTROL = 0xA3,
+ VKEY_LMENU = 0xA4,
+ VKEY_RMENU = 0xA5,
+ VKEY_BROWSER_BACK = 0xA6,
+ VKEY_BROWSER_FORWARD = 0xA7,
+ VKEY_BROWSER_REFRESH = 0xA8,
+ VKEY_BROWSER_STOP = 0xA9,
+ VKEY_BROWSER_SEARCH = 0xAA,
+ VKEY_BROWSER_FAVORITES = 0xAB,
+ VKEY_BROWSER_HOME = 0xAC,
+ VKEY_VOLUME_MUTE = 0xAD,
+ VKEY_VOLUME_DOWN = 0xAE,
+ VKEY_VOLUME_UP = 0xAF,
+ VKEY_MEDIA_NEXT_TRACK = 0xB0,
+ VKEY_MEDIA_PREV_TRACK = 0xB1,
+ VKEY_MEDIA_STOP = 0xB2,
+ VKEY_MEDIA_PLAY_PAUSE = 0xB3,
+ VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
+ VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
+ VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
+ VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
+ VKEY_OEM_1 = 0xBA,
+ VKEY_OEM_PLUS = 0xBB,
+ VKEY_OEM_COMMA = 0xBC,
+ VKEY_OEM_MINUS = 0xBD,
+ VKEY_OEM_PERIOD = 0xBE,
+ VKEY_OEM_2 = 0xBF,
+ VKEY_OEM_3 = 0xC0,
+ VKEY_OEM_4 = 0xDB,
+ VKEY_OEM_5 = 0xDC,
+ VKEY_OEM_6 = 0xDD,
+ VKEY_OEM_7 = 0xDE,
+ VKEY_OEM_8 = 0xDF,
+ VKEY_OEM_102 = 0xE2,
+ VKEY_PROCESSKEY = 0xE5,
+ VKEY_PACKET = 0xE7,
+ VKEY_ATTN = 0xF6,
+ VKEY_CRSEL = 0xF7,
+ VKEY_EXSEL = 0xF8,
+ VKEY_EREOF = 0xF9,
+ VKEY_PLAY = 0xFA,
+ VKEY_ZOOM = 0xFB,
+ VKEY_NONAME = 0xFC,
+ VKEY_PA1 = 0xFD,
+ VKEY_OEM_CLEAR = 0xFE,
+ VKEY_UNKNOWN = 0
+};
+
+static uint32_t godot_key(uint32_t p_key, bool& is_char) {
+
+ is_char = false;
+
+ switch (p_key) {
+
+ case VKEY_BACK: return KEY_BACKSPACE;
+ case VKEY_TAB: return KEY_TAB;
+ case VKEY_CLEAR: return KEY_CLEAR;
+ case VKEY_RETURN: return KEY_RETURN;
+ case VKEY_SHIFT: return KEY_SHIFT;
+ case VKEY_CONTROL: return KEY_CONTROL;
+ case VKEY_MENU: return KEY_MENU;
+ case VKEY_PAUSE: return KEY_PAUSE;
+// case VKEY_CAPITAL: return KEY_CAPITAL;
+// case VKEY_KANA: return KEY_KANA;
+// case VKEY_HANGUL: return KEY_HANGUL;
+// case VKEY_JUNJA: return KEY_JUNJA;
+// case VKEY_FINAL: return KEY_FINAL;
+// case VKEY_HANJA: return KEY_HANJA;
+// case VKEY_KANJI: return KEY_KANJI;
+ case VKEY_ESCAPE: return KEY_ESCAPE;
+// case VKEY_CONVERT: return KEY_CONVERT;
+// case VKEY_NONCONVERT: return KEY_NONCONVERT;
+// case VKEY_ACCEPT: return KEY_ACCEPT;
+// case VKEY_MODECHANGE: return KEY_MODECHANGE;
+// case VKEY_PRIOR: return KEY_PRIOR;
+// case VKEY_NEXT: return KEY_NEXT;
+ case VKEY_END: return KEY_END;
+ case VKEY_HOME: return KEY_HOME;
+ case VKEY_LEFT: return KEY_LEFT;
+ case VKEY_UP: return KEY_UP;
+ case VKEY_RIGHT: return KEY_RIGHT;
+ case VKEY_DOWN: return KEY_DOWN;
+// case VKEY_SELECT: return KEY_SELECT;
+ case VKEY_PRINT: return KEY_PRINT;
+// case VKEY_EXECUTE: return KEY_EXECUTE;
+// case VKEY_SNAPSHOT: return KEY_SNAPSHOT;
+ case VKEY_INSERT: return KEY_INSERT;
+ case VKEY_DELETE: return KEY_DELETE;
+ case VKEY_HELP: return KEY_HELP;
+// case VKEY_LWIN: return KEY_LWIN;
+// case VKEY_RWIN: return KEY_RWIN;
+// case VKEY_APPS: return KEY_APPS;
+// case VKEY_SLEEP: return KEY_SLEEP;
+ case VKEY_NUMPAD0: return KEY_KP_0;
+ case VKEY_NUMPAD1: return KEY_KP_1;
+ case VKEY_NUMPAD2: return KEY_KP_2;
+ case VKEY_NUMPAD3: return KEY_KP_3;
+ case VKEY_NUMPAD4: return KEY_KP_4;
+ case VKEY_NUMPAD5: return KEY_KP_5;
+ case VKEY_NUMPAD6: return KEY_KP_6;
+ case VKEY_NUMPAD7: return KEY_KP_7;
+ case VKEY_NUMPAD8: return KEY_KP_8;
+ case VKEY_NUMPAD9: return KEY_KP_9;
+ case VKEY_MULTIPLY: return KEY_KP_MULTIPLY;
+ case VKEY_ADD: return KEY_KP_ADD;
+// case VKEY_SEPARATOR: return KEY_SEPARATOR;
+ case VKEY_SUBTRACT: return KEY_KP_SUBSTRACT;
+ case VKEY_DECIMAL: return KEY_KP_PERIOD;
+ case VKEY_DIVIDE: return KEY_KP_DIVIDE;
+ case VKEY_F1: return KEY_F1;
+ case VKEY_F2: return KEY_F2;
+ case VKEY_F3: return KEY_F3;
+ case VKEY_F4: return KEY_F4;
+ case VKEY_F5: return KEY_F5;
+ case VKEY_F6: return KEY_F6;
+ case VKEY_F7: return KEY_F7;
+ case VKEY_F8: return KEY_F8;
+ case VKEY_F9: return KEY_F9;
+ case VKEY_F10: return KEY_F10;
+ case VKEY_F11: return KEY_F11;
+ case VKEY_F12: return KEY_F12;
+ case VKEY_F13: return KEY_F13;
+ case VKEY_F14: return KEY_F14;
+ case VKEY_F15: return KEY_F15;
+ case VKEY_F16: return KEY_F16;
+ /*
+ case VKEY_F17: return KEY_F17;
+ case VKEY_F18: return KEY_F18;
+ case VKEY_F19: return KEY_F19;
+ case VKEY_F20: return KEY_F20;
+ case VKEY_F21: return KEY_F21;
+ case VKEY_F22: return KEY_F22;
+ case VKEY_F23: return KEY_F23;
+ case VKEY_F24: return KEY_F24;
+ */
+ case VKEY_NUMLOCK: return KEY_NUMLOCK;
+ case VKEY_SCROLL: return KEY_SCROLLLOCK;
+ case VKEY_LSHIFT: return KEY_SHIFT;
+ case VKEY_RSHIFT: return KEY_SHIFT;
+ case VKEY_LCONTROL: return KEY_CONTROL;
+ case VKEY_RCONTROL: return KEY_CONTROL;
+ case VKEY_LMENU: return KEY_MENU;
+ case VKEY_RMENU: return KEY_MENU;
+ case VKEY_BROWSER_BACK: return KEY_BACK;
+ case VKEY_BROWSER_FORWARD: return KEY_FORWARD;
+ case VKEY_BROWSER_REFRESH: return KEY_REFRESH;
+ case VKEY_BROWSER_STOP: return KEY_STOP;
+ case VKEY_BROWSER_SEARCH: return KEY_SEARCH;
+ case VKEY_BROWSER_FAVORITES: return KEY_FAVORITES;
+ case VKEY_BROWSER_HOME: return KEY_HOMEPAGE;
+ case VKEY_VOLUME_MUTE: return KEY_VOLUMEMUTE;
+ case VKEY_VOLUME_DOWN: return KEY_VOLUMEDOWN;
+ case VKEY_VOLUME_UP: return KEY_VOLUMEUP;
+ case VKEY_MEDIA_NEXT_TRACK: return KEY_MEDIANEXT;
+ case VKEY_MEDIA_PREV_TRACK: return KEY_MEDIAPREVIOUS;
+ case VKEY_MEDIA_STOP: return KEY_MEDIASTOP;
+ case VKEY_MEDIA_PLAY_PAUSE: return KEY_MEDIAPLAY;
+ case VKEY_MEDIA_LAUNCH_MAIL: return KEY_LAUNCHMAIL;
+ case VKEY_MEDIA_LAUNCH_MEDIA_SELECT: return KEY_LAUNCHMEDIA; // FUCKING USELESS KEYS, HOW DO THEY WORK?
+ case VKEY_MEDIA_LAUNCH_APP1: return KEY_LAUNCH0;
+ case VKEY_MEDIA_LAUNCH_APP2: return KEY_LAUNCH0;
+// case VKEY_OEM_102: return KEY_OEM_102;
+// case VKEY_PROCESSKEY: return KEY_PROCESSKEY;
+// case VKEY_PACKET: return KEY_PACKET;
+// case VKEY_ATTN: return KEY_ATTN;
+// case VKEY_CRSEL: return KEY_CRSEL;
+// case VKEY_EXSEL: return KEY_EXSEL;
+// case VKEY_EREOF: return KEY_EREOF;
+// case VKEY_PLAY: return KEY_PLAY;
+// case VKEY_ZOOM: return KEY_ZOOM;
+// case VKEY_NONAME: return KEY_NONAME;
+// case VKEY_PA1: return KEY_PA1;
+// case VKEY_OEM_CLEAR: return KEY_OEM_CLEAR;
+
+ default: break;
+ };
+
+ is_char = true;
+
+ switch (p_key) {
+
+ case VKEY_SPACE: return KEY_SPACE;
+ case VKEY_0: return KEY_0;
+ case VKEY_1: return KEY_1;
+ case VKEY_2: return KEY_2;
+ case VKEY_3: return KEY_3;
+ case VKEY_4: return KEY_4;
+ case VKEY_5: return KEY_5;
+ case VKEY_6: return KEY_6;
+ case VKEY_7: return KEY_7;
+ case VKEY_8: return KEY_8;
+ case VKEY_9: return KEY_9;
+ case VKEY_A: return KEY_A;
+ case VKEY_B: return KEY_B;
+ case VKEY_C: return KEY_C;
+ case VKEY_D: return KEY_D;
+ case VKEY_E: return KEY_E;
+ case VKEY_F: return KEY_F;
+ case VKEY_G: return KEY_G;
+ case VKEY_H: return KEY_H;
+ case VKEY_I: return KEY_I;
+ case VKEY_J: return KEY_J;
+ case VKEY_K: return KEY_K;
+ case VKEY_L: return KEY_L;
+ case VKEY_M: return KEY_M;
+ case VKEY_N: return KEY_N;
+ case VKEY_O: return KEY_O;
+ case VKEY_P: return KEY_P;
+ case VKEY_Q: return KEY_Q;
+ case VKEY_R: return KEY_R;
+ case VKEY_S: return KEY_S;
+ case VKEY_T: return KEY_T;
+ case VKEY_U: return KEY_U;
+ case VKEY_V: return KEY_V;
+ case VKEY_W: return KEY_W;
+ case VKEY_X: return KEY_X;
+ case VKEY_Y: return KEY_Y;
+ case VKEY_Z: return KEY_Z;
+ /*
+ case VKEY_OEM_PLUS: return KEY_PLUS;
+ case VKEY_OEM_COMMA: return KEY_COMMA;
+ case VKEY_OEM_MINUS: return KEY_MINUS;
+ case VKEY_OEM_PERIOD: return KEY_PERIOD;
+ case VKEY_OEM_1: return KEY_OEM_1;
+ case VKEY_OEM_2: return KEY_OEM_2;
+ case VKEY_OEM_3: return KEY_OEM_3;
+ case VKEY_OEM_4: return KEY_OEM_4;
+ case VKEY_OEM_5: return KEY_OEM_5;
+ case VKEY_OEM_6: return KEY_OEM_6;
+ case VKEY_OEM_7: return KEY_OEM_7;
+ case VKEY_OEM_8: return KEY_OEM_8;
+ */
+ default: break;
+
+ };
+
+ return 0;
+};
+
+#endif // BASE_KEYBOARD_CODES_POSIX_H_
diff --git a/platform/nacl/opengl_context.cpp b/platform/nacl/opengl_context.cpp
new file mode 100644
index 0000000000..8dafe959a3
--- /dev/null
+++ b/platform/nacl/opengl_context.cpp
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* opengl_context.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "opengl_context.h"
+
+#include <pthread.h>
+#include "ppapi/gles2/gl2ext_ppapi.h"
+#include "os_nacl.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/utility/completion_callback_factory.h"
+
+
+namespace {
+// This is called by the brower when the 3D context has been flushed to the
+// browser window.
+void FlushCallback(void* data, int32_t result) {
+ static_cast<OpenGLContext*>(data)->set_flush_pending(false);
+ static_cast<OpenGLContext*>(data)->FlushContext();
+}
+} // namespace
+
+OpenGLContext::OpenGLContext(pp::Instance* p_instance)
+ : pp::Graphics3DClient(p_instance),
+ flush_pending_(false) {
+
+ instance = p_instance;
+ pp::Module* module = pp::Module::Get();
+ assert(module);
+ gles2_interface_ = static_cast<const struct PPB_OpenGLES2_Dev*>(
+ module->GetBrowserInterface(PPB_OPENGLES2_INTERFACE));
+ assert(gles2_interface_);
+}
+
+OpenGLContext::~OpenGLContext() {
+ glSetCurrentContextPPAPI(0);
+}
+
+bool OpenGLContext::MakeContextCurrent(pp::Instance* instance) {
+
+ if (instance == NULL) {
+ glSetCurrentContextPPAPI(0);
+ return false;
+ }
+ // Lazily create the Pepper context.
+ if (context_.is_null()) {
+ int32_t attribs[] = {
+ PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
+ PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
+ PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8,
+ PP_GRAPHICS3DATTRIB_SAMPLES, 0,
+ PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
+ PP_GRAPHICS3DATTRIB_WIDTH, width,
+ PP_GRAPHICS3DATTRIB_HEIGHT, height,
+ PP_GRAPHICS3DATTRIB_NONE
+ };
+
+ context_ = pp::Graphics3D(instance, pp::Graphics3D(), attribs);
+ if (context_.is_null()) {
+ glSetCurrentContextPPAPI(0);
+ return false;
+ }
+ instance->BindGraphics(context_);
+ }
+ glSetCurrentContextPPAPI(context_.pp_resource());
+ return true;
+}
+
+void OpenGLContext::ResizeContext(const pp::Size& size) {
+
+ width = size.width();
+ height = size.height();
+
+ if (!context_.is_null()) {
+ context_.ResizeBuffers(size.width(), size.height());
+ }
+}
+
+
+void OpenGLContext::InvalidateContext(pp::Instance* instance) {
+ glSetCurrentContextPPAPI(0);
+}
+
+void OpenGLContext::FlushContext() {
+ if (flush_pending()) {
+ // A flush is pending so do nothing; just drop this flush on the floor.
+ return;
+ }
+ set_flush_pending(true);
+
+ OSNacl* os = (OSNacl*)OS::get_singleton();
+ MakeContextCurrent(instance);
+ os->iterate();
+
+ context_.SwapBuffers(pp::CompletionCallback(&FlushCallback, this));
+}
+
diff --git a/platform/nacl/opengl_context.h b/platform/nacl/opengl_context.h
new file mode 100644
index 0000000000..b0431f29bf
--- /dev/null
+++ b/platform/nacl/opengl_context.h
@@ -0,0 +1,124 @@
+/*************************************************************************/
+/* opengl_context.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef EXAMPLES_TUMBLER_OPENGL_CONTEXT_H_
+#define EXAMPLES_TUMBLER_OPENGL_CONTEXT_H_
+
+///
+/// @file
+/// OpenGLContext manages the OpenGL context in the browser that is associated
+/// with a @a pp::Instance instance.
+///
+
+#include <pthread.h>
+
+#include <algorithm>
+#include <string>
+
+#include "ppapi/c/ppb_opengles2.h"
+//#include "ppapi/cpp/dev/context_3d_dev.h"
+#include "ppapi/cpp/graphics_3d_client.h"
+#include "ppapi/cpp/graphics_3d.h"
+//#include "ppapi/cpp/dev/surface_3d_dev.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/size.h"
+
+// A convenience wrapper for a shared OpenGLContext pointer type. As other
+// smart pointer types are needed, add them here.
+
+#include <tr1/memory>
+
+class OpenGLContext;
+
+typedef std::tr1::shared_ptr<OpenGLContext> SharedOpenGLContext;
+
+/// OpenGLContext manages an OpenGL rendering context in the browser.
+///
+class OpenGLContext : public pp::Graphics3DClient {
+ public:
+ explicit OpenGLContext(pp::Instance* instance);
+
+ /// Release all the in-browser resources used by this context, and make this
+ /// context invalid.
+ virtual ~OpenGLContext();
+
+ /// The Graphics3DClient interfcace.
+ virtual void Graphics3DContextLost() {
+ assert(!"Unexpectedly lost graphics context");
+ }
+
+ /// Make @a this the current 3D context in @a instance.
+ /// @param instance The instance of the NaCl module that will receive the
+ /// the current 3D context.
+ /// @return success.
+ bool MakeContextCurrent(pp::Instance* instance);
+
+ /// Flush the contents of this context to the browser's 3D device.
+ void FlushContext();
+
+ /// Make the underlying 3D device invalid, so that any subsequent rendering
+ /// commands will have no effect. The next call to MakeContextCurrent() will
+ /// cause the underlying 3D device to get rebound and start receiving
+ /// receiving rendering commands again. Use InvalidateContext(), for
+ /// example, when resizing the context's viewing area.
+ void InvalidateContext(pp::Instance* instance);
+
+ void ResizeContext(const pp::Size& size);
+
+ /// The OpenGL ES 2.0 interface.
+ const struct PPB_OpenGLES2_Dev* gles2() const {
+ return gles2_interface_;
+ }
+
+ /// The PP_Resource needed to make GLES2 calls through the Pepper interface.
+ const PP_Resource gl_context() const {
+ return context_.pp_resource();
+ }
+
+ /// Indicate whether a flush is pending. This can only be called from the
+ /// main thread; it is not thread safe.
+ bool flush_pending() const {
+ return flush_pending_;
+ }
+ void set_flush_pending(bool flag) {
+ flush_pending_ = flag;
+ }
+
+ private:
+ pp::Graphics3D context_;
+ bool flush_pending_;
+
+ int width, height;
+
+ pp::Instance* instance;
+
+ const struct PPB_OpenGLES2_Dev* gles2_interface_;
+};
+
+#endif // EXAMPLES_TUMBLER_OPENGL_CONTEXT_H_
+
diff --git a/platform/nacl/os_nacl.cpp b/platform/nacl/os_nacl.cpp
new file mode 100644
index 0000000000..d97195c50d
--- /dev/null
+++ b/platform/nacl/os_nacl.cpp
@@ -0,0 +1,529 @@
+/*************************************************************************/
+/* os_nacl.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "os_nacl.h"
+
+#include "drivers/unix/memory_pool_static_malloc.h"
+#include "os/memory_pool_dynamic_static.h"
+#include "main/main.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "io/file_access_memory.h"
+#include "core/io/file_access_pack.h"
+#include "scene/io/scene_loader.h"
+#include "scene/main/scene_main_loop.h"
+
+#include "servers/visual/visual_server_raster.h"
+
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "nacl_keycodes.h"
+
+#include "core/globals.h"
+#include "core/input_map.h"
+
+#include <ppapi/cpp/point.h>
+#include <ppapi/cpp/var.h>
+
+#define UNIX_ENABLED
+#include "drivers/unix/thread_posix.h"
+#include "drivers/unix/semaphore_posix.h"
+#include "drivers/unix/mutex_posix.h"
+
+
+int OSNacl::get_video_driver_count() const {
+
+ return 1;
+};
+const char * OSNacl::get_video_driver_name(int p_driver) const {
+
+ return "gles2";
+};
+
+OS::VideoMode OSNacl::get_default_video_mode() const {
+
+ return OS::VideoMode(800,600,false);
+};
+
+int OSNacl::get_audio_driver_count() const {
+
+ return 1;
+};
+
+const char * OSNacl::get_audio_driver_name(int p_driver) const {
+
+ return "nacl_audio";
+};
+
+static MemoryPoolStaticMalloc *mempool_static=NULL;
+static MemoryPoolDynamicStatic *mempool_dynamic=NULL;
+
+void OSNacl::initialize_core() {
+
+ ticks_start=0;
+ ticks_start=get_ticks_usec();
+};
+
+void OSNacl::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ rasterizer = memnew( RasterizerGLES2 );
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ visual_server->init();
+ visual_server->cursor_set_visible(false, 0);
+
+ audio_driver = memnew(AudioDriverNacl);
+ audio_driver->set_singleton();
+ audio_driver->init();
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+ audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+ audio_server->init();
+
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew(InputDefault);
+};
+
+void OSNacl::set_main_loop( MainLoop * p_main_loop ) {
+
+ main_loop = p_main_loop;
+ input->set_main_loop(p_main_loop);
+ main_loop->init();
+};
+
+void OSNacl::delete_main_loop() {
+
+ if (main_loop)
+ memdelete(main_loop);
+};
+
+void OSNacl::finalize() {
+
+
+};
+void OSNacl::finalize_core() {
+
+ if (mempool_dynamic)
+ memdelete( mempool_dynamic );
+ if (mempool_static)
+ delete mempool_static;
+
+};
+
+void OSNacl::alert(const String& p_alert,const String& p_title) {
+
+ fprintf(stderr,"ERROR: %s\n",p_alert.utf8().get_data());
+};
+
+void OSNacl::vprint(const char* p_format, va_list p_list, bool p_strerr) {
+
+ vprintf(p_format,p_list);
+ fflush(stdout);
+}
+
+
+String OSNacl::get_stdin_string(bool p_block) {
+
+ char buff[1024];
+ return fgets(buff,1024,stdin);
+};
+
+void OSNacl::set_mouse_show(bool p_show) {
+
+};
+
+void OSNacl::set_mouse_grab(bool p_grab) {
+
+};
+
+bool OSNacl::is_mouse_grab_enabled() const {
+
+ return false;
+};
+
+int OSNacl::get_mouse_button_state() const {
+
+ return mouse_mask;
+};
+
+
+Point2 OSNacl::get_mouse_pos() const {
+
+ return Point2();
+};
+
+void OSNacl::set_window_title(const String& p_title) {
+};
+
+void OSNacl::set_video_mode(const VideoMode& p_video_mode, int p_screen) {
+
+ video_mode = p_video_mode;
+};
+
+OS::VideoMode OSNacl::get_video_mode(int p_screen) const {
+
+ return video_mode;
+};
+
+void OSNacl::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+};
+
+Error OSNacl::execute(const String& p_path, const List<String>& p_arguments,bool p_blocking, OS::ProcessID *r_child_id, String* r_pipe, int *r_exitcode) {
+
+ return ERR_UNAVAILABLE;
+};
+
+Error OSNacl::kill(const ProcessID& p_pid) {
+
+ return ERR_UNAVAILABLE;
+};
+
+bool OSNacl::has_environment(const String& p_var) const {
+
+ return getenv(p_var.utf8().get_data())!=NULL;
+};
+
+String OSNacl::get_environment(const String& p_var) const {
+
+ if (getenv(p_var.utf8().get_data()))
+ return getenv(p_var.utf8().get_data());
+ return "";
+};
+
+String OSNacl::get_name() {
+
+ return "NaCl";
+};
+
+MainLoop *OSNacl::get_main_loop() const {
+
+ return main_loop;
+};
+
+OS::Date OSNacl::get_date() const {
+
+ time_t t=time(NULL);
+ struct tm *lt=localtime(&t);
+ Date ret;
+ ret.year=lt->tm_year;
+ ret.month=(Month)lt->tm_mon;
+ ret.day=lt->tm_mday;
+ ret.weekday=(Weekday)lt->tm_wday;
+ ret.dst=lt->tm_isdst;
+
+ return ret;
+};
+
+OS::Time OSNacl::get_time() const {
+
+ time_t t=time(NULL);
+ struct tm *lt=localtime(&t);
+ Time ret;
+ ret.hour=lt->tm_hour;
+ ret.min=lt->tm_min;
+ ret.sec=lt->tm_sec;
+ return ret;
+};
+
+void OSNacl::delay_usec(uint32_t p_usec) const {
+
+ //usleep(p_usec);
+};
+
+uint64_t OSNacl::get_ticks_usec() const {
+
+ struct timeval tv_now;
+ gettimeofday(&tv_now,NULL);
+
+ uint64_t longtime = (uint64_t)tv_now.tv_usec + (uint64_t)tv_now.tv_sec*1000000L;
+ longtime-=ticks_start;
+
+ return longtime;
+};
+
+bool OSNacl::can_draw() const {
+
+ return minimized != true;
+};
+
+void OSNacl::queue_event(const InputEvent& p_event) {
+
+ ERR_FAIL_INDEX( event_count, MAX_EVENTS );
+
+ event_queue[event_count++] = p_event;
+};
+
+void OSNacl::add_package(String p_name, Vector<uint8_t> p_data) {
+
+ FileAccessMemory::register_file(p_name, p_data);
+ FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_USERDATA);
+ FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_FILESYSTEM);
+
+ if (!PackedData::get_singleton())
+ memnew(PackedData);
+
+ printf("adding package %ls, %x\n", p_name.c_str(), PackedData::get_singleton());
+ PackedData::get_singleton()->set_disabled(true);
+ PackedData::get_singleton()->add_pack(p_name);
+ PackedData::get_singleton()->set_disabled(false);
+ printf("added\n");
+};
+
+void OSNacl::set_cursor_shape(CursorShape p_shape) {
+
+
+};
+
+String OSNacl::get_resource_dir() const {
+
+ return ".";
+};
+
+static int mouse_button(int p_nacl_but) {
+
+ switch (p_nacl_but) {
+
+ case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
+ return BUTTON_LEFT;
+ case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE:
+ return BUTTON_MIDDLE;
+ case PP_INPUTEVENT_MOUSEBUTTON_RIGHT:
+ return BUTTON_RIGHT;
+ };
+
+ return 0;
+};
+
+static InputModifierState modifier(uint32_t p_mod) {
+
+ InputModifierState mod_mask;
+
+ mod_mask.shift = p_mod & PP_INPUTEVENT_MODIFIER_SHIFTKEY;
+ mod_mask.alt = p_mod & PP_INPUTEVENT_MODIFIER_ALTKEY;
+ mod_mask.control = p_mod & PP_INPUTEVENT_MODIFIER_CONTROLKEY;
+ mod_mask.meta = p_mod & PP_INPUTEVENT_MODIFIER_METAKEY;
+
+ return mod_mask;
+};
+
+
+
+void OSNacl::handle_event(const pp::InputEvent& p_event) {
+
+ int type = p_event.GetType();
+ switch (type) {
+
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+ case PP_INPUTEVENT_TYPE_MOUSEUP:
+ case PP_INPUTEVENT_TYPE_WHEEL: {
+
+ InputEvent event;
+ event.ID=++event_id;
+ event.type = InputEvent::MOUSE_BUTTON;
+ event.device=0;
+
+ pp::MouseInputEvent mevent(p_event);
+ if (type == PP_INPUTEVENT_TYPE_WHEEL) {
+
+ pp::WheelInputEvent wevent(p_event);;
+ float ticks = wevent.GetTicks().y();
+ if (ticks == 0)
+ break; // whut?
+
+ event.mouse_button.pressed = true;
+ event.mouse_button.button_index = ticks > 0 ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN;
+ event.mouse_button.doubleclick = false;
+
+ } else {
+
+ event.mouse_button.pressed = (type == PP_INPUTEVENT_TYPE_MOUSEDOWN);
+ event.mouse_button.button_index = mouse_button(mevent.GetButton());
+ event.mouse_button.doubleclick = (mevent.GetClickCount() % 2) == 0;
+
+ mouse_mask &= ~(1<< (event.mouse_button.button_index - 1));
+ mouse_mask |= (event.mouse_button.pressed << (event.mouse_button.button_index - 1));
+ };
+ pp::Point pos = mevent.GetPosition();
+ event.mouse_button.button_mask = mouse_mask;
+ event.mouse_button.global_x = pos.x();
+ event.mouse_button.x = pos.x();
+ event.mouse_button.global_y = pos.y();
+ event.mouse_button.y = pos.y();
+ event.mouse_button.pointer_index = 0;
+ event.mouse_button.mod = modifier(p_event.GetModifiers());
+ queue_event(event);
+
+ } break;
+
+ case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
+
+ pp::MouseInputEvent mevent(p_event);
+ pp::Point pos = mevent.GetPosition();
+
+ InputEvent event;
+ event.ID=++event_id;
+ event.type = InputEvent::MOUSE_MOTION;
+ event.mouse_motion.pointer_index = 0;
+ event.mouse_motion.global_x = pos.x();
+ event.mouse_motion.global_y = pos.y();
+ event.mouse_motion.x = pos.x();
+ event.mouse_motion.y = pos.y();
+ event.mouse_motion.button_mask = mouse_mask;
+ event.mouse_motion.mod = modifier(p_event.GetModifiers());
+
+ event.mouse_motion.relative_x = pos.x() - mouse_last_x;
+ event.mouse_motion.relative_y = pos.y() - mouse_last_y;
+ mouse_last_x = pos.x();
+ mouse_last_y = pos.y();
+
+ queue_event(event);
+
+ } break;
+
+ case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYUP: {
+
+ pp::KeyboardInputEvent kevent(p_event);
+ bool is_char;
+ uint32_t key = godot_key(kevent.GetKeyCode(), is_char);
+ if (type != PP_INPUTEVENT_TYPE_KEYUP && is_char) {
+
+ last_scancode = key;
+ break;
+ };
+
+ InputEvent event;
+ event.ID=++event_id;
+ event.type = InputEvent::KEY;
+ event.key.pressed = (type != PP_INPUTEVENT_TYPE_KEYUP);
+ event.key.scancode = key;
+ event.key.unicode = key;
+
+ event.key.echo = p_event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT;
+ event.key.mod = modifier(p_event.GetModifiers());
+ queue_event(event);
+ } break;
+
+ case PP_INPUTEVENT_TYPE_CHAR: {
+
+ pp::KeyboardInputEvent kevent(p_event);
+ InputEvent event;
+ event.ID = ++event_id;
+ event.type = InputEvent::KEY;
+ event.key.pressed = true;
+ event.key.scancode = last_scancode;
+ event.key.unicode = kevent.GetCharacterText().AsString().c_str()[0];
+ event.key.mod = modifier(p_event.GetModifiers());
+ event.key.echo = p_event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT;
+ queue_event(event);
+
+ } break;
+
+ /*
+ case NPEventType_Minimize: {
+
+ minimized = p_event->u.minimize.value == 1;
+
+ } break;
+
+
+ case NPEventType_Focus: {
+
+ if (p_event->u.focus.value == 1) {
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+ } else {
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+ };
+ } break;
+
+ */
+
+ default:
+ ;
+ };
+};
+
+bool OSNacl::iterate() {
+
+ if (!main_loop) {
+ event_count = 0;
+ return true;
+ };
+
+ for (int i=0; i<event_count; i++) {
+
+ input->parse_input_event(event_queue[i]);
+ };
+
+ event_count = 0;
+
+ return Main::iteration();
+};
+
+
+OSNacl::OSNacl() {
+
+ main_loop=NULL;
+ mempool_dynamic = NULL;
+ mempool_static = NULL;
+ mouse_last_x = 0;
+ mouse_last_y = 0;
+ event_count = 0;
+ event_id = 0;
+ mouse_mask = 0;
+ video_mode = get_default_video_mode();
+ last_scancode = 0;
+ minimized = false;
+
+ ThreadPosix::make_default();
+ SemaphorePosix::make_default();
+ MutexPosix::make_default();
+ mempool_static = new MemoryPoolStaticMalloc;
+ mempool_dynamic = memnew( MemoryPoolDynamicStatic );
+};
+
+OSNacl::~OSNacl() {
+
+};
diff --git a/platform/nacl/os_nacl.h b/platform/nacl/os_nacl.h
new file mode 100644
index 0000000000..b8173ef61c
--- /dev/null
+++ b/platform/nacl/os_nacl.h
@@ -0,0 +1,156 @@
+/*************************************************************************/
+/* os_nacl.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef OS_NACL_H
+#define OS_NACL_H
+
+#include "core/os/os.h"
+
+#include "servers/visual_server.h"
+#include "servers/visual/rasterizer.h"
+#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/physics_2d/physics_2d_server_sw.h"
+#include "audio_driver_nacl.h"
+#include "os/input.h"
+
+
+#include <ppapi/cpp/input_event.h>
+
+class OSNacl : OS {
+
+ uint64_t ticks_start;
+
+protected:
+
+ enum {
+ MAX_EVENTS = 64,
+ };
+
+ MainLoop *main_loop;
+
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+ PhysicsServer *physics_server;
+ SpatialSoundServerSW *spatial_sound_server;
+
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+ Physics2DServer *physics_2d_server;
+ AudioDriverNacl* audio_driver;
+
+
+ // functions used by main to initialize/deintialize the OS
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
+ void vprint(const char* p_format, va_list p_list, bool p_stderr);
+
+ virtual void initialize_core();
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+ virtual void finalize_core();
+
+ int mouse_last_x, mouse_last_y;
+
+ InputEvent event_queue[MAX_EVENTS];
+ int event_count;
+ void queue_event(const InputEvent& p_event);
+
+ int event_id;
+ uint32_t mouse_mask;
+
+ uint32_t last_scancode;
+
+ bool minimized;
+
+ VideoMode video_mode;
+
+ InputDefault *input;
+
+public:
+
+ void add_package(String p_name, Vector<uint8_t> p_data);
+
+ void handle_event(const pp::InputEvent& p_event);
+
+ virtual void alert(const String& p_alert,const String& p_title);
+ virtual String get_stdin_string(bool p_block);
+
+ virtual void set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen);
+ virtual VideoMode get_video_mode(int p_screen) const;
+ virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const;
+
+ virtual Error execute(const String& p_path, const List<String>& p_arguments,bool p_blocking,ProcessID *r_child_id=NULL,String* r_pipe=NULL,int *r_exitcode=NULL);
+ virtual Error kill(const ProcessID& p_pid);
+
+ virtual bool has_environment(const String& p_var) const;
+ virtual String get_environment(const String& p_var) const;
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ virtual String get_name();
+
+ virtual MainLoop *get_main_loop() const;
+
+ virtual Date get_date() const;
+ virtual Time get_time() const;
+
+ virtual void delay_usec(uint32_t p_usec) const;
+ virtual uint64_t get_ticks_usec() const;
+
+ virtual String get_resource_dir() const;
+
+ virtual bool can_draw() const;
+
+ bool iterate();
+
+ OSNacl();
+ ~OSNacl();
+};
+
+#endif // OS_NACL_H
diff --git a/platform/nacl/pepper_main.cpp b/platform/nacl/pepper_main.cpp
new file mode 100644
index 0000000000..6a1f4acbe7
--- /dev/null
+++ b/platform/nacl/pepper_main.cpp
@@ -0,0 +1,541 @@
+/*************************************************************************/
+/* pepper_main.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+ IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and
+ your use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and
+ subject to these terms, Apple grants you a personal, non-exclusive license,
+ under Apple's copyrights in this original Apple software
+ (the "Apple Software"), to use, reproduce, modify and redistribute the Apple
+ Software, with or without modifications, in source and/or binary forms;
+ provided that if you redistribute the Apple Software in its entirety and
+ without modifications, you must retain this notice and the following text and
+ disclaimers in all such redistributions of the Apple Software. Neither the
+ name, trademarks, service marks or logos of Apple Computer, Inc. may be used
+ to endorse or promote products derived from the Apple Software without
+ specific prior written permission from Apple. Except as expressly stated in
+ this notice, no other rights or licenses, express or implied, are granted by
+ Apple herein, including but not limited to any patent rights that may be
+ infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
+ AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER
+ THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+#include "os_nacl.h"
+#include <GLES2/gl2.h>
+
+#include <nacl/npupp.h>
+#include <pgl/pgl.h>
+#include <string.h>
+#include <stdint.h>
+
+static NPNetscapeFuncs kBrowserFuncs = { 0 };
+static NPNetscapeFuncs* browser = &kBrowserFuncs;
+
+static NPDevice* device3d_ = NULL;
+static PGLContext pgl_context_;
+static NPDeviceContext3D context3d_;
+static int width_;
+static int height_;
+
+extern int nacl_main(int argc, char** argn, char** argv);
+extern void nacl_cleanup();
+
+NPExtensions* extensions = NULL;
+static NPP npp_;
+
+const int32_t kCommandBufferSize = 1024 * 1024;
+
+// Plugin entry points
+extern "C" {
+
+// Plugin entry points
+
+// Entrypoints -----------------------------------------------------------------
+
+NPError NP_GetEntryPoints(NPPluginFuncs* plugin_funcs) {
+ plugin_funcs->version = 11;
+ plugin_funcs->size = sizeof(plugin_funcs);
+ plugin_funcs->newp = NPP_New;
+ plugin_funcs->destroy = NPP_Destroy;
+ plugin_funcs->setwindow = NPP_SetWindow;
+ plugin_funcs->newstream = NPP_NewStream;
+ plugin_funcs->destroystream = NPP_DestroyStream;
+ plugin_funcs->asfile = NPP_StreamAsFile;
+ plugin_funcs->writeready = NPP_WriteReady;
+ plugin_funcs->write = (NPP_WriteUPP)NPP_Write;
+ plugin_funcs->print = NPP_Print;
+ plugin_funcs->event = NPP_HandleEvent;
+ plugin_funcs->urlnotify = NPP_URLNotify;
+ plugin_funcs->getvalue = NPP_GetValue;
+ plugin_funcs->setvalue = NPP_SetValue;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NP_Shutdown() {
+ pglTerminate();
+ return NPERR_NO_ERROR;
+}
+
+NPError NP_GetValue(void* instance, NPPVariable variable, void* value);
+char* NP_GetMIMEDescription();
+
+NPError NP_Initialize(NPNetscapeFuncs* browser_funcs,
+ NPPluginFuncs* plugin_funcs) {
+ printf("NPP_Initialize\n");
+ memcpy(&kBrowserFuncs, browser_funcs, sizeof(kBrowserFuncs));
+ pglInitialize();
+ return NP_GetEntryPoints(plugin_funcs);
+}
+
+
+} // extern "C"
+
+void Initialize3D() {
+ // Initialize a 3D context.
+ NPDeviceContext3DConfig config;
+ config.commandBufferSize = kCommandBufferSize;
+ NPError err = device3d_->initializeContext(npp_, &config, &context3d_);
+ if (err != NPERR_NO_ERROR) {
+ printf("Failed to initialize 3D context\n");
+ exit(1);
+ }
+
+ // Create a PGL context.
+ pgl_context_ = pglCreateContext(npp_, device3d_, &context3d_);
+
+ // Initialize the demo GL state.
+ //pglMakeCurrent(pgl_context_);
+ //GLFromCPPInit();
+ //pglMakeCurrent(NULL);
+}
+
+NPError NPP_New(NPMIMEType pluginType,
+ NPP instance,
+ uint16_t mode,
+ int16_t argc, char* argn[], char* argv[],
+ NPSavedData* saved) {
+ printf("NPP_New\n");
+ if (browser->version >= 14) {
+
+ npp_ = instance;
+ if (!extensions) {
+ browser->getvalue(npp_, NPNVPepperExtensions,
+ reinterpret_cast<void*>(&extensions));
+ // CHECK(extensions);
+ }
+
+ printf("%s: %i\n", __FUNCTION__, __LINE__);
+
+ device3d_ = extensions->acquireDevice(npp_, NPPepper3DDevice);
+ if (device3d_ == NULL) {
+ printf("Failed to acquire 3DDevice\n");
+ exit(1);
+ }
+ printf("%s: %i\n", __FUNCTION__, __LINE__);
+
+ /*
+ deviceaudio_ = extensions->acquireDevice(npp_, NPPepperAudioDevice);
+ if (deviceaudio_ == NULL) {
+ printf("Failed to acquire AudioDevice\n");
+ exit(1);
+ }
+ */
+ Initialize3D();
+ pglMakeCurrent(pgl_context_);
+ nacl_main(argc, argn, argv);
+ pglMakeCurrent(NULL);
+ };
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData** save) {
+
+ nacl_cleanup();
+
+ return NPERR_NO_ERROR;
+}
+
+void Destroy3D() {
+ printf("destroy 3d\n");
+ // Destroy the PGL context.
+ pglDestroyContext(pgl_context_);
+ pgl_context_ = NULL;
+
+ // Destroy the Device3D context.
+ device3d_->destroyContext(npp_, &context3d_);
+}
+
+static void iteration(void* data) {
+
+ (void)data;
+ OSNacl* os = (OSNacl*)OS::get_singleton();
+
+ if (!pglMakeCurrent(pgl_context_) && pglGetError() == PGL_CONTEXT_LOST) {
+ printf("******* Lost context! :O\n");
+ Destroy3D();
+ Initialize3D();
+ pglMakeCurrent(pgl_context_);
+ }
+
+ glViewport(0, 0, width_, height_);
+
+ os->iterate();
+
+ pglSwapBuffers();
+ pglMakeCurrent(NULL);
+
+ browser->pluginthreadasynccall(npp_, iteration, NULL);
+};
+
+NPError NPP_SetWindow(NPP instance, NPWindow* window) {
+
+ width_ = window->width;
+ height_ = window->height;
+
+ if (!pgl_context_)
+ Initialize3D();
+
+ // Schedule the first call to Draw.
+ OSNacl* os = (OSNacl*)OS::get_singleton();
+ OS::VideoMode vm;
+ vm.width = width_;
+ vm.height = height_;
+ vm.resizable = false;
+ vm.fullscreen = false;
+ os->set_video_mode(vm);
+
+ browser->pluginthreadasynccall(npp_, iteration, NULL);
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_NewStream(NPP instance,
+ NPMIMEType type,
+ NPStream* stream,
+ NPBool seekable,
+ uint16_t* stype) {
+ *stype = NP_ASFILEONLY;
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) {
+ return NPERR_NO_ERROR;
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {
+}
+
+int32_t NPP_Write(NPP instance,
+ NPStream* stream,
+ int32_t offset,
+ int32_t len,
+ void* buffer) {
+ return 0;
+}
+
+int32_t NPP_WriteReady(NPP instance, NPStream* stream) {
+ return 0;
+}
+
+void NPP_Print(NPP instance, NPPrint* platformPrint) {
+}
+
+int16_t NPP_HandleEvent(NPP instance, void* event) {
+
+ OSNacl* os = (OSNacl*)OS::get_singleton();
+ os->handle_event(event);
+ return 1;
+}
+
+void NPP_URLNotify(NPP instance,
+ const char* url,
+ NPReason reason,
+ void* notify_data) {
+ // PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+}
+
+static NPObject* Allocate(NPP npp, NPClass* npclass) {
+ return new NPObject;
+}
+
+static void Deallocate(NPObject* object) {
+ delete object;
+}
+
+// Return |true| if |method_name| is a recognized method.
+static bool HasMethod(NPObject* obj, NPIdentifier method_name) {
+
+ char *name = NPN_UTF8FromIdentifier(method_name);
+ bool is_method = false;
+ if (strcmp((const char *)name, "start_package") == 0) {
+ is_method = true;
+ } else if (strcmp((const char*)name, "add_package_chunk") == 0) {
+ is_method = true;
+ } else if (strcmp((const char*)name, "end_package") == 0) {
+ is_method = true;
+ } else if (strcmp((const char*)name, "start_scene") == 0) {
+ is_method = true;
+ }
+ NPN_MemFree(name);
+ return is_method;
+}
+
+// I don't know what this is
+static bool InvokeDefault(NPObject *obj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result) {
+ if (result) {
+ NULL_TO_NPVARIANT(*result);
+ }
+ return true;
+}
+
+static uint8_t* mem = NULL;
+static int pkg_size = 0;
+static String pkgname;
+
+static bool variant_is_number(const NPVariant& v) {
+
+ switch (v.type) {
+
+ case NPVariantType_Int32:
+ case NPVariantType_Double:
+ return true;
+
+ default:
+ return false;
+ }
+ return false;
+};
+
+static double variant_as_number(const NPVariant& v) {
+
+ switch (v.type) {
+
+ case NPVariantType_Int32:
+ return (double)v.value.intValue;
+ case NPVariantType_Double:
+ return (double)v.value.doubleValue;
+ default:
+ return 0;
+ }
+
+ return 0;
+};
+
+// Invoke() is called by the browser to invoke a function object whose name
+// is |method_name|.
+static bool Invoke(NPObject* obj,
+ NPIdentifier method_name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result) {
+ NULL_TO_NPVARIANT(*result);
+ char *name = NPN_UTF8FromIdentifier(method_name);
+ if (name == NULL)
+ return false;
+ bool rval = false;
+
+ OSNacl* os = (OSNacl*)OS::get_singleton();
+
+ if (strcmp(name, "start_package") == 0) {
+
+ printf("arg count is %i\n", arg_count);
+ for (int i=0; i<arg_count; i++) {
+ printf("type for %i is %i\n", i, args[i].type);
+ }
+ if (arg_count != 2) {
+ return false; // assuming "false" means error
+ };
+
+ if (args[0].type != NPVariantType_String) {
+ printf("arg 0 not string type %i\n", args[1].type);
+ return false;
+ };
+
+ if (!variant_is_number(args[1])) {
+
+ printf("arg 1 not number, type %i\n", args[1].type);
+ return false;
+ };
+
+ pkgname = String::utf8(args[0].value.stringValue.UTF8Characters, args[0].value.stringValue.UTF8Length);
+ pkg_size = (int)variant_as_number(args[1]);
+ mem = (uint8_t*)malloc(pkg_size);
+
+ printf("args %ls, %lf\n", pkgname.c_str(), variant_as_number(args[1]));
+
+ return true;
+ };
+
+ if (strcmp(name, "add_package_chunk") == 0) {
+
+ if (arg_count != 3) { // assuming arg_count starts from 1
+ return false; // assuming "false" means error
+ };
+
+ if (!variant_is_number(args[0])) return false;
+ if (args[1].type != NPVariantType_String) return false;
+ if (!variant_is_number(args[2])) return false;
+
+ if (!mem)
+ return false;
+
+ int ofs = variant_as_number(args[0]);
+ int len = variant_as_number(args[2]);
+
+ String s;
+ if (s.parse_utf8(args[1].value.stringValue.UTF8Characters, args[1].value.stringValue.UTF8Length)) {
+ printf("error parsing?\n");
+ };
+ uint8_t* dst = mem + ofs;
+ for (int i=0; i<len; i++) {
+
+ dst[i] = s[i];
+ };
+
+ //memcpy(mem + ofs, args[1].value.stringValue.UTF8Characters, len);
+ return true;
+ };
+
+ if (strcmp(name, "end_package") == 0) {
+
+ os->add_package(pkgname, mem, pkg_size);
+ return true;
+ };
+
+
+ if (strcmp(name, "start_scene") == 0) {
+printf("start_scene!\n");
+ if (arg_count != 1) {
+ return false;
+ };
+
+ if (args[0].type != NPVariantType_String) return false;
+printf("calling with param %s\n", args[0].value.stringValue.UTF8Characters);
+
+ printf("pepper iteration\n");
+ if (!pglMakeCurrent(pgl_context_) && pglGetError() == PGL_CONTEXT_LOST) {
+ printf("******* Lost context! :O\n");
+ Destroy3D();
+ Initialize3D();
+ pglMakeCurrent(pgl_context_);
+ }
+ os->start_scene(String::utf8(args[0].value.stringValue.UTF8Characters));
+ pglSwapBuffers();
+ pglMakeCurrent(NULL);
+
+printf("returning true\n");
+ return true;
+ };
+
+ NPN_MemFree(name);
+
+ return rval;
+}
+
+
+static NPClass GodotClass = {
+ NP_CLASS_STRUCT_VERSION,
+ Allocate,
+ Deallocate,
+ NULL, // Invalidate is not implemented
+ HasMethod,
+ Invoke,
+ InvokeDefault,
+ NULL, // HasProperty is not implemented
+ NULL, // GetProperty is not implemented
+ NULL, // SetProperty is not implemented
+};
+
+static NPObject* npobject = NULL;
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void* value) {
+ NPError err = NPERR_NO_ERROR;
+
+ switch (variable) {
+ case NPPVpluginNameString:
+ *(reinterpret_cast<const char**>(value)) = "Pepper Test PlugIn";
+ break;
+ case NPPVpluginDescriptionString:
+ *(reinterpret_cast<const char**>(value)) =
+ "Simple Pepper plug-in for manual testing.";
+ break;
+ case NPPVpluginNeedsXEmbed:
+ *(reinterpret_cast<NPBool*>(value)) = 1;
+ break;
+ case NPPVpluginScriptableNPObject: {
+ if (npobject == NULL) {
+ npobject = NPN_CreateObject(instance, &GodotClass);
+ } else {
+ NPN_RetainObject(npobject);
+ };
+ void** v = reinterpret_cast<void**>(value);
+ *v = npobject;
+ } break;
+ default:
+ fprintf(stderr, "Unhandled variable to NPP_GetValue\n");
+ err = NPERR_GENERIC_ERROR;
+ break;
+ }
+
+ return err;
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void* value) {
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NP_GetValue(void* instance, NPPVariable variable, void* value) {
+ return NPP_GetValue(reinterpret_cast<NPP>(instance), variable, value);
+}
+
+char* NP_GetMIMEDescription() {
+ return const_cast<char*>("pepper-application/x-pepper-test-plugin;");
+}
diff --git a/platform/nacl/platform_config.h b/platform/nacl/platform_config.h
new file mode 100644
index 0000000000..38fc934ae4
--- /dev/null
+++ b/platform/nacl/platform_config.h
@@ -0,0 +1,29 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <alloca.h>
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
new file mode 100644
index 0000000000..d7839d7d65
--- /dev/null
+++ b/platform/osx/SCsub
@@ -0,0 +1,11 @@
+Import('env')
+
+files = [
+ 'os_osx.mm',
+ 'godot_main_osx.mm',
+ 'audio_driver_osx.cpp',
+ 'sem_osx.cpp',
+# 'context_gl_osx.cpp',
+ ]
+
+env.Program('#bin/godot_osx',files)
diff --git a/platform/osx/audio_driver_osx.cpp b/platform/osx/audio_driver_osx.cpp
new file mode 100644
index 0000000000..8f28e8ff63
--- /dev/null
+++ b/platform/osx/audio_driver_osx.cpp
@@ -0,0 +1,160 @@
+/*************************************************************************/
+/* audio_driver_osx.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef OSX_ENABLED
+
+#include "audio_driver_osx.h"
+
+Error AudioDriverOSX::init() {
+
+ active = false;
+ channels = 2;
+
+ AudioStreamBasicDescription strdesc;
+ strdesc.mFormatID = kAudioFormatLinearPCM;
+ strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
+ strdesc.mChannelsPerFrame = channels;
+ strdesc.mSampleRate = 44100;
+ strdesc.mFramesPerPacket = 1;
+ strdesc.mBitsPerChannel = 16;
+ strdesc.mBytesPerFrame =
+ strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
+ strdesc.mBytesPerPacket =
+ strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
+
+ OSStatus result = noErr;
+ AURenderCallbackStruct callback;
+ AudioComponentDescription desc;
+ AudioComponent comp = NULL;
+ const AudioUnitElement output_bus = 0;
+ const AudioUnitElement bus = output_bus;
+ const AudioUnitScope scope = kAudioUnitScope_Input;
+
+ zeromem(&desc, sizeof(desc));
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentSubType = 0; /* !!! FIXME: ? */
+ comp = AudioComponentFindNext(NULL, &desc);
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+
+ result = AudioComponentInstanceNew(comp, &audio_unit);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+ ERR_FAIL_COND_V(comp == NULL, FAILED);
+
+ result = AudioUnitSetProperty(audio_unit,
+ kAudioUnitProperty_StreamFormat,
+ scope, bus, &strdesc, sizeof(strdesc));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ zeromem(&callback, sizeof(AURenderCallbackStruct));
+ callback.inputProc = &AudioDriverOSX::output_callback;
+ callback.inputProcRefCon = this;
+ result = AudioUnitSetProperty(audio_unit,
+ kAudioUnitProperty_SetRenderCallback,
+ scope, bus, &callback, sizeof(callback));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ result = AudioUnitInitialize(audio_unit);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ result = AudioOutputUnitStart(audio_unit);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ const int samples = 1024;
+ samples_in = memnew_arr(int32_t, samples); // whatever
+ buffer_frames = samples / channels;
+
+ return OK;
+};
+
+OSStatus AudioDriverOSX::output_callback(void *inRefCon,
+ AudioUnitRenderActionFlags * ioActionFlags,
+ const AudioTimeStamp * inTimeStamp,
+ UInt32 inBusNumber, UInt32 inNumberFrames,
+ AudioBufferList * ioData) {
+
+
+ AudioBuffer *abuf;
+ AudioDriverOSX* ad = (AudioDriverOSX*)inRefCon;
+
+ if (!ad->active) {
+ for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
+ abuf = &ioData->mBuffers[i];
+ zeromem(abuf->mData, abuf->mDataByteSize);
+ };
+ return 0;
+ };
+
+ int frames_left;
+
+ for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
+
+ abuf = &ioData->mBuffers[i];
+ frames_left = inNumberFrames;
+ int16_t* out = (int16_t*)abuf->mData;
+
+ while (frames_left) {
+
+ int frames = MIN(frames_left, ad->buffer_frames);
+ ad->lock();
+ ad->audio_server_process(frames, ad->samples_in);
+ ad->unlock();
+
+ for(int i = 0; i < frames * ad->channels; i++) {
+
+ out[i] = ad->samples_in[i]>>16;
+ }
+
+ frames_left -= frames;
+ out += frames * ad->channels;
+ };
+ };
+
+ return 0;
+};
+
+void AudioDriverOSX::start() {
+ active = true;
+};
+
+int AudioDriverOSX::get_mix_rate() const {
+ return 44100;
+};
+
+AudioDriverSW::OutputFormat AudioDriverOSX::get_output_format() const {
+ return OUTPUT_STEREO;
+};
+
+void AudioDriverOSX::lock() {};
+void AudioDriverOSX::unlock() {};
+
+void AudioDriverOSX::finish() {
+
+ memdelete_arr(samples_in);
+};
+
+#endif
diff --git a/platform/osx/audio_driver_osx.h b/platform/osx/audio_driver_osx.h
new file mode 100644
index 0000000000..daa388fb86
--- /dev/null
+++ b/platform/osx/audio_driver_osx.h
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* audio_driver_osx.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef OSX_ENABLED
+
+#ifndef AUDIO_DRIVER_OSX_H
+#define AUDIO_DRIVER_OSX_H
+
+#include "servers/audio/audio_server_sw.h"
+
+#include <AudioUnit/AudioUnit.h>
+
+class AudioDriverOSX : public AudioDriverSW {
+
+ AudioComponentInstance audio_unit;
+ bool active;
+
+ int channels;
+ int32_t* samples_in;
+ int buffer_frames;
+
+ static OSStatus output_callback(void *inRefCon,
+ AudioUnitRenderActionFlags * ioActionFlags,
+ const AudioTimeStamp * inTimeStamp,
+ UInt32 inBusNumber, UInt32 inNumberFrames,
+ AudioBufferList * ioData);
+
+
+public:
+
+ const char* get_name() const {
+ return "AudioUnit";
+ };
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+};
+
+#endif
+
+#endif
diff --git a/platform/osx/context_gl_osx.cpp b/platform/osx/context_gl_osx.cpp
new file mode 100644
index 0000000000..9c2cd16b49
--- /dev/null
+++ b/platform/osx/context_gl_osx.cpp
@@ -0,0 +1,104 @@
+/*************************************************************************/
+/* context_gl_osx.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "context_gl_osx.h"
+
+#ifdef OSX_ENABLED
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
+
+void ContextGL_OSX::release_current() {
+
+ aglSetCurrentContext( context );
+}
+
+void ContextGL_OSX::make_current() {
+
+ aglSetCurrentContext( NULL );
+}
+void ContextGL_OSX::swap_buffers() {
+
+ aglSwapBuffers( context );
+}
+
+Error ContextGL_OSX::initialize() {
+
+ if ( (Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat )
+ return FAILED;
+
+ GLint attributes[] = { AGL_RGBA,
+ AGL_DOUBLEBUFFER,
+ AGL_DEPTH_SIZE, 32,
+ AGL_NO_RECOVERY,
+ AGL_NONE,
+ AGL_NONE };
+
+ AGLPixelFormat format = NULL;
+
+ format = aglChoosePixelFormat( NULL, 0, attributes );
+
+ if ( !format )
+ return FAILED;
+
+ context = aglCreateContext( format, 0 );
+
+ if ( !context )
+ return FAILED;
+
+ aglDestroyPixelFormat( format );
+
+ aglSetWindowRef( context, window );
+
+ GLint swapInterval = 1;
+ aglSetInteger( context, AGL_SWAP_INTERVAL, &swapInterval );
+
+ aglSetCurrentContext( context );
+
+ return OK;
+}
+
+ContextGL_OSX::ContextGL_OSX(WindowRef p_window) {
+
+ window = p_window;
+}
+
+
+ContextGL_OSX::~ContextGL_OSX() {
+
+ if (context)
+ aglDestroyContext(context);
+}
+
+
+#endif
+#endif
diff --git a/platform/osx/context_gl_osx.h b/platform/osx/context_gl_osx.h
new file mode 100644
index 0000000000..54da42b331
--- /dev/null
+++ b/platform/osx/context_gl_osx.h
@@ -0,0 +1,65 @@
+/*************************************************************************/
+/* context_gl_osx.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CONTEXT_GL_OSX_H
+#define CONTEXT_GL_OSX_H
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+#ifdef OSX_ENABLED
+
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+
+#include "os/os.h"
+#include "drivers/gl_context/context_gl.h"
+#include <AGL/agl.h>
+#include <Carbon/Carbon.h>
+
+class ContextGL_OSX : public ContextGL {
+
+ AGLContext context;
+ WindowRef window;
+
+public:
+
+ virtual void release_current();
+ virtual void make_current();
+ virtual void swap_buffers();
+
+ virtual Error initialize();
+
+ ContextGL_OSX(WindowRef window);
+ ~ContextGL_OSX();
+
+};
+
+#endif
+
+#endif
+#endif
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
new file mode 100644
index 0000000000..5337416074
--- /dev/null
+++ b/platform/osx/detect.py
@@ -0,0 +1,107 @@
+
+import os
+import sys
+
+
+def is_active():
+ return True
+
+def get_name():
+ return "OSX"
+
+def can_build():
+
+ if (sys.platform != "darwin"):
+ return False
+
+ return True # osx enabled
+
+def get_opts():
+
+ return [
+ ('force_64_bits','Force 64 bits binary','no'),
+
+ ]
+
+def get_flags():
+
+ return [
+ ('opengl', 'no'),
+ ('legacygl', 'yes'),
+ ('builtin_zlib', 'no'),
+ ('freetype','builtin'), #use builtin freetype
+ ]
+
+
+
+def configure(env):
+
+ env.Append(CPPPATH=['#platform/osx'])
+
+ if (env["tools"]=="no"):
+ #no tools suffix
+ env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O2','-ffast-math','-fomit-frame-pointer','-ftree-vectorize','-msse2'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="release_debug"):
+
+ env.Append(CCFLAGS=['-O2','-DDEBUG_ENABLED'])
+ env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-g3', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
+
+
+ elif (env["target"]=="profile"):
+ env.Append(CCFLAGS=['-g','-pg'])
+ env.Append(LINKFLAGS=['-pg'])
+
+ if (env["freetype"]!="no"):
+ env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
+ env.Append(CPPPATH=['#tools/freetype'])
+ env.Append(CPPPATH=['#tools/freetype/freetype/include'])
+
+ if (env["force_64_bits"]!="no"):
+ env.Append(CCFLAGS=['-arch', 'x86_64'])
+ env.Append(LINKFLAGS=['-arch', 'x86_64'])
+ env['OBJSUFFIX'] = ".64"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".64"+env['LIBSUFFIX']
+ else:
+ env.Append(CCFLAGS=['-arch', 'i386'])
+ env.Append(LINKFLAGS=['-arch', 'i386'])
+
+# env.Append(CPPPATH=['#platform/osx/include/freetype2', '#platform/osx/include'])
+# env.Append(LIBPATH=['#platform/osx/lib'])
+
+
+ #if env['opengl'] == 'yes':
+ # env.Append(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED'])
+
+ env.Append(CPPFLAGS=["-DAPPLE_STYLE_KEYS"])
+ env.Append(CPPFLAGS=['-DUNIX_ENABLED','-DGLES2_ENABLED','-DGLEW_ENABLED', '-DOSX_ENABLED'])
+ env.Append(LIBS=['pthread'])
+ #env.Append(CPPFLAGS=['-F/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-mmacosx-version-min=10.4'])
+ #env.Append(LINKFLAGS=['-mmacosx-version-min=10.4', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk'])
+ env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit','-lz'])
+
+ if (env["CXX"]=="clang++"):
+ env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
+ env["CC"]="clang"
+ env["LD"]="clang++"
+
+ 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') } )
+
+
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
new file mode 100644
index 0000000000..f55e901794
--- /dev/null
+++ b/platform/osx/export/export.cpp
@@ -0,0 +1,504 @@
+#include "version.h"
+#include "export.h"
+#include "tools/editor/editor_settings.h"
+#include "tools/editor/editor_import_export.h"
+#include "tools/editor/editor_node.h"
+#include "io/zip_io.h"
+#include "io/marshalls.h"
+#include "io/resource_saver.h"
+#include "globals.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "platform/osx/logo.h"
+#include "string.h"
+
+
+class EditorExportPlatformOSX : public EditorExportPlatform {
+
+ OBJ_TYPE( EditorExportPlatformOSX,EditorExportPlatform );
+
+ String custom_release_package;
+ String custom_debug_package;
+
+
+ int version_code;
+
+ String app_name;
+ String info;
+ String icon;
+ String identifier;
+ String short_version;
+ String version;
+ String signature;
+ String copyright;
+ bool use64;
+ bool high_resolution;
+
+ Ref<ImageTexture> logo;
+
+ void _fix_plist(Vector<uint8_t>& plist, const String &p_binary);
+ void _make_icon(const Image& p_icon,Vector<uint8_t>& data);
+
+
+protected:
+
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+ virtual String get_name() const { return "Mac OSX"; }
+ virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_BC; }
+ virtual Ref<Texture> get_logo() const { return logo; }
+
+
+ virtual bool poll_devices() { return false;}
+ virtual int get_device_count() const { return 0; };
+ virtual String get_device_name(int p_device) const { return String(); }
+ virtual String get_device_info(int p_device) const { return String(); }
+ virtual Error run(int p_device);
+
+ virtual bool requieres_password(bool p_debug) const { return false; }
+ virtual String get_binary_extension() const { return "zip"; }
+ virtual Error export_project(const String& p_path,bool p_debug,const String& p_password="");
+
+ virtual bool can_export(String *r_error=NULL) const;
+
+ EditorExportPlatformOSX();
+ ~EditorExportPlatformOSX();
+};
+
+bool EditorExportPlatformOSX::_set(const StringName& p_name, const Variant& p_value) {
+
+ String n=p_name;
+
+ if (n=="custom_package/debug")
+ custom_debug_package=p_value;
+ else if (n=="custom_package/release")
+ custom_release_package=p_value;
+ else if (n=="application/name")
+ app_name=p_value;
+ else if (n=="application/info")
+ info=p_value;
+ else if (n=="application/icon")
+ icon=p_value;
+ else if (n=="application/identifier")
+ identifier=p_value;
+ else if (n=="application/signature")
+ signature=p_value;
+ else if (n=="application/short_version")
+ short_version=p_value;
+ else if (n=="application/version")
+ version=p_value;
+ else if (n=="application/copyright")
+ copyright=p_value;
+ else if (n=="application/64_bits")
+ use64=p_value;
+ else if (n=="display/high_res")
+ high_resolution=p_value;
+ else
+ return false;
+
+ return true;
+}
+
+bool EditorExportPlatformOSX::_get(const StringName& p_name,Variant &r_ret) const{
+
+ String n=p_name;
+
+ if (n=="custom_package/debug")
+ r_ret=custom_debug_package;
+ else if (n=="custom_package/release")
+ r_ret=custom_release_package;
+ else if (n=="application/name")
+ r_ret=app_name;
+ else if (n=="application/info")
+ r_ret=info;
+ else if (n=="application/icon")
+ r_ret=icon;
+ else if (n=="application/identifier")
+ r_ret=identifier;
+ else if (n=="application/signature")
+ r_ret=signature;
+ else if (n=="application/short_version")
+ r_ret=short_version;
+ else if (n=="application/version")
+ r_ret=version;
+ else if (n=="application/copyright")
+ r_ret=copyright;
+ else if (n=="application/64_bits")
+ r_ret=use64;
+ else if (n=="display/high_res")
+ r_ret=high_resolution;
+ else
+ return false;
+
+ return true;
+}
+void EditorExportPlatformOSX::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_FILE,"zip"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_FILE,"zip"));
+
+ p_list->push_back( PropertyInfo( Variant::STRING, "application/name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "application/info") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "application/icon",PROPERTY_HINT_FILE,"png") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "application/identifier") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "application/signature") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "application/short_version") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "application/version") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "application/copyright") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "application/64_bits") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "display/high_res") );
+
+
+ //p_list->push_back( PropertyInfo( Variant::INT, "resources/pack_mode", PROPERTY_HINT_ENUM,"Copy,Single Exec.,Pack (.pck),Bundles (Optical)"));
+
+}
+
+void EditorExportPlatformOSX::_make_icon(const Image& p_icon,Vector<uint8_t>& icon) {
+
+
+ Ref<ImageTexture> it = memnew( ImageTexture );
+ int size=512;
+
+ Vector<uint8_t> data;
+
+ data.resize(8);
+ data[0]='i';
+ data[1]='c';
+ data[2]='n';
+ data[3]='s';
+
+ const char *name[]={"ic09","ic08","ic07","icp6","icp5","icp4"};
+ int index=0;
+
+ while(size>=16) {
+
+ Image copy = p_icon;
+ copy.convert(Image::FORMAT_RGBA);
+ copy.resize(size,size);
+ it->create_from_image(copy);
+ String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/icon.png";
+ ResourceSaver::save(path,it);
+
+ FileAccess *f = FileAccess::open(path,FileAccess::READ);
+ ERR_FAIL_COND(!f);
+
+ int ofs = data.size();
+ uint32_t len = f->get_len();
+ data.resize(data.size()+len+8);
+ f->get_buffer(&data[ofs+8],len);
+ memdelete(f);
+ len+=8;
+ len=BSWAP32(len);
+ copymem(&data[ofs],name[index],4);
+ encode_uint32(len,&data[ofs+4]);
+ index++;
+ size/=2;
+ }
+
+ uint32_t total_len = data.size();
+ total_len = BSWAP32(total_len);
+ encode_uint32(total_len,&data[4]);
+
+ icon=data;
+}
+
+
+void EditorExportPlatformOSX::_fix_plist(Vector<uint8_t>& plist,const String& p_binary) {
+
+
+ String str;
+ String strnew;
+ str.parse_utf8((const char*)plist.ptr(),plist.size());
+ Vector<String> lines=str.split("\n");
+ for(int i=0;i<lines.size();i++) {
+ if (lines[i].find("$binary")!=-1) {
+ strnew+=lines[i].replace("$binary",p_binary)+"\n";
+ } else if (lines[i].find("$name")!=-1) {
+ strnew+=lines[i].replace("$name",p_binary)+"\n";
+ } else if (lines[i].find("$info")!=-1) {
+ strnew+=lines[i].replace("$info",info)+"\n";
+ } else if (lines[i].find("$identifier")!=-1) {
+ strnew+=lines[i].replace("$identifier",identifier)+"\n";
+ } else if (lines[i].find("$short_version")!=-1) {
+ strnew+=lines[i].replace("$short_version",short_version)+"\n";
+ } else if (lines[i].find("$version")!=-1) {
+ strnew+=lines[i].replace("$version",version)+"\n";
+ } else if (lines[i].find("$signature")!=-1) {
+ strnew+=lines[i].replace("$signature",signature)+"\n";
+ } else if (lines[i].find("$copyright")!=-1) {
+ strnew+=lines[i].replace("$copyright",copyright)+"\n";
+ } else if (lines[i].find("$highres")!=-1) {
+ strnew+=lines[i].replace("$highres",high_resolution?"<true/>":"<false/>")+"\n";
+ } else {
+ strnew+=lines[i]+"\n";
+ }
+ }
+
+ CharString cs = strnew.utf8();
+ plist.resize(cs.size());
+ for(int i=9;i<cs.size();i++) {
+ plist[i]=cs[i];
+ }
+}
+
+Error EditorExportPlatformOSX::export_project(const String& p_path,bool p_debug,const String& p_password) {
+
+ String src_pkg;
+
+ EditorProgress ep("export","Exporting for OSX",104);
+
+ String pkg_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/osx.zip";
+
+ if (p_debug) {
+
+ src_pkg=custom_debug_package!=""?custom_debug_package:pkg_path;
+ } else {
+
+ src_pkg=custom_release_package!=""?custom_release_package:pkg_path;
+
+ }
+
+
+ FileAccess *src_f=NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ ep.step("Creating app",0);
+
+ unzFile pkg = unzOpen2(src_pkg.utf8().get_data(), &io);
+ if (!pkg) {
+
+ EditorNode::add_io_error("Could not find template app to export:\n"+src_pkg);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(pkg);
+
+ zlib_filefunc_def io2=io;
+ FileAccess *dst_f=NULL;
+ io2.opaque=&dst_f;
+ zipFile dpkg=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2);
+
+ String binary_to_use="godot_osx_"+String(p_debug?"debug":"release")+"."+String(use64?"64":"32");
+
+ print_line("binary: "+binary_to_use);
+ String pkg_name;
+ if (app_name!="")
+ pkg_name=app_name;
+ else if (String(Globals::get_singleton()->get("application/name"))!="")
+ pkg_name=String(Globals::get_singleton()->get("application/name"));
+ else
+ pkg_name="Unnamed";
+
+
+ while(ret==UNZ_OK) {
+
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0);
+
+ String file=fname;
+
+ print_line("READ: "+file);
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg,data.ptr(),data.size());
+ unzCloseCurrentFile(pkg);
+
+ //write
+
+ file = file.replace_first("osx_template.app/","");
+
+
+ if (file=="Contents/Info.plist") {
+ print_line("parse plist");
+ _fix_plist(data,pkg_name);
+ }
+
+ if (file.begins_with("Contents/MacOS/godot_")) {
+ if (file!="Contents/MacOS/"+binary_to_use) {
+ ret = unzGoToNextFile(pkg);
+ continue; //ignore!
+ }
+ file="Contents/MacOS/"+pkg_name;
+ }
+
+ if (file=="Contents/Resources/icon.icns") {
+ //see if there is an icon
+ String iconpath = Globals::get_singleton()->get("application/icon");
+ print_line("icon? "+iconpath);
+ if (iconpath!="") {
+ Image icon;
+ icon.load(iconpath);
+ if (!icon.empty()) {
+ print_line("loaded?");
+ _make_icon(icon,data);
+ }
+ }
+ //bleh?
+ }
+
+ file=pkg_name+".app/"+file;
+
+ if (data.size()>0) {
+ print_line("ADDING: "+file+" size: "+itos(data.size()));
+
+ zip_fileinfo fi;
+ fi.tmz_date.tm_hour=info.tmu_date.tm_hour;
+ fi.tmz_date.tm_min=info.tmu_date.tm_min;
+ fi.tmz_date.tm_sec=info.tmu_date.tm_sec;
+ fi.tmz_date.tm_mon=info.tmu_date.tm_mon;
+ fi.tmz_date.tm_mday=info.tmu_date.tm_mday;
+ fi.tmz_date.tm_year=info.tmu_date.tm_year;
+ fi.dosDate=info.dosDate;
+ fi.internal_fa=info.internal_fa;
+ fi.external_fa=info.external_fa;
+
+ int err = zipOpenNewFileInZip(dpkg,
+ file.utf8().get_data(),
+ &fi,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION);
+
+ print_line("OPEN ERR: "+itos(err));
+ err = zipWriteInFileInZip(dpkg,data.ptr(),data.size());
+ print_line("WRITE ERR: "+itos(err));
+ zipCloseFileInZip(dpkg);
+ }
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+
+ ep.step("Making PKG",1);
+
+ String pack_path=EditorSettings::get_singleton()->get_settings_path()+"/tmp/data.pck";
+ FileAccess *pfs = FileAccess::open(pack_path,FileAccess::WRITE);
+ Error err = save_pack(pfs);
+ memdelete(pfs);
+
+ if (err) {
+ zipClose(dpkg,NULL);
+ unzClose(pkg);
+ return err;
+
+ }
+
+ {
+ //write datapack
+
+ int err = zipOpenNewFileInZip(dpkg,
+ (pkg_name+".app/Contents/Resources/data.pck").utf8().get_data(),
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION);
+
+
+ FileAccess *pf = FileAccess::open(pack_path,FileAccess::READ);
+ ERR_FAIL_COND_V(!pf,ERR_CANT_OPEN);
+ const int BSIZE = 16384;
+ uint8_t buf[BSIZE];
+
+ while(true) {
+
+ int r = pf->get_buffer(buf,BSIZE);
+ if (r<=0)
+ break;
+ zipWriteInFileInZip(dpkg,buf,r);
+
+ }
+ zipCloseFileInZip(dpkg);
+ memdelete(pf);
+
+ }
+
+ zipClose(dpkg,NULL);
+ unzClose(pkg);
+
+ return OK;
+}
+
+
+Error EditorExportPlatformOSX::run(int p_device) {
+
+ return OK;
+}
+
+
+EditorExportPlatformOSX::EditorExportPlatformOSX() {
+
+ Image img( _osx_logo );
+ logo = Ref<ImageTexture>( memnew( ImageTexture ));
+ logo->create_from_image(img);
+
+ info="This Game is Nice";
+ identifier="com.godot.macgame";
+ signature="godotmacgame";
+ short_version="1.0";
+ version="1.0";
+ use64=false;
+ high_resolution=false;
+
+}
+
+bool EditorExportPlatformOSX::can_export(String *r_error) const {
+
+
+ bool valid=true;
+ String err;
+ String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+
+ if (!FileAccess::exists(exe_path+"osx.zip")) {
+ valid=false;
+ err+="No export templates found.\nDownload and install export templates.\n";
+ }
+
+ if (custom_debug_package!="" && !FileAccess::exists(custom_debug_package)) {
+ valid=false;
+ err+="Custom debug package not found.\n";
+ }
+
+ if (custom_release_package!="" && !FileAccess::exists(custom_release_package)) {
+ valid=false;
+ err+="Custom release package not found.\n";
+ }
+
+ if (r_error)
+ *r_error=err;
+
+ return valid;
+}
+
+
+EditorExportPlatformOSX::~EditorExportPlatformOSX() {
+
+}
+
+
+void register_osx_exporter() {
+
+
+ Ref<EditorExportPlatformOSX> exporter = Ref<EditorExportPlatformOSX>( memnew(EditorExportPlatformOSX) );
+ EditorImportExport::get_singleton()->add_export_platform(exporter);
+
+
+}
+
diff --git a/platform/osx/export/export.h b/platform/osx/export/export.h
new file mode 100644
index 0000000000..b149e482c9
--- /dev/null
+++ b/platform/osx/export/export.h
@@ -0,0 +1,3 @@
+
+
+void register_osx_exporter();
diff --git a/platform/osx/godot_main_osx.mm b/platform/osx/godot_main_osx.mm
new file mode 100644
index 0000000000..3546c1e71a
--- /dev/null
+++ b/platform/osx/godot_main_osx.mm
@@ -0,0 +1,86 @@
+/*************************************************************************/
+/* godot_main_osx.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "os_osx.h"
+#include "main/main.h"
+
+#include <string.h>
+#include <unistd.h>
+
+//#define main godot_main
+
+int main(int argc, char** argv) {
+
+
+
+ if (argc>=1 && argv[0][0]=='/') {
+ //potentially launched from finder
+ int len = strlen(argv[0]);
+ while (len--) {
+ if (argv[0][len] == '/') break;
+ }
+ if (len>=0) {
+ char *path = (char *)malloc(len+1);
+ memcpy(path, argv[0], len);
+ path[len]=0;
+
+ char *pathinfo = (char*)malloc(strlen(path)+strlen("/../Info.plist")+1);
+ //in real code you would check for errors in malloc here
+ strcpy(pathinfo, path);
+ strcat(pathinfo, "/../Info.plist");
+
+ FILE*f=fopen(pathinfo,"rb");
+ if (f) {
+ //running from app bundle, as Info.plist was found
+ fclose(f);
+ chdir(path);
+ chdir("../Resources"); //data.pck, or just the files are here
+
+ }
+
+ free(path);
+ free(pathinfo);
+ }
+
+
+
+ }
+
+ OS_OSX os;
+
+
+ Error err = Main::setup(argv[0],argc-1,&argv[1]);
+ if (err!=OK)
+ return 255;
+
+ if (Main::start())
+ os.run(); // it is actually the OS that decides how to run
+ Main::cleanup();
+
+ return 0;
+};
diff --git a/platform/osx/godot_osx.h b/platform/osx/godot_osx.h
new file mode 100644
index 0000000000..ebac475089
--- /dev/null
+++ b/platform/osx/godot_osx.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* godot_osx.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef GODOT_OSX_H
+#define GODOT_OSX_H
+
+#import <Cocoa/Cocoa.h>
+
+@interface GodotMain : NSObject
+@end
+
+#endif
diff --git a/platform/osx/godot_osx.mm b/platform/osx/godot_osx.mm
new file mode 100644
index 0000000000..fb3c5808c7
--- /dev/null
+++ b/platform/osx/godot_osx.mm
@@ -0,0 +1,215 @@
+/*************************************************************************/
+/* godot_osx.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <sys/param.h> /* for MAXPATHLEN */
+#include <unistd.h>
+#include "godot_osx.h"
+
+/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
+ but the method still is there and works. To avoid warnings, we declare
+ it ourselves here. */
+@interface NSApplication()
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+
+static int global_argc;
+static char **global_argv;
+static BOOL gCalledAppMainline = FALSE;
+
+static NSString *getApplicationName(void)
+{
+ const NSDictionary *dict;
+ NSString *appName = 0;
+
+ /* Determine the application name */
+ dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
+ if (dict)
+ appName = [dict objectForKey: @"CFBundleName"];
+
+ if (![appName length])
+ appName = [[NSProcessInfo processInfo] processName];
+
+ return appName;
+}
+
+/* The main class of the application, the application's delegate */
+@implementation GodotMain
+
+static void setApplicationMenu(void)
+{
+ /* warning: this code is very odd */
+ NSMenu *appleMenu;
+ NSMenuItem *menuItem;
+ NSString *title;
+ NSString *appName;
+
+ appName = getApplicationName();
+ appleMenu = [[NSMenu alloc] initWithTitle:@""];
+
+ /* Add menu items */
+ title = [@"About " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Hide " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+
+ menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+
+ [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+
+ title = [@"Quit " stringByAppendingString:appName];
+ [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+
+
+ /* Put menu into the menubar */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+ [menuItem setSubmenu:appleMenu];
+ [[NSApp mainMenu] addItem:menuItem];
+
+ /* Tell the application object that this is now the application menu */
+ [NSApp setAppleMenu:appleMenu];
+
+ /* Finally give up our references to the objects */
+ [appleMenu release];
+ [menuItem release];
+}
+
+/* Create a window menu */
+static void setupWindowMenu(void)
+{
+ NSMenu *windowMenu;
+ NSMenuItem *windowMenuItem;
+ NSMenuItem *menuItem;
+
+ windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+ /* "Minimize" item */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
+ [windowMenu addItem:menuItem];
+ [menuItem release];
+
+ /* Put menu into the menubar */
+ windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
+ [windowMenuItem setSubmenu:windowMenu];
+ [[NSApp mainMenu] addItem:windowMenuItem];
+
+ /* Tell the application object that this is now the window menu */
+ [NSApp setWindowsMenu:windowMenu];
+
+ /* Finally give up our references to the objects */
+ [windowMenu release];
+ [windowMenuItem release];
+}
+
+/* Replacement for NSApplicationMain */
+static void CustomApplicationMain (int argc, char **argv)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ GodotMain *main;
+
+ /* Ensure the application object is initialised */
+ [NSApplication sharedApplication];
+
+ /* Set up the menubar */
+ [NSApp setMainMenu:[[NSMenu alloc] init]];
+ setApplicationMenu();
+ setupWindowMenu();
+
+ main = [[main alloc] init];
+ [NSApp setDelegate:main];
+
+ /* Start the main event loop */
+ [NSApp run];
+
+ [main release];
+ [pool release];
+}
+
+extern int godot_main(int argc, char** argv);
+
+/* Called when the internal event loop has just started running */
+- (void) applicationDidFinishLaunching: (NSNotification *) note
+{
+ int status;
+
+ /* Hand off to main application code */
+ gCalledAppMainline = TRUE;
+
+ int ret = godot_main(global_argc, global_argv);
+
+ exit(ret);
+}
+@end
+
+#ifdef main
+# undef main
+#endif
+
+
+int main (int argc, char **argv)
+{
+ /* Copy the arguments into a global variable */
+ /* This is passed if we are launched by double-clicking */
+ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
+ global_argv = (char **) malloc(sizeof (char *) * 2);
+ global_argv[0] = argv[0];
+ global_argv[1] = NULL;
+ global_argc = 1;
+
+ // chdir to binary's dir when launched from finder
+ int len = strlen(global_argv[0]);
+
+ while (len--){
+ if (global_argv[0][len] == '/') break;
+ }
+
+ if (len>=0) {
+ char *path = (char *)malloc(len+1);
+ memcpy(path, global_argv[0], len);
+ path[len]=0;
+ printf("Path: %s\n", path);
+ chdir(path);
+ }
+
+ } else {
+ int i;
+ global_argc = argc;
+ global_argv = (char **) malloc(sizeof (char *) * (argc+1));
+ for (i = 0; i <= argc; i++)
+ global_argv[i] = argv[i];
+ }
+
+ CustomApplicationMain (argc, argv);
+ return 0;
+}
+
diff --git a/platform/osx/logo.png b/platform/osx/logo.png
new file mode 100644
index 0000000000..2bcd3aa72e
--- /dev/null
+++ b/platform/osx/logo.png
Binary files differ
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
new file mode 100644
index 0000000000..b9e381d6ec
--- /dev/null
+++ b/platform/osx/os_osx.h
@@ -0,0 +1,166 @@
+/*************************************************************************/
+/* os_osx.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef OS_OSX_H
+#define OS_OSX_H
+
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+
+#include "servers/visual_server.h"
+#include "servers/visual/visual_server_wrap_mt.h"
+#include "servers/visual/rasterizer.h"
+#include "servers/physics_server.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/audio/sample_manager_sw.h"
+#include "servers/spatial_sound/spatial_sound_server_sw.h"
+#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "drivers/rtaudio/audio_driver_rtaudio.h"
+#include "drivers/alsa/audio_driver_alsa.h"
+#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "platform/osx/audio_driver_osx.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+//bitch
+#undef CursorShape
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+class OS_OSX : public OS_Unix {
+public:
+ bool force_quit;
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+ VideoMode current_videomode;
+ List<String> args;
+ MainLoop *main_loop;
+ unsigned int event_id;
+
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+
+ IP_Unix *ip_unix;
+
+ AudioDriverOSX audio_driver_osx;
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+
+ InputDefault *input;
+
+ /* objc */
+
+ CGEventSourceRef eventSource;
+
+ void process_events();
+
+ void* framework;
+// pthread_key_t current;
+ bool mouse_grab;
+ Point2 mouse_pos;
+ uint32_t last_id;
+
+ id delegate;
+ id window_delegate;
+ id window_object;
+ id window_view;
+ id autoreleasePool;
+ id cursor;
+ id pixelFormat;
+ id context;
+
+ CursorShape cursor_shape;
+
+protected:
+
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual void initialize_core();
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+ virtual void finalize();
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+
+public:
+
+
+
+
+
+
+ static OS_OSX* singleton;
+
+ virtual String get_name();
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ virtual void set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ virtual void set_icon(const Image& p_icon);
+
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_clipboard(const String& p_text);
+ virtual String get_clipboard() const;
+
+ virtual void release_rendering_thread();
+ virtual void make_rendering_thread();
+ virtual void swap_buffers();
+
+ Error shell_open(String p_uri);
+ void push_input(const InputEvent& p_event);
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ 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 String get_executable_path() const;
+
+ virtual void move_window_to_foreground();
+
+ void run();
+
+
+ OS_OSX();
+};
+
+#endif
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
new file mode 100644
index 0000000000..86d1dbb4c2
--- /dev/null
+++ b/platform/osx/os_osx.mm
@@ -0,0 +1,1323 @@
+/*************************************************************************/
+/* os_osx.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#import <Cocoa/Cocoa.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/hid/IOHIDLib.h>
+#include <IOKit/hid/IOHIDKeys.h>
+
+#include "sem_osx.h"
+#include "servers/visual/visual_server_raster.h"
+//#include "drivers/opengl/rasterizer_gl.h"
+//#include "drivers/gles2/rasterizer_gles2.h"
+#include "os_osx.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "print_string.h"
+#include "servers/physics/physics_server_sw.h"
+#include "drivers/gles2/rasterizer_instance_gles2.h"
+#include "servers/visual/visual_server_wrap_mt.h"
+#include "main/main.h"
+#include "os/keyboard.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libproc.h>
+//uses portions of glfw
+
+//========================================================================
+// GLFW 3.0 - www.glfw.org
+//------------------------------------------------------------------------
+// Copyright (c) 2002-2006 Marcus Geelnard
+// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would
+// be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+// be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+// distribution.
+//
+//========================================================================
+
+static NSRect convertRectToBacking(NSRect contentRect) {
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+ if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
+ return [OS_OSX::singleton->window_view convertRectToBacking:contentRect];
+ else
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+ return contentRect;
+
+}
+
+static InputModifierState translateFlags(NSUInteger flags)
+{
+ InputModifierState mod;
+
+
+ mod.shift = (flags & NSShiftKeyMask);
+ mod.control = (flags & NSControlKeyMask);
+ mod.alt = (flags & NSAlternateKeyMask);
+ mod.meta = (flags & NSCommandKeyMask);
+
+ return mod;
+}
+
+static int mouse_x=0;
+static int mouse_y=0;
+static int prev_mouse_x=0;
+static int prev_mouse_y=0;
+static int button_mask=0;
+
+
+@interface GodotApplication : NSApplication
+@end
+
+@implementation GodotApplication
+
+// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
+// This works around an AppKit bug, where key up events while holding
+// down the command key don't get sent to the key window.
+- (void)sendEvent:(NSEvent *)event
+{
+ if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask))
+ [[self keyWindow] sendEvent:event];
+ else
+ [super sendEvent:event];
+}
+
+@end
+
+@interface GodotApplicationDelegate : NSObject
+@end
+
+@implementation GodotApplicationDelegate
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
+{
+/* _Godotwindow* window;
+
+ for (window = _Godot.windowListHead; window; window = window->next)
+ _GodotInputWindowCloseRequest(window);
+*/
+ return NSTerminateCancel;
+}
+
+- (void)applicationDidHide:(NSNotification *)notification
+{
+ /* _Godotwindow* window;
+
+ for (window = _Godot.windowListHead; window; window = window->next)
+ _GodotInputWindowVisibility(window, GL_FALSE);
+ */
+}
+
+- (void)applicationDidUnhide:(NSNotification *)notification
+{
+ /*
+ _Godotwindow* window;
+
+ for (window = _Godot.windowListHead; window; window = window->next)
+ {
+ if ([window_object isVisible])
+ _GodotInputWindowVisibility(window, GL_TRUE);
+ }
+ */
+}
+
+- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
+{
+ //_GodotInputMonitorChange();
+}
+
+@end
+
+@interface GodotWindowDelegate : NSObject
+{
+ // _Godotwindow* window;
+}
+
+@end
+
+@implementation GodotWindowDelegate
+
+
+- (BOOL)windowShouldClose:(id)sender
+{
+ //_GodotInputWindowCloseRequest(window);
+ if (OS_OSX::singleton->get_main_loop())
+ OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+ return NO;
+}
+
+
+
+
+- (void)windowDidResize:(NSNotification *)notification
+{
+ [OS_OSX::singleton->context update];
+
+ const NSRect contentRect = [OS_OSX::singleton->window_view frame];
+ const NSRect fbRect = convertRectToBacking(contentRect);
+
+ OS_OSX::singleton->current_videomode.width=fbRect.size.width;
+ OS_OSX::singleton->current_videomode.height=fbRect.size.height;
+
+
+ // _GodotInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
+ // _GodotInputWindowSize(window, contentRect.size.width, contentRect.size.height);
+ //_GodotInputWindowDamage(window);
+
+ //if (window->cursorMode == Godot_CURSOR_DISABLED)
+ // centerCursor(window);
+}
+
+- (void)windowDidMove:(NSNotification *)notification
+{
+ // [window->nsgl.context update];
+
+ // int x, y;
+ // _GodotPlatformGetWindowPos(window, &x, &y);
+ // _GodotInputWindowPos(window, x, y);
+
+ //if (window->cursorMode == Godot_CURSOR_DISABLED)
+ // centerCursor(window);
+}
+
+- (void)windowDidMiniaturize:(NSNotification *)notification
+{
+ // _GodotInputWindowIconify(window, GL_TRUE);
+}
+
+- (void)windowDidDeminiaturize:(NSNotification *)notification
+{
+ //if (window->monitor)
+// enterFullscreenMode(window);
+
+ // _GodotInputWindowIconify(window, GL_FALSE);
+}
+
+- (void)windowDidBecomeKey:(NSNotification *)notification
+{
+ // _GodotInputWindowFocus(window, GL_TRUE);
+ // _GodotPlatformSetCursorMode(window, window->cursorMode);
+ if (OS_OSX::singleton->get_main_loop())
+ OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+}
+
+- (void)windowDidResignKey:(NSNotification *)notification
+{
+ // _GodotInputWindowFocus(window, GL_FALSE);
+ // _GodotPlatformSetCursorMode(window, Godot_CURSOR_NORMAL);
+ if (OS_OSX::singleton->get_main_loop())
+ OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+}
+
+@end
+
+@interface GodotContentView : NSView
+{
+ NSTrackingArea* trackingArea;
+}
+
+
+
+@end
+
+@implementation GodotContentView
+
++ (void)initialize
+{
+ if (self == [GodotContentView class])
+ {
+ /* if (_glfw.ns.cursor == nil)
+ {
+ NSImage* data = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)];
+ _glfw.ns.cursor = [[NSCursor alloc] initWithImage:data
+ hotSpot:NSZeroPoint];
+ [data release];
+ }*/
+ }
+}
+
+- (id)init
+{
+ self = [super init];
+ trackingArea = nil;
+ [self updateTrackingAreas];
+
+ return self;
+}
+
+-(void)dealloc
+{
+ [trackingArea release];
+ [super dealloc];
+}
+
+- (BOOL)isOpaque
+{
+ return YES;
+}
+
+- (BOOL)canBecomeKeyView
+{
+ return YES;
+}
+
+- (BOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+- (void)cursorUpdate:(NSEvent *)event
+{
+ // setModeCursor(window, window->cursorMode);
+}
+
+- (void)mouseDown:(NSEvent *)event
+{
+
+ print_line("mouse down:");
+ button_mask|=BUTTON_MASK_LEFT;
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.pressed=true;
+ ev.mouse_button.x=mouse_x;
+ ev.mouse_button.y=mouse_y;
+ ev.mouse_button.global_x=mouse_x;
+ ev.mouse_button.global_y=mouse_y;
+ ev.mouse_button.button_mask=button_mask;
+ ev.mouse_button.doubleclick = [event clickCount]==2;
+ ev.mouse_button.mod = translateFlags([event modifierFlags]);
+ OS_OSX::singleton->push_input(ev);
+
+
+ /* _glfwInputMouseClick(window,
+ GLFW_MOUSE_BUTTON_LEFT,
+ GLFW_PRESS,
+ translateFlags([event modifierFlags]));*/
+}
+
+- (void)mouseDragged:(NSEvent *)event
+{
+ [self mouseMoved:event];
+}
+
+- (void)mouseUp:(NSEvent *)event
+{
+
+ button_mask&=~BUTTON_MASK_LEFT;
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.mouse_button.button_index=BUTTON_LEFT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=mouse_x;
+ ev.mouse_button.y=mouse_y;
+ ev.mouse_button.global_x=mouse_x;
+ ev.mouse_button.global_y=mouse_y;
+ ev.mouse_button.button_mask=button_mask;
+ ev.mouse_button.mod = translateFlags([event modifierFlags]);
+ OS_OSX::singleton->push_input(ev);
+
+ /* _glfwInputMouseClick(window,
+ GLFW_MOUSE_BUTTON_LEFT,
+ GLFW_RELEASE,
+ translateFlags([event modifierFlags]));*/
+}
+
+- (void)mouseMoved:(NSEvent *)event
+{
+
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_MOTION;
+ ev.mouse_motion.button_mask=button_mask;
+ prev_mouse_x=mouse_x;
+ prev_mouse_y=mouse_y;
+ const NSRect contentRect = [OS_OSX::singleton->window_view frame];
+ const NSPoint p = [event locationInWindow];
+ mouse_x = p.x;
+ mouse_y = contentRect.size.height - p.y;
+ ev.mouse_motion.x=mouse_x;
+ ev.mouse_motion.y=mouse_y;
+ ev.mouse_motion.global_x=mouse_x;
+ ev.mouse_motion.global_y=mouse_y;
+ ev.mouse_motion.relative_x=mouse_x - prev_mouse_x;
+ ev.mouse_motion.relative_y=mouse_y - prev_mouse_y;
+ ev.mouse_motion.mod = translateFlags([event modifierFlags]);
+
+
+// ev.mouse_motion.relative_x=[event deltaX];
+// ev.mouse_motion.relative_y=[event deltaY];
+
+ OS_OSX::singleton->push_input(ev);
+
+
+ /* if (window->cursorMode == GLFW_CURSOR_DISABLED)
+ _glfwInputCursorMotion(window, [event deltaX], [event deltaY]);
+ else
+ {
+ const NSRect contentRect = [window->ns.view frame];
+ const NSPoint p = [event locationInWindow];
+
+ _glfwInputCursorMotion(window, p.x, contentRect.size.height - p.y);
+ }*/
+}
+
+- (void)rightMouseDown:(NSEvent *)event
+{
+
+ button_mask|=BUTTON_MASK_RIGHT;
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.mouse_button.button_index=BUTTON_RIGHT;
+ ev.mouse_button.pressed=true;
+ ev.mouse_button.x=mouse_x;
+ ev.mouse_button.y=mouse_y;
+ ev.mouse_button.global_x=mouse_x;
+ ev.mouse_button.global_y=mouse_y;
+ ev.mouse_button.button_mask=button_mask;
+ ev.mouse_button.mod = translateFlags([event modifierFlags]);
+ OS_OSX::singleton->push_input(ev);
+
+ /* _glfwInputMouseClick(window,
+ GLFW_MOUSE_BUTTON_RIGHT,
+ GLFW_PRESS,
+ translateFlags([event modifierFlags]));*/
+}
+
+- (void)rightMouseDragged:(NSEvent *)event
+{
+ [self mouseMoved:event];
+}
+
+- (void)rightMouseUp:(NSEvent *)event
+{
+
+ button_mask&=~BUTTON_MASK_RIGHT;
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.mouse_button.button_index=BUTTON_RIGHT;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=mouse_x;
+ ev.mouse_button.y=mouse_y;
+ ev.mouse_button.global_x=mouse_x;
+ ev.mouse_button.global_y=mouse_y;
+ ev.mouse_button.button_mask=button_mask;
+ ev.mouse_button.mod = translateFlags([event modifierFlags]);
+ OS_OSX::singleton->push_input(ev);
+
+ /*_glfwInputMouseClick(window,
+ GLFW_MOUSE_BUTTON_RIGHT,
+ GLFW_RELEASE,
+ translateFlags([event modifierFlags]));*/
+}
+
+- (void)otherMouseDown:(NSEvent *)event
+{
+
+ if ((int) [event buttonNumber]!=2)
+ return;
+
+ button_mask|=BUTTON_MASK_MIDDLE;
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.mouse_button.button_index=BUTTON_MIDDLE;
+ ev.mouse_button.pressed=true;
+ ev.mouse_button.x=mouse_x;
+ ev.mouse_button.y=mouse_y;
+ ev.mouse_button.global_x=mouse_x;
+ ev.mouse_button.global_y=mouse_y;
+ ev.mouse_button.button_mask=button_mask;
+ ev.mouse_button.mod = translateFlags([event modifierFlags]);
+ OS_OSX::singleton->push_input(ev);
+
+ /*_glfwInputMouseClick(window,
+ (int) [event buttonNumber],
+ GLFW_PRESS,
+ translateFlags([event modifierFlags]));*/
+}
+
+- (void)otherMouseDragged:(NSEvent *)event
+{
+ [self mouseMoved:event];
+}
+
+- (void)otherMouseUp:(NSEvent *)event
+{
+
+ if ((int) [event buttonNumber]!=2)
+ return;
+
+ button_mask&=~BUTTON_MASK_MIDDLE;
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.mouse_button.button_index=BUTTON_MIDDLE;
+ ev.mouse_button.pressed=false;
+ ev.mouse_button.x=mouse_x;
+ ev.mouse_button.y=mouse_y;
+ ev.mouse_button.global_x=mouse_x;
+ ev.mouse_button.global_y=mouse_y;
+ ev.mouse_button.button_mask=button_mask;
+ ev.mouse_button.mod = translateFlags([event modifierFlags]);
+ OS_OSX::singleton->push_input(ev);
+ /* _glfwInputMouseClick(window,
+ (int) [event buttonNumber],
+ GLFW_RELEASE,
+ translateFlags([event modifierFlags]));*/
+}
+
+- (void)mouseExited:(NSEvent *)event
+{
+ // _glfwInputCursorEnter(window, GL_FALSE);
+}
+
+- (void)mouseEntered:(NSEvent *)event
+{
+ // _glfwInputCursorEnter(window, GL_TRUE);
+}
+
+- (void)viewDidChangeBackingProperties
+{
+ /* const NSRect contentRect = [window->ns.view frame];
+ const NSRect fbRect = convertRectToBacking(window, contentRect);
+
+ _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);*/
+}
+
+- (void)updateTrackingAreas
+{
+ if (trackingArea != nil)
+ {
+ [self removeTrackingArea:trackingArea];
+ [trackingArea release];
+ }
+
+ NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInKeyWindow |
+ NSTrackingCursorUpdate |
+ NSTrackingInVisibleRect;
+
+ trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
+ options:options
+ owner:self
+ userInfo:nil];
+
+ [self addTrackingArea:trackingArea];
+ [super updateTrackingAreas];
+}
+
+// Translates a OS X keycode to a Godot keycode
+//
+static int translateKey(unsigned int key)
+{
+ // Keyboard symbol translation table
+ static const unsigned int table[128] =
+ {
+ /* 00 */ KEY_A,
+ /* 01 */ KEY_S,
+ /* 02 */ KEY_D,
+ /* 03 */ KEY_F,
+ /* 04 */ KEY_H,
+ /* 05 */ KEY_G,
+ /* 06 */ KEY_Z,
+ /* 07 */ KEY_X,
+ /* 08 */ KEY_C,
+ /* 09 */ KEY_V,
+ /* 0a */ KEY_UNKNOWN,
+ /* 0b */ KEY_B,
+ /* 0c */ KEY_Q,
+ /* 0d */ KEY_W,
+ /* 0e */ KEY_E,
+ /* 0f */ KEY_R,
+ /* 10 */ KEY_Y,
+ /* 11 */ KEY_T,
+ /* 12 */ KEY_1,
+ /* 13 */ KEY_2,
+ /* 14 */ KEY_3,
+ /* 15 */ KEY_4,
+ /* 16 */ KEY_6,
+ /* 17 */ KEY_5,
+ /* 18 */ KEY_EQUAL,
+ /* 19 */ KEY_9,
+ /* 1a */ KEY_7,
+ /* 1b */ KEY_MINUS,
+ /* 1c */ KEY_8,
+ /* 1d */ KEY_0,
+ /* 1e */ KEY_BRACERIGHT,
+ /* 1f */ KEY_O,
+ /* 20 */ KEY_U,
+ /* 21 */ KEY_BRACELEFT,
+ /* 22 */ KEY_I,
+ /* 23 */ KEY_P,
+ /* 24 */ KEY_RETURN,
+ /* 25 */ KEY_L,
+ /* 26 */ KEY_J,
+ /* 27 */ KEY_APOSTROPHE,
+ /* 28 */ KEY_K,
+ /* 29 */ KEY_SEMICOLON,
+ /* 2a */ KEY_BACKSLASH,
+ /* 2b */ KEY_COMMA,
+ /* 2c */ KEY_SLASH,
+ /* 2d */ KEY_N,
+ /* 2e */ KEY_M,
+ /* 2f */ KEY_PERIOD,
+ /* 30 */ KEY_TAB,
+ /* 31 */ KEY_SPACE,
+ /* 32 */ KEY_QUOTELEFT,
+ /* 33 */ KEY_BACKSPACE,
+ /* 34 */ KEY_UNKNOWN,
+ /* 35 */ KEY_ESCAPE,
+ /* 36 */ KEY_META,
+ /* 37 */ KEY_META,
+ /* 38 */ KEY_SHIFT,
+ /* 39 */ KEY_CAPSLOCK,
+ /* 3a */ KEY_ALT,
+ /* 3b */ KEY_CONTROL,
+ /* 3c */ KEY_SHIFT,
+ /* 3d */ KEY_ALT,
+ /* 3e */ KEY_CONTROL,
+ /* 3f */ KEY_UNKNOWN, /* Function */
+ /* 40 */ KEY_UNKNOWN,
+ /* 41 */ KEY_KP_PERIOD,
+ /* 42 */ KEY_UNKNOWN,
+ /* 43 */ KEY_KP_MULTIPLY,
+ /* 44 */ KEY_UNKNOWN,
+ /* 45 */ KEY_KP_ADD,
+ /* 46 */ KEY_UNKNOWN,
+ /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */
+ /* 48 */ KEY_UNKNOWN, /* VolumeUp */
+ /* 49 */ KEY_UNKNOWN, /* VolumeDown */
+ /* 4a */ KEY_UNKNOWN, /* Mute */
+ /* 4b */ KEY_KP_DIVIDE,
+ /* 4c */ KEY_KP_ENTER,
+ /* 4d */ KEY_UNKNOWN,
+ /* 4e */ KEY_KP_SUBSTRACT,
+ /* 4f */ KEY_UNKNOWN,
+ /* 50 */ KEY_UNKNOWN,
+ /* 51 */ KEY_EQUAL, //wtf equal?
+ /* 52 */ KEY_KP_0,
+ /* 53 */ KEY_KP_1,
+ /* 54 */ KEY_KP_2,
+ /* 55 */ KEY_KP_3,
+ /* 56 */ KEY_KP_4,
+ /* 57 */ KEY_KP_5,
+ /* 58 */ KEY_KP_6,
+ /* 59 */ KEY_KP_7,
+ /* 5a */ KEY_UNKNOWN,
+ /* 5b */ KEY_KP_8,
+ /* 5c */ KEY_KP_9,
+ /* 5d */ KEY_UNKNOWN,
+ /* 5e */ KEY_UNKNOWN,
+ /* 5f */ KEY_UNKNOWN,
+ /* 60 */ KEY_F5,
+ /* 61 */ KEY_F6,
+ /* 62 */ KEY_F7,
+ /* 63 */ KEY_F3,
+ /* 64 */ KEY_F8,
+ /* 65 */ KEY_F9,
+ /* 66 */ KEY_UNKNOWN,
+ /* 67 */ KEY_F11,
+ /* 68 */ KEY_UNKNOWN,
+ /* 69 */ KEY_F13,
+ /* 6a */ KEY_F16,
+ /* 6b */ KEY_F14,
+ /* 6c */ KEY_UNKNOWN,
+ /* 6d */ KEY_F10,
+ /* 6e */ KEY_UNKNOWN,
+ /* 6f */ KEY_F12,
+ /* 70 */ KEY_UNKNOWN,
+ /* 71 */ KEY_F15,
+ /* 72 */ KEY_INSERT, /* Really Help... */
+ /* 73 */ KEY_HOME,
+ /* 74 */ KEY_PAGEUP,
+ /* 75 */ KEY_DELETE,
+ /* 76 */ KEY_F4,
+ /* 77 */ KEY_END,
+ /* 78 */ KEY_F2,
+ /* 79 */ KEY_PAGEDOWN,
+ /* 7a */ KEY_F1,
+ /* 7b */ KEY_LEFT,
+ /* 7c */ KEY_RIGHT,
+ /* 7d */ KEY_DOWN,
+ /* 7e */ KEY_UP,
+ /* 7f */ KEY_UNKNOWN,
+ };
+
+ if (key >= 128)
+ return KEY_UNKNOWN;
+
+ return table[key];
+}
+- (void)keyDown:(NSEvent *)event
+{
+ InputEvent ev;
+ ev.type=InputEvent::KEY;
+ ev.key.pressed=true;
+ ev.key.mod=translateFlags([event modifierFlags]);
+ ev.key.scancode = translateKey([event keyCode]);
+ ev.key.echo = [event isARepeat];
+
+ NSString* characters = [event characters];
+ NSUInteger i, length = [characters length];
+
+
+ if (length>0 && keycode_has_unicode(ev.key.scancode)) {
+
+
+ for (i = 0; i < length; i++) {
+ ev.key.unicode=[characters characterAtIndex:i];
+ OS_OSX::singleton->push_input(ev);
+ ev.key.scancode=0;
+ }
+
+ } else {
+ OS_OSX::singleton->push_input(ev);
+ }
+}
+
+- (void)flagsChanged:(NSEvent *)event
+{
+ /* int action;
+ unsigned int newModifierFlags =
+ [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+
+ if (newModifierFlags > window->ns.modifierFlags)
+ action = GLFW_PRESS;
+ else
+ action = GLFW_RELEASE;
+
+ window->ns.modifierFlags = newModifierFlags;
+
+ const int key = translateKey([event keyCode]);
+ const int mods = translateFlags([event modifierFlags]);
+ _glfwInputKey(window, key, [event keyCode], action, mods);*/
+}
+
+- (void)keyUp:(NSEvent *)event
+{
+
+ InputEvent ev;
+ ev.type=InputEvent::KEY;
+ ev.key.pressed=false;
+ ev.key.mod=translateFlags([event modifierFlags]);
+ ev.key.scancode = translateKey([event keyCode]);
+ OS_OSX::singleton->push_input(ev);
+
+
+ /* const int key = translateKey([event keyCode]);
+ const int mods = translateFlags([event modifierFlags]);
+ _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods);*/
+}
+
+- (void)scrollWheel:(NSEvent *)event
+{
+
+ double deltaX, deltaY;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+ if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
+ {
+ deltaX = [event scrollingDeltaX];
+ deltaY = [event scrollingDeltaY];
+
+ if ([event hasPreciseScrollingDeltas])
+ {
+ deltaX *= 0.1;
+ deltaY *= 0.1;
+ }
+ }
+ else
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+ {
+ deltaX = [event deltaX];
+ deltaY = [event deltaY];
+ }
+
+
+ if (fabs(deltaY)) {
+
+ InputEvent ev;
+ ev.type=InputEvent::MOUSE_BUTTON;
+ ev.mouse_button.button_index=deltaY >0 ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN;
+ ev.mouse_button.pressed=true;
+ ev.mouse_button.x=mouse_x;
+ ev.mouse_button.y=mouse_y;
+ ev.mouse_button.global_x=mouse_x;
+ ev.mouse_button.global_y=mouse_y;
+ ev.mouse_button.button_mask=button_mask;
+ OS_OSX::singleton->push_input(ev);
+ ev.mouse_button.pressed=false;
+ OS_OSX::singleton->push_input(ev);
+ }
+
+}
+
+@end
+
+@interface GodotWindow : NSWindow {}
+@end
+
+@implementation GodotWindow
+
+- (BOOL)canBecomeKeyWindow
+{
+ // Required for NSBorderlessWindowMask windows
+ return YES;
+}
+
+@end
+
+
+int OS_OSX::get_video_driver_count() const {
+
+ return 1;
+}
+const char * OS_OSX::get_video_driver_name(int p_driver) const {
+
+ return "GLES2";
+}
+
+OS::VideoMode OS_OSX::get_default_video_mode() const {
+
+ VideoMode vm;
+ vm.width=800;
+ vm.height=600;
+ vm.fullscreen=false;
+ vm.resizable=true;
+ return vm;
+}
+
+
+void OS_OSX::initialize_core() {
+
+ OS_Unix::initialize_core();
+ SemaphoreOSX::make_default();
+
+}
+
+void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ /*** OSX INITIALIZATION ***/
+ /*** OSX INITIALIZATION ***/
+ /*** OSX INITIALIZATION ***/
+
+ current_videomode=p_desired;
+ window_delegate = [[GodotWindowDelegate alloc] init];
+
+ // Don't use accumulation buffer support; it's not accelerated
+ // Aux buffers probably aren't accelerated either
+
+ unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | (current_videomode.resizable?NSResizableWindowMask:0);
+
+
+ window_object = [[GodotWindow alloc]
+ initWithContentRect:NSMakeRect(0, 0, current_videomode.width,current_videomode.height)
+ styleMask:styleMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+
+ ERR_FAIL_COND( window_object==nil );
+
+ window_view = [[GodotContentView alloc] init];
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+ if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) {
+ [window_view setWantsBestResolutionOpenGLSurface:YES];
+ if (current_videomode.resizable)
+ [window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+ }
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+
+// [window_object setTitle:[NSString stringWithUTF8String:"GodotEnginies"]];
+ [window_object setContentView:window_view];
+ [window_object setDelegate:window_delegate];
+ [window_object setAcceptsMouseMovedEvents:YES];
+ [window_object center];
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+ if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
+ [window_object setRestorable:NO];
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+
+ unsigned int attributeCount = 0;
+
+ // OS X needs non-zero color size, so set resonable values
+ int colorBits = 24;
+
+ // Fail if a robustness strategy was requested
+
+
+#define ADD_ATTR(x) { attributes[attributeCount++] = x; }
+#define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); }
+
+ // Arbitrary array size here
+ NSOpenGLPixelFormatAttribute attributes[40];
+
+ ADD_ATTR(NSOpenGLPFADoubleBuffer);
+ ADD_ATTR(NSOpenGLPFAClosestPolicy);
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+ if (false/* use gl3*/)
+ ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+
+ ADD_ATTR2(NSOpenGLPFAColorSize, colorBits);
+
+ /* if (fbconfig->alphaBits > 0)
+ ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);*/
+
+ ADD_ATTR2(NSOpenGLPFADepthSize, 24);
+
+ ADD_ATTR2(NSOpenGLPFAStencilSize, 8);
+
+ /*if (fbconfig->stereo)
+ ADD_ATTR(NSOpenGLPFAStereo);*/
+
+ /* if (fbconfig->samples > 0)
+ {
+ ADD_ATTR2(NSOpenGLPFASampleBuffers, 1);
+ ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples);
+ }*/
+
+ // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
+ // frambuffer, so there's no need (and no way) to request it
+
+ ADD_ATTR(0);
+
+#undef ADD_ATTR
+#undef ADD_ATTR2
+
+ pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
+ ERR_FAIL_COND( pixelFormat == nil);
+
+
+ context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
+ shareContext:nil];
+
+ ERR_FAIL_COND(context==nil);
+
+
+ [context setView:window_view];
+
+ [context makeCurrentContext];
+
+ [NSApp activateIgnoringOtherApps:YES];
+
+ [window_object makeKeyAndOrderFront:nil];
+
+
+ /*** END OSX INITIALIZATION ***/
+ /*** END OSX INITIALIZATION ***/
+ /*** END OSX INITIALIZATION ***/
+
+ bool use_gl2=p_video_driver!=1;
+
+
+
+ AudioDriverManagerSW::add_driver(&audio_driver_osx);
+
+
+ rasterizer = instance_RasterizerGLES2();
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+
+ if (get_render_thread_mode()!=RENDER_THREAD_UNSAFE) {
+
+ visual_server =memnew(VisualServerWrapMT(visual_server,get_render_thread_mode()==RENDER_SEPARATE_THREAD));
+ }
+ visual_server->init();
+ visual_server->cursor_set_visible(false, 0);
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+
+ audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+ audio_server->init();
+
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+ _ensure_data_dir();
+
+
+}
+void OS_OSX::finalize() {
+
+}
+
+void OS_OSX::set_main_loop( MainLoop * p_main_loop ) {
+
+ main_loop=p_main_loop;
+ input->set_main_loop(p_main_loop);
+
+}
+
+void OS_OSX::delete_main_loop() {
+
+ memdelete(main_loop);
+ main_loop=NULL;
+}
+
+
+String OS_OSX::get_name() {
+
+ return "OSX";
+}
+
+void OS_OSX::set_cursor_shape(CursorShape p_shape) {
+
+ if (cursor_shape==p_shape)
+ return;
+
+ switch(p_shape) {
+ case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break;
+ case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break;
+ case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break;
+ case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break;
+ case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break;
+ case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break;
+ case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break;
+ case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break;
+ case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break;
+ case CURSOR_HELP: [[NSCursor arrowCursor] set]; break;
+ default: {};
+ }
+
+ cursor_shape=p_shape;
+}
+
+void OS_OSX::set_mouse_show(bool p_show) {
+
+}
+void OS_OSX::set_mouse_grab(bool p_grab) {
+
+}
+bool OS_OSX::is_mouse_grab_enabled() const {
+
+ return mouse_grab;
+}
+Point2 OS_OSX::get_mouse_pos() const {
+
+ return Vector2(mouse_x,mouse_y);
+}
+int OS_OSX::get_mouse_button_state() const {
+ return button_mask;
+}
+void OS_OSX::set_window_title(const String& p_title) {
+
+ [window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]];
+
+}
+
+void OS_OSX::set_icon(const Image& p_icon) {
+
+ Image img=p_icon;
+ img.convert(Image::FORMAT_RGBA);
+ NSBitmapImageRep *imgrep= [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL
+ pixelsWide: p_icon.get_width()
+ pixelsHigh: p_icon.get_height()
+ bitsPerSample: 8
+ samplesPerPixel: 4
+ hasAlpha: YES
+ isPlanar: NO
+ colorSpaceName: NSDeviceRGBColorSpace
+ bytesPerRow: p_icon.get_width()*4
+ bitsPerPixel: 32] autorelease];
+ ERR_FAIL_COND(imgrep==nil);
+ uint8_t *pixels = [imgrep bitmapData];
+
+ int len = img.get_width()*img.get_height();
+ DVector<uint8_t> data = img.get_data();
+ DVector<uint8_t>::Read r = data.read();
+
+ /* Premultiply the alpha channel */
+ for (int i = 0; i<len ; i++) {
+ uint8_t alpha = r[i*4+3];
+ pixels[i*4+0] = (uint8_t)(((uint16_t)r[i*4+0] * alpha) / 255);
+ pixels[i*4+1] = (uint8_t)(((uint16_t)r[i*4+1] * alpha) / 255);
+ pixels[i*4+2] = (uint8_t)(((uint16_t)r[i*4+2] * alpha) / 255);
+ pixels[i*4+3] = alpha;
+
+ }
+
+ NSImage *nsimg = [[[NSImage alloc] initWithSize: NSMakeSize(img.get_width(),img.get_height())] autorelease];
+ ERR_FAIL_COND(nsimg == nil);
+ [nsimg addRepresentation: imgrep];
+
+ [NSApp setApplicationIconImage:nsimg];
+
+}
+
+MainLoop *OS_OSX::get_main_loop() const {
+
+ return main_loop;
+}
+
+bool OS_OSX::can_draw() const {
+
+ return true;
+}
+
+void OS_OSX::set_clipboard(const String& p_text) {
+
+ NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil];
+
+ NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
+ [pasteboard declareTypes:types owner:nil];
+ [pasteboard setString:[NSString stringWithUTF8String:p_text.utf8().get_data()]
+ forType:NSStringPboardType];
+}
+String OS_OSX::get_clipboard() const {
+
+ NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
+
+ if (![[pasteboard types] containsObject:NSStringPboardType])
+ {
+ return "";
+ }
+
+ NSString* object = [pasteboard stringForType:NSStringPboardType];
+ if (!object)
+ {
+ return "";
+ }
+
+ char *utfs = strdup([object UTF8String]);
+ String ret;
+ ret.parse_utf8(utfs);
+ free(utfs);
+
+ return ret;
+}
+
+void OS_OSX::release_rendering_thread() {
+
+ [NSOpenGLContext clearCurrentContext];
+
+}
+void OS_OSX::make_rendering_thread() {
+
+ [context makeCurrentContext];
+
+}
+
+Error OS_OSX::shell_open(String p_uri) {
+
+ [[NSWorkspace sharedWorkspace] openURL:[[NSURL alloc] initWithString:[NSString stringWithUTF8String:p_uri.utf8().get_data()]]];
+ return OK;
+}
+
+void OS_OSX::swap_buffers() {
+
+ [context flushBuffer];
+
+}
+
+
+
+void OS_OSX::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+}
+
+OS::VideoMode OS_OSX::get_video_mode(int p_screen) const {
+
+ return current_videomode;
+}
+void OS_OSX::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+}
+
+void OS_OSX::move_window_to_foreground() {
+
+ [window_object orderFrontRegardless];
+}
+
+String OS_OSX::get_executable_path() const {
+
+ int ret;
+ pid_t pid;
+ char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
+
+ pid = getpid();
+ ret = proc_pidpath (pid, pathbuf, sizeof(pathbuf));
+ if ( ret <= 0 ) {
+ return OS::get_executable_path();
+ } else {
+ String path;
+ path.parse_utf8(pathbuf);
+
+ return path;
+ }
+
+}
+
+
+void OS_OSX::process_events() {
+
+ while (true) {
+ NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ if (event == nil)
+ break;
+
+ [NSApp sendEvent:event];
+ }
+
+ [autoreleasePool drain];
+ autoreleasePool = [[NSAutoreleasePool alloc] init];
+}
+
+
+
+void OS_OSX::push_input(const InputEvent& p_event) {
+
+ InputEvent ev=p_event;
+ ev.ID=last_id++;
+ //print_line("EV: "+String(ev));
+ input->parse_input_event(ev);
+}
+
+void OS_OSX::run() {
+
+ force_quit = false;
+
+ if (!main_loop)
+ return;
+
+ main_loop->init();
+
+// uint64_t last_ticks=get_ticks_usec();
+
+// int frames=0;
+// uint64_t frame=0;
+
+ while (!force_quit) {
+
+ process_events(); // get rid of pending events
+// process_joysticks();
+ if (Main::iteration()==true)
+ break;
+ };
+
+ main_loop->finish();
+}
+
+
+OS_OSX* OS_OSX::singleton=NULL;
+
+OS_OSX::OS_OSX() {
+
+ singleton=this;
+ autoreleasePool = [[NSAutoreleasePool alloc] init];
+
+ eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
+ ERR_FAIL_COND(!eventSource);
+
+ CGEventSourceSetLocalEventsSuppressionInterval(eventSource, 0.0);
+
+
+ /*if (pthread_key_create(&_Godot.nsgl.current, NULL) != 0)
+ {
+ _GodotInputError(Godot_PLATFORM_ERROR,
+ "NSGL: Failed to create context TLS");
+ return GL_FALSE;
+ }*/
+
+ framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
+ ERR_FAIL_COND(!framework);
+
+ // Implicitly create shared NSApplication instance
+ [GodotApplication sharedApplication];
+
+ // In case we are unbundled, make us a proper UI application
+ [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+
+ #if 0
+ // Menu bar setup must go between sharedApplication above and
+ // finishLaunching below, in order to properly emulate the behavior
+ // of NSApplicationMain
+ createMenuBar();
+ #endif
+
+ [NSApp finishLaunching];
+
+ delegate = [[GodotApplicationDelegate alloc] init];
+ ERR_FAIL_COND(!delegate);
+ [NSApp setDelegate:delegate];
+
+
+ last_id=1;
+ cursor_shape=CURSOR_ARROW;
+
+
+}
diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h
new file mode 100644
index 0000000000..da4265f3cf
--- /dev/null
+++ b/platform/osx/platform_config.h
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <alloca.h>
+#define GLES2_INCLUDE_H "gl_context/glew.h"
+#define GLES1_INCLUDE_H "gl_context/glew.h"
diff --git a/platform/osx/sem_osx.cpp b/platform/osx/sem_osx.cpp
new file mode 100644
index 0000000000..be70bedf84
--- /dev/null
+++ b/platform/osx/sem_osx.cpp
@@ -0,0 +1,115 @@
+/*************************************************************************/
+/* sem_osx.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "sem_osx.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+void cgsem_init(cgsem_t *cgsem)
+{
+ int flags, fd, i;
+
+ pipe(cgsem->pipefd);
+
+ /* Make the pipes FD_CLOEXEC to allow them to close should we call
+ * execv on restart. */
+ for (i = 0; i < 2; i++) {
+ fd = cgsem->pipefd[i];
+ flags = fcntl(fd, F_GETFD, 0);
+ flags |= FD_CLOEXEC;
+ fcntl(fd, F_SETFD, flags);
+ }
+}
+
+void cgsem_post(cgsem_t *cgsem)
+{
+ const char buf = 1;
+
+ write(cgsem->pipefd[1], &buf, 1);
+}
+
+void cgsem_wait(cgsem_t *cgsem)
+{
+ char buf;
+
+ read(cgsem->pipefd[0], &buf, 1);
+}
+
+void cgsem_destroy(cgsem_t *cgsem)
+{
+ close(cgsem->pipefd[1]);
+ close(cgsem->pipefd[0]);
+}
+
+
+#include "os/memory.h"
+#include <errno.h>
+
+
+Error SemaphoreOSX::wait() {
+
+ cgsem_wait(&sem);
+ return OK;
+}
+
+Error SemaphoreOSX::post() {
+
+ cgsem_post(&sem);
+
+ return OK;
+}
+int SemaphoreOSX::get() const {
+
+ return 0;
+}
+
+
+Semaphore *SemaphoreOSX::create_semaphore_osx() {
+
+ return memnew( SemaphoreOSX );
+}
+
+void SemaphoreOSX::make_default() {
+
+ create_func=create_semaphore_osx;
+}
+
+SemaphoreOSX::SemaphoreOSX() {
+
+ cgsem_init(&sem);
+}
+
+
+SemaphoreOSX::~SemaphoreOSX() {
+
+ cgsem_destroy(&sem);
+}
+
+
+
diff --git a/platform/osx/sem_osx.h b/platform/osx/sem_osx.h
new file mode 100644
index 0000000000..65bed7397f
--- /dev/null
+++ b/platform/osx/sem_osx.h
@@ -0,0 +1,60 @@
+/*************************************************************************/
+/* sem_osx.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef SEM_OSX_H
+#define SEM_OSX_H
+
+struct cgsem {
+ int pipefd[2];
+};
+
+typedef struct cgsem cgsem_t;
+
+#include "os/semaphore.h"
+
+class SemaphoreOSX : public Semaphore {
+
+ mutable cgsem_t sem;
+
+ static Semaphore *create_semaphore_osx();
+
+public:
+
+ virtual Error wait();
+ virtual Error post();
+ virtual int get() const;
+
+ static void make_default();
+ SemaphoreOSX();
+
+ ~SemaphoreOSX();
+
+};
+
+
+#endif
diff --git a/platform/server/SCsub b/platform/server/SCsub
new file mode 100644
index 0000000000..3dda6b4395
--- /dev/null
+++ b/platform/server/SCsub
@@ -0,0 +1,8 @@
+Import('env')
+
+
+common_server=[\
+ "os_server.cpp",\
+]
+
+env.Program('#bin/godot_server',['godot_server.cpp']+common_server)
diff --git a/platform/server/detect.py b/platform/server/detect.py
new file mode 100644
index 0000000000..1ce8c23229
--- /dev/null
+++ b/platform/server/detect.py
@@ -0,0 +1,91 @@
+
+import os
+import sys
+
+
+def is_active():
+ return True
+
+def get_name():
+ return "Server"
+
+
+def can_build():
+
+ if (os.name!="posix"):
+ return False
+
+ return True # enabled
+
+def get_opts():
+
+ return [
+ ('use_llvm','Use llvm compiler','no'),
+ ('force_32_bits','Force 32 bits binary','no')
+ ]
+
+def get_flags():
+
+ return [
+ ('builtin_zlib', 'no'),
+ ]
+
+
+
+def configure(env):
+
+ env.Append(CPPPATH=['#platform/server'])
+ if (env["use_llvm"]=="yes"):
+ env["CC"]="clang"
+ env["CXX"]="clang++"
+ env["LD"]="clang++"
+
+ env['OBJSUFFIX'] = ".srv"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".srv"+env['LIBSUFFIX']
+
+ if (env["force_32_bits"]!="no"):
+ env['OBJSUFFIX'] = ".32"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".32"+env['LIBSUFFIX']
+
+
+ if (env["tools"]=="no"):
+ #no tools suffix
+ env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
+
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O2','-ffast-math','-fomit-frame-pointer'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="release_debug"):
+
+ env.Append(CCFLAGS=['-O2','-ffast-math','-DDEBUG_ENABLED'])
+ env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
+
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-g2', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-g','-pg'])
+ env.Append(LINKFLAGS=['-pg'])
+
+
+ env.Append(CPPFLAGS=['-DSERVER_ENABLED','-DUNIX_ENABLED'])
+ env.Append(LIBS=['pthread','z']) #TODO detect linux/BSD!
+
+ if (env["force_32_bits"]=="yes"):
+ env.Append(CPPFLAGS=['-m32'])
+ env.Append(LINKFLAGS=['-m32','-L/usr/lib/i386-linux-gnu'])
+
+ if (env["CXX"]=="clang++"):
+ env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
+ env["CC"]="clang"
+ env["LD"]="clang++"
+
diff --git a/platform/server/godot_server.cpp b/platform/server/godot_server.cpp
new file mode 100644
index 0000000000..3f817c7237
--- /dev/null
+++ b/platform/server/godot_server.cpp
@@ -0,0 +1,45 @@
+/*************************************************************************/
+/* godot_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "main/main.h"
+#include "os_server.h"
+
+int main(int argc, char* argv[]) {
+
+ OS_Server os;
+
+ Error err = Main::setup(argv[0],argc-1,&argv[1]);
+ if (err!=OK)
+ return 255;
+
+ if (Main::start())
+ os.run(); // it is actually the OS that decides how to run
+ Main::cleanup();
+
+ return os.get_exit_code();
+}
diff --git a/platform/server/logo.h b/platform/server/logo.h
new file mode 100644
index 0000000000..bb383145f5
--- /dev/null
+++ b/platform/server/logo.h
@@ -0,0 +1,2 @@
+ /* AUTOGENERATED FILE, DO NOT EDIT */
+ static const unsigned char _server_logo[]={0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0x73,0x7a,0x7a,0xf4,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x12,0x0,0x0,0xb,0x12,0x1,0xd2,0xdd,0x7e,0xfc,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdd,0x9,0x8,0x10,0x20,0x27,0x86,0x78,0xdd,0x76,0x0,0x0,0x7,0xff,0x49,0x44,0x41,0x54,0x58,0xc3,0xe5,0x97,0x5b,0x6c,0x5c,0xc5,0x19,0xc7,0x7f,0x67,0xe6,0xac,0xf7,0x7e,0xb1,0xbd,0x4e,0x7c,0x49,0xe2,0x24,0xb6,0x43,0x1c,0xc,0xa6,0x20,0x94,0x4,0xda,0x26,0x5,0x51,0x28,0xb4,0x5c,0x2a,0x55,0x50,0xb5,0x85,0xa6,0xea,0x13,0x8,0xa9,0xa5,0x2f,0x54,0xaa,0x8a,0xd4,0xdb,0x4b,0xdb,0x27,0xaa,0x88,0x16,0x1a,0x50,0x8a,0x84,0xd4,0xf6,0xa1,0x2,0x24,0x6e,0x89,0x80,0x8,0x8,0x71,0x2e,0x26,0xc1,0x71,0x12,0x27,0xbe,0x67,0xd7,0xb7,0xf5,0xae,0xd7,0xf6,0xee,0xd9,0x3d,0x7b,0x66,0xa6,0xf,0x6b,0x8c,0x93,0x42,0xc,0x42,0xed,0x4b,0x47,0x1a,0x9d,0xf3,0x30,0x33,0xdf,0xff,0xfb,0x7f,0xff,0x6f,0xe6,0xfb,0xe0,0xff,0x7d,0x58,0x9f,0x77,0xc3,0xbd,0xf7,0xdd,0xdf,0xf4,0xd8,0x63,0x8f,0xee,0xac,0xab,0xab,0xbb,0x49,0x79,0xaa,0xa1,0xe2,0x55,0xd2,0xe5,0x72,0x39,0x35,0x3f,0x3f,0x9f,0x4e,0xa5,0xd2,0xa9,0x43,0xef,0xbe,0x97,0xda,0xbf,0xef,0xe9,0x14,0x60,0xbe,0x30,0x80,0xef,0x3d,0xb8,0x67,0xdd,0xf,0x1f,0xfa,0xc1,0x8e,0x86,0x86,0xe4,0xce,0x40,0x4d,0xe0,0x26,0x21,0xe5,0x8e,0x78,0x3c,0x4a,0xc5,0xad,0x50,0x2a,0x97,0x50,0x9e,0x42,0x6b,0x85,0xa7,0x14,0x46,0x6b,0xb4,0xd6,0xb8,0xae,0xcb,0xc2,0xc2,0x22,0x8b,0x8b,0x8b,0xb8,0xae,0x9b,0xf1,0x94,0x97,0x5a,0x58,0x28,0xa4,0xa,0x85,0xe2,0xd3,0x3f,0xfd,0xc9,0xa3,0xff,0xba,0xdc,0x86,0xfd,0xd1,0xcf,0x9f,0xf6,0x3e,0x15,0xa,0x6,0x2,0x77,0x77,0x77,0x77,0x6f,0xf7,0x7,0xfc,0x3b,0x7d,0xb6,0xbd,0xbd,0xb6,0xb6,0x16,0x30,0x68,0x6d,0xd0,0xc6,0xa0,0x95,0xc2,0x71,0x1c,0x94,0x52,0x68,0xa5,0x51,0x5a,0xa1,0x95,0x42,0x79,0xa,0xa5,0x3c,0x5c,0xd7,0xc5,0xf3,0x3c,0x2a,0x95,0xa,0x42,0xa,0x4a,0x65,0x37,0xd9,0x73,0xa4,0x27,0xd9,0x77,0xfa,0x74,0x77,0x3a,0x95,0x7e,0xe5,0x93,0x9c,0x5c,0x6,0xb0,0x7e,0x5d,0x73,0x2c,0x3f,0x57,0x78,0x61,0x72,0x62,0x8a,0xc6,0xa6,0x35,0x84,0x6a,0x13,0xb8,0x6e,0x19,0xad,0x34,0x58,0x16,0x9e,0xe7,0xe1,0xb3,0xab,0xcb,0x8d,0x31,0x68,0xa3,0xd1,0x4a,0x61,0x8c,0x1,0xc,0x13,0x93,0x53,0x4c,0x4f,0xcf,0x30,0x3a,0x3a,0xc6,0xc9,0x93,0xbd,0x7c,0xd0,0xdb,0xcb,0xc8,0xc8,0x30,0xc1,0x60,0x98,0x58,0x2c,0x4e,0x20,0x10,0xf2,0xad,0x1a,0x82,0x7,0xee,0xff,0xb1,0x9,0x5,0x23,0x18,0xa3,0xb1,0x6d,0x1b,0x7f,0xc0,0x47,0x34,0x16,0x21,0x14,0xc,0x10,0x89,0x86,0xf0,0xf9,0x6c,0x42,0xe1,0x0,0xc1,0x80,0x9f,0xba,0xba,0x3a,0x36,0xb4,0x6e,0xe0,0xf8,0xb1,0x13,0xbc,0xfe,0xc6,0x1b,0xc,0x9c,0x3b,0xc7,0xc0,0xc0,0x59,0xb2,0xd9,0xec,0xf2,0x79,0x42,0x48,0x62,0xd1,0x18,0x9d,0x9d,0xd7,0x21,0xa5,0xec,0x7c,0xe7,0xdd,0x3,0x67,0x3f,0x95,0x1,0x0,0xaf,0xe2,0x22,0x22,0x2,0xa3,0x2d,0x94,0x56,0x14,0xa,0x1e,0x8b,0x5,0x7,0x8c,0xa9,0x7a,0xad,0xf5,0x92,0xc7,0x10,0xa,0x7,0x19,0x1f,0x1b,0xe0,0x95,0x57,0x5f,0xfe,0x44,0xfd,0xb4,0xb4,0xb4,0xd2,0xde,0xb6,0x15,0x21,0x24,0xd3,0xd3,0x13,0xb8,0x95,0xf2,0x5d,0xc0,0x95,0x1,0x54,0xbc,0x45,0x66,0x67,0xb,0xd8,0xb6,0xf,0x29,0x6d,0x22,0x91,0x38,0xb9,0xec,0x3c,0xe1,0x48,0xc,0xcb,0x18,0x8c,0x56,0x60,0x9,0x8c,0x31,0xa8,0x8a,0x62,0x72,0x72,0xea,0x92,0xc3,0xe2,0xf1,0x5a,0xb6,0x75,0x5e,0x83,0x14,0x92,0x91,0xf1,0x21,0x8e,0x1c,0x39,0x44,0x24,0x1a,0x23,0x91,0xa8,0x27,0xe0,0xf,0x9c,0xb8,0xa2,0x6,0x0,0x84,0xc,0x13,0x9,0x47,0x11,0x42,0x60,0xdb,0x92,0x52,0xa9,0x48,0xd1,0x99,0x67,0x2e,0x3f,0x43,0x7c,0xcb,0x97,0xd8,0x75,0xff,0xb7,0xc9,0x8c,0x5c,0xe4,0xec,0xb1,0x51,0xca,0xa5,0x1c,0x0,0x3e,0x9f,0x9f,0xab,0xb6,0x74,0x92,0x48,0x24,0xc8,0x64,0xa6,0x39,0xfc,0xfe,0xa1,0x6a,0x6c,0x2d,0x68,0x6d,0xed,0x60,0xe3,0xc6,0x76,0xa4,0x94,0xcc,0xcc,0x4c,0x25,0x57,0x5,0x30,0x9b,0x49,0x61,0x99,0xb5,0xd8,0x76,0x0,0x69,0xfb,0x10,0x96,0x20,0x1e,0x5f,0x3,0x18,0x4c,0x66,0x92,0x43,0x7b,0x9f,0x42,0xd6,0xaf,0xa5,0x36,0xba,0x16,0xaf,0xe5,0x5a,0x16,0x7,0x7,0x68,0x6b,0x2b,0x30,0x38,0x74,0xe,0xc7,0x71,0x0,0x90,0xd2,0xa6,0xbd,0xed,0x2a,0xea,0xeb,0x1b,0x98,0xcd,0x66,0x18,0x18,0x38,0x4d,0x34,0x1a,0x27,0x18,0xc,0x35,0xac,0xa,0xa0,0xa5,0x65,0x23,0xa0,0x11,0xd2,0x60,0x4b,0x8f,0xe1,0xe1,0x61,0xca,0x65,0x97,0x44,0xa2,0x9e,0x70,0x20,0x84,0x52,0x60,0xb9,0xa3,0x64,0xa7,0xc7,0xf1,0x7,0xfa,0x89,0xe6,0x7,0x39,0x71,0xb6,0x1f,0x80,0x70,0x38,0x4a,0x67,0x67,0x17,0x15,0xd7,0xe5,0xc2,0xe0,0x39,0x46,0xc7,0x86,0x8,0x87,0xa3,0x34,0xae,0x6d,0xa1,0xb9,0x79,0x3d,0xc5,0x52,0xf1,0xf0,0x6a,0x0,0x44,0xa1,0x50,0x24,0x10,0x8,0xe1,0x55,0x34,0x65,0x14,0xcd,0xcd,0x6d,0x48,0x29,0x28,0x14,0xe6,0x11,0xeb,0xb7,0xb0,0xeb,0xfb,0xf,0x30,0xb5,0xe0,0x31,0xfb,0xc1,0xc,0x73,0x73,0x13,0x94,0x2e,0xc,0xd1,0xd8,0xd8,0x4c,0x53,0x53,0xb,0xf3,0xf3,0x39,0x8e,0x1d,0x3b,0xbc,0x44,0xbf,0xc5,0xc6,0x8d,0x1d,0x34,0x35,0xb6,0xe0,0x38,0xe,0x93,0x53,0x69,0xc2,0xa1,0xc8,0xd7,0x80,0xde,0x2b,0x1,0xd0,0xc5,0x62,0x96,0x72,0x39,0x4f,0x30,0x18,0xc1,0x68,0xb,0x63,0x34,0x95,0x8a,0xc0,0xb2,0x6c,0xbc,0xf1,0xb,0x1c,0xfc,0xd5,0x13,0x68,0xe5,0xe1,0x8a,0x20,0xb5,0xeb,0xdb,0xa9,0xa9,0xa9,0xc1,0x71,0xa,0xf4,0xf6,0x1e,0x5d,0xce,0xea,0xd6,0xd6,0x4d,0xd4,0xd7,0x25,0xc9,0xe6,0x66,0x19,0x1e,0xb9,0x40,0x2c,0x9a,0xa0,0xa1,0xa1,0x11,0x9f,0xcf,0x3e,0xb8,0x1a,0x3,0xd2,0xb6,0xc3,0x24,0xe2,0x75,0x28,0x5d,0xc1,0x71,0x16,0x99,0x18,0xbf,0x88,0xb4,0x25,0x16,0x16,0xf1,0x96,0xcd,0x24,0x1a,0x1a,0xc8,0x8f,0x8e,0x52,0x23,0x1c,0x54,0x66,0x8,0x51,0x98,0x21,0x9f,0xcf,0x63,0x59,0x82,0xcd,0x9b,0xdb,0xf1,0xfb,0xfd,0x8c,0x8d,0x8d,0x30,0x35,0x99,0x26,0x12,0x8d,0xd3,0xd4,0xb4,0x8e,0x48,0x38,0x86,0x52,0x1e,0x42,0x88,0x5b,0x80,0x93,0x57,0x2,0xa0,0x8a,0xc5,0x79,0xa4,0x10,0x8,0xe9,0x43,0x4a,0x3f,0x6b,0xd6,0xac,0xc3,0xb2,0x2c,0x7c,0x3e,0x1f,0x4,0x42,0x6c,0xfe,0xea,0x2e,0x8a,0x75,0xad,0xa4,0x3f,0x2c,0x61,0x6a,0x34,0x3a,0xff,0x24,0x6d,0x9b,0xb3,0x60,0x59,0x8c,0x8d,0xd,0x57,0xaf,0x60,0x21,0x68,0xdd,0xd0,0x46,0x6d,0x6d,0x1d,0x45,0xa7,0x48,0xa1,0xb0,0x40,0x24,0x12,0xc3,0xf6,0xf9,0xd4,0xaa,0x22,0x8c,0x44,0x63,0xf8,0xfd,0x12,0x4b,0x68,0xfa,0x4f,0xf7,0x13,0x8,0x4,0xa9,0xab,0x4d,0x12,0x8,0x46,0xd0,0xc5,0x49,0x8e,0x3f,0xbf,0x1f,0xb4,0x46,0x6b,0xf,0x19,0x8,0xe3,0x65,0xd3,0xc,0xe,0x5d,0x58,0xde,0xdf,0xd4,0xd4,0x42,0x22,0x51,0xcb,0xdc,0xdc,0x1c,0x93,0x93,0x13,0x44,0xa3,0xb1,0xe5,0x3b,0xc5,0x96,0x36,0xab,0x8a,0xd0,0x29,0x96,0xd1,0xda,0x2,0x3,0x1d,0x5b,0xba,0x50,0x5e,0x85,0xc5,0xc5,0x79,0xe6,0x17,0x32,0x24,0xb6,0x6d,0x67,0xd7,0xdd,0xdf,0xa0,0xb7,0xa7,0x97,0xf4,0xf1,0x53,0xf8,0xdc,0xc,0x7e,0x5c,0x0,0x92,0xc9,0x6,0x62,0xb1,0x38,0x53,0x53,0x93,0x64,0xb3,0x59,0xa2,0x91,0x28,0xe1,0x70,0x14,0x69,0xdb,0x48,0xdb,0xc6,0x5e,0xfa,0xae,0xca,0x80,0x36,0xd5,0x67,0xd5,0x0,0x8e,0xe3,0x70,0xfe,0xc2,0x19,0x9c,0xe2,0x22,0xd7,0x74,0x5d,0x4f,0xf1,0xec,0x49,0x5e,0x1e,0x3b,0x4f,0xb2,0x7d,0x1b,0xf5,0x5b,0x77,0x53,0x5a,0xd3,0x4e,0xf1,0xc0,0x5f,0x68,0x6e,0x4e,0x91,0xcb,0xe5,0xc8,0x64,0x66,0x10,0x42,0x10,0xe,0x45,0x96,0xd,0x7f,0xe4,0xf9,0x67,0x65,0x0,0xad,0x34,0x5a,0x2b,0xb4,0x31,0x60,0xe0,0x3b,0xb7,0xda,0x68,0x13,0xa1,0x67,0xa0,0x82,0x6d,0x4b,0x28,0x16,0xc9,0x9c,0x3a,0xa,0xa6,0x87,0x80,0xdf,0x47,0x68,0x66,0x8a,0x33,0xe9,0xf4,0x25,0x8f,0xcf,0x4a,0xc3,0xb6,0x5c,0xc1,0x80,0x94,0xd6,0x65,0x8f,0x9f,0x1,0x10,0x97,0x0,0xd0,0x1a,0xa5,0x34,0x46,0x6b,0xdc,0x4a,0x99,0x2d,0xdb,0x1f,0xe3,0xce,0xef,0x3e,0x49,0x3a,0x35,0x8a,0xf6,0x14,0xda,0xa8,0xea,0x1a,0xa3,0xf1,0xb4,0x5,0x42,0x5c,0xea,0x4d,0xd5,0xd0,0xb2,0x61,0x69,0x7f,0xcc,0xc0,0x12,0x80,0x2b,0x33,0x50,0x2d,0x30,0x3c,0x34,0x90,0x4e,0x5f,0x64,0xcf,0x9e,0x3d,0x48,0x29,0x70,0x4a,0xb,0x28,0xad,0x30,0x1f,0x55,0x59,0xc6,0xa0,0xf5,0xa5,0xa2,0xb6,0x2c,0x81,0x6d,0xaf,0xf0,0x7a,0x25,0xfd,0xb6,0x4d,0xa5,0x52,0x9,0x3,0x21,0xa0,0x4,0xe8,0x65,0xd6,0x56,0x1e,0x62,0xb4,0x46,0x69,0x8d,0xe3,0xb8,0x1c,0x7e,0xc6,0xe5,0xbd,0x37,0xf7,0x57,0xaf,0xe8,0xa4,0xc2,0x75,0x4b,0x4b,0xc,0x29,0x94,0xae,0xce,0x95,0x8c,0x4a,0x29,0x90,0xd2,0x46,0xac,0xa0,0x5e,0x2e,0x31,0x12,0xc,0x45,0x48,0xd4,0xd7,0x45,0x81,0x75,0x40,0x1c,0xa8,0x59,0xda,0x6c,0x89,0xff,0x64,0x40,0x61,0x61,0xf8,0xe7,0xeb,0x1e,0xe1,0xdc,0x9f,0xf9,0xdd,0x6f,0x7e,0x4b,0xcf,0xb,0x16,0xdd,0x1d,0xe5,0x6a,0x29,0xa6,0x15,0x4a,0xe9,0x6a,0xa5,0xb4,0xf2,0x16,0x5b,0xe1,0xed,0x32,0xf5,0x42,0xb2,0xb5,0xab,0x9b,0x1b,0x77,0x5c,0xeb,0xbc,0xfd,0xe6,0x4b,0x47,0x81,0x24,0xd0,0xb8,0x4,0x42,0x0,0x66,0x39,0x4,0xc9,0xc6,0x66,0xa2,0x91,0x38,0xb,0x8b,0x79,0x84,0x25,0x78,0xe6,0xb5,0xf5,0xec,0x7d,0xa9,0x82,0x52,0xff,0x20,0x73,0x5a,0x70,0xf4,0xc,0xd8,0xbe,0xa5,0x12,0xec,0xb2,0x10,0x58,0x96,0x55,0xcd,0x77,0xbb,0x1a,0x7f,0xb,0x8b,0xe6,0xd,0x6d,0x6c,0xdf,0x71,0x3,0x5e,0x29,0x8f,0xf1,0xdc,0xe0,0x97,0xbf,0xb2,0xeb,0x9a,0xd1,0xd1,0xbf,0x4d,0x2,0x8b,0x40,0xe,0x50,0x97,0x68,0x20,0x33,0x99,0xd6,0x37,0xff,0xe8,0x67,0x0,0x5c,0x4c,0x8d,0x30,0x35,0x95,0x26,0x37,0x37,0x8b,0x5b,0xb6,0x78,0xeb,0x5c,0x2b,0x96,0x71,0x97,0x6a,0x40,0x30,0x18,0x94,0x56,0xcb,0x1,0x90,0x52,0x56,0xa7,0x25,0x88,0x26,0x92,0xdc,0x7a,0xdb,0xed,0xd4,0xc5,0x7c,0x68,0x77,0x81,0x1a,0x7f,0x70,0xe6,0xc5,0x97,0x5e,0xfc,0xf5,0xa1,0xb7,0xdf,0x3a,0x8,0x8c,0x0,0xc5,0x4f,0x15,0x61,0x47,0xe7,0x9a,0xbd,0xd3,0x53,0x33,0xf,0xd7,0x25,0xb7,0x32,0x3e,0x16,0x63,0x64,0x78,0x14,0xaf,0x54,0x60,0xe6,0x86,0x6f,0xe2,0x8,0x3f,0x35,0x83,0xef,0x13,0x9f,0x1d,0x41,0xb9,0x15,0xe6,0x17,0x16,0xb0,0xac,0x8f,0xd3,0xcf,0xf6,0xd5,0x70,0xf3,0xee,0x3b,0xd8,0xb6,0x75,0x13,0xaa,0x52,0xc2,0xf6,0x85,0x38,0x3f,0x70,0x7e,0xdf,0xbe,0x7d,0x4f,0xef,0x95,0x52,0xe,0x2,0x73,0xab,0x66,0x81,0x2d,0x7c,0xf,0xc7,0x63,0x31,0x2e,0x5e,0x1c,0xa7,0xb1,0x39,0x4e,0xe7,0xb6,0x5d,0xcc,0x66,0x73,0x4c,0x5c,0xec,0xe3,0xe4,0xd1,0x1e,0x46,0x88,0xd3,0xb1,0xa5,0x99,0x5b,0x77,0xef,0xe4,0x54,0xdf,0x0,0xef,0xbc,0xfd,0x16,0x0,0x5b,0xbb,0x6e,0xe4,0xb6,0xdb,0x6e,0x41,0xb9,0xb,0x8,0xcb,0xe0,0x54,0x54,0xcf,0x1f,0xff,0xf0,0xfb,0x5f,0x66,0x32,0x33,0xc7,0x81,0x8c,0x52,0xea,0x33,0x37,0x26,0xfe,0x67,0x9f,0xdb,0x7f,0xdf,0xa6,0xcd,0x9b,0xee,0x9,0xf8,0xfd,0x77,0xcd,0xe5,0xe6,0xa2,0x7d,0x7d,0x1f,0x92,0x4a,0xa7,0x88,0x44,0x22,0xa8,0x8a,0x22,0x9b,0x9b,0xe3,0xd4,0xa9,0x93,0x9c,0x39,0xd3,0xcf,0xd5,0x57,0x5f,0x4f,0xc7,0xb6,0x2e,0x82,0x76,0x85,0x40,0x20,0x40,0x38,0x1c,0xcd,0xf7,0xf4,0x1c,0xf9,0xc5,0x6b,0xaf,0xbd,0xf2,0xf7,0x3b,0xba,0x98,0x7e,0xb5,0xef,0xb,0x76,0x46,0xf,0x3e,0xb4,0x67,0xeb,0x1d,0xb7,0xdf,0x7e,0xaf,0xcf,0xe7,0xfb,0x96,0xe3,0x38,0x37,0xe5,0x72,0x59,0x86,0x86,0x87,0x28,0x97,0xca,0xb4,0x77,0xb4,0x23,0x2c,0x41,0x7f,0x7f,0x3f,0x6b,0xd7,0x36,0x91,0x4a,0xa5,0x9e,0x7d,0xee,0xb9,0xbf,0x3e,0x51,0x5b,0x5b,0x9b,0xca,0xe5,0x72,0xfa,0xbf,0xd1,0x1b,0x5a,0x8f,0x3f,0xfe,0xf3,0xaf,0xd7,0xd7,0x27,0xef,0xf1,0xfb,0xfd,0x77,0x5e,0x77,0x5d,0x77,0x6b,0x3e,0x9f,0xe7,0xe0,0xc1,0x37,0x8f,0x1f,0x38,0xf0,0xfa,0xc3,0x7d,0x7d,0x1f,0x9e,0x0,0xbc,0xff,0x49,0x47,0x2b,0xa5,0xc4,0xb2,0xec,0xc6,0x47,0x1e,0x79,0x74,0xf7,0xe5,0x3a,0xfa,0xbc,0xe3,0xdf,0x37,0xe9,0xbc,0x82,0x8a,0x4b,0xde,0x1,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82};
diff --git a/platform/server/logo.png b/platform/server/logo.png
new file mode 100644
index 0000000000..6b7490097f
--- /dev/null
+++ b/platform/server/logo.png
Binary files differ
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
new file mode 100644
index 0000000000..7bc8f61744
--- /dev/null
+++ b/platform/server/os_server.cpp
@@ -0,0 +1,236 @@
+/*************************************************************************/
+/* os_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "servers/visual/visual_server_raster.h"
+#include "servers/visual/rasterizer_dummy.h"
+#include "os_server.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "print_string.h"
+#include "servers/physics/physics_server_sw.h"
+
+#include "main/main.h"
+
+#include <unistd.h>
+
+int OS_Server::get_video_driver_count() const {
+
+ return 1;
+}
+const char * OS_Server::get_video_driver_name(int p_driver) const {
+
+ return "Dummy";
+}
+OS::VideoMode OS_Server::get_default_video_mode() const {
+
+ return OS::VideoMode(800,600,false);
+}
+
+void OS_Server::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ args=OS::get_singleton()->get_cmdline_args();
+ current_videomode=p_desired;
+ main_loop=NULL;
+
+
+ rasterizer = memnew( RasterizerDummy );
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+ audio_server->init();
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+
+ ERR_FAIL_COND(!visual_server);
+
+ visual_server->init();
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+ _ensure_data_dir();
+
+
+}
+void OS_Server::finalize() {
+
+ if(main_loop)
+ memdelete(main_loop);
+ main_loop=NULL;
+
+ spatial_sound_server->finish();
+ memdelete(spatial_sound_server);
+ spatial_sound_2d_server->finish();
+ memdelete(spatial_sound_2d_server);
+
+ //if (debugger_connection_console) {
+// memdelete(debugger_connection_console);
+//}
+
+ audio_server->finish();
+ memdelete(audio_server);
+ memdelete(sample_manager);
+
+ visual_server->finish();
+ memdelete(visual_server);
+ memdelete(rasterizer);
+
+ physics_server->finish();
+ memdelete(physics_server);
+
+ physics_2d_server->finish();
+ memdelete(physics_2d_server);
+
+ memdelete(input);
+
+ args.clear();
+}
+
+void OS_Server::set_mouse_show(bool p_show) {
+
+
+}
+void OS_Server::set_mouse_grab(bool p_grab) {
+
+ grab=p_grab;
+}
+bool OS_Server::is_mouse_grab_enabled() const {
+
+ return grab;
+}
+
+int OS_Server::get_mouse_button_state() const {
+
+ return 0;
+}
+
+Point2 OS_Server::get_mouse_pos() const {
+
+ return Point2();
+}
+
+void OS_Server::set_window_title(const String& p_title) {
+
+
+}
+
+void OS_Server::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+
+}
+OS::VideoMode OS_Server::get_video_mode(int p_screen) const {
+
+ return current_videomode;
+}
+void OS_Server::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+
+}
+
+
+MainLoop *OS_Server::get_main_loop() const {
+
+ return main_loop;
+}
+
+void OS_Server::delete_main_loop() {
+
+ if (main_loop)
+ memdelete(main_loop);
+ main_loop=NULL;
+}
+
+void OS_Server::set_main_loop( MainLoop * p_main_loop ) {
+
+ main_loop=p_main_loop;
+ input->set_main_loop(p_main_loop);
+}
+
+bool OS_Server::can_draw() const {
+
+ return false; //can never draw
+};
+
+
+String OS_Server::get_name() {
+
+ return "Server";
+}
+
+
+
+void OS_Server::move_window_to_foreground() {
+
+}
+
+void OS_Server::set_cursor_shape(CursorShape p_shape) {
+
+
+}
+
+void OS_Server::run() {
+
+ force_quit = false;
+
+ if (!main_loop)
+ return;
+
+ main_loop->init();
+
+ while (!force_quit) {
+
+ if (Main::iteration()==true)
+ break;
+ };
+
+ main_loop->finish();
+}
+
+OS_Server::OS_Server() {
+
+ AudioDriverManagerSW::add_driver(&driver_dummy);
+ //adriver here
+ grab=false;
+
+};
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
new file mode 100644
index 0000000000..fcf96253ad
--- /dev/null
+++ b/platform/server/os_server.h
@@ -0,0 +1,119 @@
+/*************************************************************************/
+/* os_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef OS_SERVER_H
+#define OS_SERVER_H
+
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+#include "servers/visual_server.h"
+#include "servers/visual/rasterizer.h"
+#include "servers/audio/audio_driver_dummy.h"
+#include "servers/physics_server.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/audio/sample_manager_sw.h"
+#include "servers/spatial_sound/spatial_sound_server_sw.h"
+#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "drivers/rtaudio/audio_driver_rtaudio.h"
+#include "servers/physics_2d/physics_2d_server_sw.h"
+
+//bitch
+#undef CursorShape
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+class OS_Server : public OS_Unix {
+
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+ VideoMode current_videomode;
+ List<String> args;
+ MainLoop *main_loop;
+
+ AudioDriverDummy driver_dummy;
+ bool grab;
+
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+
+ virtual void delete_main_loop();
+ IP_Unix *ip_unix;
+
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+
+ bool force_quit;
+
+ InputDefault *input;
+
+
+
+protected:
+
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+ virtual void finalize();
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+
+public:
+
+ virtual String get_name();
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ virtual void set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ virtual VideoMode get_video_mode(int p_screen=0) const;
+ virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;
+
+ virtual void move_window_to_foreground();
+
+ void run();
+
+ OS_Server();
+};
+
+#endif
diff --git a/platform/server/platform_config.h b/platform/server/platform_config.h
new file mode 100644
index 0000000000..1bb5afb002
--- /dev/null
+++ b/platform/server/platform_config.h
@@ -0,0 +1,30 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <alloca.h>
+
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
new file mode 100644
index 0000000000..1d454e40c2
--- /dev/null
+++ b/platform/windows/SCsub
@@ -0,0 +1,13 @@
+Import('env')
+
+
+common_win=[
+ "context_gl_win.cpp",
+ "os_windows.cpp",
+ "ctxgl_procaddr.cpp",
+ "key_mapping_win.cpp",
+ "tcp_server_winsock.cpp",
+ "stream_peer_winsock.cpp",
+]
+
+env.Program('#bin/godot.exe',['godot_win.cpp']+common_win)
diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp
new file mode 100644
index 0000000000..a8f74fde2c
--- /dev/null
+++ b/platform/windows/context_gl_win.cpp
@@ -0,0 +1,205 @@
+/*************************************************************************/
+/* context_gl_win.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) || defined(GLES2_ENABLED)
+
+//
+// C++ Implementation: context_gl_x11
+//
+// Description:
+//
+//
+// Author: Juan Linietsky <reduzio@gmail.com>, (C) 2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#define WINVER 0x0500
+#include "context_gl_win.h"
+
+//#include "drivers/opengl/glwrapper.h"
+//#include "ctxgl_procaddr.h"
+
+#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
+#define WGL_CONTEXT_FLAGS_ARB 0x2094
+#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+
+typedef HGLRC (APIENTRY* PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int*);
+
+
+void ContextGL_Win::release_current() {
+
+
+ wglMakeCurrent(hDC,NULL);
+
+}
+
+
+void ContextGL_Win::make_current() {
+
+ wglMakeCurrent(hDC,hRC);
+}
+
+int ContextGL_Win::get_window_width() {
+
+ return OS::get_singleton()->get_video_mode().width;
+}
+
+int ContextGL_Win::get_window_height() {
+
+ return OS::get_singleton()->get_video_mode().height;
+}
+
+void ContextGL_Win::swap_buffers() {
+
+ SwapBuffers(hDC);
+}
+
+/*
+static GLWrapperFuncPtr wrapper_get_proc_address(const char* p_function) {
+
+ print_line(String()+"getting proc of: "+p_function);
+ GLWrapperFuncPtr func=(GLWrapperFuncPtr)get_gl_proc_address(p_function);
+ if (!func) {
+ print_line("Couldn't find function: "+String(p_function));
+ print_line("error: "+itos(GetLastError()));
+ }
+ return func;
+
+}
+*/
+
+
+Error ContextGL_Win::initialize() {
+
+ static PIXELFORMATDESCRIPTOR pfd= {
+ sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
+ 1,
+ PFD_DRAW_TO_WINDOW | // Format Must Support Window
+ PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
+ PFD_DOUBLEBUFFER,
+ PFD_TYPE_RGBA,
+ 24,
+ 0, 0, 0, 0, 0, 0, // Color Bits Ignored
+ 0,// No Alpha Buffer
+ 0,// Shift Bit Ignored
+ 0,// No Accumulation Buffer
+ 0, 0, 0, 0,// Accumulation Bits Ignored
+ 24,// 24Bit Z-Buffer (Depth Buffer)
+ 0,// No Stencil Buffer
+ 0,// No Auxiliary Buffer
+ PFD_MAIN_PLANE, // Main Drawing Layer
+ 0,// Reserved
+ 0, 0, 0 // Layer Masks Ignored
+ };
+
+ if (!(hDC=GetDC(hWnd))) {
+ MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ if (!(pixel_format=ChoosePixelFormat(hDC,&pfd))) // Did Windows Find A Matching Pixel Format?
+ {
+ MessageBox(NULL,"Can't Find A Suitable pixel_format.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ if(!SetPixelFormat(hDC,pixel_format,&pfd)) // Are We Able To Set The Pixel Format?
+ {
+ MessageBox(NULL,"Can't Set The pixel_format.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ if (!(hRC=wglCreateContext(hDC))) // Are We Able To Get A Rendering Context?
+ {
+ MessageBox(NULL,"Can't Create A Temporary GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ wglMakeCurrent(hDC,hRC);
+
+ if (opengl_3_context) {
+
+ int attribs[] = {
+ WGL_CONTEXT_MAJOR_VERSION_ARB, 3,//we want a 3.1 context
+ WGL_CONTEXT_MINOR_VERSION_ARB, 2,
+ //and it shall be forward compatible so that we can only use up to date functionality
+ WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+ 0}; //zero indicates the end of the array
+
+ PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; //pointer to the method
+ wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress("wglCreateContextAttribsARB");
+
+ if(wglCreateContextAttribsARB == NULL) //OpenGL 3.0 is not supported
+ {
+ MessageBox(NULL,"Cannot get Proc Adress for CreateContextAttribs", "ERROR",MB_OK|MB_ICONEXCLAMATION);
+ wglDeleteContext(hRC);
+ return ERR_CANT_CREATE;
+ }
+
+ HGLRC new_hRC;
+ if (!(new_hRC=wglCreateContextAttribsARB(hDC,0, attribs)))
+ {
+ wglDeleteContext(hRC);
+ MessageBox(NULL,"Can't Create An OpenGL 3.1 Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return ERR_CANT_CREATE; // Return false
+ }
+ wglMakeCurrent(hDC,NULL);
+ wglDeleteContext(hRC);
+ hRC=new_hRC;
+
+ if (!wglMakeCurrent(hDC,hRC)) // Try To Activate The Rendering Context
+ {
+ MessageBox(NULL,"Can't Activate The GL 3.1 Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ printf("Activated GL 3.1 context");
+ }
+
+
+// glWrapperInit(wrapper_get_proc_address);
+
+ return OK;
+}
+
+ContextGL_Win::ContextGL_Win(HWND hwnd,bool p_opengl_3_context) {
+
+ opengl_3_context=p_opengl_3_context;
+ hWnd=hwnd;
+}
+
+ContextGL_Win::~ContextGL_Win() {
+
+
+}
+
+
+#endif
diff --git a/platform/windows/context_gl_win.h b/platform/windows/context_gl_win.h
new file mode 100644
index 0000000000..6e8d99a5f0
--- /dev/null
+++ b/platform/windows/context_gl_win.h
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* context_gl_win.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) || defined(GLES2_ENABLED)
+//
+// C++ Interface: context_gl_x11
+//
+// Description:
+//
+//
+// Author: Juan Linietsky <reduzio@gmail.com>, (C) 2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef CONTEXT_GL_WIN_H
+#define CONTEXT_GL_WIN_H
+
+
+#include "os/os.h"
+#include "drivers/gl_context/context_gl.h"
+#include "error_list.h"
+
+#include <windows.h>
+
+class ContextGL_Win : public ContextGL {
+
+ HDC hDC;
+ HGLRC hRC;
+ unsigned int pixel_format;
+ HWND hWnd;
+ bool opengl_3_context;
+public:
+
+
+ virtual void release_current();
+
+ virtual void make_current();
+
+ virtual int get_window_width();
+ virtual int get_window_height();
+ virtual void swap_buffers();
+
+ virtual Error initialize();
+
+
+ ContextGL_Win(HWND hwnd,bool p_opengl_3_context);
+ ~ContextGL_Win();
+
+};
+
+#endif
+#endif
diff --git a/platform/windows/ctxgl_procaddr.cpp b/platform/windows/ctxgl_procaddr.cpp
new file mode 100644
index 0000000000..9715784c32
--- /dev/null
+++ b/platform/windows/ctxgl_procaddr.cpp
@@ -0,0 +1,186 @@
+/*************************************************************************/
+/* ctxgl_procaddr.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef OPENGL_ENABLED
+#include "ctxgl_procaddr.h"
+#include <GL/gl.h>
+#include <stdio.h>
+
+static PROC _gl_procs[]={
+ (PROC)glCullFace,
+ (PROC)glFrontFace,
+ (PROC)glHint,
+ (PROC)glLineWidth,
+ (PROC)glPointSize,
+ (PROC)glPolygonMode,
+ (PROC)glScissor,
+ (PROC)glTexParameterf,
+ (PROC)glTexParameterfv,
+ (PROC)glTexParameteri,
+ (PROC)glTexParameteriv,
+ (PROC)glTexImage1D,
+ (PROC)glTexImage2D,
+ (PROC)glDrawBuffer,
+ (PROC)glClear,
+ (PROC)glClearColor,
+ (PROC)glClearStencil,
+ (PROC)glClearDepth,
+ (PROC)glStencilMask,
+ (PROC)glColorMask,
+ (PROC)glDepthMask,
+ (PROC)glDisable,
+ (PROC)glEnable,
+ (PROC)glFinish,
+ (PROC)glFlush,
+ (PROC)glBlendFunc,
+ (PROC)glLogicOp,
+ (PROC)glStencilFunc,
+ (PROC)glStencilOp,
+ (PROC)glDepthFunc,
+ (PROC)glPixelStoref,
+ (PROC)glPixelStorei,
+ (PROC)glReadBuffer,
+ (PROC)glReadPixels,
+ (PROC)glGetBooleanv,
+ (PROC)glGetDoublev,
+ (PROC)glGetError,
+ (PROC)glGetFloatv,
+ (PROC)glGetIntegerv,
+ (PROC)glGetString,
+ (PROC)glGetTexImage,
+ (PROC)glGetTexParameterfv,
+ (PROC)glGetTexParameteriv,
+ (PROC)glGetTexLevelParameterfv,
+ (PROC)glGetTexLevelParameteriv,
+ (PROC)glIsEnabled,
+ (PROC)glDepthRange,
+ (PROC)glViewport,
+ /* not detected in ATI */
+ (PROC)glDrawArrays,
+ (PROC)glDrawElements,
+ (PROC)glGetPointerv,
+ (PROC)glPolygonOffset,
+ (PROC)glCopyTexImage1D,
+ (PROC)glCopyTexImage2D,
+ (PROC)glCopyTexSubImage1D,
+ (PROC)glCopyTexSubImage2D,
+ (PROC)glTexSubImage1D,
+ (PROC)glTexSubImage2D,
+ (PROC)glBindTexture,
+ (PROC)glDeleteTextures,
+ (PROC)glGenTextures,
+ (PROC)glIsTexture,
+
+ 0
+};
+
+static const char* _gl_proc_names[]={
+ "glCullFace",
+ "glFrontFace",
+ "glHint",
+ "glLineWidth",
+ "glPointSize",
+ "glPolygonMode",
+ "glScissor",
+ "glTexParameterf",
+ "glTexParameterfv",
+ "glTexParameteri",
+ "glTexParameteriv",
+ "glTexImage1D",
+ "glTexImage2D",
+ "glDrawBuffer",
+ "glClear",
+ "glClearColor",
+ "glClearStencil",
+ "glClearDepth",
+ "glStencilMask",
+ "glColorMask",
+ "glDepthMask",
+ "glDisable",
+ "glEnable",
+ "glFinish",
+ "glFlush",
+ "glBlendFunc",
+ "glLogicOp",
+ "glStencilFunc",
+ "glStencilOp",
+ "glDepthFunc",
+ "glPixelStoref",
+ "glPixelStorei",
+ "glReadBuffer",
+ "glReadPixels",
+ "glGetBooleanv",
+ "glGetDoublev",
+ "glGetError",
+ "glGetFloatv",
+ "glGetIntegerv",
+ "glGetString",
+ "glGetTexImage",
+ "glGetTexParameterfv",
+ "glGetTexParameteriv",
+ "glGetTexLevelParameterfv",
+ "glGetTexLevelParameteriv",
+ "glIsEnabled",
+ "glDepthRange",
+ "glViewport",
+ /* not detected in ati */
+ "glDrawArrays",
+ "glDrawElements",
+ "glGetPointerv",
+ "glPolygonOffset",
+ "glCopyTexImage1D",
+ "glCopyTexImage2D",
+ "glCopyTexSubImage1D",
+ "glCopyTexSubImage2D",
+ "glTexSubImage1D",
+ "glTexSubImage2D",
+ "glBindTexture",
+ "glDeleteTextures",
+ "glGenTextures",
+ "glIsTexture",
+
+ 0
+};
+
+PROC get_gl_proc_address(const char* p_address) {
+
+ PROC proc = wglGetProcAddress((const CHAR*)p_address);
+ if (!proc) {
+
+ int i=0;
+ while(_gl_procs[i]) {
+
+ if (strcmp(p_address,_gl_proc_names[i])==0) {
+ return _gl_procs[i];
+ }
+ i++;
+ }
+ }
+ return proc;
+}
+#endif
diff --git a/platform/windows/ctxgl_procaddr.h b/platform/windows/ctxgl_procaddr.h
new file mode 100644
index 0000000000..d3ab20e82d
--- /dev/null
+++ b/platform/windows/ctxgl_procaddr.h
@@ -0,0 +1,38 @@
+/*************************************************************************/
+/* ctxgl_procaddr.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CTXGL_PROCADDR_H
+#define CTXGL_PROCADDR_H
+
+#ifdef OPENGL_ENABLED
+#include <windows.h>
+
+
+PROC get_gl_proc_address(const char* p_address);
+#endif
+#endif // CTXGL_PROCADDR_H
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
new file mode 100644
index 0000000000..1774ba17f8
--- /dev/null
+++ b/platform/windows/detect.py
@@ -0,0 +1,208 @@
+
+
+import os
+
+import sys
+
+
+def is_active():
+ return True
+
+def get_name():
+ return "Windows"
+
+def can_build():
+
+
+ if (os.name=="nt"):
+ #building natively on windows!
+ if (os.getenv("VSINSTALLDIR")):
+ return True
+ else:
+ print("MSVC Not detected, attempting mingw.")
+ return True
+
+
+
+ if (os.name=="posix"):
+
+ if os.system("i586-mingw32msvc-gcc --version") == 0:
+ return True
+
+
+ return False
+
+def get_opts():
+
+ mwp=""
+ mwp64=""
+ if (os.name!="nt"):
+ mwp="i586-mingw32msvc-"
+ mwp64="x86_64-w64-mingw32-"
+
+ return [
+ ('force_64_bits','Force 64 bits binary','no'),
+ ('force_32_bits','Force 32 bits binary','no'),
+ ('mingw_prefix','Mingw Prefix',mwp),
+ ('mingw_prefix_64','Mingw Prefix 64 bits',mwp64),
+ ]
+
+def get_flags():
+
+ return [
+ ('freetype','builtin'), #use builtin freetype
+ ]
+
+
+
+def configure(env):
+
+ if os.name == "posix":
+ env['OBJSUFFIX'] = ".win"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".win"+env['LIBSUFFIX']
+
+ env.Append(CPPPATH=['#platform/windows'])
+
+ if (env["tools"]=="no"):
+ #no tools suffix
+ env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
+
+
+ if (os.name=="nt" and os.getenv("VSINSTALLDIR")!=None):
+ #build using visual studio
+ env['ENV']['TMP'] = os.environ['TMP']
+ env.Append(CPPPATH=['#platform/windows/include'])
+ env.Append(LIBPATH=['#platform/windows/lib'])
+
+ if (env["freetype"]!="no"):
+ env.Append(CCFLAGS=['/DFREETYPE_ENABLED'])
+ env.Append(CPPPATH=['#tools/freetype'])
+ env.Append(CPPPATH=['#tools/freetype/freetype/include'])
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['/O2'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
+
+ elif (env["target"]=="test"):
+
+ env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO','/O1'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-g','-pg'])
+ env.Append(LINKFLAGS=['-pg'])
+
+ env.Append(CCFLAGS=['/MT','/Gd','/GR','/nologo'])
+ env.Append(CXXFLAGS=['/TP'])
+ env.Append(CPPFLAGS=['/DMSVC', '/GR', ])
+ env.Append(CCFLAGS=['/I'+os.getenv("WindowsSdkDir")+"/Include"])
+ env.Append(CCFLAGS=['/DWINDOWS_ENABLED'])
+ env.Append(CCFLAGS=['/DRTAUDIO_ENABLED'])
+ env.Append(CCFLAGS=['/DWIN32'])
+ env.Append(CCFLAGS=['/DTYPED_METHOD_BIND'])
+
+ #env.Append(CCFLAGS=['/DLEGACYGL_ENABLED'])
+ env.Append(CCFLAGS=['/DGLES_ENABLED'])
+ #env.Append(CCFLAGS=['/DGLES1_ENABLED'])
+ env.Append(CCFLAGS=['/DGLEW_ENABLED'])
+ env.Append(LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32','wsock32'])
+ env.Append(LINKFLAGS=['/DEBUG'])
+
+ env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"])
+ if (os.getenv("DXSDK_DIR")):
+ DIRECTX_PATH=os.getenv("DXSDK_DIR")
+ else:
+ DIRECTX_PATH="C:/Program Files/Microsoft DirectX SDK (March 2009)"
+
+ if (os.getenv("VCINSTALLDIR")):
+ VC_PATH=os.getenv("VCINSTALLDIR")
+ else:
+ VC_PATH=""
+
+ env.Append(CCFLAGS=["/I"+VC_PATH+"/Include"])
+ env.Append(LIBPATH=[VC_PATH+"/Lib"])
+ env.Append(CCFLAGS=["/I"+DIRECTX_PATH+"/Include"])
+ env.Append(LIBPATH=[DIRECTX_PATH+"/Lib/x86"])
+ env['ENV'] = os.environ;
+ else:
+ #build using mingw
+ if (os.name=="nt"):
+ env['ENV']['TMP'] = os.environ['TMP'] #way to go scons, you can be so stupid sometimes
+
+ mingw_prefix=""
+
+ if (env["force_32_bits"]!="no"):
+ env['OBJSUFFIX'] = ".32"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".32"+env['LIBSUFFIX']
+ env.Append(CCFLAGS=['-m32'])
+ env.Append(LINKFLAGS=['-m32'])
+
+
+
+
+ if (env["force_64_bits"]!="no"):
+ mingw_prefix=env["mingw_prefix_64"];
+ env['OBJSUFFIX'] = ".64"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".64"+env['LIBSUFFIX']
+ env.Append(LINKFLAGS=['-static'])
+ else:
+ mingw_prefix=env["mingw_prefix"];
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O3','-ffast-math','-fomit-frame-pointer','-msse2'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+ elif (env["target"]=="release_debug"):
+
+ env.Append(CCFLAGS=['-O2','-DDEBUG_ENABLED'])
+ env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-g', '-Wall','-DDEBUG_ENABLED'])
+ elif (env["target"]=="release_tools"):
+
+ env.Append(CCFLAGS=['-O2','-Wall','-DDEBUG_ENABLED'])
+
+
+ if (env["freetype"]!="no"):
+ env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
+ env.Append(CPPPATH=['#tools/freetype'])
+ env.Append(CPPPATH=['#tools/freetype/freetype/include'])
+
+ env["CC"]=mingw_prefix+"gcc"
+ env['AS']=mingw_prefix+"as"
+ env['CXX'] = mingw_prefix+"g++"
+ env['AR'] = mingw_prefix+"ar"
+ env['RANLIB'] = mingw_prefix+"ranlib"
+ env['LD'] = mingw_prefix+"g++"
+
+ #env['CC'] = "winegcc"
+ #env['CXX'] = "wineg++"
+
+ env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows'])
+ env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
+ env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLES1_ENABLED','-DGLEW_ENABLED'])
+ env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','wsock32','kernel32'])
+ #'d3dx9d'
+ env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
+ env.Append(LINKFLAGS=['-g'])
+
+ 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 = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
+ env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+
+
+
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
new file mode 100644
index 0000000000..952f51fdd4
--- /dev/null
+++ b/platform/windows/export/export.cpp
@@ -0,0 +1,24 @@
+#include "export.h"
+#include "platform/windows/logo.h"
+#include "tools/editor/editor_import_export.h"
+
+void register_windows_exporter() {
+
+ Image img(_windows_logo);
+ Ref<ImageTexture> logo = memnew( ImageTexture );
+ logo->create_from_image(img);
+
+ {
+ Ref<EditorExportPlatformPC> exporter = Ref<EditorExportPlatformPC>( memnew(EditorExportPlatformPC) );
+ exporter->set_binary_extension("exe");
+ exporter->set_release_binary32("windows_32_release.exe");
+ exporter->set_debug_binary32("windows_32_debug.exe");
+ exporter->set_release_binary64("windows_64_release.exe");
+ exporter->set_debug_binary64("windows_64_debug.exe");
+ exporter->set_name("Windows Desktop");
+ exporter->set_logo(logo);
+ EditorImportExport::get_singleton()->add_export_platform(exporter);
+ }
+
+
+}
diff --git a/platform/windows/export/export.h b/platform/windows/export/export.h
new file mode 100644
index 0000000000..de3dc3fa50
--- /dev/null
+++ b/platform/windows/export/export.h
@@ -0,0 +1,3 @@
+
+void register_windows_exporter();
+
diff --git a/platform/windows/godot_win.cpp b/platform/windows/godot_win.cpp
new file mode 100644
index 0000000000..2999a9beae
--- /dev/null
+++ b/platform/windows/godot_win.cpp
@@ -0,0 +1,207 @@
+/*************************************************************************/
+/* godot_win.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "os_windows.h"
+#include "main/main.h"
+#include <stdio.h>
+
+PCHAR*
+ CommandLineToArgvA(
+ PCHAR CmdLine,
+ int* _argc
+ )
+ {
+ PCHAR* argv;
+ PCHAR _argv;
+ ULONG len;
+ ULONG argc;
+ CHAR a;
+ ULONG i, j;
+
+ BOOLEAN in_QM;
+ BOOLEAN in_TEXT;
+ BOOLEAN in_SPACE;
+
+ len = strlen(CmdLine);
+ i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID);
+
+ argv = (PCHAR*)GlobalAlloc(GMEM_FIXED,
+ i + (len+2)*sizeof(CHAR));
+
+ _argv = (PCHAR)(((PUCHAR)argv)+i);
+
+ argc = 0;
+ argv[argc] = _argv;
+ in_QM = FALSE;
+ in_TEXT = FALSE;
+ in_SPACE = TRUE;
+ i = 0;
+ j = 0;
+
+ while( (a = CmdLine[i]) ) {
+ if(in_QM) {
+ if(a == '\"') {
+ in_QM = FALSE;
+ } else {
+ _argv[j] = a;
+ j++;
+ }
+ } else {
+ switch(a) {
+ case '\"':
+ in_QM = TRUE;
+ in_TEXT = TRUE;
+ if(in_SPACE) {
+ argv[argc] = _argv+j;
+ argc++;
+ }
+ in_SPACE = FALSE;
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ if(in_TEXT) {
+ _argv[j] = '\0';
+ j++;
+ }
+ in_TEXT = FALSE;
+ in_SPACE = TRUE;
+ break;
+ default:
+ in_TEXT = TRUE;
+ if(in_SPACE) {
+ argv[argc] = _argv+j;
+ argc++;
+ }
+ _argv[j] = a;
+ j++;
+ in_SPACE = FALSE;
+ break;
+ }
+ }
+ i++;
+ }
+ _argv[j] = '\0';
+ argv[argc] = NULL;
+
+ (*_argc) = argc;
+ return argv;
+ }
+
+int main(int argc, char** argv) {
+
+ OS_Windows os(NULL);
+
+ Main::setup(argv[0], argc - 1, &argv[1]);
+ if (Main::start())
+ os.run();
+ Main::cleanup();
+
+ return os.get_exit_code();
+};
+
+HINSTANCE godot_hinstance = NULL;
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
+
+ int argc;
+ char** argv;
+
+ char* arg;
+ int index;
+ int result;
+
+ // count the arguments
+
+ argc = 1;
+ arg = lpCmdLine;
+
+ while (arg[0] != 0) {
+
+ while (arg[0] != 0 && arg[0] == ' ') {
+ arg++;
+ }
+
+ if (arg[0] != 0) {
+
+ argc++;
+
+ while (arg[0] != 0 && arg[0] != ' ') {
+ arg++;
+ }
+
+ }
+
+ }
+
+ // tokenize the arguments
+
+ argv = (char**)malloc(argc * sizeof(char*));
+
+ arg = lpCmdLine;
+ index = 1;
+
+ while (arg[0] != 0) {
+
+ while (arg[0] != 0 && arg[0] == ' ') {
+ arg++;
+ }
+
+ if (arg[0] != 0) {
+
+ argv[index] = arg;
+ index++;
+
+ while (arg[0] != 0 && arg[0] != ' ') {
+ arg++;
+ }
+
+ if (arg[0] != 0) {
+ arg[0] = 0;
+ arg++;
+ }
+
+ }
+
+ }
+
+ // put the program name into argv[0]
+
+ char filename[_MAX_PATH];
+
+ GetModuleFileName(NULL, filename, _MAX_PATH);
+ argv[0] = filename;
+
+ // call the user specified main function
+
+ result = main(argc, argv);
+
+ free(argv);
+ return result;
+}
diff --git a/platform/windows/key_mapping_win.cpp b/platform/windows/key_mapping_win.cpp
new file mode 100644
index 0000000000..bdf3b2a92f
--- /dev/null
+++ b/platform/windows/key_mapping_win.cpp
@@ -0,0 +1,256 @@
+/*************************************************************************/
+/* key_mapping_win.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#define WINVER 0x0500
+#include "key_mapping_win.h"
+#include <stdio.h>
+
+struct _WinTranslatePair {
+
+ unsigned int keysym;
+ unsigned int keycode;
+};
+
+
+static _WinTranslatePair _vk_to_keycode[]={
+
+{ KEY_BACKSPACE, VK_BACK },// (0x08) // backspace
+{ KEY_TAB, VK_TAB },//(0x09)
+
+//VK_CLEAR (0x0C)
+
+{ KEY_RETURN, VK_RETURN },//(0x0D)
+
+{ KEY_SHIFT, VK_SHIFT },//(0x10)
+
+{ KEY_CONTROL, VK_CONTROL },//(0x11)
+
+{ KEY_MENU, VK_MENU },//(0x12)
+
+{ KEY_PAUSE, VK_PAUSE },//(0x13)
+
+{ KEY_CAPSLOCK, VK_CAPITAL },//(0x14)
+
+{ KEY_ESCAPE, VK_ESCAPE },//(0x1B)
+
+{ KEY_SPACE, VK_SPACE },//(0x20)
+
+{ KEY_PAGEUP,VK_PRIOR },//(0x21)
+
+{ KEY_PAGEDOWN, VK_NEXT },//(0x22)
+
+{ KEY_END, VK_END },//(0x23)
+
+{ KEY_HOME, VK_HOME },//(0x24)
+
+{ KEY_LEFT, VK_LEFT },//(0x25)
+
+{ KEY_UP, VK_UP },//(0x26)
+
+{ KEY_RIGHT,VK_RIGHT },//(0x27)
+
+{ KEY_DOWN, VK_DOWN},// (0x28)
+
+//VK_SELECT (0x29)
+
+{ KEY_PRINT, VK_PRINT},// (0x2A)
+
+//VK_EXECUTE (0x2B)
+
+{ KEY_PRINT, VK_SNAPSHOT},// (0x2C)
+
+{ KEY_INSERT, VK_INSERT},// (0x2D)
+
+{ KEY_DELETE, VK_DELETE},// (0x2E)
+
+{ KEY_HELP, VK_HELP},// (0x2F)
+
+
+{ KEY_0, (0x30) },////0 key
+{ KEY_1, (0x31) },////1 key
+{ KEY_2, (0x32) },////2 key
+{ KEY_3, (0x33) },////3 key
+{ KEY_4, (0x34) },////4 key
+{ KEY_5, (0x35) },////5 key
+{ KEY_6, (0x36) },////6 key
+{ KEY_7, (0x37) },////7 key
+{ KEY_8, (0x38) },////8 key
+{ KEY_9, (0x39) },////9 key
+{ KEY_A, (0x41) },////A key
+{ KEY_B, (0x42) },////B key
+{ KEY_C, (0x43) },////C key
+{ KEY_D, (0x44) },////D key
+{ KEY_E, (0x45) },////E key
+{ KEY_F, (0x46) },////F key
+{ KEY_G, (0x47) },////G key
+{ KEY_H, (0x48) },////H key
+{ KEY_I, (0x49) },////I key
+{ KEY_J, (0x4A) },////J key
+{ KEY_K, (0x4B) },////K key
+{ KEY_L, (0x4C) },////L key
+{ KEY_M, (0x4D) },////M key
+{ KEY_N, (0x4E) },////N key
+{ KEY_O, (0x4F) },////O key
+{ KEY_P, (0x50) },////P key
+{ KEY_Q, (0x51) },////Q key
+{ KEY_R, (0x52) },////R key
+{ KEY_S, (0x53) },////S key
+{ KEY_T, (0x54) },////T key
+{ KEY_U, (0x55) },////U key
+{ KEY_V, (0x56) },////V key
+{ KEY_W, (0x57) },////W key
+{ KEY_X, (0x58) },////X key
+{ KEY_Y, (0x59) },////Y key
+{ KEY_Z, (0x5A) },////Z key
+
+{ KEY_MASK_META, VK_LWIN },//(0x5B)
+{ KEY_MASK_META, VK_RWIN },//(0x5C)
+//VK_APPS (0x5D)
+{ KEY_STANDBY,VK_SLEEP },//(0x5F)
+{ KEY_KP_0,VK_NUMPAD0 },//(0x60)
+{ KEY_KP_1,VK_NUMPAD1 },//(0x61)
+{ KEY_KP_2,VK_NUMPAD2 },//(0x62)
+{ KEY_KP_3,VK_NUMPAD3 },//(0x63)
+{ KEY_KP_4,VK_NUMPAD4 },//(0x64)
+{ KEY_KP_5,VK_NUMPAD5 },//(0x65)
+{ KEY_KP_6,VK_NUMPAD6 },//(0x66)
+{ KEY_KP_7,VK_NUMPAD7 },//(0x67)
+{ KEY_KP_8,VK_NUMPAD8 },//(0x68)
+{ KEY_KP_9,VK_NUMPAD9 },//(0x69)
+{ KEY_KP_MULTIPLY,VK_MULTIPLY},// (0x6A)
+{ KEY_KP_ADD,VK_ADD},// (0x6B)
+//VK_SEPARATOR (0x6C)
+{ KEY_KP_SUBSTRACT,VK_SUBTRACT},// (0x6D)
+{ KEY_KP_PERIOD,VK_DECIMAL},// (0x6E)
+{ KEY_KP_DIVIDE,VK_DIVIDE},// (0x6F)
+{ KEY_F1,VK_F1},// (0x70)
+{ KEY_F2,VK_F2},// (0x71)
+{ KEY_F3,VK_F3},// (0x72)
+{ KEY_F4,VK_F4},// (0x73)
+{ KEY_F5,VK_F5},// (0x74)
+{ KEY_F6,VK_F6},// (0x75)
+{ KEY_F7,VK_F7},// (0x76)
+{ KEY_F8,VK_F8},// (0x77)
+{ KEY_F9,VK_F9},// (0x78)
+{ KEY_F10,VK_F10},// (0x79)
+{ KEY_F11,VK_F11},// (0x7A)
+{ KEY_F12,VK_F12},// (0x7B)
+{ KEY_F13,VK_F13},// (0x7C)
+{ KEY_F14,VK_F14},// (0x7D)
+{ KEY_F15,VK_F15},// (0x7E)
+{ KEY_F16,VK_F16},// (0x7F)
+{ KEY_NUMLOCK,VK_NUMLOCK},// (0x90)
+{ KEY_SCROLLLOCK,VK_SCROLL},// (0x91)
+{ KEY_SHIFT,VK_LSHIFT},// (0xA0)
+{ KEY_SHIFT,VK_RSHIFT},// (0xA1)
+{ KEY_CONTROL,VK_LCONTROL},// (0xA2)
+{ KEY_CONTROL,VK_RCONTROL},// (0xA3)
+{ KEY_MENU,VK_LMENU},// (0xA4)
+{ KEY_MENU,VK_RMENU},// (0xA5)
+
+
+{ KEY_BACK,VK_BROWSER_BACK},// (0xA6)
+
+{ KEY_FORWARD,VK_BROWSER_FORWARD},// (0xA7)
+
+{ KEY_REFRESH,VK_BROWSER_REFRESH},// (0xA8)
+
+{ KEY_STOP,VK_BROWSER_STOP},// (0xA9)
+
+{ KEY_SEARCH,VK_BROWSER_SEARCH},// (0xAA)
+
+{ KEY_FAVORITES, VK_BROWSER_FAVORITES},// (0xAB)
+
+{ KEY_HOMEPAGE,VK_BROWSER_HOME},// (0xAC)
+
+{ KEY_VOLUMEMUTE,VK_VOLUME_MUTE},// (0xAD)
+
+{ KEY_VOLUMEDOWN,VK_VOLUME_DOWN},// (0xAE)
+
+{ KEY_VOLUMEUP,VK_VOLUME_UP},// (0xAF)
+
+
+{ KEY_MEDIANEXT,VK_MEDIA_NEXT_TRACK},// (0xB0)
+
+{ KEY_MEDIAPREVIOUS,VK_MEDIA_PREV_TRACK},// (0xB1)
+
+{ KEY_MEDIASTOP,VK_MEDIA_STOP},// (0xB2)
+
+//VK_MEDIA_PLAY_PAUSE (0xB3)
+
+{ KEY_LAUNCHMAIL, VK_LAUNCH_MAIL},// (0xB4)
+
+{ KEY_LAUNCHMEDIA,VK_LAUNCH_MEDIA_SELECT},// (0xB5)
+
+{ KEY_LAUNCH0,VK_LAUNCH_APP1},// (0xB6)
+
+{ KEY_LAUNCH1,VK_LAUNCH_APP2},// (0xB7)
+
+{ KEY_SEMICOLON,VK_OEM_1},// (0xBA)
+
+
+{ KEY_EQUAL, VK_OEM_PLUS},// (0xBB) // Windows 2000/XP: For any country/region, the '+' key
+{ KEY_COLON,VK_OEM_COMMA},// (0xBC) // Windows 2000/XP: For any country/region, the ',' key
+{ KEY_MINUS,VK_OEM_MINUS},// (0xBD) // Windows 2000/XP: For any country/region, the '-' key
+{ KEY_PERIOD,VK_OEM_PERIOD},// (0xBE) // Windows 2000/XP: For any country/region, the '.' key
+{ KEY_SLASH,VK_OEM_2},// (0xBF) //Windows 2000/XP: For the US standard keyboard, the '/?' key
+
+{KEY_QUOTELEFT, VK_OEM_3},// (0xC0)
+{KEY_BRACELEFT,VK_OEM_4},// (0xDB)
+{KEY_BACKSLASH,VK_OEM_5},// (0xDC)
+{KEY_BRACERIGHT,VK_OEM_6},// (0xDD)
+{KEY_APOSTROPHE, VK_OEM_7},// (0xDE)
+/*
+{VK_OEM_8 (0xDF)
+{VK_OEM_102 (0xE2) // Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard
+*/
+//{ KEY_PLAY, VK_PLAY},// (0xFA)
+
+{KEY_UNKNOWN, 0} };
+
+/*
+VK_ZOOM (0xFB)
+VK_NONAME (0xFC)
+VK_PA1 (0xFD)
+VK_OEM_CLEAR (0xFE)
+*/
+
+unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) {
+
+ for(int i=0;_vk_to_keycode[i].keysym!=KEY_UNKNOWN;i++) {
+
+ if (_vk_to_keycode[i].keycode==p_code) {
+ //printf("outcode: %x\n",_vk_to_keycode[i].keysym);
+
+ return _vk_to_keycode[i].keysym;
+ }
+ }
+
+
+ return KEY_UNKNOWN;
+}
diff --git a/platform/windows/key_mapping_win.h b/platform/windows/key_mapping_win.h
new file mode 100644
index 0000000000..3e351675b0
--- /dev/null
+++ b/platform/windows/key_mapping_win.h
@@ -0,0 +1,51 @@
+/*************************************************************************/
+/* key_mapping_win.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef KEY_MAPPING_WINDOWS_H
+#define KEY_MAPPING_WINDOWS_H
+
+
+#include "os/keyboard.h"
+
+#include <windows.h>
+
+#include <winuser.h>
+
+
+class KeyMappingWindows {
+
+ KeyMappingWindows() {};
+public:
+
+ static unsigned int get_keysym(unsigned int p_code);
+
+};
+
+
+
+#endif
diff --git a/platform/windows/lang_table.h b/platform/windows/lang_table.h
new file mode 100644
index 0000000000..83f3fb52fd
--- /dev/null
+++ b/platform/windows/lang_table.h
@@ -0,0 +1,190 @@
+/*************************************************************************/
+/* lang_table.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef LANG_TABLE_H
+#define LANG_TABLE_H
+
+//#include <windows.h>
+
+struct _WinLocale {
+ const char *locale;
+ int main_lang;
+ int sublang;
+};
+
+static const _WinLocale _win_locales[]={
+{"ar", LANG_ARABIC,SUBLANG_NEUTRAL},
+{"ar_AE", LANG_ARABIC,SUBLANG_ARABIC_UAE},
+{"ar_BH", LANG_ARABIC,SUBLANG_ARABIC_BAHRAIN},
+{"ar_DZ", LANG_ARABIC,SUBLANG_ARABIC_ALGERIA},
+{"ar_EG", LANG_ARABIC,SUBLANG_ARABIC_EGYPT},
+{"ar_IQ", LANG_ARABIC,SUBLANG_ARABIC_IRAQ},
+{"ar_JO", LANG_ARABIC,SUBLANG_ARABIC_JORDAN},
+{"ar_KW", LANG_ARABIC,SUBLANG_ARABIC_KUWAIT},
+{"ar_LB", LANG_ARABIC,SUBLANG_ARABIC_LEBANON},
+{"ar_LY", LANG_ARABIC,SUBLANG_ARABIC_LIBYA},
+{"ar_MA", LANG_ARABIC,SUBLANG_ARABIC_MOROCCO},
+{"ar_OM", LANG_ARABIC,SUBLANG_ARABIC_OMAN},
+{"ar_QA", LANG_ARABIC,SUBLANG_ARABIC_QATAR},
+{"ar_SA", LANG_ARABIC,SUBLANG_ARABIC_SAUDI_ARABIA},
+//no sudan
+{"ar_SY", LANG_ARABIC,SUBLANG_ARABIC_SYRIA},
+{"ar_TN", LANG_ARABIC,SUBLANG_ARABIC_TUNISIA},
+{"ar_YE", LANG_ARABIC,SUBLANG_ARABIC_YEMEN},
+{"be", LANG_BELARUSIAN,SUBLANG_NEUTRAL},
+{"be_BY", LANG_BELARUSIAN,SUBLANG_BELARUSIAN_BELARUS},
+{"bg", LANG_BULGARIAN,SUBLANG_NEUTRAL},
+{"bg_BG", LANG_BULGARIAN,SUBLANG_BULGARIAN_BULGARIA},
+{"ca", LANG_CATALAN,SUBLANG_NEUTRAL},
+{"ca_ES", LANG_CATALAN,SUBLANG_CATALAN_CATALAN},
+{"cs", LANG_CZECH,SUBLANG_NEUTRAL},
+{"cs_CZ", LANG_CZECH,SUBLANG_CZECH_CZECH_REPUBLIC},
+{"da", LANG_DANISH,SUBLANG_NEUTRAL},
+{"da_DK", LANG_DANISH,SUBLANG_DANISH_DENMARK},
+{"de", LANG_GERMAN,SUBLANG_NEUTRAL},
+{"de_AT", LANG_GERMAN,SUBLANG_GERMAN_AUSTRIAN},
+{"de_CH", LANG_GERMAN,SUBLANG_GERMAN_SWISS},
+{"de_DE", LANG_GERMAN,SUBLANG_GERMAN},
+{"de_LU", LANG_GERMAN,SUBLANG_GERMAN_LUXEMBOURG},
+{"el", LANG_GREEK,SUBLANG_NEUTRAL},
+{"el_GR", LANG_GREEK,SUBLANG_GREEK_GREECE},
+//{"en_029", LANG_ENGLISH,SUBLANG_ENGLISH_CARIBBEAN},
+{"en", LANG_ENGLISH,SUBLANG_NEUTRAL},
+{"en_AU", LANG_ENGLISH,SUBLANG_ENGLISH_AUS},
+{"en_CA", LANG_ENGLISH,SUBLANG_ENGLISH_CAN},
+{"en_GB", LANG_ENGLISH,SUBLANG_ENGLISH_UK},
+//{"en_IE", LANG_ENGLISH,SUBLANG_ENGLISH_IRELAND},
+{"en_IN", LANG_ENGLISH,SUBLANG_ENGLISH_INDIA},
+//MT
+{"en_NZ", LANG_ENGLISH,SUBLANG_ENGLISH_NZ},
+{"en_PH", LANG_ENGLISH,SUBLANG_ENGLISH_PHILIPPINES},
+{"en_SG", LANG_ENGLISH,SUBLANG_ENGLISH_SINGAPORE},
+{"en_US", LANG_ENGLISH,SUBLANG_ENGLISH_US},
+{"en_ZA", LANG_ENGLISH,SUBLANG_ENGLISH_SOUTH_AFRICA},
+{"es", LANG_SPANISH,SUBLANG_NEUTRAL},
+{"es_AR", LANG_SPANISH,SUBLANG_SPANISH_ARGENTINA},
+{"es_BO", LANG_SPANISH,SUBLANG_SPANISH_BOLIVIA},
+{"es_CL", LANG_SPANISH,SUBLANG_SPANISH_CHILE},
+{"es_CO", LANG_SPANISH,SUBLANG_SPANISH_COLOMBIA},
+{"es_CR", LANG_SPANISH,SUBLANG_SPANISH_COSTA_RICA},
+{"es_DO", LANG_SPANISH,SUBLANG_SPANISH_DOMINICAN_REPUBLIC},
+{"es_EC", LANG_SPANISH,SUBLANG_SPANISH_ECUADOR},
+{"es_ES", LANG_SPANISH,SUBLANG_SPANISH},
+{"es_GT", LANG_SPANISH,SUBLANG_SPANISH_GUATEMALA},
+{"es_HN", LANG_SPANISH,SUBLANG_SPANISH_HONDURAS},
+{"es_MX", LANG_SPANISH,SUBLANG_SPANISH_MEXICAN},
+{"es_NI", LANG_SPANISH,SUBLANG_SPANISH_NICARAGUA},
+{"es_PA", LANG_SPANISH,SUBLANG_SPANISH_PANAMA},
+{"es_PE", LANG_SPANISH,SUBLANG_SPANISH_PERU},
+{"es_PR", LANG_SPANISH,SUBLANG_SPANISH_PUERTO_RICO},
+{"es_PY", LANG_SPANISH,SUBLANG_SPANISH_PARAGUAY},
+{"es_SV", LANG_SPANISH,SUBLANG_SPANISH_EL_SALVADOR},
+{"es_US", LANG_SPANISH,SUBLANG_SPANISH_US},
+{"es_UY", LANG_SPANISH,SUBLANG_SPANISH_URUGUAY},
+{"es_VE", LANG_SPANISH,SUBLANG_SPANISH_VENEZUELA},
+{"et", LANG_ESTONIAN,SUBLANG_NEUTRAL},
+{"et_EE", LANG_ESTONIAN,SUBLANG_ESTONIAN_ESTONIA},
+{"fi", LANG_FINNISH,SUBLANG_NEUTRAL},
+{"fi_FI", LANG_FINNISH,SUBLANG_FINNISH_FINLAND},
+{"fr", LANG_FRENCH,SUBLANG_NEUTRAL},
+{"fr_BE", LANG_FRENCH,SUBLANG_FRENCH_BELGIAN},
+{"fr_CA", LANG_FRENCH,SUBLANG_FRENCH_CANADIAN},
+{"fr_CH", LANG_FRENCH,SUBLANG_FRENCH_SWISS},
+{"fr_FR", LANG_FRENCH,SUBLANG_FRENCH},
+{"fr_LU", LANG_FRENCH,SUBLANG_FRENCH_LUXEMBOURG},
+{"ga", LANG_IRISH,SUBLANG_NEUTRAL},
+{"ga_IE", LANG_IRISH,SUBLANG_IRISH_IRELAND},
+{"hi", LANG_HINDI,SUBLANG_NEUTRAL},
+{"hi_IN", LANG_HINDI,SUBLANG_HINDI_INDIA},
+{"hr", LANG_CROATIAN,SUBLANG_NEUTRAL},
+{"hr_HR", LANG_CROATIAN,SUBLANG_CROATIAN_CROATIA},
+{"hu", LANG_HUNGARIAN,SUBLANG_NEUTRAL},
+{"hu_HU", LANG_HUNGARIAN,SUBLANG_HUNGARIAN_HUNGARY},
+{"in", LANG_ARMENIAN,SUBLANG_NEUTRAL},
+{"in_ID", LANG_INDONESIAN,SUBLANG_INDONESIAN_INDONESIA},
+{"is", LANG_ICELANDIC,SUBLANG_NEUTRAL},
+{"is_IS", LANG_ICELANDIC,SUBLANG_ICELANDIC_ICELAND},
+{"it", LANG_ITALIAN,SUBLANG_NEUTRAL},
+{"it_CH", LANG_ITALIAN,SUBLANG_ITALIAN_SWISS},
+{"it_IT", LANG_ITALIAN,SUBLANG_ITALIAN},
+{"iw", LANG_HEBREW,SUBLANG_NEUTRAL},
+{"iw_IL", LANG_HEBREW,SUBLANG_HEBREW_ISRAEL},
+{"ja", LANG_JAPANESE,SUBLANG_NEUTRAL},
+{"ja_JP", LANG_JAPANESE,SUBLANG_JAPANESE_JAPAN},
+{"ko", LANG_KOREAN,SUBLANG_NEUTRAL},
+{"ko_KR", LANG_KOREAN,SUBLANG_KOREAN},
+{"lt", LANG_LITHUANIAN,SUBLANG_NEUTRAL},
+//{"lt_LT", LANG_LITHUANIAN,SUBLANG_LITHUANIAN_LITHUANIA},
+{"lv", LANG_LATVIAN,SUBLANG_NEUTRAL},
+{"lv_LV", LANG_LATVIAN,SUBLANG_LATVIAN_LATVIA},
+{"mk", LANG_MACEDONIAN,SUBLANG_NEUTRAL},
+{"mk_MK", LANG_MACEDONIAN,SUBLANG_MACEDONIAN_MACEDONIA},
+{"ms", LANG_MALAY,SUBLANG_NEUTRAL},
+{"ms_MY", LANG_MALAY,SUBLANG_MALAY_MALAYSIA},
+{"mt", LANG_MALTESE,SUBLANG_NEUTRAL},
+{"mt_MT", LANG_MALTESE,SUBLANG_MALTESE_MALTA},
+{"nl", LANG_DUTCH,SUBLANG_NEUTRAL},
+{"nl_BE", LANG_DUTCH,SUBLANG_DUTCH_BELGIAN},
+{"nl_NL", LANG_DUTCH,SUBLANG_DUTCH},
+{"no", LANG_NORWEGIAN,SUBLANG_NEUTRAL},
+{"no_NO", LANG_NORWEGIAN,SUBLANG_NORWEGIAN_BOKMAL},
+{"no_NO_NY", LANG_NORWEGIAN,SUBLANG_NORWEGIAN_NYNORSK},
+{"pl", LANG_POLISH,SUBLANG_NEUTRAL},
+{"pl_PL", LANG_POLISH,SUBLANG_POLISH_POLAND},
+{"pt", LANG_PORTUGUESE,SUBLANG_NEUTRAL},
+{"pt_BR", LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN},
+{"pt_PT", LANG_PORTUGUESE,SUBLANG_PORTUGUESE},
+{"ro", LANG_ROMANIAN,SUBLANG_NEUTRAL},
+{"ro_RO", LANG_ROMANIAN,SUBLANG_ROMANIAN_ROMANIA},
+{"ru", LANG_RUSSIAN,SUBLANG_NEUTRAL},
+{"ru_RU", LANG_RUSSIAN,SUBLANG_RUSSIAN_RUSSIA},
+{"sk", LANG_SLOVAK,SUBLANG_NEUTRAL},
+{"sk_SK", LANG_SLOVAK,SUBLANG_SLOVAK_SLOVAKIA},
+{"sl", LANG_SLOVENIAN,SUBLANG_NEUTRAL},
+{"sl_SI", LANG_SLOVENIAN,SUBLANG_SLOVENIAN_SLOVENIA},
+{"sq", LANG_ALBANIAN,SUBLANG_NEUTRAL},
+{"sq_AL", LANG_ALBANIAN,SUBLANG_ALBANIAN_ALBANIA},
+{"sr", LANG_SERBIAN_NEUTRAL,SUBLANG_NEUTRAL},
+{"sv", LANG_SWEDISH,SUBLANG_NEUTRAL},
+{"sv_SE", LANG_SWEDISH,SUBLANG_SWEDISH},
+{"th", LANG_THAI,SUBLANG_NEUTRAL},
+{"th_TH", LANG_THAI,SUBLANG_THAI_THAILAND},
+{"tr", LANG_TURKISH,SUBLANG_NEUTRAL},
+{"tr_TR", LANG_TURKISH,SUBLANG_TURKISH_TURKEY},
+{"uk", LANG_UKRAINIAN,SUBLANG_NEUTRAL},
+{"uk_UA", LANG_UKRAINIAN,SUBLANG_UKRAINIAN_UKRAINE},
+{"vi", LANG_VIETNAMESE,SUBLANG_NEUTRAL},
+{"vi_VN", LANG_VIETNAMESE,SUBLANG_VIETNAMESE_VIETNAM},
+{"zh", LANG_CHINESE,SUBLANG_NEUTRAL},
+{"zh_CN", LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED},
+{"zh_HK", LANG_CHINESE,SUBLANG_CHINESE_HONGKONG},
+{"zh_SG", LANG_CHINESE,SUBLANG_CHINESE_SINGAPORE},
+{0, 0,0},
+};
+
+#endif // LANG_TABLE_H
diff --git a/platform/windows/logo.png b/platform/windows/logo.png
new file mode 100644
index 0000000000..a27e14dde8
--- /dev/null
+++ b/platform/windows/logo.png
Binary files differ
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
new file mode 100644
index 0000000000..efeb813a2d
--- /dev/null
+++ b/platform/windows/os_windows.cpp
@@ -0,0 +1,1732 @@
+/*************************************************************************/
+/* os_windows.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "drivers/gles1/rasterizer_gles1.h"
+#include "os_windows.h"
+#include "drivers/nedmalloc/memory_pool_static_nedmalloc.h"
+#include "drivers/unix/memory_pool_static_malloc.h"
+#include "os/memory_pool_dynamic_static.h"
+#include "drivers/windows/thread_windows.h"
+#include "drivers/windows/semaphore_windows.h"
+#include "drivers/windows/mutex_windows.h"
+#include "main/main.h"
+#include "drivers/windows/file_access_windows.h"
+#include "drivers/windows/dir_access_windows.h"
+
+
+#include "servers/visual/visual_server_raster.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/visual/visual_server_wrap_mt.h"
+
+#include "tcp_server_winsock.h"
+#include "stream_peer_winsock.h"
+#include "os/pc_joystick_map.h"
+#include "lang_table.h"
+#include "os/memory_pool_dynamic_prealloc.h"
+#include "globals.h"
+#include "io/marshalls.h"
+static const WORD MAX_CONSOLE_LINES = 1500;
+
+//#define STDOUT_FILE
+
+extern HINSTANCE godot_hinstance;
+
+void RedirectIOToConsole() {
+
+ int hConHandle;
+
+ intptr_t lStdHandle;
+
+ CONSOLE_SCREEN_BUFFER_INFO coninfo;
+
+ FILE *fp;
+
+ // allocate a console for this app
+
+ AllocConsole();
+
+ // set the screen buffer to be big enough to let us scroll text
+
+ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
+
+ &coninfo);
+
+ coninfo.dwSize.Y = MAX_CONSOLE_LINES;
+
+ SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
+
+ coninfo.dwSize);
+
+ // redirect unbuffered STDOUT to the console
+
+ lStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
+
+ hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+
+ fp = _fdopen( hConHandle, "w" );
+
+ *stdout = *fp;
+
+ setvbuf( stdout, NULL, _IONBF, 0 );
+
+ // redirect unbuffered STDIN to the console
+
+ lStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE);
+
+ hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+
+ fp = _fdopen( hConHandle, "r" );
+
+ *stdin = *fp;
+
+ setvbuf( stdin, NULL, _IONBF, 0 );
+
+ // redirect unbuffered STDERR to the console
+
+ lStdHandle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE);
+
+ hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+
+ fp = _fdopen( hConHandle, "w" );
+
+ *stderr = *fp;
+
+ setvbuf( stderr, NULL, _IONBF, 0 );
+
+ // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
+
+ // point to console as well
+}
+
+int OS_Windows::get_video_driver_count() const {
+
+ return 2;
+}
+const char * OS_Windows::get_video_driver_name(int p_driver) const {
+
+ return p_driver==0?"GLES2":"GLES1";
+}
+
+OS::VideoMode OS_Windows::get_default_video_mode() const {
+
+ return VideoMode(800,600,false);
+}
+
+int OS_Windows::get_audio_driver_count() const {
+
+ return AudioDriverManagerSW::get_driver_count();
+}
+const char * OS_Windows::get_audio_driver_name(int p_driver) const {
+
+ AudioDriverSW* driver = AudioDriverManagerSW::get_driver(p_driver);
+ ERR_FAIL_COND_V( !driver, "" );
+ return AudioDriverManagerSW::get_driver(p_driver)->get_name();
+}
+
+static MemoryPoolStatic *mempool_static=NULL;
+static MemoryPoolDynamic *mempool_dynamic=NULL;
+
+void OS_Windows::initialize_core() {
+
+
+ last_button_state=0;
+
+ //RedirectIOToConsole();
+
+ ThreadWindows::make_default();
+ SemaphoreWindows::make_default();
+ MutexWindows::make_default();
+
+ FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA);
+ FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM);
+ //FileAccessBufferedFA<FileAccessWindows>::make_default();
+ DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES);
+ DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA);
+ DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM);
+
+ TCPServerWinsock::make_default();
+ StreamPeerWinsock::make_default();
+
+ mempool_static = new MemoryPoolStaticMalloc;
+#if 1
+ mempool_dynamic = memnew( MemoryPoolDynamicStatic );
+#else
+#define DYNPOOL_SIZE 4*1024*1024
+ void * buffer = malloc( DYNPOOL_SIZE );
+ mempool_dynamic = memnew( MemoryPoolDynamicPrealloc(buffer,DYNPOOL_SIZE) );
+
+#endif
+
+ // We need to know how often the clock is updated
+ if( !QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second) )
+ ticks_per_second = 1000;
+ // If timeAtGameStart is 0 then we get the time since
+ // the start of the computer when we call GetGameTime()
+ ticks_start = 0;
+ ticks_start = get_ticks_usec();
+
+ process_map = memnew((Map<ProcessID, ProcessInfo>));
+
+ IP_Unix::make_default();
+
+ cursor_shape=CURSOR_ARROW;
+
+
+}
+
+bool OS_Windows::can_draw() const {
+
+ return !minimized;
+};
+
+
+LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
+
+
+ switch (uMsg) // Check For Windows Messages
+ {
+ case WM_ACTIVATE: // Watch For Window Activate Message
+ {
+ minimized = HIWORD(wParam) != 0;
+ if (!main_loop) {
+ return 0;
+ };
+ if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) {
+
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+ alt_mem=false;
+ control_mem=false;
+ shift_mem=false;
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ RECT clipRect;
+ GetClientRect(hWnd, &clipRect);
+ ClientToScreen(hWnd, (POINT*) &clipRect.left);
+ ClientToScreen(hWnd, (POINT*) &clipRect.right);
+ ClipCursor(&clipRect);
+ SetCapture(hWnd);
+
+ }
+ } else {
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+ alt_mem=false;
+
+ };
+
+ return 0; // Return To The Message Loop
+ }
+
+ case WM_PAINT:
+
+ Main::force_redraw();
+ break;
+
+ case WM_SYSCOMMAND: // Intercept System Commands
+ {
+ switch (wParam) // Check System Calls
+ {
+ case SC_SCREENSAVE: // Screensaver Trying To Start?
+ case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
+ return 0; // Prevent From Happening
+ case SC_KEYMENU:
+ if ((lParam>>16)<=0)
+ return 0;
+ }
+ break; // Exit
+ }
+
+ case WM_CLOSE: // Did We Receive A Close Message?
+ {
+ if (main_loop)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+ //force_quit=true;
+ return 0; // Jump Back
+ }
+ case WM_MOUSELEAVE: {
+
+ old_invalid=true;
+ outside=true;
+
+ } break;
+ case WM_MOUSEMOVE: {
+
+ if (outside) {
+
+ CursorShape c=cursor_shape;
+ cursor_shape=CURSOR_MAX;
+ set_cursor_shape(c);
+ outside=false;
+
+ //Once-Off notification, must call again....
+ TRACKMOUSEEVENT tme;
+ tme.cbSize=sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags=TME_LEAVE;
+ tme.hwndTrack=hWnd;
+ tme.dwHoverTime=HOVER_DEFAULT;
+ TrackMouseEvent(&tme);
+
+ }
+ InputEvent event;
+ event.type=InputEvent::MOUSE_MOTION;
+ event.ID=++last_id;
+ InputEventMouseMotion &mm=event.mouse_motion;
+
+ mm.mod.control=(wParam&MK_CONTROL)!=0;
+ mm.mod.shift=(wParam&MK_SHIFT)!=0;
+ mm.mod.alt=alt_mem;
+
+ mm.button_mask|=(wParam&MK_LBUTTON)?(1<<0):0;
+ mm.button_mask|=(wParam&MK_RBUTTON)?(1<<1):0;
+ mm.button_mask|=(wParam&MK_MBUTTON)?(1<<2):0;
+ last_button_state=mm.button_mask;
+ /*mm.button_mask|=(wParam&MK_XBUTTON1)?(1<<5):0;
+ mm.button_mask|=(wParam&MK_XBUTTON2)?(1<<6):0;*/
+ mm.x=GET_X_LPARAM(lParam);
+ mm.y=GET_Y_LPARAM(lParam);
+
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+
+ Point2i c(video_mode.width/2,video_mode.height/2);
+ if (Point2i(mm.x,mm.y)==c) {
+ center=c;
+ return 0;
+ }
+
+ Point2i ncenter(mm.x,mm.y);
+ mm.x = old_x + (mm.x-center.x);
+ mm.y = old_y + (mm.y-center.y);
+ center=ncenter;
+ POINT pos = { (int) c.x, (int) c.y };
+ ClientToScreen(hWnd, &pos);
+ SetCursorPos(pos.x, pos.y);
+
+ }
+
+ input->set_mouse_pos(Point2(mm.x,mm.y));
+ mm.speed_x=input->get_mouse_speed().x;
+ mm.speed_y=input->get_mouse_speed().y;
+
+ if (old_invalid) {
+
+ old_x=mm.x;
+ old_y=mm.y;
+ old_invalid=false;
+ }
+
+ mm.relative_x=mm.x-old_x;
+ mm.relative_y=mm.y-old_y;
+ old_x=mm.x;
+ old_y=mm.y;
+ if (main_loop)
+ input->parse_input_event(event);
+
+
+
+ } break;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_MOUSEWHEEL:
+ case WM_LBUTTONDBLCLK:
+ /*case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP: */{
+
+ InputEvent event;
+ event.type=InputEvent::MOUSE_BUTTON;
+ event.ID=++last_id;
+ InputEventMouseButton &mb=event.mouse_button;
+
+ switch (uMsg) {
+ case WM_LBUTTONDOWN: {
+ mb.pressed=true;
+ mb.button_index=1;
+ } break;
+ case WM_LBUTTONUP: {
+ mb.pressed=false;
+ mb.button_index=1;
+ } break;
+ case WM_MBUTTONDOWN: {
+ mb.pressed=true;
+ mb.button_index=3;
+
+ } break;
+ case WM_MBUTTONUP: {
+ mb.pressed=false;
+ mb.button_index=3;
+ } break;
+ case WM_RBUTTONDOWN: {
+ mb.pressed=true;
+ mb.button_index=2;
+ } break;
+ case WM_RBUTTONUP: {
+ mb.pressed=false;
+ mb.button_index=2;
+ } break;
+ case WM_LBUTTONDBLCLK: {
+
+ mb.pressed=true;
+ mb.button_index=1;
+ mb.doubleclick = true;
+ } break;
+ case WM_MOUSEWHEEL: {
+
+ mb.pressed=true;
+ int motion = (short)HIWORD(wParam);
+ if (!motion)
+ return 0;
+
+
+ if (motion>0)
+ mb.button_index=4;
+ else
+ mb.button_index=5;
+
+
+ } break;
+ /*
+ case WM_XBUTTONDOWN: {
+ mb.pressed=true;
+ mb.button_index=(HIWORD(wParam)==XBUTTON1)?6:7;
+ } break;
+ case WM_XBUTTONUP:
+ mb.pressed=true;
+ mb.button_index=(HIWORD(wParam)==XBUTTON1)?6:7;
+ } break;*/
+ default: { return 0; }
+ }
+
+
+ mb.mod.control=(wParam&MK_CONTROL)!=0;
+ mb.mod.shift=(wParam&MK_SHIFT)!=0;
+ mb.mod.alt=alt_mem;
+ //mb.mod.alt=(wParam&MK_MENU)!=0;
+ mb.button_mask|=(wParam&MK_LBUTTON)?(1<<0):0;
+ mb.button_mask|=(wParam&MK_RBUTTON)?(1<<1):0;
+ mb.button_mask|=(wParam&MK_MBUTTON)?(1<<2):0;
+
+ last_button_state=mb.button_mask;
+ /*
+ mb.button_mask|=(wParam&MK_XBUTTON1)?(1<<5):0;
+ mb.button_mask|=(wParam&MK_XBUTTON2)?(1<<6):0;*/
+ mb.x=GET_X_LPARAM(lParam);
+ mb.y=GET_Y_LPARAM(lParam);
+
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+
+ mb.x=old_x;
+ mb.y=old_y;
+ }
+
+ mb.global_x=mb.x;
+ mb.global_y=mb.y;
+
+
+ if (uMsg != WM_MOUSEWHEEL) {
+ if (mb.pressed) {
+
+ if (++pressrc>0)
+ SetCapture(hWnd);
+ } else {
+
+
+ if (--pressrc<=0) {
+ ReleaseCapture();
+ pressrc=0;
+ }
+
+ }
+ } else if (mouse_mode!=MOUSE_MODE_CAPTURED) {
+ // for reasons unknown to mankind, wheel comes in screen cordinates
+ RECT rect;
+ GetWindowRect(hWnd,&rect);
+ mb.x-=rect.left;
+ mb.y-=rect.top;
+
+ }
+
+ if (main_loop) {
+ input->parse_input_event(event);
+ if (mb.pressed && mb.button_index>3) {
+ //send release for mouse wheel
+ mb.pressed=false;
+ event.ID=++last_id;
+ input->parse_input_event(event);
+
+ }
+ }
+
+
+
+ } break;
+
+ case WM_SIZE: {
+ video_mode.width=LOWORD(lParam);
+ video_mode.height=HIWORD(lParam);
+ //return 0; // Jump Back
+ } break;
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+ case WM_KEYDOWN: {
+
+
+ if (wParam==VK_SHIFT)
+ shift_mem=uMsg==WM_KEYDOWN;
+ if (wParam==VK_CONTROL)
+ control_mem=uMsg==WM_KEYDOWN;
+ if (wParam==VK_MENU) {
+ alt_mem=(uMsg==WM_KEYDOWN || uMsg==WM_SYSKEYDOWN);
+ if (lParam&(1<<24))
+ gr_mem=alt_mem;
+ }
+
+ //if (wParam==VK_WIN) TODO wtf is this?
+ // meta_mem=uMsg==WM_KEYDOWN;
+
+
+ } //fallthrough
+ case WM_CHAR: {
+
+ ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
+
+ KeyEvent ke;
+ ke.mod_state.shift=shift_mem;
+ ke.mod_state.alt=alt_mem;
+ ke.mod_state.control=control_mem;
+ ke.mod_state.meta=meta_mem;
+ ke.uMsg=uMsg;
+
+ if (ke.uMsg==WM_SYSKEYDOWN)
+ ke.uMsg=WM_KEYDOWN;
+ if (ke.uMsg==WM_SYSKEYUP)
+ ke.uMsg=WM_KEYUP;
+
+
+ /*if (ke.uMsg==WM_KEYDOWN && alt_mem && uMsg!=WM_SYSKEYDOWN) {
+ //altgr hack for intl keyboards, not sure how good it is
+ //windows is weeeeird
+ ke.mod_state.alt=false;
+ ke.mod_state.control=false;
+ print_line("")
+ }*/
+
+
+ ke.wParam=wParam;
+ ke.lParam=lParam;
+ key_event_buffer[key_event_pos++]=ke;
+
+ } break;
+ case WM_INPUTLANGCHANGEREQUEST: {
+
+ print_line("input lang change");
+ } break;
+ default: {
+
+ if (user_proc) {
+
+ return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
+ };
+ };
+ }
+
+ return DefWindowProcW(hWnd,uMsg,wParam,lParam);
+
+}
+
+LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
+
+ OS_Windows *os_win = static_cast<OS_Windows*>(OS::get_singleton());
+ if (os_win)
+ return os_win->WndProc(hWnd,uMsg,wParam,lParam);
+ else
+ return DefWindowProcW(hWnd,uMsg,wParam,lParam);
+
+}
+
+void OS_Windows::probe_joysticks() {
+
+ int device_count = joyGetNumDevs();
+
+ JOYINFOEX jinfo;
+ jinfo.dwSize = sizeof(JOYINFOEX);
+ jinfo.dwFlags = JOY_RETURNALL;
+
+ for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+ joysticks[i].attached = (device_count > 0) && (joyGetPosEx(JOYSTICKID1 + i, &jinfo) == JOYERR_NOERROR);
+
+ if (!joysticks[i].attached) {
+
+ continue;
+ };
+
+ joysticks[i].last_buttons = jinfo.dwButtons;
+
+ joysticks[i].last_axis[0] = jinfo.dwXpos;
+ joysticks[i].last_axis[1] = jinfo.dwYpos;
+ joysticks[i].last_axis[2] = jinfo.dwZpos;
+ joysticks[i].last_axis[3] = jinfo.dwRpos;
+ joysticks[i].last_axis[4] = jinfo.dwUpos;
+ joysticks[i].last_axis[5] = jinfo.dwVpos;
+ };
+};
+
+void OS_Windows::process_key_events() {
+
+ for(int i=0;i<key_event_pos;i++) {
+
+ KeyEvent &ke = key_event_buffer[i];
+ switch(ke.uMsg) {
+
+ case WM_CHAR: {
+
+ //do nothing
+ } break;
+ case WM_KEYUP:
+ case WM_KEYDOWN: {
+
+
+ InputEvent event;
+ event.type=InputEvent::KEY;
+ event.ID=++last_id;
+ InputEventKey &k=event.key;
+
+
+ k.mod=ke.mod_state;
+ k.pressed=(ke.uMsg==WM_KEYDOWN);
+
+ k.scancode=KeyMappingWindows::get_keysym(ke.wParam);
+ if (i+1 < key_event_pos && key_event_buffer[i+1].uMsg==WM_CHAR)
+ k.unicode=key_event_buffer[i+1].wParam;
+ if (k.unicode && gr_mem) {
+ k.mod.alt=false;
+ k.mod.control=false;
+ }
+
+ if (k.unicode<32)
+ k.unicode=0;
+
+
+
+ k.echo=(ke.uMsg==WM_KEYDOWN && (ke.lParam&(1<<30)));
+
+ input->parse_input_event(event);
+
+
+ } break;
+ }
+ }
+
+ key_event_pos=0;
+}
+
+void OS_Windows::_post_dpad(DWORD p_dpad, int p_device, bool p_pressed) {
+
+ InputEvent ievent;
+ ievent.device = p_device;
+ ievent.type = InputEvent::JOYSTICK_BUTTON;
+ ievent.joy_button.pressed = p_pressed;
+ ievent.joy_button.pressure = p_pressed ? 1.0 : 0.0;
+
+ if (p_dpad == 0) {
+
+ ievent.joy_button.button_index = JOY_DPAD_UP;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 4500) {
+
+ ievent.joy_button.button_index = JOY_DPAD_UP;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ ievent.joy_button.button_index = JOY_DPAD_RIGHT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 9000) {
+
+ ievent.joy_button.button_index = JOY_DPAD_RIGHT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 13500) {
+
+ ievent.joy_button.button_index = JOY_DPAD_RIGHT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ ievent.joy_button.button_index = JOY_DPAD_DOWN;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 18000) {
+
+ ievent.joy_button.button_index = JOY_DPAD_DOWN;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 22500) {
+
+ ievent.joy_button.button_index = JOY_DPAD_DOWN;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ ievent.joy_button.button_index = JOY_DPAD_LEFT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 27000) {
+
+ ievent.joy_button.button_index = JOY_DPAD_LEFT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ } else if (p_dpad == 31500) {
+
+ ievent.joy_button.button_index = JOY_DPAD_LEFT;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+
+ ievent.joy_button.button_index = JOY_DPAD_UP;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+ };
+};
+
+void OS_Windows::process_joysticks() {
+
+ if (!main_loop) {
+ return;
+ };
+
+ InputEvent ievent;
+
+ JOYINFOEX jinfo;
+ jinfo.dwSize = sizeof(JOYINFOEX);
+ jinfo.dwFlags = JOY_RETURNALL;
+
+ for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+ if (!joysticks[i].attached) {
+ continue;
+ };
+
+ if (joyGetPosEx(JOYSTICKID1 + i, &jinfo) != JOYERR_NOERROR) {
+
+ continue;
+ };
+
+ ievent.device = i;
+
+ #define CHECK_AXIS(n, var) \
+ if (joysticks[i].last_axis[n] != var) {\
+ ievent.type = InputEvent::JOYSTICK_MOTION;\
+ ievent.ID = ++last_id;\
+ ievent.joy_motion.axis = n;\
+ ievent.joy_motion.axis_value = (float)((int)var - MAX_JOY_AXIS) / (float)MAX_JOY_AXIS;\
+ joysticks[i].last_axis[n] = var;\
+ input->parse_input_event(ievent);\
+ };
+
+ CHECK_AXIS(0, jinfo.dwXpos);
+ CHECK_AXIS(1, jinfo.dwYpos);
+ CHECK_AXIS(2, jinfo.dwZpos);
+ CHECK_AXIS(3, jinfo.dwRpos);
+ CHECK_AXIS(4, jinfo.dwUpos);
+ CHECK_AXIS(5, jinfo.dwVpos);
+
+ if (joysticks[i].last_pov != jinfo.dwPOV) {
+
+ if (joysticks[i].last_pov != JOY_POVCENTERED)
+ _post_dpad(joysticks[i].last_pov, i, false);
+
+ if (jinfo.dwPOV != JOY_POVCENTERED)
+ _post_dpad(jinfo.dwPOV, i, true);
+
+ joysticks[i].last_pov = jinfo.dwPOV;
+ };
+
+ if (joysticks[i].last_buttons == jinfo.dwButtons) {
+ continue;
+ };
+
+ ievent.type = InputEvent::JOYSTICK_BUTTON;
+ for (int j=0; j<32; j++) {
+
+ if ( (joysticks[i].last_buttons & (1<<j)) != (jinfo.dwButtons & (1<<j)) ) {
+
+ ievent.joy_button.button_index = _pc_joystick_get_native_button(j);
+ ievent.joy_button.pressed = jinfo.dwButtons & 1<<j;
+ ievent.ID = ++last_id;
+ input->parse_input_event(ievent);
+ };
+ };
+
+ joysticks[i].last_buttons = jinfo.dwButtons;
+ };
+};
+
+void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+
+
+ main_loop=NULL;
+ outside=true;
+
+ WNDCLASSEXW wc;
+
+ video_mode=p_desired;
+ //printf("**************** desired %s, mode %s\n", p_desired.fullscreen?"true":"false", video_mode.fullscreen?"true":"false");
+ RECT WindowRect;
+
+ WindowRect.left=0;
+ WindowRect.right=video_mode.width;
+ WindowRect.top=0;
+ WindowRect.bottom=video_mode.height;
+
+ memset(&wc,0,sizeof(WNDCLASSEXW));
+ wc.cbSize=sizeof(WNDCLASSEXW);
+ wc.style= CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
+ wc.lpfnWndProc = (WNDPROC)::WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra= 0;
+ //wc.hInstance = hInstance;
+ wc.hInstance = godot_hinstance ? godot_hinstance : GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
+ wc.hCursor = NULL;//LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = L"Engine";
+
+ if (!RegisterClassExW(&wc)) {
+ MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return; // Return
+ }
+
+
+ if (video_mode.fullscreen) {
+
+ DEVMODE current;
+ memset(&current,0,sizeof(current));
+ EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &current);
+
+ DEVMODE dmScreenSettings;
+ memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
+ dmScreenSettings.dmSize=sizeof(dmScreenSettings);
+ dmScreenSettings.dmPelsWidth = video_mode.width;
+ dmScreenSettings.dmPelsHeight = video_mode.height;
+ dmScreenSettings.dmBitsPerPel = current.dmBitsPerPel;
+ dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
+
+ LONG err = ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);
+ if (err!=DISP_CHANGE_SUCCESSFUL) {
+
+ video_mode.fullscreen=false;
+ }
+ }
+
+ DWORD dwExStyle;
+ DWORD dwStyle;
+
+ if (video_mode.fullscreen) {
+
+ dwExStyle=WS_EX_APPWINDOW;
+ dwStyle=WS_POPUP;
+
+ } else {
+ dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
+ dwStyle=WS_OVERLAPPEDWINDOW;
+ }
+
+ AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
+
+
+ char* windowid = getenv("GODOT_WINDOWID");
+ if (windowid) {
+
+ // strtoull on mingw
+ #ifdef MINGW_ENABLED
+ hWnd = (HWND)strtoull(windowid, NULL, 0);
+ #else
+ hWnd = (HWND)_strtoui64(windowid, NULL, 0);
+ #endif
+ SetLastError(0);
+ user_proc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
+ SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)(WNDPROC)::WndProc);
+ DWORD le = GetLastError();
+ if (user_proc == 0 && le != 0) {
+
+ printf("Error setting WNDPROC: %li\n", le);
+ };
+ LONG_PTR proc = GetWindowLongPtr(hWnd, GWLP_WNDPROC);
+
+ RECT rect;
+ if (!GetClientRect(hWnd, &rect)) {
+ MessageBoxW(NULL,L"Window Creation Error.",L"ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return; // Return FALSE
+ };
+ video_mode.width = rect.right;
+ video_mode.height = rect.bottom;
+ video_mode.fullscreen = false;
+ } else {
+
+ if (!(hWnd=CreateWindowExW(dwExStyle,L"Engine",L"", dwStyle|WS_CLIPSIBLINGS|WS_CLIPCHILDREN, 0, 0,WindowRect.right-WindowRect.left,WindowRect.bottom-WindowRect.top, NULL,NULL, hInstance,NULL))) {
+ MessageBoxW(NULL,L"Window Creation Error.",L"ERROR",MB_OK|MB_ICONEXCLAMATION);
+ return; // Return FALSE
+ }
+
+
+ };
+
+#if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED) || defined(LEGACYGL_ENABLED)
+ gl_context = memnew( ContextGL_Win(hWnd,false) );
+ gl_context->initialize();
+ rasterizer = memnew( RasterizerGLES2 );
+#else
+ #ifdef DX9_ENABLED
+ rasterizer = memnew( RasterizerDX9(hWnd) );
+ #endif
+#endif
+
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+ if (get_render_thread_mode()!=RENDER_THREAD_UNSAFE) {
+
+ visual_server =memnew(VisualServerWrapMT(visual_server,get_render_thread_mode()==RENDER_SEPARATE_THREAD));
+ }
+
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ if (!is_no_window_mode_enabled()) {
+ ShowWindow(hWnd,SW_SHOW); // Show The Window
+ SetForegroundWindow(hWnd); // Slightly Higher Priority
+ SetFocus(hWnd); // Sets Keyboard Focus To
+ }
+
+/*
+ DEVMODE dmScreenSettings; // Device Mode
+ memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
+ dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure
+ dmScreenSettings.dmPelsWidth = width; // Selected Screen Width
+ dmScreenSettings.dmPelsHeight = height; // Selected Screen Height
+ dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel
+ dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
+ if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
+
+
+
+
+ */
+ visual_server->init();
+
+ input = memnew( InputDefault );
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+
+ audio_server->init();
+
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+ probe_joysticks();
+
+ TRACKMOUSEEVENT tme;
+ tme.cbSize=sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags=TME_LEAVE;
+ tme.hwndTrack=hWnd;
+ tme.dwHoverTime=HOVER_DEFAULT;
+ TrackMouseEvent(&tme);
+
+
+ _ensure_data_dir();
+
+
+}
+
+void OS_Windows::set_clipboard(const String& p_text) {
+
+ if (!OpenClipboard(hWnd)) {
+ ERR_EXPLAIN("Unable to open clipboard.");
+ ERR_FAIL();
+ };
+ EmptyClipboard();
+
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (p_text.length() + 1) * sizeof(CharType));
+ if (mem == NULL) {
+ ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
+ ERR_FAIL();
+ };
+ LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
+ memcpy(lptstrCopy, p_text.c_str(), (p_text.length() + 1) * sizeof(CharType));
+ //memset((lptstrCopy + p_text.length()), 0, sizeof(CharType));
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_UNICODETEXT, mem);
+
+ // set the CF_TEXT version (not needed?)
+ CharString utf8 = p_text.utf8();
+ mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
+ if (mem == NULL) {
+ ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
+ ERR_FAIL();
+ };
+ LPTSTR ptr = (LPTSTR)GlobalLock(mem);
+ memcpy(ptr, utf8.get_data(), utf8.length());
+ ptr[utf8.length()] = 0;
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_TEXT, mem);
+
+ CloseClipboard();
+};
+
+String OS_Windows::get_clipboard() const {
+
+ String ret;
+ if (!OpenClipboard(hWnd)) {
+ ERR_EXPLAIN("Unable to open clipboard.");
+ ERR_FAIL_V("");
+ };
+
+ if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem != NULL) {
+
+ LPWSTR ptr = (LPWSTR)GlobalLock(mem);
+ if (ptr != NULL) {
+
+ ret = String((CharType*)ptr);
+ GlobalUnlock(mem);
+ };
+ };
+
+ } else if (IsClipboardFormatAvailable(CF_TEXT)) {
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem != NULL) {
+
+ LPTSTR ptr = (LPTSTR)GlobalLock(mem);
+ if (ptr != NULL) {
+
+ ret.parse_utf8((const char*)ptr);
+ GlobalUnlock(mem);
+ };
+ };
+ };
+
+ CloseClipboard();
+
+ return ret;
+};
+
+
+void OS_Windows::delete_main_loop() {
+
+ if (main_loop)
+ memdelete(main_loop);
+ main_loop=NULL;
+}
+
+void OS_Windows::set_main_loop( MainLoop * p_main_loop ) {
+
+ input->set_main_loop(p_main_loop);
+ main_loop=p_main_loop;
+}
+
+void OS_Windows::finalize() {
+
+ if(main_loop)
+ memdelete(main_loop);
+
+ main_loop=NULL;
+
+ visual_server->finish();
+ memdelete(visual_server);
+#ifdef OPENGL_ENABLED
+ if (gl_context)
+ memdelete(gl_context);
+#endif
+ if (rasterizer)
+ memdelete(rasterizer);
+
+ if (user_proc) {
+ SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc);
+ };
+
+ spatial_sound_server->finish();
+ memdelete(spatial_sound_server);
+ spatial_sound_2d_server->finish();
+ memdelete(spatial_sound_2d_server);
+
+ //if (debugger_connection_console) {
+// memdelete(debugger_connection_console);
+//}
+
+ audio_server->finish();
+ memdelete(audio_server);
+ memdelete(sample_manager);
+
+ memdelete(input);
+
+ physics_server->finish();
+ memdelete(physics_server);
+
+ physics_2d_server->finish();
+ memdelete(physics_2d_server);
+
+}
+void OS_Windows::finalize_core() {
+
+ memdelete(process_map);
+
+ if (mempool_dynamic)
+ memdelete( mempool_dynamic );
+ if (mempool_static)
+ delete mempool_static;
+
+
+ TCPServerWinsock::cleanup();
+ StreamPeerWinsock::cleanup();
+}
+
+void OS_Windows::vprint(const char* p_format, va_list p_list, bool p_stderr) {
+
+ char buf[16384+1];
+ int len = vsnprintf(buf,16384,p_format,p_list);
+ if (len<=0)
+ return;
+ buf[len]=0;
+
+
+ int wlen = MultiByteToWideChar(CP_UTF8,0,buf,len,NULL,0);
+ if (wlen<0)
+ return;
+
+ wchar_t *wbuf = (wchar_t*)malloc((len+1)*sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8,0,buf,len,wbuf,wlen);
+ wbuf[wlen]=0;
+
+ if (p_stderr)
+ fwprintf(stderr,L"%s",wbuf);
+ else
+ wprintf(L"%s",wbuf);
+
+#ifdef STDOUT_FILE
+ //vwfprintf(stdo,p_format,p_list);
+#endif
+ free(wbuf);
+
+ fflush(stdout);
+};
+
+void OS_Windows::alert(const String& p_alert,const String& p_title) {
+
+ if (!is_no_window_mode_enabled())
+ MessageBoxW(NULL,p_alert.c_str(),p_title.c_str(),MB_OK|MB_ICONEXCLAMATION);
+ else
+ print_line("ALERT: "+p_alert);
+}
+
+void OS_Windows::set_mouse_mode(MouseMode p_mode) {
+
+ if (mouse_mode==p_mode)
+ return;
+ ShowCursor(p_mode==MOUSE_MODE_VISIBLE);
+ mouse_mode=p_mode;
+ if (p_mode==MOUSE_MODE_CAPTURED) {
+ RECT clipRect;
+ GetClientRect(hWnd, &clipRect);
+ ClientToScreen(hWnd, (POINT*) &clipRect.left);
+ ClientToScreen(hWnd, (POINT*) &clipRect.right);
+ ClipCursor(&clipRect);
+ SetCapture(hWnd);
+ center=Point2i(video_mode.width/2,video_mode.height/2);
+ POINT pos = { (int) center.x, (int) center.y };
+ ClientToScreen(hWnd, &pos);
+ SetCursorPos(pos.x, pos.y);
+ } else {
+ ReleaseCapture();
+ ClipCursor(NULL);
+ }
+
+}
+
+OS_Windows::MouseMode OS_Windows::get_mouse_mode() const{
+
+ return mouse_mode;
+}
+
+
+
+Point2 OS_Windows::get_mouse_pos() const {
+
+ return Point2(old_x, old_y);
+}
+
+int OS_Windows::get_mouse_button_state() const {
+
+ return last_button_state;
+}
+
+void OS_Windows::set_window_title(const String& p_title) {
+
+ SetWindowTextW(hWnd,p_title.c_str());
+}
+
+void OS_Windows::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+
+}
+OS::VideoMode OS_Windows::get_video_mode(int p_screen) const {
+
+ return video_mode;
+}
+void OS_Windows::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+
+}
+
+void OS_Windows::print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type) {
+
+ HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);
+ if (!hCon || hCon==INVALID_HANDLE_VALUE) {
+ if (p_rationale && p_rationale[0]) {
+
+ print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_rationale);
+ print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+
+ } else {
+ print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_code);
+ print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+
+ }
+ } else {
+
+ CONSOLE_SCREEN_BUFFER_INFO sbi; //original
+ GetConsoleScreenBufferInfo(hCon,&sbi);
+
+ SetConsoleTextAttribute(hCon,sbi.wAttributes);
+
+
+
+ uint32_t basecol=0;
+ switch(p_type) {
+ case ERR_ERROR: basecol = FOREGROUND_RED; break;
+ case ERR_WARNING: basecol = FOREGROUND_RED|FOREGROUND_GREEN; break;
+ case ERR_SCRIPT: basecol = FOREGROUND_GREEN; break;
+ }
+
+ if (p_rationale && p_rationale[0]) {
+
+ SetConsoleTextAttribute(hCon,basecol|FOREGROUND_INTENSITY);
+
+
+ switch(p_type) {
+ case ERR_ERROR: print("ERROR: "); break;
+ case ERR_WARNING: print("WARNING: "); break;
+ case ERR_SCRIPT: print("SCRIPT ERROR: "); break;
+ }
+
+ SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY);
+ print(" %s\n",p_rationale);
+ SetConsoleTextAttribute(hCon,basecol);
+ print("At: ");
+ SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
+ print(" %s:%i\n",p_file,p_line);
+
+
+ } else {
+ SetConsoleTextAttribute(hCon,basecol|FOREGROUND_INTENSITY);
+ switch(p_type) {
+ case ERR_ERROR: print("ERROR: %s: ",p_function); break;
+ case ERR_WARNING: print("WARNING: %s: ",p_function); break;
+ case ERR_SCRIPT: print("SCRIPT ERROR: %s: ",p_function); break;
+ }
+ SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY);
+ print(" %s\n",p_code);
+ SetConsoleTextAttribute(hCon,basecol);
+ print("At: ");
+ SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
+ print(" %s:%i\n",p_file,p_line);
+ }
+
+ SetConsoleTextAttribute(hCon,sbi.wAttributes);
+ }
+
+}
+
+
+String OS_Windows::get_name() {
+
+ return "Windows";
+}
+
+OS::Date OS_Windows::get_date() const {
+
+ SYSTEMTIME systemtime;
+ GetSystemTime(&systemtime);
+ Date date;
+ date.day=systemtime.wDay;
+ date.month=Month(systemtime.wMonth);
+ date.weekday=Weekday(systemtime.wDayOfWeek);
+ date.year=systemtime.wYear;
+ date.dst=false;
+ return date;
+}
+OS::Time OS_Windows::get_time() const {
+
+ SYSTEMTIME systemtime;
+ GetSystemTime(&systemtime);
+
+ Time time;
+ time.hour=systemtime.wHour;
+ time.min=systemtime.wMinute;
+ time.sec=systemtime.wSecond;
+ return time;
+}
+
+uint64_t OS_Windows::get_unix_time() const {
+
+ FILETIME ft;
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+
+ SYSTEMTIME ep;
+ ep.wYear = 1970;
+ ep.wMonth = 1;
+ ep.wDayOfWeek = 4;
+ ep.wDay = 1;
+ ep.wHour = 0;
+ ep.wMinute = 0;
+ ep.wSecond = 0;
+ ep.wMilliseconds = 0;
+ FILETIME fep;
+ SystemTimeToFileTime(&ep, &fep);
+
+ return (*(uint64_t*)&ft - *(uint64_t*)&fep) / 10000000;
+};
+
+void OS_Windows::delay_usec(uint32_t p_usec) const {
+
+ if (p_usec < 1000)
+ Sleep(1);
+ else
+ Sleep(p_usec / 1000);
+
+}
+uint64_t OS_Windows::get_ticks_usec() const {
+
+ uint64_t ticks;
+ uint64_t time;
+ // This is the number of clock ticks since start
+ if( !QueryPerformanceCounter((LARGE_INTEGER *)&ticks) )
+ ticks = (UINT64)timeGetTime();
+ // Divide by frequency to get the time in seconds
+ time = ticks * 1000000L / ticks_per_second;
+ // Subtract the time at game start to get
+ // the time since the game started
+ time -= ticks_start;
+ return time;
+}
+
+
+void OS_Windows::process_events() {
+
+ MSG msg;
+
+ process_joysticks();
+
+ while(PeekMessageW(&msg,NULL,0,0,PM_REMOVE)) {
+
+
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+
+ }
+
+ process_key_events();
+
+}
+
+void OS_Windows::set_cursor_shape(CursorShape p_shape) {
+
+ ERR_FAIL_INDEX(p_shape,CURSOR_MAX);
+
+ if (cursor_shape==p_shape)
+ return;
+
+ static const LPCTSTR win_cursors[CURSOR_MAX]={
+ IDC_ARROW,
+ IDC_IBEAM,
+ IDC_HAND,//finger
+ IDC_CROSS,
+ IDC_WAIT,
+ IDC_APPSTARTING,
+ IDC_ARROW,
+ IDC_ARROW,
+ IDC_NO,
+ IDC_SIZENS,
+ IDC_SIZEWE,
+ IDC_SIZENESW,
+ IDC_SIZENWSE,
+ IDC_SIZEALL,
+ IDC_SIZENS,
+ IDC_SIZEWE,
+ IDC_HELP
+ };
+
+ SetCursor(LoadCursor(hInstance,win_cursors[p_shape]));
+ cursor_shape=p_shape;
+}
+
+Error OS_Windows::execute(const String& p_path, const List<String>& p_arguments,bool p_blocking,ProcessID *r_child_id,String* r_pipe,int *r_exitcode) {
+
+ if (p_blocking && r_pipe) {
+
+
+ String argss;
+ argss="\"\""+p_path+"\"";
+
+ for(int i=0;i<p_arguments.size();i++) {
+
+ argss+=String(" \"")+p_arguments[i]+"\"";
+ }
+
+// print_line("ARGS: "+argss);
+ //argss+"\"";
+ //argss+=" 2>nul";
+
+ FILE* f=_wpopen(argss.c_str(),L"r");
+
+ ERR_FAIL_COND_V(!f,ERR_CANT_OPEN);
+
+ char buf[65535];
+ while(fgets(buf,65535,f)) {
+
+ (*r_pipe)+=buf;
+ }
+
+ int rv = _pclose(f);
+ if (r_exitcode)
+ *r_exitcode=rv;
+
+ return OK;
+ }
+
+ String cmdline = "\""+p_path+"\"";
+ const List<String>::Element* I = p_arguments.front();
+ while (I) {
+
+
+ cmdline += " \""+I->get() + "\"";
+
+ I = I->next();
+ };
+
+ //cmdline+="\"";
+
+ ProcessInfo pi;
+ ZeroMemory( &pi.si, sizeof(pi.si) );
+ pi.si.cb = sizeof(pi.si);
+ ZeroMemory( &pi.pi, sizeof(pi.pi) );
+
+ print_line("running cmdline: "+cmdline);
+
+ int ret = CreateProcess(NULL, (LPSTR)cmdline.utf8().get_data(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS, NULL, NULL, &pi.si, &pi.pi);
+ ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
+
+ if (p_blocking) {
+
+ DWORD ret = WaitForSingleObject(pi.pi.hProcess, INFINITE);
+ if (r_exitcode)
+ *r_exitcode=ret;
+
+ } else {
+
+ ProcessID pid = pi.pi.dwProcessId;
+ if (r_child_id) {
+ *r_child_id = pid;
+ };
+ process_map->insert(pid, pi);
+ };
+ return OK;
+};
+
+Error OS_Windows::kill(const ProcessID& p_pid) {
+
+ HANDLE h;
+
+ if (process_map->has(p_pid)) {
+ h = (*process_map)[p_pid].pi.hProcess;
+ process_map->erase(p_pid);
+ } else {
+
+ ERR_FAIL_COND_V(!process_map->has(p_pid), FAILED);
+ };
+
+ int ret = TerminateProcess(h, 0);
+
+ return ret != 0?OK:FAILED;
+};
+
+Error OS_Windows::set_cwd(const String& p_cwd) {
+
+ if (_wchdir(p_cwd.c_str())!=0)
+ return ERR_CANT_OPEN;
+
+ return OK;
+}
+
+void OS_Windows::set_icon(const Image& p_icon) {
+
+
+ Image icon=p_icon;
+ if (icon.get_format()!=Image::FORMAT_RGBA)
+ icon.convert(Image::FORMAT_RGBA);
+ int w = icon.get_width();
+ int h = icon.get_height();
+
+ /* Create temporary bitmap buffer */
+ int icon_len = 40 + h * w * 4;
+ BYTE *icon_bmp = (BYTE*)alloca(icon_len);
+
+ encode_uint32(40,&icon_bmp[0]);
+ encode_uint32(w,&icon_bmp[4]);
+ encode_uint32(h*2,&icon_bmp[8]);
+ encode_uint16(1,&icon_bmp[12]);
+ encode_uint16(32,&icon_bmp[14]);
+ encode_uint32(BI_RGB,&icon_bmp[16]);
+ encode_uint32(w*h*4,&icon_bmp[20]);
+ encode_uint32(0,&icon_bmp[24]);
+ encode_uint32(0,&icon_bmp[28]);
+ encode_uint32(0,&icon_bmp[32]);
+ encode_uint32(0,&icon_bmp[36]);
+
+ uint8_t *wr=&icon_bmp[40];
+ DVector<uint8_t>::Read r= icon.get_data().read();
+
+ for(int i=0;i<h;i++) {
+
+ for(int j=0;j<w;j++) {
+
+ const uint8_t *rpx = &r[((h-i-1)*w+j)*4];
+ uint8_t *wpx = &wr[(i*w+j)*4];
+ wpx[0]=rpx[2];
+ wpx[1]=rpx[1];
+ wpx[2]=rpx[0];
+ wpx[3]=rpx[3];
+ }
+ }
+
+
+ HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
+
+ /* Set the icon for the window */
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
+
+ /* Set the icon in the task manager (should we do this?) */
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
+}
+
+
+bool OS_Windows::has_environment(const String& p_var) const {
+
+ return getenv(p_var.utf8().get_data()) != NULL;
+};
+
+String OS_Windows::get_environment(const String& p_var) const {
+
+ return getenv(p_var.utf8().get_data());
+};
+
+String OS_Windows::get_stdin_string(bool p_block) {
+
+ if (p_block) {
+ char buff[1024];
+ return fgets(buff,1024,stdin);
+ };
+
+ return String();
+}
+
+
+void OS_Windows::move_window_to_foreground() {
+
+ SetForegroundWindow(hWnd);
+
+}
+
+String OS_Windows::get_locale() const {
+
+ const _WinLocale *wl = &_win_locales[0];
+
+ LANGID langid = GetUserDefaultUILanguage();
+ String neutral;
+ int lang = langid&((1<<9)-1);
+ int sublang = langid&~((1<<9)-1);
+
+ while(wl->locale) {
+
+ if (wl->main_lang==lang && wl->sublang==SUBLANG_NEUTRAL)
+ neutral=wl->locale;
+
+ if (lang==wl->main_lang && sublang==wl->sublang)
+ return wl->locale;
+
+
+ wl++;
+ }
+
+ if (neutral!="")
+ return neutral;
+
+ return "en";
+}
+
+void OS_Windows::release_rendering_thread() {
+
+ gl_context->release_current();
+
+}
+
+void OS_Windows::make_rendering_thread() {
+
+ gl_context->make_current();
+}
+
+void OS_Windows::swap_buffers() {
+
+ gl_context->swap_buffers();
+}
+
+
+void OS_Windows::run() {
+
+ if (!main_loop)
+ return;
+
+ main_loop->init();
+
+ uint64_t last_ticks=get_ticks_usec();
+
+ int frames=0;
+ uint64_t frame=0;
+
+ while (!force_quit) {
+
+ process_events(); // get rid of pending events
+ if (Main::iteration()==true)
+ break;
+ };
+
+ main_loop->finish();
+
+}
+
+
+
+MainLoop *OS_Windows::get_main_loop() const {
+
+ return main_loop;
+}
+
+
+String OS_Windows::get_data_dir() const {
+
+ String an = Globals::get_singleton()->get("application/name");
+ if (an!="") {
+
+ if (has_environment("APPDATA")) {
+
+ return OS::get_singleton()->get_environment("APPDATA")+"\\"+an;
+ }
+ }
+
+ return Globals::get_singleton()->get_resource_path();
+
+
+}
+
+
+OS_Windows::OS_Windows(HINSTANCE _hInstance) {
+
+ key_event_pos=0;
+ force_quit=false;
+ alt_mem=false;
+ gr_mem=false;
+ shift_mem=false;
+ control_mem=false;
+ meta_mem=false;
+ minimized = false;
+
+ hInstance=_hInstance;
+ pressrc=0;
+ old_invalid=true;
+ last_id=0;
+ mouse_mode=MOUSE_MODE_VISIBLE;
+#ifdef STDOUT_FILE
+ stdo=fopen("stdout.txt","wb");
+#endif
+ user_proc = NULL;
+
+#ifdef RTAUDIO_ENABLED
+ AudioDriverManagerSW::add_driver(&driver_rtaudio);
+#endif
+
+}
+
+
+OS_Windows::~OS_Windows()
+{
+#ifdef STDOUT_FILE
+ fclose(stdo);
+#endif
+}
+
+
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
new file mode 100644
index 0000000000..5587d89763
--- /dev/null
+++ b/platform/windows/os_windows.h
@@ -0,0 +1,257 @@
+/*************************************************************************/
+/* os_windows.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef OS_WINDOWS_H
+#define OS_WINDOWS_H
+
+#define WINVER 0x0500
+
+#include "os/input.h"
+#include "os/os.h"
+#include "context_gl_win.h"
+#include "servers/visual_server.h"
+#include "servers/visual/rasterizer.h"
+#include "servers/physics/physics_server_sw.h"
+
+#include "servers/audio/audio_server_sw.h"
+#include "servers/audio/sample_manager_sw.h"
+#include "drivers/rtaudio/audio_driver_rtaudio.h"
+#include "servers/spatial_sound/spatial_sound_server_sw.h"
+#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "drivers/unix/ip_unix.h"
+#include "servers/physics_2d/physics_2d_server_sw.h"
+
+
+#include <windows.h>
+
+#include "key_mapping_win.h"
+#include <windowsx.h>
+#include <io.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class OS_Windows : public OS {
+
+ enum {
+ JOYSTICKS_MAX = 8,
+ JOY_AXIS_COUNT = 6,
+ MAX_JOY_AXIS = 32768, // I've no idea
+ KEY_EVENT_BUFFER_SIZE=512
+ };
+
+ FILE *stdo;
+
+
+ struct KeyEvent {
+
+ InputModifierState mod_state;
+ UINT uMsg;
+ WPARAM wParam;
+ LPARAM lParam;
+
+ };
+
+ KeyEvent key_event_buffer[KEY_EVENT_BUFFER_SIZE];
+ int key_event_pos;
+
+
+ uint64_t ticks_start;
+ uint64_t ticks_per_second;
+
+ bool minimized;
+ bool old_invalid;
+ bool outside;
+ int old_x,old_y;
+ Point2i center;
+ unsigned int last_id;
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) || defined(GLES2_ENABLED)
+ ContextGL_Win *gl_context;
+#endif
+ VisualServer *visual_server;
+ Rasterizer *rasterizer;
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+ int pressrc;
+ HDC hDC; // Private GDI Device Context
+ HINSTANCE hInstance; // Holds The Instance Of The Application
+ HWND hWnd;
+
+ struct Joystick {
+
+ bool attached;
+
+ DWORD last_axis[JOY_AXIS_COUNT];
+ DWORD last_buttons;
+ DWORD last_pov;
+
+ Joystick() {
+ attached = false;
+ for (int i=0; i<JOY_AXIS_COUNT; i++) {
+
+ last_axis[i] = 0;
+ };
+ last_buttons = 0;
+ last_pov = 0;
+ };
+ };
+
+ int joystick_count;
+ Joystick joysticks[JOYSTICKS_MAX];
+
+ VideoMode video_mode;
+
+ MainLoop *main_loop;
+
+ WNDPROC user_proc;
+
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+
+ MouseMode mouse_mode;
+ bool alt_mem;
+ bool gr_mem;
+ bool shift_mem;
+ bool control_mem;
+ bool meta_mem;
+ bool force_quit;
+ uint32_t last_button_state;
+
+ CursorShape cursor_shape;
+
+ InputDefault *input;
+
+#ifdef RTAUDIO_ENABLED
+ AudioDriverRtAudio driver_rtaudio;
+#endif
+
+ void _post_dpad(DWORD p_dpad, int p_device, bool p_pressed);
+
+ // functions used by main to initialize/deintialize the OS
+protected:
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
+ virtual void initialize_core();
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+ virtual void finalize_core();
+
+ void process_events();
+
+ void probe_joysticks();
+ void process_joysticks();
+ void process_key_events();
+
+ struct ProcessInfo {
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ };
+ Map<ProcessID, ProcessInfo>* process_map;
+
+public:
+ LRESULT WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+
+ 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);
+
+ virtual void vprint(const char *p_format, va_list p_list, bool p_stderr=false);
+ virtual void alert(const String& p_alert,const String& p_title="ALERT!");
+ String get_stdin_string(bool p_block);
+
+ void set_mouse_mode(MouseMode p_mode);
+ MouseMode get_mouse_mode() const;
+
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ 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 MainLoop *get_main_loop() const;
+
+ virtual String get_name();
+
+ virtual Date get_date() const;
+ virtual Time get_time() const;
+ virtual uint64_t get_unix_time() const;
+
+ virtual bool can_draw() const;
+ virtual Error set_cwd(const String& p_cwd);
+
+ virtual void delay_usec(uint32_t p_usec) const;
+ virtual uint64_t get_ticks_usec() const;
+
+ virtual Error execute(const String& p_path, const List<String>& p_arguments,bool p_blocking,ProcessID *r_child_id=NULL,String* r_pipe=NULL,int *r_exitcode=NULL);
+ virtual Error kill(const ProcessID& p_pid);
+
+ virtual bool has_environment(const String& p_var) const;
+ virtual String get_environment(const String& p_var) const;
+
+ virtual void set_clipboard(const String& p_text);
+ virtual String get_clipboard() const;
+
+ void set_cursor_shape(CursorShape p_shape);
+ void set_icon(const Image& p_icon);
+
+
+ virtual String get_locale() const;
+
+ virtual void move_window_to_foreground();
+ virtual String get_data_dir() const;
+
+ virtual void release_rendering_thread();
+ virtual void make_rendering_thread();
+ virtual void swap_buffers();
+
+ void run();
+
+ virtual bool get_swap_ok_cancel() { return true; }
+
+ OS_Windows(HINSTANCE _hInstance);
+ ~OS_Windows();
+
+};
+
+#endif
diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h
new file mode 100644
index 0000000000..7bc3e42833
--- /dev/null
+++ b/platform/windows/platform_config.h
@@ -0,0 +1,35 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <malloc.h>
+//#else
+//#include <alloca.h>
+//#endif
+#define GLES2_INCLUDE_H "gl_context/glew.h"
+#define GLES1_INCLUDE_H "gl_context/glew.h"
+
diff --git a/platform/windows/stream_peer_winsock.cpp b/platform/windows/stream_peer_winsock.cpp
new file mode 100644
index 0000000000..2c3a8db7b1
--- /dev/null
+++ b/platform/windows/stream_peer_winsock.cpp
@@ -0,0 +1,368 @@
+/*************************************************************************/
+/* stream_peer_winsock.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef WINDOWS_ENABLED
+
+#include "stream_peer_winsock.h"
+
+#include <winsock2.h>
+
+int winsock_refcount = 0;
+
+static void set_addr_in(struct sockaddr_in& their_addr, const IP_Address& p_host, uint16_t p_port) {
+
+ their_addr.sin_family = AF_INET; // host byte order
+ their_addr.sin_port = htons(p_port); // short, network byte order
+ their_addr.sin_addr = *((struct in_addr*)&p_host.host);
+ memset(&(their_addr.sin_zero), '\0', 8);
+};
+
+StreamPeerTCP* StreamPeerWinsock::_create() {
+
+ return memnew(StreamPeerWinsock);
+};
+
+void StreamPeerWinsock::make_default() {
+
+ StreamPeerTCP::_create = StreamPeerWinsock::_create;
+
+ if (winsock_refcount == 0) {
+ WSADATA data;
+ WSAStartup(MAKEWORD(2,2), &data);
+ };
+ ++winsock_refcount;
+};
+
+void StreamPeerWinsock::cleanup() {
+
+ --winsock_refcount;
+ if (winsock_refcount == 0) {
+
+ WSACleanup();
+ };
+};
+
+
+Error StreamPeerWinsock::_block(int p_sockfd, bool p_read, bool p_write) const {
+
+ fd_set read, write;
+ FD_ZERO(&read);
+ FD_ZERO(&write);
+
+ if (p_read)
+ FD_SET(p_sockfd, &read);
+ if (p_write)
+ FD_SET(p_sockfd, &write);
+
+ int ret = select(p_sockfd + 1, &read, &write, NULL, NULL); // block forever
+ return ret < 0 ? FAILED : OK;
+};
+
+Error StreamPeerWinsock::_poll_connection(bool p_block) const {
+
+ ERR_FAIL_COND_V(status != STATUS_CONNECTING || sockfd == INVALID_SOCKET, FAILED);
+
+ if (p_block) {
+
+ _block(sockfd, false, true);
+ };
+
+ struct sockaddr_in their_addr;
+ set_addr_in(their_addr, peer_host, peer_port);
+
+ if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == SOCKET_ERROR) {
+
+ int err = WSAGetLastError();
+ if (err == WSAEISCONN) {
+ status = STATUS_CONNECTED;
+ return OK;
+ };
+
+ return OK;
+ } else {
+
+ status = STATUS_CONNECTED;
+ return OK;
+ };
+
+ return OK;
+};
+
+Error StreamPeerWinsock::write(const uint8_t* p_data,int p_bytes, int &r_sent, bool p_block) {
+
+ if (status == STATUS_NONE || status == STATUS_ERROR) {
+
+ return FAILED;
+ };
+
+ if (status != STATUS_CONNECTED) {
+
+ if (_poll_connection(p_block) != OK) {
+
+ return FAILED;
+ };
+
+ if (status != STATUS_CONNECTED) {
+ r_sent = 0;
+ return OK;
+ };
+ };
+
+ int data_to_send = p_bytes;
+ const uint8_t *offset = p_data;
+ if (sockfd == -1) return FAILED;
+ errno = 0;
+ int total_sent = 0;
+
+ while (data_to_send) {
+
+ int sent_amount = send(sockfd, (const char*)offset, data_to_send, 0);
+ //printf("Sent TCP data of %d bytes, errno %d\n", sent_amount, errno);
+
+ if (sent_amount == -1) {
+
+ if (WSAGetLastError() != WSAEWOULDBLOCK) {
+
+ perror("shit?");
+ disconnect();
+ ERR_PRINT("Server disconnected!\n");
+ return FAILED;
+ };
+
+ if (!p_block) {
+ r_sent = total_sent;
+ return OK;
+ };
+
+ _block(sockfd, false, true);
+ } else {
+
+ data_to_send -= sent_amount;
+ offset += sent_amount;
+ total_sent += sent_amount;
+ };
+ }
+
+ r_sent = total_sent;
+
+ return OK;
+};
+
+Error StreamPeerWinsock::read(uint8_t* p_buffer, int p_bytes,int &r_received, bool p_block) {
+
+ if (!is_connected()) {
+
+ return FAILED;
+ };
+
+ if (status != STATUS_CONNECTED) {
+
+ if (_poll_connection(p_block) != OK) {
+
+ return FAILED;
+ };
+
+ if (status != STATUS_CONNECTED) {
+ r_received = 0;
+ return OK;
+ };
+ };
+
+ int to_read = p_bytes;
+ int total_read = 0;
+ errno = 0;
+
+ while (to_read) {
+
+ int read = recv(sockfd, (char*)p_buffer + total_read, to_read, 0);
+
+ if (read == -1) {
+
+ if (WSAGetLastError() != WSAEWOULDBLOCK) {
+
+ perror("shit?");
+ disconnect();
+ ERR_PRINT("Server disconnected!\n");
+ return FAILED;
+ };
+
+ if (!p_block) {
+
+ r_received = total_read;
+ return OK;
+ };
+ _block(sockfd, true, false);
+ } else if (read == 0) {
+ disconnect();
+ return ERR_FILE_EOF;
+ } else {
+
+ to_read -= read;
+ total_read += read;
+ };
+ };
+
+ r_received = total_read;
+
+ return OK;
+};
+
+Error StreamPeerWinsock::put_data(const uint8_t* p_data,int p_bytes) {
+
+ int total;
+ return write(p_data, p_bytes, total, true);
+};
+
+Error StreamPeerWinsock::put_partial_data(const uint8_t* p_data,int p_bytes, int &r_sent) {
+
+ return write(p_data, p_bytes, r_sent, false);
+};
+
+Error StreamPeerWinsock::get_data(uint8_t* p_buffer, int p_bytes) {
+
+ int total;
+ return read(p_buffer, p_bytes, total, true);
+};
+
+Error StreamPeerWinsock::get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received) {
+
+ return read(p_buffer, p_bytes, r_received, false);
+};
+
+StreamPeerTCP::Status StreamPeerWinsock::get_status() const {
+
+ if (status == STATUS_CONNECTING) {
+ _poll_connection(false);
+ };
+
+ return status;
+};
+
+
+bool StreamPeerWinsock::is_connected() const {
+
+ if (status == STATUS_NONE || status == STATUS_ERROR) {
+
+ return false;
+ };
+ if (status != STATUS_CONNECTED) {
+ return true;
+ };
+
+ return (sockfd!=INVALID_SOCKET);
+};
+
+void StreamPeerWinsock::disconnect() {
+
+ if (sockfd != INVALID_SOCKET)
+ closesocket(sockfd);
+ sockfd=INVALID_SOCKET;
+
+ status = STATUS_NONE;
+
+ peer_host = IP_Address();
+ peer_port = 0;
+};
+
+void StreamPeerWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port) {
+
+ sockfd = p_sockfd;
+ status = STATUS_CONNECTING;
+ peer_host = p_host;
+ peer_port = p_port;
+};
+
+Error StreamPeerWinsock::connect(const IP_Address& p_host, uint16_t p_port) {
+
+ ERR_FAIL_COND_V( p_host.host == 0, ERR_INVALID_PARAMETER);
+
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
+ ERR_PRINT("Socket creation failed!");
+ disconnect();
+ //perror("socket");
+ return FAILED;
+ };
+
+ unsigned long par = 1;
+ if (ioctlsocket(sockfd, FIONBIO, &par)) {
+ perror("setting non-block mode");
+ disconnect();
+ return FAILED;
+ };
+
+ struct sockaddr_in their_addr;
+ set_addr_in(their_addr, p_host, p_port);
+
+ if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == SOCKET_ERROR) {
+
+ if (WSAGetLastError() != WSAEWOULDBLOCK) {
+ ERR_PRINT("Connection to remote host failed!");
+ disconnect();
+ return FAILED;
+ };
+ status = STATUS_CONNECTING;
+ } else {
+ status = STATUS_CONNECTED;
+ };
+
+ peer_host = p_host;
+ peer_port = p_port;
+
+ return OK;
+};
+
+void StreamPeerWinsock::set_nodelay(bool p_enabled) {
+
+
+}
+
+
+IP_Address StreamPeerWinsock::get_connected_host() const {
+
+ return peer_host;
+};
+
+uint16_t StreamPeerWinsock::get_connected_port() const {
+
+ return peer_port;
+};
+
+StreamPeerWinsock::StreamPeerWinsock() {
+
+ sockfd = INVALID_SOCKET;
+ status = STATUS_NONE;
+ peer_port = 0;
+};
+
+StreamPeerWinsock::~StreamPeerWinsock() {
+
+ disconnect();
+};
+
+
+#endif
diff --git a/platform/windows/stream_peer_winsock.h b/platform/windows/stream_peer_winsock.h
new file mode 100644
index 0000000000..14dd5f0bb1
--- /dev/null
+++ b/platform/windows/stream_peer_winsock.h
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* stream_peer_winsock.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef WINDOWS_ENABLED
+
+#ifndef STREAM_PEER_WINSOCK_H
+#define STREAM_PEER_WINSOCK_H
+
+#include "error_list.h"
+
+#include "core/io/ip_address.h"
+#include "core/io/stream_peer_tcp.h"
+
+class StreamPeerWinsock : public StreamPeerTCP {
+
+protected:
+
+ mutable Status status;
+
+ int sockfd;
+
+ Error _block(int p_sockfd, bool p_read, bool p_write) const;
+
+ Error _poll_connection(bool p_block) const;
+
+ IP_Address peer_host;
+ int peer_port;
+
+ Error write(const uint8_t* p_data,int p_bytes, int &r_sent, bool p_block);
+ Error read(uint8_t* p_buffer, int p_bytes,int &r_received, bool p_block);
+
+ static StreamPeerTCP* _create();
+
+public:
+
+ virtual Error connect(const IP_Address& p_host, uint16_t p_port);
+
+ virtual Error put_data(const uint8_t* p_data,int p_bytes);
+ virtual Error put_partial_data(const uint8_t* p_data,int p_bytes, int &r_sent);
+
+ virtual Error get_data(uint8_t* p_buffer, int p_bytes);
+ virtual Error get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received);
+
+ void set_socket(int p_sockfd, IP_Address p_host, int p_port);
+
+ virtual IP_Address get_connected_host() const;
+ virtual uint16_t get_connected_port() const;
+
+ virtual bool is_connected() const;
+ virtual Status get_status() const;
+ virtual void disconnect();
+
+ static void make_default();
+ static void cleanup();
+
+ virtual void set_nodelay(bool p_enabled);
+
+
+ StreamPeerWinsock();
+ ~StreamPeerWinsock();
+};
+
+#endif // TCP_SOCKET_POSIX_H
+
+#endif
diff --git a/platform/windows/tcp_server_winsock.cpp b/platform/windows/tcp_server_winsock.cpp
new file mode 100644
index 0000000000..7b35bcc7ad
--- /dev/null
+++ b/platform/windows/tcp_server_winsock.cpp
@@ -0,0 +1,166 @@
+/*************************************************************************/
+/* tcp_server_winsock.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "tcp_server_winsock.h"
+
+#include "stream_peer_winsock.h"
+
+#include <winsock2.h>
+
+extern int winsock_refcount;
+
+TCP_Server* TCPServerWinsock::_create() {
+
+ return memnew(TCPServerWinsock);
+};
+
+void TCPServerWinsock::make_default() {
+
+ TCP_Server::_create = TCPServerWinsock::_create;
+
+ if (winsock_refcount == 0) {
+ WSADATA data;
+ WSAStartup(MAKEWORD(2,2), &data);
+ };
+ ++winsock_refcount;
+};
+
+void TCPServerWinsock::cleanup() {
+
+ --winsock_refcount;
+ if (winsock_refcount == 0) {
+
+ WSACleanup();
+ };
+};
+
+
+Error TCPServerWinsock::listen(uint16_t p_port,const List<String> *p_accepted_hosts) {
+
+ int sockfd;
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ ERR_FAIL_COND_V(sockfd == INVALID_SOCKET, FAILED);
+
+ unsigned long par = 1;
+ if (ioctlsocket(sockfd, FIONBIO, &par)) {
+ perror("setting non-block mode");
+ stop();
+ return FAILED;
+ };
+
+ struct sockaddr_in my_addr;
+ my_addr.sin_family = AF_INET; // host byte order
+ my_addr.sin_port = htons(p_port); // short, network byte order
+ my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP TODO: use p_accepted_hosts
+ memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
+
+ if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) != SOCKET_ERROR) {
+
+ if (::listen(sockfd, SOMAXCONN) == SOCKET_ERROR) {
+
+ closesocket(sockfd);
+ ERR_FAIL_V(FAILED);
+ };
+ };
+
+ if (listen_sockfd != INVALID_SOCKET) {
+
+ stop();
+ };
+
+ listen_sockfd = sockfd;
+
+ return OK;
+};
+
+bool TCPServerWinsock::is_connection_available() const {
+
+ if (listen_sockfd == -1) {
+ return false;
+ };
+
+ timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ fd_set pfd;
+ FD_ZERO(&pfd);
+ FD_SET(listen_sockfd, &pfd);
+
+ int ret = select(listen_sockfd + 1, &pfd, NULL, NULL, &timeout);
+ ERR_FAIL_COND_V(ret < 0, 0);
+
+ if (ret && (FD_ISSET(listen_sockfd, &pfd))) {
+
+ return true;
+ };
+
+ return false;
+};
+
+
+Ref<StreamPeerTCP> TCPServerWinsock::take_connection() {
+
+ if (!is_connection_available()) {
+ return NULL;
+ };
+
+ struct sockaddr_in their_addr;
+ int sin_size = sizeof(their_addr);
+ int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &sin_size);
+ ERR_FAIL_COND_V(fd == INVALID_SOCKET, NULL);
+
+ Ref<StreamPeerWinsock> conn = memnew(StreamPeerWinsock);
+ IP_Address ip;
+ ip.host = (uint32_t)their_addr.sin_addr.s_addr;
+
+ conn->set_socket(fd, ip, ntohs(their_addr.sin_port));
+
+ return conn;
+};
+
+void TCPServerWinsock::stop() {
+
+ if (listen_sockfd != INVALID_SOCKET) {
+ closesocket(listen_sockfd);
+ };
+
+ listen_sockfd = -1;
+};
+
+
+TCPServerWinsock::TCPServerWinsock() {
+
+ listen_sockfd = INVALID_SOCKET;
+};
+
+TCPServerWinsock::~TCPServerWinsock() {
+
+ stop();
+};
+
diff --git a/platform/windows/tcp_server_winsock.h b/platform/windows/tcp_server_winsock.h
new file mode 100644
index 0000000000..2d54b6ce40
--- /dev/null
+++ b/platform/windows/tcp_server_winsock.h
@@ -0,0 +1,55 @@
+/*************************************************************************/
+/* tcp_server_winsock.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TCP_SERVER_WINSOCK_H
+#define TCP_SERVER_WINSOCK_H
+
+#include "core/io/tcp_server.h"
+
+class TCPServerWinsock : public TCP_Server {
+
+ int listen_sockfd;
+
+ static TCP_Server* _create();
+
+public:
+
+ virtual Error listen(uint16_t p_port,const List<String> *p_accepted_hosts=NULL);
+ virtual bool is_connection_available() const;
+ virtual Ref<StreamPeerTCP> take_connection();
+
+ virtual void stop(); //stop listening
+
+ static void make_default();
+ static void cleanup();
+
+ TCPServerWinsock();
+ ~TCPServerWinsock();
+};
+
+#endif
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
new file mode 100644
index 0000000000..0644ba52ec
--- /dev/null
+++ b/platform/x11/SCsub
@@ -0,0 +1,13 @@
+Import('env')
+
+
+common_x11=[\
+ "context_gl_x11.cpp",\
+ "os_x11.cpp",\
+ "key_mapping_x11.cpp",\
+]
+
+if env["target"]=="release":
+ env.Program('#bin/godot_rel',['godot_x11.cpp']+common_x11)
+else:
+ env.Program('#bin/godot',['godot_x11.cpp']+common_x11)
diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp
new file mode 100644
index 0000000000..12708f52e2
--- /dev/null
+++ b/platform/x11/context_gl_x11.cpp
@@ -0,0 +1,197 @@
+/*************************************************************************/
+/* context_gl_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "context_gl_x11.h"
+
+#ifdef X11_ENABLED
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <GL/glx.h>
+
+#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
+
+typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
+
+struct ContextGL_X11_Private {
+
+ ::GLXContext glx_context;
+};
+
+
+void ContextGL_X11::release_current() {
+
+ glXMakeCurrent(x11_display, None, NULL);
+}
+
+void ContextGL_X11::make_current() {
+
+ glXMakeCurrent(x11_display, x11_window, p->glx_context);
+}
+void ContextGL_X11::swap_buffers() {
+
+ glXSwapBuffers(x11_display,x11_window);
+}
+/*
+static GLWrapperFuncPtr wrapper_get_proc_address(const char* p_function) {
+
+ //print_line(String()+"getting proc of: "+p_function);
+ GLWrapperFuncPtr func=(GLWrapperFuncPtr)glXGetProcAddress( (const GLubyte*) p_function);
+ if (!func) {
+ print_line("Couldn't find function: "+String(p_function));
+ }
+
+ return func;
+
+}*/
+
+Error ContextGL_X11::initialize() {
+
+
+ GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = NULL;
+
+// const char *extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
+
+ glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
+
+ ERR_FAIL_COND_V( !glXCreateContextAttribsARB, ERR_UNCONFIGURED );
+
+
+ static int visual_attribs[] = {
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_DOUBLEBUFFER, true,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE,0,
+ None
+ };
+
+ int fbcount;
+ GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
+ ERR_FAIL_COND_V(!fbc,ERR_UNCONFIGURED);
+
+ XVisualInfo *vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
+
+ XSetWindowAttributes swa;
+
+ swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
+ swa.border_pixel = 0;
+ swa.event_mask = StructureNotifyMask;
+
+ /*
+ char* windowid = getenv("GODOT_WINDOWID");
+ if (windowid) {
+
+ //freopen("/home/punto/stdout", "w", stdout);
+ //reopen("/home/punto/stderr", "w", stderr);
+ x11_window = atol(windowid);
+ } else {
+ */
+ x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa);
+ ERR_FAIL_COND_V(!x11_window,ERR_UNCONFIGURED);
+ XMapWindow(x11_display, x11_window);
+ while(true) {
+ // wait for mapnotify (window created)
+ XEvent e;
+ XNextEvent(x11_display, &e);
+ if (e.type == MapNotify)
+ break;
+ }
+ //};
+
+ if (!opengl_3_context) {
+ //oldstyle context:
+ p->glx_context = glXCreateContext(x11_display, vi, 0, GL_TRUE);
+ } else {
+ static int context_attribs[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+ None
+ };
+
+ p->glx_context = glXCreateContextAttribsARB(x11_display, fbc[0], NULL, true, context_attribs);
+ ERR_FAIL_COND_V(!p->glx_context,ERR_UNCONFIGURED);
+ }
+
+ glXMakeCurrent(x11_display, x11_window, p->glx_context);
+
+ /*
+ glWrapperInit(wrapper_get_proc_address);
+ glFlush();
+
+ glXSwapBuffers(x11_display,x11_window);
+*/
+ //glXMakeCurrent(x11_display, None, NULL);
+
+ return OK;
+}
+
+int ContextGL_X11::get_window_width() {
+
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display,x11_window,&xwa);
+
+ return xwa.width;
+}
+int ContextGL_X11::get_window_height() {
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display,x11_window,&xwa);
+
+ return xwa.height;
+
+}
+
+
+ContextGL_X11::ContextGL_X11(::Display *p_x11_display,::Window &p_x11_window,const OS::VideoMode& p_default_video_mode,bool p_opengl_3_context) : x11_window(p_x11_window) {
+
+ default_video_mode=p_default_video_mode;
+ x11_display=p_x11_display;
+
+ opengl_3_context=p_opengl_3_context;
+
+ double_buffer=false;
+ direct_render=false;
+ glx_minor=glx_major=0;
+ p = memnew( ContextGL_X11_Private );
+ p->glx_context=0;
+}
+
+
+ContextGL_X11::~ContextGL_X11() {
+
+ memdelete( p );
+}
+
+
+#endif
+#endif
diff --git a/platform/x11/context_gl_x11.h b/platform/x11/context_gl_x11.h
new file mode 100644
index 0000000000..20a858bcdd
--- /dev/null
+++ b/platform/x11/context_gl_x11.h
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* context_gl_x11.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CONTEXT_GL_X11_H
+#define CONTEXT_GL_X11_H
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+#ifdef X11_ENABLED
+
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+
+
+
+#include "os/os.h"
+#include "drivers/gl_context/context_gl.h"
+#include <X11/Xlib.h>
+
+struct ContextGL_X11_Private;
+
+class ContextGL_X11 : public ContextGL {
+
+ ContextGL_X11_Private *p;
+ OS::VideoMode default_video_mode;
+// ::Colormap x11_colormap;
+ ::Display *x11_display;
+ ::Window& x11_window;
+ bool double_buffer;
+ bool direct_render;
+ int glx_minor,glx_major;
+ bool opengl_3_context;
+public:
+
+ virtual void release_current();
+ virtual void make_current();
+ virtual void swap_buffers();
+ virtual int get_window_width();
+ virtual int get_window_height();
+
+ virtual Error initialize();
+
+ ContextGL_X11(::Display *p_x11_display,::Window &p_x11_window,const OS::VideoMode& p_default_video_mode,bool p_opengl_3_context);
+ ~ContextGL_X11();
+
+};
+
+#endif
+
+#endif
+#endif
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
new file mode 100644
index 0000000000..38f697ef10
--- /dev/null
+++ b/platform/x11/detect.py
@@ -0,0 +1,146 @@
+
+import os
+import sys
+
+
+def is_active():
+ return True
+
+def get_name():
+ return "X11"
+
+
+def can_build():
+
+ if (os.name!="posix"):
+ return False
+
+ if sys.platform == "darwin":
+ return False # no x11 on mac for now
+
+ errorval=os.system("pkg-config --version > /dev/null")
+
+ if (errorval):
+ print("pkg-config not found.. x11 disabled.")
+ return False
+
+ x11_error=os.system("pkg-config x11 --modversion > /dev/null ")
+ if (x11_error):
+ print("X11 not found.. x11 disabled.")
+ return False
+
+ x11_error=os.system("pkg-config xcursor --modversion > /dev/null ")
+ if (x11_error):
+ print("xcursor not found.. x11 disabled.")
+ return False
+
+ return True # X11 enabled
+
+def get_opts():
+
+ return [
+ ('use_llvm','Use llvm compiler','no'),
+ ('use_sanitizer','Use llvm compiler sanitize address','no'),
+ ('force_32_bits','Force 32 bits binary','no')
+ ]
+
+def get_flags():
+
+ return [
+ ('opengl', 'no'),
+ ('legacygl', 'yes'),
+ ('builtin_zlib', 'no'),
+ ]
+
+
+
+def configure(env):
+
+ env.Append(CPPPATH=['#platform/x11'])
+ if (env["use_llvm"]=="yes"):
+ env["CC"]="clang"
+ env["CXX"]="clang++"
+ env["LD"]="clang++"
+ if (env["use_sanitizer"]=="yes"):
+ env.Append(CXXFLAGS=['-fsanitize=address','-fno-omit-frame-pointer'])
+ env.Append(LINKFLAGS=['-fsanitize=address'])
+
+
+
+ if (env["tools"]=="no"):
+ #no tools suffix
+ env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX']
+
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-O2','-ffast-math','-fomit-frame-pointer'])
+ env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
+
+ elif (env["target"]=="release_debug"):
+
+ env.Append(CCFLAGS=['-O2','-ffast-math','-DDEBUG_ENABLED'])
+ env['OBJSUFFIX'] = "_optd"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = "_optd"+env['LIBSUFFIX']
+
+
+# env.Append(CCFLAGS=['-Os','-ffast-math','-fomit-frame-pointer'])
+#does not seem to have much effect
+# env.Append(CCFLAGS=['-fno-default-inline'])
+#recommended by wxwidgets
+# env.Append(CCFLAGS=['-ffunction-sections','-fdata-sections'])
+# env.Append(LINKFLAGS=['-Wl','--gc-sections'])
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-g2', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
+#does not seem to have much effect
+# env.Append(CCFLAGS=['-fno-default-inline'])
+#recommended by wxwidgets
+# env.Append(CCFLAGS=['-ffunction-sections','-fdata-sections'])
+# env.Append(LINKFLAGS=['-Wl','--gc-sections'])
+
+ elif (env["target"]=="debug_light"):
+
+ env.Append(CCFLAGS=['-g1', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
+
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-g','-pg'])
+ env.Append(LINKFLAGS=['-pg'])
+
+ env.ParseConfig('pkg-config x11 --cflags --libs')
+ env.ParseConfig('pkg-config xcursor --cflags --libs')
+
+
+ env.ParseConfig('pkg-config freetype2 --cflags --libs')
+ env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
+
+
+ if env['opengl'] == 'yes':
+ env.Append(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED'])
+ #env.Append(CPPFLAGS=["-DRTAUDIO_ENABLED"])
+ env.Append(CPPFLAGS=["-DALSA_ENABLED"])
+ env.Append(CPPFLAGS=['-DX11_ENABLED','-DUNIX_ENABLED','-DGLES2_ENABLED','-DGLES1_ENABLED','-DGLES_OVER_GL'])
+# env.Append(CPPFLAGS=['-DX11_ENABLED','-DUNIX_ENABLED','-DGLES2_ENABLED','-DGLES_OVER_GL'])
+ env.Append(LIBS=['GL', 'GLU', 'pthread','asound','z']) #TODO detect linux/BSD!
+ #env.Append(CPPFLAGS=['-DMPC_FIXED_POINT'])
+ if (env["force_32_bits"]=="yes"):
+ env.Append(CPPFLAGS=['-m32'])
+ env.Append(LINKFLAGS=['-m32','-L/usr/lib/i386-linux-gnu'])
+
+ if (env["CXX"]=="clang++"):
+ env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
+ env["CC"]="clang"
+ env["LD"]="clang++"
+
+ 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') } )
+
diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp
new file mode 100644
index 0000000000..b17b92bccf
--- /dev/null
+++ b/platform/x11/export/export.cpp
@@ -0,0 +1,24 @@
+#include "export.h"
+#include "platform/x11/logo.h"
+#include "tools/editor/editor_import_export.h"
+#include "scene/resources/texture.h"
+
+void register_x11_exporter() {
+
+ Image img(_x11_logo);
+ Ref<ImageTexture> logo = memnew( ImageTexture );
+ logo->create_from_image(img);
+
+ {
+ Ref<EditorExportPlatformPC> exporter = Ref<EditorExportPlatformPC>( memnew(EditorExportPlatformPC) );
+ exporter->set_binary_extension("bin");
+ exporter->set_release_binary32("linux_x11_32_release");
+ exporter->set_debug_binary32("linux_x11_32_debug");
+ exporter->set_release_binary64("linux_x11_64_release");
+ exporter->set_debug_binary64("linux_x11_64_debug");
+ exporter->set_name("Linux X11");
+ exporter->set_logo(logo);
+ EditorImportExport::get_singleton()->add_export_platform(exporter);
+ }
+
+}
diff --git a/platform/x11/export/export.h b/platform/x11/export/export.h
new file mode 100644
index 0000000000..1077709ea1
--- /dev/null
+++ b/platform/x11/export/export.h
@@ -0,0 +1,4 @@
+
+
+void register_x11_exporter();
+
diff --git a/platform/x11/godot_x11.cpp b/platform/x11/godot_x11.cpp
new file mode 100644
index 0000000000..3b50e8e515
--- /dev/null
+++ b/platform/x11/godot_x11.cpp
@@ -0,0 +1,45 @@
+/*************************************************************************/
+/* godot_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "main/main.h"
+#include "os_x11.h"
+
+int main(int argc, char* argv[]) {
+
+ OS_X11 os;
+
+ Error err = Main::setup(argv[0],argc-1,&argv[1]);
+ if (err!=OK)
+ return 255;
+
+ if (Main::start())
+ os.run(); // it is actually the OS that decides how to run
+ Main::cleanup();
+
+ return os.get_exit_code();
+}
diff --git a/platform/x11/key_mapping_x11.cpp b/platform/x11/key_mapping_x11.cpp
new file mode 100644
index 0000000000..2f109355b8
--- /dev/null
+++ b/platform/x11/key_mapping_x11.cpp
@@ -0,0 +1,1812 @@
+/*************************************************************************/
+/* key_mapping_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "key_mapping_x11.h"
+
+
+/***** SCAN CODE CONVERSION ******/
+
+struct _XTranslatePair {
+
+ KeySym keysym;
+ unsigned int keycode;
+};
+
+static _XTranslatePair _xkeysym_to_keycode[]={
+ // misc keys
+
+ { XK_Escape, KEY_ESCAPE },
+ { XK_Tab, KEY_TAB },
+ { XK_ISO_Left_Tab, KEY_BACKTAB },
+ { XK_BackSpace, KEY_BACKSPACE },
+ { XK_Return, KEY_RETURN },
+ { XK_Insert, KEY_INSERT },
+ { XK_Delete, KEY_DELETE },
+ { XK_Clear, KEY_DELETE },
+ { XK_Pause, KEY_PAUSE },
+ { XK_Print, KEY_PRINT },
+ { XK_Home, KEY_HOME },
+ { XK_End, KEY_END },
+ { XK_Left, KEY_LEFT },
+ { XK_Up, KEY_UP },
+ { XK_Right, KEY_RIGHT },
+ { XK_Down, KEY_DOWN },
+ { XK_Prior, KEY_PAGEUP },
+ { XK_Next, KEY_PAGEDOWN },
+ { XK_Shift_L, KEY_SHIFT },
+ { XK_Shift_R, KEY_SHIFT },
+ { XK_Shift_Lock, KEY_SHIFT },
+ { XK_Control_L, KEY_CONTROL },
+ { XK_Control_R, KEY_CONTROL },
+ { XK_Meta_L, KEY_META },
+ { XK_Meta_R, KEY_META },
+ { XK_Alt_L, KEY_ALT },
+ { XK_Alt_R, KEY_ALT },
+ { XK_Caps_Lock, KEY_CAPSLOCK },
+ { XK_Num_Lock, KEY_NUMLOCK },
+ { XK_Scroll_Lock, KEY_SCROLLLOCK },
+ { XK_Super_L, KEY_SUPER_L },
+ { XK_Super_R, KEY_SUPER_R },
+ { XK_Menu, KEY_MENU },
+ { XK_Hyper_L, KEY_HYPER_L },
+ { XK_Hyper_R, KEY_HYPER_R },
+ { XK_Help, KEY_HELP },
+ { XK_KP_Space, KEY_SPACE },
+ { XK_KP_Tab, KEY_TAB },
+ { XK_KP_Enter, KEY_ENTER },
+ { XK_Home, KEY_HOME },
+ { XK_Left, KEY_LEFT },
+ { XK_Up, KEY_UP },
+ { XK_Right, KEY_RIGHT },
+ { XK_Down, KEY_DOWN },
+ { XK_Prior, KEY_PAGEUP },
+ { XK_Next, KEY_PAGEDOWN },
+ { XK_End, KEY_END },
+ { XK_Begin, KEY_CLEAR },
+ { XK_Insert, KEY_INSERT },
+ { XK_Delete, KEY_DELETE },
+// { XK_KP_Equal, KEY_EQUAL },
+// { XK_KP_Separator, KEY_COMMA },
+ { XK_KP_Decimal, KEY_KP_PERIOD },
+ { XK_KP_Delete, KEY_KP_PERIOD },
+ { XK_KP_Enter, KEY_KP_ENTER },
+ { XK_KP_Multiply, KEY_KP_MULTIPLY},
+ { XK_KP_Divide, KEY_KP_DIVIDE},
+ { XK_KP_Subtract, KEY_KP_SUBSTRACT},
+ { XK_KP_Add, KEY_KP_ADD},
+ { XK_KP_0, KEY_KP_0},
+ { XK_KP_1, KEY_KP_1},
+ { XK_KP_2, KEY_KP_2},
+ { XK_KP_3, KEY_KP_3},
+ { XK_KP_4, KEY_KP_4},
+ { XK_KP_5, KEY_KP_5},
+ { XK_KP_6, KEY_KP_6},
+ { XK_KP_7, KEY_KP_7},
+ { XK_KP_8, KEY_KP_8},
+ { XK_KP_9, KEY_KP_9},
+ // same but with numlock
+ { XK_KP_Insert, KEY_KP_0},
+ { XK_KP_End, KEY_KP_1},
+ { XK_KP_Down, KEY_KP_2},
+ { XK_KP_Page_Down, KEY_KP_3},
+ { XK_KP_Left, KEY_KP_4},
+ { XK_KP_Begin, KEY_KP_5},
+ { XK_KP_Right, KEY_KP_6},
+ { XK_KP_Home, KEY_KP_7},
+ { XK_KP_Up, KEY_KP_8},
+ { XK_KP_Page_Up, KEY_KP_9},
+ { XK_F1, KEY_F1},
+ { XK_F2, KEY_F2},
+ { XK_F3, KEY_F3},
+ { XK_F4, KEY_F4},
+ { XK_F5, KEY_F5},
+ { XK_F6, KEY_F6},
+ { XK_F7, KEY_F7},
+ { XK_F8, KEY_F8},
+ { XK_F9, KEY_F9},
+ { XK_F10, KEY_F10},
+ { XK_F11, KEY_F11},
+ { XK_F12, KEY_F12},
+ { XK_F13, KEY_F13},
+ { XK_F14, KEY_F14},
+ { XK_F15, KEY_F15},
+ { XK_F16, KEY_F16},
+
+ // media keys
+ { XF86XK_Back, KEY_BACK },
+ { XF86XK_Forward, KEY_FORWARD },
+ { XF86XK_Stop, KEY_STOP },
+ { XF86XK_Refresh, KEY_REFRESH },
+ { XF86XK_Favorites, KEY_FAVORITES },
+ { XF86XK_AudioMedia, KEY_LAUNCHMEDIA },
+ { XF86XK_OpenURL, KEY_OPENURL },
+ { XF86XK_HomePage, KEY_HOMEPAGE },
+ { XF86XK_Search, KEY_SEARCH },
+ { XF86XK_AudioLowerVolume, KEY_VOLUMEDOWN },
+ { XF86XK_AudioMute, KEY_VOLUMEMUTE },
+ { XF86XK_AudioRaiseVolume, KEY_VOLUMEUP },
+ { XF86XK_AudioPlay, KEY_MEDIAPLAY },
+ { XF86XK_AudioStop, KEY_MEDIASTOP },
+ { XF86XK_AudioPrev, KEY_MEDIAPREVIOUS },
+ { XF86XK_AudioNext, KEY_MEDIANEXT },
+ { XF86XK_AudioRecord, KEY_MEDIARECORD },
+
+ // launch keys
+ { XF86XK_Mail, KEY_LAUNCHMAIL },
+ { XF86XK_MyComputer, KEY_LAUNCH0 },
+ { XF86XK_Calculator, KEY_LAUNCH1 },
+ { XF86XK_Standby, KEY_STANDBY },
+
+ { XF86XK_Launch0, KEY_LAUNCH2 },
+ { XF86XK_Launch1, KEY_LAUNCH3 },
+ { XF86XK_Launch2, KEY_LAUNCH4 },
+ { XF86XK_Launch3, KEY_LAUNCH5 },
+ { XF86XK_Launch4, KEY_LAUNCH6 },
+ { XF86XK_Launch5, KEY_LAUNCH7 },
+ { XF86XK_Launch6, KEY_LAUNCH8 },
+ { XF86XK_Launch7, KEY_LAUNCH9 },
+ { XF86XK_Launch8, KEY_LAUNCHA },
+ { XF86XK_Launch9, KEY_LAUNCHB },
+ { XF86XK_LaunchA, KEY_LAUNCHC },
+ { XF86XK_LaunchB, KEY_LAUNCHD },
+ { XF86XK_LaunchC, KEY_LAUNCHE },
+ { XF86XK_LaunchD, KEY_LAUNCHF },
+
+ {0, 0 }
+};
+
+
+unsigned int KeyMappingX11::get_keycode(KeySym p_keysym) {
+
+ // kinda bruteforce.. could optimize.
+
+ if (p_keysym<0x100) // Latin 1, maps 1-1
+ return p_keysym;
+
+ // look for special key
+ for(int idx=0;_xkeysym_to_keycode[idx].keysym!=0;idx++) {
+
+ if (_xkeysym_to_keycode[idx].keysym==p_keysym)
+ return _xkeysym_to_keycode[idx].keycode;
+ }
+
+ return 0;
+}
+KeySym KeyMappingX11::get_keysym(unsigned int p_code) {
+
+ // kinda bruteforce.. could optimize.
+
+ if (p_code<0x100) // Latin 1, maps 1-1
+ return p_code;
+
+ // look for special key
+ for(int idx=0;_xkeysym_to_keycode[idx].keysym!=0;idx++) {
+
+ if (_xkeysym_to_keycode[idx].keycode==p_code)
+ return _xkeysym_to_keycode[idx].keysym;
+ }
+
+ return 0;
+}
+
+
+/***** UNICODE CONVERSION ******/
+
+// Tables taken from FOX toolkit
+
+struct _XTranslateUnicodePair {
+
+ KeySym keysym;
+ unsigned int unicode;
+};
+
+enum {
+
+ _KEYSYM_MAX=759
+};
+
+static _XTranslateUnicodePair _xkeysym_to_unicode[_KEYSYM_MAX] = {
+ { 0x01A1, 0x0104 },
+ { 0x01A2, 0x02D8 },
+ { 0x01A3, 0x0141 },
+ { 0x01A5, 0x013D },
+ { 0x01A6, 0x015A },
+ { 0x01A9, 0x0160 },
+ { 0x01AA, 0x015E },
+ { 0x01AB, 0x0164 },
+ { 0x01AC, 0x0179 },
+ { 0x01AE, 0x017D },
+ { 0x01AF, 0x017B },
+ { 0x01B1, 0x0105 },
+ { 0x01B2, 0x02DB },
+ { 0x01B3, 0x0142 },
+ { 0x01B5, 0x013E },
+ { 0x01B6, 0x015B },
+ { 0x01B7, 0x02C7 },
+ { 0x01B9, 0x0161 },
+ { 0x01BA, 0x015F },
+ { 0x01BB, 0x0165 },
+ { 0x01BC, 0x017A },
+ { 0x01BD, 0x02DD },
+ { 0x01BE, 0x017E },
+ { 0x01BF, 0x017C },
+ { 0x01C0, 0x0154 },
+ { 0x01C3, 0x0102 },
+ { 0x01C5, 0x0139 },
+ { 0x01C6, 0x0106 },
+ { 0x01C8, 0x010C },
+ { 0x01CA, 0x0118 },
+ { 0x01CC, 0x011A },
+ { 0x01CF, 0x010E },
+ { 0x01D0, 0x0110 },
+ { 0x01D1, 0x0143 },
+ { 0x01D2, 0x0147 },
+ { 0x01D5, 0x0150 },
+ { 0x01D8, 0x0158 },
+ { 0x01D9, 0x016E },
+ { 0x01DB, 0x0170 },
+ { 0x01DE, 0x0162 },
+ { 0x01E0, 0x0155 },
+ { 0x01E3, 0x0103 },
+ { 0x01E5, 0x013A },
+ { 0x01E6, 0x0107 },
+ { 0x01E8, 0x010D },
+ { 0x01EA, 0x0119 },
+ { 0x01EC, 0x011B },
+ { 0x01EF, 0x010F },
+ { 0x01F0, 0x0111 },
+ { 0x01F1, 0x0144 },
+ { 0x01F2, 0x0148 },
+ { 0x01F5, 0x0151 },
+ { 0x01F8, 0x0159 },
+ { 0x01F9, 0x016F },
+ { 0x01FB, 0x0171 },
+ { 0x01FE, 0x0163 },
+ { 0x01FF, 0x02D9 },
+ { 0x02A1, 0x0126 },
+ { 0x02A6, 0x0124 },
+ { 0x02A9, 0x0130 },
+ { 0x02AB, 0x011E },
+ { 0x02AC, 0x0134 },
+ { 0x02B1, 0x0127 },
+ { 0x02B6, 0x0125 },
+ { 0x02B9, 0x0131 },
+ { 0x02BB, 0x011F },
+ { 0x02BC, 0x0135 },
+ { 0x02C5, 0x010A },
+ { 0x02C6, 0x0108 },
+ { 0x02D5, 0x0120 },
+ { 0x02D8, 0x011C },
+ { 0x02DD, 0x016C },
+ { 0x02DE, 0x015C },
+ { 0x02E5, 0x010B },
+ { 0x02E6, 0x0109 },
+ { 0x02F5, 0x0121 },
+ { 0x02F8, 0x011D },
+ { 0x02FD, 0x016D },
+ { 0x02FE, 0x015D },
+ { 0x03A2, 0x0138 },
+ { 0x03A3, 0x0156 },
+ { 0x03A5, 0x0128 },
+ { 0x03A6, 0x013B },
+ { 0x03AA, 0x0112 },
+ { 0x03AB, 0x0122 },
+ { 0x03AC, 0x0166 },
+ { 0x03B3, 0x0157 },
+ { 0x03B5, 0x0129 },
+ { 0x03B6, 0x013C },
+ { 0x03BA, 0x0113 },
+ { 0x03BB, 0x0123 },
+ { 0x03BC, 0x0167 },
+ { 0x03BD, 0x014A },
+ { 0x03BF, 0x014B },
+ { 0x03C0, 0x0100 },
+ { 0x03C7, 0x012E },
+ { 0x03CC, 0x0116 },
+ { 0x03CF, 0x012A },
+ { 0x03D1, 0x0145 },
+ { 0x03D2, 0x014C },
+ { 0x03D3, 0x0136 },
+ { 0x03D9, 0x0172 },
+ { 0x03DD, 0x0168 },
+ { 0x03DE, 0x016A },
+ { 0x03E0, 0x0101 },
+ { 0x03E7, 0x012F },
+ { 0x03EC, 0x0117 },
+ { 0x03EF, 0x012B },
+ { 0x03F1, 0x0146 },
+ { 0x03F2, 0x014D },
+ { 0x03F3, 0x0137 },
+ { 0x03F9, 0x0173 },
+ { 0x03FD, 0x0169 },
+ { 0x03FE, 0x016B },
+ { 0x047E, 0x203E },
+ { 0x04A1, 0x3002 },
+ { 0x04A2, 0x300C },
+ { 0x04A3, 0x300D },
+ { 0x04A4, 0x3001 },
+ { 0x04A5, 0x30FB },
+ { 0x04A6, 0x30F2 },
+ { 0x04A7, 0x30A1 },
+ { 0x04A8, 0x30A3 },
+ { 0x04A9, 0x30A5 },
+ { 0x04AA, 0x30A7 },
+ { 0x04AB, 0x30A9 },
+ { 0x04AC, 0x30E3 },
+ { 0x04AD, 0x30E5 },
+ { 0x04AE, 0x30E7 },
+ { 0x04AF, 0x30C3 },
+ { 0x04B0, 0x30FC },
+ { 0x04B1, 0x30A2 },
+ { 0x04B2, 0x30A4 },
+ { 0x04B3, 0x30A6 },
+ { 0x04B4, 0x30A8 },
+ { 0x04B5, 0x30AA },
+ { 0x04B6, 0x30AB },
+ { 0x04B7, 0x30AD },
+ { 0x04B8, 0x30AF },
+ { 0x04B9, 0x30B1 },
+ { 0x04BA, 0x30B3 },
+ { 0x04BB, 0x30B5 },
+ { 0x04BC, 0x30B7 },
+ { 0x04BD, 0x30B9 },
+ { 0x04BE, 0x30BB },
+ { 0x04BF, 0x30BD },
+ { 0x04C0, 0x30BF },
+ { 0x04C1, 0x30C1 },
+ { 0x04C2, 0x30C4 },
+ { 0x04C3, 0x30C6 },
+ { 0x04C4, 0x30C8 },
+ { 0x04C5, 0x30CA },
+ { 0x04C6, 0x30CB },
+ { 0x04C7, 0x30CC },
+ { 0x04C8, 0x30CD },
+ { 0x04C9, 0x30CE },
+ { 0x04CA, 0x30CF },
+ { 0x04CB, 0x30D2 },
+ { 0x04CC, 0x30D5 },
+ { 0x04CD, 0x30D8 },
+ { 0x04CE, 0x30DB },
+ { 0x04CF, 0x30DE },
+ { 0x04D0, 0x30DF },
+ { 0x04D1, 0x30E0 },
+ { 0x04D2, 0x30E1 },
+ { 0x04D3, 0x30E2 },
+ { 0x04D4, 0x30E4 },
+ { 0x04D5, 0x30E6 },
+ { 0x04D6, 0x30E8 },
+ { 0x04D7, 0x30E9 },
+ { 0x04D8, 0x30EA },
+ { 0x04D9, 0x30EB },
+ { 0x04DA, 0x30EC },
+ { 0x04DB, 0x30ED },
+ { 0x04DC, 0x30EF },
+ { 0x04DD, 0x30F3 },
+ { 0x04DE, 0x309B },
+ { 0x04DF, 0x309C },
+ { 0x05AC, 0x060C },
+ { 0x05BB, 0x061B },
+ { 0x05BF, 0x061F },
+ { 0x05C1, 0x0621 },
+ { 0x05C2, 0x0622 },
+ { 0x05C3, 0x0623 },
+ { 0x05C4, 0x0624 },
+ { 0x05C5, 0x0625 },
+ { 0x05C6, 0x0626 },
+ { 0x05C7, 0x0627 },
+ { 0x05C8, 0x0628 },
+ { 0x05C9, 0x0629 },
+ { 0x05CA, 0x062A },
+ { 0x05CB, 0x062B },
+ { 0x05CC, 0x062C },
+ { 0x05CD, 0x062D },
+ { 0x05CE, 0x062E },
+ { 0x05CF, 0x062F },
+ { 0x05D0, 0x0630 },
+ { 0x05D1, 0x0631 },
+ { 0x05D2, 0x0632 },
+ { 0x05D3, 0x0633 },
+ { 0x05D4, 0x0634 },
+ { 0x05D5, 0x0635 },
+ { 0x05D6, 0x0636 },
+ { 0x05D7, 0x0637 },
+ { 0x05D8, 0x0638 },
+ { 0x05D9, 0x0639 },
+ { 0x05DA, 0x063A },
+ { 0x05E0, 0x0640 },
+ { 0x05E1, 0x0641 },
+ { 0x05E2, 0x0642 },
+ { 0x05E3, 0x0643 },
+ { 0x05E4, 0x0644 },
+ { 0x05E5, 0x0645 },
+ { 0x05E6, 0x0646 },
+ { 0x05E7, 0x0647 },
+ { 0x05E8, 0x0648 },
+ { 0x05E9, 0x0649 },
+ { 0x05EA, 0x064A },
+ { 0x05EB, 0x064B },
+ { 0x05EC, 0x064C },
+ { 0x05ED, 0x064D },
+ { 0x05EE, 0x064E },
+ { 0x05EF, 0x064F },
+ { 0x05F0, 0x0650 },
+ { 0x05F1, 0x0651 },
+ { 0x05F2, 0x0652 },
+ { 0x06A1, 0x0452 },
+ { 0x06A2, 0x0453 },
+ { 0x06A3, 0x0451 },
+ { 0x06A4, 0x0454 },
+ { 0x06A5, 0x0455 },
+ { 0x06A6, 0x0456 },
+ { 0x06A7, 0x0457 },
+ { 0x06A8, 0x0458 },
+ { 0x06A9, 0x0459 },
+ { 0x06AA, 0x045A },
+ { 0x06AB, 0x045B },
+ { 0x06AC, 0x045C },
+ { 0x06AE, 0x045E },
+ { 0x06AF, 0x045F },
+ { 0x06B0, 0x2116 },
+ { 0x06B1, 0x0402 },
+ { 0x06B2, 0x0403 },
+ { 0x06B3, 0x0401 },
+ { 0x06B4, 0x0404 },
+ { 0x06B5, 0x0405 },
+ { 0x06B6, 0x0406 },
+ { 0x06B7, 0x0407 },
+ { 0x06B8, 0x0408 },
+ { 0x06B9, 0x0409 },
+ { 0x06BA, 0x040A },
+ { 0x06BB, 0x040B },
+ { 0x06BC, 0x040C },
+ { 0x06BE, 0x040E },
+ { 0x06BF, 0x040F },
+ { 0x06C0, 0x044E },
+ { 0x06C1, 0x0430 },
+ { 0x06C2, 0x0431 },
+ { 0x06C3, 0x0446 },
+ { 0x06C4, 0x0434 },
+ { 0x06C5, 0x0435 },
+ { 0x06C6, 0x0444 },
+ { 0x06C7, 0x0433 },
+ { 0x06C8, 0x0445 },
+ { 0x06C9, 0x0438 },
+ { 0x06CA, 0x0439 },
+ { 0x06CB, 0x043A },
+ { 0x06CC, 0x043B },
+ { 0x06CD, 0x043C },
+ { 0x06CE, 0x043D },
+ { 0x06CF, 0x043E },
+ { 0x06D0, 0x043F },
+ { 0x06D1, 0x044F },
+ { 0x06D2, 0x0440 },
+ { 0x06D3, 0x0441 },
+ { 0x06D4, 0x0442 },
+ { 0x06D5, 0x0443 },
+ { 0x06D6, 0x0436 },
+ { 0x06D7, 0x0432 },
+ { 0x06D8, 0x044C },
+ { 0x06D9, 0x044B },
+ { 0x06DA, 0x0437 },
+ { 0x06DB, 0x0448 },
+ { 0x06DC, 0x044D },
+ { 0x06DD, 0x0449 },
+ { 0x06DE, 0x0447 },
+ { 0x06DF, 0x044A },
+ { 0x06E0, 0x042E },
+ { 0x06E1, 0x0410 },
+ { 0x06E2, 0x0411 },
+ { 0x06E3, 0x0426 },
+ { 0x06E4, 0x0414 },
+ { 0x06E5, 0x0415 },
+ { 0x06E6, 0x0424 },
+ { 0x06E7, 0x0413 },
+ { 0x06E8, 0x0425 },
+ { 0x06E9, 0x0418 },
+ { 0x06EA, 0x0419 },
+ { 0x06EB, 0x041A },
+ { 0x06EC, 0x041B },
+ { 0x06ED, 0x041C },
+ { 0x06EE, 0x041D },
+ { 0x06EF, 0x041E },
+ { 0x06F0, 0x041F },
+ { 0x06F1, 0x042F },
+ { 0x06F2, 0x0420 },
+ { 0x06F3, 0x0421 },
+ { 0x06F4, 0x0422 },
+ { 0x06F5, 0x0423 },
+ { 0x06F6, 0x0416 },
+ { 0x06F7, 0x0412 },
+ { 0x06F8, 0x042C },
+ { 0x06F9, 0x042B },
+ { 0x06FA, 0x0417 },
+ { 0x06FB, 0x0428 },
+ { 0x06FC, 0x042D },
+ { 0x06FD, 0x0429 },
+ { 0x06FE, 0x0427 },
+ { 0x06FF, 0x042A },
+ { 0x07A1, 0x0386 },
+ { 0x07A2, 0x0388 },
+ { 0x07A3, 0x0389 },
+ { 0x07A4, 0x038A },
+ { 0x07A5, 0x03AA },
+ { 0x07A7, 0x038C },
+ { 0x07A8, 0x038E },
+ { 0x07A9, 0x03AB },
+ { 0x07AB, 0x038F },
+ { 0x07AE, 0x0385 },
+ { 0x07AF, 0x2015 },
+ { 0x07B1, 0x03AC },
+ { 0x07B2, 0x03AD },
+ { 0x07B3, 0x03AE },
+ { 0x07B4, 0x03AF },
+ { 0x07B5, 0x03CA },
+ { 0x07B6, 0x0390 },
+ { 0x07B7, 0x03CC },
+ { 0x07B8, 0x03CD },
+ { 0x07B9, 0x03CB },
+ { 0x07BA, 0x03B0 },
+ { 0x07BB, 0x03CE },
+ { 0x07C1, 0x0391 },
+ { 0x07C2, 0x0392 },
+ { 0x07C3, 0x0393 },
+ { 0x07C4, 0x0394 },
+ { 0x07C5, 0x0395 },
+ { 0x07C6, 0x0396 },
+ { 0x07C7, 0x0397 },
+ { 0x07C8, 0x0398 },
+ { 0x07C9, 0x0399 },
+ { 0x07CA, 0x039A },
+ { 0x07CB, 0x039B },
+ { 0x07CC, 0x039C },
+ { 0x07CD, 0x039D },
+ { 0x07CE, 0x039E },
+ { 0x07CF, 0x039F },
+ { 0x07D0, 0x03A0 },
+ { 0x07D1, 0x03A1 },
+ { 0x07D2, 0x03A3 },
+ { 0x07D4, 0x03A4 },
+ { 0x07D5, 0x03A5 },
+ { 0x07D6, 0x03A6 },
+ { 0x07D7, 0x03A7 },
+ { 0x07D8, 0x03A8 },
+ { 0x07D9, 0x03A9 },
+ { 0x07E1, 0x03B1 },
+ { 0x07E2, 0x03B2 },
+ { 0x07E3, 0x03B3 },
+ { 0x07E4, 0x03B4 },
+ { 0x07E5, 0x03B5 },
+ { 0x07E6, 0x03B6 },
+ { 0x07E7, 0x03B7 },
+ { 0x07E8, 0x03B8 },
+ { 0x07E9, 0x03B9 },
+ { 0x07EA, 0x03BA },
+ { 0x07EB, 0x03BB },
+ { 0x07EC, 0x03BC },
+ { 0x07ED, 0x03BD },
+ { 0x07EE, 0x03BE },
+ { 0x07EF, 0x03BF },
+ { 0x07F0, 0x03C0 },
+ { 0x07F1, 0x03C1 },
+ { 0x07F2, 0x03C3 },
+ { 0x07F3, 0x03C2 },
+ { 0x07F4, 0x03C4 },
+ { 0x07F5, 0x03C5 },
+ { 0x07F6, 0x03C6 },
+ { 0x07F7, 0x03C7 },
+ { 0x07F8, 0x03C8 },
+ { 0x07F9, 0x03C9 },
+ { 0x08A1, 0x23B7 },
+ { 0x08A2, 0x250C },
+ { 0x08A3, 0x2500 },
+ { 0x08A4, 0x2320 },
+ { 0x08A5, 0x2321 },
+ { 0x08A6, 0x2502 },
+ { 0x08A7, 0x23A1 },
+ { 0x08A8, 0x23A3 },
+ { 0x08A9, 0x23A4 },
+ { 0x08AA, 0x23A6 },
+ { 0x08AB, 0x239B },
+ { 0x08AC, 0x239D },
+ { 0x08AD, 0x239E },
+ { 0x08AE, 0x23A0 },
+ { 0x08AF, 0x23A8 },
+ { 0x08B0, 0x23AC },
+ { 0x08BC, 0x2264 },
+ { 0x08BD, 0x2260 },
+ { 0x08BE, 0x2265 },
+ { 0x08BF, 0x222B },
+ { 0x08C0, 0x2234 },
+ { 0x08C1, 0x221D },
+ { 0x08C2, 0x221E },
+ { 0x08C5, 0x2207 },
+ { 0x08C8, 0x223C },
+ { 0x08C9, 0x2243 },
+ { 0x08CD, 0x21D4 },
+ { 0x08CE, 0x21D2 },
+ { 0x08CF, 0x2261 },
+ { 0x08D6, 0x221A },
+ { 0x08DA, 0x2282 },
+ { 0x08DB, 0x2283 },
+ { 0x08DC, 0x2229 },
+ { 0x08DD, 0x222A },
+ { 0x08DE, 0x2227 },
+ { 0x08DF, 0x2228 },
+ { 0x08EF, 0x2202 },
+ { 0x08F6, 0x0192 },
+ { 0x08FB, 0x2190 },
+ { 0x08FC, 0x2191 },
+ { 0x08FD, 0x2192 },
+ { 0x08FE, 0x2193 },
+ { 0x09E0, 0x25C6 },
+ { 0x09E1, 0x2592 },
+ { 0x09E2, 0x2409 },
+ { 0x09E3, 0x240C },
+ { 0x09E4, 0x240D },
+ { 0x09E5, 0x240A },
+ { 0x09E8, 0x2424 },
+ { 0x09E9, 0x240B },
+ { 0x09EA, 0x2518 },
+ { 0x09EB, 0x2510 },
+ { 0x09EC, 0x250C },
+ { 0x09ED, 0x2514 },
+ { 0x09EE, 0x253C },
+ { 0x09EF, 0x23BA },
+ { 0x09F0, 0x23BB },
+ { 0x09F1, 0x2500 },
+ { 0x09F2, 0x23BC },
+ { 0x09F3, 0x23BD },
+ { 0x09F4, 0x251C },
+ { 0x09F5, 0x2524 },
+ { 0x09F6, 0x2534 },
+ { 0x09F7, 0x252C },
+ { 0x09F8, 0x2502 },
+ { 0x0AA1, 0x2003 },
+ { 0x0AA2, 0x2002 },
+ { 0x0AA3, 0x2004 },
+ { 0x0AA4, 0x2005 },
+ { 0x0AA5, 0x2007 },
+ { 0x0AA6, 0x2008 },
+ { 0x0AA7, 0x2009 },
+ { 0x0AA8, 0x200A },
+ { 0x0AA9, 0x2014 },
+ { 0x0AAA, 0x2013 },
+ { 0x0AAE, 0x2026 },
+ { 0x0AAF, 0x2025 },
+ { 0x0AB0, 0x2153 },
+ { 0x0AB1, 0x2154 },
+ { 0x0AB2, 0x2155 },
+ { 0x0AB3, 0x2156 },
+ { 0x0AB4, 0x2157 },
+ { 0x0AB5, 0x2158 },
+ { 0x0AB6, 0x2159 },
+ { 0x0AB7, 0x215A },
+ { 0x0AB8, 0x2105 },
+ { 0x0ABB, 0x2012 },
+ { 0x0ABC, 0x2329 },
+ { 0x0ABE, 0x232A },
+ { 0x0AC3, 0x215B },
+ { 0x0AC4, 0x215C },
+ { 0x0AC5, 0x215D },
+ { 0x0AC6, 0x215E },
+ { 0x0AC9, 0x2122 },
+ { 0x0ACA, 0x2613 },
+ { 0x0ACC, 0x25C1 },
+ { 0x0ACD, 0x25B7 },
+ { 0x0ACE, 0x25CB },
+ { 0x0ACF, 0x25AF },
+ { 0x0AD0, 0x2018 },
+ { 0x0AD1, 0x2019 },
+ { 0x0AD2, 0x201C },
+ { 0x0AD3, 0x201D },
+ { 0x0AD4, 0x211E },
+ { 0x0AD6, 0x2032 },
+ { 0x0AD7, 0x2033 },
+ { 0x0AD9, 0x271D },
+ { 0x0ADB, 0x25AC },
+ { 0x0ADC, 0x25C0 },
+ { 0x0ADD, 0x25B6 },
+ { 0x0ADE, 0x25CF },
+ { 0x0ADF, 0x25AE },
+ { 0x0AE0, 0x25E6 },
+ { 0x0AE1, 0x25AB },
+ { 0x0AE2, 0x25AD },
+ { 0x0AE3, 0x25B3 },
+ { 0x0AE4, 0x25BD },
+ { 0x0AE5, 0x2606 },
+ { 0x0AE6, 0x2022 },
+ { 0x0AE7, 0x25AA },
+ { 0x0AE8, 0x25B2 },
+ { 0x0AE9, 0x25BC },
+ { 0x0AEA, 0x261C },
+ { 0x0AEB, 0x261E },
+ { 0x0AEC, 0x2663 },
+ { 0x0AED, 0x2666 },
+ { 0x0AEE, 0x2665 },
+ { 0x0AF0, 0x2720 },
+ { 0x0AF1, 0x2020 },
+ { 0x0AF2, 0x2021 },
+ { 0x0AF3, 0x2713 },
+ { 0x0AF4, 0x2717 },
+ { 0x0AF5, 0x266F },
+ { 0x0AF6, 0x266D },
+ { 0x0AF7, 0x2642 },
+ { 0x0AF8, 0x2640 },
+ { 0x0AF9, 0x260E },
+ { 0x0AFA, 0x2315 },
+ { 0x0AFB, 0x2117 },
+ { 0x0AFC, 0x2038 },
+ { 0x0AFD, 0x201A },
+ { 0x0AFE, 0x201E },
+ { 0x0BA3, 0x003C },
+ { 0x0BA6, 0x003E },
+ { 0x0BA8, 0x2228 },
+ { 0x0BA9, 0x2227 },
+ { 0x0BC0, 0x00AF },
+ { 0x0BC2, 0x22A5 },
+ { 0x0BC3, 0x2229 },
+ { 0x0BC4, 0x230A },
+ { 0x0BC6, 0x005F },
+ { 0x0BCA, 0x2218 },
+ { 0x0BCC, 0x2395 },
+ { 0x0BCE, 0x22A4 },
+ { 0x0BCF, 0x25CB },
+ { 0x0BD3, 0x2308 },
+ { 0x0BD6, 0x222A },
+ { 0x0BD8, 0x2283 },
+ { 0x0BDA, 0x2282 },
+ { 0x0BDC, 0x22A2 },
+ { 0x0BFC, 0x22A3 },
+ { 0x0CDF, 0x2017 },
+ { 0x0CE0, 0x05D0 },
+ { 0x0CE1, 0x05D1 },
+ { 0x0CE2, 0x05D2 },
+ { 0x0CE3, 0x05D3 },
+ { 0x0CE4, 0x05D4 },
+ { 0x0CE5, 0x05D5 },
+ { 0x0CE6, 0x05D6 },
+ { 0x0CE7, 0x05D7 },
+ { 0x0CE8, 0x05D8 },
+ { 0x0CE9, 0x05D9 },
+ { 0x0CEA, 0x05DA },
+ { 0x0CEB, 0x05DB },
+ { 0x0CEC, 0x05DC },
+ { 0x0CED, 0x05DD },
+ { 0x0CEE, 0x05DE },
+ { 0x0CEF, 0x05DF },
+ { 0x0CF0, 0x05E0 },
+ { 0x0CF1, 0x05E1 },
+ { 0x0CF2, 0x05E2 },
+ { 0x0CF3, 0x05E3 },
+ { 0x0CF4, 0x05E4 },
+ { 0x0CF5, 0x05E5 },
+ { 0x0CF6, 0x05E6 },
+ { 0x0CF7, 0x05E7 },
+ { 0x0CF8, 0x05E8 },
+ { 0x0CF9, 0x05E9 },
+ { 0x0CFA, 0x05EA },
+ { 0x0DA1, 0x0E01 },
+ { 0x0DA2, 0x0E02 },
+ { 0x0DA3, 0x0E03 },
+ { 0x0DA4, 0x0E04 },
+ { 0x0DA5, 0x0E05 },
+ { 0x0DA6, 0x0E06 },
+ { 0x0DA7, 0x0E07 },
+ { 0x0DA8, 0x0E08 },
+ { 0x0DA9, 0x0E09 },
+ { 0x0DAA, 0x0E0A },
+ { 0x0DAB, 0x0E0B },
+ { 0x0DAC, 0x0E0C },
+ { 0x0DAD, 0x0E0D },
+ { 0x0DAE, 0x0E0E },
+ { 0x0DAF, 0x0E0F },
+ { 0x0DB0, 0x0E10 },
+ { 0x0DB1, 0x0E11 },
+ { 0x0DB2, 0x0E12 },
+ { 0x0DB3, 0x0E13 },
+ { 0x0DB4, 0x0E14 },
+ { 0x0DB5, 0x0E15 },
+ { 0x0DB6, 0x0E16 },
+ { 0x0DB7, 0x0E17 },
+ { 0x0DB8, 0x0E18 },
+ { 0x0DB9, 0x0E19 },
+ { 0x0DBA, 0x0E1A },
+ { 0x0DBB, 0x0E1B },
+ { 0x0DBC, 0x0E1C },
+ { 0x0DBD, 0x0E1D },
+ { 0x0DBE, 0x0E1E },
+ { 0x0DBF, 0x0E1F },
+ { 0x0DC0, 0x0E20 },
+ { 0x0DC1, 0x0E21 },
+ { 0x0DC2, 0x0E22 },
+ { 0x0DC3, 0x0E23 },
+ { 0x0DC4, 0x0E24 },
+ { 0x0DC5, 0x0E25 },
+ { 0x0DC6, 0x0E26 },
+ { 0x0DC7, 0x0E27 },
+ { 0x0DC8, 0x0E28 },
+ { 0x0DC9, 0x0E29 },
+ { 0x0DCA, 0x0E2A },
+ { 0x0DCB, 0x0E2B },
+ { 0x0DCC, 0x0E2C },
+ { 0x0DCD, 0x0E2D },
+ { 0x0DCE, 0x0E2E },
+ { 0x0DCF, 0x0E2F },
+ { 0x0DD0, 0x0E30 },
+ { 0x0DD1, 0x0E31 },
+ { 0x0DD2, 0x0E32 },
+ { 0x0DD3, 0x0E33 },
+ { 0x0DD4, 0x0E34 },
+ { 0x0DD5, 0x0E35 },
+ { 0x0DD6, 0x0E36 },
+ { 0x0DD7, 0x0E37 },
+ { 0x0DD8, 0x0E38 },
+ { 0x0DD9, 0x0E39 },
+ { 0x0DDA, 0x0E3A },
+ { 0x0DDF, 0x0E3F },
+ { 0x0DE0, 0x0E40 },
+ { 0x0DE1, 0x0E41 },
+ { 0x0DE2, 0x0E42 },
+ { 0x0DE3, 0x0E43 },
+ { 0x0DE4, 0x0E44 },
+ { 0x0DE5, 0x0E45 },
+ { 0x0DE6, 0x0E46 },
+ { 0x0DE7, 0x0E47 },
+ { 0x0DE8, 0x0E48 },
+ { 0x0DE9, 0x0E49 },
+ { 0x0DEA, 0x0E4A },
+ { 0x0DEB, 0x0E4B },
+ { 0x0DEC, 0x0E4C },
+ { 0x0DED, 0x0E4D },
+ { 0x0DF0, 0x0E50 },
+ { 0x0DF1, 0x0E51 },
+ { 0x0DF2, 0x0E52 },
+ { 0x0DF3, 0x0E53 },
+ { 0x0DF4, 0x0E54 },
+ { 0x0DF5, 0x0E55 },
+ { 0x0DF6, 0x0E56 },
+ { 0x0DF7, 0x0E57 },
+ { 0x0DF8, 0x0E58 },
+ { 0x0DF9, 0x0E59 },
+ { 0x0EA1, 0x3131 },
+ { 0x0EA2, 0x3132 },
+ { 0x0EA3, 0x3133 },
+ { 0x0EA4, 0x3134 },
+ { 0x0EA5, 0x3135 },
+ { 0x0EA6, 0x3136 },
+ { 0x0EA7, 0x3137 },
+ { 0x0EA8, 0x3138 },
+ { 0x0EA9, 0x3139 },
+ { 0x0EAA, 0x313A },
+ { 0x0EAB, 0x313B },
+ { 0x0EAC, 0x313C },
+ { 0x0EAD, 0x313D },
+ { 0x0EAE, 0x313E },
+ { 0x0EAF, 0x313F },
+ { 0x0EB0, 0x3140 },
+ { 0x0EB1, 0x3141 },
+ { 0x0EB2, 0x3142 },
+ { 0x0EB3, 0x3143 },
+ { 0x0EB4, 0x3144 },
+ { 0x0EB5, 0x3145 },
+ { 0x0EB6, 0x3146 },
+ { 0x0EB7, 0x3147 },
+ { 0x0EB8, 0x3148 },
+ { 0x0EB9, 0x3149 },
+ { 0x0EBA, 0x314A },
+ { 0x0EBB, 0x314B },
+ { 0x0EBC, 0x314C },
+ { 0x0EBD, 0x314D },
+ { 0x0EBE, 0x314E },
+ { 0x0EBF, 0x314F },
+ { 0x0EC0, 0x3150 },
+ { 0x0EC1, 0x3151 },
+ { 0x0EC2, 0x3152 },
+ { 0x0EC3, 0x3153 },
+ { 0x0EC4, 0x3154 },
+ { 0x0EC5, 0x3155 },
+ { 0x0EC6, 0x3156 },
+ { 0x0EC7, 0x3157 },
+ { 0x0EC8, 0x3158 },
+ { 0x0EC9, 0x3159 },
+ { 0x0ECA, 0x315A },
+ { 0x0ECB, 0x315B },
+ { 0x0ECC, 0x315C },
+ { 0x0ECD, 0x315D },
+ { 0x0ECE, 0x315E },
+ { 0x0ECF, 0x315F },
+ { 0x0ED0, 0x3160 },
+ { 0x0ED1, 0x3161 },
+ { 0x0ED2, 0x3162 },
+ { 0x0ED3, 0x3163 },
+ { 0x0ED4, 0x11A8 },
+ { 0x0ED5, 0x11A9 },
+ { 0x0ED6, 0x11AA },
+ { 0x0ED7, 0x11AB },
+ { 0x0ED8, 0x11AC },
+ { 0x0ED9, 0x11AD },
+ { 0x0EDA, 0x11AE },
+ { 0x0EDB, 0x11AF },
+ { 0x0EDC, 0x11B0 },
+ { 0x0EDD, 0x11B1 },
+ { 0x0EDE, 0x11B2 },
+ { 0x0EDF, 0x11B3 },
+ { 0x0EE0, 0x11B4 },
+ { 0x0EE1, 0x11B5 },
+ { 0x0EE2, 0x11B6 },
+ { 0x0EE3, 0x11B7 },
+ { 0x0EE4, 0x11B8 },
+ { 0x0EE5, 0x11B9 },
+ { 0x0EE6, 0x11BA },
+ { 0x0EE7, 0x11BB },
+ { 0x0EE8, 0x11BC },
+ { 0x0EE9, 0x11BD },
+ { 0x0EEA, 0x11BE },
+ { 0x0EEB, 0x11BF },
+ { 0x0EEC, 0x11C0 },
+ { 0x0EED, 0x11C1 },
+ { 0x0EEE, 0x11C2 },
+ { 0x0EEF, 0x316D },
+ { 0x0EF0, 0x3171 },
+ { 0x0EF1, 0x3178 },
+ { 0x0EF2, 0x317F },
+ { 0x0EF3, 0x3181 },
+ { 0x0EF4, 0x3184 },
+ { 0x0EF5, 0x3186 },
+ { 0x0EF6, 0x318D },
+ { 0x0EF7, 0x318E },
+ { 0x0EF8, 0x11EB },
+ { 0x0EF9, 0x11F0 },
+ { 0x0EFA, 0x11F9 },
+ { 0x0EFF, 0x20A9 },
+ { 0x13A4, 0x20AC },
+ { 0x13BC, 0x0152 },
+ { 0x13BD, 0x0153 },
+ { 0x13BE, 0x0178 },
+ { 0x20AC, 0x20AC },
+};
+
+unsigned int KeyMappingX11::get_unicode_from_keysym(KeySym p_keysym) {
+
+ /* Latin-1 */
+ if (p_keysym>=0x20 && p_keysym<=0x7e)
+ return p_keysym;
+ if (p_keysym>=0xa0 && p_keysym<=0xff)
+ return p_keysym;
+ // keypad to latin1 is easy
+ if (p_keysym>=0xffaa && p_keysym<=0xffb9)
+ return p_keysym-0xff80;
+
+ /* Unicode (may be present)*/
+
+ if((p_keysym&0xff000000)==0x01000000)
+ return p_keysym&0x00ffffff;
+
+ int middle,low=0,high=_KEYSYM_MAX-1;
+ do {
+ middle=(high+low)/2;
+ if ( _xkeysym_to_unicode[middle].keysym==p_keysym)
+ return _xkeysym_to_unicode[middle].unicode;
+ if ( _xkeysym_to_unicode[middle].keysym<=p_keysym )
+ low=middle+1;
+ else
+ high=middle-1;
+ } while (high>=low);
+
+ return 0;
+
+}
+
+struct _XTranslateUnicodePairReverse {
+
+ unsigned int unicode;
+ KeySym keysym;
+};
+
+enum {
+
+ _UNICODE_MAX=750
+};
+
+static _XTranslateUnicodePairReverse _unicode_to_xkeysym[_UNICODE_MAX] = {
+ { 0x0ABD, 0x002E },
+ { 0x0BA3, 0x003C },
+ { 0x0BA6, 0x003E },
+ { 0x0BC6, 0x005F },
+ { 0x0BC0, 0x00AF },
+ { 0x03C0, 0x0100 },
+ { 0x03E0, 0x0101 },
+ { 0x01C3, 0x0102 },
+ { 0x01E3, 0x0103 },
+ { 0x01A1, 0x0104 },
+ { 0x01B1, 0x0105 },
+ { 0x01C6, 0x0106 },
+ { 0x01E6, 0x0107 },
+ { 0x02C6, 0x0108 },
+ { 0x02E6, 0x0109 },
+ { 0x02C5, 0x010A },
+ { 0x02E5, 0x010B },
+ { 0x01C8, 0x010C },
+ { 0x01E8, 0x010D },
+ { 0x01CF, 0x010E },
+ { 0x01EF, 0x010F },
+ { 0x01D0, 0x0110 },
+ { 0x01F0, 0x0111 },
+ { 0x03AA, 0x0112 },
+ { 0x03BA, 0x0113 },
+ { 0x03CC, 0x0116 },
+ { 0x03EC, 0x0117 },
+ { 0x01CA, 0x0118 },
+ { 0x01EA, 0x0119 },
+ { 0x01CC, 0x011A },
+ { 0x01EC, 0x011B },
+ { 0x02D8, 0x011C },
+ { 0x02F8, 0x011D },
+ { 0x02AB, 0x011E },
+ { 0x02BB, 0x011F },
+ { 0x02D5, 0x0120 },
+ { 0x02F5, 0x0121 },
+ { 0x03AB, 0x0122 },
+ { 0x03BB, 0x0123 },
+ { 0x02A6, 0x0124 },
+ { 0x02B6, 0x0125 },
+ { 0x02A1, 0x0126 },
+ { 0x02B1, 0x0127 },
+ { 0x03A5, 0x0128 },
+ { 0x03B5, 0x0129 },
+ { 0x03CF, 0x012A },
+ { 0x03EF, 0x012B },
+ { 0x03C7, 0x012E },
+ { 0x03E7, 0x012F },
+ { 0x02A9, 0x0130 },
+ { 0x02B9, 0x0131 },
+ { 0x02AC, 0x0134 },
+ { 0x02BC, 0x0135 },
+ { 0x03D3, 0x0136 },
+ { 0x03F3, 0x0137 },
+ { 0x03A2, 0x0138 },
+ { 0x01C5, 0x0139 },
+ { 0x01E5, 0x013A },
+ { 0x03A6, 0x013B },
+ { 0x03B6, 0x013C },
+ { 0x01A5, 0x013D },
+ { 0x01B5, 0x013E },
+ { 0x01A3, 0x0141 },
+ { 0x01B3, 0x0142 },
+ { 0x01D1, 0x0143 },
+ { 0x01F1, 0x0144 },
+ { 0x03D1, 0x0145 },
+ { 0x03F1, 0x0146 },
+ { 0x01D2, 0x0147 },
+ { 0x01F2, 0x0148 },
+ { 0x03BD, 0x014A },
+ { 0x03BF, 0x014B },
+ { 0x03D2, 0x014C },
+ { 0x03F2, 0x014D },
+ { 0x01D5, 0x0150 },
+ { 0x01F5, 0x0151 },
+ { 0x13BC, 0x0152 },
+ { 0x13BD, 0x0153 },
+ { 0x01C0, 0x0154 },
+ { 0x01E0, 0x0155 },
+ { 0x03A3, 0x0156 },
+ { 0x03B3, 0x0157 },
+ { 0x01D8, 0x0158 },
+ { 0x01F8, 0x0159 },
+ { 0x01A6, 0x015A },
+ { 0x01B6, 0x015B },
+ { 0x02DE, 0x015C },
+ { 0x02FE, 0x015D },
+ { 0x01AA, 0x015E },
+ { 0x01BA, 0x015F },
+ { 0x01A9, 0x0160 },
+ { 0x01B9, 0x0161 },
+ { 0x01DE, 0x0162 },
+ { 0x01FE, 0x0163 },
+ { 0x01AB, 0x0164 },
+ { 0x01BB, 0x0165 },
+ { 0x03AC, 0x0166 },
+ { 0x03BC, 0x0167 },
+ { 0x03DD, 0x0168 },
+ { 0x03FD, 0x0169 },
+ { 0x03DE, 0x016A },
+ { 0x03FE, 0x016B },
+ { 0x02DD, 0x016C },
+ { 0x02FD, 0x016D },
+ { 0x01D9, 0x016E },
+ { 0x01F9, 0x016F },
+ { 0x01DB, 0x0170 },
+ { 0x01FB, 0x0171 },
+ { 0x03D9, 0x0172 },
+ { 0x03F9, 0x0173 },
+ { 0x13BE, 0x0178 },
+ { 0x01AC, 0x0179 },
+ { 0x01BC, 0x017A },
+ { 0x01AF, 0x017B },
+ { 0x01BF, 0x017C },
+ { 0x01AE, 0x017D },
+ { 0x01BE, 0x017E },
+ { 0x08F6, 0x0192 },
+ { 0x01B7, 0x02C7 },
+ { 0x01A2, 0x02D8 },
+ { 0x01FF, 0x02D9 },
+ { 0x01B2, 0x02DB },
+ { 0x01BD, 0x02DD },
+ { 0x07AE, 0x0385 },
+ { 0x07A1, 0x0386 },
+ { 0x07A2, 0x0388 },
+ { 0x07A3, 0x0389 },
+ { 0x07A4, 0x038A },
+ { 0x07A7, 0x038C },
+ { 0x07A8, 0x038E },
+ { 0x07AB, 0x038F },
+ { 0x07B6, 0x0390 },
+ { 0x07C1, 0x0391 },
+ { 0x07C2, 0x0392 },
+ { 0x07C3, 0x0393 },
+ { 0x07C4, 0x0394 },
+ { 0x07C5, 0x0395 },
+ { 0x07C6, 0x0396 },
+ { 0x07C7, 0x0397 },
+ { 0x07C8, 0x0398 },
+ { 0x07C9, 0x0399 },
+ { 0x07CA, 0x039A },
+ { 0x07CB, 0x039B },
+ { 0x07CC, 0x039C },
+ { 0x07CD, 0x039D },
+ { 0x07CE, 0x039E },
+ { 0x07CF, 0x039F },
+ { 0x07D0, 0x03A0 },
+ { 0x07D1, 0x03A1 },
+ { 0x07D2, 0x03A3 },
+ { 0x07D4, 0x03A4 },
+ { 0x07D5, 0x03A5 },
+ { 0x07D6, 0x03A6 },
+ { 0x07D7, 0x03A7 },
+ { 0x07D8, 0x03A8 },
+ { 0x07D9, 0x03A9 },
+ { 0x07A5, 0x03AA },
+ { 0x07A9, 0x03AB },
+ { 0x07B1, 0x03AC },
+ { 0x07B2, 0x03AD },
+ { 0x07B3, 0x03AE },
+ { 0x07B4, 0x03AF },
+ { 0x07BA, 0x03B0 },
+ { 0x07E1, 0x03B1 },
+ { 0x07E2, 0x03B2 },
+ { 0x07E3, 0x03B3 },
+ { 0x07E4, 0x03B4 },
+ { 0x07E5, 0x03B5 },
+ { 0x07E6, 0x03B6 },
+ { 0x07E7, 0x03B7 },
+ { 0x07E8, 0x03B8 },
+ { 0x07E9, 0x03B9 },
+ { 0x07EA, 0x03BA },
+ { 0x07EB, 0x03BB },
+ { 0x07EC, 0x03BC },
+ { 0x07ED, 0x03BD },
+ { 0x07EE, 0x03BE },
+ { 0x07EF, 0x03BF },
+ { 0x07F0, 0x03C0 },
+ { 0x07F1, 0x03C1 },
+ { 0x07F3, 0x03C2 },
+ { 0x07F2, 0x03C3 },
+ { 0x07F4, 0x03C4 },
+ { 0x07F5, 0x03C5 },
+ { 0x07F6, 0x03C6 },
+ { 0x07F7, 0x03C7 },
+ { 0x07F8, 0x03C8 },
+ { 0x07F9, 0x03C9 },
+ { 0x07B5, 0x03CA },
+ { 0x07B9, 0x03CB },
+ { 0x07B7, 0x03CC },
+ { 0x07B8, 0x03CD },
+ { 0x07BB, 0x03CE },
+ { 0x06B3, 0x0401 },
+ { 0x06B1, 0x0402 },
+ { 0x06B2, 0x0403 },
+ { 0x06B4, 0x0404 },
+ { 0x06B5, 0x0405 },
+ { 0x06B6, 0x0406 },
+ { 0x06B7, 0x0407 },
+ { 0x06B8, 0x0408 },
+ { 0x06B9, 0x0409 },
+ { 0x06BA, 0x040A },
+ { 0x06BB, 0x040B },
+ { 0x06BC, 0x040C },
+ { 0x06BE, 0x040E },
+ { 0x06BF, 0x040F },
+ { 0x06E1, 0x0410 },
+ { 0x06E2, 0x0411 },
+ { 0x06F7, 0x0412 },
+ { 0x06E7, 0x0413 },
+ { 0x06E4, 0x0414 },
+ { 0x06E5, 0x0415 },
+ { 0x06F6, 0x0416 },
+ { 0x06FA, 0x0417 },
+ { 0x06E9, 0x0418 },
+ { 0x06EA, 0x0419 },
+ { 0x06EB, 0x041A },
+ { 0x06EC, 0x041B },
+ { 0x06ED, 0x041C },
+ { 0x06EE, 0x041D },
+ { 0x06EF, 0x041E },
+ { 0x06F0, 0x041F },
+ { 0x06F2, 0x0420 },
+ { 0x06F3, 0x0421 },
+ { 0x06F4, 0x0422 },
+ { 0x06F5, 0x0423 },
+ { 0x06E6, 0x0424 },
+ { 0x06E8, 0x0425 },
+ { 0x06E3, 0x0426 },
+ { 0x06FE, 0x0427 },
+ { 0x06FB, 0x0428 },
+ { 0x06FD, 0x0429 },
+ { 0x06FF, 0x042A },
+ { 0x06F9, 0x042B },
+ { 0x06F8, 0x042C },
+ { 0x06FC, 0x042D },
+ { 0x06E0, 0x042E },
+ { 0x06F1, 0x042F },
+ { 0x06C1, 0x0430 },
+ { 0x06C2, 0x0431 },
+ { 0x06D7, 0x0432 },
+ { 0x06C7, 0x0433 },
+ { 0x06C4, 0x0434 },
+ { 0x06C5, 0x0435 },
+ { 0x06D6, 0x0436 },
+ { 0x06DA, 0x0437 },
+ { 0x06C9, 0x0438 },
+ { 0x06CA, 0x0439 },
+ { 0x06CB, 0x043A },
+ { 0x06CC, 0x043B },
+ { 0x06CD, 0x043C },
+ { 0x06CE, 0x043D },
+ { 0x06CF, 0x043E },
+ { 0x06D0, 0x043F },
+ { 0x06D2, 0x0440 },
+ { 0x06D3, 0x0441 },
+ { 0x06D4, 0x0442 },
+ { 0x06D5, 0x0443 },
+ { 0x06C6, 0x0444 },
+ { 0x06C8, 0x0445 },
+ { 0x06C3, 0x0446 },
+ { 0x06DE, 0x0447 },
+ { 0x06DB, 0x0448 },
+ { 0x06DD, 0x0449 },
+ { 0x06DF, 0x044A },
+ { 0x06D9, 0x044B },
+ { 0x06D8, 0x044C },
+ { 0x06DC, 0x044D },
+ { 0x06C0, 0x044E },
+ { 0x06D1, 0x044F },
+ { 0x06A3, 0x0451 },
+ { 0x06A1, 0x0452 },
+ { 0x06A2, 0x0453 },
+ { 0x06A4, 0x0454 },
+ { 0x06A5, 0x0455 },
+ { 0x06A6, 0x0456 },
+ { 0x06A7, 0x0457 },
+ { 0x06A8, 0x0458 },
+ { 0x06A9, 0x0459 },
+ { 0x06AA, 0x045A },
+ { 0x06AB, 0x045B },
+ { 0x06AC, 0x045C },
+ { 0x06AE, 0x045E },
+ { 0x06AF, 0x045F },
+ { 0x0CE0, 0x05D0 },
+ { 0x0CE1, 0x05D1 },
+ { 0x0CE2, 0x05D2 },
+ { 0x0CE3, 0x05D3 },
+ { 0x0CE4, 0x05D4 },
+ { 0x0CE5, 0x05D5 },
+ { 0x0CE6, 0x05D6 },
+ { 0x0CE7, 0x05D7 },
+ { 0x0CE8, 0x05D8 },
+ { 0x0CE9, 0x05D9 },
+ { 0x0CEA, 0x05DA },
+ { 0x0CEB, 0x05DB },
+ { 0x0CEC, 0x05DC },
+ { 0x0CED, 0x05DD },
+ { 0x0CEE, 0x05DE },
+ { 0x0CEF, 0x05DF },
+ { 0x0CF0, 0x05E0 },
+ { 0x0CF1, 0x05E1 },
+ { 0x0CF2, 0x05E2 },
+ { 0x0CF3, 0x05E3 },
+ { 0x0CF4, 0x05E4 },
+ { 0x0CF5, 0x05E5 },
+ { 0x0CF6, 0x05E6 },
+ { 0x0CF7, 0x05E7 },
+ { 0x0CF8, 0x05E8 },
+ { 0x0CF9, 0x05E9 },
+ { 0x0CFA, 0x05EA },
+ { 0x05AC, 0x060C },
+ { 0x05BB, 0x061B },
+ { 0x05BF, 0x061F },
+ { 0x05C1, 0x0621 },
+ { 0x05C2, 0x0622 },
+ { 0x05C3, 0x0623 },
+ { 0x05C4, 0x0624 },
+ { 0x05C5, 0x0625 },
+ { 0x05C6, 0x0626 },
+ { 0x05C7, 0x0627 },
+ { 0x05C8, 0x0628 },
+ { 0x05C9, 0x0629 },
+ { 0x05CA, 0x062A },
+ { 0x05CB, 0x062B },
+ { 0x05CC, 0x062C },
+ { 0x05CD, 0x062D },
+ { 0x05CE, 0x062E },
+ { 0x05CF, 0x062F },
+ { 0x05D0, 0x0630 },
+ { 0x05D1, 0x0631 },
+ { 0x05D2, 0x0632 },
+ { 0x05D3, 0x0633 },
+ { 0x05D4, 0x0634 },
+ { 0x05D5, 0x0635 },
+ { 0x05D6, 0x0636 },
+ { 0x05D7, 0x0637 },
+ { 0x05D8, 0x0638 },
+ { 0x05D9, 0x0639 },
+ { 0x05DA, 0x063A },
+ { 0x05E0, 0x0640 },
+ { 0x05E1, 0x0641 },
+ { 0x05E2, 0x0642 },
+ { 0x05E3, 0x0643 },
+ { 0x05E4, 0x0644 },
+ { 0x05E5, 0x0645 },
+ { 0x05E6, 0x0646 },
+ { 0x05E7, 0x0647 },
+ { 0x05E8, 0x0648 },
+ { 0x05E9, 0x0649 },
+ { 0x05EA, 0x064A },
+ { 0x05EB, 0x064B },
+ { 0x05EC, 0x064C },
+ { 0x05ED, 0x064D },
+ { 0x05EE, 0x064E },
+ { 0x05EF, 0x064F },
+ { 0x05F0, 0x0650 },
+ { 0x05F1, 0x0651 },
+ { 0x05F2, 0x0652 },
+ { 0x0DA1, 0x0E01 },
+ { 0x0DA2, 0x0E02 },
+ { 0x0DA3, 0x0E03 },
+ { 0x0DA4, 0x0E04 },
+ { 0x0DA5, 0x0E05 },
+ { 0x0DA6, 0x0E06 },
+ { 0x0DA7, 0x0E07 },
+ { 0x0DA8, 0x0E08 },
+ { 0x0DA9, 0x0E09 },
+ { 0x0DAA, 0x0E0A },
+ { 0x0DAB, 0x0E0B },
+ { 0x0DAC, 0x0E0C },
+ { 0x0DAD, 0x0E0D },
+ { 0x0DAE, 0x0E0E },
+ { 0x0DAF, 0x0E0F },
+ { 0x0DB0, 0x0E10 },
+ { 0x0DB1, 0x0E11 },
+ { 0x0DB2, 0x0E12 },
+ { 0x0DB3, 0x0E13 },
+ { 0x0DB4, 0x0E14 },
+ { 0x0DB5, 0x0E15 },
+ { 0x0DB6, 0x0E16 },
+ { 0x0DB7, 0x0E17 },
+ { 0x0DB8, 0x0E18 },
+ { 0x0DB9, 0x0E19 },
+ { 0x0DBA, 0x0E1A },
+ { 0x0DBB, 0x0E1B },
+ { 0x0DBC, 0x0E1C },
+ { 0x0DBD, 0x0E1D },
+ { 0x0DBE, 0x0E1E },
+ { 0x0DBF, 0x0E1F },
+ { 0x0DC0, 0x0E20 },
+ { 0x0DC1, 0x0E21 },
+ { 0x0DC2, 0x0E22 },
+ { 0x0DC3, 0x0E23 },
+ { 0x0DC4, 0x0E24 },
+ { 0x0DC5, 0x0E25 },
+ { 0x0DC6, 0x0E26 },
+ { 0x0DC7, 0x0E27 },
+ { 0x0DC8, 0x0E28 },
+ { 0x0DC9, 0x0E29 },
+ { 0x0DCA, 0x0E2A },
+ { 0x0DCB, 0x0E2B },
+ { 0x0DCC, 0x0E2C },
+ { 0x0DCD, 0x0E2D },
+ { 0x0DCE, 0x0E2E },
+ { 0x0DCF, 0x0E2F },
+ { 0x0DD0, 0x0E30 },
+ { 0x0DD1, 0x0E31 },
+ { 0x0DD2, 0x0E32 },
+ { 0x0DD3, 0x0E33 },
+ { 0x0DD4, 0x0E34 },
+ { 0x0DD5, 0x0E35 },
+ { 0x0DD6, 0x0E36 },
+ { 0x0DD7, 0x0E37 },
+ { 0x0DD8, 0x0E38 },
+ { 0x0DD9, 0x0E39 },
+ { 0x0DDA, 0x0E3A },
+ { 0x0DDF, 0x0E3F },
+ { 0x0DE0, 0x0E40 },
+ { 0x0DE1, 0x0E41 },
+ { 0x0DE2, 0x0E42 },
+ { 0x0DE3, 0x0E43 },
+ { 0x0DE4, 0x0E44 },
+ { 0x0DE5, 0x0E45 },
+ { 0x0DE6, 0x0E46 },
+ { 0x0DE7, 0x0E47 },
+ { 0x0DE8, 0x0E48 },
+ { 0x0DE9, 0x0E49 },
+ { 0x0DEA, 0x0E4A },
+ { 0x0DEB, 0x0E4B },
+ { 0x0DEC, 0x0E4C },
+ { 0x0DED, 0x0E4D },
+ { 0x0DF0, 0x0E50 },
+ { 0x0DF1, 0x0E51 },
+ { 0x0DF2, 0x0E52 },
+ { 0x0DF3, 0x0E53 },
+ { 0x0DF4, 0x0E54 },
+ { 0x0DF5, 0x0E55 },
+ { 0x0DF6, 0x0E56 },
+ { 0x0DF7, 0x0E57 },
+ { 0x0DF8, 0x0E58 },
+ { 0x0DF9, 0x0E59 },
+ { 0x0ED4, 0x11A8 },
+ { 0x0ED5, 0x11A9 },
+ { 0x0ED6, 0x11AA },
+ { 0x0ED7, 0x11AB },
+ { 0x0ED8, 0x11AC },
+ { 0x0ED9, 0x11AD },
+ { 0x0EDA, 0x11AE },
+ { 0x0EDB, 0x11AF },
+ { 0x0EDC, 0x11B0 },
+ { 0x0EDD, 0x11B1 },
+ { 0x0EDE, 0x11B2 },
+ { 0x0EDF, 0x11B3 },
+ { 0x0EE0, 0x11B4 },
+ { 0x0EE1, 0x11B5 },
+ { 0x0EE2, 0x11B6 },
+ { 0x0EE3, 0x11B7 },
+ { 0x0EE4, 0x11B8 },
+ { 0x0EE5, 0x11B9 },
+ { 0x0EE6, 0x11BA },
+ { 0x0EE7, 0x11BB },
+ { 0x0EE8, 0x11BC },
+ { 0x0EE9, 0x11BD },
+ { 0x0EEA, 0x11BE },
+ { 0x0EEB, 0x11BF },
+ { 0x0EEC, 0x11C0 },
+ { 0x0EED, 0x11C1 },
+ { 0x0EEE, 0x11C2 },
+ { 0x0EF8, 0x11EB },
+ { 0x0EFA, 0x11F9 },
+ { 0x0AA2, 0x2002 },
+ { 0x0AA1, 0x2003 },
+ { 0x0AA3, 0x2004 },
+ { 0x0AA4, 0x2005 },
+ { 0x0AA5, 0x2007 },
+ { 0x0AA6, 0x2008 },
+ { 0x0AA7, 0x2009 },
+ { 0x0AA8, 0x200A },
+ { 0x0ABB, 0x2012 },
+ { 0x0AAA, 0x2013 },
+ { 0x0AA9, 0x2014 },
+ { 0x07AF, 0x2015 },
+ { 0x0CDF, 0x2017 },
+ { 0x0AD0, 0x2018 },
+ { 0x0AD1, 0x2019 },
+ { 0x0AFD, 0x201A },
+ { 0x0AD2, 0x201C },
+ { 0x0AD3, 0x201D },
+ { 0x0AFE, 0x201E },
+ { 0x0AF1, 0x2020 },
+ { 0x0AF2, 0x2021 },
+ { 0x0AE6, 0x2022 },
+ { 0x0AAE, 0x2026 },
+ { 0x0AD6, 0x2032 },
+ { 0x0AD7, 0x2033 },
+ { 0x0AFC, 0x2038 },
+ { 0x047E, 0x203E },
+ { 0x20A0, 0x20A0 },
+ { 0x20A1, 0x20A1 },
+ { 0x20A2, 0x20A2 },
+ { 0x20A3, 0x20A3 },
+ { 0x20A4, 0x20A4 },
+ { 0x20A5, 0x20A5 },
+ { 0x20A6, 0x20A6 },
+ { 0x20A7, 0x20A7 },
+ { 0x20A8, 0x20A8 },
+ { 0x0EFF, 0x20A9 },
+ { 0x20A9, 0x20A9 },
+ { 0x20AA, 0x20AA },
+ { 0x20AB, 0x20AB },
+ { 0x20AC, 0x20AC },
+ { 0x0AB8, 0x2105 },
+ { 0x06B0, 0x2116 },
+ { 0x0AFB, 0x2117 },
+ { 0x0AD4, 0x211E },
+ { 0x0AC9, 0x2122 },
+ { 0x0AB0, 0x2153 },
+ { 0x0AB1, 0x2154 },
+ { 0x0AB2, 0x2155 },
+ { 0x0AB3, 0x2156 },
+ { 0x0AB4, 0x2157 },
+ { 0x0AB5, 0x2158 },
+ { 0x0AB6, 0x2159 },
+ { 0x0AB7, 0x215A },
+ { 0x0AC3, 0x215B },
+ { 0x0AC4, 0x215C },
+ { 0x0AC5, 0x215D },
+ { 0x0AC6, 0x215E },
+ { 0x08FB, 0x2190 },
+ { 0x08FC, 0x2191 },
+ { 0x08FD, 0x2192 },
+ { 0x08FE, 0x2193 },
+ { 0x08CE, 0x21D2 },
+ { 0x08CD, 0x21D4 },
+ { 0x08EF, 0x2202 },
+ { 0x08C5, 0x2207 },
+ { 0x0BCA, 0x2218 },
+ { 0x08D6, 0x221A },
+ { 0x08C1, 0x221D },
+ { 0x08C2, 0x221E },
+ { 0x08DE, 0x2227 },
+ { 0x0BA9, 0x2227 },
+ { 0x08DF, 0x2228 },
+ { 0x0BA8, 0x2228 },
+ { 0x08DC, 0x2229 },
+ { 0x0BC3, 0x2229 },
+ { 0x08DD, 0x222A },
+ { 0x0BD6, 0x222A },
+ { 0x08BF, 0x222B },
+ { 0x08C0, 0x2234 },
+ { 0x08C8, 0x2245 },
+ { 0x08BD, 0x2260 },
+ { 0x08CF, 0x2261 },
+ { 0x08BC, 0x2264 },
+ { 0x08BE, 0x2265 },
+ { 0x08DA, 0x2282 },
+ { 0x0BDA, 0x2282 },
+ { 0x08DB, 0x2283 },
+ { 0x0BD8, 0x2283 },
+ { 0x0BFC, 0x22A2 },
+ { 0x0BDC, 0x22A3 },
+ { 0x0BC2, 0x22A4 },
+ { 0x0BCE, 0x22A5 },
+ { 0x0BD3, 0x2308 },
+ { 0x0BC4, 0x230A },
+ { 0x0AFA, 0x2315 },
+ { 0x08A4, 0x2320 },
+ { 0x08A5, 0x2321 },
+ { 0x0ABC, 0x2329 },
+ { 0x0ABE, 0x232A },
+ { 0x0BCC, 0x2395 },
+ { 0x09E2, 0x2409 },
+ { 0x09E5, 0x240A },
+ { 0x09E9, 0x240B },
+ { 0x09E3, 0x240C },
+ { 0x09E4, 0x240D },
+ { 0x09DF, 0x2422 },
+ { 0x09E8, 0x2424 },
+ { 0x09F1, 0x2500 },
+ { 0x08A6, 0x2502 },
+ { 0x09F8, 0x2502 },
+ { 0x09EC, 0x250C },
+ { 0x09EB, 0x2510 },
+ { 0x09ED, 0x2514 },
+ { 0x09EA, 0x2518 },
+ { 0x09F4, 0x251C },
+ { 0x09F5, 0x2524 },
+ { 0x09F7, 0x252C },
+ { 0x09F6, 0x2534 },
+ { 0x09EE, 0x253C },
+ { 0x09E1, 0x2592 },
+ { 0x0ADF, 0x25A0 },
+ { 0x0ACF, 0x25A1 },
+ { 0x0AE7, 0x25AA },
+ { 0x0AE1, 0x25AB },
+ { 0x0ADB, 0x25AC },
+ { 0x0AE2, 0x25AD },
+ { 0x0AE8, 0x25B2 },
+ { 0x0AE3, 0x25B3 },
+ { 0x0ADD, 0x25B6 },
+ { 0x0ACD, 0x25B7 },
+ { 0x0AE9, 0x25BC },
+ { 0x0AE4, 0x25BD },
+ { 0x0ADC, 0x25C0 },
+ { 0x0ACC, 0x25C1 },
+ { 0x09E0, 0x25C6 },
+ { 0x0ACE, 0x25CB },
+ { 0x0BCF, 0x25CB },
+ { 0x0ADE, 0x25CF },
+ { 0x0AE0, 0x25E6 },
+ { 0x0AE5, 0x2606 },
+ { 0x0AF9, 0x260E },
+ { 0x0ACA, 0x2613 },
+ { 0x0AEA, 0x261C },
+ { 0x0AEB, 0x261E },
+ { 0x0AF8, 0x2640 },
+ { 0x0AF7, 0x2642 },
+ { 0x0AEC, 0x2663 },
+ { 0x0AEE, 0x2665 },
+ { 0x0AED, 0x2666 },
+ { 0x0AF6, 0x266D },
+ { 0x0AF5, 0x266F },
+ { 0x0AF3, 0x2713 },
+ { 0x0AF4, 0x2717 },
+ { 0x0AD9, 0x271D },
+ { 0x0AF0, 0x2720 },
+ { 0x04A4, 0x3001 },
+ { 0x04A1, 0x3002 },
+ { 0x04A2, 0x300C },
+ { 0x04A3, 0x300D },
+ { 0x04DE, 0x309B },
+ { 0x04DF, 0x309C },
+ { 0x04A7, 0x30A1 },
+ { 0x04B1, 0x30A2 },
+ { 0x04A8, 0x30A3 },
+ { 0x04B2, 0x30A4 },
+ { 0x04A9, 0x30A5 },
+ { 0x04B3, 0x30A6 },
+ { 0x04AA, 0x30A7 },
+ { 0x04B4, 0x30A8 },
+ { 0x04AB, 0x30A9 },
+ { 0x04B5, 0x30AA },
+ { 0x04B6, 0x30AB },
+ { 0x04B7, 0x30AD },
+ { 0x04B8, 0x30AF },
+ { 0x04B9, 0x30B1 },
+ { 0x04BA, 0x30B3 },
+ { 0x04BB, 0x30B5 },
+ { 0x04BC, 0x30B7 },
+ { 0x04BD, 0x30B9 },
+ { 0x04BE, 0x30BB },
+ { 0x04BF, 0x30BD },
+ { 0x04C0, 0x30BF },
+ { 0x04C1, 0x30C1 },
+ { 0x04AF, 0x30C3 },
+ { 0x04C2, 0x30C4 },
+ { 0x04C3, 0x30C6 },
+ { 0x04C4, 0x30C8 },
+ { 0x04C5, 0x30CA },
+ { 0x04C6, 0x30CB },
+ { 0x04C7, 0x30CC },
+ { 0x04C8, 0x30CD },
+ { 0x04C9, 0x30CE },
+ { 0x04CA, 0x30CF },
+ { 0x04CB, 0x30D2 },
+ { 0x04CC, 0x30D5 },
+ { 0x04CD, 0x30D8 },
+ { 0x04CE, 0x30DB },
+ { 0x04CF, 0x30DE },
+ { 0x04D0, 0x30DF },
+ { 0x04D1, 0x30E0 },
+ { 0x04D2, 0x30E1 },
+ { 0x04D3, 0x30E2 },
+ { 0x04AC, 0x30E3 },
+ { 0x04D4, 0x30E4 },
+ { 0x04AD, 0x30E5 },
+ { 0x04D5, 0x30E6 },
+ { 0x04AE, 0x30E7 },
+ { 0x04D6, 0x30E8 },
+ { 0x04D7, 0x30E9 },
+ { 0x04D8, 0x30EA },
+ { 0x04D9, 0x30EB },
+ { 0x04DA, 0x30EC },
+ { 0x04DB, 0x30ED },
+ { 0x04DC, 0x30EF },
+ { 0x04A6, 0x30F2 },
+ { 0x04DD, 0x30F3 },
+ { 0x04A5, 0x30FB },
+ { 0x04B0, 0x30FC },
+ { 0x0EA1, 0x3131 },
+ { 0x0EA2, 0x3132 },
+ { 0x0EA3, 0x3133 },
+ { 0x0EA4, 0x3134 },
+ { 0x0EA5, 0x3135 },
+ { 0x0EA6, 0x3136 },
+ { 0x0EA7, 0x3137 },
+ { 0x0EA8, 0x3138 },
+ { 0x0EA9, 0x3139 },
+ { 0x0EAA, 0x313A },
+ { 0x0EAB, 0x313B },
+ { 0x0EAC, 0x313C },
+ { 0x0EAD, 0x313D },
+ { 0x0EAE, 0x313E },
+ { 0x0EAF, 0x313F },
+ { 0x0EB0, 0x3140 },
+ { 0x0EB1, 0x3141 },
+ { 0x0EB2, 0x3142 },
+ { 0x0EB3, 0x3143 },
+ { 0x0EB4, 0x3144 },
+ { 0x0EB5, 0x3145 },
+ { 0x0EB6, 0x3146 },
+ { 0x0EB7, 0x3147 },
+ { 0x0EB8, 0x3148 },
+ { 0x0EB9, 0x3149 },
+ { 0x0EBA, 0x314A },
+ { 0x0EBB, 0x314B },
+ { 0x0EBC, 0x314C },
+ { 0x0EBD, 0x314D },
+ { 0x0EBE, 0x314E },
+ { 0x0EBF, 0x314F },
+ { 0x0EC0, 0x3150 },
+ { 0x0EC1, 0x3151 },
+ { 0x0EC2, 0x3152 },
+ { 0x0EC3, 0x3153 },
+ { 0x0EC4, 0x3154 },
+ { 0x0EC5, 0x3155 },
+ { 0x0EC6, 0x3156 },
+ { 0x0EC7, 0x3157 },
+ { 0x0EC8, 0x3158 },
+ { 0x0EC9, 0x3159 },
+ { 0x0ECA, 0x315A },
+ { 0x0ECB, 0x315B },
+ { 0x0ECC, 0x315C },
+ { 0x0ECD, 0x315D },
+ { 0x0ECE, 0x315E },
+ { 0x0ECF, 0x315F },
+ { 0x0ED0, 0x3160 },
+ { 0x0ED1, 0x3161 },
+ { 0x0ED2, 0x3162 },
+ { 0x0ED3, 0x3163 },
+ { 0x0EEF, 0x316D },
+ { 0x0EF0, 0x3171 },
+ { 0x0EF1, 0x3178 },
+ { 0x0EF2, 0x317F },
+ { 0x0EF4, 0x3184 },
+ { 0x0EF5, 0x3186 },
+ { 0x0EF6, 0x318D },
+ { 0x0EF7, 0x318E }
+};
+
+KeySym KeyMappingX11::get_keysym_from_unicode(unsigned int p_unicode) {
+
+ /* Latin 1 */
+
+ if (p_unicode>=0x20 && p_unicode<=0x7e)
+ return p_unicode;
+
+ if (p_unicode>=0xa0 && p_unicode<=0xff)
+ return p_unicode;
+
+ int middle,low=0,high=_UNICODE_MAX-1;
+ do {
+ middle=(high+low)/2;
+ if ( _unicode_to_xkeysym[middle].keysym==p_unicode)
+ return _unicode_to_xkeysym[middle].keysym;
+ if ( _unicode_to_xkeysym[middle].keysym<=p_unicode )
+ low=middle+1;
+ else
+ high=middle-1;
+ } while (high>=low);
+
+ // if not found, let's hope X understands it as unicode
+ return p_unicode|0x01000000;
+}
diff --git a/platform/x11/key_mapping_x11.h b/platform/x11/key_mapping_x11.h
new file mode 100644
index 0000000000..97393d92f3
--- /dev/null
+++ b/platform/x11/key_mapping_x11.h
@@ -0,0 +1,55 @@
+/*************************************************************************/
+/* key_mapping_x11.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef KEY_MAPPING_X11_H
+#define KEY_MAPPING_X11_H
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+#include <X11/Xlib.h>
+#include <X11/XF86keysym.h>
+#define XK_MISCELLANY
+#define XK_LATIN1
+#define XK_XKB_KEYS
+#include <X11/keysymdef.h>
+
+#include "os/keyboard.h"
+
+class KeyMappingX11 {
+ KeyMappingX11() {};
+public:
+ static unsigned int get_keycode(KeySym p_keysym);
+ static KeySym get_keysym(unsigned int p_code);
+ static unsigned int get_unicode_from_keysym(KeySym p_keysym);
+ static KeySym get_keysym_from_unicode(unsigned int p_unicode);
+
+};
+
+
+#endif
diff --git a/platform/x11/logo.png b/platform/x11/logo.png
new file mode 100644
index 0000000000..c40214d6de
--- /dev/null
+++ b/platform/x11/logo.png
Binary files differ
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
new file mode 100644
index 0000000000..79dd6f1234
--- /dev/null
+++ b/platform/x11/os_x11.cpp
@@ -0,0 +1,1300 @@
+/*************************************************************************/
+/* os_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "servers/visual/visual_server_raster.h"
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "drivers/gles1/rasterizer_gles1.h"
+#include "os_x11.h"
+#include "key_mapping_x11.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "print_string.h"
+#include "servers/physics/physics_server_sw.h"
+
+#include "X11/Xutil.h"
+#include "main/main.h"
+
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/joystick.h>
+
+//stupid linux.h
+#ifdef KEY_TAB
+#undef KEY_TAB
+#endif
+
+
+#include <X11/Xatom.h>
+#include "os/pc_joystick_map.h"
+
+#undef CursorShape
+
+int OS_X11::get_video_driver_count() const {
+
+ return 2;
+}
+const char * OS_X11::get_video_driver_name(int p_driver) const {
+
+ return p_driver==0?"GLES2":"GLES1";
+}
+OS::VideoMode OS_X11::get_default_video_mode() const {
+
+ return OS::VideoMode(800,600,false);
+}
+
+void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
+
+ last_button_state=0;
+ dpad_last[0]=0;
+ dpad_last[1]=0;
+
+ xmbstring=NULL;
+ event_id=0;
+ x11_window=0;
+ last_click_ms=0;
+ args=OS::get_singleton()->get_cmdline_args();
+ current_videomode=p_desired;
+ main_loop=NULL;
+ last_timestamp=0;
+ last_mouse_pos_valid=false;
+ last_keyrelease_time=0;
+
+ if (get_render_thread_mode()==RENDER_SEPARATE_THREAD) {
+ XInitThreads();
+ }
+
+ /** XLIB INITIALIZATION **/
+ x11_display = XOpenDisplay(NULL);
+
+ char * modifiers = XSetLocaleModifiers ("@im=none");
+ ERR_FAIL_COND( modifiers == NULL );
+
+ xim = XOpenIM (x11_display, NULL, NULL, NULL);
+
+
+ if (xim == NULL) {
+ WARN_PRINT("XOpenIM failed");
+ xim_style=NULL;
+ } else {
+ ::XIMStyles *xim_styles=NULL;
+ xim_style=0;
+ char *imvalret=NULL;
+ imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
+ if (imvalret != NULL || xim_styles == NULL) {
+ fprintf (stderr, "Input method doesn't support any styles\n");
+ }
+
+ if (xim_styles) {
+ xim_style = 0;
+ for (int i=0;i<xim_styles->count_styles;i++) {
+
+ if (xim_styles->supported_styles[i] ==
+ (XIMPreeditNothing | XIMStatusNothing)) {
+
+ xim_style = xim_styles->supported_styles[i];
+ break;
+ }
+ }
+
+ XFree (xim_styles);
+ }
+ }
+
+ /*
+ char* windowid = getenv("GODOT_WINDOWID");
+ if (windowid) {
+
+ //freopen("/home/punto/stdout", "w", stdout);
+ //reopen("/home/punto/stderr", "w", stderr);
+ x11_window = atol(windowid);
+
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display,x11_window,&xwa);
+
+ current_videomode.width = xwa.width;
+ current_videomode.height = xwa.height;
+ };
+ */
+
+ // maybe contextgl wants to be in charge of creating the window
+ //print_line("def videomode "+itos(current_videomode.width)+","+itos(current_videomode.height));
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+ context_gl = memnew( ContextGL_X11( x11_display, x11_window,current_videomode, false ) );
+ context_gl->initialize();
+
+ if (p_video_driver == 0) {
+ rasterizer = memnew( RasterizerGLES2 );
+ } else {
+ rasterizer = memnew( RasterizerGLES1 );
+ };
+
+#endif
+ visual_server = memnew( VisualServerRaster(rasterizer) );
+
+ if (get_render_thread_mode()!=RENDER_THREAD_UNSAFE) {
+
+ visual_server =memnew(VisualServerWrapMT(visual_server,get_render_thread_mode()==RENDER_SEPARATE_THREAD));
+ }
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
+
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerSW(sample_manager) );
+ audio_server->init();
+ spatial_sound_server = memnew( SpatialSoundServerSW );
+ spatial_sound_server->init();
+ spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
+ spatial_sound_2d_server->init();
+
+
+ ERR_FAIL_COND(!visual_server);
+ ERR_FAIL_COND(x11_window==0);
+
+ XSetWindowAttributes new_attr;
+
+ new_attr.event_mask=KeyPressMask | KeyReleaseMask | ButtonPressMask |
+ ButtonReleaseMask | EnterWindowMask |
+ LeaveWindowMask | PointerMotionMask |
+ Button1MotionMask |
+ Button2MotionMask | Button3MotionMask |
+ Button4MotionMask | Button5MotionMask |
+ ButtonMotionMask | KeymapStateMask |
+ ExposureMask | VisibilityChangeMask |
+ StructureNotifyMask |
+ SubstructureNotifyMask | SubstructureRedirectMask |
+ FocusChangeMask | PropertyChangeMask |
+ ColormapChangeMask | OwnerGrabButtonMask;
+
+ XChangeWindowAttributes(x11_display, x11_window,CWEventMask,&new_attr);
+
+ wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true);
+ XSetWMProtocols(x11_display, x11_window, &wm_delete, 1);
+
+
+ if (xim && xim_style) {
+
+ xic = XCreateIC (xim,XNInputStyle, xim_style,XNClientWindow,x11_window,XNFocusWindow, x11_window, (char*)NULL);
+ } else {
+
+ xic=NULL;
+ WARN_PRINT("XCreateIC couldn't create xic");
+
+ }
+
+ XcursorSetTheme(x11_display,"default");
+ cursor_size = XcursorGetDefaultSize(x11_display);
+ cursor_theme = XcursorGetTheme(x11_display);
+
+ if (!cursor_theme) {
+ print_line("not found theme");
+ cursor_theme="default";
+ }
+
+ for(int i=0;i<CURSOR_MAX;i++) {
+
+ cursors[i]=None;
+ }
+
+ current_cursor=CURSOR_ARROW;
+
+ if (cursor_theme) {
+ //print_line("cursor theme: "+String(cursor_theme));
+ for(int i=0;i<CURSOR_MAX;i++) {
+
+ static const char *cursor_file[]={
+ "left_ptr",
+ "xterm",
+ "hand2",
+ "cross",
+ "watch",
+ "left_ptr_watch",
+ "fleur",
+ "hand1",
+ "X_cursor",
+ "sb_v_double_arrow",
+ "sb_h_double_arrow",
+ "size_bdiag",
+ "size_fdiag",
+ "hand1",
+ "sb_v_double_arrow",
+ "sb_h_double_arrow",
+ "question_arrow"
+ };
+
+ XcursorImage *img = XcursorLibraryLoadImage(cursor_file[i],cursor_theme,cursor_size);
+ if (img) {
+ cursors[i]=XcursorImageLoadCursor(x11_display,img);
+ //print_line("found cursor: "+String(cursor_file[i])+" id "+itos(cursors[i]));
+ } else {
+ if (OS::is_stdout_verbose())
+ print_line("failed cursor: "+String(cursor_file[i]));
+ }
+ }
+
+ }
+
+
+ {
+ Pixmap cursormask;
+ XGCValues xgc;
+ GC gc;
+ XColor col;
+ Cursor cursor;
+
+ cursormask = XCreatePixmap(x11_display, RootWindow(x11_display,DefaultScreen(x11_display)), 1, 1, 1);
+ xgc.function = GXclear;
+ gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc);
+ XFillRectangle(x11_display, cursormask, gc, 0, 0, 1, 1);
+ col.pixel = 0;
+ col.red = 0;
+ col.flags = 4;
+ cursor = XCreatePixmapCursor(x11_display,
+ cursormask, cursormask,
+ &col, &col, 0, 0);
+ XFreePixmap(x11_display, cursormask);
+ XFreeGC(x11_display, gc);
+
+
+
+ if (cursor == None)
+ {
+ ERR_PRINT("FAILED CREATING CURSOR");
+ }
+
+ null_cursor=cursor;
+ }
+ set_cursor_shape(CURSOR_BUSY);
+
+
+ visual_server->init();
+ //
+ physics_server = memnew( PhysicsServerSW );
+ physics_server->init();
+ physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server->init();
+
+ input = memnew( InputDefault );
+
+ probe_joystick();
+
+ _ensure_data_dir();
+
+ net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
+
+
+ //printf("got map notify\n");
+
+}
+void OS_X11::finalize() {
+
+ if(main_loop)
+ memdelete(main_loop);
+ main_loop=NULL;
+
+ spatial_sound_server->finish();
+ memdelete(spatial_sound_server);
+ spatial_sound_2d_server->finish();
+ memdelete(spatial_sound_2d_server);
+
+ //if (debugger_connection_console) {
+// memdelete(debugger_connection_console);
+//}
+
+ audio_server->finish();
+ memdelete(audio_server);
+ memdelete(sample_manager);
+
+ visual_server->finish();
+ memdelete(visual_server);
+ memdelete(rasterizer);
+
+ physics_server->finish();
+ memdelete(physics_server);
+
+ physics_2d_server->finish();
+ memdelete(physics_2d_server);
+
+ memdelete(input);
+
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+ memdelete(context_gl);
+#endif
+
+
+ XCloseDisplay(x11_display);
+ if (xmbstring)
+ memfree(xmbstring);
+
+ args.clear();
+}
+
+
+void OS_X11::set_mouse_mode(MouseMode p_mode) {
+
+ print_line("WUTF "+itos(p_mode)+" old "+itos(mouse_mode));
+ if (p_mode==mouse_mode)
+ return;
+
+ if (mouse_mode==MOUSE_MODE_CAPTURED)
+ XUngrabPointer(x11_display, CurrentTime);
+ if (mouse_mode!=MOUSE_MODE_VISIBLE && p_mode==MOUSE_MODE_VISIBLE)
+ XUndefineCursor(x11_display,x11_window);
+ if (p_mode!=MOUSE_MODE_VISIBLE && mouse_mode==MOUSE_MODE_VISIBLE) {
+ XDefineCursor(x11_display,x11_window,null_cursor);
+ }
+
+ mouse_mode=p_mode;
+
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ if (XGrabPointer(x11_display, x11_window, True,
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask, GrabModeAsync, GrabModeAsync,
+ x11_window, None, CurrentTime) !=
+ GrabSuccess) {
+ ERR_PRINT("NO GRAB");
+ }
+
+ center.x = current_videomode.width/2;
+ center.y = current_videomode.height/2;
+ XWarpPointer(x11_display, None, x11_window,
+ 0,0,0,0, (int)center.x, (int)center.y);
+ }
+
+}
+
+OS::MouseMode OS_X11::get_mouse_mode() const {
+
+ return mouse_mode;
+}
+
+
+
+int OS_X11::get_mouse_button_state() const {
+
+ return last_button_state;
+}
+
+Point2 OS_X11::get_mouse_pos() const {
+
+ return last_mouse_pos;
+}
+
+void OS_X11::set_window_title(const String& p_title) {
+
+ XStoreName(x11_display,x11_window,p_title.utf8().get_data());
+}
+
+void OS_X11::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
+
+
+}
+OS::VideoMode OS_X11::get_video_mode(int p_screen) const {
+
+ return current_videomode;
+}
+void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
+
+
+}
+
+
+InputModifierState OS_X11::get_key_modifier_state(unsigned int p_x11_state) {
+
+ InputModifierState state;
+
+ state.shift = (p_x11_state&ShiftMask);
+ state.control = (p_x11_state&ControlMask);
+ state.alt = (p_x11_state&Mod1Mask /*|| p_x11_state&Mod5Mask*/); //altgr should not count as alt
+ state.meta = (p_x11_state&Mod4Mask);
+
+ return state;
+}
+
+unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_state) {
+
+ unsigned int state=0;
+
+ if (p_x11_state&Button1Mask) {
+
+ state|=1<<0;
+ }
+
+ if (p_x11_state&Button3Mask) {
+
+ state|=1<<1;
+ }
+
+ if (p_x11_state&Button2Mask) {
+
+ state|=1<<2;
+ }
+
+ if (p_x11_state&Button4Mask) {
+
+ state|=1<<3;
+ }
+
+ if (p_x11_state&Button5Mask) {
+
+ state|=1<<4;
+ }
+
+ last_button_state=state;
+ return state;
+}
+
+void OS_X11::handle_key_event(XKeyEvent *p_event) {
+
+
+ // X11 functions don't know what const is
+ XKeyEvent *xkeyevent = p_event;
+
+ // This code was pretty difficult to write.
+ // The docs stink and every toolkit seems to
+ // do it in a different way.
+
+ /* Phase 1, obtain a proper keysym */
+
+ // This was also very difficult to figure out.
+ // You'd expect you could just use Keysym provided by
+ // XKeycodeToKeysym to obtain internationalized
+ // input.. WRONG!!
+ // you must use XLookupString (???) which not only wastes
+ // cycles generating an unnecesary string, but also
+ // still works in half the cases. (won't handle deadkeys)
+ // For more complex input methods (deadkeys and more advanced)
+ // you have to use XmbLookupString (??).
+ // So.. then you have to chosse which of both results
+ // you want to keep.
+ // This is a real bizarreness and cpu waster.
+
+ KeySym keysym_keycode=0; // keysym used to find a keycode
+ KeySym keysym_unicode=0; // keysym used to find unicode
+
+ int nbytes=0; // bytes the string takes
+
+ // XLookupString returns keysyms usable as nice scancodes/
+ char str[256+1];
+ nbytes=XLookupString(xkeyevent, str, 256, &keysym_keycode, NULL);
+
+ // Meanwhile, XLookupString returns keysyms useful for unicode.
+
+
+ if (!xmbstring) {
+ // keep a temporary buffer for the string
+ xmbstring=(char*)memalloc(sizeof(char)*8);
+ xmblen=8;
+ }
+
+ if (xkeyevent->type == KeyPress && xic) {
+
+ Status status;
+ do {
+
+ int mnbytes = XmbLookupString (xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
+ xmbstring[mnbytes] = '\0';
+
+ if (status == XBufferOverflow) {
+ xmblen = mnbytes + 1;
+ xmbstring = (char*)memrealloc (xmbstring, xmblen);
+ }
+ } while (status == XBufferOverflow);
+ }
+
+
+ /* Phase 2, obtain a pigui keycode from the keysym */
+
+ // KeyMappingX11 just translated the X11 keysym to a PIGUI
+ // keysym, so it works in all platforms the same.
+
+ unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
+
+ /* Phase 3, obtain an unicode character from the keysym */
+
+ // KeyMappingX11 also translates keysym to unicode.
+ // It does a binary search on a table to translate
+ // most properly.
+ //print_line("keysym_unicode: "+rtos(keysym_unicode));
+ unsigned int unicode = keysym_unicode>0? KeyMappingX11::get_unicode_from_keysym(keysym_unicode):0;
+
+
+ /* Phase 4, determine if event must be filtered */
+
+ // This seems to be a side-effect of using XIM.
+ // XEventFilter looks like a core X11 funciton,
+ // but it's actually just used to see if we must
+ // ignore a deadkey, or events XIM determines
+ // must not reach the actual gui.
+ // Guess it was a design problem of the extension
+
+ bool keypress = xkeyevent->type == KeyPress;
+
+ if (xkeyevent->type == KeyPress && xic) {
+ if (XFilterEvent((XEvent*)xkeyevent, x11_window))
+ return;
+ }
+
+ if (keycode==0 && unicode==0)
+ return;
+
+ /* Phase 5, determine modifier mask */
+
+ // No problems here, except I had no way to
+ // know Mod1 was ALT and Mod4 was META (applekey/winkey)
+ // just tried Mods until i found them.
+
+ //print_line("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask));
+
+ InputModifierState state = get_key_modifier_state(xkeyevent->state);
+
+ /* Phase 6, determine echo character */
+
+ // Echo characters in X11 are a keyrelease and a keypress
+ // one after the other with the (almot) same timestamp.
+ // To detect them, i use XPeekEvent and check that their
+ // difference in time is below a treshold.
+
+ bool echo=false;
+
+ if (xkeyevent->type == KeyPress) {
+
+ // saved the time of the last keyrelease to see
+ // if it's the same as this keypress.
+ if (xkeyevent->time==last_keyrelease_time)
+ echo=true;
+
+ } else {
+
+ // make sure there are events pending,
+ // so this call won't block.
+ if (XPending(x11_display)>0) {
+ XEvent peek_event;
+ XPeekEvent(x11_display, &peek_event);
+
+ // I'm using a treshold of 5 msecs,
+ // since sometimes there seems to be a little
+ // jitter. I'm still not convinced that all this approach
+ // is correct, but the xorg developers are
+ // not very helpful today.
+
+ ::Time tresh=ABS(peek_event.xkey.time-xkeyevent->time);
+ if (peek_event.type == KeyPress && tresh<5 )
+ echo=true;
+
+ // use the time from peek_event so it always works
+ last_keyrelease_time=peek_event.xkey.time;
+ } else {
+ last_keyrelease_time=xkeyevent->time;
+ }
+
+ // save the time to check for echo when keypress happens
+
+ }
+
+
+ /* Phase 7, send event to Window */
+
+ InputEvent event;
+ event.ID=++event_id;
+ event.type = InputEvent::KEY;
+ event.device=0;
+ event.key.mod=state;
+ event.key.pressed=keypress;
+
+ if (keycode>='a' && keycode<='z')
+ keycode-='a'-'A';
+
+ event.key.scancode=keycode;
+ event.key.unicode=unicode;
+ event.key.echo=echo;
+
+ if (event.key.scancode==KEY_BACKTAB) {
+ //make it consistent accross platforms.
+ event.key.scancode=KEY_TAB;
+ event.key.mod.shift=true;
+ }
+
+ //printf("key: %x\n",event.key.scancode);
+ input->parse_input_event( event);
+
+
+}
+
+void OS_X11::process_xevents() {
+
+ //printf("checking events %i\n", XPending(x11_display));
+
+ bool do_mouse_warp=false;
+
+ while (XPending(x11_display) > 0) {
+ XEvent event;
+ XNextEvent(x11_display, &event);
+
+ switch (event.type) {
+ case Expose:
+ Main::force_redraw();
+ break;
+
+ case NoExpose:
+ minimized = true;
+ break;
+
+ case VisibilityNotify: {
+
+ XVisibilityEvent * visibility = (XVisibilityEvent *)&event;
+ minimized = (visibility->state == VisibilityFullyObscured);
+
+ } break;
+
+ case FocusIn:
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ XGrabPointer(x11_display, x11_window, True,
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask, GrabModeAsync, GrabModeAsync,
+ x11_window, None, CurrentTime);
+ }
+ break;
+
+ case FocusOut:
+ main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ //dear X11, I try, I really try, but you never work, you do whathever you want.
+ XUngrabPointer(x11_display, CurrentTime);
+ }
+ break;
+
+ case ConfigureNotify:
+ /* call resizeGLScene only if our window-size changed */
+
+ if ((event.xconfigure.width == current_videomode.width) &&
+ (event.xconfigure.height == current_videomode.height))
+ break;
+
+ current_videomode.width=event.xconfigure.width;
+ current_videomode.height=event.xconfigure.height;
+ break;
+ case ButtonPress:
+ case ButtonRelease: {
+
+ /* exit in case of a mouse button press */
+ last_timestamp=event.xbutton.time;
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+ event.xbutton.x=last_mouse_pos.x;
+ event.xbutton.y=last_mouse_pos.y;
+ }
+
+ InputEvent mouse_event;
+ mouse_event.ID=++event_id;
+ mouse_event.type = InputEvent::MOUSE_BUTTON;
+ mouse_event.device=0;
+ mouse_event.mouse_button.mod = get_key_modifier_state(event.xbutton.state);
+ mouse_event.mouse_button.button_mask = get_mouse_button_state(event.xbutton.state);
+ mouse_event.mouse_button.x=event.xbutton.x;
+ mouse_event.mouse_button.y=event.xbutton.y;
+ mouse_event.mouse_button.global_x=event.xbutton.x;
+ mouse_event.mouse_button.global_y=event.xbutton.y;
+ mouse_event.mouse_button.button_index=event.xbutton.button;
+ if (mouse_event.mouse_button.button_index==2)
+ mouse_event.mouse_button.button_index=3;
+ else if (mouse_event.mouse_button.button_index==3)
+ mouse_event.mouse_button.button_index=2;
+
+ mouse_event.mouse_button.pressed=(event.type==ButtonPress);
+
+
+ if (event.type==ButtonPress && event.xbutton.button==1) {
+
+ uint64_t diff = get_ticks_usec()/1000 - last_click_ms;
+
+ if (diff<400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x,event.xbutton.y))<5) {
+
+ last_click_ms=0;
+ last_click_pos = Point2(-100,-100);
+ mouse_event.mouse_button.doubleclick=true;
+ mouse_event.ID=++event_id;
+
+ } else {
+ last_click_ms+=diff;
+ last_click_pos = Point2(event.xbutton.x,event.xbutton.y);
+ }
+ }
+
+ input->parse_input_event( mouse_event);
+
+
+ } break;
+ case MotionNotify: {
+
+
+ last_timestamp=event.xmotion.time;
+
+ // Motion is also simple.
+ // A little hack is in order
+ // to be able to send relative motion events.
+
+ Point2i pos( event.xmotion.x, event.xmotion.y );
+
+ if (mouse_mode==MOUSE_MODE_CAPTURED) {
+#if 1
+ Vector2 c = Point2i(current_videomode.width/2,current_videomode.height/2);
+ if (pos==Point2i(current_videomode.width/2,current_videomode.height/2)) {
+ //this sucks, it's a hack, etc and is a little inaccurate, etc.
+ //but nothing I can do, X11 sucks.
+
+ center=pos;
+ break;
+ }
+
+ Point2i ncenter = pos;
+ pos = last_mouse_pos + ( pos-center );
+ center=ncenter;
+ do_mouse_warp=true;
+#else
+ //Dear X11, thanks for making my life miserable
+
+ center.x = current_videomode.width/2;
+ center.y = current_videomode.height/2;
+ pos = last_mouse_pos + ( pos-center );
+ if (pos==last_mouse_pos)
+ break;
+ XWarpPointer(x11_display, None, x11_window,
+ 0,0,0,0, (int)center.x, (int)center.y);
+#endif
+
+ }
+
+
+ if (!last_mouse_pos_valid) {
+
+ last_mouse_pos=pos;
+ last_mouse_pos_valid=true;
+ }
+
+ Point2i rel = pos - last_mouse_pos;
+
+ InputEvent motion_event;
+ motion_event.ID=++event_id;
+ motion_event.type=InputEvent::MOUSE_MOTION;
+ motion_event.device=0;
+
+ motion_event.mouse_motion.mod = get_key_modifier_state(event.xmotion.state);
+ motion_event.mouse_motion.button_mask = get_mouse_button_state(event.xmotion.state);
+ motion_event.mouse_motion.x=pos.x;
+ motion_event.mouse_motion.y=pos.y;
+ input->set_mouse_pos(pos);
+ motion_event.mouse_motion.global_x=pos.x;
+ motion_event.mouse_motion.global_y=pos.y;
+ motion_event.mouse_motion.speed_x=input->get_mouse_speed().x;
+ motion_event.mouse_motion.speed_y=input->get_mouse_speed().y;
+
+ motion_event.mouse_motion.relative_x=rel.x;
+ motion_event.mouse_motion.relative_y=rel.y;
+
+ last_mouse_pos=pos;
+
+ input->parse_input_event( motion_event);
+
+ } break;
+ case KeyPress:
+ case KeyRelease: {
+
+ last_timestamp=event.xkey.time;
+
+ // key event is a little complex, so
+ // it will be handled in it's own function.
+ handle_key_event( (XKeyEvent*)&event );
+ } break;
+ case SelectionRequest: {
+
+ XSelectionRequestEvent *req;
+ XEvent e, respond;
+ e = event;
+
+ req=&(e.xselectionrequest);
+ if (req->target == XA_STRING || req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
+ req->target == XInternAtom(x11_display, "UTF8_STRING", 0))
+ {
+ CharString clip = OS::get_clipboard().utf8();
+ XChangeProperty (x11_display,
+ req->requestor,
+ req->property,
+ req->target,
+ 8,
+ PropModeReplace,
+ (unsigned char*)clip.get_data(),
+ clip.length());
+ respond.xselection.property=req->property;
+ } else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {
+
+ Atom data[2];
+ data[0] = XInternAtom(x11_display, "UTF8_STRING", 0);
+ data[1] = XA_STRING;
+ XChangeProperty (x11_display, req->requestor, req->property, req->target,
+ 8, PropModeReplace, (unsigned char *) &data,
+ sizeof (data));
+ respond.xselection.property=req->property;
+
+ } else {
+ printf ("No String %x\n",
+ (int)req->target);
+ respond.xselection.property= None;
+ }
+ respond.xselection.type= SelectionNotify;
+ respond.xselection.display= req->display;
+ respond.xselection.requestor= req->requestor;
+ respond.xselection.selection=req->selection;
+ respond.xselection.target= req->target;
+ respond.xselection.time = req->time;
+ XSendEvent (x11_display, req->requestor,0,0,&respond);
+ XFlush (x11_display);
+ } break;
+
+
+ case ClientMessage:
+
+ if ((unsigned int)event.xclient.data.l[0]==(unsigned int)wm_delete)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+ break;
+ default:
+ break;
+ }
+ }
+
+ XFlush(x11_display);
+
+ if (do_mouse_warp) {
+
+ XWarpPointer(x11_display, None, x11_window,
+ 0,0,0,0, (int)current_videomode.width/2, (int)current_videomode.height/2);
+
+ }
+}
+
+MainLoop *OS_X11::get_main_loop() const {
+
+ return main_loop;
+}
+
+void OS_X11::delete_main_loop() {
+
+ if (main_loop)
+ memdelete(main_loop);
+ main_loop=NULL;
+}
+
+void OS_X11::set_main_loop( MainLoop * p_main_loop ) {
+
+ main_loop=p_main_loop;
+ input->set_main_loop(p_main_loop);
+}
+
+bool OS_X11::can_draw() const {
+
+ return !minimized;
+};
+
+void OS_X11::set_clipboard(const String& p_text) {
+
+ OS::set_clipboard(p_text);
+
+ XSetSelectionOwner(x11_display, XA_PRIMARY, x11_window, CurrentTime);
+ XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, CurrentTime);
+};
+
+static String _get_clipboard(Atom p_source, Window x11_window, ::Display* x11_display, String p_internal_clipboard) {
+
+ String ret;
+
+ Atom type;
+ Atom selection = XA_PRIMARY;
+ int format, result;
+ unsigned long len, bytes_left, dummy;
+ unsigned char *data;
+ Window Sown = XGetSelectionOwner (x11_display, p_source);
+
+ if (Sown == x11_window) {
+
+ printf("returning internal clipboard\n");
+ return p_internal_clipboard;
+ };
+
+ if (Sown != None) {
+ XConvertSelection (x11_display, p_source, XA_STRING, selection,
+ x11_window, CurrentTime);
+ XFlush (x11_display);
+ while (true) {
+ XEvent event;
+ XNextEvent(x11_display, &event);
+ if (event.type == SelectionNotify && event.xselection.requestor == x11_window) {
+ break;
+ };
+ };
+
+ //
+ // Do not get any data, see how much data is there
+ //
+ XGetWindowProperty (x11_display, x11_window,
+ selection, // Tricky..
+ 0, 0, // offset - len
+ 0, // Delete 0==FALSE
+ AnyPropertyType, //flag
+ &type, // return type
+ &format, // return format
+ &len, &bytes_left, //that
+ &data);
+ // DATA is There
+ if (bytes_left > 0)
+ {
+ result = XGetWindowProperty (x11_display, x11_window,
+ selection, 0,bytes_left,0,
+ AnyPropertyType, &type,&format,
+ &len, &dummy, &data);
+ if (result == Success) {
+ ret.parse_utf8((const char*)data);
+ } else printf ("FAIL\n");
+ XFree (data);
+ }
+ }
+
+ return ret;
+
+};
+
+String OS_X11::get_clipboard() const {
+
+ String ret;
+ ret = _get_clipboard(XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, x11_display, OS::get_clipboard());
+
+ if (ret == "") {
+ ret = _get_clipboard(XA_PRIMARY, x11_window, x11_display, OS::get_clipboard());
+ };
+
+ return ret;
+};
+
+String OS_X11::get_name() {
+
+ return "X11";
+}
+
+
+void OS_X11::close_joystick(int p_id) {
+
+ if (p_id == -1) {
+ for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+ close_joystick(i);
+ };
+ return;
+ };
+
+
+ if (joysticks[p_id].fd != -1) {
+ close(joysticks[p_id].fd);
+ joysticks[p_id].fd = -1;
+ };
+};
+
+void OS_X11::probe_joystick(int p_id) {
+
+ if (p_id == -1) {
+
+ for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+ probe_joystick(i);
+ };
+ return;
+ };
+
+ close_joystick(p_id);
+
+ const char *joy_names[] = {
+ "/dev/input/js%d",
+ "/dev/js%d",
+ NULL
+ };
+
+ int i=0;
+ while(joy_names[i]) {
+
+ char fname[64];
+ sprintf(fname, joy_names[i], p_id);
+ int fd = open(fname, O_RDONLY);
+ if (fd != -1) {
+
+ fcntl( fd, F_SETFL, O_NONBLOCK );
+ joysticks[p_id] = Joystick(); // this will reset the axis array
+ joysticks[p_id].fd = fd;
+ break; // don't try the next name
+ };
+
+ ++i;
+ };
+};
+
+void OS_X11::move_window_to_foreground() {
+
+ XRaiseWindow(x11_display,x11_window);
+}
+
+void OS_X11::process_joysticks() {
+
+ int bytes;
+ js_event events[32];
+ InputEvent ievent;
+ for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+ if (joysticks[i].fd == -1)
+ continue;
+ ievent.device = i;
+
+ while ( (bytes = read(joysticks[i].fd, &events, sizeof(events))) > 0) {
+
+ int ev_count = bytes / sizeof(js_event);
+ for (int j=0; j<ev_count; j++) {
+
+ js_event& event = events[j];
+
+ //printf("got event on joystick %i, %i, %i, %i, %i\n", i, joysticks[i].fd, event.type, event.number, event.value);
+ if (event.type & JS_EVENT_INIT)
+ continue;
+
+ switch (event.type & ~JS_EVENT_INIT) {
+
+ case JS_EVENT_AXIS:
+
+ if (joysticks[i].last_axis[event.number] != event.value) {
+
+ if (event.number==5 || event.number==6) {
+
+ int axis=event.number-5;
+ int val = event.value;
+ if (val<0)
+ val=-1;
+ if (val>0)
+ val=+1;
+
+ InputEvent ev;
+ ev.type = InputEvent::JOYSTICK_BUTTON;
+ ev.ID = ++event_id;
+
+
+ if (val!=dpad_last[axis]) {
+
+ int prev_val = dpad_last[axis];
+ if (prev_val!=0) {
+
+ ev.joy_button.pressed=false;
+ ev.joy_button.pressure=0.0;
+ if (event.number==5)
+ ev.joy_button.button_index=JOY_DPAD_LEFT+(prev_val+1)/2;
+ if (event.number==6)
+ ev.joy_button.button_index=JOY_DPAD_UP+(prev_val+1)/2;
+
+ input->parse_input_event( ev );
+ }
+ }
+
+ if (val!=0) {
+
+ ev.joy_button.pressed=true;
+ ev.joy_button.pressure=1.0;
+ if (event.number==5)
+ ev.joy_button.button_index=JOY_DPAD_LEFT+(val+1)/2;
+ if (event.number==6)
+ ev.joy_button.button_index=JOY_DPAD_UP+(val+1)/2;
+
+ input->parse_input_event( ev );
+ }
+
+
+ dpad_last[axis]=val;
+
+ }
+ //print_line("ev: "+itos(event.number)+" val: "+ rtos((float)event.value / (float)MAX_JOY_AXIS));
+ if (event.number >= JOY_AXIS_MAX)
+ break;
+ //ERR_FAIL_COND(event.number >= JOY_AXIS_MAX);
+ ievent.type = InputEvent::JOYSTICK_MOTION;
+ ievent.ID = ++event_id;
+ ievent.joy_motion.axis = _pc_joystick_get_native_axis(event.number);
+ ievent.joy_motion.axis_value = (float)event.value / (float)MAX_JOY_AXIS;
+ joysticks[i].last_axis[event.number] = event.value;
+ input->parse_input_event( ievent );
+ };
+ break;
+
+ case JS_EVENT_BUTTON:
+
+
+ ievent.type = InputEvent::JOYSTICK_BUTTON;
+ ievent.ID = ++event_id;
+ ievent.joy_button.button_index = _pc_joystick_get_native_button(event.number);
+ ievent.joy_button.pressed = event.value;
+ input->parse_input_event( ievent );
+ break;
+ };
+ };
+ };
+ };
+};
+
+void OS_X11::set_cursor_shape(CursorShape p_shape) {
+
+ ERR_FAIL_INDEX(p_shape,CURSOR_MAX);
+
+ if (p_shape==current_cursor)
+ return;
+ if (mouse_mode==MOUSE_MODE_VISIBLE) {
+ if (cursors[p_shape]!=None)
+ XDefineCursor(x11_display,x11_window,cursors[p_shape]);
+ else if (cursors[CURSOR_ARROW]!=None)
+ XDefineCursor(x11_display,x11_window,cursors[CURSOR_ARROW]);
+ }
+
+
+ current_cursor=p_shape;
+}
+
+
+void OS_X11::release_rendering_thread() {
+
+ context_gl->release_current();
+
+}
+
+void OS_X11::make_rendering_thread() {
+
+ context_gl->make_current();
+}
+
+void OS_X11::swap_buffers() {
+
+ context_gl->swap_buffers();
+}
+
+
+void OS_X11::set_icon(const Image& p_icon) {
+
+ //does not work, if anyone knows why, please fix
+ if (!p_icon.empty()) {
+
+ Image img=p_icon;
+ img.convert(Image::FORMAT_RGBA);
+
+
+ int w = img.get_width();
+ int h = img.get_height();
+
+ Vector<long> pd;
+
+ pd.resize((2+w*h)*sizeof(long));
+
+ print_line("***** SET ICON ***** "+itos(w)+" "+itos(h));
+
+ pd[0]=w;
+ pd[1]=h;
+
+ DVector<uint8_t>::Read r = img.get_data().read();
+
+ uint32_t *wr=(uint32_t*)&pd[2];
+
+ for(int i=0;i<w*h;i++) {
+
+ uint32_t v=0;
+ v|=r[i*4+3];
+ v<<=8;
+ v|=r[i*4+0];
+ v<<=8;
+ v|=r[i*4+1];
+ v<<=8;
+ v|=r[i*4+2];
+ wr[i]=v;
+ }
+
+ XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) pd.ptr(),
+ (2+w*h));
+ } else {
+ XDeleteProperty(x11_display, x11_window, net_wm_icon);
+ }
+ XFlush(x11_display);
+
+}
+
+
+void OS_X11::run() {
+
+ force_quit = false;
+
+ if (!main_loop)
+ return;
+
+ main_loop->init();
+
+// uint64_t last_ticks=get_ticks_usec();
+
+// int frames=0;
+// uint64_t frame=0;
+
+ while (!force_quit) {
+
+ process_xevents(); // get rid of pending events
+ process_joysticks();
+ if (Main::iteration()==true)
+ break;
+ };
+
+ main_loop->finish();
+}
+
+OS_X11::OS_X11() {
+
+#ifdef RTAUDIO_ENABLED
+ AudioDriverManagerSW::add_driver(&driver_rtaudio);
+#endif
+
+#ifdef ALSA_ENABLED
+ AudioDriverManagerSW::add_driver(&driver_alsa);
+#endif
+
+ minimized = false;
+ xim_style=NULL;
+ mouse_mode=MOUSE_MODE_VISIBLE;
+
+
+};
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
new file mode 100644
index 0000000000..ee50bdea4a
--- /dev/null
+++ b/platform/x11/os_x11.h
@@ -0,0 +1,203 @@
+/*************************************************************************/
+/* os_x11.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef OS_X11_H
+#define OS_X11_H
+
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+#include "context_gl_x11.h"
+#include "servers/visual_server.h"
+#include "servers/visual/visual_server_wrap_mt.h"
+#include "servers/visual/rasterizer.h"
+#include "servers/physics_server.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/audio/sample_manager_sw.h"
+#include "servers/spatial_sound/spatial_sound_server_sw.h"
+#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "drivers/rtaudio/audio_driver_rtaudio.h"
+#include "drivers/alsa/audio_driver_alsa.h"
+#include "servers/physics_2d/physics_2d_server_sw.h"
+
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xcursor/Xcursor.h>
+
+//bitch
+#undef CursorShape
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+class OS_X11 : public OS_Unix {
+
+ Atom wm_delete;
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+ ContextGL_X11 *context_gl;
+#endif
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+ VideoMode current_videomode;
+ List<String> args;
+ Window x11_window;
+ MainLoop *main_loop;
+ ::Display* x11_display;
+ char *xmbstring;
+ int xmblen;
+ unsigned long last_timestamp;
+ ::Time last_keyrelease_time;
+ ::XIC xic;
+ ::XIM xim;
+ ::XIMStyle xim_style;
+ Point2i last_mouse_pos;
+ bool last_mouse_pos_valid;
+ Point2i last_click_pos;
+ uint64_t last_click_ms;
+ unsigned int event_id;
+ uint32_t last_button_state;
+
+ PhysicsServer *physics_server;
+ unsigned int get_mouse_button_state(unsigned int p_x11_state);
+ InputModifierState get_key_modifier_state(unsigned int p_x11_state);
+ Physics2DServer *physics_2d_server;
+
+ MouseMode mouse_mode;
+ Point2i center;
+
+ void handle_key_event(XKeyEvent *p_event);
+ void process_xevents();
+ virtual void delete_main_loop();
+ IP_Unix *ip_unix;
+
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+
+ bool force_quit;
+ bool minimized;
+ int dpad_last[2];
+
+
+ const char *cursor_theme;
+ int cursor_size;
+ Cursor cursors[CURSOR_MAX];
+ Cursor null_cursor;
+ CursorShape current_cursor;
+
+ InputDefault *input;
+
+#ifdef RTAUDIO_ENABLED
+ AudioDriverRtAudio driver_rtaudio;
+#endif
+
+#ifdef ALSA_ENABLED
+ AudioDriverALSA driver_alsa;
+#endif
+
+ enum {
+ JOYSTICKS_MAX = 8,
+ MAX_JOY_AXIS = 32768, // I've no idea
+ };
+
+ struct Joystick {
+
+ int fd;
+ int last_axis[JOY_AXIS_MAX];
+
+ Joystick() {
+ fd = -1;
+ for (int i=0; i<JOY_AXIS_MAX; i++) {
+
+ last_axis[i] = 0;
+ };
+ };
+ };
+
+ Atom net_wm_icon;
+
+
+ int joystick_count;
+ Joystick joysticks[JOYSTICKS_MAX];
+
+
+protected:
+
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+ virtual void finalize();
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+
+ void probe_joystick(int p_id = -1);
+ void process_joysticks();
+ void close_joystick(int p_id = -1);
+
+public:
+
+ virtual String get_name();
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ void set_mouse_mode(MouseMode p_mode);
+ MouseMode get_mouse_mode() const;
+
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ virtual void set_icon(const Image& p_icon);
+
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_clipboard(const String& p_text);
+ virtual String get_clipboard() const;
+
+ virtual void release_rendering_thread();
+ virtual void make_rendering_thread();
+ virtual void swap_buffers();
+
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ virtual VideoMode get_video_mode(int p_screen=0) const;
+ virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;
+
+ virtual void move_window_to_foreground();
+
+ void run();
+
+ OS_X11();
+};
+
+#endif
diff --git a/platform/x11/platform_config.h b/platform/x11/platform_config.h
new file mode 100644
index 0000000000..d14f3e3f9a
--- /dev/null
+++ b/platform/x11/platform_config.h
@@ -0,0 +1,32 @@
+/*************************************************************************/
+/* platform_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include <alloca.h>
+#define GLES2_INCLUDE_H "gl_context/glew.h"
+#define GLES1_INCLUDE_H "gl_context/glew.h"
+