diff options
author | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
commit | 0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch) | |
tree | 276c4d099e178eb67fbd14f61d77b05e3808e9e3 /platform/osx | |
parent | 0e49da1687bc8192ed210947da52c9e5c5f301bb (diff) |
GODOT IS OPEN SOURCE
Diffstat (limited to 'platform/osx')
-rw-r--r-- | platform/osx/SCsub | 11 | ||||
-rw-r--r-- | platform/osx/audio_driver_osx.cpp | 160 | ||||
-rw-r--r-- | platform/osx/audio_driver_osx.h | 71 | ||||
-rw-r--r-- | platform/osx/context_gl_osx.cpp | 104 | ||||
-rw-r--r-- | platform/osx/context_gl_osx.h | 65 | ||||
-rw-r--r-- | platform/osx/detect.py | 107 | ||||
-rw-r--r-- | platform/osx/export/export.cpp | 504 | ||||
-rw-r--r-- | platform/osx/export/export.h | 3 | ||||
-rw-r--r-- | platform/osx/godot_main_osx.mm | 86 | ||||
-rw-r--r-- | platform/osx/godot_osx.h | 37 | ||||
-rw-r--r-- | platform/osx/godot_osx.mm | 215 | ||||
-rw-r--r-- | platform/osx/logo.png | bin | 0 -> 1905 bytes | |||
-rw-r--r-- | platform/osx/os_osx.h | 166 | ||||
-rw-r--r-- | platform/osx/os_osx.mm | 1323 | ||||
-rw-r--r-- | platform/osx/platform_config.h | 31 | ||||
-rw-r--r-- | platform/osx/sem_osx.cpp | 115 | ||||
-rw-r--r-- | platform/osx/sem_osx.h | 60 |
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 Binary files differnew file mode 100644 index 0000000000..2bcd3aa72e --- /dev/null +++ b/platform/osx/logo.png 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 |