summaryrefslogtreecommitdiff
path: root/platform/osx
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/osx
parent0e49da1687bc8192ed210947da52c9e5c5f301bb (diff)
GODOT IS OPEN SOURCE
Diffstat (limited to 'platform/osx')
-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
17 files changed, 3058 insertions, 0 deletions
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