diff options
114 files changed, 3595 insertions, 1640 deletions
diff --git a/.gitignore b/.gitignore index de9eed200a..abe1a234f5 100644 --- a/.gitignore +++ b/.gitignore @@ -233,3 +233,4 @@ Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ +logo.h @@ -15,9 +15,13 @@ Development is sponsored by OKAM Studio (http://www.okamstudio.com). Having been developed as in-house means that the user experience may still not be ideal for everyone. The features needed to make a great game are there, but we really need your help to fix all the rough edges and improve usability (via feedback and/or code contributions). We know we are close to having an awesome, open source, game engine with nothing to envy from the best commercial offerings, but we can't do this alone. This is why Godot is now open source, so everyone can help us reach this goal. -### Binary Downloads, Documentation, Community, etc. +### Documentation -Binary downloads, documentation, community, etc. can be found in Godot homepage: +Documentation has been moved to the [GitHub Wiki](https://github.com/okamstudio/godot/wiki). + +### Binary Downloads, Community, etc. + +Binary downloads, community, etc. can be found in Godot homepage: http://www.godotengine.org diff --git a/SConstruct b/SConstruct index 879396ef62..ed65f2b89f 100644 --- a/SConstruct +++ b/SConstruct @@ -88,7 +88,7 @@ if profile: elif os.path.isfile(profile+".py"): customs.append(profile+".py") -opts=Options(customs, ARGUMENTS) +opts=Variables(customs, ARGUMENTS) opts.Add('target', 'Compile Target (debug/profile/release).', "debug") opts.Add('platform','Platform: '+str(platform_list)+'(sfml).',"") opts.Add('python','Build Python Support: (yes/no)','no') @@ -221,18 +221,9 @@ for p in platform_list: if (env["builtin_zlib"]=='yes'): env.Append(CPPPATH=['#drivers/builtin_zlib/zlib']) - if (env['squirrel']=='yes'): - - env.Append(CPPFLAGS=['-DSQUIRREL_ENABLED']) - env.Append(CPPPATH=['#script/squirrel/src']) - # to test 64 bits compiltion # env.Append(CPPFLAGS=['-m64']) - if (env['lua']=='yes'): - - env.Append(CPPFLAGS=['-DLUA_ENABLED']) - env.Append(CPPPATH=['#script/lua/src']) if (env_base['squish']=='yes'): env.Append(CPPFLAGS=['-DSQUISH_ENABLED']); @@ -308,7 +299,6 @@ for p in platform_list: SConscript("servers/SCsub") SConscript("scene/SCsub") SConscript("tools/SCsub") - SConscript("script/SCsub"); SConscript("drivers/SCsub") SConscript("bin/SCsub") diff --git a/bin/tests/test_gdscript.cpp b/bin/tests/test_gdscript.cpp index 48f982425b..9670e6af6e 100644 --- a/bin/tests/test_gdscript.cpp +++ b/bin/tests/test_gdscript.cpp @@ -35,10 +35,10 @@ #ifdef GDSCRIPT_ENABLED -#include "script/gdscript/gd_tokenizer.h" -#include "script/gdscript/gd_parser.h" -#include "script/gdscript/gd_compiler.h" -#include "script/gdscript/gd_script.h" +#include "modules/gdscript/gd_tokenizer.h" +#include "modules/gdscript/gd_parser.h" +#include "modules/gdscript/gd_compiler.h" +#include "modules/gdscript/gd_script.h" namespace TestGDScript { @@ -864,7 +864,7 @@ MainLoop* test(TestType p_test) { if (p_test==TEST_TOKENIZER) { - GDTokenizer tk; + GDTokenizerText tk; tk.set_code(code); int line=-1; while(tk.get_token()!=GDTokenizer::TK_EOF) { @@ -969,8 +969,16 @@ MainLoop* test(TestType p_test) { + } else if (p_test==TEST_BYTECODE) { + + Vector<uint8_t> buf = GDTokenizerBuffer::parse_code_string(code); + String dst = test.basename()+".gdc"; + FileAccess *fw = FileAccess::open(dst,FileAccess::WRITE); + fw->store_buffer(buf.ptr(),buf.size()); + memdelete(fw); } + #if 0 Parser parser; Error err = parser.parse(code); diff --git a/bin/tests/test_gdscript.h b/bin/tests/test_gdscript.h index c3869abb8e..1659880c2a 100644 --- a/bin/tests/test_gdscript.h +++ b/bin/tests/test_gdscript.h @@ -36,7 +36,8 @@ namespace TestGDScript { enum TestType { TEST_TOKENIZER, TEST_PARSER, - TEST_COMPILER + TEST_COMPILER, + TEST_BYTECODE, }; MainLoop* test(TestType p_type); diff --git a/bin/tests/test_main.cpp b/bin/tests/test_main.cpp index eb63a7af84..5d66f35f24 100644 --- a/bin/tests/test_main.cpp +++ b/bin/tests/test_main.cpp @@ -152,6 +152,11 @@ MainLoop* test_main(String p_test,const List<String>& p_args) { return TestGDScript::test(TestGDScript::TEST_COMPILER); } + if (p_test=="gd_bytecode") { + + return TestGDScript::test(TestGDScript::TEST_BYTECODE); + } + if (p_test=="image") { return TestImage::test(); diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 61209ecb90..73f6f753b9 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -413,6 +413,56 @@ void _OS::dump_memory_to_file(const String& p_file) { OS::get_singleton()->dump_memory_to_file(p_file.utf8().get_data()); } +struct _OSCoreBindImg { + + String path; + Size2 size; + int fmt; + ObjectID id; + int vram; + bool operator<(const _OSCoreBindImg& p_img) const { return vram==p_img.vram ? id<p_img.id : vram > p_img.vram; } +}; + +void _OS::print_all_textures_by_size() { + + + List<_OSCoreBindImg> imgs; + int total=0; + { + List<Ref<Resource> > rsrc; + ResourceCache::get_cached_resources(&rsrc); + + for (List<Ref<Resource> >::Element *E=rsrc.front();E;E=E->next()) { + + if (!E->get()->is_type("ImageTexture")) + continue; + + Size2 size = E->get()->call("get_size"); + int fmt = E->get()->call("get_format"); + + _OSCoreBindImg img; + img.size=size; + img.fmt=fmt; + img.path=E->get()->get_path(); + img.vram=Image::get_image_data_size(img.size.width,img.size.height,Image::Format(img.fmt)); + img.id=E->get()->get_instance_ID(); + total+=img.vram; + imgs.push_back(img); + } + } + + imgs.sort(); + + for(List<_OSCoreBindImg>::Element *E=imgs.front();E;E=E->next()) { + + print_line(E->get().path+" - "+String::humanize_size(E->get().vram)+" ("+E->get().size+") - total:"+String::humanize_size(total) ); + total-=E->get().vram; + } + + + +} + void _OS::print_all_resources(const String& p_to_file ) { OS::get_singleton()->print_all_resources(p_to_file); @@ -516,6 +566,8 @@ void _OS::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_frames_per_second"),&_OS::get_frames_per_second); + ObjectTypeDB::bind_method(_MD("print_all_textures_by_size"),&_OS::print_all_textures_by_size); + BIND_CONSTANT( DAY_SUNDAY ); BIND_CONSTANT( DAY_MONDAY ); BIND_CONSTANT( DAY_TUESDAY ); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index e47c9c434a..9545fc65fb 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -128,6 +128,7 @@ public: void print_resources_in_use(bool p_short=false); void print_all_resources(const String& p_to_file); + void print_all_textures_by_size(); bool has_touchscreen_ui_hint() const; diff --git a/core/image.cpp b/core/image.cpp index a9485feff2..ccabd04d6f 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1260,6 +1260,12 @@ int Image::get_format_pixel_size(Format p_format) { return 1; } break; + case FORMAT_ATC: + case FORMAT_ATC_ALPHA_EXPLICIT: + case FORMAT_ATC_ALPHA_INTERPOLATED: { + + return 1; + } break; case FORMAT_ETC: { return 1; @@ -1323,6 +1329,15 @@ void Image::_get_format_min_data_size(Format p_format,int &r_w, int &r_h) { r_w=8; r_h=8; } break; + case FORMAT_ATC: + case FORMAT_ATC_ALPHA_EXPLICIT: + case FORMAT_ATC_ALPHA_INTERPOLATED: { + + r_w=8; + r_h=8; + + } break; + case FORMAT_ETC: { r_w=4; @@ -1339,7 +1354,7 @@ void Image::_get_format_min_data_size(Format p_format,int &r_w, int &r_h) { int Image::get_format_pixel_rshift(Format p_format) { - if (p_format==FORMAT_BC1 || p_format==FORMAT_BC4 || p_format==FORMAT_PVRTC4 || p_format==FORMAT_PVRTC4_ALPHA || p_format==FORMAT_ETC) + if (p_format==FORMAT_BC1 || p_format==FORMAT_BC4 || p_format==FORMAT_ATC || p_format==FORMAT_PVRTC4 || p_format==FORMAT_PVRTC4_ALPHA || p_format==FORMAT_ETC) return 1; else if (p_format==FORMAT_PVRTC2 || p_format==FORMAT_PVRTC2_ALPHA) return 2; diff --git a/core/image.h b/core/image.h index 4ab2870c23..186aceb1bf 100644 --- a/core/image.h +++ b/core/image.h @@ -70,6 +70,9 @@ public: FORMAT_PVRTC4, FORMAT_PVRTC4_ALPHA, FORMAT_ETC, // regular ETC, no transparency + FORMAT_ATC, + FORMAT_ATC_ALPHA_EXPLICIT, + FORMAT_ATC_ALPHA_INTERPOLATED, /*FORMAT_ETC2_R, for the future.. FORMAT_ETC2_RG, FORMAT_ETC2_RGB, diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index d2461498a6..c54398935e 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -90,6 +90,9 @@ enum { IMAGE_FORMAT_PVRTC4=14, IMAGE_FORMAT_PVRTC4_ALPHA=15, IMAGE_FORMAT_ETC=16, + IMAGE_FORMAT_ATC=17, + IMAGE_FORMAT_ATC_ALPHA_EXPLICIT=18, + IMAGE_FORMAT_ATC_ALPHA_INTERPOLATED=19, IMAGE_FORMAT_CUSTOM=30, @@ -283,6 +286,9 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { case IMAGE_FORMAT_PVRTC4: { fmt=Image::FORMAT_PVRTC4; } break; case IMAGE_FORMAT_PVRTC4_ALPHA: { fmt=Image::FORMAT_PVRTC4_ALPHA; } break; case IMAGE_FORMAT_ETC: { fmt=Image::FORMAT_ETC; } break; + case IMAGE_FORMAT_ATC: { fmt=Image::FORMAT_ATC; } break; + case IMAGE_FORMAT_ATC_ALPHA_EXPLICIT: { fmt=Image::FORMAT_ATC_ALPHA_EXPLICIT; } break; + case IMAGE_FORMAT_ATC_ALPHA_INTERPOLATED: { fmt=Image::FORMAT_ATC_ALPHA_INTERPOLATED; } break; case IMAGE_FORMAT_CUSTOM: { fmt=Image::FORMAT_CUSTOM; } break; default: { @@ -1335,6 +1341,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant& p_property, case Image::FORMAT_PVRTC4: f->store_32(IMAGE_FORMAT_PVRTC4 ); break; case Image::FORMAT_PVRTC4_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC4_ALPHA ); break; case Image::FORMAT_ETC: f->store_32(IMAGE_FORMAT_ETC); break; + case Image::FORMAT_ATC: f->store_32(IMAGE_FORMAT_ATC); break; + case Image::FORMAT_ATC_ALPHA_EXPLICIT: f->store_32(IMAGE_FORMAT_ATC_ALPHA_EXPLICIT); break; + case Image::FORMAT_ATC_ALPHA_INTERPOLATED: f->store_32(IMAGE_FORMAT_ATC_ALPHA_INTERPOLATED); break; case Image::FORMAT_CUSTOM: f->store_32(IMAGE_FORMAT_CUSTOM ); break; default: {} diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index 20a42f25df..fc5aecfd99 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -111,7 +111,7 @@ ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool } break; - } else if ( ((!reading_value && (c<33)) || c=='=' || c=='"') && tag.name.length()) { + } else if ( ((!reading_value && (c<33)) || c=='=' || c=='"' || c=='\'') && tag.name.length()) { if (!reading_value && name.length()) { @@ -551,6 +551,12 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name) imgformat=Image::FORMAT_PVRTC4_ALPHA; } else if (format=="etc") { imgformat=Image::FORMAT_ETC; + } else if (format=="atc") { + imgformat=Image::FORMAT_ATC; + } else if (format=="atcai") { + imgformat=Image::FORMAT_ATC_ALPHA_INTERPOLATED; + } else if (format=="atcae") { + imgformat=Image::FORMAT_ATC_ALPHA_EXPLICIT; } else if (format=="custom") { imgformat=Image::FORMAT_CUSTOM; } else { @@ -1937,6 +1943,9 @@ void ResourceFormatSaverXMLInstance::write_property(const String& p_name,const V case Image::FORMAT_PVRTC4: params+=" format=\"pvrtc4\""; break; case Image::FORMAT_PVRTC4_ALPHA: params+=" format=\"pvrtc4a\""; break; case Image::FORMAT_ETC: params+=" format=\"etc\""; break; + case Image::FORMAT_ATC: params+=" format=\"atc\""; break; + case Image::FORMAT_ATC_ALPHA_EXPLICIT: params+=" format=\"atcae\""; break; + case Image::FORMAT_ATC_ALPHA_INTERPOLATED: params+=" format=\"atcai\""; break; case Image::FORMAT_CUSTOM: params+=" format=\"custom\" custom_size=\""+itos(img.get_data().size())+"\""; break; default: {} } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 3bae6be83c..5ee48bae25 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -192,6 +192,7 @@ RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_n res->set_last_modified_time(mt); } #endif + return res; } @@ -246,7 +247,7 @@ String ResourceLoader::find_complete_path(const String& p_path,const String& p_t String path = local_path+E->get(); - if (FileAccess::exists(path)) { + if (PathRemap::get_singleton()->has_remap(path) || FileAccess::exists(path)) { candidates.push_back(path); } diff --git a/core/script_language.h b/core/script_language.h index 102d7c8436..9731273610 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -31,6 +31,7 @@ #include "resource.h" #include "map.h" +#include "pair.h" /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -157,6 +158,7 @@ public: virtual void get_recognized_extensions(List<String> *p_extensions) const=0; virtual void get_public_functions(List<MethodInfo> *p_functions) const=0; + virtual void get_public_constants(List<Pair<String,Variant> > *p_constants) const=0; virtual void frame(); diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 846b924a42..be1b0eb3d3 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -1487,6 +1487,9 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl _VariantCall::constant_data[Variant::IMAGE].value["FORMAT_PVRTC4"]=Image::FORMAT_PVRTC4; _VariantCall::constant_data[Variant::IMAGE].value["FORMAT_PVRTC4_ALPHA"]=Image::FORMAT_PVRTC4_ALPHA; _VariantCall::constant_data[Variant::IMAGE].value["FORMAT_ETC"]=Image::FORMAT_ETC; + _VariantCall::constant_data[Variant::IMAGE].value["FORMAT_ATC"]=Image::FORMAT_ATC; + _VariantCall::constant_data[Variant::IMAGE].value["FORMAT_ATC_ALPHA_EXPLICIT"]=Image::FORMAT_ATC_ALPHA_EXPLICIT; + _VariantCall::constant_data[Variant::IMAGE].value["FORMAT_ATC_ALPHA_INTERPOLATED"]=Image::FORMAT_ATC_ALPHA_INTERPOLATED; _VariantCall::constant_data[Variant::IMAGE].value["FORMAT_CUSTOM"]=Image::FORMAT_CUSTOM; } diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 109e4ab387..50908bbf94 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -1319,7 +1319,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid) return; int type=p_value; - if (type<0 || type>=6) + if (type<0 || type>=InputEvent::TYPE_MAX) return; //fail valid=true; ie.type=InputEvent::Type(type); @@ -2765,6 +2765,7 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const { InputEvent ie = operator InputEvent(); + p_list->push_back( PropertyInfo(Variant::INT,"type")); p_list->push_back( PropertyInfo(Variant::INT,"device")); p_list->push_back( PropertyInfo(Variant::INT,"ID")); diff --git a/core/vmap.h b/core/vmap.h index c6c3d50bc7..516299280b 100644 --- a/core/vmap.h +++ b/core/vmap.h @@ -142,6 +142,12 @@ public: } + int find_nearest(const T& p_val) const { + + bool exact; + return _find(p_val,exact); + + } _FORCE_INLINE_ int size() const { return _data.size(); } _FORCE_INLINE_ bool empty() const { return _data.empty(); } diff --git a/demos/2d/kinematic_char/colworld.gd b/demos/2d/kinematic_char/colworld.gd new file mode 100644 index 0000000000..efd1dab805 --- /dev/null +++ b/demos/2d/kinematic_char/colworld.gd @@ -0,0 +1,17 @@ + +extends Node2D + +# member variables here, example: +# var a=2 +# var b="textvar" + +func _ready(): + # Initalization here + pass + + + + +func _on_princess_body_enter( body ): + #the name of this editor-generated callback is unfortunate + get_node("youwin").show() diff --git a/demos/2d/kinematic_char/colworld.scn b/demos/2d/kinematic_char/colworld.scn Binary files differnew file mode 100644 index 0000000000..b1285b4811 --- /dev/null +++ b/demos/2d/kinematic_char/colworld.scn diff --git a/demos/2d/kinematic_char/engine.cfg b/demos/2d/kinematic_char/engine.cfg new file mode 100644 index 0000000000..0132442c18 --- /dev/null +++ b/demos/2d/kinematic_char/engine.cfg @@ -0,0 +1,13 @@ +[application] + +name="Kinematic Collision" +main_scene="res://colworld.scn" +icon="res://icon.png" + +[input] + +move_up=[key(Up)] +move_left=[key(Left)] +move_right=[key(Right)] +move_bottom=[key(Down)] +jump=[key(Space)] diff --git a/demos/2d/kinematic_char/icon.png b/demos/2d/kinematic_char/icon.png Binary files differnew file mode 100644 index 0000000000..bdca104c1f --- /dev/null +++ b/demos/2d/kinematic_char/icon.png diff --git a/demos/2d/kinematic_char/obstacle.png b/demos/2d/kinematic_char/obstacle.png Binary files differnew file mode 100644 index 0000000000..3ade3c3a52 --- /dev/null +++ b/demos/2d/kinematic_char/obstacle.png diff --git a/demos/2d/kinematic_char/player.gd b/demos/2d/kinematic_char/player.gd new file mode 100644 index 0000000000..b35bbfa693 --- /dev/null +++ b/demos/2d/kinematic_char/player.gd @@ -0,0 +1,116 @@ + +extends KinematicBody2D + +# This is a simple collision demo showing how +# the kinematic cotroller works. +# move() will allow to move the node, and will +# always move it to a non-colliding spot, +# as long as it starts from a non-colliding spot too. + + +#pixels / second +const GRAVITY = 500.0 + +# Angle in degrees towards either side that the player can +# consider "floor". +const FLOOR_ANGLE_TOLERANCE = 40 +const WALK_FORCE = 600 +const WALK_MAX_SPEED = 200 +const STOP_FORCE = 1300 +const JUMP_SPEED = 200 +const JUMP_MAX_AIRBORNE_TIME=0.2 + +var velocity = Vector2() +var on_air_time=100 +var jumping=false + +var prev_jump_pressed=false + +func _fixed_process(delta): + + #create forces + var force = Vector2(0,GRAVITY) + + var stop = velocity.x!=0.0 + + var walk_left = Input.is_action_pressed("move_left") + var walk_right = Input.is_action_pressed("move_right") + var jump = Input.is_action_pressed("jump") + + var stop=true + + if (walk_left): + if (velocity.x<=0 and velocity.x > -WALK_MAX_SPEED): + force.x-=WALK_FORCE + stop=false + + elif (walk_right): + if (velocity.x>=0 and velocity.x < WALK_MAX_SPEED): + force.x+=WALK_FORCE + stop=false + + if (stop): + var vsign = sign(velocity.x) + var vlen = abs(velocity.x) + + vlen -= STOP_FORCE * delta + if (vlen<0): + vlen=0 + + velocity.x=vlen*vsign + + + + #integrate forces to velocity + velocity += force * delta + + #integrate velocity into motion and move + var motion = velocity * delta + + #move and consume motion +# + motion = move(motion) + + + var floor_velocity=Vector2() + + if (is_colliding()): + #ran against something, is it the floor? get normal + var n = get_collision_normal() + + if ( rad2deg(acos(n.dot( Vector2(0,-1)))) < FLOOR_ANGLE_TOLERANCE ): + #if angle to the "up" vectors is < angle tolerance + #char is on floor + on_air_time=0 + floor_velocity=get_collider_velocity() + #velocity.y=0 + + # But we were moving and our motion was interrupted, + # so try to complete the motion by "sliding" + # by the normal + motion = n.slide(motion) + velocity = n.slide(velocity) + + #then move again + move(motion) + + if (floor_velocity!=Vector2()): + #if floor moves, move with floor + move(floor_velocity*delta) + + if (jumping and velocity.y>0): + jumping=false + + if (on_air_time<JUMP_MAX_AIRBORNE_TIME and jump and not prev_jump_pressed and not jumping): + velocity.y=-JUMP_SPEED + jumping=true + + on_air_time+=delta + prev_jump_pressed=jump + +func _ready(): + # Initalization here + set_fixed_process(true) + pass + + diff --git a/demos/2d/kinematic_char/player.png b/demos/2d/kinematic_char/player.png Binary files differnew file mode 100644 index 0000000000..0e7d843899 --- /dev/null +++ b/demos/2d/kinematic_char/player.png diff --git a/demos/2d/kinematic_char/player.scn b/demos/2d/kinematic_char/player.scn Binary files differnew file mode 100644 index 0000000000..126b332184 --- /dev/null +++ b/demos/2d/kinematic_char/player.scn diff --git a/demos/2d/kinematic_char/princess.png b/demos/2d/kinematic_char/princess.png Binary files differnew file mode 100644 index 0000000000..9605c9c831 --- /dev/null +++ b/demos/2d/kinematic_char/princess.png diff --git a/demos/2d/kinematic_col/colworld.scn b/demos/2d/kinematic_col/colworld.scn Binary files differnew file mode 100644 index 0000000000..064ff12075 --- /dev/null +++ b/demos/2d/kinematic_col/colworld.scn diff --git a/demos/2d/kinematic_col/engine.cfg b/demos/2d/kinematic_col/engine.cfg new file mode 100644 index 0000000000..654288a9bd --- /dev/null +++ b/demos/2d/kinematic_col/engine.cfg @@ -0,0 +1,12 @@ +[application] + +name="Kinematic Collision" +main_scene="res://colworld.scn" +icon="res://icon.png" + +[input] + +move_up=[key(Up)] +move_left=[key(Left)] +move_right=[key(Right)] +move_bottom=[key(Down)] diff --git a/demos/2d/kinematic_col/icon.png b/demos/2d/kinematic_col/icon.png Binary files differnew file mode 100644 index 0000000000..2774de6110 --- /dev/null +++ b/demos/2d/kinematic_col/icon.png diff --git a/demos/2d/kinematic_col/obstacle.png b/demos/2d/kinematic_col/obstacle.png Binary files differnew file mode 100644 index 0000000000..693f115a98 --- /dev/null +++ b/demos/2d/kinematic_col/obstacle.png diff --git a/demos/2d/kinematic_col/player.gd b/demos/2d/kinematic_col/player.gd new file mode 100644 index 0000000000..36784a9d9f --- /dev/null +++ b/demos/2d/kinematic_col/player.gd @@ -0,0 +1,36 @@ + +extends KinematicBody2D + +# This is a simple collision demo showing how +# the kinematic cotroller works. +# move() will allow to move the node, and will +# always move it to a non-colliding spot, +# as long as it starts from a non-colliding spot too. + + +#pixels / second +const MOTION_SPEED=160 + +func _fixed_process(delta): + + var motion = Vector2() + + if (Input.is_action_pressed("move_up")): + motion+=Vector2(0,-1) + if (Input.is_action_pressed("move_bottom")): + motion+=Vector2(0,1) + if (Input.is_action_pressed("move_left")): + motion+=Vector2(-1,0) + if (Input.is_action_pressed("move_right")): + motion+=Vector2(1,0) + + motion = motion.normalized() * MOTION_SPEED * delta + move(motion) + + +func _ready(): + # Initalization here + set_fixed_process(true) + pass + + diff --git a/demos/2d/kinematic_col/player.png b/demos/2d/kinematic_col/player.png Binary files differnew file mode 100644 index 0000000000..0e7d843899 --- /dev/null +++ b/demos/2d/kinematic_col/player.png diff --git a/demos/2d/kinematic_col/player.scn b/demos/2d/kinematic_col/player.scn Binary files differnew file mode 100644 index 0000000000..e558bffe8e --- /dev/null +++ b/demos/2d/kinematic_col/player.scn diff --git a/demos/2d/platformer/engine.cfg b/demos/2d/platformer/engine.cfg index 0ca951ed00..5fc2c3b2ba 100644 --- a/demos/2d/platformer/engine.cfg +++ b/demos/2d/platformer/engine.cfg @@ -26,3 +26,7 @@ default_gravity=700 [render] mipmap_policy=1 + +[texture_import] + +filter=false diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index d29ecd64bb..5be6045d50 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -303,6 +303,11 @@ void RasterizerGLES2::_draw_primitive(int p_points, const Vector3 *p_vertices, c #define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE #define _EXT_ETC1_RGB8_OES 0x8D64 +#define _EXT_ATC_RGB_AMD 0x8C92 +#define _EXT_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 +#define _EXT_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE + + /* TEXTURE API */ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,int &r_gl_components,bool &r_has_alpha_cache,bool &r_compressed) { @@ -394,6 +399,7 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For } break; case Image::FORMAT_BC5: { + r_gl_format=_EXT_COMPRESSED_RG_RGTC2; r_gl_components=1; //doesn't matter much r_compressed=true; @@ -492,6 +498,63 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For } } break; + case Image::FORMAT_ATC: { + + if (!atitc_supported) { + + if (!image.empty()) { + image.decompress(); + } + r_gl_components=3; + r_gl_format=GL_RGB; + + + } else { + + r_gl_format=_EXT_ATC_RGB_AMD; + r_gl_components=1; //doesn't matter much + r_compressed=true; + } + + } break; + case Image::FORMAT_ATC_ALPHA_EXPLICIT: { + + if (!atitc_supported) { + + if (!image.empty()) { + image.decompress(); + } + r_gl_components=4; + r_gl_format=GL_RGBA; + + + } else { + + r_gl_format=_EXT_ATC_RGBA_EXPLICIT_ALPHA_AMD; + r_gl_components=1; //doesn't matter much + r_compressed=true; + } + + } break; + case Image::FORMAT_ATC_ALPHA_INTERPOLATED: { + + if (!atitc_supported) { + + if (!image.empty()) { + image.decompress(); + } + r_gl_components=4; + r_gl_format=GL_RGBA; + + + } else { + + r_gl_format=_EXT_ATC_RGBA_INTERPOLATED_ALPHA_AMD; + r_gl_components=1; //doesn't matter much + r_compressed=true; + } + + } break; case Image::FORMAT_YUV_422: case Image::FORMAT_YUV_444: { @@ -557,7 +620,9 @@ void RasterizerGLES2::texture_allocate(RID p_texture,int p_width, int p_height,I texture->flags=p_flags; texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; - bool scale_textures = !(p_flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && (!npo2_textures_available || p_flags&VS::TEXTURE_FLAG_MIPMAPS); + _get_gl_image_and_format(Image(),texture->format,texture->flags,format,components,has_alpha_cache,compressed); + + bool scale_textures = !compressed && !(p_flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && (!npo2_textures_available || p_flags&VS::TEXTURE_FLAG_MIPMAPS); if (scale_textures) { @@ -570,7 +635,6 @@ void RasterizerGLES2::texture_allocate(RID p_texture,int p_width, int p_height,I texture->alloc_height = texture->height; }; - _get_gl_image_and_format(Image(),texture->format,texture->flags,format,components,has_alpha_cache,compressed); texture->gl_components_cache=components; texture->gl_format_cache=format; @@ -584,32 +648,7 @@ void RasterizerGLES2::texture_allocate(RID p_texture,int p_width, int p_height,I glBindTexture(texture->target, texture->tex_id); - if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS) - glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR); - else - glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - if (texture->flags&VS::TEXTURE_FLAG_FILTER) { - - glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering - - } else { - - glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // raw Filtering - } - - bool force_clamp_to_edge = !(p_flags&VS::TEXTURE_FLAG_MIPMAPS) && (nearest_power_of_2(texture->alloc_height)!=texture->alloc_height || nearest_power_of_2(texture->alloc_width)!=texture->alloc_width); - - if (!force_clamp_to_edge && texture->flags&VS::TEXTURE_FLAG_REPEAT && texture->target != GL_TEXTURE_CUBE_MAP) { - - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); - } else { - - //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); - glTexParameterf( texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameterf( texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } if (p_flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) { //prealloc if video @@ -652,6 +691,8 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu texture->has_alpha=true; } + + GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP)?_cube_side_enum[p_cube_side]:GL_TEXTURE_2D; texture->data_size=img.get_data().size(); @@ -660,6 +701,35 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex_id); + texture->ignore_mipmaps = compressed && img.get_mipmaps()==0; + + if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR); + else + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + if (texture->flags&VS::TEXTURE_FLAG_FILTER) { + + glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering + + } else { + + glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // raw Filtering + } + + bool force_clamp_to_edge = !(texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) && (nearest_power_of_2(texture->alloc_height)!=texture->alloc_height || nearest_power_of_2(texture->alloc_width)!=texture->alloc_width); + + if (!force_clamp_to_edge && texture->flags&VS::TEXTURE_FLAG_REPEAT && texture->target != GL_TEXTURE_CUBE_MAP) { + + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + } else { + + //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); + glTexParameterf( texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameterf( texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + } + int mipmaps= (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && img.get_mipmaps()>0) ? img.get_mipmaps() +1 : 1; @@ -699,7 +769,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu //printf("texture: %i x %i - size: %i - total: %i\n",texture->width,texture->height,tsize,_rinfo.texture_mem); - if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && mipmaps==1) { + if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && mipmaps==1 && !texture->ignore_mipmaps) { //generate mipmaps if they were requested and the image does not contain them glGenerateMipmap(texture->target); } @@ -889,7 +959,7 @@ void RasterizerGLES2::texture_set_flags(RID p_texture,uint32_t p_flags) { uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP; texture->flags=p_flags|cube; // can't remove a cube from being a cube - bool force_clamp_to_edge = !(p_flags&VS::TEXTURE_FLAG_MIPMAPS) && (nearest_power_of_2(texture->alloc_height)!=texture->alloc_height || nearest_power_of_2(texture->alloc_width)!=texture->alloc_width); + bool force_clamp_to_edge = !(p_flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) && (nearest_power_of_2(texture->alloc_height)!=texture->alloc_height || nearest_power_of_2(texture->alloc_width)!=texture->alloc_width); if (!force_clamp_to_edge && texture->flags&VS::TEXTURE_FLAG_REPEAT && texture->target != GL_TEXTURE_CUBE_MAP) { @@ -903,17 +973,18 @@ void RasterizerGLES2::texture_set_flags(RID p_texture,uint32_t p_flags) { } + if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR); + else + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + if (texture->flags&VS::TEXTURE_FLAG_FILTER) { glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering - if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS) - glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR); - else - glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering } else { - glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // nearest + glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // raw Filtering } } uint32_t RasterizerGLES2::texture_get_flags(RID p_texture) const { @@ -7493,6 +7564,7 @@ void RasterizerGLES2::init() { etc_supported=false; use_depth24 =true; s3tc_supported = true; + atitc_supported = false; use_hw_skeleton_xform = false; // use_texture_instancing=false; // use_attribute_instancing=true; @@ -7506,6 +7578,10 @@ void RasterizerGLES2::init() { use_half_float=true; #else + + for (Set<String>::Element *E=extensions.front();E;E=E->next()) { + print_line(E->get()); + } read_depth_supported=extensions.has("GL_OES_depth_texture"); use_rgba_shadowmaps=!read_depth_supported; pvr_supported=extensions.has("GL_IMG_texture_compression_pvrtc"); @@ -7513,7 +7589,9 @@ void RasterizerGLES2::init() { use_depth24 = extensions.has("GL_OES_depth24"); s3tc_supported = extensions.has("GL_EXT_texture_compression_dxt1") || extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc"); use_half_float = extensions.has("GL_OES_vertex_half_float"); + atitc_supported=extensions.has("GL_AMD_compressed_ATC_texture"); + print_line("S3TC: "+itos(s3tc_supported)+" ATITC: "+itos(atitc_supported)); GLint vtf; glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,&vtf); @@ -7885,6 +7963,7 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo use_fast_texture_filter=GLOBAL_DEF("rasterizer/trilinear_mipmap_filter",true); skel_default.resize(1024*4); for(int i=0;i<1024/3;i++) { + float * ptr = skel_default.ptr(); ptr+=i*4*4; ptr[0]=1.0; @@ -7901,7 +7980,6 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo ptr[9]=0.0; ptr[10]=1.0; ptr[12]=0.0; - } base_framebuffer=0; diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index bab560dddb..52c4c8d681 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -75,6 +75,7 @@ class RasterizerGLES2 : public Rasterizer { bool pvr_supported; bool s3tc_supported; bool etc_supported; + bool atitc_supported; bool npo2_textures_available; bool read_depth_supported; bool use_framebuffers; @@ -111,6 +112,7 @@ class RasterizerGLES2 : public Rasterizer { bool compressed; bool disallow_mipmaps; int total_data_size; + bool ignore_mipmaps; ObjectID reloader; StringName reloader_func; @@ -123,6 +125,7 @@ class RasterizerGLES2 : public Rasterizer { Texture() { + ignore_mipmaps=false; render_target=NULL; flags=width=height=0; tex_id=0; diff --git a/main/main.cpp b/main/main.cpp index 305cc88be7..7d19c2ebcf 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -33,7 +33,6 @@ #include "core/register_core_types.h" #include "scene/register_scene_types.h" #include "drivers/register_driver_types.h" -#include "script/register_script_types.h" #include "servers/register_server_types.h" #include "modules/register_module_types.h" #include "script_debugger_local.h" @@ -766,7 +765,6 @@ Error Main::setup2() { MAIN_PRINT("Main: Load Scripts, Modules, Drivers"); register_module_types(); - register_script_types(); register_driver_types(); MAIN_PRINT("Main: Load Translations"); @@ -1367,11 +1365,14 @@ void Main::cleanup() { OS::get_singleton()->_execpath=""; OS::get_singleton()->_local_clipboard=""; +#ifdef TOOLS_ENABLED + EditorNode::unregister_editor_types(); +#endif + unregister_driver_types(); unregister_module_types(); unregister_scene_types(); unregister_server_types(); - unregister_script_types(); OS::get_singleton()->finalize(); diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub new file mode 100644 index 0000000000..d20da72b72 --- /dev/null +++ b/modules/gdscript/SCsub @@ -0,0 +1,7 @@ +Import('env') + +env.add_source_files(env.modules_sources,"*.cpp") + +Export('env') + + diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py new file mode 100644 index 0000000000..f9bd7da08d --- /dev/null +++ b/modules/gdscript/config.py @@ -0,0 +1,11 @@ + + +def can_build(platform): + return True + + +def configure(env): + pass + + + diff --git a/script/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index dd2834bf34..dd2834bf34 100644 --- a/script/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp diff --git a/script/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h index cda221dab0..cda221dab0 100644 --- a/script/gdscript/gd_compiler.h +++ b/modules/gdscript/gd_compiler.h diff --git a/script/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 4bb5d3206c..f8717c292f 100644 --- a/script/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -106,7 +106,7 @@ bool GDScriptLanguage::has_named_classes() const { int GDScriptLanguage::find_function(const String& p_function,const String& p_code) const { - GDTokenizer tokenizer; + GDTokenizerText tokenizer; tokenizer.set_code(p_code); int indent=0; while(tokenizer.get_token()!=GDTokenizer::TK_EOF && tokenizer.get_token()!=GDTokenizer::TK_ERROR) { @@ -282,6 +282,14 @@ void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const } } +void GDScriptLanguage::get_public_constants(List<Pair<String,Variant> > *p_constants) const { + + Pair<String,Variant> pi; + pi.first="PI"; + pi.second=Math_PI; + p_constants->push_back(pi); +} + String GDScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const { String s="func "+p_name+"("; diff --git a/script/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index 2930d9322c..2930d9322c 100644 --- a/script/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp diff --git a/script/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h index 2ab397d18a..2ab397d18a 100644 --- a/script/gdscript/gd_functions.h +++ b/modules/gdscript/gd_functions.h diff --git a/script/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index e558ceb416..fb4f56aa8f 100644 --- a/script/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -54,18 +54,18 @@ T* GDParser::alloc_node() { if (!head) head=t; - t->line=tokenizer.get_token_line(); - t->column=tokenizer.get_token_column(); + t->line=tokenizer->get_token_line(); + t->column=tokenizer->get_token_column(); return t; } bool GDParser::_end_statement() { - if (tokenizer.get_token()==GDTokenizer::TK_SEMICOLON) { - tokenizer.advance(); + if (tokenizer->get_token()==GDTokenizer::TK_SEMICOLON) { + tokenizer->advance(); return true; //handle next - } else if (tokenizer.get_token()==GDTokenizer::TK_NEWLINE || tokenizer.get_token()==GDTokenizer::TK_EOF) { + } else if (tokenizer->get_token()==GDTokenizer::TK_NEWLINE || tokenizer->get_token()==GDTokenizer::TK_EOF) { return true; //will be handled properly } @@ -75,14 +75,14 @@ bool GDParser::_end_statement() { bool GDParser::_enter_indent_block(BlockNode* p_block) { - if (tokenizer.get_token()!=GDTokenizer::TK_COLON) { + if (tokenizer->get_token()!=GDTokenizer::TK_COLON) { _set_error("':' expected at end of line."); return false; } - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_NEWLINE) { + if (tokenizer->get_token()!=GDTokenizer::TK_NEWLINE) { _set_error("newline expected after ':'."); return false; @@ -90,35 +90,35 @@ bool GDParser::_enter_indent_block(BlockNode* p_block) { while(true) { - if (tokenizer.get_token()!=GDTokenizer::TK_NEWLINE) { + if (tokenizer->get_token()!=GDTokenizer::TK_NEWLINE) { return false; //wtf - } else if (tokenizer.get_token(1)!=GDTokenizer::TK_NEWLINE) { + } else if (tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE) { - int indent = tokenizer.get_token_line_indent(); + int indent = tokenizer->get_token_line_indent(); int current = tab_level.back()->get(); if (indent<=current) return false; tab_level.push_back(indent); - tokenizer.advance(); + tokenizer->advance(); return true; } else if (p_block) { NewLineNode *nl = alloc_node<NewLineNode>(); - nl->line=tokenizer.get_token_line(); + nl->line=tokenizer->get_token_line(); p_block->statements.push_back(nl); } - tokenizer.advance(); // go to next newline + tokenizer->advance(); // go to next newline } } bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static) { - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { - tokenizer.advance(); + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { + tokenizer->advance(); } else { while(true) { @@ -130,19 +130,19 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat p_args.push_back(arg); - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { - tokenizer.advance(); + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { + tokenizer->advance(); break; - } else if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { + } else if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { - if (tokenizer.get_token(1)==GDTokenizer::TK_PARENTHESIS_CLOSE) { + if (tokenizer->get_token(1)==GDTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expression expected"); return false; } - tokenizer.advance(); + tokenizer->advance(); } else { // something is broken _set_error("Expected ',' or ')'"); @@ -174,45 +174,45 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ /* Parse Operand */ /*****************/ - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { //subexpression () - tokenizer.advance(); + tokenizer->advance(); Node* subexpr = _parse_expression(p_parent,p_static); if (!subexpr) return NULL; - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected ')' in expression"); return NULL; } - tokenizer.advance(); + tokenizer->advance(); expr=subexpr; - } else if (tokenizer.get_token()==GDTokenizer::TK_CONSTANT) { + } else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT) { //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); - constant->value=tokenizer.get_token_constant(); - tokenizer.advance(); + constant->value=tokenizer->get_token_constant(); + tokenizer->advance(); expr=constant; - } else if (tokenizer.get_token()==GDTokenizer::TK_PR_PRELOAD) { + } else if (tokenizer->get_token()==GDTokenizer::TK_PR_PRELOAD) { //constant defined by tokenizer - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { _set_error("Expected '(' after 'preload'"); return NULL; } - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || tokenizer.get_token_constant().get_type()!=Variant::STRING) { + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type()!=Variant::STRING) { _set_error("Expected string constant as 'preload' argument."); return NULL; } - String path = tokenizer.get_token_constant(); + String path = tokenizer->get_token_constant(); if (!path.is_abs_path() && base_path!="") path=base_path+"/"+path; @@ -222,20 +222,20 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ return NULL; } - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected ')' after 'preload' path"); return NULL; } ConstantNode *constant = alloc_node<ConstantNode>(); constant->value=res; - tokenizer.advance(); + tokenizer->advance(); expr=constant; - } else if (tokenizer.get_token()==GDTokenizer::TK_SELF) { + } else if (tokenizer->get_token()==GDTokenizer::TK_SELF) { if (p_static) { _set_error("'self'' not allowed in static function or constant expression"); @@ -243,18 +243,18 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ } //constant defined by tokenizer SelfNode *self = alloc_node<SelfNode>(); - tokenizer.advance(); + tokenizer->advance(); expr=self; - } else if (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_TYPE && tokenizer.get_token(1)==GDTokenizer::TK_PERIOD) { + } else if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE && tokenizer->get_token(1)==GDTokenizer::TK_PERIOD) { - Variant::Type bi_type = tokenizer.get_token_type(); - tokenizer.advance(2); - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { + Variant::Type bi_type = tokenizer->get_token_type(); + tokenizer->advance(2); + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { _set_error("Built-in type constant expected after '.'"); return NULL; } - StringName identifier = tokenizer.get_token_identifier(); + StringName identifier = tokenizer->get_token_identifier(); if (!Variant::has_numeric_constant(bi_type,identifier)) { _set_error("Static constant '"+identifier.operator String()+"' not present in built-in type "+Variant::get_type_name(bi_type)+"."); @@ -264,23 +264,23 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ ConstantNode *cn = alloc_node<ConstantNode>(); cn->value=Variant::get_numeric_constant_value(bi_type,identifier); expr=cn; - tokenizer.advance(); + tokenizer->advance(); - } else if (tokenizer.get_token(1)==GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_TYPE || tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER || tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_FUNC)) { + } else if (tokenizer->get_token(1)==GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE || tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER || tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC)) { //function or constructor OperatorNode *op = alloc_node<OperatorNode>(); op->op=OperatorNode::OP_CALL; - if (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_TYPE) { + if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE) { TypeNode *tn = alloc_node<TypeNode>(); - tn->vtype=tokenizer.get_token_type(); + tn->vtype=tokenizer->get_token_type(); op->arguments.push_back(tn); - } else if (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_FUNC) { + } else if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC) { BuiltInFunctionNode *bn = alloc_node<BuiltInFunctionNode>(); - bn->function=tokenizer.get_token_built_in_func(); + bn->function=tokenizer->get_token_built_in_func(); op->arguments.push_back(bn); } else { @@ -288,25 +288,25 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ op->arguments.push_back(self); IdentifierNode* id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(); + id->name=tokenizer->get_token_identifier(); op->arguments.push_back(id); } - tokenizer.advance(2); + tokenizer->advance(2); if (!_parse_arguments(op,op->arguments,p_static)) return NULL; expr=op; - } else if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER) { + } else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) { //identifier (reference) IdentifierNode *id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(); - tokenizer.advance(); + id->name=tokenizer->get_token_identifier(); + tokenizer->advance(); expr=id; - } else if (/*tokenizer.get_token()==GDTokenizer::TK_OP_ADD ||*/ tokenizer.get_token()==GDTokenizer::TK_OP_SUB || tokenizer.get_token()==GDTokenizer::TK_OP_NOT || tokenizer.get_token()==GDTokenizer::TK_OP_BIT_INVERT) { + } else if (/*tokenizer->get_token()==GDTokenizer::TK_OP_ADD ||*/ tokenizer->get_token()==GDTokenizer::TK_OP_SUB || tokenizer->get_token()==GDTokenizer::TK_OP_NOT || tokenizer->get_token()==GDTokenizer::TK_OP_BIT_INVERT) { //single prefix operators like !expr -expr ++expr --expr OperatorNode *op = alloc_node<OperatorNode>(); @@ -314,7 +314,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ Expression e; e.is_op=true; - switch(tokenizer.get_token()) { + switch(tokenizer->get_token()) { case GDTokenizer::TK_OP_SUB: e.op=OperatorNode::OP_NEG; break; case GDTokenizer::TK_OP_NOT: e.op=OperatorNode::OP_NOT; break; case GDTokenizer::TK_OP_BIT_INVERT: e.op=OperatorNode::OP_BIT_INVERT;; break; @@ -322,9 +322,9 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ } - tokenizer.advance(); + tokenizer->advance(); - if (e.op!=OperatorNode::OP_NOT && tokenizer.get_token()==GDTokenizer::TK_OP_NOT) { + if (e.op!=OperatorNode::OP_NOT && tokenizer->get_token()==GDTokenizer::TK_OP_NOT) { _set_error("Misplaced 'not'."); return NULL; } @@ -339,34 +339,34 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ op->arguments.push_back(subexpr); expr=op;*/ - } else if (tokenizer.get_token()==GDTokenizer::TK_BRACKET_OPEN) { + } else if (tokenizer->get_token()==GDTokenizer::TK_BRACKET_OPEN) { // array - tokenizer.advance(); + tokenizer->advance(); ArrayNode *arr = alloc_node<ArrayNode>(); bool expecting_comma=false; while(true) { - if (tokenizer.get_token()==GDTokenizer::TK_EOF) { + if (tokenizer->get_token()==GDTokenizer::TK_EOF) { _set_error("Unterminated array"); return NULL; - } else if (tokenizer.get_token()==GDTokenizer::TK_BRACKET_CLOSE) { - tokenizer.advance(); + } else if (tokenizer->get_token()==GDTokenizer::TK_BRACKET_CLOSE) { + tokenizer->advance(); break; - } else if (tokenizer.get_token()==GDTokenizer::TK_NEWLINE) { + } else if (tokenizer->get_token()==GDTokenizer::TK_NEWLINE) { - tokenizer.advance(); //ignore newline - } else if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); //ignore newline + } else if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { if (!expecting_comma) { _set_error("expression or ']' expected"); return NULL; } expecting_comma=false; - tokenizer.advance(); //ignore newline + tokenizer->advance(); //ignore newline } else { //parse expression if (expecting_comma) { @@ -382,9 +382,9 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ } expr=arr; - } else if (tokenizer.get_token()==GDTokenizer::TK_CURLY_BRACKET_OPEN) { + } else if (tokenizer->get_token()==GDTokenizer::TK_CURLY_BRACKET_OPEN) { // array - tokenizer.advance(); + tokenizer->advance(); DictionaryNode *dict = alloc_node<DictionaryNode>(); @@ -403,12 +403,12 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ while(true) { - if (tokenizer.get_token()==GDTokenizer::TK_EOF) { + if (tokenizer->get_token()==GDTokenizer::TK_EOF) { _set_error("Unterminated dictionary"); return NULL; - } else if (tokenizer.get_token()==GDTokenizer::TK_CURLY_BRACKET_CLOSE) { + } else if (tokenizer->get_token()==GDTokenizer::TK_CURLY_BRACKET_CLOSE) { if (expecting==DICT_EXPECT_COLON) { _set_error("':' expected"); @@ -418,12 +418,12 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ _set_error("value expected"); return NULL; } - tokenizer.advance(); + tokenizer->advance(); break; - } else if (tokenizer.get_token()==GDTokenizer::TK_NEWLINE) { + } else if (tokenizer->get_token()==GDTokenizer::TK_NEWLINE) { - tokenizer.advance(); //ignore newline - } else if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); //ignore newline + } else if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { if (expecting==DICT_EXPECT_KEY) { _set_error("key or '}' expected"); @@ -439,9 +439,9 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ } expecting=DICT_EXPECT_KEY; - tokenizer.advance(); //ignore newline + tokenizer->advance(); //ignore newline - } else if (tokenizer.get_token()==GDTokenizer::TK_COLON) { + } else if (tokenizer->get_token()==GDTokenizer::TK_COLON) { if (expecting==DICT_EXPECT_KEY) { _set_error("key or '}' expected"); @@ -457,7 +457,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ } expecting=DICT_EXPECT_VALUE; - tokenizer.advance(); //ignore newline + tokenizer->advance(); //ignore newline } else { if (expecting==DICT_EXPECT_COMMA) { @@ -471,12 +471,12 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ if (expecting==DICT_EXPECT_KEY) { - if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer.get_token(1)==GDTokenizer::TK_OP_ASSIGN) { + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)==GDTokenizer::TK_OP_ASSIGN) { //lua style identifier, easier to write ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value = tokenizer.get_token_identifier(); + cn->value = tokenizer->get_token_identifier(); key = cn; - tokenizer.advance(2); + tokenizer->advance(2); expecting=DICT_EXPECT_VALUE; } else { //python/js style more flexible @@ -506,10 +506,10 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ expr=dict; - } else if (tokenizer.get_token()==GDTokenizer::TK_PERIOD && tokenizer.get_token(1)==GDTokenizer::TK_IDENTIFIER && tokenizer.get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) { + } else if (tokenizer->get_token()==GDTokenizer::TK_PERIOD && tokenizer->get_token(1)==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) { // parent call - tokenizer.advance(); //goto identifier + tokenizer->advance(); //goto identifier OperatorNode *op = alloc_node<OperatorNode>(); op->op=OperatorNode::OP_PARENT_CALL; @@ -519,10 +519,10 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ forbidden for now */ IdentifierNode* id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(); + id->name=tokenizer->get_token_identifier(); op->arguments.push_back(id); - tokenizer.advance(2); + tokenizer->advance(2); if (!_parse_arguments(op,op->arguments,p_static)) return NULL; @@ -534,7 +534,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ print_line("found bug?"); - _set_error("Error parsing expression, misplaced: "+String(tokenizer.get_token_name(tokenizer.get_token()))); + _set_error("Error parsing expression, misplaced: "+String(tokenizer->get_token_name(tokenizer->get_token()))); return NULL; //nothing } @@ -553,31 +553,31 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ //expressions can be indexed any number of times - if (tokenizer.get_token()==GDTokenizer::TK_PERIOD) { + if (tokenizer->get_token()==GDTokenizer::TK_PERIOD) { //indexing using "." - if (tokenizer.get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer.get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) { + if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) { _set_error("Expected identifier as member"); return NULL; - } else if (tokenizer.get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) { + } else if (tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) { //call!! OperatorNode * op = alloc_node<OperatorNode>(); op->op=OperatorNode::OP_CALL; IdentifierNode * id = alloc_node<IdentifierNode>(); - if (tokenizer.get_token(1)==GDTokenizer::TK_BUILT_IN_FUNC ) { + if (tokenizer->get_token(1)==GDTokenizer::TK_BUILT_IN_FUNC ) { //small hack so built in funcs don't obfuscate methods - id->name=GDFunctions::get_func_name(tokenizer.get_token_built_in_func(1)); + id->name=GDFunctions::get_func_name(tokenizer->get_token_built_in_func(1)); } else { - id->name=tokenizer.get_token_identifier(1); + id->name=tokenizer->get_token_identifier(1); } op->arguments.push_back(expr); // call what op->arguments.push_back(id); // call func //get arguments - tokenizer.advance(3); + tokenizer->advance(3); if (!_parse_arguments(op,op->arguments,p_static)) return NULL; expr=op; @@ -588,36 +588,36 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ op->op=OperatorNode::OP_INDEX_NAMED; IdentifierNode * id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(1); + id->name=tokenizer->get_token_identifier(1); op->arguments.push_back(expr); op->arguments.push_back(id); expr=op; - tokenizer.advance(2); + tokenizer->advance(2); } - } else if (tokenizer.get_token()==GDTokenizer::TK_BRACKET_OPEN) { + } else if (tokenizer->get_token()==GDTokenizer::TK_BRACKET_OPEN) { //indexing using "[]" OperatorNode * op = alloc_node<OperatorNode>(); op->op=OperatorNode::OP_INDEX; - tokenizer.advance(1); + tokenizer->advance(1); Node *subexpr = _parse_expression(op,p_static); if (!subexpr) { return NULL; } - if (tokenizer.get_token()!=GDTokenizer::TK_BRACKET_CLOSE) { + if (tokenizer->get_token()!=GDTokenizer::TK_BRACKET_CLOSE) { _set_error("Expected ']'"); return NULL; } op->arguments.push_back(expr); op->arguments.push_back(subexpr); - tokenizer.advance(1); + tokenizer->advance(1); expr=op; } else @@ -641,7 +641,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ //assign, if allowed is only alowed on the first operator #define _VALIDATE_ASSIGN if (!p_allow_assign) { _set_error("Unexpected assign."); return NULL; } p_allow_assign=false; - switch(tokenizer.get_token()) { //see operator + switch(tokenizer->get_token()) { //see operator case GDTokenizer::TK_OP_IN: op=OperatorNode::OP_IN; break; case GDTokenizer::TK_OP_EQUAL: op=OperatorNode::OP_EQUAL ; break; @@ -682,7 +682,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ e.is_op=true; e.op=op; expression.push_back(e); - tokenizer.advance(); + tokenizer->advance(); } else { break; } @@ -1190,18 +1190,18 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { NewLineNode *nl = alloc_node<NewLineNode>(); - nl->line=tokenizer.get_token_line(); + nl->line=tokenizer->get_token_line(); p_block->statements.push_back(nl); #endif while(true) { - GDTokenizer::Token token = tokenizer.get_token(); + GDTokenizer::Token token = tokenizer->get_token(); if (error_set) return; if (indent_level>tab_level.back()->get()) { - p_block->end_line=tokenizer.get_token_line(); + p_block->end_line=tokenizer->get_token_line(); return; //go back a level } @@ -1209,7 +1209,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { case GDTokenizer::TK_EOF: - p_block->end_line=tokenizer.get_token_line(); + p_block->end_line=tokenizer->get_token_line(); case GDTokenizer::TK_ERROR: { return; //go back @@ -1219,38 +1219,38 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { case GDTokenizer::TK_NEWLINE: { NewLineNode *nl = alloc_node<NewLineNode>(); - nl->line=tokenizer.get_token_line(); + nl->line=tokenizer->get_token_line(); p_block->statements.push_back(nl); if (!_parse_newline()) { if (!error_set) { - p_block->end_line=tokenizer.get_token_line(); + p_block->end_line=tokenizer->get_token_line(); } return; } } break; case GDTokenizer::TK_CF_PASS: { - if (tokenizer.get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer.get_token(1)!=GDTokenizer::TK_NEWLINE ) { + if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE ) { _set_error("Expected ';' or <NewLine>."); return; } - tokenizer.advance(); + tokenizer->advance(); } break; case GDTokenizer::TK_PR_VAR: { //variale declaration and (eventual) initialization - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { _set_error("Expected identifier for local variable name."); return; } - StringName n = tokenizer.get_token_identifier(); - tokenizer.advance(); + StringName n = tokenizer->get_token_identifier(); + tokenizer->advance(); p_block->variables.push_back(n); //line? - p_block->variable_lines.push_back(tokenizer.get_token_line()); + p_block->variable_lines.push_back(tokenizer->get_token_line()); //must know when the local variable is declared @@ -1260,9 +1260,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { Node *assigned=NULL; - if (tokenizer.get_token()==GDTokenizer::TK_OP_ASSIGN) { + if (tokenizer->get_token()==GDTokenizer::TK_OP_ASSIGN) { - tokenizer.advance(); + tokenizer->advance(); Node *subexpr=NULL; subexpr = _parse_and_reduce_expression(p_block,p_static); @@ -1294,7 +1294,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; case GDTokenizer::TK_CF_IF: { - tokenizer.advance(); + tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block,p_static); if (!condition) return; @@ -1308,7 +1308,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { p_block->sub_blocks.push_back(cf_if->body); if (!_enter_indent_block(cf_if->body)) { - p_block->end_line=tokenizer.get_token_line(); + p_block->end_line=tokenizer->get_token_line(); return; } @@ -1319,16 +1319,16 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { while(true) { - while(tokenizer.get_token()==GDTokenizer::TK_NEWLINE) { - tokenizer.advance(); + while(tokenizer->get_token()==GDTokenizer::TK_NEWLINE) { + tokenizer->advance(); } if (tab_level.back()->get() < indent_level) { //not at current indent level - p_block->end_line=tokenizer.get_token_line(); + p_block->end_line=tokenizer->get_token_line(); return; } - if (tokenizer.get_token()==GDTokenizer::TK_CF_ELIF) { + if (tokenizer->get_token()==GDTokenizer::TK_CF_ELIF) { if (tab_level.back()->get() > indent_level) { @@ -1336,7 +1336,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { return; } - tokenizer.advance(); + tokenizer->advance(); cf_if->body_else=alloc_node<BlockNode>(); p_block->sub_blocks.push_back(cf_if->body_else); @@ -1358,7 +1358,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { if (!_enter_indent_block(cf_if->body)) { - p_block->end_line=tokenizer.get_token_line(); + p_block->end_line=tokenizer->get_token_line(); return; } @@ -1367,7 +1367,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { return; - } else if (tokenizer.get_token()==GDTokenizer::TK_CF_ELSE) { + } else if (tokenizer->get_token()==GDTokenizer::TK_CF_ELSE) { if (tab_level.back()->get() > indent_level) { @@ -1376,12 +1376,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } - tokenizer.advance(); + tokenizer->advance(); cf_if->body_else=alloc_node<BlockNode>(); p_block->sub_blocks.push_back(cf_if->body_else); if (!_enter_indent_block(cf_if->body_else)) { - p_block->end_line=tokenizer.get_token_line(); + p_block->end_line=tokenizer->get_token_line(); return; } _parse_block(cf_if->body_else,p_static); @@ -1400,7 +1400,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; case GDTokenizer::TK_CF_WHILE: { - tokenizer.advance(); + tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block,p_static); if (!condition) return; @@ -1414,7 +1414,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { p_block->sub_blocks.push_back(cf_while->body); if (!_enter_indent_block(cf_while->body)) { - p_block->end_line=tokenizer.get_token_line(); + p_block->end_line=tokenizer->get_token_line(); return; } @@ -1425,24 +1425,24 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; case GDTokenizer::TK_CF_FOR: { - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { _set_error("identifier expected after 'for'"); } IdentifierNode *id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(); + id->name=tokenizer->get_token_identifier(); - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_OP_IN) { + if (tokenizer->get_token()!=GDTokenizer::TK_OP_IN) { _set_error("'in' expected after identifier"); return; } - tokenizer.advance(); + tokenizer->advance(); Node *container = _parse_and_reduce_expression(p_block,p_static); if (!container) @@ -1458,7 +1458,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { p_block->sub_blocks.push_back(cf_for->body); if (!_enter_indent_block(cf_for->body)) { - p_block->end_line=tokenizer.get_token_line(); + p_block->end_line=tokenizer->get_token_line(); return; } @@ -1469,7 +1469,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; case GDTokenizer::TK_CF_CONTINUE: { - tokenizer.advance(); + tokenizer->advance(); ControlFlowNode *cf_continue = alloc_node<ControlFlowNode>(); cf_continue->cf_type=ControlFlowNode::CF_CONTINUE; p_block->statements.push_back(cf_continue); @@ -1480,7 +1480,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; case GDTokenizer::TK_CF_BREAK: { - tokenizer.advance(); + tokenizer->advance(); ControlFlowNode *cf_break = alloc_node<ControlFlowNode>(); cf_break->cf_type=ControlFlowNode::CF_BREAK; p_block->statements.push_back(cf_break); @@ -1491,13 +1491,13 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; case GDTokenizer::TK_CF_RETURN: { - tokenizer.advance(); + tokenizer->advance(); ControlFlowNode *cf_return = alloc_node<ControlFlowNode>(); cf_return->cf_type=ControlFlowNode::CF_RETURN; - if (tokenizer.get_token()==GDTokenizer::TK_SEMICOLON || tokenizer.get_token()==GDTokenizer::TK_NEWLINE || tokenizer.get_token()==GDTokenizer::TK_EOF) { + if (tokenizer->get_token()==GDTokenizer::TK_SEMICOLON || tokenizer->get_token()==GDTokenizer::TK_NEWLINE || tokenizer->get_token()==GDTokenizer::TK_EOF) { //expect end of statement p_block->statements.push_back(cf_return); if (!_end_statement()) { @@ -1520,7 +1520,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; case GDTokenizer::TK_PR_ASSERT: { - tokenizer.advance(); + tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block,p_static); if (!condition) return; @@ -1548,11 +1548,11 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { /* case GDTokenizer::TK_CF_LOCAL: { - if (tokenizer.get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer.get_token(1)!=GDTokenizer::TK_NEWLINE ) { + if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE ) { _set_error("Expected ';' or <NewLine>."); } - tokenizer.advance(); + tokenizer->advance(); } break; */ @@ -1563,9 +1563,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { bool GDParser::_parse_newline() { - if (tokenizer.get_token(1)!=GDTokenizer::TK_EOF && tokenizer.get_token(1)!=GDTokenizer::TK_NEWLINE) { + if (tokenizer->get_token(1)!=GDTokenizer::TK_EOF && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE) { - int indent = tokenizer.get_token_line_indent(); + int indent = tokenizer->get_token_line_indent(); int current_indent = tab_level.back()->get(); if (indent>current_indent) { @@ -1593,12 +1593,12 @@ bool GDParser::_parse_newline() { current_indent = tab_level.back()->get(); } - tokenizer.advance(); + tokenizer->advance(); return false; } } - tokenizer.advance(); + tokenizer->advance(); return true; } @@ -1622,11 +1622,11 @@ void GDParser::_parse_extends(ClassNode *p_class) { p_class->extends_used=true; //see if inheritance happens from a file - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()==GDTokenizer::TK_CONSTANT) { + if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT) { - Variant constant = tokenizer.get_token_constant(); + Variant constant = tokenizer->get_token_constant(); if (constant.get_type()!=Variant::STRING) { _set_error("'extends' constant must be a string."); @@ -1634,27 +1634,27 @@ void GDParser::_parse_extends(ClassNode *p_class) { } p_class->extends_file=constant; - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PERIOD) { + if (tokenizer->get_token()!=GDTokenizer::TK_PERIOD) { return; } else - tokenizer.advance(); + tokenizer->advance(); } while(true) { - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { _set_error("Invalid 'extends' syntax, expected string constant (path) and/or identifier (parent class)."); return; } - StringName identifier=tokenizer.get_token_identifier(); + StringName identifier=tokenizer->get_token_identifier(); p_class->extends_class.push_back(identifier); - tokenizer.advance(1); - if (tokenizer.get_token()!=GDTokenizer::TK_PERIOD) + tokenizer->advance(1); + if (tokenizer->get_token()!=GDTokenizer::TK_PERIOD) return; } @@ -1666,19 +1666,19 @@ void GDParser::_parse_class(ClassNode *p_class) { while(true) { - GDTokenizer::Token token = tokenizer.get_token(); + GDTokenizer::Token token = tokenizer->get_token(); if (error_set) return; if (indent_level>tab_level.back()->get()) { - p_class->end_line=tokenizer.get_token_line(); + p_class->end_line=tokenizer->get_token_line(); return; //go back a level } switch(token) { case GDTokenizer::TK_EOF: - p_class->end_line=tokenizer.get_token_line(); + p_class->end_line=tokenizer->get_token_line(); case GDTokenizer::TK_ERROR: { return; //go back //end of file! @@ -1686,7 +1686,7 @@ void GDParser::_parse_class(ClassNode *p_class) { case GDTokenizer::TK_NEWLINE: { if (!_parse_newline()) { if (!error_set) { - p_class->end_line=tokenizer.get_token_line(); + p_class->end_line=tokenizer->get_token_line(); } return; } @@ -1709,7 +1709,7 @@ void GDParser::_parse_class(ClassNode *p_class) { } p_class->tool=true; - tokenizer.advance(); + tokenizer->advance(); } break; case GDTokenizer::TK_PR_CLASS: { @@ -1718,13 +1718,13 @@ void GDParser::_parse_class(ClassNode *p_class) { StringName name; StringName extends; - if (tokenizer.get_token(1)!=GDTokenizer::TK_IDENTIFIER) { + if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER) { _set_error("'class' syntax: 'class <Name>:' or 'class <Name> extends <BaseClass>:'"); return; } - name = tokenizer.get_token_identifier(1); - tokenizer.advance(2); + name = tokenizer->get_token_identifier(1); + tokenizer->advance(2); ClassNode *newclass = alloc_node<ClassNode>(); newclass->initializer = alloc_node<BlockNode>(); @@ -1733,7 +1733,7 @@ void GDParser::_parse_class(ClassNode *p_class) { p_class->subclasses.push_back(newclass); - if (tokenizer.get_token()==GDTokenizer::TK_PR_EXTENDS) { + if (tokenizer->get_token()==GDTokenizer::TK_PR_EXTENDS) { _parse_extends(newclass); if (error_set) @@ -1751,12 +1751,12 @@ void GDParser::_parse_class(ClassNode *p_class) { /* this is for functions.... case GDTokenizer::TK_CF_PASS: { - tokenizer.advance(1); + tokenizer->advance(1); } break; */ case GDTokenizer::TK_PR_STATIC: { - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PR_FUNCTION) { + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PR_FUNCTION) { _set_error("Expected 'func'."); return; @@ -1767,19 +1767,19 @@ void GDParser::_parse_class(ClassNode *p_class) { bool _static=false; - if (tokenizer.get_token(-1)==GDTokenizer::TK_PR_STATIC) { + if (tokenizer->get_token(-1)==GDTokenizer::TK_PR_STATIC) { _static=true; } - if (tokenizer.get_token(1)!=GDTokenizer::TK_IDENTIFIER) { + if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER) { _set_error("Expected identifier after 'func' (syntax: 'func <identifier>([arguments]):' )."); return; } - StringName name = tokenizer.get_token_identifier(1); + StringName name = tokenizer->get_token_identifier(1); for(int i=0;i<p_class->functions.size();i++) { if (p_class->functions[i]->name==name) { @@ -1791,56 +1791,56 @@ void GDParser::_parse_class(ClassNode *p_class) { _set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->static_functions[i]->line)+")."); } } - tokenizer.advance(2); + tokenizer->advance(2); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { _set_error("Expected '(' after identifier (syntax: 'func <identifier>([arguments]):' )."); return; } - tokenizer.advance(); + tokenizer->advance(); Vector<StringName> arguments; Vector<Node*> default_values; - int fnline = tokenizer.get_token_line(); + int fnline = tokenizer->get_token_line(); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { //has arguments bool defaulting=false; while(true) { - if (tokenizer.get_token()==GDTokenizer::TK_PR_VAR) { + if (tokenizer->get_token()==GDTokenizer::TK_PR_VAR) { - tokenizer.advance(); //var before the identifier is allowed + tokenizer->advance(); //var before the identifier is allowed } - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { _set_error("Expected identifier for argument."); return; } - StringName argname=tokenizer.get_token_identifier(); + StringName argname=tokenizer->get_token_identifier(); arguments.push_back(argname); - tokenizer.advance(); + tokenizer->advance(); - if (defaulting && tokenizer.get_token()!=GDTokenizer::TK_OP_ASSIGN) { + if (defaulting && tokenizer->get_token()!=GDTokenizer::TK_OP_ASSIGN) { _set_error("Default parameter expected."); return; } - //tokenizer.advance(); + //tokenizer->advance(); - if (tokenizer.get_token()==GDTokenizer::TK_OP_ASSIGN) { + if (tokenizer->get_token()==GDTokenizer::TK_OP_ASSIGN) { defaulting=true; - tokenizer.advance(1); + tokenizer->advance(1); Node *defval=NULL; defval=_parse_and_reduce_expression(p_class,_static); @@ -1864,10 +1864,10 @@ void GDParser::_parse_class(ClassNode *p_class) { default_values.push_back(on); } - if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { - tokenizer.advance(); + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); continue; - } else if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + } else if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected ',' or ')'."); return; @@ -1879,7 +1879,7 @@ void GDParser::_parse_class(ClassNode *p_class) { } - tokenizer.advance(); + tokenizer->advance(); BlockNode *block = alloc_node<BlockNode>(); @@ -1895,24 +1895,24 @@ void GDParser::_parse_class(ClassNode *p_class) { id->name="_init"; cparent->arguments.push_back(id); - if (tokenizer.get_token()==GDTokenizer::TK_PERIOD) { - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { + if (tokenizer->get_token()==GDTokenizer::TK_PERIOD) { + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { _set_error("expected '(' for parent constructor arguments."); } - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { //has arguments while(true) { Node *arg = _parse_and_reduce_expression(p_class,_static); cparent->arguments.push_back(arg); - if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { - tokenizer.advance(); + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); continue; - } else if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + } else if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected ',' or ')'."); return; @@ -1923,12 +1923,12 @@ void GDParser::_parse_class(ClassNode *p_class) { } } - tokenizer.advance(); + tokenizer->advance(); } } else { - if (tokenizer.get_token()==GDTokenizer::TK_PERIOD) { + if (tokenizer->get_token()==GDTokenizer::TK_PERIOD) { _set_error("Parent constructor call found for a class without inheritance."); return; @@ -1963,41 +1963,41 @@ void GDParser::_parse_class(ClassNode *p_class) { } break; case GDTokenizer::TK_PR_EXPORT: { - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { - tokenizer.advance(); - if (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_TYPE) { + tokenizer->advance(); + if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE) { - Variant::Type type = tokenizer.get_token_type(); + Variant::Type type = tokenizer->get_token_type(); if (type==Variant::NIL) { _set_error("Can't export null type."); return; } current_export.type=type; - tokenizer.advance(); - if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { // hint expected next! - tokenizer.advance(); + tokenizer->advance(); switch(current_export.type) { case Variant::INT: { - if (tokenizer.get_token()==GDTokenizer::TK_CONSTANT && tokenizer.get_token_constant().get_type()==Variant::STRING) { + if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING) { //enumeration current_export.hint=PROPERTY_HINT_ENUM; bool first=true; while(true) { - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || tokenizer.get_token_constant().get_type()!=Variant::STRING) { + if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type()!=Variant::STRING) { current_export=PropertyInfo(); _set_error("Expected a string constant in enumeration hint."); } - String c = tokenizer.get_token_constant(); + String c = tokenizer->get_token_constant(); if (!first) current_export.hint_string+=","; else @@ -2005,16 +2005,16 @@ void GDParser::_parse_class(ClassNode *p_class) { current_export.hint_string+=c.xml_escape(); - tokenizer.advance(); - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) + tokenizer->advance(); + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) break; - if (tokenizer.get_token()!=GDTokenizer::TK_COMMA) { + if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) { current_export=PropertyInfo(); _set_error("Expected ')' or ',' in enumeration hint."); } - tokenizer.advance(); + tokenizer->advance(); } @@ -2024,7 +2024,7 @@ void GDParser::_parse_class(ClassNode *p_class) { }; case Variant::REAL: { - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer.get_token_constant().is_num()) { + if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) { current_export=PropertyInfo(); _set_error("Expected a range in numeric hint."); @@ -2033,119 +2033,119 @@ void GDParser::_parse_class(ClassNode *p_class) { //enumeration current_export.hint=PROPERTY_HINT_RANGE; - current_export.hint_string=tokenizer.get_token_constant().operator String(); - tokenizer.advance(); + current_export.hint_string=tokenizer->get_token_constant().operator String(); + tokenizer->advance(); - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { current_export.hint_string="0,"+current_export.hint_string; break; } - if (tokenizer.get_token()!=GDTokenizer::TK_COMMA) { + if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) { current_export=PropertyInfo(); _set_error("Expected ',' or ')' in numeric range hint."); } - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer.get_token_constant().is_num()) { + if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) { current_export=PropertyInfo(); _set_error("Expected a number as upper bound in numeric range hint."); } - current_export.hint_string+=","+tokenizer.get_token_constant().operator String(); - tokenizer.advance(); + current_export.hint_string+=","+tokenizer->get_token_constant().operator String(); + tokenizer->advance(); - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) break; - if (tokenizer.get_token()!=GDTokenizer::TK_COMMA) { + if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) { current_export=PropertyInfo(); _set_error("Expected ',' or ')' in numeric range hint."); } - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer.get_token_constant().is_num()) { + if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) { current_export=PropertyInfo(); _set_error("Expected a number as step in numeric range hint."); } - current_export.hint_string+=","+tokenizer.get_token_constant().operator String(); - tokenizer.advance(); + current_export.hint_string+=","+tokenizer->get_token_constant().operator String(); + tokenizer->advance(); } break; case Variant::STRING: { - if (tokenizer.get_token()==GDTokenizer::TK_CONSTANT && tokenizer.get_token_constant().get_type()==Variant::STRING) { + if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING) { //enumeration current_export.hint=PROPERTY_HINT_ENUM; bool first=true; while(true) { - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || tokenizer.get_token_constant().get_type()!=Variant::STRING) { + if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type()!=Variant::STRING) { current_export=PropertyInfo(); _set_error("Expected a string constant in enumeration hint."); } - String c = tokenizer.get_token_constant(); + String c = tokenizer->get_token_constant(); if (!first) current_export.hint_string+=","; else first=false; current_export.hint_string+=c.xml_escape(); - tokenizer.advance(); - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) + tokenizer->advance(); + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) break; - if (tokenizer.get_token()!=GDTokenizer::TK_COMMA) { + if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) { current_export=PropertyInfo(); _set_error("Expected ')' or ',' in enumeration hint."); return; } - tokenizer.advance(); + tokenizer->advance(); } break; } - if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer.get_token_identifier()=="DIR") { + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="DIR") { current_export.hint=PROPERTY_HINT_DIR; - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected ')' in hint."); return; } break; } - if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer.get_token_identifier()=="FILE") { + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="FILE") { current_export.hint=PROPERTY_HINT_FILE; - tokenizer.advance(); + tokenizer->advance(); - if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || tokenizer.get_token_constant().get_type()!=Variant::STRING) { + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type()!=Variant::STRING) { _set_error("Expected string constant with filter"); return; } - current_export.hint_string=tokenizer.get_token_constant(); - tokenizer.advance(); + current_export.hint_string=tokenizer->get_token_constant(); + tokenizer->advance(); } - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected ')' in hint."); return; } @@ -2154,14 +2154,14 @@ void GDParser::_parse_class(ClassNode *p_class) { } break; case Variant::COLOR: { - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER ) { + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER ) { current_export=PropertyInfo(); _set_error("Color type hint expects RGB or RGBA as hints"); return; } - String identifier = tokenizer.get_token_identifier(); + String identifier = tokenizer->get_token_identifier(); if (identifier=="RGB") { current_export.hint=PROPERTY_HINT_COLOR_NO_ALPHA; } else if (identifier=="RGBA") { @@ -2171,7 +2171,7 @@ void GDParser::_parse_class(ClassNode *p_class) { _set_error("Color type hint expects RGB or RGBA as hints"); return; } - tokenizer.advance(); + tokenizer->advance(); } break; default: { @@ -2184,9 +2184,9 @@ void GDParser::_parse_class(ClassNode *p_class) { } - } else if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER) { + } else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) { - String identifier = tokenizer.get_token_identifier(); + String identifier = tokenizer->get_token_identifier(); if (!ObjectTypeDB::is_type(identifier,"Resource")) { current_export=PropertyInfo(); @@ -2197,10 +2197,10 @@ void GDParser::_parse_class(ClassNode *p_class) { current_export.hint=PROPERTY_HINT_RESOURCE_TYPE; current_export.hint_string=identifier; - tokenizer.advance(); + tokenizer->advance(); } - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { current_export=PropertyInfo(); _set_error("Expected ')' or ',' after export hint."); @@ -2208,11 +2208,11 @@ void GDParser::_parse_class(ClassNode *p_class) { } - tokenizer.advance(); + tokenizer->advance(); } - if (tokenizer.get_token()!=GDTokenizer::TK_PR_VAR) { + if (tokenizer->get_token()!=GDTokenizer::TK_PR_VAR) { current_export=PropertyInfo(); _set_error("Expected 'var'."); @@ -2224,26 +2224,26 @@ void GDParser::_parse_class(ClassNode *p_class) { //variale declaration and (eventual) initialization ClassNode::Member member; - bool autoexport = tokenizer.get_token(-1)==GDTokenizer::TK_PR_EXPORT; + bool autoexport = tokenizer->get_token(-1)==GDTokenizer::TK_PR_EXPORT; if (current_export.type!=Variant::NIL) { member._export=current_export; current_export=PropertyInfo(); } - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { _set_error("Expected identifier for member variable name."); return; } - member.identifier=tokenizer.get_token_identifier(); + member.identifier=tokenizer->get_token_identifier(); member._export.name=member.identifier; - tokenizer.advance(); + tokenizer->advance(); p_class->variables.push_back(member); - if (tokenizer.get_token()!=GDTokenizer::TK_OP_ASSIGN) { + if (tokenizer->get_token()!=GDTokenizer::TK_OP_ASSIGN) { if (autoexport) { @@ -2253,9 +2253,9 @@ void GDParser::_parse_class(ClassNode *p_class) { break; } #ifdef DEBUG_ENABLED - int line = tokenizer.get_token_line(); + int line = tokenizer->get_token_line(); #endif - tokenizer.advance(); + tokenizer->advance(); Node *subexpr=NULL; @@ -2324,22 +2324,22 @@ void GDParser::_parse_class(ClassNode *p_class) { ClassNode::Constant constant; - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { _set_error("Expected name (identifier) for constant."); return; } - constant.identifier=tokenizer.get_token_identifier(); - tokenizer.advance(); + constant.identifier=tokenizer->get_token_identifier(); + tokenizer->advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_OP_ASSIGN) { + if (tokenizer->get_token()!=GDTokenizer::TK_OP_ASSIGN) { _set_error("Constant expects assignment."); return; } - tokenizer.advance(); + tokenizer->advance(); Node *subexpr=NULL; @@ -2362,7 +2362,7 @@ void GDParser::_parse_class(ClassNode *p_class) { default: { - _set_error(String()+"Unexpected token: "+tokenizer.get_token_name(tokenizer.get_token())+":"+tokenizer.get_token_identifier()); + _set_error(String()+"Unexpected token: "+tokenizer->get_token_name(tokenizer->get_token())+":"+tokenizer->get_token_identifier()); return; } break; @@ -2382,8 +2382,8 @@ void GDParser::_set_error(const String& p_error, int p_line, int p_column) { return; //allow no further errors error=p_error; - error_line=p_line<0?tokenizer.get_token_line():p_line; - error_column=p_column<0?tokenizer.get_token_column():p_column; + error_line=p_line<0?tokenizer->get_token_line():p_line; + error_column=p_column<0?tokenizer->get_token_column():p_column; error_set=true; } @@ -2402,11 +2402,10 @@ int GDParser::get_error_column() const { } -Error GDParser::parse(const String& p_code,const String& p_base_path) { +Error GDParser::_parse(const String& p_base_path) { - base_path=p_base_path; - tokenizer.set_code(p_code); + base_path=p_base_path; clear(); @@ -2416,9 +2415,9 @@ Error GDParser::parse(const String& p_code,const String& p_base_path) { _parse_class(main_class); - if (tokenizer.get_token()==GDTokenizer::TK_ERROR) { + if (tokenizer->get_token()==GDTokenizer::TK_ERROR) { error_set=false; - _set_error("Parse Error: "+tokenizer.get_token_error()); + _set_error("Parse Error: "+tokenizer->get_token_error()); } if (error_set) { @@ -2428,6 +2427,31 @@ Error GDParser::parse(const String& p_code,const String& p_base_path) { return OK; } +Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path) { + + GDTokenizerBuffer *tb = memnew( GDTokenizerBuffer ); + tb->set_code_buffer(p_bytecode); + tokenizer=tb; + Error ret = _parse(p_base_path); + memdelete(tb); + tokenizer=NULL; + return ret; +} + + +Error GDParser::parse(const String& p_code,const String& p_base_path) { + + + GDTokenizerText *tt = memnew( GDTokenizerText ); + tt->set_code(p_code); + + tokenizer=tt; + Error ret = _parse(p_base_path); + memdelete(tt); + tokenizer=NULL; + return ret; +} + const GDParser::Node *GDParser::get_parse_tree() const { return head; @@ -2459,6 +2483,7 @@ GDParser::GDParser() { head=NULL; list=NULL; + tokenizer=NULL; clear(); } diff --git a/script/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 8011495340..1925808cac 100644 --- a/script/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -343,10 +343,12 @@ public: ProgramNode() { type=TYPE_PROGRAM; } }; */ + + private: - GDTokenizer tokenizer; + GDTokenizer *tokenizer; Node *head; @@ -380,12 +382,15 @@ private: void _parse_class(ClassNode *p_class); bool _end_statement(); + Error _parse(const String& p_base_path); + public: String get_error() const; int get_error_line() const; int get_error_column() const; Error parse(const String& p_code,const String& p_base_path=""); + Error parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path=""); const Node *get_parse_tree() const; diff --git a/script/gdscript/gd_pretty_print.cpp b/modules/gdscript/gd_pretty_print.cpp index a5a993bb3a..a5a993bb3a 100644 --- a/script/gdscript/gd_pretty_print.cpp +++ b/modules/gdscript/gd_pretty_print.cpp diff --git a/script/gdscript/gd_pretty_print.h b/modules/gdscript/gd_pretty_print.h index fbf002295b..fbf002295b 100644 --- a/script/gdscript/gd_pretty_print.h +++ b/modules/gdscript/gd_pretty_print.h diff --git a/script/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 5679e1e066..29857e6be6 100644 --- a/script/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -1416,7 +1416,7 @@ Error GDScript::reload() { String basedir=path; if (basedir=="") - basedir==get_path(); + basedir=get_path(); if (basedir!="") basedir=basedir.get_base_dir(); @@ -1560,6 +1560,49 @@ void GDScript::_bind_methods() { } + + +Error GDScript::load_byte_code(const String& p_path) { + + Vector<uint8_t> bytecode = FileAccess::get_file_as_array(p_path); + ERR_FAIL_COND_V(bytecode.size()==0,ERR_PARSE_ERROR); + path=p_path; + + String basedir=path; + + if (basedir=="") + basedir=get_path(); + + if (basedir!="") + basedir=basedir.get_base_dir(); + + valid=false; + GDParser parser; + Error err = parser.parse_bytecode(bytecode,basedir); + if (err) { + _err_print_error("GDScript::load_byte_code",path.empty()?"built-in":(const char*)path.utf8().get_data(),parser.get_error_line(),("Parse Error: "+parser.get_error()).utf8().get_data()); + ERR_FAIL_V(ERR_PARSE_ERROR); + } + + GDCompiler compiler; + err = compiler.compile(&parser,this); + + if (err) { + _err_print_error("GDScript::load_byte_code",path.empty()?"built-in":(const char*)path.utf8().get_data(),compiler.get_error_line(),("Compile Error: "+compiler.get_error()).utf8().get_data()); + ERR_FAIL_V(ERR_COMPILATION_FAILED); + } + + valid=true; + + for(Map<StringName,Ref<GDScript> >::Element *E=subclasses.front();E;E=E->next()) { + + _set_subclass_path(E->get(),path); + } + + return OK; +} + + Error GDScript::load_source_code(const String& p_path) { @@ -2153,24 +2196,39 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig Ref<GDScript> scriptres(script); - Error err = script->load_source_code(p_path); + if (p_path.ends_with(".gdc")) { - if (err!=OK) { + script->set_script_path(p_original_path); // script needs this. + script->set_path(p_original_path); + Error err = script->load_byte_code(p_path); - ERR_FAIL_COND_V(err!=OK, RES()); - } - script->set_script_path(p_original_path); // script needs this. - script->set_path(p_original_path); - //script->set_name(p_path.get_file()); + if (err!=OK) { + + ERR_FAIL_COND_V(err!=OK, RES()); + } + + } else { + Error err = script->load_source_code(p_path); - script->reload(); + if (err!=OK) { + + ERR_FAIL_COND_V(err!=OK, RES()); + } + + script->set_script_path(p_original_path); // script needs this. + script->set_path(p_original_path); + //script->set_name(p_path.get_file()); + + script->reload(); + } return scriptres; } void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("gd"); + p_extensions->push_back("gdc"); } bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const { @@ -2180,7 +2238,8 @@ bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const { String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const { - if (p_path.extension().to_lower()=="gd") + String el = p_path.extension().to_lower(); + if (el=="gd" || el=="gdc") return "GDScript"; return ""; } diff --git a/script/gdscript/gd_script.h b/modules/gdscript/gd_script.h index bb9beaaf56..55bc547e8d 100644 --- a/script/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -261,6 +261,7 @@ public: virtual String get_node_type() const; void set_script_path(const String& p_path) { path=p_path; } //because subclasses need a path too... Error load_source_code(const String& p_path); + Error load_byte_code(const String& p_path); virtual ScriptLanguage *get_language() const; @@ -440,6 +441,8 @@ public: virtual void frame(); virtual void get_public_functions(List<MethodInfo> *p_functions) const; + virtual void get_public_constants(List<Pair<String,Variant> > *p_constants) const; + /* LOADER FUNCTIONS */ virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/script/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index f7320799a5..ff9be7926b 100644 --- a/script/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -29,6 +29,9 @@ #include "gd_tokenizer.h" #include "print_string.h" #include "gd_functions.h" +#include "io/marshalls.h" +#include "map.h" + const char* GDTokenizer::token_names[TK_MAX]={ "Empty", "Identifier", @@ -128,7 +131,7 @@ static bool _is_hex(CharType c) { return (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'); } -void GDTokenizer::_make_token(Token p_type) { +void GDTokenizerText::_make_token(Token p_type) { TokenData &tk=tk_rb[tk_rb_pos]; @@ -138,7 +141,7 @@ void GDTokenizer::_make_token(Token p_type) { tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE; } -void GDTokenizer::_make_identifier(const StringName& p_identifier) { +void GDTokenizerText::_make_identifier(const StringName& p_identifier) { TokenData &tk=tk_rb[tk_rb_pos]; @@ -151,7 +154,7 @@ void GDTokenizer::_make_identifier(const StringName& p_identifier) { } -void GDTokenizer::_make_built_in_func(GDFunctions::Function p_func) { +void GDTokenizerText::_make_built_in_func(GDFunctions::Function p_func) { TokenData &tk=tk_rb[tk_rb_pos]; @@ -163,7 +166,7 @@ void GDTokenizer::_make_built_in_func(GDFunctions::Function p_func) { tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE; } -void GDTokenizer::_make_constant(const Variant& p_constant) { +void GDTokenizerText::_make_constant(const Variant& p_constant) { TokenData &tk=tk_rb[tk_rb_pos]; @@ -176,7 +179,7 @@ void GDTokenizer::_make_constant(const Variant& p_constant) { } -void GDTokenizer::_make_type(const Variant::Type& p_type) { +void GDTokenizerText::_make_type(const Variant::Type& p_type) { TokenData &tk=tk_rb[tk_rb_pos]; @@ -191,7 +194,7 @@ void GDTokenizer::_make_type(const Variant::Type& p_type) { } -void GDTokenizer::_make_error(const String& p_error) { +void GDTokenizerText::_make_error(const String& p_error) { error_flag=true; last_error=p_error; @@ -206,7 +209,7 @@ void GDTokenizer::_make_error(const String& p_error) { } -void GDTokenizer::_make_newline(int p_spaces) { +void GDTokenizerText::_make_newline(int p_spaces) { TokenData &tk=tk_rb[tk_rb_pos]; tk.type=TK_NEWLINE; @@ -216,7 +219,7 @@ void GDTokenizer::_make_newline(int p_spaces) { tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE; } -void GDTokenizer::_advance() { +void GDTokenizerText::_advance() { if (error_flag) { //parser broke @@ -859,7 +862,7 @@ void GDTokenizer::_advance() { } -void GDTokenizer::set_code(const String& p_code) { +void GDTokenizerText::set_code(const String& p_code) { code=p_code; len = p_code.length(); @@ -878,7 +881,7 @@ void GDTokenizer::set_code(const String& p_code) { _advance(); } -GDTokenizer::Token GDTokenizer::get_token(int p_offset) const { +GDTokenizerText::Token GDTokenizerText::get_token(int p_offset) const { ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, TK_ERROR); ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, TK_ERROR); @@ -886,7 +889,7 @@ GDTokenizer::Token GDTokenizer::get_token(int p_offset) const { return tk_rb[ofs].type; } -int GDTokenizer::get_token_line(int p_offset) const { +int GDTokenizerText::get_token_line(int p_offset) const { ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, -1); ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, -1); @@ -894,7 +897,7 @@ int GDTokenizer::get_token_line(int p_offset) const { return tk_rb[ofs].line; } -int GDTokenizer::get_token_column(int p_offset) const { +int GDTokenizerText::get_token_column(int p_offset) const { ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, -1); ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, -1); @@ -902,7 +905,7 @@ int GDTokenizer::get_token_column(int p_offset) const { return tk_rb[ofs].col; } -const Variant& GDTokenizer::get_token_constant(int p_offset) const { +const Variant& GDTokenizerText::get_token_constant(int p_offset) const { ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, tk_rb[0].constant); ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, tk_rb[0].constant); @@ -910,7 +913,7 @@ const Variant& GDTokenizer::get_token_constant(int p_offset) const { ERR_FAIL_COND_V(tk_rb[ofs].type!=TK_CONSTANT,tk_rb[0].constant); return tk_rb[ofs].constant; } -StringName GDTokenizer::get_token_identifier(int p_offset) const { +StringName GDTokenizerText::get_token_identifier(int p_offset) const { ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, StringName()); ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, StringName()); @@ -921,7 +924,7 @@ StringName GDTokenizer::get_token_identifier(int p_offset) const { } -GDFunctions::Function GDTokenizer::get_token_built_in_func(int p_offset) const { +GDFunctions::Function GDTokenizerText::get_token_built_in_func(int p_offset) const { ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, GDFunctions::FUNC_MAX); ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, GDFunctions::FUNC_MAX); @@ -932,7 +935,7 @@ GDFunctions::Function GDTokenizer::get_token_built_in_func(int p_offset) const { } -Variant::Type GDTokenizer::get_token_type(int p_offset) const { +Variant::Type GDTokenizerText::get_token_type(int p_offset) const { ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, Variant::NIL); ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, Variant::NIL); @@ -944,7 +947,7 @@ Variant::Type GDTokenizer::get_token_type(int p_offset) const { } -int GDTokenizer::get_token_line_indent(int p_offset) const { +int GDTokenizerText::get_token_line_indent(int p_offset) const { ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, 0); ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, 0); @@ -955,7 +958,7 @@ int GDTokenizer::get_token_line_indent(int p_offset) const { } -String GDTokenizer::get_token_error(int p_offset) const { +String GDTokenizerText::get_token_error(int p_offset) const { ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, String()); ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, String()); @@ -965,9 +968,377 @@ String GDTokenizer::get_token_error(int p_offset) const { return tk_rb[ofs].constant; } -void GDTokenizer::advance(int p_amount) { +void GDTokenizerText::advance(int p_amount) { ERR_FAIL_COND( p_amount <=0 ); for(int i=0;i<p_amount;i++) _advance(); } + + + + + + + + + + + +////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define BYTECODE_VERSION 1 + +Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) { + + + const uint8_t *buf=p_buffer.ptr(); + int total_len=p_buffer.size(); + ERR_FAIL_COND_V( p_buffer.size()<24 || p_buffer[0]!='G' || p_buffer[1]!='D' || p_buffer[2]!='S' || p_buffer[3]!='C',ERR_INVALID_DATA); + + int version = decode_uint32(&buf[4]); + if (version>1) { + ERR_EXPLAIN("Bytecode is too New!"); + ERR_FAIL_COND_V(version>BYTECODE_VERSION,ERR_INVALID_DATA); + } + int identifier_count = decode_uint32(&buf[8]); + int constant_count = decode_uint32(&buf[12]); + int line_count = decode_uint32(&buf[16]); + int token_count = decode_uint32(&buf[20]); + + const uint8_t *b=buf; + + b=&buf[24]; + total_len-=24; + + identifiers.resize(identifier_count); + for(int i=0;i<identifier_count;i++) { + + int len = decode_uint32(b); + ERR_FAIL_COND_V(len>total_len,ERR_INVALID_DATA); + b+=4; + Vector<uint8_t> cs; + cs.resize(len); + for(int j=0;j<len;j++) { + cs[j]=b[j]^0xb6; + } + + cs[cs.size()-1]=0; + String s; + s.parse_utf8((const char*)cs.ptr()); + b+=len; + total_len-=len+4; + identifiers[i]=s; + } + + constants.resize(constant_count); + for(int i=0;i<constant_count;i++) { + + Variant v; + int len; + Error err = decode_variant(v,b,total_len,&len); + if (err) + return err; + b+=len; + total_len-=len; + constants[i]=v; + + } + + ERR_FAIL_COND_V(line_count*8>total_len,ERR_INVALID_DATA); + + for(int i=0;i<line_count;i++) { + + uint32_t token=decode_uint32(b); + b+=4; + uint32_t linecol=decode_uint32(b); + b+=4; + + lines.insert(token,linecol); + total_len-=8; + } + + tokens.resize(token_count); + + for(int i=0;i<token_count;i++) { + + ERR_FAIL_COND_V( total_len < 1, ERR_INVALID_DATA); + + if ((*b)&TOKEN_BYTE_MASK) { //little endian always + ERR_FAIL_COND_V( total_len < 4, ERR_INVALID_DATA); + + tokens[i]=decode_uint32(b)&~TOKEN_BYTE_MASK; + b+=4; + } else { + tokens[i]=*b; + b+=1; + total_len--; + } + } + + token=0; + + return OK; + +} + + +Vector<uint8_t> GDTokenizerBuffer::parse_code_string(const String& p_code) { + + Vector<uint8_t> buf; + + + Map<StringName,int> identifier_map; + HashMap<Variant,int,VariantHasher> constant_map; + Map<uint32_t,int> line_map; + Vector<uint32_t> token_array; + + GDTokenizerText tt; + tt.set_code(p_code); + int line=-1; + int col=0; + + while(true) { + + if (tt.get_token_line()!=line) { + + line=tt.get_token_line(); + line_map[line]=token_array.size(); + } + + uint32_t token=tt.get_token(); + switch(tt.get_token()) { + + case TK_IDENTIFIER: { + StringName id = tt.get_token_identifier(); + if (!identifier_map.has(id)) { + int idx = identifier_map.size(); + identifier_map[id]=idx; + } + token|=identifier_map[id]<<TOKEN_BITS; + } break; + case TK_CONSTANT: { + + Variant c = tt.get_token_constant(); + if (!constant_map.has(c)) { + int idx = constant_map.size(); + constant_map[c]=idx; + } + token|=constant_map[c]<<TOKEN_BITS; + } break; + case TK_BUILT_IN_TYPE: { + + token|=tt.get_token_type()<<TOKEN_BITS; + } break; + case TK_BUILT_IN_FUNC: { + + token|=tt.get_token_built_in_func()<<TOKEN_BITS; + + } break; + case TK_NEWLINE: { + + token|=tt.get_token_line_indent()<<TOKEN_BITS; + } break; + case TK_ERROR: { + + ERR_FAIL_V(Vector<uint8_t>()); + } break; + default: {} + + }; + + token_array.push_back(token); + + if (tt.get_token()==TK_EOF) + break; + tt.advance(); + + } + + //reverse maps + + Map<int,StringName> rev_identifier_map; + for(Map<StringName,int>::Element *E=identifier_map.front();E;E=E->next()) { + rev_identifier_map[E->get()]=E->key(); + } + + Map<int,Variant> rev_constant_map; + const Variant *K =NULL; + while((K=constant_map.next(K))) { + rev_constant_map[constant_map[*K]]=*K; + } + + Map<int,uint32_t> rev_line_map; + for(Map<uint32_t,int>::Element *E=line_map.front();E;E=E->next()) { + rev_line_map[E->get()]=E->key(); + } + + //save header + buf.resize(24); + buf[0]='G'; + buf[1]='D'; + buf[2]='S'; + buf[3]='C'; + encode_uint32(BYTECODE_VERSION,&buf[4]); + encode_uint32(identifier_map.size(),&buf[8]); + encode_uint32(constant_map.size(),&buf[12]); + encode_uint32(line_map.size(),&buf[16]); + encode_uint32(token_array.size(),&buf[20]); + + //save identifiers + + for(Map<int,StringName>::Element *E=rev_identifier_map.front();E;E=E->next()) { + + CharString cs = String(E->get()).utf8(); + int len = cs.length()+1; + int extra = 4-(len%4); + if (extra==4) + extra=0; + + uint8_t ibuf[4]; + encode_uint32(len+extra,ibuf); + for(int i=0;i<4;i++) { + buf.push_back(ibuf[i]); + } + for(int i=0;i<len;i++) { + buf.push_back(cs[i]^0xb6); + } + for(int i=0;i<extra;i++) { + buf.push_back(0^0xb6); + } + } + + for(Map<int,Variant>::Element *E=rev_constant_map.front();E;E=E->next()) { + + int len; + Error err = encode_variant(E->get(),NULL,len); + ERR_FAIL_COND_V(err!=OK,Vector<uint8_t>()); + int pos=buf.size(); + buf.resize(pos+len); + encode_variant(E->get(),&buf[pos],len); + } + + for(Map<int,uint32_t>::Element *E=rev_line_map.front();E;E=E->next()) { + + uint8_t ibuf[8]; + encode_uint32(E->key(),&ibuf[0]); + encode_uint32(E->get(),&ibuf[4]); + for(int i=0;i<8;i++) + buf.push_back(ibuf[i]); + } + + for(int i=0;i<token_array.size();i++) { + + uint32_t token = token_array[i]; + + if (token&~TOKEN_MASK) { + uint8_t buf4[4]; + encode_uint32(token_array[i]|TOKEN_BYTE_MASK,&buf4[0]); + for(int j=0;j<4;j++) { + buf.push_back(buf4[j]); + } + } else { + buf.push_back(token); + } + } + + return buf; + +} + +GDTokenizerBuffer::Token GDTokenizerBuffer::get_token(int p_offset) const { + + int offset = token+p_offset; + + if (offset<0 || offset>=tokens.size()) + return TK_EOF; + + return GDTokenizerBuffer::Token(tokens[offset]&TOKEN_MASK); +} + + +StringName GDTokenizerBuffer::get_token_identifier(int p_offset) const{ + + int offset = token+p_offset; + + ERR_FAIL_INDEX_V(offset,tokens.size(),StringName()); + uint32_t identifier = tokens[offset]>>TOKEN_BITS; + ERR_FAIL_INDEX_V(identifier,identifiers.size(),StringName()); + + return identifiers[identifier]; +} + +GDFunctions::Function GDTokenizerBuffer::get_token_built_in_func(int p_offset) const{ + + int offset = token+p_offset; + ERR_FAIL_INDEX_V(offset,tokens.size(),GDFunctions::FUNC_MAX); + return GDFunctions::Function(tokens[offset]>>TOKEN_BITS); +} + +Variant::Type GDTokenizerBuffer::get_token_type(int p_offset) const{ + + int offset = token+p_offset; + ERR_FAIL_INDEX_V(offset,tokens.size(),Variant::NIL); + + return Variant::Type(tokens[offset]>>TOKEN_BITS); +} + +int GDTokenizerBuffer::get_token_line(int p_offset) const{ + + int offset = token+p_offset; + int pos = lines.find_nearest(offset); + + if (pos<0) + return -1; + if (pos>=lines.size()) + pos=lines.size()-1; + + uint32_t l = lines.getv(pos); + return l&TOKEN_LINE_MASK; + +} +int GDTokenizerBuffer::get_token_column(int p_offset) const{ + + int offset = token+p_offset; + int pos = lines.find_nearest(offset); + if (pos<0) + return -1; + if (pos>=lines.size()) + pos=lines.size()-1; + + uint32_t l = lines.getv(pos); + return l>>TOKEN_LINE_BITS; + +} +int GDTokenizerBuffer::get_token_line_indent(int p_offset) const{ + + int offset = token+p_offset; + ERR_FAIL_INDEX_V(offset,tokens.size(),0); + return tokens[offset]>>TOKEN_BITS; +} +const Variant& GDTokenizerBuffer::get_token_constant(int p_offset) const{ + + + int offset = token+p_offset; + ERR_FAIL_INDEX_V(offset,tokens.size(),nil); + uint32_t constant = tokens[offset]>>TOKEN_BITS; + ERR_FAIL_INDEX_V(constant,constants.size(),nil); + return constants[constant]; + +} +String GDTokenizerBuffer::get_token_error(int p_offset) const{ + + ERR_FAIL_V(String()); +} + +void GDTokenizerBuffer::advance(int p_amount){ + + ERR_FAIL_INDEX(p_amount+token,tokens.size()); + token+=p_amount; +} +GDTokenizerBuffer::GDTokenizerBuffer(){ + + token=0; + +} + diff --git a/script/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index 24ee2be7ad..c517e07b89 100644 --- a/script/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -33,6 +33,8 @@ #include "variant.h" #include "string_db.h" #include "gd_functions.h" +#include "vmap.h" + class GDTokenizer { public: @@ -117,11 +119,28 @@ public: TK_MAX }; +protected: + static const char* token_names[TK_MAX]; +public: + static const char *get_token_name(Token p_token); + virtual const Variant& get_token_constant(int p_offset=0) const=0; + virtual Token get_token(int p_offset=0) const=0; + virtual StringName get_token_identifier(int p_offset=0) const=0; + virtual GDFunctions::Function get_token_built_in_func(int p_offset=0) const=0; + virtual Variant::Type get_token_type(int p_offset=0) const=0; + virtual int get_token_line(int p_offset=0) const=0; + virtual int get_token_column(int p_offset=0) const=0; + virtual int get_token_line_indent(int p_offset=0) const=0; + virtual String get_token_error(int p_offset=0) const=0; + virtual void advance(int p_amount=1)=0; -private: + virtual ~GDTokenizer(){}; + +}; + +class GDTokenizerText : public GDTokenizer { - static const char* token_names[TK_MAX]; enum { MAX_LOOKAHEAD=4, TK_RB_SIZE=MAX_LOOKAHEAD*2+1 @@ -162,20 +181,59 @@ private: void _advance(); public: - static const char *get_token_name(Token p_token); void set_code(const String& p_code); - Token get_token(int p_offset=0) const; - const Variant& get_token_constant(int p_offset=0) const; - StringName get_token_identifier(int p_offset=0) const; - GDFunctions::Function get_token_built_in_func(int p_offset=0) const; - Variant::Type get_token_type(int p_offset=0) const; - int get_token_line(int p_offset=0) const; - int get_token_column(int p_offset=0) const; - int get_token_line_indent(int p_offset=0) const; - - String get_token_error(int p_offset=0) const; - void advance(int p_amount=1); + virtual Token get_token(int p_offset=0) const; + virtual StringName get_token_identifier(int p_offset=0) const; + virtual GDFunctions::Function get_token_built_in_func(int p_offset=0) const; + virtual Variant::Type get_token_type(int p_offset=0) const; + virtual int get_token_line(int p_offset=0) const; + virtual int get_token_column(int p_offset=0) const; + virtual int get_token_line_indent(int p_offset=0) const; + virtual const Variant& get_token_constant(int p_offset=0) const; + virtual String get_token_error(int p_offset=0) const; + virtual void advance(int p_amount=1); +}; + + + + +class GDTokenizerBuffer : public GDTokenizer { + + + enum { + + TOKEN_BYTE_MASK=0x80, + TOKEN_BITS=8, + TOKEN_MASK=(1<<TOKEN_BITS)-1, + TOKEN_LINE_BITS=24, + TOKEN_LINE_MASK=(1<<TOKEN_LINE_BITS)-1, + }; + + + Vector<StringName> identifiers; + Vector<Variant> constants; + VMap<uint32_t,uint32_t> lines; + Vector<uint32_t> tokens; + Variant nil; + int token; + +public: + + + Error set_code_buffer(const Vector<uint8_t> & p_buffer); + static Vector<uint8_t> parse_code_string(const String& p_code); + virtual Token get_token(int p_offset=0) const; + virtual StringName get_token_identifier(int p_offset=0) const; + virtual GDFunctions::Function get_token_built_in_func(int p_offset=0) const; + virtual Variant::Type get_token_type(int p_offset=0) const; + virtual int get_token_line(int p_offset=0) const; + virtual int get_token_column(int p_offset=0) const; + virtual int get_token_line_indent(int p_offset=0) const; + virtual const Variant& get_token_constant(int p_offset=0) const; + virtual String get_token_error(int p_offset=0) const; + virtual void advance(int p_amount=1); + GDTokenizerBuffer(); }; #endif // TOKENIZER_H diff --git a/script/register_script_types.cpp b/modules/gdscript/register_types.cpp index 1927cd5c1f..6bcd12857b 100644 --- a/script/register_script_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -9,25 +9,66 @@ /* All Rights Reserved. */ /*************************************************/ -#include "register_script_types.h" +#include "register_types.h" -#include "script/gdscript/gd_script.h" -#include "script/multiscript/multi_script.h" +#include "gd_script.h" #include "io/resource_loader.h" +#include "os/file_access.h" - -#ifdef GDSCRIPT_ENABLED GDScriptLanguage *script_language_gd=NULL; ResourceFormatLoaderGDScript *resource_loader_gd=NULL; ResourceFormatSaverGDScript *resource_saver_gd=NULL; -#endif -static MultiScriptLanguage *script_multi_script=NULL; +#ifdef TOOLS_ENABLED + +#include "tools/editor/editor_import_export.h" +#include "gd_tokenizer.h" +#include "tools/editor/editor_node.h" + +class EditorExportGDScript : public EditorExportPlugin { + + OBJ_TYPE(EditorExportGDScript,EditorExportPlugin); + +public: -void register_script_types() { + virtual Vector<uint8_t> custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) { + //compile gdscript to bytecode + if (p_path.ends_with(".gd")) { + Vector<uint8_t> file = FileAccess::get_file_as_array(p_path); + if (file.empty()) + return file; + String txt; + txt.parse_utf8((const char*)file.ptr(),file.size()); + file = GDTokenizerBuffer::parse_code_string(txt); + if (!file.empty()) { + print_line("PREV: "+p_path); + p_path=p_path.basename()+".gdc"; + print_line("NOW: "+p_path); + return file; + } + + } + + return Vector<uint8_t>(); + } + + + EditorExportGDScript(){} + +}; + +static void register_editor_plugin() { + + Ref<EditorExportGDScript> egd = memnew( EditorExportGDScript ); + EditorImportExport::get_singleton()->add_export_plugin(egd); +} + + +#endif + +void register_gdscript_types() { -#ifdef GDSCRIPT_ENABLED script_language_gd=memnew( GDScriptLanguage ); script_language_gd->init(); @@ -37,21 +78,18 @@ void register_script_types() { ResourceLoader::add_resource_format_loader(resource_loader_gd); resource_saver_gd=memnew( ResourceFormatSaverGDScript ); ResourceSaver::add_resource_format_saver(resource_saver_gd); -#endif - - script_multi_script = memnew( MultiScriptLanguage ); - ScriptServer::register_language(script_multi_script); - ObjectTypeDB::register_type<MultiScript>(); +#ifdef TOOLS_ENABLED + EditorNode::add_init_callback(register_editor_plugin); +#endif } -void unregister_script_types() { +void unregister_gdscript_types() { -#ifdef GDSCRIPT_ENABLED if (script_language_gd) memdelete( script_language_gd ); if (resource_loader_gd) @@ -59,8 +97,4 @@ void unregister_script_types() { if (resource_saver_gd) memdelete( resource_saver_gd ); -#endif - - if (script_multi_script); - memdelete(script_multi_script); } diff --git a/script/register_script_types.h b/modules/gdscript/register_types.h index eec0cfe539..ff7c2734df 100644 --- a/script/register_script_types.h +++ b/modules/gdscript/register_types.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* register_script_types.h */ +/* register_types.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -26,13 +26,5 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef REGISTER_SCRIPT_TYPES_H -#define REGISTER_SCRIPT_TYPES_H - -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ -void register_script_types(); -void unregister_script_types(); - -#endif +void register_gdscript_types(); +void unregister_gdscript_types(); diff --git a/modules/multiscript/SCsub b/modules/multiscript/SCsub new file mode 100644 index 0000000000..d20da72b72 --- /dev/null +++ b/modules/multiscript/SCsub @@ -0,0 +1,7 @@ +Import('env') + +env.add_source_files(env.modules_sources,"*.cpp") + +Export('env') + + diff --git a/modules/multiscript/config.py b/modules/multiscript/config.py new file mode 100644 index 0000000000..f9bd7da08d --- /dev/null +++ b/modules/multiscript/config.py @@ -0,0 +1,11 @@ + + +def can_build(platform): + return True + + +def configure(env): + pass + + + diff --git a/script/multiscript/multi_script.cpp b/modules/multiscript/multi_script.cpp index 1924cf2a6e..1924cf2a6e 100644 --- a/script/multiscript/multi_script.cpp +++ b/modules/multiscript/multi_script.cpp diff --git a/script/multiscript/multi_script.h b/modules/multiscript/multi_script.h index a67cedc56b..87d4b4e4c8 100644 --- a/script/multiscript/multi_script.h +++ b/modules/multiscript/multi_script.h @@ -148,6 +148,7 @@ public: virtual void get_recognized_extensions(List<String> *p_extensions) const {} virtual void get_public_functions(List<MethodInfo> *p_functions) const {} + virtual void get_public_constants(List<Pair<String,Variant> > *p_constants) const {} MultiScriptLanguage() { singleton=this; } virtual ~MultiScriptLanguage() {}; diff --git a/modules/multiscript/register_types.cpp b/modules/multiscript/register_types.cpp new file mode 100644 index 0000000000..4b25656723 --- /dev/null +++ b/modules/multiscript/register_types.cpp @@ -0,0 +1,32 @@ +/*************************************************/ +/* register_script_types.cpp */ +/*************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/*************************************************/ +/* Source code within this file is: */ +/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */ +/* All Rights Reserved. */ +/*************************************************/ + +#include "register_types.h" + +#include "multi_script.h" +#include "io/resource_loader.h" + +static MultiScriptLanguage *script_multi_script=NULL; + +void register_multiscript_types() { + + + script_multi_script = memnew( MultiScriptLanguage ); + ScriptServer::register_language(script_multi_script); + ObjectTypeDB::register_type<MultiScript>(); + + +} +void unregister_multiscript_types() { + + if (script_multi_script); + memdelete(script_multi_script); +} diff --git a/modules/multiscript/register_types.h b/modules/multiscript/register_types.h new file mode 100644 index 0000000000..d137b1c63f --- /dev/null +++ b/modules/multiscript/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_multiscript_types(); +void unregister_multiscript_types(); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index d95818b4a1..a09575bad5 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -45,7 +45,10 @@ #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> + +#ifdef __linux__ #include <linux/joystick.h> +#endif //stupid linux.h #ifdef KEY_TAB @@ -1031,7 +1034,7 @@ void OS_X11::close_joystick(int p_id) { }; void OS_X11::probe_joystick(int p_id) { - + #ifndef __FreeBSD__ if (p_id == -1) { for (int i=0; i<JOYSTICKS_MAX; i++) { @@ -1065,6 +1068,7 @@ void OS_X11::probe_joystick(int p_id) { ++i; }; + #endif }; void OS_X11::move_window_to_foreground() { @@ -1073,7 +1077,7 @@ void OS_X11::move_window_to_foreground() { } void OS_X11::process_joysticks() { - + #ifndef __FreeBSD__ int bytes; js_event events[32]; InputEvent ievent; @@ -1172,6 +1176,7 @@ void OS_X11::process_joysticks() { }; }; }; + #endif }; void OS_X11::set_cursor_shape(CursorShape p_shape) { diff --git a/platform/x11/platform_config.h b/platform/x11/platform_config.h index d14f3e3f9a..21703969cc 100644 --- a/platform/x11/platform_config.h +++ b/platform/x11/platform_config.h @@ -26,7 +26,13 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifdef __linux__ #include <alloca.h> +#endif +#ifdef __FreeBSD__ +#include <stdlib.h> +#endif + #define GLES2_INCLUDE_H "gl_context/glew.h" #define GLES1_INCLUDE_H "gl_context/glew.h" diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 9b2994ef84..a2bee43e58 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -162,6 +162,10 @@ void Node2D::set_scale(const Size2& p_scale) { if (_xform_dirty) ((Node2D*)this)->_update_xform_values(); scale=p_scale; + if (scale.x==0) + scale.x=CMP_EPSILON; + if (scale.y==0) + scale.y=CMP_EPSILON; _update_transform(); _change_notify("transform/scale"); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 166ee4daa8..afdca4a3be 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -744,192 +744,149 @@ bool KinematicBody2D::_ignores_mode(Physics2DServer::BodyMode p_mode) const { return true; } -bool KinematicBody2D::is_trapped() const { - - ERR_FAIL_COND_V(!is_inside_scene(),false); - - Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); - ERR_FAIL_COND_V(!dss,false); - - const int max_shapes=32; - Physics2DDirectSpaceState::ShapeResult sr[max_shapes]; - - Set<RID> exclude; - exclude.insert(get_rid()); - - - for(int i=0;i<get_shape_count();i++) { - - - int res = dss->intersect_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),sr,max_shapes,exclude); - - for(int j=0;j<res;j++) { - - Physics2DServer::BodyMode bm = Physics2DServer::get_singleton()->body_get_mode(sr[j].rid); - if (!_ignores_mode(bm)) { - return true; //it's indeed trapped - } - - } - - } - - return false; +Vector2 KinematicBody2D::move(const Vector2& p_motion) { -} -void KinematicBody2D::untrap() { + //give me back regular physics engine logic + //this is madness + //and most people using this function will think + //what it does is simpler than using physics + //this took about a week to get right.. + //but is it right? who knows at this point.. - //this is reaaaaaaaaally wild, will probably only work for simple cases - ERR_FAIL_COND(!is_inside_scene()); + colliding=false; + ERR_FAIL_COND_V(!is_inside_scene(),Vector2()); Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); - ERR_FAIL_COND(!dss); - + ERR_FAIL_COND_V(!dss,Vector2()); const int max_shapes=32; - Physics2DDirectSpaceState::ShapeResult sr[max_shapes]; - const int max_contacts=8; - Vector2 pairs[max_contacts*2]; + Vector2 sr[max_shapes*2]; + int res_shapes; Set<RID> exclude; exclude.insert(get_rid()); - Vector2 untrap_vec; - - for(int i=0;i<get_shape_count();i++) { - Matrix32 shape_xform = get_global_transform() * get_shape_transform(i); - int res = dss->intersect_shape(get_shape(i)->get_rid(), shape_xform,Vector2(),sr,max_shapes,exclude); + //recover first + int recover_attempts=4; - for(int j=0;j<res;j++) { + bool collided=false; + uint32_t mask=0; + if (collide_static) + mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY; + if (collide_kinematic) + mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; + if (collide_rigid) + mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY; + if (collide_character) + mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY; - Physics2DServer::BodyMode bm = Physics2DServer::get_singleton()->body_get_mode(sr[j].rid); - if (_ignores_mode(bm)) { - exclude.insert(sr[j].rid); - } else { +// print_line("motion: "+p_motion+" margin: "+rtos(margin)); - int rc; - bool c = Physics2DServer::get_singleton()->body_collide_shape(sr[j].rid,sr[j].shape,get_shape(i)->get_rid(),shape_xform,Vector2(),pairs,max_contacts,rc); + //print_line("margin: "+rtos(margin)); + do { - if (c) { - - for(int k=0;k<rc;k++) { + //fill exclude list.. + for(int i=0;i<get_shape_count();i++) { - untrap_vec+=pairs[k*2+0]-pairs[k*2+1]; - } - } - } + if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,0,mask)) + collided=true; } - } - - untrap_vec += untrap_vec.normalized()*margin; + if (!collided) + break; + Vector2 recover_motion; - Matrix32 gt = get_global_transform(); - gt.elements[2]+=untrap_vec; - set_global_transform(gt); + for(int i=0;i<res_shapes;i++) { -} + Vector2 a = sr[i*2+0]; + Vector2 b = sr[i*2+1]; -Vector2 KinematicBody2D::move(const Vector2& p_motion) { + float d = a.distance_to(b); - colliding=false; - ERR_FAIL_COND_V(!is_inside_scene(),Vector2()); - Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); - ERR_FAIL_COND_V(!dss,Vector2()); - const int max_shapes=32; - Physics2DDirectSpaceState::ShapeResult sr[max_shapes]; + //if (d<margin) + /// continue; + recover_motion+=(b-a)*0.2; + } - float best_travel = 1e20; - Physics2DDirectSpaceState::MotionCastCollision mcc_final; - Set<RID> exclude; - exclude.insert(get_rid()); + if (recover_motion==Vector2()) { + collided=false; + break; + } - print_line("pos: "+get_global_pos()); - print_line("mlen: "+p_motion); + Matrix32 gt = get_global_transform(); + gt.elements[2]+=recover_motion; + set_global_transform(gt); - if (!collide_static || ! collide_rigid || !collide_character || !collide_kinematic) { - //fill exclude list.. - for(int i=0;i<get_shape_count();i++) { + recover_attempts--; + } while (recover_attempts); - int res = dss->intersect_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),p_motion,sr,max_shapes,exclude); - for(int j=0;j<res;j++) { - - Physics2DServer::BodyMode bm = Physics2DServer::get_singleton()->body_get_mode(sr[j].rid); - if (_ignores_mode(bm)) { - exclude.insert(sr[j].rid); - } else { - // print_line("DANGER???"); - } - } - } - } + //move second + float safe = 1.0; + float unsafe = 1.0; + int best_shape=-1; for(int i=0;i<get_shape_count();i++) { - Physics2DDirectSpaceState::MotionCastCollision mcc; - bool res = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, mcc,exclude,0); - if (res==false) + float lsafe,lunsafe; + bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,0,mask); + //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel)); + if (!valid) { + safe=0; + unsafe=0; + best_shape=i; //sadly it's the best + break; + } + if (lsafe==1.0) { continue; - if (mcc.travel<=0) { - //uh it's trapped - colliding=false; - return p_motion; } - if (mcc.travel < best_travel) { + if (lsafe < safe) { - mcc_final=mcc; - best_travel=mcc.travel; + safe=lsafe; + unsafe=lunsafe; + best_shape=i; } } - float motion; - Vector2 motion_ret; - Vector2 push; - if (best_travel>1) { + + //print_line("best shape: "+itos(best_shape)+" motion "+p_motion); + + if (safe>=1) { //not collided colliding=false; - motion=p_motion.length(); //no stopped } else { - colliding=true; - collision=mcc_final.point; - normal=mcc_final.normal; - collider=mcc_final.collider_id; - Vector2 mnormal=p_motion.normalized(); - - float sine = Math::abs(mnormal.dot(normal)); - float retreat=0; - motion = p_motion.length()*mcc_final.travel; - - if (sine==0) { - //something odd going on, do not allow motion? - - retreat=motion; - + //it collided, let's get the rest info in unsafe advance + Matrix32 ugt = get_global_transform(); + ugt.elements[2]+=p_motion*unsafe; + Physics2DDirectSpaceState::ShapeRestInfo rest_info; + bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), Vector2(), margin,&rest_info,exclude,0,mask); + if (!c2) { + //should not happen, but floating point precision is so weird.. + colliding=false; } else { - retreat = margin/sine; - if (retreat>motion) - retreat=motion; + //print_line("Travel: "+rtos(travel)); + colliding=true; + collision=rest_info.point; + normal=rest_info.normal; + collider=rest_info.collider_id; + collider_vel=rest_info.linear_velocity; } - motion_ret=p_motion.normalized() * ( p_motion.length() - motion); - motion-=retreat; - - } + Vector2 motion=p_motion*safe; Matrix32 gt = get_global_transform(); - gt.elements[2]+=p_motion.normalized()*motion; + gt.elements[2]+=motion; set_global_transform(gt); - return motion_ret; + return p_motion-motion; } @@ -938,18 +895,31 @@ Vector2 KinematicBody2D::move_to(const Vector2& p_position) { return move(p_position-get_global_pos()); } -bool KinematicBody2D::can_move_to(const Vector2& p_position) { +bool KinematicBody2D::can_move_to(const Vector2& p_position, bool p_discrete) { ERR_FAIL_COND_V(!is_inside_scene(),false); Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); ERR_FAIL_COND_V(!dss,false); - const int max_shapes=32; - Physics2DDirectSpaceState::ShapeResult sr[max_shapes]; + uint32_t mask=0; + if (collide_static) + mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY; + if (collide_kinematic) + mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; + if (collide_rigid) + mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY; + if (collide_character) + mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY; Vector2 motion = p_position-get_global_pos(); + Matrix32 xform=get_global_transform(); + + if (p_discrete) { + + xform.elements[2]+=motion; + motion=Vector2(); + } - Physics2DDirectSpaceState::MotionCastCollision mcc_final; Set<RID> exclude; exclude.insert(get_rid()); @@ -957,19 +927,9 @@ bool KinematicBody2D::can_move_to(const Vector2& p_position) { for(int i=0;i<get_shape_count();i++) { - int res = dss->intersect_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),motion,sr,max_shapes,exclude); - - for(int j=0;j<res;j++) { - - Physics2DServer::BodyMode bm = Physics2DServer::get_singleton()->body_get_mode(sr[j].rid); - if (_ignores_mode(bm)) { - exclude.insert(sr[j].rid); - continue; - } - - return false; //omg collided - - } + bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),motion,0,NULL,0,exclude,0,mask); + if (col) + return false; } return true; @@ -993,6 +953,12 @@ Vector2 KinematicBody2D::get_collision_normal() const { return normal; } + +Vector2 KinematicBody2D::get_collider_velocity() const { + + return collider_vel; +} + ObjectID KinematicBody2D::get_collider() const { ERR_FAIL_COND_V(!colliding,0); @@ -1051,9 +1017,6 @@ float KinematicBody2D::get_collision_margin() const{ void KinematicBody2D::_bind_methods() { - ObjectTypeDB::bind_method(_MD("is_trapped"),&KinematicBody2D::is_trapped); - ObjectTypeDB::bind_method(_MD("untrap"),&KinematicBody2D::untrap); - ObjectTypeDB::bind_method(_MD("move","rel_vec"),&KinematicBody2D::move); ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody2D::move_to); @@ -1063,6 +1026,7 @@ void KinematicBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_pos"),&KinematicBody2D::get_collision_pos); ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody2D::get_collision_normal); + ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody2D::get_collider_velocity); ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody2D::get_collider); @@ -1085,7 +1049,7 @@ void KinematicBody2D::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/kinematic"),_SCS("set_collide_with_kinematic_bodies"),_SCS("can_collide_with_kinematic_bodies")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/rigid"),_SCS("set_collide_with_rigid_bodies"),_SCS("can_collide_with_rigid_bodies")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collide_with/character"),_SCS("set_collide_with_character_bodies"),_SCS("can_collide_with_character_bodies")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/margin",PROPERTY_HINT_RANGE,"0.01,256,0.01"),_SCS("set_collision_margin"),_SCS("get_collision_margin")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/margin",PROPERTY_HINT_RANGE,"0.001,256,0.001"),_SCS("set_collision_margin"),_SCS("get_collision_margin")); } @@ -1100,7 +1064,7 @@ KinematicBody2D::KinematicBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_KI colliding=false; collider=0; - margin=1; + margin=0.01; } KinematicBody2D::~KinematicBody2D() { diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 6596c0ce04..e7b65b1ef3 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -243,6 +243,7 @@ class KinematicBody2D : public PhysicsBody2D { bool colliding; Vector2 collision; Vector2 normal; + Vector2 collider_vel; ObjectID collider; @@ -254,16 +255,14 @@ protected: static void _bind_methods(); public: - bool is_trapped() const; - void untrap(); - Vector2 move(const Vector2& p_motion); Vector2 move_to(const Vector2& p_position); - bool can_move_to(const Vector2& p_position); + bool can_move_to(const Vector2& p_position,bool p_discrete=false); bool is_colliding() const; Vector2 get_collision_pos() const; Vector2 get_collision_normal() const; + Vector2 get_collider_velocity() const; ObjectID get_collider() const; void set_collide_with_static_bodies(bool p_enable); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 6ec23f96fb..b77a4e0fe3 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -43,7 +43,8 @@ bool Skeleton::_set(const StringName& p_path, const Variant& p_value) { int which=path.get_slice("/",1).to_int(); String what=path.get_slice("/",2); - + + if (which==bones.size() && what=="name") { add_bone(p_value); @@ -94,7 +95,7 @@ bool Skeleton::_get(const StringName& p_name,Variant &r_ret) const { if (what=="name") r_ret=get_bone_name(which); - if (what=="parent") + else if (what=="parent") r_ret=get_bone_parent(which); else if (what=="rest") r_ret=get_bone_rest(which); @@ -250,7 +251,7 @@ void Skeleton::add_bone(const String& p_name) { ERR_FAIL_COND( bones[i].name=="p_name"); } - + Bone b; b.name=p_name; bones.push_back(b); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 9be3c97901..fb85f0c6b7 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1591,7 +1591,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ case TreeItem::CELL_MODE_CUSTOM: { edited_item=p_item; edited_col=col; - custom_popup_rect=Rect2i(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs+item_h-v_scroll->get_val()), Size2(get_column_width(col),item_h)); + custom_popup_rect=Rect2i(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs+item_h-cache.offset.y), Size2(get_column_width(col),item_h)); emit_signal("custom_popup_edited",((bool)(x >= (col_width-item_h/2)))); bring_up_editor=false; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 1f54040de4..9b592a77d5 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -462,7 +462,7 @@ void Node::_set_name_nocheck(const StringName& p_name) { void Node::set_name(const String& p_name) { - String name=p_name.replace(":","").replace("/",""); + String name=p_name.replace(":","").replace("/","").replace("@",""); ERR_FAIL_COND(name==""); data.name=name; @@ -479,45 +479,99 @@ void Node::set_name(const String& p_name) { } } +static bool node_hrcr=false; +static SafeRefCount node_hrcr_count; + +void Node::init_node_hrcr() { + node_hrcr_count.init(1); +} + +void Node::set_human_readable_collision_renaming(bool p_enabled) { + + node_hrcr=p_enabled; +} + + void Node::_validate_child_name(Node *p_child) { /* Make sure the name is unique */ - String basename = p_child->data.name; - if (basename=="") { - - basename = p_child->get_type(); - } - - int val=1; - - for(;;) { - - String attempted = val > 1 ? (basename + " " +itos(val) ) : basename; + if (node_hrcr) { - bool found=false; - - for (int i=0;i<data.children.size();i++) { - - if (data.children[i]==p_child) + //this approach to autoset node names is human readable but very slow + //it's turned on while running in the editor + + String basename = p_child->data.name; + + if (basename=="") { + + basename = p_child->get_type(); + } + + int val=1; + + for(;;) { + + String attempted = val > 1 ? (basename + " " +itos(val) ) : basename; + + bool found=false; + + for (int i=0;i<data.children.size();i++) { + + if (data.children[i]==p_child) + continue; + if (data.children[i]->get_name() == attempted) { + found=true; + break; + } + + } + + if (found) { + + val++; continue; - if (data.children[i]->get_name() == attempted) { - found=true; - break; } - + + p_child->data.name=attempted; + break; } - - if (found) { - - val++; - continue; + } else { + + //this approach to autoset node names is fast but not as readable + //it's the default and reserves the '@' character for unique names. + + bool unique=true; + + if (p_child->data.name==StringName() || p_child->data.name.operator String()[0]=='@') { + //new unique name must be assigned + unique=false; + } else { + //check if exists + Node **childs=data.children.ptr(); + int cc = data.children.size(); + + for(int i=0;i<cc;i++) { + if (childs[i]==p_child) + continue; + if (childs[i]->data.name==p_child->data.name) { + unique=false; + break; + } + } + } + + if (!unique) { + + node_hrcr_count.ref(); +#ifdef DEBUG_ENABLED + String name = "@"+String(p_child->get_type_name())+itos(node_hrcr_count.get()); +#else + String name = "@"+itos(node_hrcr_count.get()); +#endif + p_child->data.name=name; } - - p_child->data.name=attempted; - break; } - } void Node::_add_child_nocheck(Node* p_child,const StringName& p_name) { @@ -541,6 +595,7 @@ void Node::_add_child_nocheck(Node* p_child,const StringName& p_name) { } + void Node::add_child(Node *p_child) { ERR_FAIL_NULL(p_child); diff --git a/scene/main/node.h b/scene/main/node.h index f38a782181..ec03fb19e8 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -261,6 +261,9 @@ public: void queue_delete(); + static void set_human_readable_collision_renaming(bool p_enabled); + static void init_node_hrcr(); + /* CANVAS */ Node(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index ae2b925008..4aed217cef 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -782,16 +782,41 @@ void Viewport::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_as_render_target","enable"), &Viewport::set_as_render_target); ObjectTypeDB::bind_method(_MD("is_set_as_render_target"), &Viewport::is_set_as_render_target); + ObjectTypeDB::bind_method(_MD("set_render_target_update_mode","mode"), &Viewport::set_render_target_update_mode); + ObjectTypeDB::bind_method(_MD("get_render_target_update_mode"), &Viewport::get_render_target_update_mode); + + ObjectTypeDB::bind_method(_MD("get_render_target_texture:RenderTargetTexture"), &Viewport::get_render_target_texture); + + ObjectTypeDB::bind_method(_MD("get_viewport"), &Viewport::get_viewport); + ObjectTypeDB::bind_method(_MD("update_worlds"), &Viewport::update_worlds); + + ObjectTypeDB::bind_method(_MD("set_as_audio_listener","enable"), &Viewport::set_as_audio_listener); + ObjectTypeDB::bind_method(_MD("is_audio_listener","enable"), &Viewport::is_audio_listener); + + ObjectTypeDB::bind_method(_MD("set_as_audio_listener_2d","enable"), &Viewport::set_as_audio_listener_2d); + ObjectTypeDB::bind_method(_MD("is_audio_listener_2d","enable"), &Viewport::is_audio_listener_2d); + + + ADD_PROPERTY( PropertyInfo(Variant::RECT2,"rect"), _SCS("set_rect"), _SCS("get_rect") ); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world",PROPERTY_HINT_RESOURCE_TYPE,"World"), _SCS("set_world"), _SCS("get_world") ); // ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world_2d",PROPERTY_HINT_RESOURCE_TYPE,"World2D"), _SCS("set_world_2d"), _SCS("get_world_2d") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transparent_bg"), _SCS("set_transparent_background"), _SCS("has_transparent_background") ); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target"), _SCS("set_as_render_target"), _SCS("is_set_as_render_target") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/enabled"), _SCS("set_as_render_target"), _SCS("is_set_as_render_target") ); + ADD_PROPERTY( PropertyInfo(Variant::INT,"render_target/update_mode",PROPERTY_HINT_ENUM,"Disabled,Once,When Visible,Always"), _SCS("set_render_target_update_mode"), _SCS("get_render_target_update_mode") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"audio_listener/enable_2d"), _SCS("set_as_audio_listener_2d"), _SCS("is_audio_listener_2d") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"audio_listener/enable_3d"), _SCS("set_as_audio_listener"), _SCS("is_audio_listener") ); ADD_SIGNAL(MethodInfo("size_changed")); + + BIND_CONSTANT( RENDER_TARGET_UPDATE_DISABLED ); + BIND_CONSTANT( RENDER_TARGET_UPDATE_ONCE ); + BIND_CONSTANT( RENDER_TARGET_UPDATE_WHEN_VISIBLE ); + BIND_CONSTANT( RENDER_TARGET_UPDATE_ALWAYS ); + } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index a35bc51e1e..7fbae20f7d 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -154,11 +154,9 @@ public: Camera* get_camera() const; - void set_listener_transform(const Transform& p_xform); void set_as_audio_listener(bool p_enable); bool is_audio_listener() const; - void set_listener_2d_transform(const Matrix32& p_xform); void set_as_audio_listener_2d(bool p_enable); bool is_audio_listener_2d() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index ae67023d5b..007ecb88b7 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -223,6 +223,7 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init + Node::init_node_hrcr(); #ifdef OLD_SCENE_FORMAT_ENABLED ObjectTypeDB::register_type<SceneIO>(); @@ -452,7 +453,7 @@ void register_scene_types() { ObjectTypeDB::register_virtual_type<PhysicsBody2D>(); ObjectTypeDB::register_type<StaticBody2D>(); ObjectTypeDB::register_type<RigidBody2D>(); - //ObjectTypeDB::register_type<KinematicBody2D>(); + ObjectTypeDB::register_type<KinematicBody2D>(); ObjectTypeDB::register_type<Area2D>(); ObjectTypeDB::register_type<CollisionShape2D>(); ObjectTypeDB::register_type<CollisionPolygon2D>(); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index ac1826a0b8..3bd7314778 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -26,564 +26,564 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "packed_scene.h"
-#include "globals.h"
-#include "io/resource_loader.h"
-
-bool PackedScene::can_instance() const {
-
- return nodes.size()>0;
-}
-
-Node *PackedScene::instance(bool p_gen_edit_state) const {
-
- int nc = nodes.size();
- ERR_FAIL_COND_V(nc==0,NULL);
-
- const StringName*snames=NULL;
- int sname_count=names.size();
- if (sname_count)
- snames=&names[0];
-
- const Variant*props=NULL;
- int prop_count=variants.size();
- if (prop_count)
- props=&variants[0];
-
- Vector<Variant> properties;
-
- const NodeData *nd = &nodes[0];
-
- Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc );
-
-
- for(int i=0;i<nc;i++) {
-
- const NodeData &n=nd[i];
-
- if (!ObjectTypeDB::is_type_enabled(snames[n.type])) {
- ret_nodes[i]=NULL;
- continue;
- }
-
- Node *node=NULL;
-
- if (n.instance>=0) {
- //instance existing
- Ref<PackedScene> sdata = props[ n.instance ];
- ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
- node = sdata->instance();
- ERR_FAIL_COND_V(!node,NULL);
- if (p_gen_edit_state)
- node->generate_instance_state();
-
- } else {
- //create anew
- Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
- ERR_FAIL_COND_V(!obj,NULL);
- node = obj->cast_to<Node>();
- ERR_FAIL_COND_V(!node,NULL);
-
- }
-
-
- //properties
- int nprop_count=n.properties.size();
- if (nprop_count) {
-
- const NodeData::Property* nprops=&n.properties[0];
-
- for(int j=0;j<nprop_count;j++) {
-
- bool valid;
- ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL );
- ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL );
-
- node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
- }
- }
-
- //name
-
- //groups
- for(int j=0;j<n.groups.size();j++) {
-
- ERR_FAIL_INDEX_V( n.groups[j], sname_count, NULL );
- node->add_to_group( snames[ n.groups[j] ], true );
- }
-
-
- ret_nodes[i]=node;
-
- if (i>0) {
- ERR_FAIL_INDEX_V(n.parent,i,NULL);
- ERR_FAIL_COND_V(!ret_nodes[n.parent],NULL);
- ret_nodes[n.parent]->_add_child_nocheck(node,snames[n.name]);
- } else {
- node->_set_name_nocheck( snames[ n.name ] );
- }
-
-
- if (n.owner>=0) {
-
- ERR_FAIL_INDEX_V(n.owner,i,NULL);
- node->_set_owner_nocheck(ret_nodes[n.owner]);
- }
-
- }
-
-
- //do connections
-
- int cc = connections.size();
- const ConnectionData *cdata = connections.ptr();
-
- for(int i=0;i<cc;i++) {
-
- const ConnectionData &c=cdata[i];
- ERR_FAIL_INDEX_V( c.from, nc, NULL );
- ERR_FAIL_INDEX_V( c.to, nc, NULL );
-
- Vector<Variant> binds;
- if (c.binds.size()) {
- binds.resize(c.binds.size());
- for(int j=0;j<c.binds.size();j++)
- binds[j]=props[ c.binds[j] ];
- }
-
- if (!ret_nodes[c.from] || !ret_nodes[c.to])
- continue;
- ret_nodes[c.from]->connect( snames[ c.signal], ret_nodes[ c.to ], snames[ c.method], binds,CONNECT_PERSIST|c.flags );
- }
-
- Node *s = ret_nodes[0];
-
- if (get_path()!="" && get_path().find("::")==-1)
- s->set_filename(get_path());
- return ret_nodes[0];
-
-}
-
-
-static int _nm_get_string(const String& p_string, Map<StringName,int> &name_map) {
-
- if (name_map.has(p_string))
- return name_map[p_string];
-
- int idx = name_map.size();
- name_map[p_string]=idx;
- return idx;
-}
-
-static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,VariantHasher> &variant_map) {
-
- if (variant_map.has(p_variant))
- return variant_map[p_variant];
-
- int idx = variant_map.size();
- variant_map[p_variant]=idx;
- return idx;
-}
-
-Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) {
-
- if (p_node!=p_owner && (p_node->get_owner()!=p_owner))
- return OK; //nothing to do with this node, may either belong to another scene or be onowned
-
- NodeData nd;
-
- nd.name=_nm_get_string(p_node->get_name(),name_map);
- nd.type=_nm_get_string(p_node->get_type(),name_map);
- nd.parent=p_parent_idx;
-
-
- Dictionary instance_state;
- Set<StringName> instance_groups;
-
-
- if (p_node!=p_owner && p_node->get_filename()!="") {
- //instanced
- Ref<PackedScene> instance = ResourceLoader::load(p_node->get_filename());
- if (!instance.is_valid()) {
- return ERR_CANT_OPEN;
- }
-
- nd.instance=_vm_get_variant(instance,variant_map);
- instance_state = p_node->get_instance_state();
- Vector<StringName> ig = p_node->get_instance_groups();
- for(int i=0;i<ig.size();i++)
- instance_groups.insert(ig[i]);
- } else {
-
- nd.instance=-1;
- }
-
-
- //instance state makes sure that only changes to instance are saved
-
- List<PropertyInfo> plist;
- p_node->get_property_list(&plist);
- for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
-
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
- continue;
-
- String name = E->get().name;
- Variant value = p_node->get( E->get().name );
-
- if (E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())
- continue;
-
-
- if (nd.instance>=0) {
- //only save changed properties in instance
- if (!instance_state.has(name))
- continue;
- if (instance_state[name]==value)
- continue;
-
- }
-
- NodeData::Property prop;
- prop.name=_nm_get_string( name,name_map);
- prop.value=_vm_get_variant( value, variant_map);
- nd.properties.push_back(prop);
-
- }
-
-
- List<Node::GroupInfo> groups;
- p_node->get_groups(&groups);
- for(List<Node::GroupInfo>::Element *E=groups.front();E;E=E->next()) {
- Node::GroupInfo &gi=E->get();
-
- if (!gi.persistent)
- continue;
- if (nd.instance>=0 && instance_groups.has(gi.name))
- continue; //group was instanced, don't add here
-
- nd.groups.push_back(_nm_get_string(gi.name,name_map));
- }
-
- if (node_map.has(p_node->get_owner()))
- nd.owner=node_map[p_node->get_owner()];
- else
- nd.owner=-1;
-
- int idx = nodes.size();
- node_map[p_node]=idx;
- nodes.push_back(nd);
-
-
-
- for(int i=0;i<p_node->get_child_count();i++) {
-
- Node *c=p_node->get_child(i);
- Error err = _parse_node(p_owner,c,idx,name_map,variant_map,node_map);
- if (err)
- return err;
- }
-
- return OK;
-
-}
-
-Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) {
-
- if (p_node!=p_owner && (p_node->get_owner()!=p_owner))
- return OK; //nothing to do with this node, may either belong to another scene or be onowned
-
- List<MethodInfo> signals;
- p_node->get_signal_list(&signals);
-
- ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG);
- NodeData &nd = nodes[node_map[p_node]];
- Set<Connection> instance_connections;
-
- if (nd.instance>=0) {
-
- Vector<Connection> iconns = p_node->get_instance_connections();
- for(int i=0;i<iconns.size();i++) {
-
- instance_connections.insert(iconns[i]);
- }
- }
-
-
- for(List<MethodInfo>::Element *E=signals.front();E;E=E->next()) {
-
- List<Node::Connection> conns;
- p_node->get_signal_connection_list(E->get().name,&conns);
- for(List<Node::Connection>::Element *F=conns.front();F;F=F->next()) {
-
- const Node::Connection &c = F->get();
- if (!(c.flags&CONNECT_PERSIST))
- continue;
-
- if (nd.instance>=0 && instance_connections.has(c))
- continue; //came from instance, don't save!
-
- Node *n=c.target->cast_to<Node>();
- if (!n)
- continue;
-
- if (!node_map.has(n)) {
- WARN_PRINT("Connection to node outside scene??")
- continue;
- }
-
- ConnectionData cd;
- cd.from=node_map[p_node];
- cd.to=node_map[n];
- cd.method=_nm_get_string(c.method,name_map);
- cd.signal=_nm_get_string(c.signal,name_map);
- cd.flags=c.flags;
- for(int i=0;i<c.binds.size();i++) {
-
- cd.binds.push_back( _vm_get_variant(c.binds[i],variant_map));
- }
- connections.push_back(cd);
- }
- }
-
- for(int i=0;i<p_node->get_child_count();i++) {
-
- Node *c=p_node->get_child(i);
- Error err = _parse_connections(p_owner,c,name_map,variant_map,node_map);
- if (err)
- return err;
- }
-
- return OK;
-}
-
-
-Error PackedScene::pack(Node *p_scene) {
- ERR_FAIL_NULL_V( p_scene, ERR_INVALID_PARAMETER );
-
-
- clear();
-
- Node *scene = p_scene;
-
- Map<StringName,int> name_map;
- HashMap<Variant,int,VariantHasher> variant_map;
- Map<Node*,int> node_map;
-
- Error err = _parse_node(scene,scene,-1,name_map,variant_map,node_map);
- if (err) {
- clear();
- ERR_FAIL_V(err);
- }
-
- err = _parse_connections(scene,scene,name_map,variant_map,node_map);
- if (err) {
- clear();
- ERR_FAIL_V(err);
- }
-
- names.resize(name_map.size());
-
- for(Map<StringName,int>::Element *E=name_map.front();E;E=E->next()) {
-
- names[E->get()]=E->key();
- }
-
- variants.resize(variant_map.size());
- const Variant *K=NULL;
- while((K=variant_map.next(K))) {
-
- int idx = variant_map[*K];
- variants[idx]=*K;
- }
-
- return OK;
-}
-
-void PackedScene::clear() {
-
- names.clear();
- variants.clear();
- nodes.clear();
- connections.clear();
-
-}
-
-void PackedScene::_set_bundled_scene(const Dictionary& d) {
-
-
- ERR_FAIL_COND( !d.has("names"));
- ERR_FAIL_COND( !d.has("variants"));
- ERR_FAIL_COND( !d.has("node_count"));
- ERR_FAIL_COND( !d.has("nodes"));
- ERR_FAIL_COND( !d.has("conn_count"));
- ERR_FAIL_COND( !d.has("conns"));
-// ERR_FAIL_COND( !d.has("path"));
-
- DVector<String> snames = d["names"];
- if (snames.size()) {
-
- int namecount = snames.size();
- names.resize(namecount);
- DVector<String>::Read r =snames.read();
- for(int i=0;i<names.size();i++)
- names[i]=r[i];
- }
-
- Array svariants = d["variants"];
-
- if (svariants.size()) {
- int varcount=svariants.size();
- variants.resize(varcount);
- for(int i=0;i<varcount;i++) {
-
- variants[i]=svariants[i];
- }
-
- } else {
- variants.clear();
- }
-
- nodes.resize(d["node_count"]);
- int nc=nodes.size();
- if (nc) {
- DVector<int> snodes = d["nodes"];
- DVector<int>::Read r = snodes.read();
- int idx=0;
- for(int i=0;i<nc;i++) {
- NodeData &nd = nodes[i];
- nd.parent=r[idx++];
- nd.owner=r[idx++];
- nd.type=r[idx++];
- nd.name=r[idx++];
- nd.instance=r[idx++];
- nd.properties.resize(r[idx++]);
- for(int j=0;j<nd.properties.size();j++) {
-
- nd.properties[j].name=r[idx++];
- nd.properties[j].value=r[idx++];
- }
- nd.groups.resize(r[idx++]);
- for(int j=0;j<nd.groups.size();j++) {
-
- nd.groups[j]=r[idx++];
- }
- }
-
- }
-
- connections.resize(d["conn_count"]);
- int cc=connections.size();
-
- if (cc) {
-
- DVector<int> sconns = d["conns"];
- DVector<int>::Read r = sconns.read();
- int idx=0;
- for(int i=0;i<cc;i++) {
- ConnectionData &cd = connections[i];
- cd.from=r[idx++];
- cd.to=r[idx++];
- cd.signal=r[idx++];
- cd.method=r[idx++];
- cd.flags=r[idx++];
- cd.binds.resize(r[idx++]);
-
- for(int j=0;j<cd.binds.size();j++) {
-
- cd.binds[j]=r[idx++];
- }
- }
-
- }
-
-// path=d["path"];
-
-}
-
-Dictionary PackedScene::_get_bundled_scene() const {
-
- DVector<String> rnames;
- rnames.resize(names.size());
-
- if (names.size()) {
-
- DVector<String>::Write r=rnames.write();
-
- for(int i=0;i<names.size();i++)
- r[i]=names[i];
- }
-
- Dictionary d;
- d["names"]=rnames;
- d["variants"]=variants;
-
- Vector<int> rnodes;
- d["node_count"]=nodes.size();
-
- for(int i=0;i<nodes.size();i++) {
-
- const NodeData &nd=nodes[i];
- rnodes.push_back(nd.parent);
- rnodes.push_back(nd.owner);
- rnodes.push_back(nd.type);
- rnodes.push_back(nd.name);
- rnodes.push_back(nd.instance);
- rnodes.push_back(nd.properties.size());
- for(int j=0;j<nd.properties.size();j++) {
-
- rnodes.push_back(nd.properties[j].name);
- rnodes.push_back(nd.properties[j].value);
- }
- rnodes.push_back(nd.groups.size());
- for(int j=0;j<nd.groups.size();j++) {
-
- rnodes.push_back(nd.groups[j]);
- }
- }
-
- d["nodes"]=rnodes;
-
- Vector<int> rconns;
- d["conn_count"]=connections.size();
-
- for(int i=0;i<connections.size();i++) {
-
- const ConnectionData &cd=connections[i];
- rconns.push_back(cd.from);
- rconns.push_back(cd.to);
- rconns.push_back(cd.signal);
- rconns.push_back(cd.method);
- rconns.push_back(cd.flags);
- rconns.push_back(cd.binds.size());
- for(int j=0;j<cd.binds.size();j++)
- rconns.push_back(cd.binds[j]);
-
- }
-
- d["conns"]=rconns;
- d["version"]=1;
-
-// d["path"]=path;
-
- return d;
-
-
-}
-
-void PackedScene::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("pack","path:Node"),&PackedScene::pack);
- ObjectTypeDB::bind_method(_MD("instance:Node"),&PackedScene::instance,DEFVAL(false));
- ObjectTypeDB::bind_method(_MD("can_instance"),&PackedScene::can_instance);
- ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&PackedScene::_set_bundled_scene);
- ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&PackedScene::_get_bundled_scene);
-
- ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled"),_SCS("_set_bundled_scene"),_SCS("_get_bundled_scene"));
-
-}
-
-PackedScene::PackedScene() {
-
-
-}
+#include "packed_scene.h" +#include "globals.h" +#include "io/resource_loader.h" + +bool PackedScene::can_instance() const { + + return nodes.size()>0; +} + +Node *PackedScene::instance(bool p_gen_edit_state) const { + + int nc = nodes.size(); + ERR_FAIL_COND_V(nc==0,NULL); + + const StringName*snames=NULL; + int sname_count=names.size(); + if (sname_count) + snames=&names[0]; + + const Variant*props=NULL; + int prop_count=variants.size(); + if (prop_count) + props=&variants[0]; + + Vector<Variant> properties; + + const NodeData *nd = &nodes[0]; + + Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc ); + + + for(int i=0;i<nc;i++) { + + const NodeData &n=nd[i]; + + if (!ObjectTypeDB::is_type_enabled(snames[n.type])) { + ret_nodes[i]=NULL; + continue; + } + + Node *node=NULL; + + if (n.instance>=0) { + //instance existing + Ref<PackedScene> sdata = props[ n.instance ]; + ERR_FAIL_COND_V( !sdata.is_valid(), NULL); + node = sdata->instance(); + ERR_FAIL_COND_V(!node,NULL); + if (p_gen_edit_state) + node->generate_instance_state(); + + } else { + //create anew + Object * obj = ObjectTypeDB::instance(snames[ n.type ]); + ERR_FAIL_COND_V(!obj,NULL); + node = obj->cast_to<Node>(); + ERR_FAIL_COND_V(!node,NULL); + + } + + + //properties + int nprop_count=n.properties.size(); + if (nprop_count) { + + const NodeData::Property* nprops=&n.properties[0]; + + for(int j=0;j<nprop_count;j++) { + + bool valid; + ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL ); + ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL ); + + node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid); + } + } + + //name + + //groups + for(int j=0;j<n.groups.size();j++) { + + ERR_FAIL_INDEX_V( n.groups[j], sname_count, NULL ); + node->add_to_group( snames[ n.groups[j] ], true ); + } + + + ret_nodes[i]=node; + + if (i>0) { + ERR_FAIL_INDEX_V(n.parent,i,NULL); + ERR_FAIL_COND_V(!ret_nodes[n.parent],NULL); + ret_nodes[n.parent]->_add_child_nocheck(node,snames[n.name]); + } else { + node->_set_name_nocheck( snames[ n.name ] ); + } + + + if (n.owner>=0) { + + ERR_FAIL_INDEX_V(n.owner,i,NULL); + node->_set_owner_nocheck(ret_nodes[n.owner]); + } + + } + + + //do connections + + int cc = connections.size(); + const ConnectionData *cdata = connections.ptr(); + + for(int i=0;i<cc;i++) { + + const ConnectionData &c=cdata[i]; + ERR_FAIL_INDEX_V( c.from, nc, NULL ); + ERR_FAIL_INDEX_V( c.to, nc, NULL ); + + Vector<Variant> binds; + if (c.binds.size()) { + binds.resize(c.binds.size()); + for(int j=0;j<c.binds.size();j++) + binds[j]=props[ c.binds[j] ]; + } + + if (!ret_nodes[c.from] || !ret_nodes[c.to]) + continue; + ret_nodes[c.from]->connect( snames[ c.signal], ret_nodes[ c.to ], snames[ c.method], binds,CONNECT_PERSIST|c.flags ); + } + + Node *s = ret_nodes[0]; + + if (get_path()!="" && get_path().find("::")==-1) + s->set_filename(get_path()); + return ret_nodes[0]; + +} + + +static int _nm_get_string(const String& p_string, Map<StringName,int> &name_map) { + + if (name_map.has(p_string)) + return name_map[p_string]; + + int idx = name_map.size(); + name_map[p_string]=idx; + return idx; +} + +static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,VariantHasher> &variant_map) { + + if (variant_map.has(p_variant)) + return variant_map[p_variant]; + + int idx = variant_map.size(); + variant_map[p_variant]=idx; + return idx; +} + +Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) { + + if (p_node!=p_owner && (p_node->get_owner()!=p_owner)) + return OK; //nothing to do with this node, may either belong to another scene or be onowned + + NodeData nd; + + nd.name=_nm_get_string(p_node->get_name(),name_map); + nd.type=_nm_get_string(p_node->get_type(),name_map); + nd.parent=p_parent_idx; + + + Dictionary instance_state; + Set<StringName> instance_groups; + + + if (p_node!=p_owner && p_node->get_filename()!="") { + //instanced + Ref<PackedScene> instance = ResourceLoader::load(p_node->get_filename()); + if (!instance.is_valid()) { + return ERR_CANT_OPEN; + } + + nd.instance=_vm_get_variant(instance,variant_map); + instance_state = p_node->get_instance_state(); + Vector<StringName> ig = p_node->get_instance_groups(); + for(int i=0;i<ig.size();i++) + instance_groups.insert(ig[i]); + } else { + + nd.instance=-1; + } + + + //instance state makes sure that only changes to instance are saved + + List<PropertyInfo> plist; + p_node->get_property_list(&plist); + for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { + + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) + continue; + + String name = E->get().name; + Variant value = p_node->get( E->get().name ); + + if (E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero()) + continue; + + + if (nd.instance>=0) { + //only save changed properties in instance + if (!instance_state.has(name)) + continue; + if (instance_state[name]==value) + continue; + + } + + NodeData::Property prop; + prop.name=_nm_get_string( name,name_map); + prop.value=_vm_get_variant( value, variant_map); + nd.properties.push_back(prop); + + } + + + List<Node::GroupInfo> groups; + p_node->get_groups(&groups); + for(List<Node::GroupInfo>::Element *E=groups.front();E;E=E->next()) { + Node::GroupInfo &gi=E->get(); + + if (!gi.persistent) + continue; + if (nd.instance>=0 && instance_groups.has(gi.name)) + continue; //group was instanced, don't add here + + nd.groups.push_back(_nm_get_string(gi.name,name_map)); + } + + if (node_map.has(p_node->get_owner())) + nd.owner=node_map[p_node->get_owner()]; + else + nd.owner=-1; + + int idx = nodes.size(); + node_map[p_node]=idx; + nodes.push_back(nd); + + + + for(int i=0;i<p_node->get_child_count();i++) { + + Node *c=p_node->get_child(i); + Error err = _parse_node(p_owner,c,idx,name_map,variant_map,node_map); + if (err) + return err; + } + + return OK; + +} + +Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) { + + if (p_node!=p_owner && (p_node->get_owner()!=p_owner)) + return OK; //nothing to do with this node, may either belong to another scene or be onowned + + List<MethodInfo> signals; + p_node->get_signal_list(&signals); + + ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG); + NodeData &nd = nodes[node_map[p_node]]; + Set<Connection> instance_connections; + + if (nd.instance>=0) { + + Vector<Connection> iconns = p_node->get_instance_connections(); + for(int i=0;i<iconns.size();i++) { + + instance_connections.insert(iconns[i]); + } + } + + + for(List<MethodInfo>::Element *E=signals.front();E;E=E->next()) { + + List<Node::Connection> conns; + p_node->get_signal_connection_list(E->get().name,&conns); + for(List<Node::Connection>::Element *F=conns.front();F;F=F->next()) { + + const Node::Connection &c = F->get(); + if (!(c.flags&CONNECT_PERSIST)) + continue; + + if (nd.instance>=0 && instance_connections.has(c)) + continue; //came from instance, don't save! + + Node *n=c.target->cast_to<Node>(); + if (!n) + continue; + + if (!node_map.has(n)) { + WARN_PRINT("Connection to node outside scene??") + continue; + } + + ConnectionData cd; + cd.from=node_map[p_node]; + cd.to=node_map[n]; + cd.method=_nm_get_string(c.method,name_map); + cd.signal=_nm_get_string(c.signal,name_map); + cd.flags=c.flags; + for(int i=0;i<c.binds.size();i++) { + + cd.binds.push_back( _vm_get_variant(c.binds[i],variant_map)); + } + connections.push_back(cd); + } + } + + for(int i=0;i<p_node->get_child_count();i++) { + + Node *c=p_node->get_child(i); + Error err = _parse_connections(p_owner,c,name_map,variant_map,node_map); + if (err) + return err; + } + + return OK; +} + + +Error PackedScene::pack(Node *p_scene) { + ERR_FAIL_NULL_V( p_scene, ERR_INVALID_PARAMETER ); + + + clear(); + + Node *scene = p_scene; + + Map<StringName,int> name_map; + HashMap<Variant,int,VariantHasher> variant_map; + Map<Node*,int> node_map; + + Error err = _parse_node(scene,scene,-1,name_map,variant_map,node_map); + if (err) { + clear(); + ERR_FAIL_V(err); + } + + err = _parse_connections(scene,scene,name_map,variant_map,node_map); + if (err) { + clear(); + ERR_FAIL_V(err); + } + + names.resize(name_map.size()); + + for(Map<StringName,int>::Element *E=name_map.front();E;E=E->next()) { + + names[E->get()]=E->key(); + } + + variants.resize(variant_map.size()); + const Variant *K=NULL; + while((K=variant_map.next(K))) { + + int idx = variant_map[*K]; + variants[idx]=*K; + } + + return OK; +} + +void PackedScene::clear() { + + names.clear(); + variants.clear(); + nodes.clear(); + connections.clear(); + +} + +void PackedScene::_set_bundled_scene(const Dictionary& d) { + + + ERR_FAIL_COND( !d.has("names")); + ERR_FAIL_COND( !d.has("variants")); + ERR_FAIL_COND( !d.has("node_count")); + ERR_FAIL_COND( !d.has("nodes")); + ERR_FAIL_COND( !d.has("conn_count")); + ERR_FAIL_COND( !d.has("conns")); +// ERR_FAIL_COND( !d.has("path")); + + DVector<String> snames = d["names"]; + if (snames.size()) { + + int namecount = snames.size(); + names.resize(namecount); + DVector<String>::Read r =snames.read(); + for(int i=0;i<names.size();i++) + names[i]=r[i]; + } + + Array svariants = d["variants"]; + + if (svariants.size()) { + int varcount=svariants.size(); + variants.resize(varcount); + for(int i=0;i<varcount;i++) { + + variants[i]=svariants[i]; + } + + } else { + variants.clear(); + } + + nodes.resize(d["node_count"]); + int nc=nodes.size(); + if (nc) { + DVector<int> snodes = d["nodes"]; + DVector<int>::Read r = snodes.read(); + int idx=0; + for(int i=0;i<nc;i++) { + NodeData &nd = nodes[i]; + nd.parent=r[idx++]; + nd.owner=r[idx++]; + nd.type=r[idx++]; + nd.name=r[idx++]; + nd.instance=r[idx++]; + nd.properties.resize(r[idx++]); + for(int j=0;j<nd.properties.size();j++) { + + nd.properties[j].name=r[idx++]; + nd.properties[j].value=r[idx++]; + } + nd.groups.resize(r[idx++]); + for(int j=0;j<nd.groups.size();j++) { + + nd.groups[j]=r[idx++]; + } + } + + } + + connections.resize(d["conn_count"]); + int cc=connections.size(); + + if (cc) { + + DVector<int> sconns = d["conns"]; + DVector<int>::Read r = sconns.read(); + int idx=0; + for(int i=0;i<cc;i++) { + ConnectionData &cd = connections[i]; + cd.from=r[idx++]; + cd.to=r[idx++]; + cd.signal=r[idx++]; + cd.method=r[idx++]; + cd.flags=r[idx++]; + cd.binds.resize(r[idx++]); + + for(int j=0;j<cd.binds.size();j++) { + + cd.binds[j]=r[idx++]; + } + } + + } + +// path=d["path"]; + +} + +Dictionary PackedScene::_get_bundled_scene() const { + + DVector<String> rnames; + rnames.resize(names.size()); + + if (names.size()) { + + DVector<String>::Write r=rnames.write(); + + for(int i=0;i<names.size();i++) + r[i]=names[i]; + } + + Dictionary d; + d["names"]=rnames; + d["variants"]=variants; + + Vector<int> rnodes; + d["node_count"]=nodes.size(); + + for(int i=0;i<nodes.size();i++) { + + const NodeData &nd=nodes[i]; + rnodes.push_back(nd.parent); + rnodes.push_back(nd.owner); + rnodes.push_back(nd.type); + rnodes.push_back(nd.name); + rnodes.push_back(nd.instance); + rnodes.push_back(nd.properties.size()); + for(int j=0;j<nd.properties.size();j++) { + + rnodes.push_back(nd.properties[j].name); + rnodes.push_back(nd.properties[j].value); + } + rnodes.push_back(nd.groups.size()); + for(int j=0;j<nd.groups.size();j++) { + + rnodes.push_back(nd.groups[j]); + } + } + + d["nodes"]=rnodes; + + Vector<int> rconns; + d["conn_count"]=connections.size(); + + for(int i=0;i<connections.size();i++) { + + const ConnectionData &cd=connections[i]; + rconns.push_back(cd.from); + rconns.push_back(cd.to); + rconns.push_back(cd.signal); + rconns.push_back(cd.method); + rconns.push_back(cd.flags); + rconns.push_back(cd.binds.size()); + for(int j=0;j<cd.binds.size();j++) + rconns.push_back(cd.binds[j]); + + } + + d["conns"]=rconns; + d["version"]=1; + +// d["path"]=path; + + return d; + + +} + +void PackedScene::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("pack","path:Node"),&PackedScene::pack); + ObjectTypeDB::bind_method(_MD("instance:Node"),&PackedScene::instance,DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("can_instance"),&PackedScene::can_instance); + ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&PackedScene::_set_bundled_scene); + ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&PackedScene::_get_bundled_scene); + + ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled"),_SCS("_set_bundled_scene"),_SCS("_get_bundled_scene")); + +} + +PackedScene::PackedScene() { + + +} diff --git a/script/SCsub b/script/SCsub deleted file mode 100644 index 7093dee36d..0000000000 --- a/script/SCsub +++ /dev/null @@ -1,16 +0,0 @@ -Import('env') - -env.script_sources=[] -env.add_source_files(env.script_sources,"*.cpp") - -Export('env') - -if (env["gdscript"]=="yes"): - SConscript('gdscript/SCsub'); -SConscript('multiscript/SCsub'); - -lib = env.Library("script",env.script_sources, LIBSUFFIX=env['platform_libsuffix']) - -env.Prepend(LIBS=[lib]) - - diff --git a/script/gdscript/SCsub b/script/gdscript/SCsub deleted file mode 100644 index dd812edec5..0000000000 --- a/script/gdscript/SCsub +++ /dev/null @@ -1,7 +0,0 @@ -Import('env') - -env.add_source_files(env.script_sources,"*.cpp") - -Export('env') - - diff --git a/script/multiscript/SCsub b/script/multiscript/SCsub deleted file mode 100644 index dd812edec5..0000000000 --- a/script/multiscript/SCsub +++ /dev/null @@ -1,7 +0,0 @@ -Import('env') - -env.add_source_files(env.script_sources,"*.cpp") - -Export('env') - - diff --git a/script/script_binder.cpp b/script/script_binder.cpp deleted file mode 100644 index 63c6d1d050..0000000000 --- a/script/script_binder.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/*************************************************/ -/* script_binder.cpp */ -/*************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/*************************************************/ -/* Source code within this file is: */ -/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */ -/* All Rights Reserved. */ -/*************************************************/ - -#include "script_binder.h" - diff --git a/script/script_binder.h b/script/script_binder.h deleted file mode 100644 index c3167a901d..0000000000 --- a/script/script_binder.h +++ /dev/null @@ -1,15 +0,0 @@ -/*************************************************/ -/* script_binder.h */ -/*************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/*************************************************/ -/* Source code within this file is: */ -/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */ -/* All Rights Reserved. */ -/*************************************************/ - -#ifndef SCRIPT_BINDER_H -#define SCRIPT_BINDER_H - -#endif // SCRIPT_BINDER_H diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index 14cae3dbb0..ffe47e0267 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -62,6 +62,7 @@ class Body2DSW : public CollisionObject2DSW { Vector2 applied_force; real_t applied_torque; + SelfList<Body2DSW> active_list; SelfList<Body2DSW> inertia_update_list; SelfList<Body2DSW> direct_state_query_list; diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp index 129c9ecb9c..0f08f63937 100644 --- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp +++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp @@ -434,8 +434,9 @@ void BroadPhase2DHashGrid::_cull(const Point2i p_cell,const Rect2& p_aabb,const if (E->key()->pass==pass) continue; - if (use_aabb && !p_aabb.intersects(E->key()->aabb)) + if (use_aabb && !p_aabb.intersects(E->key()->aabb)) { continue; + } if (use_segment && !E->key()->aabb.intersects_segment(p_from,p_to)) continue; diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index 3a5c8c3ade..e07dca472b 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -218,4 +218,5 @@ CollisionObject2DSW::CollisionObject2DSW(Type p_type) { type=p_type; space=NULL; instance_id=0; + user_mask=0; } diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index 74457cfa0a..8138cfcc69 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -65,6 +65,7 @@ private: Space2DSW *space; Matrix32 transform; Matrix32 inv_transform; + uint32_t user_mask; bool _static; void _update_shapes(); @@ -117,6 +118,8 @@ public: _FORCE_INLINE_ bool is_shape_set_as_trigger(int p_idx) const { return shapes[p_idx].trigger; } + void set_user_mask(uint32_t p_mask) {user_mask=p_mask;} + _FORCE_INLINE_ uint32_t get_user_mask() const { return user_mask; } void remove_shape(Shape2DSW *p_shape); void remove_shape(int p_index); diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp index fdbbebefcf..7d85183645 100644 --- a/servers/physics_2d/collision_solver_2d_sat.cpp +++ b/servers/physics_2d/collision_solver_2d_sat.cpp @@ -321,7 +321,7 @@ static void _generate_contacts_from_supports(const Vector2 * p_points_A,int p_po -template<class ShapeA, class ShapeB,bool castA=false,bool castB=false> +template<class ShapeA, class ShapeB,bool castA=false,bool castB=false, bool withMargin=false> class SeparatorAxisTest2D { const ShapeA *shape_A; @@ -334,6 +334,8 @@ class SeparatorAxisTest2D { int best_axis_index; Vector2 motion_A; Vector2 motion_B; + real_t margin_A; + real_t margin_B; _CollectorCallback2D *callback; public: @@ -397,6 +399,13 @@ public: else shape_B->project_range(axis,*transform_B,min_B,max_B); + if (withMargin) { + min_A-=margin_A; + max_A+=margin_A; + min_B-=margin_B; + max_B+=margin_B; + } + min_B -= ( max_A - min_A ) * 0.5; max_B += ( max_A - min_A ) * 0.5; @@ -468,6 +477,14 @@ public: } } + if (withMargin) { + + for(int i=0;i<support_count_A;i++) { + supports_A[i]+=-best_axis*margin_A; + } + + } + Vector2 supports_B[max_supports]; @@ -480,6 +497,15 @@ public: supports_B[i] = transform_B->xform(supports_B[i]); } } + + if (withMargin) { + + for(int i=0;i<support_count_B;i++) { + supports_B[i]+=best_axis*margin_B; + } + + } + /* @@ -517,7 +543,10 @@ public: } - _FORCE_INLINE_ SeparatorAxisTest2D(const ShapeA *p_shape_A,const Matrix32& p_transform_a, const ShapeB *p_shape_B,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_A=Vector2(), const Vector2& p_motion_B=Vector2()) { + _FORCE_INLINE_ SeparatorAxisTest2D(const ShapeA *p_shape_A,const Matrix32& p_transform_a, const ShapeB *p_shape_B,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_A=Vector2(), const Vector2& p_motion_B=Vector2(),real_t p_margin_A=0,real_t p_margin_B=0) { + + margin_A=p_margin_A; + margin_B=p_margin_B; best_depth=1e15; shape_A=p_shape_A; shape_B=p_shape_B; @@ -548,16 +577,16 @@ public: (castA && castB && !separator.test_axis(((m_a)+p_motion_a-((m_b)+p_motion_b)).normalized())) ) -typedef void (*CollisionFunc)(const Shape2DSW*,const Matrix32&,const Shape2DSW*,const Matrix32&,_CollectorCallback2D *p_collector,const Vector2&,const Vector2&); +typedef void (*CollisionFunc)(const Shape2DSW*,const Matrix32&,const Shape2DSW*,const Matrix32&,_CollectorCallback2D *p_collector,const Vector2&,const Vector2&,float,float); -template<bool castA, bool castB> -static void _collision_segment_segment(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_segment_segment(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW*>(p_a); const SegmentShape2DSW *segment_B = static_cast<const SegmentShape2DSW*>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW,SegmentShape2DSW,castA,castB> separator(segment_A,p_transform_a,segment_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<SegmentShape2DSW,SegmentShape2DSW,castA,castB,withMargin> separator(segment_A,p_transform_a,segment_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -570,24 +599,39 @@ static void _collision_segment_segment(const Shape2DSW* p_a,const Matrix32& p_tr if (!separator.test_cast()) return; + if (!separator.test_axis(segment_A->get_xformed_normal(p_transform_a))) return; if (!separator.test_axis(segment_B->get_xformed_normal(p_transform_b))) return; + if (withMargin) { + //points grow to circles + + + if (TEST_POINT( p_transform_a.xform(segment_A->get_a()),p_transform_b.xform(segment_B->get_a())) ) + return; + if (TEST_POINT( p_transform_a.xform(segment_A->get_a()),p_transform_b.xform(segment_B->get_b())) ) + return; + if (TEST_POINT( p_transform_a.xform(segment_A->get_b()),p_transform_b.xform(segment_B->get_a())) ) + return; + if (TEST_POINT( p_transform_a.xform(segment_A->get_b()),p_transform_b.xform(segment_B->get_b())) ) + return; + } + separator.generate_contacts(); } -template<bool castA, bool castB> -static void _collision_segment_circle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_segment_circle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW*>(p_a); const CircleShape2DSW *circle_B = static_cast<const CircleShape2DSW*>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW,CircleShape2DSW,castA,castB> separator(segment_A,p_transform_a,circle_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<SegmentShape2DSW,CircleShape2DSW,castA,castB,withMargin> separator(segment_A,p_transform_a,circle_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -612,13 +656,13 @@ static void _collision_segment_circle(const Shape2DSW* p_a,const Matrix32& p_tra separator.generate_contacts(); } -template<bool castA, bool castB> -static void _collision_segment_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_segment_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW*>(p_a); const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW*>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW,RectangleShape2DSW,castA,castB> separator(segment_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<SegmentShape2DSW,RectangleShape2DSW,castA,castB,withMargin> separator(segment_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -635,17 +679,55 @@ static void _collision_segment_rectangle(const Shape2DSW* p_a,const Matrix32& p_ if (!separator.test_axis(p_transform_b.elements[1].normalized())) return; + if (withMargin) { + + Matrix32 inv = p_transform_b.affine_inverse(); + + Vector2 a = p_transform_a.xform(segment_A->get_a()); + Vector2 b = p_transform_a.xform(segment_A->get_b()); + + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,a))) + return; + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,b))) + return; + + if (castA) { + + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,a+p_motion_a))) + return; + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,b+p_motion_a))) + return; + } + + if (castB) { + + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,a-p_motion_b))) + return; + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,b-p_motion_b))) + return; + } + + if (castA && castB) { + + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,a-p_motion_b+p_motion_a))) + return; + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,b-p_motion_b+p_motion_a))) + return; + } + + } + separator.generate_contacts(); } -template<bool castA, bool castB> -static void _collision_segment_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_segment_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW*>(p_a); const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW*>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW,CapsuleShape2DSW,castA,castB> separator(segment_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<SegmentShape2DSW,CapsuleShape2DSW,castA,castB,withMargin> separator(segment_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -671,13 +753,13 @@ static void _collision_segment_capsule(const Shape2DSW* p_a,const Matrix32& p_tr separator.generate_contacts(); } -template<bool castA, bool castB> -static void _collision_segment_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_segment_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW*>(p_a); const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW*>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW,ConvexPolygonShape2DSW,castA,castB> separator(segment_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<SegmentShape2DSW,ConvexPolygonShape2DSW,castA,castB,withMargin> separator(segment_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -692,6 +774,16 @@ static void _collision_segment_convex_polygon(const Shape2DSW* p_a,const Matrix3 if (!separator.test_axis( convex_B->get_xformed_segment_normal(p_transform_b,i))) return; + + if (withMargin) { + + if (TEST_POINT(p_transform_a.xform(segment_A->get_a()),p_transform_b.xform(convex_B->get_point(i) ))) + return; + if (TEST_POINT(p_transform_a.xform(segment_A->get_b()),p_transform_b.xform(convex_B->get_point(i) ))) + return; + + } + } separator.generate_contacts(); @@ -701,14 +793,14 @@ static void _collision_segment_convex_polygon(const Shape2DSW* p_a,const Matrix3 ///////// -template<bool castA, bool castB> -static void _collision_circle_circle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_circle_circle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW*>(p_a); const CircleShape2DSW *circle_B = static_cast<const CircleShape2DSW*>(p_b); - SeparatorAxisTest2D<CircleShape2DSW,CircleShape2DSW,castA,castB> separator(circle_A,p_transform_a,circle_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<CircleShape2DSW,CircleShape2DSW,castA,castB,withMargin> separator(circle_A,p_transform_a,circle_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -724,14 +816,14 @@ static void _collision_circle_circle(const Shape2DSW* p_a,const Matrix32& p_tran } -template<bool castA, bool castB> -static void _collision_circle_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_circle_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW*>(p_a); const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW*>(p_b); - SeparatorAxisTest2D<CircleShape2DSW,RectangleShape2DSW,castA,castB> separator(circle_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<CircleShape2DSW,RectangleShape2DSW,castA,castB,withMargin> separator(circle_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -741,7 +833,7 @@ static void _collision_circle_rectangle(const Shape2DSW* p_a,const Matrix32& p_t const Vector2 &sphere=p_transform_a.elements[2]; const Vector2 *axis=&p_transform_b.elements[0]; - const Vector2& half_extents = rectangle_B->get_half_extents(); +// const Vector2& half_extents = rectangle_B->get_half_extents(); if (!separator.test_axis(axis[0].normalized())) return; @@ -749,75 +841,45 @@ static void _collision_circle_rectangle(const Shape2DSW* p_a,const Matrix32& p_t if (!separator.test_axis(axis[1].normalized())) return; + Matrix32 binv = p_transform_b.affine_inverse(); { - Vector2 local_v = p_transform_b.affine_inverse().xform(p_transform_a.get_origin()); - - Vector2 he( - (local_v.x<0) ? -half_extents.x : half_extents.x, - (local_v.y<0) ? -half_extents.y : half_extents.y - ); - - if (!separator.test_axis((p_transform_b.xform(he)-sphere).normalized())) + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,binv,sphere ) ) ) return; } if (castA) { Vector2 sphereofs = sphere + p_motion_a; - Vector2 local_v = p_transform_b.affine_inverse().xform(sphereofs); - - Vector2 he( - (local_v.x<0) ? -half_extents.x : half_extents.x, - (local_v.y<0) ? -half_extents.y : half_extents.y - ); - - - if (!separator.test_axis((p_transform_b.xform(he)-sphereofs).normalized())) + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,binv, sphereofs) ) ) return; } if (castB) { Vector2 sphereofs = sphere - p_motion_b; - Vector2 local_v = p_transform_b.affine_inverse().xform(sphereofs); - - Vector2 he( - (local_v.x<0) ? -half_extents.x : half_extents.x, - (local_v.y<0) ? -half_extents.y : half_extents.y - ); - - - if (!separator.test_axis((p_transform_b.xform(he)-sphereofs).normalized())) + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,binv, sphereofs) ) ) return; } if (castA && castB) { Vector2 sphereofs = sphere - p_motion_b + p_motion_a; - Vector2 local_v = p_transform_b.affine_inverse().xform(sphereofs); - - Vector2 he( - (local_v.x<0) ? -half_extents.x : half_extents.x, - (local_v.y<0) ? -half_extents.y : half_extents.y - ); - - - if (!separator.test_axis((p_transform_b.xform(he)-sphereofs).normalized())) + if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,binv, sphereofs) ) ) return; } separator.generate_contacts(); } -template<bool castA, bool castB> -static void _collision_circle_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_circle_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW*>(p_a); const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW*>(p_b); - SeparatorAxisTest2D<CircleShape2DSW,CapsuleShape2DSW,castA,castB> separator(circle_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<CircleShape2DSW,CapsuleShape2DSW,castA,castB,withMargin> separator(circle_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -840,14 +902,14 @@ static void _collision_circle_capsule(const Shape2DSW* p_a,const Matrix32& p_tra } -template<bool castA, bool castB> -static void _collision_circle_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_circle_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW*>(p_a); const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW*>(p_b); - SeparatorAxisTest2D<CircleShape2DSW,ConvexPolygonShape2DSW,castA,castB> separator(circle_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<CircleShape2DSW,ConvexPolygonShape2DSW,castA,castB,withMargin> separator(circle_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -872,14 +934,14 @@ static void _collision_circle_convex_polygon(const Shape2DSW* p_a,const Matrix32 ///////// -template<bool castA, bool castB> -static void _collision_rectangle_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_rectangle_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW*>(p_a); const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW*>(p_b); - SeparatorAxisTest2D<RectangleShape2DSW,RectangleShape2DSW,castA,castB> separator(rectangle_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<RectangleShape2DSW,RectangleShape2DSW,castA,castB,withMargin> separator(rectangle_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -901,17 +963,56 @@ static void _collision_rectangle_rectangle(const Shape2DSW* p_a,const Matrix32& if (!separator.test_axis(p_transform_b.elements[1].normalized())) return; + if (withMargin) { + + Matrix32 invA=p_transform_a.affine_inverse(); + Matrix32 invB=p_transform_b.affine_inverse(); + + if (!separator.test_axis( rectangle_A->get_box_axis(p_transform_a,invA,rectangle_B,p_transform_b,invB) ) ) + return; + + if (castA || castB) { + + Matrix32 aofs = p_transform_a; + aofs.elements[2]+=p_motion_a; + + Matrix32 bofs = p_transform_b; + bofs.elements[2]+=p_motion_b; + + Matrix32 aofsinv = aofs.affine_inverse(); + Matrix32 bofsinv = bofs.affine_inverse(); + + if (castA) { + + if (!separator.test_axis( rectangle_A->get_box_axis(aofs,aofsinv,rectangle_B,p_transform_b,invB) ) ) + return; + } + + if (castB) { + + if (!separator.test_axis( rectangle_A->get_box_axis(p_transform_a,invA,rectangle_B,bofs,bofsinv) ) ) + return; + } + + if (castA && castB) { + + if (!separator.test_axis( rectangle_A->get_box_axis(aofs,aofsinv,rectangle_B,bofs,bofsinv) ) ) + return; + } + } + } + separator.generate_contacts(); } -template<bool castA, bool castB> -static void _collision_rectangle_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_rectangle_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW*>(p_a); const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW*>(p_b); - SeparatorAxisTest2D<RectangleShape2DSW,CapsuleShape2DSW,castA,castB> separator(rectangle_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<RectangleShape2DSW,CapsuleShape2DSW,castA,castB,withMargin> separator(rectangle_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -940,15 +1041,7 @@ static void _collision_rectangle_capsule(const Shape2DSW* p_a,const Matrix32& p_ { Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5); - const Vector2& half_extents = rectangle_A->get_half_extents(); - Vector2 local_v = boxinv.xform(capsule_endpoint); - - Vector2 he( - (local_v.x<0) ? -half_extents.x : half_extents.x, - (local_v.y<0) ? -half_extents.y : half_extents.y - ); - - if (!separator.test_axis(p_transform_a.xform(he-capsule_endpoint).normalized())) + if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,capsule_endpoint))) return; } @@ -957,16 +1050,7 @@ static void _collision_rectangle_capsule(const Shape2DSW* p_a,const Matrix32& p_ Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5); capsule_endpoint-=p_motion_a; - - const Vector2& half_extents = rectangle_A->get_half_extents(); - Vector2 local_v = boxinv.xform(capsule_endpoint); - - Vector2 he( - (local_v.x<0) ? -half_extents.x : half_extents.x, - (local_v.y<0) ? -half_extents.y : half_extents.y - ); - - if (!separator.test_axis(p_transform_a.xform(he-capsule_endpoint).normalized())) + if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,capsule_endpoint))) return; } @@ -974,16 +1058,7 @@ static void _collision_rectangle_capsule(const Shape2DSW* p_a,const Matrix32& p_ Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5); capsule_endpoint+=p_motion_b; - - const Vector2& half_extents = rectangle_A->get_half_extents(); - Vector2 local_v = boxinv.xform(capsule_endpoint); - - Vector2 he( - (local_v.x<0) ? -half_extents.x : half_extents.x, - (local_v.y<0) ? -half_extents.y : half_extents.y - ); - - if (!separator.test_axis(p_transform_a.xform(he-capsule_endpoint).normalized())) + if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,capsule_endpoint))) return; } @@ -993,15 +1068,7 @@ static void _collision_rectangle_capsule(const Shape2DSW* p_a,const Matrix32& p_ capsule_endpoint+=p_motion_b; - const Vector2& half_extents = rectangle_A->get_half_extents(); - Vector2 local_v = boxinv.xform(capsule_endpoint); - - Vector2 he( - (local_v.x<0) ? -half_extents.x : half_extents.x, - (local_v.y<0) ? -half_extents.y : half_extents.y - ); - - if (!separator.test_axis(p_transform_a.xform(he-capsule_endpoint).normalized())) + if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,capsule_endpoint))) return; } @@ -1011,13 +1078,13 @@ static void _collision_rectangle_capsule(const Shape2DSW* p_a,const Matrix32& p_ separator.generate_contacts(); } -template<bool castA, bool castB> -static void _collision_rectangle_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_rectangle_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW*>(p_a); const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW*>(p_b); - SeparatorAxisTest2D<RectangleShape2DSW,ConvexPolygonShape2DSW,castA,castB> separator(rectangle_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<RectangleShape2DSW,ConvexPolygonShape2DSW,castA,castB,withMargin> separator(rectangle_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -1033,10 +1100,36 @@ static void _collision_rectangle_convex_polygon(const Shape2DSW* p_a,const Matri return; //convex faces + Matrix32 boxinv; + if (withMargin) { + boxinv=p_transform_a.affine_inverse(); + } for(int i=0;i<convex_B->get_point_count();i++) { if (!separator.test_axis( convex_B->get_xformed_segment_normal(p_transform_b,i))) return; + + if (withMargin) { + //all points vs all points need to be tested if margin exist + if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,p_transform_b.xform(convex_B->get_point(i))))) + return; + if (castA) { + + if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,p_transform_b.xform(convex_B->get_point(i))-p_motion_a))) + return; + } + if (castB) { + + if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,p_transform_b.xform(convex_B->get_point(i))+p_motion_b))) + return; + } + if (castA && castB) { + + if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,p_transform_b.xform(convex_B->get_point(i))+p_motion_b-p_motion_a))) + return; + } + + } } separator.generate_contacts(); @@ -1046,14 +1139,14 @@ static void _collision_rectangle_convex_polygon(const Shape2DSW* p_a,const Matri ///////// -template<bool castA, bool castB> -static void _collision_capsule_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_capsule_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const CapsuleShape2DSW *capsule_A = static_cast<const CapsuleShape2DSW*>(p_a); const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW*>(p_b); - SeparatorAxisTest2D<CapsuleShape2DSW,CapsuleShape2DSW,castA,castB> separator(capsule_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<CapsuleShape2DSW,CapsuleShape2DSW,castA,castB,withMargin> separator(capsule_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -1089,14 +1182,14 @@ static void _collision_capsule_capsule(const Shape2DSW* p_a,const Matrix32& p_tr } -template<bool castA, bool castB> -static void _collision_capsule_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_capsule_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const CapsuleShape2DSW *capsule_A = static_cast<const CapsuleShape2DSW*>(p_a); const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW*>(p_b); - SeparatorAxisTest2D<CapsuleShape2DSW,ConvexPolygonShape2DSW,castA,castB> separator(capsule_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<CapsuleShape2DSW,ConvexPolygonShape2DSW,castA,castB,withMargin> separator(capsule_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -1135,14 +1228,14 @@ static void _collision_capsule_convex_polygon(const Shape2DSW* p_a,const Matrix3 ///////// -template<bool castA, bool castB> -static void _collision_convex_polygon_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) { +template<bool castA, bool castB,bool withMargin> +static void _collision_convex_polygon_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) { const ConvexPolygonShape2DSW *convex_A = static_cast<const ConvexPolygonShape2DSW*>(p_a); const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW*>(p_b); - SeparatorAxisTest2D<ConvexPolygonShape2DSW,ConvexPolygonShape2DSW,castA,castB> separator(convex_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b); + SeparatorAxisTest2D<ConvexPolygonShape2DSW,ConvexPolygonShape2DSW,castA,castB,withMargin> separator(convex_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B); if (!separator.test_previous_axis()) return; @@ -1161,6 +1254,19 @@ static void _collision_convex_polygon_convex_polygon(const Shape2DSW* p_a,const if (!separator.test_axis( convex_B->get_xformed_segment_normal(p_transform_b,i))) return; + + } + + if (withMargin) { + + for(int i=0;i<convex_A->get_point_count();i++) { + for(int j=0;j<convex_B->get_point_count();j++) { + + if (TEST_POINT(p_transform_a.xform(convex_A->get_point(i)) , p_transform_b.xform(convex_B->get_point(j)))) + return; + } + } + } separator.generate_contacts(); @@ -1170,7 +1276,7 @@ static void _collision_convex_polygon_convex_polygon(const Shape2DSW* p_a,const //////// -bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Matrix32& p_transform_A, const Vector2& p_motion_A, const Shape2DSW *p_shape_B, const Matrix32& p_transform_B,const Vector2& p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback,void *p_userdata, bool p_swap,Vector2 *sep_axis) { +bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Matrix32& p_transform_A, const Vector2& p_motion_A, const Shape2DSW *p_shape_B, const Matrix32& p_transform_B,const Vector2& p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback,void *p_userdata, bool p_swap,Vector2 *sep_axis,float p_margin_A,float p_margin_B) { Physics2DServer::ShapeType type_A=p_shape_A->get_type(); @@ -1186,121 +1292,238 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Matrix32& p_ static const CollisionFunc collision_table[5][5]={ - {_collision_segment_segment<false,false>, - _collision_segment_circle<false,false>, - _collision_segment_rectangle<false,false>, - _collision_segment_capsule<false,false>, - _collision_segment_convex_polygon<false,false>}, + {_collision_segment_segment<false,false,false>, + _collision_segment_circle<false,false,false>, + _collision_segment_rectangle<false,false,false>, + _collision_segment_capsule<false,false,false>, + _collision_segment_convex_polygon<false,false,false>}, {0, - _collision_circle_circle<false,false>, - _collision_circle_rectangle<false,false>, - _collision_circle_capsule<false,false>, - _collision_circle_convex_polygon<false,false>}, + _collision_circle_circle<false,false,false>, + _collision_circle_rectangle<false,false,false>, + _collision_circle_capsule<false,false,false>, + _collision_circle_convex_polygon<false,false,false>}, {0, 0, - _collision_rectangle_rectangle<false,false>, - _collision_rectangle_capsule<false,false>, - _collision_rectangle_convex_polygon<false,false>}, + _collision_rectangle_rectangle<false,false,false>, + _collision_rectangle_capsule<false,false,false>, + _collision_rectangle_convex_polygon<false,false,false>}, {0, 0, 0, - _collision_capsule_capsule<false,false>, - _collision_capsule_convex_polygon<false,false>}, + _collision_capsule_capsule<false,false,false>, + _collision_capsule_convex_polygon<false,false,false>}, {0, 0, 0, 0, - _collision_convex_polygon_convex_polygon<false,false>} + _collision_convex_polygon_convex_polygon<false,false,false>} }; static const CollisionFunc collision_table_castA[5][5]={ - {_collision_segment_segment<true,false>, - _collision_segment_circle<true,false>, - _collision_segment_rectangle<true,false>, - _collision_segment_capsule<true,false>, - _collision_segment_convex_polygon<true,false>}, + {_collision_segment_segment<true,false,false>, + _collision_segment_circle<true,false,false>, + _collision_segment_rectangle<true,false,false>, + _collision_segment_capsule<true,false,false>, + _collision_segment_convex_polygon<true,false,false>}, {0, - _collision_circle_circle<true,false>, - _collision_circle_rectangle<true,false>, - _collision_circle_capsule<true,false>, - _collision_circle_convex_polygon<true,false>}, + _collision_circle_circle<true,false,false>, + _collision_circle_rectangle<true,false,false>, + _collision_circle_capsule<true,false,false>, + _collision_circle_convex_polygon<true,false,false>}, {0, 0, - _collision_rectangle_rectangle<true,false>, - _collision_rectangle_capsule<true,false>, - _collision_rectangle_convex_polygon<true,false>}, + _collision_rectangle_rectangle<true,false,false>, + _collision_rectangle_capsule<true,false,false>, + _collision_rectangle_convex_polygon<true,false,false>}, {0, 0, 0, - _collision_capsule_capsule<true,false>, - _collision_capsule_convex_polygon<true,false>}, + _collision_capsule_capsule<true,false,false>, + _collision_capsule_convex_polygon<true,false,false>}, {0, 0, 0, 0, - _collision_convex_polygon_convex_polygon<true,false>} + _collision_convex_polygon_convex_polygon<true,false,false>} }; static const CollisionFunc collision_table_castB[5][5]={ - {_collision_segment_segment<false,true>, - _collision_segment_circle<false,true>, - _collision_segment_rectangle<false,true>, - _collision_segment_capsule<false,true>, - _collision_segment_convex_polygon<false,true>}, + {_collision_segment_segment<false,true,false>, + _collision_segment_circle<false,true,false>, + _collision_segment_rectangle<false,true,false>, + _collision_segment_capsule<false,true,false>, + _collision_segment_convex_polygon<false,true,false>}, {0, - _collision_circle_circle<false,true>, - _collision_circle_rectangle<false,true>, - _collision_circle_capsule<false,true>, - _collision_circle_convex_polygon<false,true>}, + _collision_circle_circle<false,true,false>, + _collision_circle_rectangle<false,true,false>, + _collision_circle_capsule<false,true,false>, + _collision_circle_convex_polygon<false,true,false>}, {0, 0, - _collision_rectangle_rectangle<false,true>, - _collision_rectangle_capsule<false,true>, - _collision_rectangle_convex_polygon<false,true>}, + _collision_rectangle_rectangle<false,true,false>, + _collision_rectangle_capsule<false,true,false>, + _collision_rectangle_convex_polygon<false,true,false>}, {0, 0, 0, - _collision_capsule_capsule<false,true>, - _collision_capsule_convex_polygon<false,true>}, + _collision_capsule_capsule<false,true,false>, + _collision_capsule_convex_polygon<false,true,false>}, {0, 0, 0, 0, - _collision_convex_polygon_convex_polygon<false,true>} + _collision_convex_polygon_convex_polygon<false,true,false>} }; static const CollisionFunc collision_table_castA_castB[5][5]={ - {_collision_segment_segment<true,true>, - _collision_segment_circle<true,true>, - _collision_segment_rectangle<true,true>, - _collision_segment_capsule<true,true>, - _collision_segment_convex_polygon<true,true>}, + {_collision_segment_segment<true,true,false>, + _collision_segment_circle<true,true,false>, + _collision_segment_rectangle<true,true,false>, + _collision_segment_capsule<true,true,false>, + _collision_segment_convex_polygon<true,true,false>}, + {0, + _collision_circle_circle<true,true,false>, + _collision_circle_rectangle<true,true,false>, + _collision_circle_capsule<true,true,false>, + _collision_circle_convex_polygon<true,true,false>}, + {0, + 0, + _collision_rectangle_rectangle<true,true,false>, + _collision_rectangle_capsule<true,true,false>, + _collision_rectangle_convex_polygon<true,true,false>}, + {0, + 0, + 0, + _collision_capsule_capsule<true,true,false>, + _collision_capsule_convex_polygon<true,true,false>}, + {0, + 0, + 0, + 0, + _collision_convex_polygon_convex_polygon<true,true,false>} + + }; + + static const CollisionFunc collision_table_margin[5][5]={ + {_collision_segment_segment<false,false,true>, + _collision_segment_circle<false,false,true>, + _collision_segment_rectangle<false,false,true>, + _collision_segment_capsule<false,false,true>, + _collision_segment_convex_polygon<false,false,true>}, + {0, + _collision_circle_circle<false,false,true>, + _collision_circle_rectangle<false,false,true>, + _collision_circle_capsule<false,false,true>, + _collision_circle_convex_polygon<false,false,true>}, + {0, + 0, + _collision_rectangle_rectangle<false,false,true>, + _collision_rectangle_capsule<false,false,true>, + _collision_rectangle_convex_polygon<false,false,true>}, {0, - _collision_circle_circle<true,true>, - _collision_circle_rectangle<true,true>, - _collision_circle_capsule<true,true>, - _collision_circle_convex_polygon<true,true>}, + 0, + 0, + _collision_capsule_capsule<false,false,true>, + _collision_capsule_convex_polygon<false,false,true>}, + {0, + 0, + 0, + 0, + _collision_convex_polygon_convex_polygon<false,false,true>} + + }; + + static const CollisionFunc collision_table_castA_margin[5][5]={ + {_collision_segment_segment<true,false,true>, + _collision_segment_circle<true,false,true>, + _collision_segment_rectangle<true,false,true>, + _collision_segment_capsule<true,false,true>, + _collision_segment_convex_polygon<true,false,true>}, + {0, + _collision_circle_circle<true,false,true>, + _collision_circle_rectangle<true,false,true>, + _collision_circle_capsule<true,false,true>, + _collision_circle_convex_polygon<true,false,true>}, + {0, + 0, + _collision_rectangle_rectangle<true,false,true>, + _collision_rectangle_capsule<true,false,true>, + _collision_rectangle_convex_polygon<true,false,true>}, + {0, + 0, + 0, + _collision_capsule_capsule<true,false,true>, + _collision_capsule_convex_polygon<true,false,true>}, + {0, + 0, + 0, + 0, + _collision_convex_polygon_convex_polygon<true,false,true>} + + }; + + static const CollisionFunc collision_table_castB_margin[5][5]={ + {_collision_segment_segment<false,true,true>, + _collision_segment_circle<false,true,true>, + _collision_segment_rectangle<false,true,true>, + _collision_segment_capsule<false,true,true>, + _collision_segment_convex_polygon<false,true,true>}, + {0, + _collision_circle_circle<false,true,true>, + _collision_circle_rectangle<false,true,true>, + _collision_circle_capsule<false,true,true>, + _collision_circle_convex_polygon<false,true,true>}, + {0, + 0, + _collision_rectangle_rectangle<false,true,true>, + _collision_rectangle_capsule<false,true,true>, + _collision_rectangle_convex_polygon<false,true,true>}, + {0, + 0, + 0, + _collision_capsule_capsule<false,true,true>, + _collision_capsule_convex_polygon<false,true,true>}, + {0, + 0, + 0, + 0, + _collision_convex_polygon_convex_polygon<false,true,true>} + + }; + + static const CollisionFunc collision_table_castA_castB_margin[5][5]={ + {_collision_segment_segment<true,true,true>, + _collision_segment_circle<true,true,true>, + _collision_segment_rectangle<true,true,true>, + _collision_segment_capsule<true,true,true>, + _collision_segment_convex_polygon<true,true,true>}, + {0, + _collision_circle_circle<true,true,true>, + _collision_circle_rectangle<true,true,true>, + _collision_circle_capsule<true,true,true>, + _collision_circle_convex_polygon<true,true,true>}, {0, 0, - _collision_rectangle_rectangle<true,true>, - _collision_rectangle_capsule<true,true>, - _collision_rectangle_convex_polygon<true,true>}, + _collision_rectangle_rectangle<true,true,true>, + _collision_rectangle_capsule<true,true,true>, + _collision_rectangle_convex_polygon<true,true,true>}, {0, 0, 0, - _collision_capsule_capsule<true,true>, - _collision_capsule_convex_polygon<true,true>}, + _collision_capsule_capsule<true,true,true>, + _collision_capsule_convex_polygon<true,true,true>}, {0, 0, 0, 0, - _collision_convex_polygon_convex_polygon<true,true>} + _collision_convex_polygon_convex_polygon<true,true,true>} }; + _CollectorCallback2D callback; callback.callback=p_result_callback; callback.swap=p_swap; @@ -1314,32 +1537,49 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Matrix32& p_ const Matrix32 *transform_B=&p_transform_B; const Vector2 *motion_A=&p_motion_A; const Vector2 *motion_B=&p_motion_B; + real_t margin_A=p_margin_A,margin_B=p_margin_B; if (type_A > type_B) { SWAP(A,B); SWAP(transform_A,transform_B); SWAP(type_A,type_B); SWAP(motion_A,motion_B); + SWAP(margin_A,margin_B); callback.swap = !callback.swap; } CollisionFunc collision_func; - if (*motion_A==Vector2() && *motion_B==Vector2()) { - collision_func = collision_table[type_A-2][type_B-2]; - } else if (*motion_A!=Vector2() && *motion_B==Vector2()) { - collision_func = collision_table_castA[type_A-2][type_B-2]; - } else if (*motion_A==Vector2() && *motion_B!=Vector2()) { - collision_func = collision_table_castB[type_A-2][type_B-2]; + + if (p_margin_A || p_margin_B) { + if (*motion_A==Vector2() && *motion_B==Vector2()) { + collision_func = collision_table_margin[type_A-2][type_B-2]; + } else if (*motion_A!=Vector2() && *motion_B==Vector2()) { + collision_func = collision_table_castA_margin[type_A-2][type_B-2]; + } else if (*motion_A==Vector2() && *motion_B!=Vector2()) { + collision_func = collision_table_castB_margin[type_A-2][type_B-2]; + } else { + collision_func = collision_table_castA_castB_margin[type_A-2][type_B-2]; + } } else { - collision_func = collision_table_castA_castB[type_A-2][type_B-2]; + + if (*motion_A==Vector2() && *motion_B==Vector2()) { + collision_func = collision_table[type_A-2][type_B-2]; + } else if (*motion_A!=Vector2() && *motion_B==Vector2()) { + collision_func = collision_table_castA[type_A-2][type_B-2]; + } else if (*motion_A==Vector2() && *motion_B!=Vector2()) { + collision_func = collision_table_castB[type_A-2][type_B-2]; + } else { + collision_func = collision_table_castA_castB[type_A-2][type_B-2]; + } + } ERR_FAIL_COND_V(!collision_func,false); - collision_func(A,*transform_A,B,*transform_B,&callback,*motion_A,*motion_B); + collision_func(A,*transform_A,B,*transform_B,&callback,*motion_A,*motion_B,margin_A,margin_B); return callback.collided; diff --git a/servers/physics_2d/collision_solver_2d_sat.h b/servers/physics_2d/collision_solver_2d_sat.h index 95468a18b8..be5a3dc79f 100644 --- a/servers/physics_2d/collision_solver_2d_sat.h +++ b/servers/physics_2d/collision_solver_2d_sat.h @@ -32,6 +32,6 @@ #include "collision_solver_2d_sw.h" -bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Matrix32& p_transform_A, const Vector2& p_motion_A,const Shape2DSW *p_shape_B, const Matrix32& p_transform_B,const Vector2& p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback,void *p_userdata, bool p_swap=false,Vector2 *sep_axis=NULL); +bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Matrix32& p_transform_A, const Vector2& p_motion_A,const Shape2DSW *p_shape_B, const Matrix32& p_transform_B,const Vector2& p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback,void *p_userdata, bool p_swap=false,Vector2 *sep_axis=NULL,float p_margin_A=0,float p_margin_B=0); #endif // COLLISION_SOLVER_2D_SAT_H diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp index 5d43510aea..4c7e68d643 100644 --- a/servers/physics_2d/collision_solver_2d_sw.cpp +++ b/servers/physics_2d/collision_solver_2d_sw.cpp @@ -150,6 +150,8 @@ struct _ConcaveCollisionInfo2D { const Matrix32 *transform_B; Vector2 motion_A; Vector2 motion_B; + real_t margin_A; + real_t margin_B; CollisionSolver2DSW::CallbackResult result_callback; void *userdata; bool swap_result; @@ -169,7 +171,7 @@ void CollisionSolver2DSW::concave_callback(void *p_userdata, Shape2DSW *p_convex if (!cinfo.result_callback && cinfo.collided) return; //already collided and no contacts requested, don't test anymore - bool collided = collision_solver(cinfo.shape_A, *cinfo.transform_A, cinfo.motion_A, p_convex,*cinfo.transform_B, cinfo.motion_B, cinfo.result_callback, cinfo.userdata, cinfo.swap_result,cinfo.sep_axis ); + bool collided = collision_solver(cinfo.shape_A, *cinfo.transform_A, cinfo.motion_A, p_convex,*cinfo.transform_B, cinfo.motion_B, cinfo.result_callback, cinfo.userdata, cinfo.swap_result,cinfo.sep_axis,cinfo.margin_A,cinfo.margin_B ); if (!collided) return; @@ -179,7 +181,7 @@ void CollisionSolver2DSW::concave_callback(void *p_userdata, Shape2DSW *p_convex } -bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Vector2& p_motion_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,const Vector2& p_motion_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result,Vector2 *sep_axis) { +bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Vector2& p_motion_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,const Vector2& p_motion_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result,Vector2 *sep_axis,float p_margin_A,float p_margin_B) { const ConcaveShape2DSW *concave_B=static_cast<const ConcaveShape2DSW*>(p_shape_B); @@ -195,6 +197,8 @@ bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A,const Matrix3 cinfo.collided=false; cinfo.collisions=0; cinfo.sep_axis=sep_axis; + cinfo.margin_A=p_margin_A; + cinfo.margin_B=p_margin_B; cinfo.aabb_tests=0; @@ -227,7 +231,7 @@ bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A,const Matrix3 } -bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Vector2& p_motion_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,const Vector2& p_motion_B,CallbackResult p_result_callback,void *p_userdata,Vector2 *sep_axis) { +bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Vector2& p_motion_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,const Vector2& p_motion_B,CallbackResult p_result_callback,void *p_userdata,Vector2 *sep_axis,float p_margin_A,float p_margin_B) { @@ -236,12 +240,14 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A,const Matrix32& p_tra Physics2DServer::ShapeType type_B=p_shape_B->get_type(); bool concave_A=p_shape_A->is_concave(); bool concave_B=p_shape_B->is_concave(); + real_t margin_A=p_margin_A,margin_B=p_margin_B; bool swap = false; if (type_A>type_B) { SWAP(type_A,type_B); SWAP(concave_A,concave_B); + SWAP(margin_A,margin_B); swap=true; } @@ -292,16 +298,16 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A,const Matrix32& p_tra return false; if (!swap) - return solve_concave(p_shape_A,p_transform_A,p_motion_A,p_shape_B,p_transform_B,p_motion_B,p_result_callback,p_userdata,false,sep_axis); + return solve_concave(p_shape_A,p_transform_A,p_motion_A,p_shape_B,p_transform_B,p_motion_B,p_result_callback,p_userdata,false,sep_axis,margin_A,margin_B); else - return solve_concave(p_shape_B,p_transform_B,p_motion_B,p_shape_A,p_transform_A,p_motion_A,p_result_callback,p_userdata,true,sep_axis); + return solve_concave(p_shape_B,p_transform_B,p_motion_B,p_shape_A,p_transform_A,p_motion_A,p_result_callback,p_userdata,true,sep_axis,margin_A,margin_B); } else { - return collision_solver(p_shape_A, p_transform_A,p_motion_A, p_shape_B, p_transform_B, p_motion_B,p_result_callback,p_userdata,false,sep_axis); + return collision_solver(p_shape_A, p_transform_A,p_motion_A, p_shape_B, p_transform_B, p_motion_B,p_result_callback,p_userdata,false,sep_axis,margin_A,margin_B); } diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/collision_solver_2d_sw.h index 11b5701f46..07141b0d09 100644 --- a/servers/physics_2d/collision_solver_2d_sw.h +++ b/servers/physics_2d/collision_solver_2d_sw.h @@ -37,14 +37,14 @@ public: private: static bool solve_static_line(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result); static void concave_callback(void *p_userdata, Shape2DSW *p_convex); - static bool solve_concave(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Vector2& p_motion_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,const Vector2& p_motion_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result,Vector2 *sep_axis=NULL); + static bool solve_concave(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Vector2& p_motion_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,const Vector2& p_motion_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result,Vector2 *sep_axis=NULL,float p_margin_A=0,float p_margin_B=0); static bool solve_raycast(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result,Vector2 *sep_axis=NULL); public: - static bool solve(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Vector2& p_motion_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,const Vector2& p_motion_B,CallbackResult p_result_callback,void *p_userdata,Vector2 *sep_axis=NULL); + static bool solve(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Vector2& p_motion_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,const Vector2& p_motion_B,CallbackResult p_result_callback,void *p_userdata,Vector2 *sep_axis=NULL,float p_margin_A=0,float p_margin_B=0); }; diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 0fbd461f46..fd1ea579f0 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -132,8 +132,12 @@ real_t Physics2DServerSW::shape_get_custom_solver_bias(RID p_shape) const { void Physics2DServerSW::_shape_col_cbk(const Vector2& p_point_A,const Vector2& p_point_B,void *p_userdata) { + CollCbkData *cbk=(CollCbkData *)p_userdata; + if (cbk->max==0) + return; + if (cbk->amount == cbk->max) { //find least deep float min_depth=1e20; @@ -159,6 +163,7 @@ void Physics2DServerSW::_shape_col_cbk(const Vector2& p_point_A,const Vector2& p cbk->ptr[cbk->amount*2+0]=p_point_A; cbk->ptr[cbk->amount*2+1]=p_point_B; + cbk->amount++; } } @@ -648,19 +653,20 @@ uint32_t Physics2DServerSW::body_get_object_instance_ID(RID p_body) const { }; -void Physics2DServerSW::body_set_user_flags(RID p_body, uint32_t p_flags) { +void Physics2DServerSW::body_set_user_mask(RID p_body, uint32_t p_flags) { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); + body->set_user_mask(p_flags); }; -uint32_t Physics2DServerSW::body_get_user_flags(RID p_body, uint32_t p_flags) const { +uint32_t Physics2DServerSW::body_get_user_mask(RID p_body, uint32_t p_flags) const { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND_V(!body,0); - return 0; + return body->get_user_mask(); }; void Physics2DServerSW::body_set_param(RID p_body, BodyParameter p_param, float p_value) { diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index ef00eae7e4..e50bb0ab96 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -58,6 +58,12 @@ friend class Physics2DDirectSpaceStateSW; mutable RID_Owner<Body2DSW> body_owner; mutable RID_Owner<Joint2DSW> joint_owner; + + + +// void _clear_query(Query2DSW *p_query); +public: + struct CollCbkData { int max; @@ -68,9 +74,6 @@ friend class Physics2DDirectSpaceStateSW; static void _shape_col_cbk(const Vector2& p_point_A,const Vector2& p_point_B,void *p_userdata); -// void _clear_query(Query2DSW *p_query); -public: - virtual RID shape_create(ShapeType p_shape); virtual void shape_set_data(RID p_shape, const Variant& p_data); virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias); @@ -158,8 +161,8 @@ public: virtual void body_set_continuous_collision_detection_mode(RID p_body,CCDMode p_mode); virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const; - virtual void body_set_user_flags(RID p_body, uint32_t p_flags); - virtual uint32_t body_get_user_flags(RID p_body, uint32_t p_flags) const; + virtual void body_set_user_mask(RID p_body, uint32_t p_mask); + virtual uint32_t body_get_user_mask(RID p_body, uint32_t p_mask) const; virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value); virtual float body_get_param(RID p_body, BodyParameter p_param) const; diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h index ba5f60cb32..d3fcf1fab2 100644 --- a/servers/physics_2d/shape_2d_sw.h +++ b/servers/physics_2d/shape_2d_sw.h @@ -354,6 +354,51 @@ public: r_max = distance + length; } + + + _FORCE_INLINE_ Vector2 get_circle_axis(const Matrix32& p_xform, const Matrix32& p_xform_inv,const Vector2& p_circle) const { + + Vector2 local_v = p_xform_inv.xform(p_circle); + + Vector2 he( + (local_v.x<0) ? -half_extents.x : half_extents.x, + (local_v.y<0) ? -half_extents.y : half_extents.y + ); + + return (p_xform.xform(he)-p_circle).normalized(); + } + + _FORCE_INLINE_ Vector2 get_box_axis(const Matrix32& p_xform, const Matrix32& p_xform_inv,const RectangleShape2DSW *p_B,const Matrix32& p_B_xform, const Matrix32& p_B_xform_inv) const { + + Vector2 a,b; + + { + Vector2 local_v = p_xform_inv.xform(p_B_xform.get_origin()); + + Vector2 he( + (local_v.x<0) ? -half_extents.x : half_extents.x, + (local_v.y<0) ? -half_extents.y : half_extents.y + ); + + a=p_xform.xform(he); + + } + { + Vector2 local_v = p_B_xform_inv.xform(p_xform.get_origin()); + + Vector2 he( + (local_v.x<0) ? -p_B->half_extents.x : p_B->half_extents.x, + (local_v.y<0) ? -p_B->half_extents.y : p_B->half_extents.y + ); + + b=p_B_xform.xform(he); + + } + + return (a-b).normalized(); + } + + DEFAULT_PROJECT_RANGE_CAST }; diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 2c714f5065..d1aec92984 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -31,7 +31,22 @@ #include "physics_2d_server_sw.h" -bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set<RID>& p_exclude,uint32_t p_user_mask) { +_FORCE_INLINE_ static bool _match_object_type_query(CollisionObject2DSW *p_object, uint32_t p_user_mask, uint32_t p_type_mask) { + + if (p_user_mask && !(p_object->get_user_mask()&p_user_mask)) + return false; + + if (p_object->get_type()==CollisionObject2DSW::TYPE_AREA && !(p_type_mask&Physics2DDirectSpaceState::TYPE_MASK_AREA)) + return false; + + Body2DSW *body = static_cast<Body2DSW*>(p_object); + + return (1<<body->get_mode())&p_type_mask; + +} + +bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set<RID>& p_exclude,uint32_t p_user_mask,uint32_t p_object_type_mask) { + ERR_FAIL_COND_V(space->locked,false); @@ -55,8 +70,8 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vec for(int i=0;i<amount;i++) { - if (space->intersection_query_results[i]->get_type()==CollisionObject2DSW::TYPE_AREA) - continue; //ignore area + if (!_match_object_type_query(space->intersection_query_results[i],p_user_mask,p_object_type_mask)) + continue; if (p_exclude.has( space->intersection_query_results[i]->get_self())) continue; @@ -120,7 +135,7 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vec } -int Physics2DDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude,uint32_t p_user_mask) { +int Physics2DDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude,uint32_t p_user_mask,uint32_t p_object_type_mask) { if (p_result_max<=0) return 0; @@ -129,6 +144,7 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Matri ERR_FAIL_COND_V(!shape,0); Rect2 aabb = p_xform.xform(shape->get_aabb()); + aabb=aabb.grow(p_margin); int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results); @@ -137,11 +153,8 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Matri for(int i=0;i<amount;i++) { - if (cc>=p_result_max) - break; - - if (space->intersection_query_results[i]->get_type()==CollisionObject2DSW::TYPE_AREA) - continue; //ignore area + if (!_match_object_type_query(space->intersection_query_results[i],p_user_mask,p_object_type_mask)) + continue; if (p_exclude.has( space->intersection_query_results[i]->get_self())) continue; @@ -150,7 +163,7 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Matri const CollisionObject2DSW *col_obj=space->intersection_query_results[i]; int shape_idx=space->intersection_query_subindex_results[i]; - if (!CollisionSolver2DSW::solve(shape,p_xform,p_motion,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2(),NULL,NULL,NULL)) + if (!CollisionSolver2DSW::solve(shape,p_xform,p_motion,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2(),NULL,NULL,NULL,p_margin)) continue; r_results[cc].collider_id=col_obj->get_instance_id(); @@ -168,193 +181,235 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Matri } -struct MotionCallbackRayCastData { - Vector2 best_contact; - Vector2 best_normal; - float best_len; - Matrix32 b_xform_inv; - Matrix32 b_xform; - Vector2 motion; - Shape2DSW * shape_B; +bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,float &p_closest_safe,float &p_closest_unsafe, const Set<RID>& p_exclude,uint32_t p_user_mask,uint32_t p_object_type_mask) { -}; -static void _motion_cbk_result(const Vector2& p_point_A,const Vector2& p_point_B,void *p_userdata) { + Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape); + ERR_FAIL_COND_V(!shape,false); + + Rect2 aabb = p_xform.xform(shape->get_aabb()); + aabb=aabb.merge(Rect2(aabb.pos+p_motion,aabb.size)); //motion + aabb=aabb.grow(p_margin); - MotionCallbackRayCastData *rd=(MotionCallbackRayCastData*)p_userdata; + //if (p_motion!=Vector2()) + // print_line(p_motion); - Vector2 contact_normal = (p_point_B-p_point_A).normalized(); + int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results); - Vector2 from=p_point_A-(rd->motion*1.01); - Vector2 p,n; + float best_safe=1; + float best_unsafe=1; + + for(int i=0;i<amount;i++) { - if (contact_normal.dot(rd->motion.normalized())<CMP_EPSILON) { - //safe to assume it was a perpendicular collision - n=contact_normal; - p=p_point_B; - } else { - //entered in a different angle - Vector2 to = p_point_A+rd->motion; //avoid precission issues + if (!_match_object_type_query(space->intersection_query_results[i],p_user_mask,p_object_type_mask)) + continue; + + if (p_exclude.has( space->intersection_query_results[i]->get_self())) + continue; //ignore excluded - bool res = rd->shape_B->intersect_segment(rd->b_xform_inv.xform(from),rd->b_xform_inv.xform(to),p,n); + const CollisionObject2DSW *col_obj=space->intersection_query_results[i]; + int shape_idx=space->intersection_query_subindex_results[i]; - if (!res) { - print_line("lolwut failed"); - return; + + Matrix32 col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); + //test initial overlap, does it collide if going all the way? + if (!CollisionSolver2DSW::solve(shape,p_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,p_margin)) { + continue; } - p = rd->b_xform.xform(p); - n = rd->b_xform_inv.basis_xform_inv(n).normalized(); - } + //test initial overlap + if (CollisionSolver2DSW::solve(shape,p_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,p_margin)) { + + return false; + } + + + //just do kinematic solving + float low=0; + float hi=1; + Vector2 mnormal=p_motion.normalized(); + + for(int i=0;i<8;i++) { //steps should be customizable.. + + Matrix32 xfa = p_xform; + float ofs = (low+hi)*0.5; + + Vector2 sep=mnormal; //important optimization for this to work fast enough + bool collided = CollisionSolver2DSW::solve(shape,p_xform,p_motion*ofs,col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),NULL,NULL,&sep,p_margin); + + if (collided) { + + hi=ofs; + } else { + + low=ofs; + } + } - float len = p.distance_to(from); + if (low<best_safe) { + best_safe=low; + best_unsafe=hi; + } - if (len<rd->best_len) { - rd->best_contact=p; - rd->best_normal=n; - rd->best_len=len; } + + p_closest_safe=best_safe; + p_closest_unsafe=best_unsafe; + + return true; + + } -bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion, MotionCastCollision &r_result, const Set<RID>& p_exclude,uint32_t p_user_mask) { + +bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,float p_margin,Vector2 *r_results,int p_result_max,int &r_result_count, const Set<RID>& p_exclude,uint32_t p_user_mask,uint32_t p_object_type_mask) { + + + if (p_result_max<=0) + return 0; Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape,0); - Rect2 aabb = p_xform.xform(shape->get_aabb()); + Rect2 aabb = p_shape_xform.xform(shape->get_aabb()); aabb=aabb.merge(Rect2(aabb.pos+p_motion,aabb.size)); //motion + aabb=aabb.grow(p_margin); int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results); bool collided=false; - r_result.travel=1; - - MotionCallbackRayCastData best_normal; - best_normal.best_len=1e20; - for(int i=0;i<amount;i++) { - + int cc=0; + r_result_count=0; + + Physics2DServerSW::CollCbkData cbk; + cbk.max=p_result_max; + cbk.amount=0; + cbk.ptr=r_results; + CollisionSolver2DSW::CallbackResult cbkres=NULL; + + Physics2DServerSW::CollCbkData *cbkptr=NULL; + if (p_result_max>0) { + cbkptr=&cbk; + cbkres=Physics2DServerSW::_shape_col_cbk; + } - if (space->intersection_query_results[i]->get_type()==CollisionObject2DSW::TYPE_AREA) - continue; //ignore area - if (p_exclude.has( space->intersection_query_results[i]->get_self())) - continue; //ignore excluded + for(int i=0;i<amount;i++) { + if (!_match_object_type_query(space->intersection_query_results[i],p_user_mask,p_object_type_mask)) + continue; const CollisionObject2DSW *col_obj=space->intersection_query_results[i]; int shape_idx=space->intersection_query_subindex_results[i]; + if (p_exclude.has( col_obj->get_self() )) + continue; - Matrix32 col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); - //test initial overlap, does it collide if going all the way? - if (!CollisionSolver2DSW::solve(shape,p_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL)) { - continue; + if (CollisionSolver2DSW::solve(shape,p_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2(),cbkres,cbkptr,NULL,p_margin)) { + collided=true; } + } - //test initial overlap - if (CollisionSolver2DSW::solve(shape,p_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL)) { - - r_result.collider_id=col_obj->get_instance_id(); - r_result.collider=r_result.collider_id!=0 ? ObjectDB::get_instance(col_obj->get_instance_id()) : NULL; - r_result.shape=shape_idx; - r_result.rid=col_obj->get_self(); - r_result.travel=0; - r_result.point=Vector2(); - r_result.normal=Vector2(); - return true; - } + r_result_count=cbk.amount; -#if 0 - Vector2 mnormal=p_motion.normalized(); - Matrix32 col_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); - ShapeSW *col_shape = col_obj->get_shape(shape_idx); + return collided; +} - real_t min,max; - col_shape->project_rangev(mnormal,col_shape_xform,min,max); - real_t width = max-min; - int a; - Vector2 s[2]; - col_shape->get_supports(col_shape_xform.basis_xform(mnormal).normalized(),s,a); - Vector2 from = col_shape_xform.xform(s[0]); - Vector2 to = from + p_motion; +struct _RestCallbackData { - Matrix32 from_inv = col_shape_xform.affine_inverse(); + const CollisionObject2DSW *object; + const CollisionObject2DSW *best_object; + int shape; + int best_shape; + Vector2 best_contact; + Vector2 best_normal; + float best_len; +}; - Vector2 local_from = from_inv.xform(from-mnormal*width*0.1); //start from a little inside the bounding box - Vector2 local_to = from_inv.xform(to); +static void _rest_cbk_result(const Vector2& p_point_A,const Vector2& p_point_B,void *p_userdata) { - Vector2 rpos,rnorm; - if (!col_shape->intersect_segment(local_from,local_to,rpos,rnorm)) - return false; - //ray hit something + _RestCallbackData *rd=(_RestCallbackData*)p_userdata; + Vector2 contact_rel = p_point_B - p_point_A; + float len = contact_rel.length(); + if (len <= rd->best_len) + return; - Vector2 hitpos = p_xform_B.xform(rpos); -#endif + rd->best_len=len; + rd->best_contact=p_point_B; + rd->best_normal=contact_rel/len; + rd->best_object=rd->object; + rd->best_shape=rd->shape; - //just do kinematic solving - float low=0; - float hi=1; - Vector2 mnormal=p_motion.normalized(); +} - for(int i=0;i<8;i++) { //steps should be customizable.. - Matrix32 xfa = p_xform; - float ofs = (low+hi)*0.5; +bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,float p_margin,ShapeRestInfo *r_info, const Set<RID>& p_exclude,uint32_t p_user_mask,uint32_t p_object_type_mask) { - Vector2 sep=mnormal; //important optimization for this to work fast enough - bool collided = CollisionSolver2DSW::solve(shape,p_xform,p_motion*ofs,col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),NULL,NULL,&sep); - if (collided) { + Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape); + ERR_FAIL_COND_V(!shape,0); - hi=ofs; - } else { + Rect2 aabb = p_shape_xform.xform(shape->get_aabb()); + aabb=aabb.merge(Rect2(aabb.pos+p_motion,aabb.size)); //motion + aabb=aabb.grow(p_margin); - low=ofs; - } - } + int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results); + + _RestCallbackData rcd; + rcd.best_len=0; + rcd.best_object=NULL; + rcd.best_shape=0; + for(int i=0;i<amount;i++) { - best_normal.shape_B=col_obj->get_shape(shape_idx); - best_normal.motion=p_motion*hi; - best_normal.b_xform=col_obj_xform; - best_normal.b_xform_inv=col_obj_xform.affine_inverse(); - bool sc = CollisionSolver2DSW::solve(shape,p_xform,p_motion*hi,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2() ,_motion_cbk_result,&best_normal); - print_line("CLD: "+itos(sc)); + if (!_match_object_type_query(space->intersection_query_results[i],p_user_mask,p_object_type_mask)) + continue; + const CollisionObject2DSW *col_obj=space->intersection_query_results[i]; + int shape_idx=space->intersection_query_subindex_results[i]; - if (collided && low>=r_result.travel) + if (p_exclude.has( col_obj->get_self() )) continue; - collided=true; - r_result.travel=low; + rcd.object=col_obj; + rcd.shape=shape_idx; + bool sc = CollisionSolver2DSW::solve(shape,p_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2() ,_rest_cbk_result,&rcd,NULL,p_margin); + if (!sc) + continue; - r_result.collider_id=col_obj->get_instance_id(); - r_result.collider=r_result.collider_id!=0 ? ObjectDB::get_instance(col_obj->get_instance_id()) : NULL; - r_result.shape=shape_idx; - r_result.rid=col_obj->get_self(); } - if (collided) { - ERR_FAIL_COND_V(best_normal.best_normal==Vector2(),false); - r_result.normal=best_normal.best_normal; - r_result.point=best_normal.best_contact; - } + if (rcd.best_len==0) + return false; - return collided; + r_info->collider_id=rcd.best_object->get_instance_id(); + r_info->shape=rcd.best_shape; + r_info->normal=rcd.best_normal; + r_info->point=rcd.best_contact; + r_info->rid=rcd.best_object->get_self(); + if (rcd.best_object->get_type()==CollisionObject2DSW::TYPE_BODY) { + const Body2DSW *body = static_cast<const Body2DSW*>(rcd.best_object); + Vector2 rel_vec = r_info->point-body->get_transform().get_origin(); + r_info->linear_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity(); + } else { + r_info->linear_velocity=Vector2(); + } + + return true; } diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 978e88479d..9d3dfae9b5 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -46,9 +46,11 @@ public: Space2DSW *space; - bool intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0); - int intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0); - bool cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion, MotionCastCollision &r_result, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0); + virtual bool intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION); + virtual int intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION); + virtual bool cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,float &p_closest_safe,float &p_closest_unsafe, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION); + virtual bool collide_shape(RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,float p_margin,Vector2 *r_results,int p_result_max,int &r_result_count, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION); + virtual bool rest_info(RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,float p_margin,ShapeRestInfo *r_info, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION); Physics2DDirectSpaceStateSW(); }; diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index cbf5cffce6..0851ad59ef 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -145,7 +145,7 @@ Variant Physics2DDirectSpaceState::_intersect_shape(const RID& p_shape, const Ma ShapeResult *res=(ShapeResult*)alloca(p_result_max*sizeof(ShapeResult)); - int rc = intersect_shape(p_shape,p_xform,Vector2(),res,p_result_max,exclude,p_user_mask); + int rc = intersect_shape(p_shape,p_xform,Vector2(),0,res,p_result_max,exclude,p_user_mask); if (rc==0) return Variant(); @@ -163,15 +163,13 @@ Variant Physics2DDirectSpaceState::_intersect_shape(const RID& p_shape, const Ma Variant Physics2DDirectSpaceState::_cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,const Vector<RID>& p_exclude,uint32_t p_user_mask) { +#if 0 Set<RID> exclude; for(int i=0;i<p_exclude.size();i++) exclude.insert(p_exclude[i]); - - MotionCastCollision mcc; - - bool result = cast_motion(p_shape,p_xform,p_motion,mcc,exclude,p_user_mask); + bool result = cast_motion(p_shape,p_xform,p_motion,0,mcc,exclude,p_user_mask); if (!result) return Variant(); @@ -185,7 +183,8 @@ Variant Physics2DDirectSpaceState::_cast_motion(const RID& p_shape, const Matrix d["shape"]=mcc.shape; return d; - +#endif + return Variant(); } diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 5242ec0e2a..172fa1699b 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -98,6 +98,16 @@ protected: public: + enum ObjectTypeMask { + TYPE_MASK_STATIC_BODY=1<<0, + TYPE_MASK_KINEMATIC_BODY=1<<1, + TYPE_MASK_RIGID_BODY=1<<2, + TYPE_MASK_CHARACTER_BODY=1<<3, + TYPE_MASK_AREA=1<<4, + TYPE_MASK_COLLISION=TYPE_MASK_STATIC_BODY|TYPE_MASK_CHARACTER_BODY|TYPE_MASK_KINEMATIC_BODY|TYPE_MASK_RIGID_BODY + + }; + struct RayResult { Vector2 position; @@ -108,7 +118,7 @@ public: int shape; }; - virtual bool intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0)=0; + virtual bool intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION)=0; struct ShapeResult { @@ -119,25 +129,26 @@ public: }; - virtual int intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0)=0; + virtual int intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION)=0; + + virtual bool cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,float &p_closest_safe,float &p_closest_unsafe, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION)=0; - struct MotionCastCollision { + virtual bool collide_shape(RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,float p_margin,Vector2 *r_results,int p_result_max,int &r_result_count, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION)=0; + + struct ShapeRestInfo { - float travel; //0 to 1, if 0 then it's blocked Vector2 point; Vector2 normal; RID rid; ObjectID collider_id; - Object *collider; int shape; + Vector2 linear_velocity; //velocity at contact point }; - virtual bool cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion, MotionCastCollision &r_result, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0)=0; - - + virtual bool rest_info(RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,float p_margin,ShapeRestInfo *r_info, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_user_mask=0,uint32_t p_object_type_mask=TYPE_MASK_COLLISION)=0; Physics2DDirectSpaceState(); @@ -327,8 +338,8 @@ public: virtual void body_set_continuous_collision_detection_mode(RID p_body,CCDMode p_mode)=0; virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const=0; - virtual void body_set_user_flags(RID p_body, uint32_t p_flags)=0; - virtual uint32_t body_get_user_flags(RID p_body, uint32_t p_flags) const=0; + virtual void body_set_user_mask(RID p_body, uint32_t p_mask)=0; + virtual uint32_t body_get_user_mask(RID p_body, uint32_t p_mask) const=0; // common body variables enum BodyParameter { diff --git a/tools/doc/doc_data.cpp b/tools/doc/doc_data.cpp index 5167b9a0b0..35f1140644 100644 --- a/tools/doc/doc_data.cpp +++ b/tools/doc/doc_data.cpp @@ -530,6 +530,17 @@ void DocData::generate(bool p_basic_types) { } + List<Pair<String,Variant> > cinfo; + lang->get_public_constants(&cinfo); + + + for(List<Pair<String,Variant> >::Element *E=cinfo.front();E;E=E->next()) { + + ConstantDoc cd; + cd.name=E->get().first; + cd.value=E->get().second; + c.constants.push_back(cd); + } } } diff --git a/tools/docdump/makemd.py b/tools/docdump/makemd.py new file mode 100644 index 0000000000..7cc2e9dc4b --- /dev/null +++ b/tools/docdump/makemd.py @@ -0,0 +1,345 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +import xml.etree.ElementTree as ET + +input_list = [] + +for arg in sys.argv[1:]: + input_list.append(arg) + +if len(input_list) < 1: + print 'usage: makedoku.py <class_list.xml>' + sys.exit(0) + + +def validate_tag(elem, tag): + if elem.tag != tag: + print "Tag mismatch, expected '" + tag + "', got " + elem.tag + sys.exit(255) + + +class_names = [] +classes = {} + + +def make_class_list(class_list, columns): + + f = open('class_list.md', 'wb') + prev = 0 + col_max = len(class_list) / columns + 1 + print ('col max is ', col_max) + col_count = 0 + row_count = 0 + last_initial = '' + fit_columns = [] + + for n in range(0, columns): + fit_columns += [[]] + + indexers = [] + last_initial = '' + + idx = 0 + for n in class_list: + col = idx / col_max + if col >= columns: + col = columns - 1 + fit_columns[col] += [n] + idx += 1 + if n[:1] != last_initial: + indexers += [n] + last_initial = n[:1] + + row_max = 0 + f.write("\n") + + for n in range(0, columns): + if len(fit_columns[n]) > row_max: + row_max = len(fit_columns[n]) + + f.write("| ") + for n in range(0, columns): + f.write(" | |") + + f.write("\n") + f.write("| ") + for n in range(0, columns): + f.write(" --- | ------- |") + f.write("\n") + + for r in range(0, row_max): + s = '| ' + for c in range(0, columns): + if r >= len(fit_columns[c]): + continue + + classname = fit_columns[c][r] + initial = classname[0] + if classname in indexers: + s += '**' + initial + '** | ' + else: + s += ' | ' + + s += '[' + classname + '](class_'+ classname.lower()+') | ' + + s += '\n' + f.write(s) + + +def dokuize_text(txt): + + return txt + + +def dokuize_text(text): + pos = 0 + while True: + pos = text.find('[', pos) + if pos == -1: + break + + endq_pos = text.find(']', pos + 1) + if endq_pos == -1: + break + + pre_text = text[:pos] + post_text = text[endq_pos + 1:] + tag_text = text[pos + 1:endq_pos] + + if tag_text in class_names: + tag_text = make_type(tag_text) + else: + + # command + + cmd = tag_text + space_pos = tag_text.find(' ') + if cmd.find('html') == 0: + cmd = tag_text[:space_pos] + param = tag_text[space_pos + 1:] + tag_text = '<' + param + '>' + elif cmd.find('method') == 0: + cmd = tag_text[:space_pos] + param = tag_text[space_pos + 1:] + + if param.find('.') != -1: + (class_param, method_param) = param.split('.') + tag_text = '['+class_param+'.'+method_param.replace("_","_")+'](' + class_param.lower() + '#' \ + + method_param + ')' + else: + tag_text = '[' + param.replace("_","_") + '](#' + param + ')' + elif cmd.find('image=') == 0: + tag_text = '![](' + cmd[6:] + ')' + elif cmd.find('url=') == 0: + tag_text = '[' + cmd[4:] + ']('+cmd[4:] + elif cmd == '/url': + tag_text = ')' + elif cmd == 'center': + tag_text = '' + elif cmd == '/center': + tag_text = '' + elif cmd == 'br': + tag_text = '\n' + elif cmd == 'i' or cmd == '/i': + tag_text = '_' + elif cmd == 'b' or cmd == '/b': + tag_text = '**' + elif cmd == 'u' or cmd == '/u': + tag_text = '__' + else: + tag_text = '[' + tag_text + ']' + + text = pre_text + tag_text + post_text + pos = len(pre_text) + len(tag_text) + + # tnode = ET.SubElement(parent,"div") + # tnode.text=text + + return text + + +def make_type(t): + global class_names + if t in class_names: + return '[' + t + '](class_' + t.lower() + ')' + return t + + +def make_method( + f, + name, + m, + declare, + event=False, + ): + + s = ' * ' + ret_type = 'void' + args = list(m) + mdata = {} + mdata['argidx'] = [] + for a in args: + if a.tag == 'return': + idx = -1 + elif a.tag == 'argument': + idx = int(a.attrib['index']) + else: + continue + + mdata['argidx'].append(idx) + mdata[idx] = a + + if not event: + if -1 in mdata['argidx']: + s += make_type(mdata[-1].attrib['type']) + else: + s += 'void' + s += ' ' + + if declare: + + # span.attrib["class"]="funcdecl" + # a=ET.SubElement(span,"a") + # a.attrib["name"]=name+"_"+m.attrib["name"] + # a.text=name+"::"+m.attrib["name"] + + s += ' **'+m.attrib['name'].replace("_","_")+'** ' + else: + s += ' **['+ m.attrib['name'].replace("_","_")+'](#' + m.attrib['name'] + ')** ' + + s += ' **(**' + argfound = False + for a in mdata['argidx']: + arg = mdata[a] + if a < 0: + continue + if a > 0: + s += ', ' + else: + s += ' ' + + s += make_type(arg.attrib['type']) + if 'name' in arg.attrib: + s += ' ' + arg.attrib['name'] + else: + s += ' arg' + str(a) + + if 'default' in arg.attrib: + s += '=' + arg.attrib['default'] + + argfound = True + + if argfound: + s += ' ' + s += ' **)**' + + if 'qualifiers' in m.attrib: + s += ' ' + m.attrib['qualifiers'] + + f.write(s + '\n') + + +def make_doku_class(node): + + name = node.attrib['name'] + + f = open("class_"+name.lower() + '.md', 'wb') + + f.write('# ' + name + ' \n') + + if 'inherits' in node.attrib: + inh = node.attrib['inherits'].strip() + f.write('####**Inherits:** '+make_type(inh)+'\n') + if 'category' in node.attrib: + f.write('####**Category:** ' + node.attrib['category'].strip() + + '\n') + + briefd = node.find('brief_description') + if briefd != None: + f.write('\n### Brief Description \n') + f.write(dokuize_text(briefd.text.strip()) + '\n') + + methods = node.find('methods') + + if methods != None and len(list(methods)) > 0: + f.write('\n### Member Functions \n') + for m in list(methods): + make_method(f, node.attrib['name'], m, False) + + events = node.find('signals') + if events != None and len(list(events)) > 0: + f.write('\n### Signals \n') + for m in list(events): + make_method(f, node.attrib['name'], m, True, True) + + members = node.find('members') + + if members != None and len(list(members)) > 0: + f.write('\n### Member Variables \n') + + for c in list(members): + s = ' * ' + s += make_type(c.attrib['type']) + ' ' + s += '**' + c.attrib['name'] + '**' + if c.text.strip() != '': + s += ' - ' + c.text.strip() + f.write(s + '\n') + + constants = node.find('constants') + if constants != None and len(list(constants)) > 0: + f.write('\n### Numeric Constants \n') + for c in list(constants): + s = ' * ' + s += '**' + c.attrib['name'] + '**' + if 'value' in c.attrib: + s += ' = **' + c.attrib['value'] + '**' + if c.text.strip() != '': + s += ' - ' + c.text.strip() + f.write(s + '\n') + + descr = node.find('description') + if descr != None and descr.text.strip() != '': + f.write('\n### Description \n') + f.write(dokuize_text(descr.text.strip()) + '\n') + + methods = node.find('methods') + + if methods != None and len(list(methods)) > 0: + f.write('\n### Member Function Description \n') + for m in list(methods): + + d = m.find('description') + if d == None or d.text.strip() == '': + continue + f.write('\n#### <a name="'+m.attrib['name']+'">' + m.attrib['name'] + '</a>\n') + make_method(f, node.attrib['name'], m, True) + f.write('\n') + f.write(dokuize_text(d.text.strip())) + f.write('\n') + + +for file in input_list: + tree = ET.parse(file) + doc = tree.getroot() + + if 'version' not in doc.attrib: + print "Version missing from 'doc'" + sys.exit(255) + + version = doc.attrib['version'] + + for c in list(doc): + if c.attrib['name'] in class_names: + continue + class_names.append(c.attrib['name']) + classes[c.attrib['name']] = c + +class_names.sort() + +make_class_list(class_names, 3) + +for cn in class_names: + c = classes[cn] + make_doku_class(c) + diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp index 87d3e17694..1a5dd73040 100644 --- a/tools/editor/editor_import_export.cpp +++ b/tools/editor/editor_import_export.cpp @@ -124,6 +124,40 @@ EditorImportPlugin::EditorImportPlugin() { ///////////////////////////////////////////////////////////////////////////////////////////////////// +void EditorExportPlugin::_bind_methods() { + + BIND_VMETHOD( MethodInfo("custom_export:Dictionary",PropertyInfo(Variant::STRING,"name",PROPERTY_HINT_RESOURCE_TYPE,"EditorExportPlatformPC")) ); +} + + +Vector<uint8_t> EditorExportPlugin::custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) { + + if (get_script_instance()) { + + Variant d = get_script_instance()->call("custom_export",p_path,p_platform); + if (d.get_type()==Variant::NIL) + return Vector<uint8_t>(); + ERR_FAIL_COND_V(d.get_type()!=Variant::DICTIONARY,Vector<uint8_t>()); + Dictionary dict=d; + ERR_FAIL_COND_V(!dict.has("name"),Vector<uint8_t>()); + ERR_FAIL_COND_V(!dict.has("data"),Vector<uint8_t>()); + p_path=dict["name"]; + return dict["data"]; + } + + return Vector<uint8_t>(); + +} + + +EditorExportPlugin::EditorExportPlugin() { + + +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// + + static void _add_to_list(EditorFileSystemDirectory *p_efsd,Set<StringName>& r_list) { for(int i=0;i<p_efsd->get_subdir_count();i++) { @@ -223,48 +257,17 @@ static void _add_filter_to_list(Set<StringName>& r_list,const String& p_filter) Vector<uint8_t> EditorExportPlatform::get_exported_file(String& p_fname) const { + Ref<EditorExportPlatform> ep=EditorImportExport::get_singleton()->get_export_platform(get_name()); - Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_fname); - - if (rimd.is_valid()) { - - if (rimd->get_editor()!="") { - Ref<EditorImportPlugin> pl = EditorImportExport::get_singleton()->get_import_plugin_by_name(rimd->get_editor()); - if (pl.is_valid()) { - Vector<uint8_t> ce = pl->custom_export(p_fname,EditorImportExport::get_singleton()->get_export_platform(get_name())); - if (ce.size()) - return ce; - } - } - } else if (EditorImportExport::get_singleton()->image_get_export_group(p_fname)) { - - - Ref<EditorImportPlugin> pl = EditorImportExport::get_singleton()->get_import_plugin_by_name("texture_2d"); - if (pl.is_valid()) { - Vector<uint8_t> ce = pl->custom_export(p_fname,EditorImportExport::get_singleton()->get_export_platform(get_name())); - if (ce.size()) { - p_fname=p_fname.basename()+".tex"; - return ce; - } - } - - } else if (EditorImportExport::get_singleton()->get_export_image_action()!=EditorImportExport::IMAGE_ACTION_NONE){ + for(int i=0;i<EditorImportExport::get_singleton()->get_export_plugin_count();i++) { - String xt = p_fname.extension().to_lower(); - print_line("TRY FOR: "+p_fname); - if (EditorImportExport::get_singleton()->get_image_formats().has(xt)) { //should check for more I guess? + Vector<uint8_t> data = EditorImportExport::get_singleton()->get_export_plugin(i)->custom_export(p_fname,ep); + if (data.size()) + return data; - Ref<EditorImportPlugin> pl = EditorImportExport::get_singleton()->get_import_plugin_by_name("texture_2d"); - if (pl.is_valid()) { - Vector<uint8_t> ce = pl->custom_export(p_fname,EditorImportExport::get_singleton()->get_export_platform(get_name())); - if (ce.size()) { - p_fname=p_fname.basename()+".tex"; - return ce; - } - } - } } + FileAccess *f = FileAccess::open(p_fname,FileAccess::READ); ERR_FAIL_COND_V(!f,Vector<uint8_t>()); Vector<uint8_t> ret; @@ -489,6 +492,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func int group_format=0; float group_lossy_quality=EditorImportExport::get_singleton()->image_export_group_get_lossy_quality(E->get()); int group_shrink=EditorImportExport::get_singleton()->image_export_group_get_shrink(E->get()); + group_shrink*=EditorImportExport::get_singleton()->get_export_image_shrink(); switch(EditorImportExport::get_singleton()->image_export_group_get_image_action(E->get())) { case EditorImportExport::IMAGE_ACTION_NONE: { @@ -1061,12 +1065,29 @@ Ref<EditorImportPlugin> EditorImportExport::get_import_plugin(int p_idx) const{ return plugins[p_idx]; } + + + Ref<EditorImportPlugin> EditorImportExport::get_import_plugin_by_name(const String& p_string) const{ ERR_FAIL_COND_V( !by_idx.has(p_string), Ref<EditorImportPlugin>()); return plugins[ by_idx[p_string] ]; } +void EditorImportExport::add_export_plugin(const Ref<EditorExportPlugin>& p_plugin) { + + export_plugins.push_back(p_plugin); +} + +int EditorImportExport::get_export_plugin_count() const{ + + return export_plugins.size(); +} +Ref<EditorExportPlugin> EditorImportExport::get_export_plugin(int p_idx) const{ + + ERR_FAIL_INDEX_V(p_idx,export_plugins.size(),Ref<EditorExportPlugin>()); + return export_plugins[p_idx]; +} void EditorImportExport::set_export_file_action(const StringName& p_file, FileAction p_action) { @@ -1166,6 +1187,16 @@ EditorImportExport::ImageAction EditorImportExport::get_export_image_action() co return image_action; } +void EditorImportExport::set_export_image_shrink(int p_shrink) { + + image_shrink=p_shrink; +} + +int EditorImportExport::get_export_image_shrink() const{ + + return image_shrink; +} + void EditorImportExport::set_export_image_quality(float p_quality){ @@ -1316,6 +1347,10 @@ void EditorImportExport::load_config() { image_action=IMAGE_ACTION_COMPRESS_DISK; image_action_compress_quality = cf->get_value(ci,"compress_quality"); + if (cf->has_section_key(ci,"shrink")) + image_shrink = cf->get_value(ci,"shrink"); + else + image_shrink=1; String formats=cf->get_value(ci,"formats"); Vector<String> f = formats.split(","); image_formats.clear(); @@ -1362,8 +1397,6 @@ void EditorImportExport::load_config() { List<String> keys; cf->get_section_keys(s,&keys); for(List<String>::Element *F=keys.front();F;F=F->next()) { - print_line("sk: "+F->get()); - ep->set(F->get(),cf->get_value(s,F->get())); } } @@ -1474,6 +1507,7 @@ void EditorImportExport::save_config() { case IMAGE_ACTION_COMPRESS_DISK: cf->set_value("convert_images","action","compress_disk"); break; } + cf->set_value("convert_images","shrink",image_shrink); cf->set_value("convert_images","compress_quality",image_action_compress_quality); String formats; @@ -1542,9 +1576,7 @@ EditorImportExport::EditorImportExport() { image_action=IMAGE_ACTION_NONE; image_action_compress_quality=0.7; image_formats.insert("png"); - - - + image_shrink=1; } diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h index 1e5e733921..94fbaba842 100644 --- a/tools/editor/editor_import_export.h +++ b/tools/editor/editor_import_export.h @@ -36,6 +36,7 @@ class EditorExportPlatform; class FileAccess; class EditorProgress; + class EditorImportPlugin : public Reference { OBJ_TYPE( EditorImportPlugin, Reference); @@ -59,6 +60,20 @@ public: EditorImportPlugin(); }; +class EditorExportPlugin : public Reference { + + OBJ_TYPE( EditorExportPlugin, Reference); + +protected: + static void _bind_methods(); + +public: + + virtual Vector<uint8_t> custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform); + + EditorExportPlugin(); +}; + class EditorExportPlatform : public Reference { OBJ_TYPE( EditorExportPlatform,Reference ); @@ -223,10 +238,12 @@ protected: int shrink; }; + Vector<Ref<EditorExportPlugin> > export_plugins; Vector<Ref<EditorImportPlugin> > plugins; Map<String,int> by_idx; ImageAction image_action; float image_action_compress_quality; + int image_shrink; Set<String> image_formats; ExportFilter export_filter; @@ -249,6 +266,10 @@ public: Ref<EditorImportPlugin> get_import_plugin(int p_idx) const; Ref<EditorImportPlugin> get_import_plugin_by_name(const String& p_string) const; + void add_export_plugin(const Ref<EditorExportPlugin>& p_plugin); + int get_export_plugin_count() const; + Ref<EditorExportPlugin> get_export_plugin(int p_idx) const; + bool poll_export_platforms(); void set_export_file_action(const StringName& p_export_file, FileAction p_action); @@ -268,6 +289,9 @@ public: void set_export_image_action(ImageAction p_action); ImageAction get_export_image_action() const; + void set_export_image_shrink(int p_shrink); + int get_export_image_shrink() const; + void set_export_image_quality(float p_quality); float get_export_image_quality() const; diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index ed932396db..d8f9dcc947 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -3058,6 +3058,12 @@ void EditorNode::register_editor_types() { // ObjectTypeDB::register_type<EditorPostImport>(); } +void EditorNode::unregister_editor_types() { + + _init_callbacks.clear(); +} + + void EditorNode::stop_child_process() { _menu_option_confirm(RUN_STOP,false); @@ -3193,6 +3199,7 @@ void EditorNode::_file_dialog_unregister(FileDialog *p_dialog){ singleton->file_dialogs.erase(p_dialog); } +Vector<EditorNodeInitCallback> EditorNode::_init_callbacks; Error EditorNode::export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after) { @@ -3451,8 +3458,8 @@ EditorNode::EditorNode() { p->add_item("Run Script",FILE_RUN_SCRIPT,KEY_MASK_CMD+KEY_R); p->add_separator(); p->add_item("Project Settings",RUN_SETTINGS); - p->add_item("Project Manager",RUN_PROJECT_MANAGER); p->add_separator(); + p->add_item("Quit to Project List",RUN_PROJECT_MANAGER); p->add_item("Quit",FILE_QUIT,KEY_MASK_CMD+KEY_Q); recent_scenes = memnew( PopupMenu ); @@ -4006,10 +4013,12 @@ EditorNode::EditorNode() { editor_import_export->add_import_plugin( Ref<EditorSampleImportPlugin>( memnew(EditorSampleImportPlugin(this)))); editor_import_export->add_import_plugin( Ref<EditorTranslationImportPlugin>( memnew(EditorTranslationImportPlugin(this)))); + for(int i=0;i<editor_import_export->get_import_plugin_count();i++) { import_menu->get_popup()->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(),IMPORT_PLUGIN_BASE+i); } + editor_import_export->add_export_plugin( Ref<EditorTextureExportPlugin>( memnew(EditorTextureExportPlugin))); add_editor_plugin( memnew( CanvasItemEditorPlugin(this) ) ); add_editor_plugin( memnew( SpatialEditorPlugin(this) ) ); @@ -4148,10 +4157,13 @@ EditorNode::EditorNode() { EditorSettings::get_singleton()->enable_plugins(); + Node::set_human_readable_collision_renaming(true); // Ref<ImageTexture> it = gui_base->get_icon("logo","Icons"); // OS::get_singleton()->set_icon( it->get_data() ); + for(int i=0;i<_init_callbacks.size();i++) + _init_callbacks[i](); } diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index 30504aa08e..87f17247c3 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -91,6 +91,9 @@ + +typedef void (*EditorNodeInitCallback)(); + class EditorNode : public Node { OBJ_TYPE( EditorNode, Node ); @@ -393,6 +396,8 @@ class EditorNode : public Node { static EditorNode *singleton; + static Vector<EditorNodeInitCallback> _init_callbacks; + protected: void _notification(int p_what); static void _bind_methods(); @@ -463,6 +468,7 @@ public: Error export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after=false); static void register_editor_types(); + static void unregister_editor_types(); Control *get_gui_base() { return gui_base; } @@ -481,6 +487,8 @@ public: ~EditorNode(); void get_singleton(const char* arg1, bool arg2); + static void add_init_callback(EditorNodeInitCallback p_callback) { _init_callbacks.push_back(p_callback); } + }; diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index 53b5a8a47d..09d55650c8 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -413,7 +413,7 @@ void EditorSettings::_load_defaults() { set("on_save/compress_binary_resources",true); set("on_save/save_modified_external_resources",true); set("on_save/save_paths_as_relative",false); - set("on_save/save_paths_without_extension",true); + set("on_save/save_paths_without_extension",false); set("text_editor/create_signal_callbacks",true); diff --git a/tools/editor/io_plugins/editor_font_import_plugin.cpp b/tools/editor/io_plugins/editor_font_import_plugin.cpp index 7c38b105fd..4de68c7f4c 100644 --- a/tools/editor/io_plugins/editor_font_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_font_import_plugin.cpp @@ -884,15 +884,20 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata ++missing; }; }; - printf("total %i/%i\n", missing, import_chars.size()); + print_line("total_chars: "+itos(font_data_list.size())); /* KERNING */ for(int i=0;i<font_data_list.size();i++) { + if (font_data_list[i]->character>512) + continue; for(int j=0;j<font_data_list.size();j++) { + if (font_data_list[j]->character>512) + continue; + FT_Vector delta; FT_Get_Kerning( face, font_data_list[i]->glyph,font_data_list[j]->glyph, FT_KERNING_DEFAULT, &delta ); diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp index ffb68dff83..5fce4233e1 100644 --- a/tools/editor/io_plugins/editor_import_collada.cpp +++ b/tools/editor/io_plugins/editor_import_collada.cpp @@ -108,6 +108,7 @@ Error ColladaImport::_populate_skeleton(Skeleton *p_skeleton,Collada::Node *p_no Collada::NodeJoint *joint = static_cast<Collada::NodeJoint*>(p_node); + p_skeleton->add_bone(p_node->name); if (p_parent>=0) p_skeleton->set_bone_parent(r_bone,p_parent); diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp index 2e6e755136..90dcbb97e0 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp @@ -610,7 +610,7 @@ String EditorTextureImportPlugin::get_visible_name() const { } break; case MODE_ATLAS: { - return "Atlas Teture"; + return "Atlas Texture"; } break; } @@ -899,6 +899,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc } } + if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) { Image image=texture->get_data(); @@ -952,6 +953,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc } else { + print_line("compress..."); Image image=texture->get_data(); ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA); @@ -988,13 +990,17 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc } + print_line("COMPRESSED TO: "+itos(image.get_format())); texture->create_from_image(image,tex_flags); + if (shrink>1) { texture->set_size_override(Size2(orig_w,orig_h)); } - Error err = ResourceSaver::save(p_path,texture); + uint32_t save_flags=ResourceSaver::FLAG_COMPRESS; + + Error err = ResourceSaver::save(p_path,texture,save_flags); if (err!=OK) { EditorNode::add_io_error("Couldn't save converted texture: "+p_path); return err; @@ -1021,6 +1027,7 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c int group_format=0; float group_lossy_quality=EditorImportExport::get_singleton()->image_export_group_get_lossy_quality(group); int group_shrink=EditorImportExport::get_singleton()->image_export_group_get_shrink(group); + group_shrink*=EditorImportExport::get_singleton()->get_export_image_shrink(); switch(EditorImportExport::get_singleton()->image_export_group_get_image_action(group)) { case EditorImportExport::IMAGE_ACTION_NONE: { @@ -1062,6 +1069,7 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c flags|=IMAGE_FLAG_FIX_BORDER_ALPHA; + print_line("group format"+itos(group_format)); rimd->set_option("format",group_format); rimd->set_option("flags",flags); rimd->set_option("quality",group_lossy_quality); @@ -1090,6 +1098,7 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c flags|=IMAGE_FLAG_FIX_BORDER_ALPHA; + rimd->set_option("shrink",EditorImportExport::get_singleton()->get_export_image_shrink()); rimd->set_option("flags",flags); rimd->set_option("quality",EditorImportExport::get_singleton()->get_export_image_quality()); rimd->set_option("atlas",false); @@ -1108,18 +1117,21 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c } uint32_t flags = rimd->get_option("flags"); + uint8_t shrink = rimd->has_option("shrink") ? rimd->get_option("shrink"): Variant(1); + uint8_t format = rimd->get_option("format"); + uint8_t comp = (format==EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM)?uint8_t(p_platform->get_image_compression()):uint8_t(255); MD5_CTX ctx; uint8_t f4[4]; encode_uint32(flags,&f4[0]); - uint8_t ic = p_platform->get_image_compression(); MD5Init(&ctx); String gp = Globals::get_singleton()->globalize_path(p_path); CharString cs = gp.utf8(); MD5Update(&ctx,(unsigned char*)cs.get_data(),cs.length()); MD5Update(&ctx,f4,4); - MD5Update(&ctx,&ic,1); - + MD5Update(&ctx,&format,1); + MD5Update(&ctx,&comp,1); + MD5Update(&ctx,&shrink,1); MD5Final(&ctx); uint64_t sd=0; @@ -1137,6 +1149,7 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c uint64_t d = f->get_line().strip_edges().to_int64(); sd = FileAccess::get_modified_time(p_path); + if (d==sd) { valid=true; } else { @@ -1190,3 +1203,56 @@ EditorTextureImportPlugin::EditorTextureImportPlugin(EditorNode *p_editor, Mode editor->get_gui_base()->add_child(dialog); } + +//////////////////////////// + + + Vector<uint8_t> EditorTextureExportPlugin::custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) { + + Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_path); + + if (rimd.is_valid()) { + + if (rimd->get_editor()!="") { + Ref<EditorImportPlugin> pl = EditorImportExport::get_singleton()->get_import_plugin_by_name(rimd->get_editor()); + if (pl.is_valid()) { + Vector<uint8_t> ce = pl->custom_export(p_path,p_platform); + if (ce.size()) + return ce; + } + } + } else if (EditorImportExport::get_singleton()->image_get_export_group(p_path)) { + + + Ref<EditorImportPlugin> pl = EditorImportExport::get_singleton()->get_import_plugin_by_name("texture_2d"); + if (pl.is_valid()) { + Vector<uint8_t> ce = pl->custom_export(p_path,p_platform); + if (ce.size()) { + p_path=p_path.basename()+".tex"; + return ce; + } + } + + } else if (EditorImportExport::get_singleton()->get_export_image_action()!=EditorImportExport::IMAGE_ACTION_NONE){ + + String xt = p_path.extension().to_lower(); + if (EditorImportExport::get_singleton()->get_image_formats().has(xt)) { //should check for more I guess? + + Ref<EditorImportPlugin> pl = EditorImportExport::get_singleton()->get_import_plugin_by_name("texture_2d"); + if (pl.is_valid()) { + Vector<uint8_t> ce = pl->custom_export(p_path,p_platform); + if (ce.size()) { + p_path=p_path.basename()+".tex"; + return ce; + } + } + } + } + + return Vector<uint8_t>(); +} + +EditorTextureExportPlugin::EditorTextureExportPlugin() { + + +} diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.h b/tools/editor/io_plugins/editor_texture_import_plugin.h index 4a9dd6ae9d..b2950a889c 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.h +++ b/tools/editor/io_plugins/editor_texture_import_plugin.h @@ -106,6 +106,16 @@ public: }; +class EditorTextureExportPlugin : public EditorExportPlugin { + + OBJ_TYPE( EditorTextureExportPlugin, EditorExportPlugin); + + +public: + + virtual Vector<uint8_t> custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform); + EditorTextureExportPlugin(); +}; class EditorImportTextureOptions : public VBoxContainer { OBJ_TYPE( EditorImportTextureOptions, VBoxContainer ); diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index be7214aaa7..0014c5a68a 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -1407,6 +1407,9 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { } break; + case KEY_F: { + _menu_option(VIEW_CENTER_TO_SELECTION); + } break; } diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp index 192fcaa908..eae5dacb27 100644 --- a/tools/editor/project_export.cpp +++ b/tools/editor/project_export.cpp @@ -207,6 +207,12 @@ void ProjectExportDialog::_quality_edited(float what) { _save_export_cfg(); } +void ProjectExportDialog::_shrink_edited(float what) { + + EditorImportExport::get_singleton()->set_export_image_shrink(what); + _save_export_cfg(); +} + void ProjectExportDialog::_image_export_edited(int what) { EditorImportExport::get_singleton()->set_export_image_action(EditorImportExport::ImageAction(what)); @@ -270,7 +276,9 @@ void ProjectExportDialog::_notification(int p_what) { image_action->select(EditorImportExport::get_singleton()->get_export_image_action()); image_quality->set_val(EditorImportExport::get_singleton()->get_export_image_quality()); + image_shrink->set_val(EditorImportExport::get_singleton()->get_export_image_quality()); image_quality->connect("value_changed",this,"_quality_edited"); + image_shrink->connect("value_changed",this,"_shrink_edited"); image_action->connect("item_selected",this,"_image_export_edited"); for(int i=0;i<formats.size();i++) { @@ -966,6 +974,7 @@ void ProjectExportDialog::_bind_methods() { ObjectTypeDB::bind_method(_MD("_export_action"),&ProjectExportDialog::_export_action); ObjectTypeDB::bind_method(_MD("_export_action_pck"),&ProjectExportDialog::_export_action_pck); ObjectTypeDB::bind_method(_MD("_quality_edited"),&ProjectExportDialog::_quality_edited); + ObjectTypeDB::bind_method(_MD("_shrink_edited"),&ProjectExportDialog::_shrink_edited); ObjectTypeDB::bind_method(_MD("_image_export_edited"),&ProjectExportDialog::_image_export_edited); ObjectTypeDB::bind_method(_MD("_format_toggled"),&ProjectExportDialog::_format_toggled); ObjectTypeDB::bind_method(_MD("_group_changed"),&ProjectExportDialog::_group_changed); @@ -1090,6 +1099,11 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { image_quality->set_max(1); image_quality->set_step(0.01); image_vb->add_margin_child("Compress for Disk (Lossy) Quality:",qhb); + image_shrink = memnew( SpinBox ); + image_shrink->set_min(1); + image_shrink->set_max(8); + image_shrink->set_step(1); + image_vb->add_margin_child("Shrink All Images:",image_shrink); sections->add_child(image_vb); image_formats=memnew(Tree); diff --git a/tools/editor/project_export.h b/tools/editor/project_export.h index 25709babb9..6ceffadc62 100644 --- a/tools/editor/project_export.h +++ b/tools/editor/project_export.h @@ -110,6 +110,7 @@ private: VBoxContainer *image_vb; OptionButton *image_action; HSlider *image_quality; + SpinBox *image_shrink; Tree *image_formats; Vector<TreeItem*> formats; @@ -150,6 +151,8 @@ private: void _quality_edited(float what); void _image_export_edited(int what); + void _shrink_edited(float what); + void _update_group_list(); void _select_group(const String& p_by_name); diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp index 02daa3c245..86331faa1d 100644 --- a/tools/editor/scenes_dock.cpp +++ b/tools/editor/scenes_dock.cpp @@ -181,7 +181,7 @@ void ScenesDock::_instance_pressed() { if (!sel) return; String path = sel->get_metadata(0); - emit_signal("instance","res://"+path); + emit_signal("instance",path); } void ScenesDock::_open_pressed(){ diff --git a/plugins/terrain/plugin.cfg b/tools/script_plugins/terrain/plugin.cfg index d2f2917420..d2f2917420 100644 --- a/plugins/terrain/plugin.cfg +++ b/tools/script_plugins/terrain/plugin.cfg diff --git a/plugins/terrain/terrain.gd b/tools/script_plugins/terrain/terrain.gd index b3e3121e7a..b3e3121e7a 100644 --- a/plugins/terrain/terrain.gd +++ b/tools/script_plugins/terrain/terrain.gd diff --git a/plugins/terrain/terrain.png b/tools/script_plugins/terrain/terrain.png Binary files differindex 7c1c3d70d6..7c1c3d70d6 100644 --- a/plugins/terrain/terrain.png +++ b/tools/script_plugins/terrain/terrain.png diff --git a/plugins/terrain/terrain_node.gd b/tools/script_plugins/terrain/terrain_node.gd index 91cf3fcb2b..91cf3fcb2b 100644 --- a/plugins/terrain/terrain_node.gd +++ b/tools/script_plugins/terrain/terrain_node.gd diff --git a/plugins/time/plugin.cfg b/tools/script_plugins/time/plugin.cfg index 5430306a79..5430306a79 100644 --- a/plugins/time/plugin.cfg +++ b/tools/script_plugins/time/plugin.cfg diff --git a/plugins/time/time.gd b/tools/script_plugins/time/time.gd index 66b3e9ed04..66b3e9ed04 100644 --- a/plugins/time/time.gd +++ b/tools/script_plugins/time/time.gd |