diff options
30 files changed, 953 insertions, 140 deletions
diff --git a/core/func_ref.cpp b/core/func_ref.cpp index 644d8b5b63..ca890111be 100644 --- a/core/func_ref.cpp +++ b/core/func_ref.cpp @@ -61,11 +61,7 @@ void FuncRef::_bind_methods() { MethodInfo mi; mi.name="call_func"; Vector<Variant> defargs; - for(int i=0;i<10;i++) { - mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); - defargs.push_back(Variant()); - } - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call_func:Variant",&FuncRef::call_func,mi,defargs); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"call_func:Variant",&FuncRef::call_func,mi,defargs); } diff --git a/core/method_bind.h b/core/method_bind.h index 072953743c..04ff5c22c6 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -52,6 +52,7 @@ enum MethodFlags { METHOD_FLAG_REVERSE=16, // used for events METHOD_FLAG_VIRTUAL=32, METHOD_FLAG_FROM_SCRIPT=64, + METHOD_FLAG_VARARG=128, METHOD_FLAGS_DEFAULT=METHOD_FLAG_NORMAL, }; @@ -229,7 +230,7 @@ public: Vector<StringName> get_argument_names() const; #endif void set_hint_flags(uint32_t p_hint) { hint_flags=p_hint; } - uint32_t get_hint_flags() const { return hint_flags|(is_const()?METHOD_FLAG_CONST:0); } + uint32_t get_hint_flags() const { return hint_flags|(is_const()?METHOD_FLAG_CONST:0)|(is_vararg()?METHOD_FLAG_VARARG:0); } virtual String get_instance_type() const=0; _FORCE_INLINE_ int get_argument_count() const { return argument_count; }; @@ -267,7 +268,7 @@ public: _FORCE_INLINE_ int get_method_id() const { return method_id; } _FORCE_INLINE_ bool is_const() const { return _const; } _FORCE_INLINE_ bool has_return() const { return _returns; } - + virtual bool is_vararg() const { return false; } void set_default_arguments(const Vector<Variant>& p_defargs); @@ -277,7 +278,7 @@ public: template<class T> -class MethodBindNative : public MethodBind { +class MethodBindVarArg : public MethodBind { public: typedef Variant (T::*NativeCall)(const Variant**,int ,Variant::CallError &); protected: @@ -319,7 +320,9 @@ public: } #ifdef PTRCALL_ENABLED - virtual void ptrcall(Object* p_object,const void** p_args,void* r_ret) {} //todo + virtual void ptrcall(Object* p_object,const void** p_args,void* r_ret) { + ERR_FAIL(); //can't call + } //todo #endif @@ -327,14 +330,16 @@ public: virtual bool is_const() const { return false; } virtual String get_instance_type() const { return T::get_type_static(); } - MethodBindNative() { call_method=NULL; _set_returns(true);} + virtual bool is_vararg() const { return true; } + + MethodBindVarArg() { call_method=NULL; _set_returns(true);} }; template<class T > -MethodBind* create_native_method_bind( Variant (T::*p_method)(const Variant**,int ,Variant::CallError &), const MethodInfo& p_info ) { +MethodBind* create_vararg_method_bind( Variant (T::*p_method)(const Variant**,int ,Variant::CallError &), const MethodInfo& p_info ) { - MethodBindNative<T > * a = memnew( (MethodBindNative<T >) ); + MethodBindVarArg<T > * a = memnew( (MethodBindVarArg<T >) ); a->set_method(p_method); a->set_method_info(p_info); return a; diff --git a/core/object.cpp b/core/object.cpp index b036efa501..81fdc2a90c 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -1693,42 +1693,26 @@ void Object::_bind_methods() { MethodInfo mi; mi.name="emit_signal"; mi.arguments.push_back( PropertyInfo( Variant::STRING, "signal")); - Vector<Variant> defargs; - for(int i=0;i<VARIANT_ARG_MAX;i++) { - mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); - defargs.push_back(Variant()); - } - - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"emit_signal",&Object::_emit_signal,mi,defargs); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"emit_signal",&Object::_emit_signal,mi); } { MethodInfo mi; mi.name="call"; mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); - Vector<Variant> defargs; - for(int i=0;i<10;i++) { - mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); - defargs.push_back(Variant()); - } - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call:Variant",&Object::_call_bind,mi,defargs); + + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"call:Variant",&Object::_call_bind,mi); } { MethodInfo mi; mi.name="call_deferred"; mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); - Vector<Variant> defargs; - for(int i=0;i<VARIANT_ARG_MAX;i++) { - mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); - defargs.push_back(Variant()); - } - - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call_deferred",&Object::_call_deferred_bind,mi,defargs); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"call_deferred",&Object::_call_deferred_bind,mi); } ObjectTypeDB::bind_method(_MD("callv:Variant","method","arg_array"),&Object::callv); diff --git a/core/object_type_db.h b/core/object_type_db.h index 3fcd38aa31..725b424c9a 100644 --- a/core/object_type_db.h +++ b/core/object_type_db.h @@ -415,13 +415,13 @@ public: #endif template<class M> - static MethodBind* bind_native_method(uint32_t p_flags, StringName p_name, M p_method,const MethodInfo& p_info=MethodInfo(),const Vector<Variant>& p_default_args=Vector<Variant>()) { + static MethodBind* bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method,const MethodInfo& p_info=MethodInfo(),const Vector<Variant>& p_default_args=Vector<Variant>()) { GLOBAL_LOCK_FUNCTION; - MethodBind *bind = create_native_method_bind(p_method,p_info); + MethodBind *bind = create_vararg_method_bind(p_method,p_info); ERR_FAIL_COND_V(!bind,NULL); String rettype; diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 99740b365c..e8a71d4991 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -490,13 +490,9 @@ void UndoRedo::_bind_methods() { mi.name="add_do_method"; mi.arguments.push_back( PropertyInfo( Variant::OBJECT, "object")); mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); - Vector<Variant> defargs; - for(int i=0;i<VARIANT_ARG_MAX;++i) { - mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); - defargs.push_back(Variant()); - } - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"add_do_method",&UndoRedo::_add_do_method,mi,defargs); + + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"add_do_method",&UndoRedo::_add_do_method,mi); } { @@ -504,13 +500,9 @@ void UndoRedo::_bind_methods() { mi.name="add_undo_method"; mi.arguments.push_back( PropertyInfo( Variant::OBJECT, "object")); mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); - Vector<Variant> defargs; - for(int i=0;i<VARIANT_ARG_MAX;++i) { - mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); - defargs.push_back(Variant()); - } - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"add_undo_method",&UndoRedo::_add_undo_method,mi,defargs); + + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"add_undo_method",&UndoRedo::_add_undo_method,mi); } ObjectTypeDB::bind_method(_MD("add_do_property","object", "property", "value:Variant"),&UndoRedo::add_do_property); diff --git a/doc/base/classes.xml b/doc/base/classes.xml index e0b18e968b..1b54a70be8 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -10871,7 +10871,7 @@ </return> <description> Initialise the stream used to list all files and directories using the [method get_next] function, closing the current opened stream if needed. Once the stream has been processed, it should typically be closed with [method list_dir_end]. - Return false if the stream could not be initialised. + Return true if the stream could not be initialised. </description> </method> <method name="list_dir_end"> diff --git a/main/input_default.cpp b/main/input_default.cpp index d84b0b0f58..ce480b4f99 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -655,7 +655,7 @@ static const char *s_ControllerMappings [] = "030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,", "030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,", "030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", - "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e0400001907000000010000,X360 Wireless Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:h0.8,lefttrigger:a2,x:b2,dpup:h0.1,back:b6,leftstick:b9,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,", "030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000005e0400008e02000001000000,Microsoft X-Box 360 pad,leftstick:b9,leftx:a0,lefty:a1,dpdown:h0.1,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:h0.2,lefttrigger:a2,x:b2,dpup:h0.4,back:b6,leftshoulder:b4,y:b3,a:b0,dpright:h0.8,righttrigger:a5,b:b1,", "030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp index b2cc6341c1..094e21bb4f 100644 --- a/modules/gdscript/gd_function.cpp +++ b/modules/gdscript/gd_function.cpp @@ -1437,7 +1437,7 @@ void GDFunctionState::_bind_methods() { ObjectTypeDB::bind_method(_MD("resume:Variant","arg"),&GDFunctionState::resume,DEFVAL(Variant())); ObjectTypeDB::bind_method(_MD("is_valid"),&GDFunctionState::is_valid); - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback")); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback")); } diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index b97a0fcbb6..0ea10950df 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -751,7 +751,7 @@ void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { void GDScript::_bind_methods() { - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo(Variant::OBJECT,"new")); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo(Variant::OBJECT,"new")); ObjectTypeDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 94f9a6a6b5..bd042c8989 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -2439,7 +2439,7 @@ void VisualScriptFunctionState::_bind_methods() { ObjectTypeDB::bind_method(_MD("connect_to_signal","obj","signals","args"),&VisualScriptFunctionState::connect_to_signal); ObjectTypeDB::bind_method(_MD("resume:Array","args"),&VisualScriptFunctionState::resume,DEFVAL(Variant())); ObjectTypeDB::bind_method(_MD("is_valid"),&VisualScriptFunctionState::is_valid); - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&VisualScriptFunctionState::_signal_callback,MethodInfo("_signal_callback")); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&VisualScriptFunctionState::_signal_callback,MethodInfo("_signal_callback")); } VisualScriptFunctionState::VisualScriptFunctionState() { diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index de99beacaf..5a21cb40e9 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -417,6 +417,14 @@ void VisualScriptFunctionCall::_update_method_cache() { method_cache.return_val = mb->get_argument_info(-1); #endif + + if (mb->is_vararg()) { + //for vararg just give it 10 arguments (should be enough for most use cases) + for(int i=0;i<10;i++) { + method_cache.arguments.push_back(PropertyInfo(Variant::NIL,"arg"+itos(i))); + use_default_args++; + } + } } else if (script.is_valid() && script->has_method(function)) { method_cache = script->get_method_info(function); diff --git a/platform/osx/SCsub b/platform/osx/SCsub index 3785eb3fb3..4169795519 100644 --- a/platform/osx/SCsub +++ b/platform/osx/SCsub @@ -7,6 +7,7 @@ files = [ 'sem_osx.cpp', # 'context_gl_osx.cpp', 'dir_access_osx.mm', + 'joystick_osx.cpp', ] env.Program('#bin/godot',files) diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 1982beb10e..01ea09fa21 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -92,7 +92,7 @@ def configure(env): 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', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit','-lz']) + env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit','-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) if (env["CXX"]=="clang++"): env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) diff --git a/platform/osx/joystick_osx.cpp b/platform/osx/joystick_osx.cpp new file mode 100644 index 0000000000..ffb6ac326b --- /dev/null +++ b/platform/osx/joystick_osx.cpp @@ -0,0 +1,623 @@ +/*************************************************************************/ +/* joystick_osx.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 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 "joystick_osx.h" +#include <machine/endian.h> + +#define GODOT_JOY_LOOP_RUN_MODE CFSTR("GodotJoystick") + +static JoystickOSX* self = NULL; + +joystick::joystick() { + device_ref = NULL; + ff_device = NULL; + ff_axes = NULL; + ff_directions = NULL; + ffservice = 0; + ff_timestamp = 0; + id = 0; + + ff_constant_force.lMagnitude = 10000; + ff_effect.dwDuration = 0; + ff_effect.dwSamplePeriod = 0; + ff_effect.dwGain = 10000; + ff_effect.dwFlags = FFEFF_OBJECTOFFSETS; + ff_effect.dwTriggerButton = FFEB_NOTRIGGER; + ff_effect.dwStartDelay = 0; + ff_effect.dwTriggerRepeatInterval = 0; + ff_effect.lpEnvelope = NULL; + ff_effect.cbTypeSpecificParams = sizeof(FFCONSTANTFORCE); + ff_effect.lpvTypeSpecificParams = &ff_constant_force; + ff_effect.dwSize = sizeof(ff_effect); +} + +void joystick::free() { + if (device_ref) { + IOHIDDeviceUnscheduleFromRunLoop(device_ref, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); + } + if (ff_device) { + FFDeviceReleaseEffect(ff_device, ff_object); + FFReleaseDevice(ff_device); + memfree(ff_axes); + memfree(ff_directions); + } +} + +bool joystick::has_element(IOHIDElementCookie p_cookie, Vector<rec_element> *p_list) const { + for (int i = 0; i < p_list->size(); i++) { + if (p_cookie == p_list->get(i).cookie) { + return true; + } + } + return false; +} + +int joystick::get_hid_element_state(rec_element *p_element) const { + int value = 0; + if (p_element && p_element->ref) { + IOHIDValueRef valueRef; + if (IOHIDDeviceGetValue(device_ref, p_element->ref, &valueRef) == kIOReturnSuccess) { + value = (SInt32) IOHIDValueGetIntegerValue(valueRef); + + /* record min and max for auto calibration */ + if (value < p_element->min) { + p_element->min = value; + } + if (value > p_element->max) { + p_element->max = value; + } + } + } + return value; +} +void joystick::add_hid_element(IOHIDElementRef p_element) { + const CFTypeID elementTypeID = p_element ? CFGetTypeID(p_element) : 0; + + if (p_element && (elementTypeID == IOHIDElementGetTypeID())) { + const IOHIDElementCookie cookie = IOHIDElementGetCookie(p_element); + const uint32_t usagePage = IOHIDElementGetUsagePage(p_element); + const uint32_t usage = IOHIDElementGetUsage(p_element); + Vector<rec_element> *list = NULL; + + switch (IOHIDElementGetType(p_element)) { + case kIOHIDElementTypeInput_Misc: + case kIOHIDElementTypeInput_Button: + case kIOHIDElementTypeInput_Axis: { + switch (usagePage) { + case kHIDPage_GenericDesktop: + switch (usage) { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + case kHIDUsage_GD_Slider: + case kHIDUsage_GD_Dial: + case kHIDUsage_GD_Wheel: + if (!has_element(cookie, &axis_elements)) { + list = &axis_elements; + } + break; + + case kHIDUsage_GD_Hatswitch: + if (!has_element(cookie, &hat_elements)) { + list = &hat_elements; + } + break; + case kHIDUsage_GD_DPadUp: + case kHIDUsage_GD_DPadDown: + case kHIDUsage_GD_DPadRight: + case kHIDUsage_GD_DPadLeft: + case kHIDUsage_GD_Start: + case kHIDUsage_GD_Select: + if (!has_element(cookie, &button_elements)) { + list = &button_elements; + } + break; + } + break; + + case kHIDPage_Simulation: + switch (usage) { + case kHIDUsage_Sim_Rudder: + case kHIDUsage_Sim_Throttle: + if (!has_element(cookie, &axis_elements)) { + list = &axis_elements; + } + break; + + default: + break; + } + break; + + case kHIDPage_Button: + case kHIDPage_Consumer: + if (!has_element(cookie, &button_elements)) { + list = &button_elements; + } + break; + + default: + break; + } + } + break; + + case kIOHIDElementTypeCollection: { + CFArrayRef array = IOHIDElementGetChildren(p_element); + if (array) { + add_hid_elements(array); + } + } + break; + + default: + break; + } + + if (list) { /* add to list */ + rec_element element; + + element.ref = p_element; + element.usage = usage; + + element.min = (SInt32) IOHIDElementGetLogicalMin(p_element); + element.max = (SInt32) IOHIDElementGetLogicalMax(p_element); + element.cookie = IOHIDElementGetCookie(p_element); + list->push_back(element); + list->sort_custom<rec_element::Comparator>(); + } + } +} + +static void hid_element_added(const void *p_value, void *p_parameter) { + joystick *joy = (joystick*) p_parameter; + joy->add_hid_element((IOHIDElementRef) p_value); +} + +void joystick::add_hid_elements(CFArrayRef p_array) { + CFRange range = { 0, CFArrayGetCount(p_array) }; + CFArrayApplyFunction(p_array, range,hid_element_added,this); +} + +static void joystick_removed_callback(void *ctx, IOReturn result, void *sender) { + int id = (intptr_t) ctx; + self->_device_removed(id); +} + + +static void joystick_added_callback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef ioHIDDeviceObject) { + self->_device_added(res, ioHIDDeviceObject); +} + +static bool is_joystick(IOHIDDeviceRef p_device_ref) { + CFTypeRef refCF = NULL; + int usage_page = 0; + int usage = 0; + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDPrimaryUsagePageKey)); + if (refCF) { + CFNumberGetValue((CFNumberRef) refCF, kCFNumberSInt32Type, &usage_page); + } + if (usage_page != kHIDPage_GenericDesktop) { + return false; + } + + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDPrimaryUsageKey)); + if (refCF) { + CFNumberGetValue((CFNumberRef) refCF, kCFNumberSInt32Type, &usage); + } + if ((usage != kHIDUsage_GD_Joystick && + usage != kHIDUsage_GD_GamePad && + usage != kHIDUsage_GD_MultiAxisController)) { + return false; + } + return true; +} + +void JoystickOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { + + if (p_res != kIOReturnSuccess || have_device(p_device)) { + return; + } + + joystick new_joystick; + if (is_joystick(p_device)) { + configure_joystick(p_device, &new_joystick); +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + if (IOHIDDeviceGetService != NULL) { +#endif + const io_service_t ioservice = IOHIDDeviceGetService(p_device); + if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK) && new_joystick.config_force_feedback(ioservice)) { + new_joystick.ffservice = ioservice; + } +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + } +#endif + device_list.push_back(new_joystick); + } + IOHIDDeviceRegisterRemovalCallback(p_device, joystick_removed_callback, (void*) (intptr_t) new_joystick.id); + IOHIDDeviceScheduleWithRunLoop(p_device, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); +} + +void JoystickOSX::_device_removed(int p_id) { + + int device = get_joy_index(p_id); + ERR_FAIL_COND(device == -1); + + input->joy_connection_changed(p_id, false, ""); + device_list[device].free(); + device_list.remove(device); + attached_devices[p_id] = false; +} + +static String _hex_str(uint8_t p_byte) { + + static const char* dict = "0123456789abcdef"; + char ret[3]; + ret[2] = 0; + + ret[0] = dict[p_byte>>4]; + ret[1] = dict[p_byte & 0xF]; + + return ret; +} + +bool JoystickOSX::configure_joystick(IOHIDDeviceRef p_device_ref, joystick* p_joy) { + + CFTypeRef refCF = NULL; + + p_joy->device_ref = p_device_ref; + /* get device name */ + String name; + char c_name[256]; + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDProductKey)); + if (!refCF) { + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDManufacturerKey)); + } + if ((!refCF) || (!CFStringGetCString((CFStringRef) refCF, c_name, sizeof (c_name), kCFStringEncodingUTF8))) { + name = "Unidentified Joystick"; + } + name = c_name; + + int id = get_free_joy_id(); + ERR_FAIL_COND_V(id == -1, false); + p_joy->id = id; + int vendor = 0; + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDVendorIDKey)); + if (refCF) { + CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &vendor); + } + + int product_id = 0; + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDProductIDKey)); + if (refCF) { + CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &product_id); + } + if (vendor && product_id) { + char uid[128]; + sprintf(uid, "%04x%08x%04x%08x", OSSwapHostToBigInt32(vendor),0, OSSwapHostToBigInt32(product_id), 0); + input->joy_connection_changed(id, true, name, uid); + } + else { + //bluetooth device + String guid = "05000000"; + for (int i = 0; i < 12; i++) { + if (i < name.size()) guid += _hex_str(name[i]); + else guid += "00"; + } + input->joy_connection_changed(id, true, name, guid); + } + + CFArrayRef array = NULL; + array = IOHIDDeviceCopyMatchingElements(p_device_ref, NULL, kIOHIDOptionsTypeNone); + if (array) { + p_joy->add_hid_elements(array); + CFRelease(array); + } + return true; +} + +#define FF_ERR() { if (ret != FF_OK) { FFReleaseDevice(ff_device); return false; } } +bool joystick::config_force_feedback(io_service_t p_service) { + + HRESULT ret = FFCreateDevice(p_service, &ff_device); + ERR_FAIL_COND_V(ret != FF_OK, false); + + ret = FFDeviceSendForceFeedbackCommand(ff_device, FFSFFC_RESET); + FF_ERR(); + + ret = FFDeviceSendForceFeedbackCommand(ff_device, FFSFFC_SETACTUATORSON); + FF_ERR(); + + if (check_ff_features()) { + ret = FFDeviceCreateEffect(ff_device, kFFEffectType_ConstantForce_ID, &ff_effect, &ff_object); + FF_ERR(); + return true; + } + FFReleaseDevice(ff_device); + return false; +} +#undef FF_ERR + +#define TEST_FF(ff) (features.supportedEffects & (ff)) +bool joystick::check_ff_features() { + + FFCAPABILITIES features; + HRESULT ret = FFDeviceGetForceFeedbackCapabilities(ff_device, &features); + if (ret == FF_OK && (features.supportedEffects & FFCAP_ET_CONSTANTFORCE)) { + uint32_t val; + ret = FFDeviceGetForceFeedbackProperty(ff_device, FFPROP_FFGAIN, &val, sizeof(val)); + if (ret != FF_OK) return false; + int num_axes = features.numFfAxes; + ff_axes = (DWORD*) memalloc(sizeof(DWORD) * num_axes); + ff_directions = (LONG*) memalloc(sizeof(LONG) * num_axes); + + for (int i = 0; i < num_axes; i++) { + ff_axes[i] = features.ffAxes[i]; + ff_directions[i] = 0; + } + + ff_effect.cAxes = num_axes; + ff_effect.rgdwAxes = ff_axes; + ff_effect.rglDirection = ff_directions; + return true; + } + return false; +} + +static int process_hat_value(int p_min, int p_max, int p_value) { + int range = (p_max - p_min + 1); + int value = p_value - p_min; + int hat_value = InputDefault::HAT_MASK_CENTER; + if (range == 4) { + value *= 2; + } + + switch (value) { + case 0: + hat_value = InputDefault::HAT_MASK_UP; + break; + case 1: + hat_value = InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_RIGHT; + break; + case 2: + hat_value = InputDefault::HAT_MASK_RIGHT; + break; + case 3: + hat_value = InputDefault::HAT_MASK_DOWN | InputDefault::HAT_MASK_RIGHT; + break; + case 4: + hat_value = InputDefault::HAT_MASK_DOWN; + break; + case 5: + hat_value = InputDefault::HAT_MASK_DOWN | InputDefault::HAT_MASK_LEFT; + break; + case 6: + hat_value = InputDefault::HAT_MASK_LEFT; + break; + case 7: + hat_value = InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_LEFT; + break; + default: + hat_value = InputDefault::HAT_MASK_CENTER; + break; + } + return hat_value; +} + +void JoystickOSX::poll_joysticks() const { + while (CFRunLoopRunInMode(GODOT_JOY_LOOP_RUN_MODE,0,TRUE) == kCFRunLoopRunHandledSource) { + /* no-op. Pending callbacks will fire. */ + } +} + +static const InputDefault::JoyAxis axis_correct(int p_value, int p_min, int p_max) { + InputDefault::JoyAxis jx; + if (p_min < 0) { + jx.min = -1; + if (p_value < 0) { + jx.value = (float) -p_value / p_min; + } + else jx.value = (float) p_value / p_max; + } + if (p_min == 0) { + jx.min = 0; + jx.value = 0.0f + (float) p_value / p_max; + } + return jx; +} + +uint32_t JoystickOSX::process_joysticks(uint32_t p_last_id){ + poll_joysticks(); + + for (int i = 0; i < device_list.size(); i++) { + joystick &joy = device_list[i]; + + for (int j = 0; j < joy.axis_elements.size(); j++) { + rec_element &elem = joy.axis_elements[j]; + int value = joy.get_hid_element_state(&elem); + p_last_id = input->joy_axis(p_last_id, joy.id, j, axis_correct(value, elem.min, elem.max)); + } + for (int j = 0; j < joy.button_elements.size(); j++) { + int value = joy.get_hid_element_state(&joy.button_elements[j]); + p_last_id = input->joy_button(p_last_id, joy.id, j, (value>=1)); + } + for (int j = 0; j < joy.hat_elements.size(); j++) { + rec_element &elem = joy.hat_elements[j]; + int value = joy.get_hid_element_state(&elem); + int hat_value = process_hat_value(elem.min, elem.max, value); + p_last_id = input->joy_hat(p_last_id, joy.id, hat_value); + } + + if (joy.ffservice) { + uint64_t timestamp = input->get_joy_vibration_timestamp(joy.id); + if (timestamp > joy.ff_timestamp) { + Vector2 strength = input->get_joy_vibration_strength(joy.id); + float duration = input->get_joy_vibration_duration(joy.id); + if (strength.x == 0 && strength.y == 0) { + joystick_vibration_stop(joy.id, timestamp); + } + else { + float gain = MAX(strength.x, strength.y); + joystick_vibration_start(joy.id, gain, duration, timestamp); + } + } + } + } + return p_last_id; +} + +void JoystickOSX::joystick_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp) { + joystick *joy = &device_list[get_joy_index(p_id)]; + joy->ff_timestamp = p_timestamp; + joy->ff_effect.dwDuration = p_duration * FF_SECONDS; + joy->ff_effect.dwGain = p_magnitude * FF_FFNOMINALMAX; + FFEffectSetParameters(joy->ff_object, &joy->ff_effect, FFEP_DURATION | FFEP_GAIN); + FFEffectStart(joy->ff_object, 1, 0); +} + +void JoystickOSX::joystick_vibration_stop(int p_id, uint64_t p_timestamp) { + joystick* joy = &device_list[get_joy_index(p_id)]; + joy->ff_timestamp = p_timestamp; + FFEffectStop(joy->ff_object); +} + +int JoystickOSX::get_free_joy_id() { + for (int i = 0; i < JOYSTICKS_MAX; i++) { + if (!attached_devices[i]) { + attached_devices[i] = true; + return i; + } + } + return -1; +} + +int JoystickOSX::get_joy_index(int p_id) const { + for (int i = 0; i < device_list.size(); i++) { + if (device_list[i].id == p_id) return i; + } + return -1; +} + +bool JoystickOSX::have_device(IOHIDDeviceRef p_device) const { + for (int i = 0; i < device_list.size(); i++) { + if (device_list[i].device_ref == p_device) { + return true; + } + } + return false; +} + +static CFDictionaryRef create_match_dictionary(const UInt32 page, const UInt32 usage, int *okay) +{ + CFDictionaryRef retval = NULL; + CFNumberRef pageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page); + CFNumberRef usageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + const void *keys[2] = { (void *) CFSTR(kIOHIDDeviceUsagePageKey), (void *) CFSTR(kIOHIDDeviceUsageKey) }; + const void *vals[2] = { (void *) pageNumRef, (void *) usageNumRef }; + + if (pageNumRef && usageNumRef) { + retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + + if (pageNumRef) { + CFRelease(pageNumRef); + } + if (usageNumRef) { + CFRelease(usageNumRef); + } + + if (!retval) { + *okay = 0; + } + + return retval; +} + +void JoystickOSX::config_hid_manager(CFArrayRef p_matching_array) const { + + CFRunLoopRef runloop = CFRunLoopGetCurrent(); + IOReturn ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); + ERR_FAIL_COND(ret != kIOReturnSuccess); + + IOHIDManagerSetDeviceMatchingMultiple(hid_manager, p_matching_array); + IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, joystick_added_callback, NULL); + IOHIDManagerScheduleWithRunLoop(hid_manager, runloop, GODOT_JOY_LOOP_RUN_MODE); + + while (CFRunLoopRunInMode(GODOT_JOY_LOOP_RUN_MODE,0,TRUE) == kCFRunLoopRunHandledSource) { + /* no-op. Callback fires once per existing device. */ + } +} + +JoystickOSX::JoystickOSX() +{ + self = this; + input = (InputDefault*)Input::get_singleton(); + + for (int i = 0; i < JOYSTICKS_MAX; i++) { + attached_devices[i] = false; + } + + int okay = 1; + const void *vals[] = { + (void *) create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, &okay), + (void *) create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, &okay), + (void *) create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController, &okay), + }; + const size_t n_elements = sizeof(vals)/sizeof(vals[0]); + CFArrayRef array = okay ? CFArrayCreate(kCFAllocatorDefault, vals, n_elements, &kCFTypeArrayCallBacks) : NULL; + + for (int i = 0; i < n_elements; i++) { + if (vals[i]) { + CFRelease((CFTypeRef) vals[i]); + } + } + + if (array) { + hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (hid_manager != NULL) { + config_hid_manager(array); + } + CFRelease(array); + } +} + +JoystickOSX::~JoystickOSX() { + + for (int i = 0; i < device_list.size(); i++) { + device_list[i].free(); + } + + IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); + IOHIDManagerClose(hid_manager, kIOHIDOptionsTypeNone); + CFRelease(hid_manager); + hid_manager = NULL; +} + diff --git a/platform/osx/joystick_osx.h b/platform/osx/joystick_osx.h new file mode 100644 index 0000000000..38a4e3b1d3 --- /dev/null +++ b/platform/osx/joystick_osx.h @@ -0,0 +1,125 @@ +/*************************************************************************/ +/* joystick_osx.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 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 JOYSTICKOSX_H +#define JOYSTICKOSX_H + +#ifdef MACOS_10_0_4 +#include <IOKit/hidsystem/IOHIDUsageTables.h> +#else +#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h> +#endif +#include <IOKit/hid/IOHIDLib.h> +#include <ForceFeedback/ForceFeedback.h> +#include <ForceFeedback/ForceFeedbackConstants.h> + +#include "main/input_default.h" + +struct rec_element { + IOHIDElementRef ref; + IOHIDElementCookie cookie; + + uint32_t usage; + + int min; + int max; + + struct Comparator { + bool operator()(const rec_element p_a, const rec_element p_b) const { return p_a.usage < p_b.usage; } + }; +}; + +struct joystick { + IOHIDDeviceRef device_ref; + + Vector<rec_element> axis_elements; + Vector<rec_element> button_elements; + Vector<rec_element> hat_elements; + + int id; + + io_service_t ffservice; /* Interface for force feedback, 0 = no ff */ + FFCONSTANTFORCE ff_constant_force; + FFDeviceObjectReference ff_device; + FFEffectObjectReference ff_object; + uint64_t ff_timestamp; + LONG *ff_directions; + FFEFFECT ff_effect; + DWORD *ff_axes; + + void add_hid_elements(CFArrayRef p_array); + void add_hid_element(IOHIDElementRef p_element); + + bool has_element(IOHIDElementCookie p_cookie, Vector<rec_element> *p_list) const; + bool config_force_feedback(io_service_t p_service); + bool check_ff_features(); + + int get_hid_element_state(rec_element *p_element) const; + + void free(); + joystick(); +}; + +class JoystickOSX { + + enum { + JOYSTICKS_MAX = 16, + }; + +private: + InputDefault *input; + IOHIDManagerRef hid_manager; + + bool attached_devices[JOYSTICKS_MAX]; + Vector<joystick> device_list; + + bool have_device(IOHIDDeviceRef p_device) const; + bool configure_joystick(IOHIDDeviceRef p_device_ref, joystick *p_joy); + + + int get_free_joy_id(); + int get_joy_index(int p_id) const; + + void poll_joysticks() const; + void setup_joystick_objects(); + void config_hid_manager(CFArrayRef p_matching_array) const; + + void joystick_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp); + void joystick_vibration_stop(int p_id, uint64_t p_timestamp); + +public: + uint32_t process_joysticks(uint32_t p_last_id); + + void _device_added(IOReturn p_res, IOHIDDeviceRef p_device); + void _device_removed(int p_id); + + JoystickOSX(); + ~JoystickOSX(); +}; + +#endif // JOYSTICKOSX_H diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 8f89695a68..e23ae49a35 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -31,6 +31,7 @@ #include "os/input.h" +#include "joystick_osx.h" #include "drivers/unix/os_unix.h" #include "main/input_default.h" #include "servers/visual_server.h" @@ -76,6 +77,7 @@ public: SpatialSound2DServerSW *spatial_sound_2d_server; InputDefault *input; + JoystickOSX *joystick_osx; /* objc */ @@ -203,6 +205,7 @@ public: virtual void set_window_maximized(bool p_enabled); virtual bool is_window_maximized() const; virtual void request_attention(); + virtual String get_joy_guid(int p_device) const; void run(); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index b084a08ecc..cc893cc7a0 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1123,6 +1123,7 @@ void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi physics_2d_server->init(); input = memnew( InputDefault ); + joystick_osx = memnew( JoystickOSX ); _ensure_data_dir(); @@ -1165,7 +1166,7 @@ void OS_OSX::finalize() { spatial_sound_2d_server->finish(); memdelete(spatial_sound_2d_server); - + memdelete(joystick_osx); memdelete(input); memdelete(sample_manager); @@ -1738,7 +1739,7 @@ void OS_OSX::run() { while (!force_quit) { process_events(); // get rid of pending events -// process_joysticks(); + last_id = joystick_osx->process_joysticks(last_id); if (Main::iteration()==true) break; }; @@ -1773,6 +1774,10 @@ OS::MouseMode OS_OSX::get_mouse_mode() const { return mouse_mode; } +String OS_OSX::get_joy_guid(int p_device) const { + return input->get_joy_guid_remapped(p_device); +} + OS_OSX* OS_OSX::singleton=NULL; OS_OSX::OS_OSX() { diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 4dbc106834..93e46da82b 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -399,8 +399,6 @@ AcceptDialog::AcceptDialog() { add_child(label); hbc = memnew( HBoxContainer ); - hbc->set_area_as_parent_rect(margin); - hbc->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,button_margin); add_child(hbc); hbc->add_spacer(); diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index 923a35031c..2c576b6ba5 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -297,6 +297,7 @@ void TextureProgress::_bind_methods() { TextureProgress::TextureProgress() { mode=FILL_LEFT_TO_RIGHT; + rad_init_angle=0; rad_center_off=Point2(); rad_max_degrees=360; } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 086b69c1c5..1892240426 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2903,16 +2903,16 @@ void Node::_bind_methods() { mi.name="rpc"; - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc",&Node::_rpc_bind,mi); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"rpc",&Node::_rpc_bind,mi); mi.name="rpc_unreliable"; - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable",&Node::_rpc_unreliable_bind,mi); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable",&Node::_rpc_unreliable_bind,mi); - mi.arguments.push_front( PropertyInfo( Variant::INT, "peer_") ); + mi.arguments.push_front( PropertyInfo( Variant::INT, "peer_id") ); mi.name="rpc_id"; - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc_id",&Node::_rpc_id_bind,mi); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"rpc_id",&Node::_rpc_id_bind,mi); mi.name="rpc_unreliable_id"; - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable_id",&Node::_rpc_unreliable_id_bind,mi); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable_id",&Node::_rpc_unreliable_id_bind,mi); } diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index 4c7b7c1399..e3472c074a 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -2200,13 +2200,9 @@ void SceneTree::_bind_methods() { mi.arguments.push_back( PropertyInfo( Variant::INT, "flags")); mi.arguments.push_back( PropertyInfo( Variant::STRING, "group")); mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); - Vector<Variant> defargs; - for(int i=0;i<VARIANT_ARG_MAX;i++) { - mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); - defargs.push_back(Variant()); - } - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call_group",&SceneTree::_call_group,mi,defargs); + + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"call_group",&SceneTree::_call_group,mi); ObjectTypeDB::bind_method(_MD("set_current_scene","child_node:Node"),&SceneTree::set_current_scene); ObjectTypeDB::bind_method(_MD("get_current_scene:Node"),&SceneTree::get_current_scene); diff --git a/tools/doc/doc_data.cpp b/tools/doc/doc_data.cpp index 479b99a03d..4a8fdfb215 100644 --- a/tools/doc/doc_data.cpp +++ b/tools/doc/doc_data.cpp @@ -198,6 +198,11 @@ void DocData::generate(bool p_basic_types) { if (method.qualifiers!="") method.qualifiers+=" "; method.qualifiers+="const"; + + } else if (E->get().flags&METHOD_FLAG_VARARG) { + if (method.qualifiers!="") + method.qualifiers+=" "; + method.qualifiers+="vararg"; } for(int i=-1;i<E->get().arguments.size();i++) { diff --git a/tools/editor/editor_help.cpp b/tools/editor/editor_help.cpp index 8f486ba0c2..4f83dc2f66 100644 --- a/tools/editor/editor_help.cpp +++ b/tools/editor/editor_help.cpp @@ -882,6 +882,15 @@ Error EditorHelp::_goto_desc(const String& p_class,int p_vscr) { class_desc->pop(); } + if (cd.methods[i].qualifiers.find("vararg")!=-1) { + class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color")); + class_desc->add_text(","); + class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/symbol_color")); + class_desc->add_text(" ... "); + class_desc->pop(); + class_desc->pop(); + } + class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/symbol_color")); class_desc->add_text(cd.methods[i].arguments.size()?" )":")"); class_desc->pop(); diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index f4b67f6e2b..8496530db3 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -1228,7 +1228,7 @@ void EditorNode::_dialog_action(String p_file) { //_save_scene(p_file); _save_scene_with_preview(p_file); - _run(false); + _run(true); } } break; diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index 99c80fdc36..ad5cd86b4b 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -574,6 +574,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("grid_map/pick_distance", 5000.0); + set("3d_editor/grid_color",Color(0,1,0,0.2)); + hints["3d_editor/grid_color"]=PropertyInfo(Variant::COLOR,"3d_editor/grid_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT|PROPERTY_USAGE_RESTART_IF_CHANGED); + set("3d_editor/default_fov",45.0); set("3d_editor/default_z_near",0.1); set("3d_editor/default_z_far",500.0); diff --git a/tools/editor/plugins/canvas_item_editor_plugin.cpp b/tools/editor/plugins/canvas_item_editor_plugin.cpp index 57707ffa72..3468f42a6c 100644 --- a/tools/editor/plugins/canvas_item_editor_plugin.cpp +++ b/tools/editor/plugins/canvas_item_editor_plugin.cpp @@ -290,6 +290,7 @@ Dictionary CanvasItemEditor::get_state() const { state["snap_rotation"]=snap_rotation; state["snap_relative"]=snap_relative; state["snap_pixel"]=snap_pixel; + state["skeleton_show_bones"]=skeleton_show_bones; return state; } void CanvasItemEditor::set_state(const Dictionary& p_state){ @@ -351,6 +352,12 @@ void CanvasItemEditor::set_state(const Dictionary& p_state){ int idx = edit_menu->get_popup()->get_item_index(SNAP_USE_PIXEL); edit_menu->get_popup()->set_item_checked(idx,snap_pixel); } + + if (state.has("skeleton_show_bones")) { + skeleton_show_bones=state["skeleton_show_bones"]; + int idx = skeleton_menu->get_item_index(SKELETON_SHOW_BONES); + skeleton_menu->set_item_checked(idx,skeleton_show_bones); + } } @@ -2083,76 +2090,78 @@ void CanvasItemEditor::_viewport_draw() { } - int bone_width = EditorSettings::get_singleton()->get("2d_editor/bone_width"); - Color bone_color1 = EditorSettings::get_singleton()->get("2d_editor/bone_color1"); - Color bone_color2 = EditorSettings::get_singleton()->get("2d_editor/bone_color2"); - Color bone_ik_color = EditorSettings::get_singleton()->get("2d_editor/bone_ik_color"); - Color bone_selected_color = EditorSettings::get_singleton()->get("2d_editor/bone_selected_color"); + if (skeleton_show_bones) { + int bone_width = EditorSettings::get_singleton()->get("2d_editor/bone_width"); + Color bone_color1 = EditorSettings::get_singleton()->get("2d_editor/bone_color1"); + Color bone_color2 = EditorSettings::get_singleton()->get("2d_editor/bone_color2"); + Color bone_ik_color = EditorSettings::get_singleton()->get("2d_editor/bone_ik_color"); + Color bone_selected_color = EditorSettings::get_singleton()->get("2d_editor/bone_selected_color"); - for(Map<ObjectID,BoneList>::Element*E=bone_list.front();E;E=E->next()) { + for(Map<ObjectID,BoneList>::Element*E=bone_list.front();E;E=E->next()) { - E->get().from=Vector2(); - E->get().to=Vector2(); + E->get().from=Vector2(); + E->get().to=Vector2(); - Object *obj = ObjectDB::get_instance(E->get().bone); - if (!obj) - continue; + Object *obj = ObjectDB::get_instance(E->get().bone); + if (!obj) + continue; - Node2D* n2d = obj->cast_to<Node2D>(); - if (!n2d) - continue; + Node2D* n2d = obj->cast_to<Node2D>(); + if (!n2d) + continue; - if (!n2d->get_parent()) - continue; + if (!n2d->get_parent()) + continue; - CanvasItem *pi = n2d->get_parent_item(); + CanvasItem *pi = n2d->get_parent_item(); - Node2D* pn2d=n2d->get_parent()->cast_to<Node2D>(); + Node2D* pn2d=n2d->get_parent()->cast_to<Node2D>(); - if (!pn2d) - continue; + if (!pn2d) + continue; - Vector2 from = transform.xform(pn2d->get_global_pos()); - Vector2 to = transform.xform(n2d->get_global_pos()); + Vector2 from = transform.xform(pn2d->get_global_pos()); + Vector2 to = transform.xform(n2d->get_global_pos()); - E->get().from=from; - E->get().to=to; + E->get().from=from; + E->get().to=to; - Vector2 rel = to-from; - Vector2 relt = rel.tangent().normalized()*bone_width; + Vector2 rel = to-from; + Vector2 relt = rel.tangent().normalized()*bone_width; - Vector<Vector2> bone_shape; - bone_shape.push_back(from); - bone_shape.push_back(from+rel*0.2+relt); - bone_shape.push_back(to); - bone_shape.push_back(from+rel*0.2-relt); - Vector<Color> colors; - if (pi->has_meta("_edit_ik_")) { + Vector<Vector2> bone_shape; + bone_shape.push_back(from); + bone_shape.push_back(from+rel*0.2+relt); + bone_shape.push_back(to); + bone_shape.push_back(from+rel*0.2-relt); + Vector<Color> colors; + if (pi->has_meta("_edit_ik_")) { - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - } else { - colors.push_back(bone_color1); - colors.push_back(bone_color2); - colors.push_back(bone_color1); - colors.push_back(bone_color2); - } + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + } else { + colors.push_back(bone_color1); + colors.push_back(bone_color2); + colors.push_back(bone_color1); + colors.push_back(bone_color2); + } - VisualServer::get_singleton()->canvas_item_add_primitive(ci,bone_shape,colors,Vector<Vector2>(),RID()); + VisualServer::get_singleton()->canvas_item_add_primitive(ci,bone_shape,colors,Vector<Vector2>(),RID()); - if (editor_selection->is_selected(pi)) { - for(int i=0;i<bone_shape.size();i++) { + if (editor_selection->is_selected(pi)) { + for(int i=0;i<bone_shape.size();i++) { - VisualServer::get_singleton()->canvas_item_add_line(ci,bone_shape[i],bone_shape[(i+1)%bone_shape.size()],bone_selected_color,2); + VisualServer::get_singleton()->canvas_item_add_line(ci,bone_shape[i],bone_shape[(i+1)%bone_shape.size()],bone_selected_color,2); + } } - } + } } } @@ -2536,6 +2545,12 @@ void CanvasItemEditor::_popup_callback(int p_op) { ((SnapDialog *)snap_dialog)->set_fields(snap_offset, snap_step, snap_rotation_offset, snap_rotation_step); snap_dialog->popup_centered(Size2(220,160)); } break; + case SKELETON_SHOW_BONES: { + skeleton_show_bones = !skeleton_show_bones; + int idx = skeleton_menu->get_item_index(SKELETON_SHOW_BONES); + skeleton_menu->set_item_checked(idx,skeleton_show_bones); + viewport->update(); + } break; case ZOOM_IN: { if (zoom>MAX_ZOOM) return; @@ -2999,6 +3014,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { continue; n2d->set_meta("_edit_bone_",true); + if (!skeleton_show_bones) + skeleton_menu->activate_item(skeleton_menu->get_item_index(SKELETON_SHOW_BONES)); } viewport->update(); @@ -3017,6 +3034,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { continue; n2d->set_meta("_edit_bone_",Variant()); + if (!skeleton_show_bones) + skeleton_menu->activate_item(skeleton_menu->get_item_index(SKELETON_SHOW_BONES)); } viewport->update(); @@ -3036,6 +3055,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { continue; canvas_item->set_meta("_edit_ik_",true); + if (!skeleton_show_bones) + skeleton_menu->activate_item(skeleton_menu->get_item_index(SKELETON_SHOW_BONES)); } @@ -3055,6 +3076,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { continue; n2d->set_meta("_edit_ik_",Variant()); + if (!skeleton_show_bones) + skeleton_menu->activate_item(skeleton_menu->get_item_index(SKELETON_SHOW_BONES)); } viewport->update(); @@ -3401,15 +3424,17 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_shortcut(ED_SHORTCUT("canvas_item_editor/expand_to_parent", TTR("Expand to Parent"), KEY_MASK_CMD | KEY_P), EXPAND_TO_PARENT); p->add_separator(); p->add_submenu_item(TTR("Skeleton.."),"skeleton"); - PopupMenu *p2 = memnew(PopupMenu); - p->add_child(p2); - p2->set_name("skeleton"); - p2->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bones"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B ),SKELETON_MAKE_BONES); - p2->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Bones")), SKELETON_CLEAR_BONES); - p2->add_separator(); - p2->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_set_ik_chain", TTR("Make IK Chain")), SKELETON_SET_IK_CHAIN); - p2->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_ik_chain", TTR("Clear IK Chain")), SKELETON_CLEAR_IK_CHAIN); - p2->connect("item_pressed", this,"_popup_callback"); + skeleton_menu = memnew(PopupMenu); + p->add_child(skeleton_menu); + skeleton_menu->set_name("skeleton"); + skeleton_menu->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bones"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B ),SKELETON_MAKE_BONES); + skeleton_menu->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Bones")), SKELETON_CLEAR_BONES); + skeleton_menu->add_separator(); + skeleton_menu->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES); + skeleton_menu->add_separator(); + skeleton_menu->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_set_ik_chain", TTR("Make IK Chain")), SKELETON_SET_IK_CHAIN); + skeleton_menu->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_ik_chain", TTR("Clear IK Chain")), SKELETON_CLEAR_IK_CHAIN); + skeleton_menu->connect("item_pressed", this,"_popup_callback"); /* @@ -3535,6 +3560,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { snap_show_grid=false; snap_rotation=false; snap_pixel=false; + skeleton_show_bones=true; + skeleton_menu->set_item_checked(skeleton_menu->get_item_index(SKELETON_SHOW_BONES),true); updating_value_dialog=false; box_selecting=false; //zoom=0.5; diff --git a/tools/editor/plugins/canvas_item_editor_plugin.h b/tools/editor/plugins/canvas_item_editor_plugin.h index ea582f6fa7..9f4bc46eb4 100644 --- a/tools/editor/plugins/canvas_item_editor_plugin.h +++ b/tools/editor/plugins/canvas_item_editor_plugin.h @@ -124,6 +124,7 @@ class CanvasItemEditor : public VBoxContainer { VIEW_FRAME_TO_SELECTION, SKELETON_MAKE_BONES, SKELETON_CLEAR_BONES, + SKELETON_SHOW_BONES, SKELETON_SET_IK_CHAIN, SKELETON_CLEAR_IK_CHAIN @@ -175,6 +176,7 @@ class CanvasItemEditor : public VBoxContainer { bool snap_rotation; bool snap_relative; bool snap_pixel; + bool skeleton_show_bones; bool box_selecting; Point2 box_selecting_to; bool key_pos; @@ -256,6 +258,7 @@ class CanvasItemEditor : public VBoxContainer { ToolButton *ungroup_button; MenuButton *edit_menu; + PopupMenu *skeleton_menu; MenuButton *view_menu; HBoxContainer *animation_hb; MenuButton *animation_menu; diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 95106d2c81..41956747e1 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -3151,6 +3151,8 @@ void SpatialEditor::_init_indicators() { Vector<Color> origin_colors; Vector<Vector3> origin_points; + Color grid_color = EditorSettings::get_singleton()->get("3d_editor/grid_color"); + for(int i=0;i<3;i++) { Vector3 axis; axis[i]=1; @@ -3168,10 +3170,10 @@ void SpatialEditor::_init_indicators() { for(int j=-ORIGIN_GRID_SIZE;j<=ORIGIN_GRID_SIZE;j++) { - grid_colors[i].push_back(Color(axis.x,axis.y,axis.z,0.2)); - grid_colors[i].push_back(Color(axis.x,axis.y,axis.z,0.2)); - grid_colors[i].push_back(Color(axis.x,axis.y,axis.z,0.2)); - grid_colors[i].push_back(Color(axis.x,axis.y,axis.z,0.2)); + grid_colors[i].push_back(grid_color); + grid_colors[i].push_back(grid_color); + grid_colors[i].push_back(grid_color); + grid_colors[i].push_back(grid_color); grid_points[i].push_back(axis_n1*ORIGIN_GRID_SIZE+axis_n2*j); grid_points[i].push_back(-axis_n1*ORIGIN_GRID_SIZE+axis_n2*j); grid_points[i].push_back(axis_n2*ORIGIN_GRID_SIZE+axis_n1*j); diff --git a/tools/editor/plugins/tile_map_editor_plugin.cpp b/tools/editor/plugins/tile_map_editor_plugin.cpp index 822d9e6c87..43fe7d7ea9 100644 --- a/tools/editor/plugins/tile_map_editor_plugin.cpp +++ b/tools/editor/plugins/tile_map_editor_plugin.cpp @@ -289,15 +289,16 @@ void TileMapEditor::_pick_tile(const Point2& p_pos) { canvas_item_editor->update(); } -DVector<Vector2> TileMapEditor::_bucket_fill(const Point2i& p_start) { +DVector<Vector2> TileMapEditor::_bucket_fill(const Point2i& p_start, bool erase) { - if (node->get_cell(p_start.x, p_start.y) != TileMap::INVALID_CELL) - return DVector<Vector2>(); + int prev_id = node->get_cell(p_start.x, p_start.y); + int id = TileMap::INVALID_CELL; + if (!erase) { + id = get_selected_tile(); - int id = get_selected_tile(); - - if (id == TileMap::INVALID_CELL) - return DVector<Vector2>(); + if (id == TileMap::INVALID_CELL) + return DVector<Vector2>(); + } Rect2 r = node->get_item_rect(); r.pos = r.pos/node->get_cell_size(); @@ -316,7 +317,7 @@ DVector<Vector2> TileMapEditor::_bucket_fill(const Point2i& p_start) { if (!r.has_point(n)) continue; - if (node->get_cell(n.x, n.y) == TileMap::INVALID_CELL) { + if (node->get_cell(n.x, n.y) == prev_id) { node->set_cellv(n, id, flip_h, flip_v, transpose); @@ -685,6 +686,12 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) { } else if (tool==TOOL_BUCKET) { + Dictionary pop; + pop["id"] = node->get_cell(over_tile.x, over_tile.y); + pop["flip_h"] = node->is_cell_x_flipped(over_tile.x, over_tile.y); + pop["flip_v"] = node->is_cell_y_flipped(over_tile.x, over_tile.y); + pop["transpose"] = node->is_cell_transposed(over_tile.x, over_tile.y); + DVector<Vector2> points = _bucket_fill(over_tile); if (points.size() == 0) @@ -699,7 +706,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) { undo_redo->create_action("Bucket Fill"); undo_redo->add_do_method(this, "_fill_points", points, op); - undo_redo->add_undo_method(this, "_erase_points", points); + undo_redo->add_undo_method(this, "_fill_points", points, pop); undo_redo->commit_action(); } @@ -782,6 +789,26 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) { tool=TOOL_NONE; return true; + + } else if (tool==TOOL_BUCKET) { + + Dictionary pop; + pop["id"] = node->get_cell(over_tile.x, over_tile.y); + pop["flip_h"] = node->is_cell_x_flipped(over_tile.x, over_tile.y); + pop["flip_v"] = node->is_cell_y_flipped(over_tile.x, over_tile.y); + pop["transpose"] = node->is_cell_transposed(over_tile.x, over_tile.y); + + DVector<Vector2> points = _bucket_fill(over_tile, true); + + if (points.size() == 0) + return false; + + undo_redo->create_action("Bucket Fill"); + + undo_redo->add_do_method(this, "_erase_points", points); + undo_redo->add_undo_method(this, "_fill_points", points, pop); + + undo_redo->commit_action(); } } } @@ -798,7 +825,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) { canvas_item_editor->update(); } - int tile_under = node->get_cell(over_tile.x, over_tile.y); + int tile_under = node->get_cell(over_tile.x, over_tile.y); String tile_name = "none"; if (node->get_tileset()->has_tile(tile_under)) diff --git a/tools/editor/plugins/tile_map_editor_plugin.h b/tools/editor/plugins/tile_map_editor_plugin.h index 666290489b..4b47dccd15 100644 --- a/tools/editor/plugins/tile_map_editor_plugin.h +++ b/tools/editor/plugins/tile_map_editor_plugin.h @@ -129,7 +129,7 @@ class TileMapEditor : public VBoxContainer { void _pick_tile(const Point2& p_pos); - DVector<Vector2> _bucket_fill(const Point2i& p_start); + DVector<Vector2> _bucket_fill(const Point2i& p_start, bool erase=false); void _fill_points(const DVector<Vector2> p_points, const Dictionary& p_op); void _erase_points(const DVector<Vector2> p_points); |