diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/gdscript/gd_compiler.cpp | 73 | ||||
-rw-r--r-- | modules/gdscript/gd_compiler.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gd_editor.cpp | 574 | ||||
-rw-r--r-- | modules/gdscript/gd_functions.cpp | 62 | ||||
-rw-r--r-- | modules/gdscript/gd_functions.h | 5 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.cpp | 97 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.h | 12 | ||||
-rw-r--r-- | modules/gdscript/gd_pretty_print.cpp | 2 | ||||
-rw-r--r-- | modules/gdscript/gd_pretty_print.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gd_script.cpp | 104 | ||||
-rw-r--r-- | modules/gdscript/gd_script.h | 8 | ||||
-rw-r--r-- | modules/gdscript/gd_tokenizer.cpp | 38 | ||||
-rw-r--r-- | modules/gdscript/gd_tokenizer.h | 3 | ||||
-rw-r--r-- | modules/gdscript/register_types.h | 2 | ||||
-rw-r--r-- | modules/gridmap/grid_map.cpp | 10 | ||||
-rw-r--r-- | modules/gridmap/grid_map.h | 2 | ||||
-rw-r--r-- | modules/gridmap/grid_map_editor_plugin.cpp | 164 | ||||
-rw-r--r-- | modules/gridmap/grid_map_editor_plugin.h | 23 | ||||
-rw-r--r-- | modules/gridmap/register_types.cpp | 2 | ||||
-rw-r--r-- | modules/gridmap/register_types.h | 2 |
20 files changed, 963 insertions, 224 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index 278651d642..a62225f663 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -28,15 +28,6 @@ /*************************************************************************/ #include "gd_compiler.h" #include "gd_script.h" -/* TODO: - - *AND and OR need early abort - -Inheritance properly process (done?) - *create built in initializer and constructor - *assign operators - *build arrays and dictionaries - *call parent constructor - */ void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) { @@ -559,7 +550,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre int index; if (named) { +#ifdef DEBUG_ENABLED + if (on->arguments[0]->type==GDParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) { + const Map<StringName,GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name); + if (MI && MI->get().getter==codegen.function_node->name) { + String n = static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name; + _set_error("Must use '"+n+"' instead of 'self."+n+"' in getter.",on); + return -1; + } + } +#endif index=codegen.get_name_map_pos(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name); } else { @@ -703,6 +704,25 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre if (on->arguments[0]->type==GDParser::Node::TYPE_OPERATOR && (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX || static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED)) { //SET (chained) MODE!! + +#ifdef DEBUG_ENABLED + if (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED) { + const GDParser::OperatorNode* inon = static_cast<GDParser::OperatorNode*>(on->arguments[0]); + + + if (inon->arguments[0]->type==GDParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) { + + const Map<StringName,GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(static_cast<GDParser::IdentifierNode*>(inon->arguments[1])->name); + if (MI && MI->get().setter==codegen.function_node->name) { + String n = static_cast<GDParser::IdentifierNode*>(inon->arguments[1])->name; + _set_error("Must use '"+n+"' instead of 'self."+n+"' in setter.",inon); + return -1; + } + } + } +#endif + + int slevel=p_stack_level; GDParser::OperatorNode* op = static_cast<GDParser::OperatorNode*>(on->arguments[0]); @@ -1368,13 +1388,14 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars int index_from=0; + Ref<GDNativeClass> native; if (p_class->extends_used) { //do inheritance String path = p_class->extends_file; Ref<GDScript> script; - Ref<GDNativeClass> native; + if (path!="") { //path (and optionally subclasses) @@ -1386,7 +1407,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars _set_error("Could not resolve relative path for parent class: "+path,p_class); return ERR_FILE_NOT_FOUND; } - path=base.get_base_dir().plus_file(path); + path=base.get_base_dir().plus_file(path).simplify_path(); } script = ResourceLoader::load(path); if (script.is_null()) { @@ -1544,7 +1565,35 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars //p_script->constants[constant->value].make_const(); } + for(int i=0;i<p_class->_signals.size();i++) { + + StringName name = p_class->_signals[i].name; + + GDScript *c = p_script; + while(c) { + + if (c->_signals.has(name)) { + _set_error("Signal '"+name+"' redefined (in current or parent class)",p_class); + return ERR_ALREADY_EXISTS; + } + + if (c->base.is_valid()) { + c=c->base.ptr(); + } else { + c=NULL; + } + } + + if (native.is_valid()) { + if (ObjectTypeDB::has_signal(native->get_name(),name)) { + _set_error("Signal '"+name+"' redefined (original in native class '"+String(native->get_name())+"')",p_class); + return ERR_ALREADY_EXISTS; + } + } + + p_script->_signals[name]=p_class->_signals[i].arguments; + } //parse sub-classes for(int i=0;i<p_class->subclasses.size();i++) { diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h index 0c34c23b25..bdf4e9816a 100644 --- a/modules/gdscript/gd_compiler.h +++ b/modules/gdscript/gd_compiler.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index df091fbcc9..7cb9882f3a 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -29,11 +29,12 @@ #include "gd_script.h" #include "gd_compiler.h" #include "globals.h" +#include "os/file_access.h" void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { p_delimiters->push_back("#"); - p_delimiters->push_back("\"\"\""); + p_delimiters->push_back("\"\"\" \"\"\""); } void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { @@ -238,26 +239,26 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p if (_debug_parse_err_line>=0) return; - ERR_FAIL_INDEX(p_level,_debug_call_stack_pos); - int l = _debug_call_stack_pos - p_level -1; + ERR_FAIL_INDEX(p_level,_debug_call_stack_pos); + int l = _debug_call_stack_pos - p_level -1; - GDInstance *instance = _call_stack[l].instance; + GDInstance *instance = _call_stack[l].instance; - if (!instance) - return; + if (!instance) + return; - Ref<GDScript> script = instance->get_script(); - ERR_FAIL_COND( script.is_null() ); + Ref<GDScript> script = instance->get_script(); + ERR_FAIL_COND( script.is_null() ); - const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices(); + const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices(); - for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) { + for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) { - p_members->push_back(E->key()); - p_values->push_back( instance->debug_get_member_by_index(E->get().index)); - } + p_members->push_back(E->key()); + p_values->push_back( instance->debug_get_member_by_index(E->get().index)); + } } void GDScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) { @@ -317,6 +318,7 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam struct GDCompletionIdentifier { StringName obj_type; + Ref<GDScript> script; Variant::Type type; Variant value; //im case there is a value, also return it }; @@ -381,7 +383,12 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) { path=context.base_path.plus_file(path); } - script = ResourceLoader::load(path); + + if (ScriptCodeCompletionCache::get_sigleton()) + script = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path); + else + script = ResourceLoader::load(path); + if (script.is_null()) { return REF(); } @@ -441,7 +448,7 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) { base_class=base_class->subclasses[subclass]; } else { - print_line("Could not find subclass: "+subclass); + //print_line("Could not find subclass: "+subclass); return _get_type_from_class(context); //fail please } } @@ -626,7 +633,9 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: //try calling the function if constant and all args are constant, should not crash.. Object *baseptr = base.value; - if (baseptr && mb->is_const() && pi.type==Variant::OBJECT) { + + if (mb->is_const() && pi.type==Variant::OBJECT) { + bool all_valid=true; Vector<Variant> args; for(int i=2;i<op->arguments.size();i++) { @@ -643,25 +652,88 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: all_valid=false; } } - if (all_valid) { - Vector<const Variant*> argptr; - for(int i=0;i<args.size();i++) { - argptr.push_back(&args[i]); - } - Variant::CallError ce; - Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce); + if (all_valid && String(id)=="get_node" && ObjectTypeDB::is_type(base.obj_type,"Node") && args.size()) { + + String arg1=args[0]; + if (arg1.begins_with("/root/")) { + String which = arg1.get_slice("/",2); + if (which!="") { + List<PropertyInfo> props; + Globals::get_singleton()->get_property_list(&props); + //print_line("find singleton"); + for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { - if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) { + String s = E->get().name; + if (!s.begins_with("autoload/")) + continue; + //print_line("found "+s); + String name = s.get_slice("/",1); + //print_line("name: "+name+", which: "+which); + if (name==which) { + String script = Globals::get_singleton()->get(s); - if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) { + if (!script.begins_with("res://")) { + script="res://"+script; + } - r_type=_get_type_from_variant(ret); - return true; + if (!script.ends_with(".gd")) { + //not a script, try find the script anyway, + //may have some success + script=script.basename()+".gd"; + } + + if (FileAccess::exists(script)) { + + //print_line("is a script"); + + + Ref<Script> scr; + if (ScriptCodeCompletionCache::get_sigleton()) + scr = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(script); + else + scr = ResourceLoader::load(script); + + + r_type.obj_type="Node"; + r_type.type=Variant::OBJECT; + r_type.script=scr; + r_type.value=Variant(); + + return true; + + } + } + } } } + } + + + if (baseptr) { + + if (all_valid) { + Vector<const Variant*> argptr; + for(int i=0;i<args.size();i++) { + argptr.push_back(&args[i]); + } + + Variant::CallError ce; + Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce); + + + if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) { + + if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) { + + r_type=_get_type_from_variant(ret); + return true; + } + } + + } } } @@ -1195,7 +1267,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl } static const char*_type_names[Variant::VARIANT_MAX]={ - "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform", + "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Transform", "Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray", "Vector2Array","Vector3Array","ColorArray"}; @@ -1276,6 +1348,7 @@ static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argid static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const StringName& p_method,const GDCompletionIdentifier& id, int p_argidx, Set<String>& result, String& arghint) { + //print_line("find type arguments?"); if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) { List<PropertyInfo> pinfo; @@ -1296,78 +1369,300 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method); - if (!m) - return; + if (!m) { + //not in static method, see script + + //print_line("not in static: "+String(p_method)); + Ref<GDScript> on_script; + + if (id.value.get_type()) { + Object *obj=id.value; + + + if (obj) { + + + GDScript *scr = obj->cast_to<GDScript>(); + if (scr) { + while (scr) { + + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + if (E->get().is_static() && p_method==E->get().get_name()) { + arghint="static func "+String(p_method)+"("; + for(int i=0;i<E->get().get_argument_count();i++) { + if (i>0) + arghint+=", "; + else + arghint+=" "; + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + arghint+="var "+E->get().get_argument_name(i); + int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count(); + if (i>=deffrom) { + int defidx = deffrom-i; + if (defidx>=0 && defidx<E->get().get_default_argument_count()) { + arghint+="="+E->get().get_default_argument(defidx).get_construct_string(); + } + } + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + } + arghint+=")"; + return; //found + } + } + + if (scr->get_base().is_valid()) + scr=scr->get_base().ptr(); + else + scr=NULL; + } + } else { + on_script=obj->get_script(); + } + } + } + + //print_line("but it has a script?"); + if (!on_script.is_valid() && id.script.is_valid()) { + //print_line("yes"); + on_script=id.script; + } - if (p_method.operator String()=="connect") { + if (on_script.is_valid()) { + GDScript *scr = on_script.ptr(); + if (scr) { + while (scr) { - if (p_argidx==0) { - List<MethodInfo> sigs; - ObjectTypeDB::get_signal_list(id.obj_type,&sigs); - for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) { - result.insert("\""+E->get().name+"\""); + String code = scr->get_source_code(); + //print_line("has source code!"); + + if (code!="") { + //if there is code, parse it. This way is slower but updates in real-time + GDParser p; + //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false); + + Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false); + + if (err==OK) { + //print_line("checking the functions..."); + //only if ok, otherwise use what is cached on the script + //GDParser::ClassNode *base = p. + const GDParser::Node *root = p.get_parse_tree(); + ERR_FAIL_COND(root->type!=GDParser::Node::TYPE_CLASS); + + const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root); + + const GDParser::FunctionNode* func=NULL; + bool st=false; + + for(int i=0;i<cl->functions.size();i++) { + //print_line(String(cl->functions[i]->name)+" vs "+String(p_method)); + if (cl->functions[i]->name==p_method) { + func=cl->functions[i]; + } + } + + for(int i=0;i<cl->static_functions.size();i++) { + + //print_line(String(cl->static_functions[i]->name)+" vs "+String(p_method)); + if (cl->static_functions[i]->name==p_method) { + func=cl->static_functions[i]; + st=true; + } + + } + + if (func) { + + arghint="func "+String(p_method)+"("; + if (st) + arghint="static "+arghint; + for(int i=0;i<func->arguments.size();i++) { + if (i>0) + arghint+=", "; + else + arghint+=" "; + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + arghint+="var "+String(func->arguments[i]); + int deffrom = func->arguments.size()-func->default_values.size(); + if (i>=deffrom) { + + int defidx = deffrom-i; + + if (defidx>=0 && defidx<func->default_values.size() && func->default_values[defidx]->type==GDParser::Node::TYPE_OPERATOR) { + const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(func->default_values[defidx]); + if (op->op==GDParser::OperatorNode::OP_ASSIGN) { + const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(op->arguments[1]); + arghint+="="+cn->value.get_construct_string(); + } + } + } + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + } + + arghint+=" )"; + return; + } + } else { + //print_line("failed parsing?"); + code=""; + } + + } + + if (code=="") { + + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + if (p_method==E->get().get_name()) { + arghint="func "+String(p_method)+"("; + for(int i=0;i<E->get().get_argument_count();i++) { + if (i>0) + arghint+=", "; + else + arghint+=" "; + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + arghint+="var "+E->get().get_argument_name(i); + int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count(); + if (i>=deffrom) { + int defidx = deffrom-i; + if (defidx>=0 && defidx<E->get().get_default_argument_count()) { + arghint+="="+E->get().get_default_argument(defidx).get_construct_string(); + } + } + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + } + arghint+=")"; + return; //found + } + } +#if 0 + //use class directly, no code was found + if (!isfunction) { + for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) { + options.insert(E->key()); + } + } + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + options.insert(String(E->key())+"("); + } + + for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) { + options.insert(E->get()); + } +#endif + } + + if (scr->get_base().is_valid()) + scr=scr->get_base().ptr(); + else + scr=NULL; + } } } - /*if (p_argidx==2) { - ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR); - const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node); - if (op->arguments.size()>) - }*/ } else { + //regular method - Object *obj=id.value; - if (obj) { - List<String> options; - obj->get_argument_options(p_method,p_argidx,&options); - for(List<String>::Element *E=options.front();E;E=E->next()) { + if (p_method.operator String()=="connect") { - result.insert(E->get()); + + if (p_argidx==0) { + List<MethodInfo> sigs; + ObjectTypeDB::get_signal_list(id.obj_type,&sigs); + for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) { + result.insert("\""+E->get().name+"\""); + } } - } + /*if (p_argidx==2) { - } + ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR); + const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node); + if (op->arguments.size()>) - arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("("); + }*/ + } else { - for(int i=0;i<m->get_argument_count();i++) { - if (i>0) - arghint+=", "; - else - arghint+=" "; + if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ObjectTypeDB::is_type(id.obj_type,"Node")) { - if (i==p_argidx) { - arghint+=String::chr(0xFFFF); - } - String n = m->get_argument_info(i).name; - int dp = n.find(":"); - if (dp!=-1) - n=n.substr(0,dp); - arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n; - int deffrom = m->get_argument_count()-m->get_default_argument_count(); + List<PropertyInfo> props; + Globals::get_singleton()->get_property_list(&props); + + for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { + String s = E->get().name; + if (!s.begins_with("autoload/")) + continue; + // print_line("found "+s); + String name = s.get_slice("/",1); + result.insert("\"/root/"+name+"\""); + } + } - if (i>=deffrom) { - int defidx = i-deffrom; + Object *obj=id.value; + if (obj) { + List<String> options; + obj->get_argument_options(p_method,p_argidx,&options); - if (defidx>=0 && defidx<m->get_default_argument_count()) { - Variant v= m->get_default_argument(i); - arghint+="="+v.get_construct_string(); + for(List<String>::Element *E=options.front();E;E=E->next()) { + + result.insert(E->get()); + } } - } - if (i==p_argidx) { - arghint+=String::chr(0xFFFF); } - } - if (m->get_argument_count()>0) - arghint+=" "; + arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("("); + for(int i=0;i<m->get_argument_count();i++) { + if (i>0) + arghint+=", "; + else + arghint+=" "; - arghint+=")"; + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + String n = m->get_argument_info(i).name; + int dp = n.find(":"); + if (dp!=-1) + n=n.substr(0,dp); + arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n; + int deffrom = m->get_argument_count()-m->get_default_argument_count(); + + + if (i>=deffrom) { + int defidx = i-deffrom; + + if (defidx>=0 && defidx<m->get_default_argument_count()) { + Variant v= m->get_default_argument(i); + arghint+="="+v.get_construct_string(); + } + } + + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + + } + if (m->get_argument_count()>0) + arghint+=" "; + + + arghint+=")"; + } } } @@ -1414,7 +1709,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No arghint+=")"; } else if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) { - //complete built-in function + //complete constructor const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode*>(op->arguments[0]); List<MethodInfo> mil; @@ -1549,7 +1844,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No } } else { - + //indexed lookup GDCompletionIdentifier ci; if (_guess_expression_type(context,op->arguments[0],p_line,ci)) { @@ -1661,7 +1956,9 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base //print_line( p_code.replace(String::chr(0xFFFF),"<cursor>")); GDParser p; - Error err = p.parse(p_code,p_base_path,true); + //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false); + + Error err = p.parse(p_code,p_base_path,false,"",true); bool isfunction=false; Set<String> options; @@ -1713,20 +2010,123 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base if (t.type==Variant::OBJECT && t.obj_type!=StringName()) { + Ref<GDScript> on_script; if (t.value.get_type()) { Object *obj=t.value; + + if (obj) { + + GDScript *scr = obj->cast_to<GDScript>(); + if (scr) { + while (scr) { + + if (!isfunction) { + for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) { + options.insert(E->key()); + } + } + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + if (E->get().is_static()) + options.insert(E->key()); + } + + if (scr->get_base().is_valid()) + scr=scr->get_base().ptr(); + else + scr=NULL; + } + } else { + on_script=obj->get_script(); + } + } + } + + + if (!on_script.is_valid() && t.script.is_valid()) { + on_script=t.script; + } + + if (on_script.is_valid()) { + + GDScript *scr = on_script.ptr(); + if (scr) { while (scr) { - if (!isfunction) { - for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) { - options.insert(E->key()); + String code = scr->get_source_code(); + + if (code!="") { + //if there is code, parse it. This way is slower but updates in real-time + GDParser p; + //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false); + + Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false); + + if (err==OK) { + //only if ok, otherwise use what is cached on the script + //GDParser::ClassNode *base = p. + const GDParser::Node *root = p.get_parse_tree(); + ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_PARSE_ERROR); + + const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root); + + for(int i=0;i<cl->functions.size();i++) { + + if (cl->functions[i]->arguments.size()) + options.insert(String(cl->functions[i]->name)+"("); + else + options.insert(String(cl->functions[i]->name)+"()"); + } + + for(int i=0;i<cl->static_functions.size();i++) { + + if (cl->static_functions[i]->arguments.size()) + options.insert(String(cl->static_functions[i]->name)+"("); + else + options.insert(String(cl->static_functions[i]->name)+"()"); + + } + + if (!isfunction) { + for(int i=0;i<cl->variables.size();i++) { + + options.insert(String(cl->variables[i].identifier)); + } + + for(int i=0;i<cl->constant_expressions.size();i++) { + + options.insert(String(cl->constant_expressions[i].identifier)); + } + + } + + + } else { + code=""; //well, then no code } + } - for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { - options.insert(E->key()); + + if (code=="") { + //use class directly, no code was found + if (!isfunction) { + for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) { + options.insert(E->key()); + } + } + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + if (E->get().get_argument_count()) + options.insert(String(E->key())+"()"); + else + options.insert(String(E->key())+"("); + + } + + for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) { + options.insert(E->get()); + } } if (scr->get_base().is_valid()) @@ -1738,6 +2138,10 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base } + + + + if (!isfunction) { ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options); } diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index f37b2f645a..37ddb2bc41 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -71,6 +71,7 @@ const char *GDFunctions::get_func_name(Function p_func) { "randi", "randf", "rand_range", + "seed", "rand_seed", "deg2rad", "rad2deg", @@ -87,6 +88,7 @@ const char *GDFunctions::get_func_name(Function p_func) { "str", "print", "printt", + "prints", "printerr", "printraw", "var2str", @@ -97,6 +99,7 @@ const char *GDFunctions::get_func_name(Function p_func) { "dict2inst", "hash", "print_stack", + "instance_from_id", }; return _names[p_func]; @@ -328,6 +331,13 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va VALIDATE_ARG_NUM(1); r_ret=Math::random(*p_args[0],*p_args[1]); } break; + case MATH_SEED: { + VALIDATE_ARG_COUNT(1); + VALIDATE_ARG_NUM(0); + uint32_t seed=*p_args[0]; + Math::seed(seed); + r_ret=Variant(); + } break; case MATH_RANDSEED: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); @@ -553,6 +563,22 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va } break; + case TEXT_PRINT_SPACED: { + + String str; + for(int i=0;i<p_arg_count;i++) { + + if (i) + str+=" "; + str+=p_args[i]->operator String(); + } + + //str+="\n"; + print_line(str); + r_ret=Variant(); + + + } break; case TEXT_PRINTERR: { @@ -575,7 +601,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va } //str+="\n"; - OS::get_singleton()->print("%s\n",str.utf8().get_data()); + OS::get_singleton()->print("%s",str.utf8().get_data()); r_ret=Variant(); } break; @@ -895,6 +921,20 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va }; } break; + case INSTANCE_FROM_ID: { + + VALIDATE_ARG_COUNT(1); + if (p_args[0]->get_type()!=Variant::INT && p_args[0]->get_type()!=Variant::REAL) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_ret=Variant(); + break; + } + + uint32_t id=*p_args[0]; + r_ret=ObjectDB::get_instance(id); + + } break; case FUNC_MAX: { ERR_FAIL_V(); @@ -1130,6 +1170,11 @@ MethodInfo GDFunctions::get_info(Function p_func) { mi.return_val.type=Variant::REAL; return mi; } break; + case MATH_SEED: { + MethodInfo mi("seed",PropertyInfo(Variant::REAL,"seed")); + mi.return_val.type=Variant::NIL; + return mi; + } break; case MATH_RANDSEED: { MethodInfo mi("rand_seed",PropertyInfo(Variant::REAL,"seed")); mi.return_val.type=Variant::ARRAY; @@ -1224,6 +1269,13 @@ MethodInfo GDFunctions::get_info(Function p_func) { return mi; } break; + case TEXT_PRINT_SPACED: { + + MethodInfo mi("prints",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); + mi.return_val.type=Variant::NIL; + return mi; + + } break; case TEXT_PRINTERR: { MethodInfo mi("printerr",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); @@ -1288,6 +1340,12 @@ MethodInfo GDFunctions::get_info(Function p_func) { return mi; } break; + case INSTANCE_FROM_ID: { + MethodInfo mi("instance_from_id",PropertyInfo(Variant::INT,"instance_id")); + mi.return_val.type=Variant::OBJECT; + return mi; + } break; + case FUNC_MAX: { ERR_FAIL_V(MethodInfo()); diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h index 05ff6a2e73..ad35a628d5 100644 --- a/modules/gdscript/gd_functions.h +++ b/modules/gdscript/gd_functions.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -67,6 +67,7 @@ public: MATH_RAND, MATH_RANDF, MATH_RANDOM, + MATH_SEED, MATH_RANDSEED, MATH_DEG2RAD, MATH_RAD2DEG, @@ -83,6 +84,7 @@ public: TEXT_STR, TEXT_PRINT, TEXT_PRINT_TABBED, + TEXT_PRINT_SPACED, TEXT_PRINTERR, TEXT_PRINTRAW, VAR_TO_STR, @@ -93,6 +95,7 @@ public: DICT2INST, HASH, PRINT_STACK, + INSTANCE_FROM_ID, FUNC_MAX }; diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index aa2878f9e1..afe8c9aa71 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -30,6 +30,7 @@ #include "print_string.h" #include "io/resource_loader.h" #include "os/file_access.h" +#include "script_language.h" template<class T> T* GDParser::alloc_node() { @@ -116,6 +117,14 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) { _make_completable_call(argidx); completion_node=p_parent; + } else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING && tokenizer->get_token(1)==GDTokenizer::TK_CURSOR) { + //completing a string argument.. + completion_cursor=tokenizer->get_token_constant(); + + _make_completable_call(argidx); + completion_node=p_parent; + tokenizer->advance(1); + return false; } Node*arg = _parse_expression(p_parent,p_static); @@ -277,7 +286,11 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ if (!validating) { //this can be too slow for just validating code - res = ResourceLoader::load(path); + if (for_completion && ScriptCodeCompletionCache::get_sigleton()) { + res = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path); + } else { + res = ResourceLoader::load(path); + } if (!res.is_valid()) { _set_error("Can't preload resource at path: "+path); return NULL; @@ -1075,6 +1088,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) { ConstantNode *cn = alloc_node<ConstantNode>(); Array arr(!p_to_const); + //print_line("mk array "+itos(!p_to_const)); arr.resize(an->elements.size()); for(int i=0;i<an->elements.size();i++) { ConstantNode *acn = static_cast<ConstantNode*>(an->elements[i]); @@ -1461,7 +1475,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } 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 && tokenizer->get_token(1)!=GDTokenizer::TK_EOF) { _set_error("Expected ';' or <NewLine>."); return; @@ -1519,8 +1533,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { op->arguments.push_back(assigned); p_block->statements.push_back(op); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (var)"); + return; + } } break; case GDTokenizer::TK_CF_IF: { @@ -1945,8 +1961,10 @@ void GDParser::_parse_class(ClassNode *p_class) { _parse_extends(p_class); if (error_set) return; - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement after extends"); + return; + } } break; case GDTokenizer::TK_PR_TOOL: { @@ -2226,6 +2244,53 @@ void GDParser::_parse_class(ClassNode *p_class) { //arguments } break; + case GDTokenizer::TK_PR_SIGNAL: { + tokenizer->advance(); + + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier after 'signal'."); + return; + } + + ClassNode::Signal sig; + sig.name = tokenizer->get_token_identifier(); + tokenizer->advance(); + + + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { + tokenizer->advance(); + while(true) { + + + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { + tokenizer->advance(); + break; + } + + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier in signal argument."); + return; + } + + sig.arguments.push_back(tokenizer->get_token_identifier()); + tokenizer->advance(); + + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); + } else if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ',' or ')' after signal parameter identifier."); + return; + } + } + } + + p_class->_signals.push_back(sig); + + if (!_end_statement()) { + _set_error("Expected end of statement (signal)"); + return; + } + } break; case GDTokenizer::TK_PR_EXPORT: { tokenizer->advance(); @@ -2643,8 +2708,10 @@ void GDParser::_parse_class(ClassNode *p_class) { p_class->variables.push_back(member); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (continue)"); + return; + } } break; case GDTokenizer::TK_PR_CONST: { //variale declaration and (eventual) initialization @@ -2681,8 +2748,10 @@ void GDParser::_parse_class(ClassNode *p_class) { p_class->constant_expressions.push_back(constant); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (constant)"); + return; + } } break; @@ -2758,6 +2827,8 @@ Error GDParser::_parse(const String& p_base_path) { Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path, const String &p_self_path) { + for_completion=false; + validating=false; completion_type=COMPLETION_NONE; completion_node=NULL; completion_class=NULL; @@ -2778,7 +2849,7 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p } -Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path) { +Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path,bool p_for_completion) { completion_type=COMPLETION_NONE; completion_node=NULL; @@ -2795,6 +2866,7 @@ Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_ju tt->set_code(p_code); validating=p_just_validate; + for_completion=p_for_completion; tokenizer=tt; Error ret = _parse(p_base_path); memdelete(tt); @@ -2830,6 +2902,7 @@ void GDParser::clear() { current_function=NULL; validating=false; + for_completion=false; error_set=false; tab_level.clear(); tab_level.push_back(0); diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 44e7b55323..fd8a2576fa 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -76,6 +76,7 @@ public: StringName extends_file; Vector<StringName> extends_class; + struct Member { PropertyInfo _export; #ifdef TOOLS_ENABLED @@ -92,11 +93,17 @@ public: Node *expression; }; + struct Signal { + StringName name; + Vector<StringName> arguments; + }; + Vector<ClassNode*> subclasses; Vector<Member> variables; Vector<Constant> constant_expressions; Vector<FunctionNode*> functions; Vector<FunctionNode*> static_functions; + Vector<Signal> _signals; BlockNode *initializer; ClassNode *owner; //Vector<Node*> initializers; @@ -380,6 +387,7 @@ private: T* alloc_node(); bool validating; + bool for_completion; int parenthesis; bool error_set; String error; @@ -436,7 +444,7 @@ 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="", bool p_just_validate=false,const String& p_self_path=""); + Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false); Error parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path="",const String& p_self_path=""); const Node *get_parse_tree() const; diff --git a/modules/gdscript/gd_pretty_print.cpp b/modules/gdscript/gd_pretty_print.cpp index a5a993bb3a..9c290eac4a 100644 --- a/modules/gdscript/gd_pretty_print.cpp +++ b/modules/gdscript/gd_pretty_print.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ diff --git a/modules/gdscript/gd_pretty_print.h b/modules/gdscript/gd_pretty_print.h index fbf002295b..998fdc53ab 100644 --- a/modules/gdscript/gd_pretty_print.h +++ b/modules/gdscript/gd_pretty_print.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 06c746c4fb..53ae0c8702 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -140,7 +140,7 @@ String GDFunction::_get_call_error(const Variant::CallError& p_err, const String } else if (p_err.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { err_text="Invalid call to "+p_where+". Expected "+itos(p_err.argument)+" arguments."; } else if (p_err.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) { - err_text="Invalid call. Unexisting "+p_where+"."; + err_text="Invalid call. Nonexistent "+p_where+"."; } else if (p_err.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) { err_text="Attempt to call "+p_where+" on a null instance."; } else { @@ -335,17 +335,30 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GET_VARIANT_PTR(b,3); GET_VARIANT_PTR(dst,4); +#ifdef DEBUG_ENABLED + Variant ret; + Variant::evaluate(op,*a,*b,ret,valid); +#else Variant::evaluate(op,*a,*b,*dst,valid); +#endif + if (!valid) { - if (dst->get_type()==Variant::STRING) { +#ifdef DEBUG_ENABLED + + if (ret.get_type()==Variant::STRING) { //return a string when invalid with the error - err_text=*dst; + err_text=ret; err_text += " in operator '"+Variant::get_operator_name(op)+"'."; } else { err_text="Invalid operands '"+Variant::get_type_name(a->get_type())+"' and '"+Variant::get_type_name(b->get_type())+"' in operator '"+Variant::get_operator_name(op)+"'."; } +#endif break; + } +#ifdef DEBUG_ENABLED + *dst=ret; +#endif ip+=5; @@ -457,8 +470,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GET_VARIANT_PTR(dst,3); bool valid; +#ifdef DEBUG_ENABLED +//allow better error message in cases where src and dst are the same stack position + Variant ret = src->get(*index,&valid); +#else *dst = src->get(*index,&valid); +#endif if (!valid) { String v = index->operator String(); if (v!="") { @@ -469,6 +487,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a err_text="Invalid get index "+v+" (on base: '"+_get_var_type(src)+"')."; break; } +#ifdef DEBUG_ENABLED + *dst=ret; +#endif ip+=4; } continue; case OPCODE_SET_NAMED: { @@ -508,7 +529,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a const StringName *index = &_global_names_ptr[indexname]; bool valid; +#ifdef DEBUG_ENABLED +//allow better error message in cases where src and dst are the same stack position + Variant ret = src->get_named(*index,&valid); + +#else *dst = src->get_named(*index,&valid); +#endif if (!valid) { if (src->has_method(*index)) { @@ -518,7 +545,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } break; } - +#ifdef DEBUG_ENABLED + *dst=ret; +#endif ip+=4; } continue; case OPCODE_ASSIGN: { @@ -1689,7 +1718,7 @@ bool GDScript::_update_exports() { } - if (c->extends_used && String(c->extends_file)!="") { + if (c->extends_used && String(c->extends_file)!="" && String(c->extends_file) != get_path()) { String path = c->extends_file; if (path.is_rel_path()) { @@ -1727,6 +1756,12 @@ bool GDScript::_update_exports() { //print_line("found "+c->variables[i]._export.name); member_default_values_cache[c->variables[i].identifier]=c->variables[i].default_value; } + + _signals.clear(); + + for(int i=0;i<c->_signals.size();i++) { + _signals[c->_signals[i].name]=c->_signals[i].arguments; + } } } else { //print_line("unchaged is "+get_path()); @@ -1942,9 +1977,17 @@ void GDScript::_bind_methods() { ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo("new")); + ObjectTypeDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code); + } +Vector<uint8_t> GDScript::get_as_byte_code() const { + + GDTokenizerBuffer tokenizer; + return tokenizer.parse_code_string(source); +}; + Error GDScript::load_byte_code(const String& p_path) { @@ -2071,6 +2114,47 @@ Ref<GDScript> GDScript::get_base() const { return base; } +bool GDScript::has_script_signal(const StringName& p_signal) const { + if (_signals.has(p_signal)) + return true; + if (base.is_valid()) { + return base->has_script_signal(p_signal); + } +#ifdef TOOLS_ENABLED + else if (base_cache.is_valid()){ + return base_cache->has_script_signal(p_signal); + } + +#endif + return false; +} +void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + + for(const Map<StringName,Vector<StringName> >::Element *E=_signals.front();E;E=E->next()) { + + MethodInfo mi; + mi.name=E->key(); + for(int i=0;i<E->get().size();i++) { + PropertyInfo arg; + arg.name=E->get()[i]; + mi.arguments.push_back(arg); + } + r_signals->push_back(mi); + } + + if (base.is_valid()) { + base->get_script_signal_list(r_signals); + } +#ifdef TOOLS_ENABLED + else if (base_cache.is_valid()){ + base_cache->get_script_signal_list(r_signals); + } + +#endif + +} + + GDScript::GDScript() { @@ -2102,7 +2186,6 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) { { const Map<StringName,GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); if (E) { - members[E->get().index]=p_value; if (E->get().setter) { const Variant *val=&p_value; Variant::CallError err; @@ -2111,6 +2194,8 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) { return true; //function exists, call was successful } } + else + members[E->get().index] = p_value; return true; } } @@ -2479,9 +2564,9 @@ void GDScriptLanguage::init() { //populate native classes - List<String> class_list; + List<StringName> class_list; ObjectTypeDB::get_type_list(&class_list); - for(List<String>::Element *E=class_list.front();E;E=E->next()) { + for(List<StringName>::Element *E=class_list.front();E;E=E->next()) { StringName n = E->get(); String s = String(n); @@ -2564,6 +2649,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "static", "float", "int", + "signal", 0}; diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 5574b30d44..1e1279d5f5 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -260,6 +260,7 @@ friend class GDScriptLanguage; Map<StringName,GDFunction> member_functions; Map<StringName,MemberInfo> member_indices; //members are just indices to the instanced script. Map<StringName,Ref<GDScript> > subclasses; + Map<StringName,Vector<StringName> > _signals; #ifdef TOOLS_ENABLED @@ -318,6 +319,9 @@ public: const Map<StringName,GDFunction>& get_member_functions() const { return member_functions; } const Ref<GDNativeClass>& get_native() const { return native; } + virtual bool has_script_signal(const StringName& p_signal) const; + virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + bool is_tool() const { return tool; } Ref<GDScript> get_base() const; @@ -345,6 +349,8 @@ public: Error load_source_code(const String& p_path); Error load_byte_code(const String& p_path); + Vector<uint8_t> get_as_byte_code() const; + virtual ScriptLanguage *get_language() const; GDScript(); diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index 1979577a17..8b25b38bd3 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -568,7 +568,10 @@ void GDTokenizerText::_advance() { } else if( string_mode!=STRING_MULTILINE && CharType(GETCHAR(i))=='\n') { _make_error("Unexpected EOL at String."); return; - + } else if( CharType(GETCHAR(i))==0xFFFF) { + //string ends here, next will be TK + i--; + break; } else if (CharType(GETCHAR(i))=='\\') { //escaped characters... i++; @@ -670,19 +673,19 @@ void GDTokenizerText::_advance() { while(true) { if (GETCHAR(i)=='.') { if (period_found || exponent_found) { - _make_error("Invalid numeric constant at '.'"); + _make_error("Invalid numeric constant at '.'"); return; } period_found=true; } else if (GETCHAR(i)=='x') { - if (hexa_found || str.length()!=1 || !( (i==1 && str[0]=='0') || (i==2 && str[1]=='0' && str[0]=='-') ) ) { - _make_error("Invalid numeric constant at 'x'"); + if (hexa_found || str.length()!=1 || !( (i==1 && str[0]=='0') || (i==2 && str[1]=='0' && str[0]=='-') ) ) { + _make_error("Invalid numeric constant at 'x'"); return; } hexa_found=true; - } else if (!hexa_found && GETCHAR(i)=='e') { + } else if (!hexa_found && GETCHAR(i)=='e') { if (hexa_found || exponent_found) { - _make_error("Invalid numeric constant at 'e'"); + _make_error("Invalid numeric constant at 'e'"); return; } exponent_found=true; @@ -692,7 +695,7 @@ void GDTokenizerText::_advance() { } else if ((GETCHAR(i)=='-' || GETCHAR(i)=='+') && exponent_found) { if (sign_found) { - _make_error("Invalid numeric constant at '-'"); + _make_error("Invalid numeric constant at '-'"); return; } sign_found=true; @@ -703,20 +706,20 @@ void GDTokenizerText::_advance() { i++; } - if (!( _is_number(str[str.length()-1]) || (hexa_found && _is_hex(str[str.length()-1])))) { - _make_error("Invalid numeric constant: "+str); + if (!( _is_number(str[str.length()-1]) || (hexa_found && _is_hex(str[str.length()-1])))) { + _make_error("Invalid numeric constant: "+str); return; } INCPOS(str.length()); - if (hexa_found) { - int val = str.hex_to_int(); - _make_constant(val); - } else if (period_found) { + if (hexa_found) { + int val = str.hex_to_int(); + _make_constant(val); + } else if (period_found) { real_t val = str.to_double(); //print_line("*%*%*%*% to convert: "+str+" result: "+rtos(val)); _make_constant(val); - } else { + } else { int val = str.to_int(); _make_constant(val); @@ -825,7 +828,7 @@ void GDTokenizerText::_advance() { _make_built_in_func(GDFunctions::Function(i)); found=true; - break; + break; } } @@ -856,6 +859,7 @@ void GDTokenizerText::_advance() { {TK_PR_PRELOAD,"preload"}, {TK_PR_ASSERT,"assert"}, {TK_PR_YIELD,"yield"}, + {TK_PR_SIGNAL,"signal"}, {TK_PR_CONST,"const"}, //controlflow {TK_CF_IF,"if"}, @@ -1036,7 +1040,7 @@ void GDTokenizerText::advance(int p_amount) { ////////////////////////////////////////////////////////////////////////////////////////////////////// -#define BYTECODE_VERSION 3 +#define BYTECODE_VERSION 5 Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) { diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index ff59c249a7..d6bd63c5b8 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -104,6 +104,7 @@ public: TK_PR_PRELOAD, TK_PR_ASSERT, TK_PR_YIELD, + TK_PR_SIGNAL, TK_BRACKET_OPEN, TK_BRACKET_CLOSE, TK_CURLY_BRACKET_OPEN, diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h index ff7c2734df..9eb5d1846b 100644 --- a/modules/gdscript/register_types.h +++ b/modules/gdscript/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 441b274e33..4f0daf329f 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -130,8 +130,8 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) { } else if (name.begins_with("areas/")) { - int which = name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); + int which = name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); if (what=="bounds") { ERR_FAIL_COND_V(area_map.has(which),false); create_area(which,p_value); @@ -215,8 +215,8 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const { r_ret= d; } else if (name.begins_with("areas/")) { - int which = name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); + int which = name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); if (what=="bounds") r_ret= area_get_bounds(which); else if (what=="name") diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index df805d99fa..dff9fe3d68 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index f2afffd321..3d56b04cac 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -61,7 +61,7 @@ void GridMapEditor::_menu_option(int p_option) { case MENU_OPTION_CONFIGURE: { - + } break; case MENU_OPTION_LOCK_VIEW: { @@ -522,7 +522,9 @@ void GridMapEditor::_duplicate_paste() { } bool GridMapEditor::forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event) { - + if (!node) { + return false; + } if (edit_mode->get_selected()==0) { // regular click switch (p_event.type) { @@ -706,9 +708,40 @@ struct _CGMEItemSort { }; +void GridMapEditor::_set_display_mode(int p_mode) { + if (display_mode==p_mode) { + return; + } + + if (p_mode == DISPLAY_LIST) { + mode_list->set_pressed(true); + mode_thumbnail->set_pressed(false); + } else if (p_mode == DISPLAY_THUMBNAIL) { + mode_list->set_pressed(false); + mode_thumbnail->set_pressed(true); + } + + display_mode=p_mode; + + update_pallete(); +} + void GridMapEditor::update_pallete() { + int selected = theme_pallete->get_current(); theme_pallete->clear(); + if (display_mode == DISPLAY_THUMBNAIL) { + theme_pallete->set_max_columns(0); + theme_pallete->set_icon_mode(ItemList::ICON_MODE_TOP); + } else if (display_mode == DISPLAY_LIST){ + theme_pallete->set_max_columns(1); + theme_pallete->set_icon_mode(ItemList::ICON_MODE_LEFT); + } + + float min_size = EDITOR_DEF("grid_map/preview_size",64); + theme_pallete->set_min_icon_size(Size2(min_size, min_size)); + theme_pallete->set_fixed_column_width(min_size*3/2); + theme_pallete->set_max_text_lines(2); Ref<MeshLibrary> theme = node->get_theme(); @@ -720,10 +753,6 @@ void GridMapEditor::update_pallete() { Vector<int> ids; ids = theme->get_item_list(); - TreeItem *root = theme_pallete->create_item(NULL); - theme_pallete->set_hide_root(true); - TreeItem *selected=NULL; - List<_CGMEItemSort> il; for(int i=0;i<ids.size();i++) { @@ -734,45 +763,31 @@ void GridMapEditor::update_pallete() { } il.sort(); - int col=0; - TreeItem *ti=NULL; - int selected_col=0; + int item = 0; for(List<_CGMEItemSort>::Element *E=il.front();E;E=E->next()) { - int id = E->get().id; - if (col==0) { - ti = theme_pallete->create_item(root); - } + theme_pallete->add_item(""); String name=theme->get_item_name(id); Ref<Texture> preview = theme->get_item_preview(id); if (!preview.is_null()) { - - ti->set_cell_mode(col,TreeItem::CELL_MODE_ICON); - ti->set_icon(col,preview); - ti->set_tooltip(col,name); - } else { - - ti->set_text(col,name); + theme_pallete->set_item_icon(item, preview); + theme_pallete->set_item_tooltip(item, name); } - ti->set_metadata(col,id); - - if (selected_pallete==id) { - selected=ti; - selected_col=col; + if (name!="") { + theme_pallete->set_item_text(item,name); } + theme_pallete->set_item_metadata(item, id); - col++; - if (col==theme_pallete->get_columns()) - col=0; - + item++; } - if (selected) - selected->select(selected_col); + if (selected!=-1) { + theme_pallete->select(selected); + } last_theme=theme.operator->(); } @@ -842,6 +857,9 @@ void GridMapEditor::edit(GridMap *p_gridmap) { VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,false); } + + VisualServer::get_singleton()->instance_geometry_set_flag(cursor_instance, VS::INSTANCE_FLAG_VISIBLE,false); + _clear_areas(); return; @@ -868,7 +886,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) { { //update grids - RID indicator_mat = VisualServer::get_singleton()->fixed_material_create(); + indicator_mat = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_UNSHADED, true ); VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_ONTOP, false ); @@ -922,7 +940,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) { d[VS::ARRAY_VERTEX]=grid_points[i]; d[VS::ARRAY_COLOR]=grid_colors[i]; VisualServer::get_singleton()->mesh_add_surface(grid[i],VisualServer::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat,true); + VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat); } @@ -951,7 +969,7 @@ void GridMapEditor::update_grid() { grid_xform.origin.x-=1; //force update in hackish way.. what do i care - VS *vs = VS::get_singleton(); + //VS *vs = VS::get_singleton(); grid_ofs[edit_axis]=edit_floor[edit_axis]*node->get_cell_size(); @@ -976,7 +994,7 @@ void GridMapEditor::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { - theme_pallete->connect("cell_selected", this,"_item_selected_cbk"); + theme_pallete->connect("item_selected", this,"_item_selected_cbk"); edit_mode->connect("item_selected", this,"_edit_mode_changed"); area_list->connect("item_edited", this,"_area_renamed"); area_list->connect("item_selected", this,"_area_selected"); @@ -1014,7 +1032,7 @@ void GridMapEditor::_notification(int p_what) { if (xf!=grid_xform) { for(int i=0;i<3;i++) { - + VS::get_singleton()->instance_set_transform(grid_instance[i],xf * edit_grid_xform); } grid_xform=xf; @@ -1043,7 +1061,9 @@ void GridMapEditor::_notification(int p_what) { } void GridMapEditor::_update_cursor_instance() { - + if (!node) { + return; + } if (cursor_instance.is_valid()) VisualServer::get_singleton()->free(cursor_instance); @@ -1063,18 +1083,8 @@ void GridMapEditor::_update_cursor_instance() { } -void GridMapEditor::_item_selected_cbk() { - - TreeItem *it = theme_pallete->get_selected(); - if (it) { - - selected_pallete=it->get_metadata(theme_pallete->get_selected_column()); - - } else { - - selected_pallete=-1; - - } +void GridMapEditor::_item_selected_cbk(int idx) { + selected_pallete=theme_pallete->get_item_metadata(idx); _update_cursor_instance(); @@ -1092,7 +1102,9 @@ void GridMapEditor::_clear_areas() { } void GridMapEditor::_update_areas_display() { - + if (!node) { + return; + } _clear_areas(); List<int> areas; @@ -1179,7 +1191,7 @@ void GridMapEditor::_bind_methods() { ObjectTypeDB::bind_method("_area_selected",&GridMapEditor::_area_selected); ObjectTypeDB::bind_method("_floor_changed",&GridMapEditor::_floor_changed); - + ObjectTypeDB::bind_method(_MD("_set_display_mode","mode"), &GridMapEditor::_set_display_mode); } @@ -1240,6 +1252,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { clip_mode=CLIP_DISABLED; options->get_popup()->connect("item_pressed", this,"_menu_option"); + HBoxContainer *hb = memnew( HBoxContainer ); + add_child(hb); + hb->set_h_size_flags(SIZE_EXPAND_FILL); edit_mode = memnew(OptionButton); edit_mode->set_area_as_parent_rect(); @@ -1247,13 +1262,27 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { edit_mode->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,14);; edit_mode->add_item("Tiles"); edit_mode->add_item("Areas"); - add_child(edit_mode); - + hb->add_child(edit_mode); + edit_mode->set_h_size_flags(SIZE_EXPAND_FILL); + + mode_thumbnail = memnew( ToolButton ); + mode_thumbnail->set_toggle_mode(true); + mode_thumbnail->set_pressed(true); + mode_thumbnail->set_icon(p_editor->get_gui_base()->get_icon("FileThumbnail","EditorIcons")); + hb->add_child(mode_thumbnail); + mode_thumbnail->connect("pressed", this, "_set_display_mode", varray(DISPLAY_THUMBNAIL)); + + mode_list = memnew( ToolButton ); + mode_list->set_toggle_mode(true); + mode_list->set_pressed(false); + mode_list->set_icon(p_editor->get_gui_base()->get_icon("FileList", "EditorIcons")); + hb->add_child(mode_list); + mode_list->connect("pressed", this, "_set_display_mode", varray(DISPLAY_LIST)); + + display_mode = DISPLAY_THUMBNAIL; selected_area=-1; - - theme_pallete = memnew( Tree ); - theme_pallete->set_columns(3); + theme_pallete = memnew( ItemList ); add_child(theme_pallete); theme_pallete->set_v_size_flags(SIZE_EXPAND_FILL); @@ -1340,7 +1369,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { Array d; d.resize(VS::ARRAY_MAX); - RID inner_mat = VisualServer::get_singleton()->fixed_material_create(); + inner_mat = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->fixed_material_set_param(inner_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.3)); VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_ONTOP,true); VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_UNSHADED,true); @@ -1349,9 +1378,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { d[VS::ARRAY_VERTEX]=triangles; VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_TRIANGLES,d); - VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat,true); + VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat); - RID outer_mat = VisualServer::get_singleton()->fixed_material_create(); + outer_mat = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->fixed_material_set_param(outer_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.8)); VisualServer::get_singleton()->material_set_line_width(outer_mat,3.0); VisualServer::get_singleton()->material_set_flag(outer_mat,VS::MATERIAL_FLAG_ONTOP,true); @@ -1361,10 +1390,10 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { d[VS::ARRAY_VERTEX]=lines; VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat,true); + VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat); - RID inner_mat_dup = VisualServer::get_singleton()->fixed_material_create(); + inner_mat_dup = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->fixed_material_set_param(inner_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.3)); VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_ONTOP,true); VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_UNSHADED,true); @@ -1373,9 +1402,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { d[VS::ARRAY_VERTEX]=triangles; VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_TRIANGLES,d); - VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat_dup,true); + VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat_dup); - RID outer_mat_dup = VisualServer::get_singleton()->fixed_material_create(); + outer_mat_dup = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->fixed_material_set_param(outer_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.8)); VisualServer::get_singleton()->material_set_line_width(outer_mat_dup,3.0); VisualServer::get_singleton()->material_set_flag(outer_mat_dup,VS::MATERIAL_FLAG_ONTOP,true); @@ -1385,7 +1414,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { d[VS::ARRAY_VERTEX]=lines; VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat_dup,true); + VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat_dup); } @@ -1409,6 +1438,11 @@ GridMapEditor::~GridMapEditor() { VisualServer::get_singleton()->free(cursor_instance); } + VisualServer::get_singleton()->free(inner_mat); + VisualServer::get_singleton()->free(outer_mat); + VisualServer::get_singleton()->free(inner_mat_dup); + VisualServer::get_singleton()->free(outer_mat_dup); + VisualServer::get_singleton()->free(selection_mesh); if (selection_instance.is_valid()) VisualServer::get_singleton()->free(selection_instance); diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 1240d78426..26fe8f20dc 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ @@ -40,10 +40,8 @@ class SpatialEditorPlugin; class GridMapEditor : public VBoxContainer { - OBJ_TYPE(GridMapEditor, VBoxContainer ); - enum { GRID_CURSOR_SIZE=50 @@ -66,6 +64,10 @@ class GridMapEditor : public VBoxContainer { CLIP_BELOW }; + enum DisplayMode { + DISPLAY_THUMBNAIL, + DISPLAY_LIST + }; UndoRedo *undo_redo; InputAction input_action; @@ -73,6 +75,8 @@ class GridMapEditor : public VBoxContainer { MenuButton * options; SpinBox *floor; OptionButton *edit_mode; + ToolButton *mode_thumbnail; + ToolButton *mode_list; HBoxContainer *spatial_editor_hb; struct SetItem { @@ -105,6 +109,13 @@ class GridMapEditor : public VBoxContainer { RID duplicate_mesh; RID duplicate_instance; + RID indicator_mat; + + RID inner_mat; + RID outer_mat; + RID inner_mat_dup; + RID outer_mat_dup; + bool updating; @@ -125,6 +136,7 @@ class GridMapEditor : public VBoxContainer { Vector3 cursor_origin; Vector3 last_mouseover; + int display_mode; int selected_pallete; int selected_area; int cursor_rot; @@ -176,9 +188,10 @@ class GridMapEditor : public VBoxContainer { void _configure(); void _menu_option(int); void update_pallete(); - Tree *theme_pallete; + void _set_display_mode(int p_mode); + ItemList *theme_pallete; Tree *area_list; - void _item_selected_cbk(); + void _item_selected_cbk(int idx); void _update_cursor_transform(); void _update_cursor_instance(); void _update_clip(); diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp index 887687a37b..2bc440759d 100644 --- a/modules/gridmap/register_types.cpp +++ b/modules/gridmap/register_types.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h index 5cddb96b70..326d7acf24 100644 --- a/modules/gridmap/register_types.h +++ b/modules/gridmap/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 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 */ |