Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount) { if (_block_signals) return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked Signal *s = signal_map.getptr(p_name); if (!s) { #ifdef DEBUG_ENABLED bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_name); //check in script if (!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name)) { ERR_EXPLAIN("Can't emit non-existing signal " + String("\"") + p_name + "\"."); ERR_FAIL_V(ERR_UNAVAILABLE); } #endif //not connected? just return return ERR_UNAVAILABLE; } List<_ObjectSignalDisconnectData> disconnect_data; //copy on write will ensure that disconnecting the signal or even deleting the object will not affect the signal calling. //this happens automatically and will not change the performance of calling. //awesome, isn't it? VMap<Signal::Target, Signal::Slot> slot_map = s->slot_map; int ssize = slot_map.size(); OBJ_DEBUG_LOCK Vector<const Variant *> bind_mem; Error err = OK; for (int i = 0; i < ssize; i++) { const Connection &c = slot_map.getv(i).conn; Object *target; #ifdef DEBUG_ENABLED target = ObjectDB::get_instance(slot_map.getk(i)._id); ERR_CONTINUE(!target); #else target = c.target; #endif const Variant **args = p_args; int argc = p_argcount; if (c.binds.size()) { //handle binds bind_mem.resize(p_argcount + c.binds.size()); for (int j = 0; j < p_argcount; j++) { bind_mem[j] = p_args[j]; } for (int j = 0; j < c.binds.size(); j++) { bind_mem[p_argcount + j] = &c.binds[j]; } args = bind_mem.ptr(); argc = bind_mem.size(); } if (c.flags & CONNECT_DEFERRED) { MessageQueue::get_singleton()->push_call(target->get_instance_id(), c.method, args, argc, true); } else { Variant::CallError ce; target->call(c.method, args, argc, ce); if (ce.error != Variant::CallError::CALL_OK) { if (ce.error == Variant::CallError::CALL_ERROR_INVALID_METHOD && !ClassDB::class_exists(target->get_class_name())) { //most likely object is not initialized yet, do not throw error. } else { ERR_PRINTS("Error calling method from signal '" + String(p_name) + "': " + Variant::get_call_error_text(target, c.method, args, argc, ce)); err = ERR_METHOD_NOT_FOUND; } } } if (c.flags & CONNECT_ONESHOT) { _ObjectSignalDisconnectData dd; dd.signal = p_name; dd.target = target; dd.method = c.method; disconnect_data.push_back(dd); } } while (!disconnect_data.empty()) { const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get(); disconnect(dd.signal, dd.target, dd.method); disconnect_data.pop_front(); } return err; }
RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_original_path) { Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); ERR_EXPLAIN("Unable to open theme file: "+p_path); ERR_FAIL_COND_V(err,RES()); String base_path = p_path.get_base_dir(); Ref<Theme> theme( memnew( Theme ) ); Map<StringName,Variant> library; bool reading_library=false; int line=0; while(!f->eof_reached()) { String l = f->get_line().strip_edges(); line++; int comment = l.find(";"); if (comment!=-1) l=l.substr(0,comment); if (l=="") continue; if (l.begins_with("[")) { if (l=="[library]") { reading_library=true; } else if (l=="[theme]") { reading_library=false; } else { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Unknown section type: '"+l+"'."); ERR_FAIL_V(RES()); } continue; } int eqpos = l.find("="); if (eqpos==-1) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Expected '='."); ERR_FAIL_V(RES()); } String right=l.substr(eqpos+1,l.length()).strip_edges(); if (right=="") { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Expected value after '='."); ERR_FAIL_V(RES()); } Variant value; if (right.is_valid_integer()) { //is number value = right.to_int(); } else if (right.is_valid_html_color()) { //is html color value = Color::html(right); } else if (right.begins_with("@")) { //reference String reference = right.substr(1,right.length()); if (!library.has(reference)) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid reference to '"+reference+"'."); ERR_FAIL_V(RES()); } value=library[reference]; } else if (right.begins_with("default")) { //use default //do none } else { //attempt to parse a constructor int popenpos = right.find("("); if (popenpos==-1) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid constructor syntax: "+right); ERR_FAIL_V(RES()); } int pclosepos = right.find_last(")"); if (pclosepos==-1) { ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid constructor parameter syntax: "+right); ERR_FAIL_V(RES()); } String type = right.substr(0,popenpos); String param = right.substr(popenpos+1,pclosepos-popenpos-1); if (type=="icon") { String path; if (param.is_abs_path()) path=param; else path=base_path+"/"+param; Ref<Texture> texture = ResourceLoader::load(path); if (!texture.is_valid()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Couldn't find icon at path: "+path); ERR_FAIL_V(RES()); } value=texture; } else if (type=="sbox") { String path; if (param.is_abs_path()) path=param; else path=base_path+"/"+param; Ref<StyleBox> stylebox = ResourceLoader::load(path); if (!stylebox.is_valid()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Couldn't find stylebox at path: "+path); ERR_FAIL_V(RES()); } value=stylebox; } else if (type=="sboxt") { Vector<String> params = param.split(","); if (params.size()!=5 && params.size()!=9) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid param count for sboxt(): '"+right+"'."); ERR_FAIL_V(RES()); } String path=params[0]; if (!param.is_abs_path()) path=base_path+"/"+path; Ref<Texture> tex = ResourceLoader::load(path); if (tex.is_null()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Could not open texture for sboxt at path: '"+params[0]+"'."); ERR_FAIL_V(RES()); } Ref<StyleBoxTexture> sbtex( memnew(StyleBoxTexture) ); sbtex->set_texture(tex); for(int i=0;i<4;i++) { if (!params[i+1].is_valid_integer()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid expand margin parameter for sboxt #"+itos(i+1) +", expected integer constant, got: '"+params[i+1]+"'."); ERR_FAIL_V(RES()); } int margin = params[i+1].to_int(); sbtex->set_expand_margin_size(Margin(i),margin); } if (params.size()==9) { for(int i=0;i<4;i++) { if (!params[i+5].is_valid_integer()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid expand margin parameter for sboxt #"+itos(i+5) +", expected integer constant, got: '"+params[i+5]+"'."); ERR_FAIL_V(RES()); } int margin = params[i+5].to_int(); sbtex->set_margin_size(Margin(i),margin); } } value = sbtex; } else if (type=="sboxf") { Vector<String> params = param.split(","); if (params.size()<2) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid param count for sboxf(): '"+right+"'."); ERR_FAIL_V(RES()); } Ref<StyleBoxFlat> sbflat( memnew(StyleBoxFlat) ); if (!params[0].is_valid_integer()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Expected integer numeric constant for parameter 0 (border size)."); ERR_FAIL_V(RES()); } sbflat->set_border_size(params[0].to_int()); if (!params[0].is_valid_integer()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Expected integer numeric constant for parameter 0 (border size)."); ERR_FAIL_V(RES()); } int left = MIN( params.size()-1, 3 ); int ccodes=0; for(int i=0;i<left;i++) { if (params[i+1].is_valid_html_color()) ccodes++; else break; } Color normal; Color bright; Color dark; if (ccodes<1) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Expected at least 1, 2 or 3 html color codes."); ERR_FAIL_V(RES()); } else if (ccodes==1) { normal=Color::html(params[1]); bright=Color::html(params[1]); dark=Color::html(params[1]); } else if (ccodes==2) { normal=Color::html(params[1]); bright=Color::html(params[2]); dark=Color::html(params[2]); } else { normal=Color::html(params[1]); bright=Color::html(params[2]); dark=Color::html(params[3]); } sbflat->set_dark_color(dark); sbflat->set_light_color(bright); sbflat->set_bg_color(normal); if (params.size()==ccodes+5) { //margins for(int i=0;i<4;i++) { if (!params[i+ccodes+1].is_valid_integer()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid expand margin parameter for sboxf #"+itos(i+ccodes+1) +", expected integer constant, got: '"+params[i+ccodes+1]+"'."); ERR_FAIL_V(RES()); } // int margin = params[i+ccodes+1].to_int(); //sbflat->set_margin_size(Margin(i),margin); } } else if (params.size()!=ccodes+1) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid amount of margin parameters for sboxt."); ERR_FAIL_V(RES()); } value=sbflat; } else { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid constructor type: '"+type+"'."); ERR_FAIL_V(RES()); } } //parse left and do something with it String left= l.substr(0,eqpos); if (reading_library) { left=left.strip_edges(); if (!left.is_valid_identifier()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": <LibraryItem> is not a valid identifier."); ERR_FAIL_V(RES()); } if (library.has(left)) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Already in library: '"+left+"'."); ERR_FAIL_V(RES()); } library[left]=value; } else { int pointpos = left.find("."); if (pointpos==-1) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Expected 'control.item=..' assign syntax."); ERR_FAIL_V(RES()); } String control=left.substr(0,pointpos).strip_edges(); if (!control.is_valid_identifier()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": <Control> is not a valid identifier."); ERR_FAIL_V(RES()); } String item=left.substr(pointpos+1,left.size()).strip_edges(); if (!item.is_valid_identifier()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": <Item> is not a valid identifier."); ERR_FAIL_V(RES()); } if (value.get_type()==Variant::NIL) { //try to use exiting if (Theme::get_default()->has_stylebox(item,control)) value=Theme::get_default()->get_stylebox(item,control); else if (Theme::get_default()->has_font(item,control)) value=Theme::get_default()->get_font(item,control); else if (Theme::get_default()->has_icon(item,control)) value=Theme::get_default()->get_icon(item,control); else if (Theme::get_default()->has_color(item,control)) value=Theme::get_default()->get_color(item,control); else if (Theme::get_default()->has_constant(item,control)) value=Theme::get_default()->get_constant(item,control); else { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Default not present for: '"+control+"."+item+"'."); ERR_FAIL_V(RES()); } } if (value.get_type()==Variant::OBJECT) { Ref<Resource> res = value; if (!res.is_valid()) { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid resource (NULL)."); ERR_FAIL_V(RES()); } if (res->cast_to<StyleBox>()) { theme->set_stylebox(item,control,res); } else if (res->cast_to<Font>()) { theme->set_font(item,control,res); } else if (res->cast_to<Font>()) { theme->set_font(item,control,res); } else if (res->cast_to<Texture>()) { theme->set_icon(item,control,res); } else { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Invalid resource type."); ERR_FAIL_V(RES()); } } else if (value.get_type()==Variant::COLOR) { theme->set_color(item,control,value); } else if (value.get_type()==Variant::INT) { theme->set_constant(item,control,value); } else { memdelete(f); ERR_EXPLAIN(p_path+":"+itos(line)+": Couldn't even determine what this setting is! what did you do!?"); ERR_FAIL_V(RES()); } } } f->close(); memdelete(f); return theme; }
void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) { lock->read_lock(); ClassInfo *type = classes.getptr(p_class); lock->read_unlock(); ERR_FAIL_COND(!type); MethodBind *mb_set = NULL; if (p_setter) { mb_set = get_method(p_class, p_setter); #ifdef DEBUG_METHODS_ENABLED if (!mb_set) { ERR_EXPLAIN("Invalid Setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name); ERR_FAIL_COND(!mb_set); } else { int exp_args = 1 + (p_index >= 0 ? 1 : 0); if (mb_set->get_argument_count() != exp_args) { ERR_EXPLAIN("Invalid Function for Setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name); ERR_FAIL(); } } #endif } MethodBind *mb_get = NULL; if (p_getter) { mb_get = get_method(p_class, p_getter); #ifdef DEBUG_METHODS_ENABLED if (!mb_get) { ERR_EXPLAIN("Invalid Getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name); ERR_FAIL_COND(!mb_get); } else { int exp_args = 0 + (p_index >= 0 ? 1 : 0); if (mb_get->get_argument_count() != exp_args) { ERR_EXPLAIN("Invalid Function for Getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name); ERR_FAIL(); } } #endif } #ifdef DEBUG_METHODS_ENABLED if (type->property_setget.has(p_pinfo.name)) { ERR_EXPLAIN("Object already has property: " + p_class); ERR_FAIL(); } #endif OBJTYPE_WLOCK type->property_list.push_back(p_pinfo); #ifdef DEBUG_METHODS_ENABLED if (mb_get) { type->methods_in_properties.insert(p_getter); } if (mb_set) { type->methods_in_properties.insert(p_setter); } #endif PropertySetGet psg; psg.setter = p_setter; psg.getter = p_getter; psg._setptr = mb_set; psg._getptr = mb_get; psg.index = p_index; psg.type = p_pinfo.type; type->property_setget[p_pinfo.name] = psg; }
Error DynamicFontAtSize::_load() { int error = FT_Init_FreeType(&library); ERR_EXPLAIN(TTR("Error initializing FreeType.")); ERR_FAIL_COND_V(error != 0, ERR_CANT_CREATE); // FT_OPEN_STREAM is extremely slow only on Android. if (OS::get_singleton()->get_name() == "Android" && font->font_mem == NULL && font->font_path != String()) { // cache font only once for each font->font_path if (_fontdata.has(font->font_path)) { font->set_font_ptr(_fontdata[font->font_path].ptr(), _fontdata[font->font_path].size()); } else { FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ); ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); size_t len = f->get_len(); _fontdata[font->font_path] = Vector<uint8_t>(); Vector<uint8_t> &fontdata = _fontdata[font->font_path]; fontdata.resize(len); f->get_buffer(fontdata.ptr(), len); font->set_font_ptr(fontdata.ptr(), len); f->close(); } } if (font->font_mem == NULL && font->font_path != String()) { FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ); ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); memset(&stream, 0, sizeof(FT_StreamRec)); stream.base = NULL; stream.size = f->get_len(); stream.pos = 0; stream.descriptor.pointer = f; stream.read = _ft_stream_io; stream.close = _ft_stream_close; FT_Open_Args fargs; memset(&fargs, 0, sizeof(FT_Open_Args)); fargs.flags = FT_OPEN_STREAM; fargs.stream = &stream; error = FT_Open_Face(library, &fargs, 0, &face); } else if (font->font_mem) { memset(&stream, 0, sizeof(FT_StreamRec)); stream.base = (unsigned char *)font->font_mem; stream.size = font->font_mem_size; stream.pos = 0; FT_Open_Args fargs; memset(&fargs, 0, sizeof(FT_Open_Args)); fargs.memory_base = (unsigned char *)font->font_mem; fargs.memory_size = font->font_mem_size; fargs.flags = FT_OPEN_MEMORY; fargs.stream = &stream; error = FT_Open_Face(library, &fargs, 0, &face); } else { ERR_EXPLAIN("DynamicFont uninitialized"); ERR_FAIL_V(ERR_UNCONFIGURED); } //error = FT_New_Face( library, src_path.utf8().get_data(),0,&face ); if (error == FT_Err_Unknown_File_Format) { ERR_EXPLAIN(TTR("Unknown font format.")); FT_Done_FreeType(library); } else if (error) { ERR_EXPLAIN(TTR("Error loading font.")); FT_Done_FreeType(library); } ERR_FAIL_COND_V(error, ERR_FILE_CANT_OPEN); /*error = FT_Set_Char_Size(face,0,64*size,512,512); if ( error ) { FT_Done_FreeType( library ); ERR_EXPLAIN(TTR("Invalid font size.")); ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER ); }*/ error = FT_Set_Pixel_Sizes(face, 0, id.size); ascent = face->size->metrics.ascender >> 6; descent = -face->size->metrics.descender >> 6; linegap = 0; texture_flags = 0; if (id.mipmaps) texture_flags |= Texture::FLAG_MIPMAPS; if (id.filter) texture_flags |= Texture::FLAG_FILTER; //print_line("ASCENT: "+itos(ascent)+" descent "+itos(descent)+" hinted: "+itos(face->face_flags&FT_FACE_FLAG_HINTER)); valid = true; return OK; }
void ObjectTypeDB::add_property(StringName p_type,const PropertyInfo& p_pinfo, const StringName& p_setter, const StringName& p_getter, int p_index) { TypeInfo *type=types.getptr(p_type); ERR_FAIL_COND(!type); MethodBind *mb_set=NULL; if (p_setter) { mb_set = get_method(p_type,p_setter); #ifdef DEBUG_METHODS_ENABLED if (!mb_set) { ERR_EXPLAIN("Invalid Setter: "+p_type+"::"+p_setter+" for property: "+p_pinfo.name); ERR_FAIL_COND(!mb_set); } else { int exp_args=1+(p_index>=0?1:0); if (mb_set->get_argument_count()!=exp_args) { ERR_EXPLAIN("Invalid Function for Setter: "+p_type+"::"+p_setter+" for property: "+p_pinfo.name); ERR_FAIL(); } } #endif } MethodBind *mb_get=NULL; if (p_getter) { MethodBind *mb_get = get_method(p_type,p_getter); #ifdef DEBUG_METHODS_ENABLED if (!mb_get) { ERR_EXPLAIN("Invalid Getter: "+p_type+"::"+p_getter+" for property: "+p_pinfo.name); ERR_FAIL_COND(!mb_get); } else { int exp_args=0+(p_index>=0?1:0); if (mb_get->get_argument_count()!=exp_args) { ERR_EXPLAIN("Invalid Function for Getter: "+p_type+"::"+p_getter+" for property: "+p_pinfo.name); ERR_FAIL(); } } #endif } #ifdef DEBUG_METHODS_ENABLED if (type->property_setget.has(p_pinfo.name)) { ERR_EXPLAIN("Object already has property: "+p_type); ERR_FAIL(); } #endif type->property_list.push_back(p_pinfo); PropertySetGet psg; psg.setter=p_setter; psg.getter=p_getter; psg._setptr=mb_set; psg._getptr=mb_get; psg.index=p_index; type->property_setget[p_pinfo.name]=psg; }
void Timer::set_wait_time(float p_time) { ERR_EXPLAIN("time should be greater than zero."); ERR_FAIL_COND(p_time<=0); wait_time=p_time; }
Error BitmapFont::create_from_fnt(const String &p_file) { //fnt format used by angelcode bmfont //http://www.angelcode.com/products/bmfont/ FileAccess *f = FileAccess::open(p_file, FileAccess::READ); if (!f) { ERR_EXPLAIN("Can't open font: " + p_file); ERR_FAIL_V(ERR_FILE_NOT_FOUND); } clear(); while (true) { String line = f->get_line(); int delimiter = line.find(" "); String type = line.substr(0, delimiter); int pos = delimiter + 1; Map<String, String> keys; while (pos < line.size() && line[pos] == ' ') pos++; while (pos < line.size()) { int eq = line.find("=", pos); if (eq == -1) break; String key = line.substr(pos, eq - pos); int end = -1; String value; if (line[eq + 1] == '"') { end = line.find("\"", eq + 2); if (end == -1) break; value = line.substr(eq + 2, end - 1 - eq - 1); pos = end + 1; } else { end = line.find(" ", eq + 1); if (end == -1) end = line.size(); value = line.substr(eq + 1, end - eq); pos = end; } while (pos < line.size() && line[pos] == ' ') pos++; keys[key] = value; } if (type == "info") { if (keys.has("face")) set_name(keys["face"]); /* if (keys.has("size")) font->set_height(keys["size"].to_int()); */ } else if (type == "common") { if (keys.has("lineHeight")) set_height(keys["lineHeight"].to_int()); if (keys.has("base")) set_ascent(keys["base"].to_int()); } else if (type == "page") { if (keys.has("file")) { String base_dir = p_file.get_base_dir(); String file = base_dir.plus_file(keys["file"]); Ref<Texture> tex = ResourceLoader::load(file); if (tex.is_null()) { ERR_PRINT("Can't load font texture!"); } else { add_texture(tex); } } } else if (type == "char") { CharType idx = 0; if (keys.has("id")) idx = keys["id"].to_int(); Rect2 rect; if (keys.has("x")) rect.position.x = keys["x"].to_int(); if (keys.has("y")) rect.position.y = keys["y"].to_int(); if (keys.has("width")) rect.size.width = keys["width"].to_int(); if (keys.has("height")) rect.size.height = keys["height"].to_int(); Point2 ofs; if (keys.has("xoffset")) ofs.x = keys["xoffset"].to_int(); if (keys.has("yoffset")) ofs.y = keys["yoffset"].to_int(); int texture = 0; if (keys.has("page")) texture = keys["page"].to_int(); int advance = -1; if (keys.has("xadvance")) advance = keys["xadvance"].to_int(); add_char(idx, texture, rect, ofs, advance); } else if (type == "kerning") { CharType first = 0, second = 0; int k = 0; if (keys.has("first")) first = keys["first"].to_int(); if (keys.has("second")) second = keys["second"].to_int(); if (keys.has("amount")) k = keys["amount"].to_int(); add_kerning_pair(first, second, -k); } if (f->eof_reached()) break; } memdelete(f); return OK; }
Error DocData::save(const String& p_path) { Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::WRITE,&err); if (err) { ERR_EXPLAIN("Can't write doc file: "+p_path); ERR_FAIL_V(err); } _write_string(f,0,"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); _write_string(f,0,"<doc version=\""+String(VERSION_MKSTRING)+"\" name=\"Engine Types\">"); for( Map<String,ClassDoc>::Element *E=class_list.front();E;E=E->next()) { ClassDoc &c=E->get(); String header="<class name=\""+c.name+"\""; if (c.inherits!="") header+=" inherits=\""+c.inherits+"\""; String category=c.category; if (c.category=="") category="Core"; header+=" category=\""+category+"\""; header+=">"; _write_string(f,0,header); _write_string(f,1,"<brief_description>"); if (c.brief_description!="") _write_string(f,1,c.brief_description.xml_escape()); _write_string(f,1,"</brief_description>"); _write_string(f,1,"<description>"); if (c.description!="") _write_string(f,1,c.description.xml_escape()); _write_string(f,1,"</description>"); _write_string(f,1,"<methods>"); for(int i=0;i<c.methods.size();i++) { MethodDoc &m=c.methods[i]; String qualifiers; if (m.qualifiers!="") qualifiers+="qualifiers=\""+m.qualifiers.xml_escape()+"\""; _write_string(f,2,"<method name=\""+m.name+"\" "+qualifiers+" >"); if (m.return_type!="") { _write_string(f,3,"<return type=\""+m.return_type+"\">"); _write_string(f,3,"</return>"); } for(int j=0;j<m.arguments.size();j++) { ArgumentDoc &a = m.arguments[j]; if (a.default_value!="") _write_string(f,3,"<argument index=\""+itos(j)+"\" name=\""+a.name.xml_escape()+"\" type=\""+a.type.xml_escape()+"\" default=\""+a.default_value.xml_escape(true)+"\">"); else _write_string(f,3,"<argument index=\""+itos(j)+"\" name=\""+a.name.xml_escape()+"\" type=\""+a.type.xml_escape()+"\">"); _write_string(f,3,"</argument>"); } _write_string(f,3,"<description>"); if (m.description!="") _write_string(f,3,m.description.xml_escape()); _write_string(f,3,"</description>"); _write_string(f,2,"</method>"); } _write_string(f,1,"</methods>"); if (c.properties.size()) { _write_string(f,1,"<members>"); for(int i=0;i<c.properties.size();i++) { PropertyDoc &p=c.properties[i]; _write_string(f,2,"<member name=\""+p.name+"\" type=\""+p.type+"\">"); _write_string(f,2,"</member>"); } _write_string(f,1,"</members>"); } if (c.signals.size()) { _write_string(f,1,"<signals>"); for(int i=0;i<c.signals.size();i++) { MethodDoc &m=c.signals[i]; _write_string(f,2,"<signal name=\""+m.name+"\">"); for(int j=0;j<m.arguments.size();j++) { ArgumentDoc &a = m.arguments[j]; _write_string(f,3,"<argument index=\""+itos(j)+"\" name=\""+a.name.xml_escape()+"\" type=\""+a.type.xml_escape()+"\">"); _write_string(f,3,"</argument>"); } _write_string(f,3,"<description>"); if (m.description!="") _write_string(f,3,m.description.xml_escape()); _write_string(f,3,"</description>"); _write_string(f,2,"</signal>"); } _write_string(f,1,"</signals>"); } _write_string(f,1,"<constants>"); for(int i=0;i<c.constants.size();i++) { ConstantDoc &k=c.constants[i]; _write_string(f,2,"<constant name=\""+k.name+"\" value=\""+k.value+"\">"); if (k.description!="") _write_string(f,3,k.description.xml_escape()); _write_string(f,2,"</constant>"); } _write_string(f,1,"</constants>"); _write_string(f,0,"</class>"); } _write_string(f,0,"</doc>"); f->close(); memdelete(f); return OK; }
void GDNative::set_library(Ref<GDNativeLibrary> p_library) { ERR_EXPLAIN("Tried to change library of GDNative when it is already set"); ERR_FAIL_COND(library.is_valid()); library = p_library; }
void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { error=OK; f=p_f; uint8_t header[4]; f->get_buffer(header,4); if (header[0]=='R' && header[1]=='S' && header[2]=='C' && header[3]=='C') { //compressed FileAccessCompressed *fac = memnew( FileAccessCompressed ); fac->open_after_magic(f); f=fac; } else if (header[0]!='R' || header[1]!='S' || header[2]!='R' || header[3]!='C') { //not normal error=ERR_FILE_UNRECOGNIZED; ERR_EXPLAIN("Unrecognized binary resource file: "+local_path); ERR_FAIL_V(); } bool big_endian = f->get_32(); #ifdef BIG_ENDIAN_ENABLED endian_swap = !big_endian; #else bool endian_swap = big_endian; #endif bool use_real64 = f->get_32(); f->set_endian_swap(big_endian!=0); //read big endian if saved as big endian uint32_t ver_major=f->get_32(); uint32_t ver_minor=f->get_32(); uint32_t ver_format=f->get_32(); print_bl("big endian: "+itos(big_endian)); print_bl("endian swap: "+itos(endian_swap)); print_bl("real64: "+itos(use_real64)); print_bl("major: "+itos(ver_major)); print_bl("minor: "+itos(ver_minor)); print_bl("format: "+itos(ver_format)); if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) { f->close(); ERR_EXPLAIN("File Format '"+itos(FORMAT_VERSION)+"."+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+local_path); ERR_FAIL(); } type=get_unicode_string(); print_bl("type: "+type); importmd_ofs = f->get_64(); for(int i=0;i<14;i++) f->get_32(); //skip a few reserved fields uint32_t string_table_size=f->get_32(); string_map.resize(string_table_size); for(uint32_t i=0;i<string_table_size;i++) { StringName s = get_unicode_string(); string_map[i]=s; } print_bl("strings: "+itos(string_table_size)); uint32_t ext_resources_size=f->get_32(); for(uint32_t i=0;i<ext_resources_size;i++) { ExtResoucre er; er.type=get_unicode_string(); er.path=get_unicode_string(); external_resources.push_back(er); } //see if the exporter has different set of external resources for more efficient loading String preload_depts = "deps/"+res_path.md5_text(); if (Globals::get_singleton()->has(preload_depts)) { external_resources.clear(); //ignore external resources and use these NodePath depts=Globals::get_singleton()->get(preload_depts); external_resources.resize(depts.get_name_count()); for(int i=0;i<depts.get_name_count();i++) { external_resources[i].path=depts.get_name(i); } print_line(res_path+" - EXTERNAL RESOURCES: "+itos(external_resources.size())); } print_bl("ext resources: "+itos(ext_resources_size)); uint32_t int_resources_size=f->get_32(); for(uint32_t i=0;i<int_resources_size;i++) { IntResoucre ir; ir.path=get_unicode_string(); ir.offset=f->get_64(); internal_resources.push_back(ir); } print_bl("int resources: "+itos(int_resources_size)); if (f->eof_reached()) { error=ERR_FILE_CORRUPT; ERR_EXPLAIN("Premature End Of File: "+local_path); ERR_FAIL(); } }
Error DocData::_load(Ref<XMLParser> parser) { Error err=OK; while((err=parser->read())==OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { if (parser->get_node_name() == "doc") { break; } else if (!parser->is_empty()) parser->skip_section();// unknown section, likely headers } } if (parser->has_attribute("version")) version=parser->get_attribute_value("version"); while((err=parser->read())==OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="doc") break; //end of <doc> if (parser->get_node_type() != XMLParser::NODE_ELEMENT) continue; //no idea what this may be, but skipping anyway ERR_FAIL_COND_V( parser->get_node_name()!="class", ERR_FILE_CORRUPT ); ERR_FAIL_COND_V( !parser->has_attribute("name"), ERR_FILE_CORRUPT); String name = parser->get_attribute_value("name"); class_list[name]=ClassDoc(); ClassDoc& c = class_list[name]; c.name=name; if (parser->has_attribute("inherits")) c.inherits = parser->get_attribute_value("inherits"); if (parser->has_attribute("category")) c.category = parser->get_attribute_value("category"); while(parser->read()==OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { String name = parser->get_node_name(); if (name=="brief_description") { parser->read(); if (parser->get_node_type()==XMLParser::NODE_TEXT) c.brief_description=parser->get_node_data().strip_edges(); } else if (name=="description") { parser->read(); if (parser->get_node_type()==XMLParser::NODE_TEXT) c.description=parser->get_node_data().strip_edges(); } else if (name=="methods") { Error err = _parse_methods(parser,c.methods); ERR_FAIL_COND_V(err,err); } else if (name=="signals") { Error err = _parse_methods(parser,c.signals); ERR_FAIL_COND_V(err,err); } else if (name=="members") { while(parser->read()==OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { String name = parser->get_node_name(); if (name=="member") { PropertyDoc prop; ERR_FAIL_COND_V(!parser->has_attribute("name"),ERR_FILE_CORRUPT); prop.name=parser->get_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("type"),ERR_FILE_CORRUPT); prop.type=parser->get_attribute_value("type"); parser->read(); if (parser->get_node_type()==XMLParser::NODE_TEXT) prop.description=parser->get_node_data().strip_edges(); c.properties.push_back(prop); } else { ERR_EXPLAIN("Invalid tag in doc file: "+name); ERR_FAIL_V(ERR_FILE_CORRUPT); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="members") break; //end of <constants> } } else if (name=="constants") { while(parser->read()==OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { String name=parser->get_node_name(); if (name=="constant") { ConstantDoc constant; ERR_FAIL_COND_V(!parser->has_attribute("name"),ERR_FILE_CORRUPT); constant.name=parser->get_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("value"),ERR_FILE_CORRUPT); constant.value=parser->get_attribute_value("value"); parser->read(); if (parser->get_node_type()==XMLParser::NODE_TEXT) constant.description=parser->get_node_data().strip_edges(); c.constants.push_back(constant); } else { ERR_EXPLAIN("Invalid tag in doc file: "+name); ERR_FAIL_V(ERR_FILE_CORRUPT); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="constants") break; //end of <constants> } } else { ERR_EXPLAIN("Invalid tag in doc file: "+name); ERR_FAIL_V(ERR_FILE_CORRUPT); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="class") break; //end of <asset> } } return OK; }
Error ResourceInteractiveLoaderBinary::poll(){ if (error!=OK) return error; int s = stage; if (s<external_resources.size()) { RES res = ResourceLoader::load(external_resources[s].path,external_resources[s].type); if (res.is_null()) { if (!ResourceLoader::get_abort_on_missing_resources()) { ResourceLoader::notify_load_error("Resource Not Found: "+external_resources[s].path); } else { error=ERR_FILE_CORRUPT; ERR_EXPLAIN("Can't load dependency: "+external_resources[s].path); ERR_FAIL_V(error); } } else { resource_cache.push_back(res); } stage++; return error; } s-=external_resources.size(); if (s>=internal_resources.size()) { error=ERR_BUG; ERR_FAIL_COND_V(s>=internal_resources.size(),error); } bool main = s==(internal_resources.size()-1); //maybe it is loaded already String path; if (!main) { path=internal_resources[s].path; if (path.begins_with("local://")) path=path.replace("local://",res_path+"::"); if (ResourceCache::has(path)) { //already loaded, don't do anything stage++; error=OK; return error; } } else { path=res_path; } uint64_t offset = internal_resources[s].offset; f->seek(offset); String t = get_unicode_string(); Object *obj = ObjectTypeDB::instance(t); if (!obj) { error=ERR_FILE_CORRUPT; ERR_EXPLAIN(local_path+":Resource of unrecognized type in file: "+t); } ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT); Resource *r = obj->cast_to<Resource>(); if (!r) { error=ERR_FILE_CORRUPT; memdelete(obj); //bye ERR_EXPLAIN(local_path+":Resoucre type in resource field not a resource, type is: "+obj->get_type()); ERR_FAIL_COND_V(!r,ERR_FILE_CORRUPT); } RES res = RES( r ); r->set_path(path); int pc = f->get_32(); //set properties for(int i=0;i<pc;i++) { uint32_t name_idx = f->get_32(); if (name_idx>=(uint32_t)string_map.size()) { error=ERR_FILE_CORRUPT; ERR_FAIL_V(ERR_FILE_CORRUPT); } Variant value; error = parse_variant(value); if (error) return error; res->set(string_map[name_idx],value); } #ifdef TOOLS_ENABLED res->set_edited(false); #endif stage++; resource_cache.push_back(res); if (main) { if (importmd_ofs) { f->seek(importmd_ofs); Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata ); imd->set_editor(get_unicode_string()); int sc = f->get_32(); for(int i=0;i<sc;i++) { String src = get_unicode_string(); String md5 = get_unicode_string(); imd->add_source(src,md5); } int pc = f->get_32(); for(int i=0;i<pc;i++) { String name = get_unicode_string(); Variant val; parse_variant(val); imd->set_option(name,val); } res->set_import_metadata(imd); } f->close(); resource=res; error=ERR_FILE_EOF; } else { error=OK; } return OK; }
Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { uint32_t type = f->get_32(); print_bl("find property of type: "+itos(type)); switch(type) { case VARIANT_NIL: { r_v=Variant(); } break; case VARIANT_BOOL: { r_v=bool(f->get_32()); } break; case VARIANT_INT: { r_v=int(f->get_32()); } break; case VARIANT_REAL: { r_v=f->get_real(); } break; case VARIANT_STRING: { r_v=get_unicode_string(); } break; case VARIANT_VECTOR2: { Vector2 v; v.x=f->get_real(); v.y=f->get_real(); r_v=v; } break; case VARIANT_RECT2: { Rect2 v; v.pos.x=f->get_real(); v.pos.y=f->get_real(); v.size.x=f->get_real(); v.size.y=f->get_real(); r_v=v; } break; case VARIANT_VECTOR3: { Vector3 v; v.x=f->get_real(); v.y=f->get_real(); v.z=f->get_real(); r_v=v; } break; case VARIANT_PLANE: { Plane v; v.normal.x=f->get_real(); v.normal.y=f->get_real(); v.normal.z=f->get_real(); v.d=f->get_real(); r_v=v; } break; case VARIANT_QUAT: { Quat v; v.x=f->get_real(); v.y=f->get_real(); v.z=f->get_real(); v.w=f->get_real(); r_v=v; } break; case VARIANT_AABB: { AABB v; v.pos.x=f->get_real(); v.pos.y=f->get_real(); v.pos.z=f->get_real(); v.size.x=f->get_real(); v.size.y=f->get_real(); v.size.z=f->get_real(); r_v=v; } break; case VARIANT_MATRIX32: { Matrix32 v; v.elements[0].x=f->get_real(); v.elements[0].y=f->get_real(); v.elements[1].x=f->get_real(); v.elements[1].y=f->get_real(); v.elements[2].x=f->get_real(); v.elements[2].y=f->get_real(); r_v=v; } break; case VARIANT_MATRIX3: { Matrix3 v; v.elements[0].x=f->get_real(); v.elements[0].y=f->get_real(); v.elements[0].z=f->get_real(); v.elements[1].x=f->get_real(); v.elements[1].y=f->get_real(); v.elements[1].z=f->get_real(); v.elements[2].x=f->get_real(); v.elements[2].y=f->get_real(); v.elements[2].z=f->get_real(); r_v=v; } break; case VARIANT_TRANSFORM: { Transform v; v.basis.elements[0].x=f->get_real(); v.basis.elements[0].y=f->get_real(); v.basis.elements[0].z=f->get_real(); v.basis.elements[1].x=f->get_real(); v.basis.elements[1].y=f->get_real(); v.basis.elements[1].z=f->get_real(); v.basis.elements[2].x=f->get_real(); v.basis.elements[2].y=f->get_real(); v.basis.elements[2].z=f->get_real(); v.origin.x=f->get_real(); v.origin.y=f->get_real(); v.origin.z=f->get_real(); r_v=v; } break; case VARIANT_COLOR: { Color v; v.r=f->get_real(); v.g=f->get_real(); v.b=f->get_real(); v.a=f->get_real(); r_v=v; } break; case VARIANT_IMAGE: { uint32_t encoding = f->get_32(); if (encoding==IMAGE_ENCODING_EMPTY) { r_v=Variant(); break; } else if (encoding==IMAGE_ENCODING_RAW) { uint32_t width = f->get_32(); uint32_t height = f->get_32(); uint32_t mipmaps = f->get_32(); uint32_t format = f->get_32(); Image::Format fmt; switch(format) { case IMAGE_FORMAT_GRAYSCALE: { fmt=Image::FORMAT_GRAYSCALE; } break; case IMAGE_FORMAT_INTENSITY: { fmt=Image::FORMAT_INTENSITY; } break; case IMAGE_FORMAT_GRAYSCALE_ALPHA: { fmt=Image::FORMAT_GRAYSCALE_ALPHA; } break; case IMAGE_FORMAT_RGB: { fmt=Image::FORMAT_RGB; } break; case IMAGE_FORMAT_RGBA: { fmt=Image::FORMAT_RGBA; } break; case IMAGE_FORMAT_INDEXED: { fmt=Image::FORMAT_INDEXED; } break; case IMAGE_FORMAT_INDEXED_ALPHA: { fmt=Image::FORMAT_INDEXED_ALPHA; } break; case IMAGE_FORMAT_BC1: { fmt=Image::FORMAT_BC1; } break; case IMAGE_FORMAT_BC2: { fmt=Image::FORMAT_BC2; } break; case IMAGE_FORMAT_BC3: { fmt=Image::FORMAT_BC3; } break; case IMAGE_FORMAT_BC4: { fmt=Image::FORMAT_BC4; } break; case IMAGE_FORMAT_BC5: { fmt=Image::FORMAT_BC5; } break; case IMAGE_FORMAT_PVRTC2: { fmt=Image::FORMAT_PVRTC2; } break; case IMAGE_FORMAT_PVRTC2_ALPHA: { fmt=Image::FORMAT_PVRTC2_ALPHA; } break; 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: { ERR_FAIL_V(ERR_FILE_CORRUPT); } } uint32_t datalen = f->get_32(); DVector<uint8_t> imgdata; imgdata.resize(datalen); DVector<uint8_t>::Write w = imgdata.write(); f->get_buffer(w.ptr(),datalen); _advance_padding(datalen); w=DVector<uint8_t>::Write(); r_v=Image(width,height,mipmaps,fmt,imgdata); } else { //compressed DVector<uint8_t> data; data.resize(f->get_32()); DVector<uint8_t>::Write w = data.write(); f->get_buffer(w.ptr(),data.size()); w = DVector<uint8_t>::Write(); Image img; if (encoding==IMAGE_ENCODING_LOSSY && Image::lossy_unpacker) { img = Image::lossy_unpacker(data); } else if (encoding==IMAGE_ENCODING_LOSSLESS && Image::lossless_unpacker) { img = Image::lossless_unpacker(data); } _advance_padding(data.size()); r_v=img; } } break; case VARIANT_NODE_PATH: { Vector<StringName> names; Vector<StringName> subnames; StringName property; bool absolute; int name_count = f->get_16(); uint32_t subname_count = f->get_16(); absolute=subname_count&0x8000; subname_count&=0x7FFF; for(int i=0;i<name_count;i++) names.push_back(string_map[f->get_32()]); for(uint32_t i=0;i<subname_count;i++) subnames.push_back(string_map[f->get_32()]); property=string_map[f->get_32()]; NodePath np = NodePath(names,subnames,absolute,property); //print_line("got path: "+String(np)); r_v=np; } break; case VARIANT_RID: { r_v=f->get_32(); } break; case VARIANT_OBJECT: { uint32_t type=f->get_32(); switch(type) { case OBJECT_EMPTY: { //do none } break; case OBJECT_INTERNAL_RESOURCE: { uint32_t index=f->get_32(); String path = res_path+"::"+itos(index); RES res = ResourceLoader::load(path); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); } r_v=res; } break; case OBJECT_EXTERNAL_RESOURCE: { String type = get_unicode_string(); String path = get_unicode_string(); if (path.find("://")==-1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path path=Globals::get_singleton()->localize_path(res_path.get_base_dir()+"/"+path); } RES res=ResourceLoader::load(path,type); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); } r_v=res; } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); } break; } } break; case VARIANT_INPUT_EVENT: { } break; case VARIANT_DICTIONARY: { uint32_t len=f->get_32(); Dictionary d(len&0x80000000); //last bit means shared len&=0x7FFFFFFF; for(uint32_t i=0;i<len;i++) { Variant key; Error err = parse_variant(key); ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); Variant value; err = parse_variant(value); ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); d[key]=value; } r_v=d; } break; case VARIANT_ARRAY: { uint32_t len=f->get_32(); Array a(len&0x80000000); //last bit means shared len&=0x7FFFFFFF; a.resize(len); for(uint32_t i=0;i<len;i++) { Variant val; Error err = parse_variant(val); ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); a[i]=val; } r_v=a; } break; case VARIANT_RAW_ARRAY: { uint32_t len = f->get_32(); DVector<uint8_t> array; array.resize(len); DVector<uint8_t>::Write w = array.write(); f->get_buffer(w.ptr(),len); _advance_padding(len); w=DVector<uint8_t>::Write(); r_v=array; } break; case VARIANT_INT_ARRAY: { uint32_t len = f->get_32(); DVector<int> array; array.resize(len); DVector<int>::Write w = array.write(); f->get_buffer((uint8_t*)w.ptr(),len*4); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif w=DVector<int>::Write(); r_v=array; } break; case VARIANT_REAL_ARRAY: { uint32_t len = f->get_32(); DVector<real_t> array; array.resize(len); DVector<real_t>::Write w = array.write(); f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif w=DVector<real_t>::Write(); r_v=array; } break; case VARIANT_STRING_ARRAY: { uint32_t len = f->get_32(); DVector<String> array; array.resize(len); DVector<String>::Write w = array.write(); for(uint32_t i=0;i<len;i++) w[i]=get_unicode_string(); w=DVector<String>::Write(); r_v=array; } break; case VARIANT_VECTOR2_ARRAY: { uint32_t len = f->get_32(); DVector<Vector2> array; array.resize(len); DVector<Vector2>::Write w = array.write(); if (sizeof(Vector2)==8) { f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*2); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len*2;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Vector2 size is NOT 8!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w=DVector<Vector2>::Write(); r_v=array; } break; case VARIANT_VECTOR3_ARRAY: { uint32_t len = f->get_32(); DVector<Vector3> array; array.resize(len); DVector<Vector3>::Write w = array.write(); if (sizeof(Vector3)==12) { f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*3); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len*3;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Vector3 size is NOT 12!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w=DVector<Vector3>::Write(); r_v=array; } break; case VARIANT_COLOR_ARRAY: { uint32_t len = f->get_32(); DVector<Color> array; array.resize(len); DVector<Color>::Write w = array.write(); if (sizeof(Color)==16) { f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*4); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len*4;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Color size is NOT 16!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w=DVector<Color>::Write(); r_v=array; } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); } break; } return OK; //never reach anyway }
Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { uint32_t type = f->get_32(); print_bl("find property of type: " + itos(type)); switch (type) { case VARIANT_NIL: { r_v = Variant(); } break; case VARIANT_BOOL: { r_v = bool(f->get_32()); } break; case VARIANT_INT: { r_v = int(f->get_32()); } break; case VARIANT_INT64: { r_v = int64_t(f->get_64()); } break; case VARIANT_REAL: { r_v = f->get_real(); } break; case VARIANT_DOUBLE: { r_v = f->get_double(); } break; case VARIANT_STRING: { r_v = get_unicode_string(); } break; case VARIANT_VECTOR2: { Vector2 v; v.x = f->get_real(); v.y = f->get_real(); r_v = v; } break; case VARIANT_RECT2: { Rect2 v; v.position.x = f->get_real(); v.position.y = f->get_real(); v.size.x = f->get_real(); v.size.y = f->get_real(); r_v = v; } break; case VARIANT_VECTOR3: { Vector3 v; v.x = f->get_real(); v.y = f->get_real(); v.z = f->get_real(); r_v = v; } break; case VARIANT_PLANE: { Plane v; v.normal.x = f->get_real(); v.normal.y = f->get_real(); v.normal.z = f->get_real(); v.d = f->get_real(); r_v = v; } break; case VARIANT_QUAT: { Quat v; v.x = f->get_real(); v.y = f->get_real(); v.z = f->get_real(); v.w = f->get_real(); r_v = v; } break; case VARIANT_AABB: { AABB v; v.position.x = f->get_real(); v.position.y = f->get_real(); v.position.z = f->get_real(); v.size.x = f->get_real(); v.size.y = f->get_real(); v.size.z = f->get_real(); r_v = v; } break; case VARIANT_MATRIX32: { Transform2D v; v.elements[0].x = f->get_real(); v.elements[0].y = f->get_real(); v.elements[1].x = f->get_real(); v.elements[1].y = f->get_real(); v.elements[2].x = f->get_real(); v.elements[2].y = f->get_real(); r_v = v; } break; case VARIANT_MATRIX3: { Basis v; v.elements[0].x = f->get_real(); v.elements[0].y = f->get_real(); v.elements[0].z = f->get_real(); v.elements[1].x = f->get_real(); v.elements[1].y = f->get_real(); v.elements[1].z = f->get_real(); v.elements[2].x = f->get_real(); v.elements[2].y = f->get_real(); v.elements[2].z = f->get_real(); r_v = v; } break; case VARIANT_TRANSFORM: { Transform v; v.basis.elements[0].x = f->get_real(); v.basis.elements[0].y = f->get_real(); v.basis.elements[0].z = f->get_real(); v.basis.elements[1].x = f->get_real(); v.basis.elements[1].y = f->get_real(); v.basis.elements[1].z = f->get_real(); v.basis.elements[2].x = f->get_real(); v.basis.elements[2].y = f->get_real(); v.basis.elements[2].z = f->get_real(); v.origin.x = f->get_real(); v.origin.y = f->get_real(); v.origin.z = f->get_real(); r_v = v; } break; case VARIANT_COLOR: { Color v; v.r = f->get_real(); v.g = f->get_real(); v.b = f->get_real(); v.a = f->get_real(); r_v = v; } break; case VARIANT_NODE_PATH: { Vector<StringName> names; Vector<StringName> subnames; bool absolute; int name_count = f->get_16(); uint32_t subname_count = f->get_16(); absolute = subname_count & 0x8000; subname_count &= 0x7FFF; if (ver_format < FORMAT_VERSION_NO_NODEPATH_PROPERTY) { subname_count += 1; // has a property field, so we should count it as well } for (int i = 0; i < name_count; i++) names.push_back(_get_string()); for (uint32_t i = 0; i < subname_count; i++) subnames.push_back(_get_string()); NodePath np = NodePath(names, subnames, absolute); r_v = np; } break; case VARIANT_RID: { r_v = f->get_32(); } break; case VARIANT_OBJECT: { uint32_t type = f->get_32(); switch (type) { case OBJECT_EMPTY: { //do none } break; case OBJECT_INTERNAL_RESOURCE: { uint32_t index = f->get_32(); String path = res_path + "::" + itos(index); RES res = ResourceLoader::load(path); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data()); } r_v = res; } break; case OBJECT_EXTERNAL_RESOURCE: { //old file format, still around for compatibility String type = get_unicode_string(); String path = get_unicode_string(); if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); } if (remaps.find(path)) { path = remaps[path]; } RES res = ResourceLoader::load(path, type); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data()); } r_v = res; } break; case OBJECT_EXTERNAL_RESOURCE_INDEX: { //new file format, just refers to an index in the external list int erindex = f->get_32(); if (erindex < 0 || erindex >= external_resources.size()) { WARN_PRINT("Broken external resource! (index out of size"); r_v = Variant(); } else { String type = external_resources[erindex].type; String path = external_resources[erindex].path; if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); } RES res = ResourceLoader::load(path, type); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data()); } r_v = res; } } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); } break; } } break; case VARIANT_DICTIONARY: { uint32_t len = f->get_32(); Dictionary d; //last bit means shared len &= 0x7FFFFFFF; for (uint32_t i = 0; i < len; i++) { Variant key; Error err = parse_variant(key); ERR_FAIL_COND_V(err, ERR_FILE_CORRUPT); Variant value; err = parse_variant(value); ERR_FAIL_COND_V(err, ERR_FILE_CORRUPT); d[key] = value; } r_v = d; } break; case VARIANT_ARRAY: { uint32_t len = f->get_32(); Array a; //last bit means shared len &= 0x7FFFFFFF; a.resize(len); for (uint32_t i = 0; i < len; i++) { Variant val; Error err = parse_variant(val); ERR_FAIL_COND_V(err, ERR_FILE_CORRUPT); a[i] = val; } r_v = a; } break; case VARIANT_RAW_ARRAY: { uint32_t len = f->get_32(); PoolVector<uint8_t> array; array.resize(len); PoolVector<uint8_t>::Write w = array.write(); f->get_buffer(w.ptr(), len); _advance_padding(len); w = PoolVector<uint8_t>::Write(); r_v = array; } break; case VARIANT_INT_ARRAY: { uint32_t len = f->get_32(); PoolVector<int> array; array.resize(len); PoolVector<int>::Write w = array.write(); f->get_buffer((uint8_t *)w.ptr(), len * 4); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif w = PoolVector<int>::Write(); r_v = array; } break; case VARIANT_REAL_ARRAY: { uint32_t len = f->get_32(); PoolVector<real_t> array; array.resize(len); PoolVector<real_t>::Write w = array.write(); f->get_buffer((uint8_t *)w.ptr(), len * sizeof(real_t)); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif w = PoolVector<real_t>::Write(); r_v = array; } break; case VARIANT_STRING_ARRAY: { uint32_t len = f->get_32(); PoolVector<String> array; array.resize(len); PoolVector<String>::Write w = array.write(); for (uint32_t i = 0; i < len; i++) w[i] = get_unicode_string(); w = PoolVector<String>::Write(); r_v = array; } break; case VARIANT_VECTOR2_ARRAY: { uint32_t len = f->get_32(); PoolVector<Vector2> array; array.resize(len); PoolVector<Vector2>::Write w = array.write(); if (sizeof(Vector2) == 8) { f->get_buffer((uint8_t *)w.ptr(), len * sizeof(real_t) * 2); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len * 2; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Vector2 size is NOT 8!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w = PoolVector<Vector2>::Write(); r_v = array; } break; case VARIANT_VECTOR3_ARRAY: { uint32_t len = f->get_32(); PoolVector<Vector3> array; array.resize(len); PoolVector<Vector3>::Write w = array.write(); if (sizeof(Vector3) == 12) { f->get_buffer((uint8_t *)w.ptr(), len * sizeof(real_t) * 3); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len * 3; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Vector3 size is NOT 12!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w = PoolVector<Vector3>::Write(); r_v = array; } break; case VARIANT_COLOR_ARRAY: { uint32_t len = f->get_32(); PoolVector<Color> array; array.resize(len); PoolVector<Color>::Write w = array.write(); if (sizeof(Color) == 16) { f->get_buffer((uint8_t *)w.ptr(), len * sizeof(real_t) * 4); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len * 4; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Color size is NOT 16!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w = PoolVector<Color>::Write(); r_v = array; } break; #ifndef DISABLE_DEPRECATED case VARIANT_IMAGE: { uint32_t encoding = f->get_32(); if (encoding == IMAGE_ENCODING_EMPTY) { r_v = Ref<Image>(); break; } else if (encoding == IMAGE_ENCODING_RAW) { uint32_t width = f->get_32(); uint32_t height = f->get_32(); uint32_t mipmaps = f->get_32(); uint32_t format = f->get_32(); const uint32_t format_version_shift = 24; const uint32_t format_version_mask = format_version_shift - 1; uint32_t format_version = format >> format_version_shift; const uint32_t current_version = 0; if (format_version > current_version) { ERR_PRINT("Format version for encoded binary image is too new"); return ERR_PARSE_ERROR; } Image::Format fmt = Image::Format(format & format_version_mask); //if format changes, we can add a compatibility bit on top uint32_t datalen = f->get_32(); PoolVector<uint8_t> imgdata; imgdata.resize(datalen); PoolVector<uint8_t>::Write w = imgdata.write(); f->get_buffer(w.ptr(), datalen); _advance_padding(datalen); w = PoolVector<uint8_t>::Write(); Ref<Image> image; image.instance(); image->create(width, height, mipmaps, fmt, imgdata); r_v = image; } else { //compressed PoolVector<uint8_t> data; data.resize(f->get_32()); PoolVector<uint8_t>::Write w = data.write(); f->get_buffer(w.ptr(), data.size()); w = PoolVector<uint8_t>::Write(); Ref<Image> image; if (encoding == IMAGE_ENCODING_LOSSY && Image::lossy_unpacker) { image = Image::lossy_unpacker(data); } else if (encoding == IMAGE_ENCODING_LOSSLESS && Image::lossless_unpacker) { image = Image::lossless_unpacker(data); } _advance_padding(data.size()); r_v = image; } } break;
Error DynamicFontAtSize::_load() { int error = FT_Init_FreeType( &library ); ERR_EXPLAIN(TTR("Error initializing FreeType.")); ERR_FAIL_COND_V( error !=0, ERR_CANT_CREATE ); if (font->font_path!=String()) { FileAccess *f=FileAccess::open(font->font_path,FileAccess::READ); ERR_FAIL_COND_V(!f,ERR_CANT_OPEN); memset(&stream,0,sizeof(FT_StreamRec)); stream.base=NULL; stream.size=f->get_len(); stream.pos=0; stream.descriptor.pointer=f; stream.read=_ft_stream_io; stream.close=_ft_stream_close; FT_Open_Args fargs; memset(&fargs,0,sizeof(FT_Open_Args)); fargs.flags=FT_OPEN_STREAM; fargs.stream=&stream; error = FT_Open_Face( library,&fargs,0,&face); } else if (font->font_mem) { memset(&stream,0,sizeof(FT_StreamRec)); stream.base=(unsigned char*)font->font_mem; stream.size=font->font_mem_size; stream.pos=0; FT_Open_Args fargs; memset(&fargs,0,sizeof(FT_Open_Args)); fargs.memory_base=(unsigned char*)font->font_mem; fargs.memory_size=font->font_mem_size; fargs.flags= FT_OPEN_MEMORY; fargs.stream=&stream; error = FT_Open_Face( library,&fargs,0,&face); } else { ERR_EXPLAIN("DynamicFont uninitialized"); ERR_FAIL_V(ERR_UNCONFIGURED); } //error = FT_New_Face( library, src_path.utf8().get_data(),0,&face ); if ( error == FT_Err_Unknown_File_Format ) { ERR_EXPLAIN(TTR("Unknown font format.")); FT_Done_FreeType( library ); } else if ( error ) { ERR_EXPLAIN(TTR("Error loading font.")); FT_Done_FreeType( library ); } ERR_FAIL_COND_V(error,ERR_FILE_CANT_OPEN); /*error = FT_Set_Char_Size(face,0,64*size,512,512); if ( error ) { FT_Done_FreeType( library ); ERR_EXPLAIN(TTR("Invalid font size.")); ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER ); }*/ error = FT_Set_Pixel_Sizes(face,0,size); ascent=face->size->metrics.ascender>>6; descent=-face->size->metrics.descender>>6; linegap=0; //print_line("ASCENT: "+itos(ascent)+" descent "+itos(descent)+" hinted: "+itos(face->face_flags&FT_FACE_FLAG_HINTER)); valid=true; return OK; }
Variant Object::call(const StringName& p_name, VARIANT_ARG_DECLARE) { #if 0 if (p_name==CoreStringNames::get_singleton()->_free) { #ifdef DEBUG_ENABLED if (cast_to<Reference>()) { ERR_EXPLAIN("Can't 'free' a reference."); ERR_FAIL_V(Variant()); } #endif //must be here, must be before everything, memdelete(this); return Variant(); } VARIANT_ARGPTRS; int argc=0; for(int i=0;i<VARIANT_ARG_MAX;i++) { if (argptr[i]->get_type()==Variant::NIL) break; argc++; } Variant::CallError error; Variant ret; if (script_instance) { ret = script_instance->call(p_name,argptr,argc,error); if (_test_call_error(p_name,error)) return ret; } MethodBind *method=ObjectTypeDB::get_method(get_type_name(),p_name); if (method) { Variant ret = method->call(this,argptr,argc,error); if (_test_call_error(p_name,error)) return ret; return ret; } else { } return Variant(); #else VARIANT_ARGPTRS; int argc=0; for(int i=0;i<VARIANT_ARG_MAX;i++) { if (argptr[i]->get_type()==Variant::NIL) break; argc++; } Variant::CallError error; Variant ret = call(p_name,argptr,argc,error); return ret; #endif }
RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) { if (r_error) *r_error = ERR_CANT_OPEN; String local_path; if (p_path.is_rel_path()) local_path = "res://" + p_path; else local_path = ProjectSettings::get_singleton()->localize_path(p_path); bool xl_remapped = false; String path = _path_remap(local_path, &xl_remapped); ERR_FAIL_COND_V(path == "", RES()); if (!p_no_cache && ResourceCache::has(path)) { if (OS::get_singleton()->is_stdout_verbose()) print_line("load resource: " + path + " (cached)"); return RES(ResourceCache::get(path)); } if (OS::get_singleton()->is_stdout_verbose()) print_line("load resource: " + path); bool found = false; // Try all loaders and pick the first match for the type hint for (int i = 0; i < loader_count; i++) { if (!loader[i]->recognize_path(path, p_type_hint)) { continue; } found = true; RES res = loader[i]->load(path, path, r_error); if (res.is_null()) { continue; } if (!p_no_cache) res->set_path(local_path); if (xl_remapped) res->set_as_translation_remapped(true); #ifdef TOOLS_ENABLED res->set_edited(false); if (timestamp_on_load) { uint64_t mt = FileAccess::get_modified_time(path); //printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt); res->set_last_modified_time(mt); } #endif return res; } if (found) { ERR_EXPLAIN("Failed loading resource: " + path); } else { ERR_EXPLAIN("No loader found for resource: " + path); } ERR_FAIL_V(RES()); return RES(); }
Variant Object::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) { if (p_method==CoreStringNames::get_singleton()->_free) { //free must be here, before anything, always ready #ifdef DEBUG_ENABLED if (p_argcount!=0) { r_error.argument=0; r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; return Variant(); } if (cast_to<Reference>()) { r_error.argument=0; r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; ERR_EXPLAIN("Can't 'free' a reference."); ERR_FAIL_V(Variant()); } if (_lock_index.get()>1) { r_error.argument=0; r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; ERR_EXPLAIN("Object is locked and can't be freed."); ERR_FAIL_V(Variant()); } #endif //must be here, must be before everything, memdelete(this); r_error.error=Variant::CallError::CALL_OK; return Variant(); } Variant ret; OBJ_DEBUG_LOCK if (script_instance) { ret = script_instance->call(p_method,p_args,p_argcount,r_error); //force jumptable switch(r_error.error) { case Variant::CallError::CALL_OK: return ret; case Variant::CallError::CALL_ERROR_INVALID_METHOD: break; case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT: case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: return ret; case Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL: {} } } MethodBind *method=ObjectTypeDB::get_method(get_type_name(),p_method); if (method) { ret=method->call(this,p_args,p_argcount,r_error); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; } return ret; }
void Particles2DEditorPlugin::_generate_emission_mask() { Ref<ParticlesMaterial> pm = particles->get_process_material(); if (!pm.is_valid()) { EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material")); return; } Ref<Image> img; img.instance(); Error err = ImageLoader::load_image(source_emission_file, img); ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file); ERR_FAIL_COND(err != OK); if (img->is_compressed()) { img->decompress(); } img->convert(Image::FORMAT_RGBA8); ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8); Size2i s = Size2(img->get_width(), img->get_height()); ERR_FAIL_COND(s.width == 0 || s.height == 0); Vector<Point2> valid_positions; Vector<Point2> valid_normals; Vector<uint8_t> valid_colors; valid_positions.resize(s.width * s.height); EmissionMode emode = (EmissionMode)emission_mask_mode->get_selected(); if (emode == EMISSION_MODE_BORDER_DIRECTED) { valid_normals.resize(s.width * s.height); } bool capture_colors = emission_colors->is_pressed(); if (capture_colors) { valid_colors.resize(s.width * s.height * 4); } int vpc = 0; { PoolVector<uint8_t> data = img->get_data(); PoolVector<uint8_t>::Read r = data.read(); for (int i = 0; i < s.width; i++) { for (int j = 0; j < s.height; j++) { uint8_t a = r[(j * s.width + i) * 4 + 3]; if (a > 128) { if (emode == EMISSION_MODE_SOLID) { if (capture_colors) { valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; } valid_positions.write[vpc++] = Point2(i, j); } else { bool on_border = false; for (int x = i - 1; x <= i + 1; x++) { for (int y = j - 1; y <= j + 1; y++) { if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) { on_border = true; break; } } if (on_border) break; } if (on_border) { valid_positions.write[vpc] = Point2(i, j); if (emode == EMISSION_MODE_BORDER_DIRECTED) { Vector2 normal; for (int x = i - 2; x <= i + 2; x++) { for (int y = j - 2; y <= j + 2; y++) { if (x == i && y == j) continue; if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) { normal += Vector2(x - i, y - j).normalized(); } } } normal.normalize(); valid_normals.write[vpc] = normal; } if (capture_colors) { valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; } vpc++; } } } } } } valid_positions.resize(vpc); if (valid_normals.size()) { valid_normals.resize(vpc); } ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image...")); ERR_FAIL_COND(valid_positions.size() == 0); PoolVector<uint8_t> texdata; int w = 2048; int h = (vpc / 2048) + 1; texdata.resize(w * h * 2 * sizeof(float)); { PoolVector<uint8_t>::Write tw = texdata.write(); float *twf = (float *)tw.ptr(); for (int i = 0; i < vpc; i++) { twf[i * 2 + 0] = valid_positions[i].x; twf[i * 2 + 1] = valid_positions[i].y; } } img.instance(); img->create(w, h, false, Image::FORMAT_RGF, texdata); Ref<ImageTexture> imgt; imgt.instance(); imgt->create_from_image(img, 0); pm->set_emission_point_texture(imgt); pm->set_emission_point_count(vpc); if (capture_colors) { PoolVector<uint8_t> colordata; colordata.resize(w * h * 4); //use RG texture { PoolVector<uint8_t>::Write tw = colordata.write(); for (int i = 0; i < vpc * 4; i++) { tw[i] = valid_colors[i]; } } img.instance(); img->create(w, h, false, Image::FORMAT_RGBA8, colordata); imgt.instance(); imgt->create_from_image(img, 0); pm->set_emission_color_texture(imgt); } if (valid_normals.size()) { pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS); PoolVector<uint8_t> normdata; normdata.resize(w * h * 2 * sizeof(float)); //use RG texture { PoolVector<uint8_t>::Write tw = normdata.write(); float *twf = (float *)tw.ptr(); for (int i = 0; i < vpc; i++) { twf[i * 2 + 0] = valid_normals[i].x; twf[i * 2 + 1] = valid_normals[i].y; } } img.instance(); img->create(w, h, false, Image::FORMAT_RGF, normdata); imgt.instance(); imgt->create_from_image(img, 0); pm->set_emission_normal_texture(imgt); } else { pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); } }
void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool p_give_internet) { const int CHUNK_AXML_FILE = 0x00080003; const int CHUNK_RESOURCEIDS = 0x00080180; const int CHUNK_STRINGS = 0x001C0001; const int CHUNK_XML_END_NAMESPACE = 0x00100101; const int CHUNK_XML_END_TAG = 0x00100103; const int CHUNK_XML_START_NAMESPACE = 0x00100100; const int CHUNK_XML_START_TAG = 0x00100102; const int CHUNK_XML_TEXT = 0x00100104; const int UTF8_FLAG = 0x00000100; Vector<String> string_table; uint32_t ofs=0; uint32_t header = decode_uint32(&p_manifest[ofs]); uint32_t filesize = decode_uint32(&p_manifest[ofs+4]); ofs+=8; // print_line("FILESIZE: "+itos(filesize)+" ACTUAL: "+itos(p_manifest.size())); uint32_t string_count; uint32_t styles_count; uint32_t string_flags; uint32_t string_data_offset; uint32_t styles_offset; uint32_t string_table_begins; uint32_t string_table_ends; Vector<uint8_t> stable_extra; while(ofs < p_manifest.size()) { uint32_t chunk = decode_uint32(&p_manifest[ofs]); uint32_t size = decode_uint32(&p_manifest[ofs+4]); switch(chunk) { case CHUNK_STRINGS: { int iofs=ofs+8; string_count=decode_uint32(&p_manifest[iofs]); styles_count=decode_uint32(&p_manifest[iofs+4]); uint32_t string_flags=decode_uint32(&p_manifest[iofs+8]); string_data_offset=decode_uint32(&p_manifest[iofs+12]); styles_offset=decode_uint32(&p_manifest[iofs+16]); /* printf("string count: %i\n",string_count); printf("flags: %i\n",string_flags); printf("sdata ofs: %i\n",string_data_offset); printf("styles ofs: %i\n",styles_offset); */ uint32_t st_offset=iofs+20; string_table.resize(string_count); uint32_t string_end=0; string_table_begins=st_offset; for(int i=0;i<string_count;i++) { uint32_t string_at = decode_uint32(&p_manifest[st_offset+i*4]); string_at+=st_offset+string_count*4; ERR_EXPLAIN("Unimplemented, can't read utf8 string table."); ERR_FAIL_COND(string_flags&UTF8_FLAG); if (string_flags&UTF8_FLAG) { } else { uint32_t len = decode_uint16(&p_manifest[string_at]); Vector<CharType> ucstring; ucstring.resize(len+1); for(int j=0;j<len;j++) { uint16_t c=decode_uint16(&p_manifest[string_at+2+2*j]); ucstring[j]=c; } string_end=MAX(string_at+2+2*len,string_end); ucstring[len]=0; string_table[i]=ucstring.ptr(); } // print_line("String "+itos(i)+": "+string_table[i]); } for(int i=string_end;i<(ofs+size);i++) { stable_extra.push_back(p_manifest[i]); } // printf("stable extra: %i\n",int(stable_extra.size())); string_table_ends=ofs+size; // print_line("STABLE SIZE: "+itos(size)+" ACTUAL: "+itos(string_table_ends)); } break; case CHUNK_XML_START_TAG: { int iofs=ofs+8; uint32_t line=decode_uint32(&p_manifest[iofs]); uint32_t nspace=decode_uint32(&p_manifest[iofs+8]); uint32_t name=decode_uint32(&p_manifest[iofs+12]); uint32_t check=decode_uint32(&p_manifest[iofs+16]); String tname=string_table[name]; // printf("NSPACE: %i\n",nspace); //printf("NAME: %i (%s)\n",name,tname.utf8().get_data()); //printf("CHECK: %x\n",check); uint32_t attrcount=decode_uint32(&p_manifest[iofs+20]); iofs+=28; //printf("ATTRCOUNT: %x\n",attrcount); for(int i=0;i<attrcount;i++) { uint32_t attr_nspace=decode_uint32(&p_manifest[iofs]); uint32_t attr_name=decode_uint32(&p_manifest[iofs+4]); uint32_t attr_value=decode_uint32(&p_manifest[iofs+8]); uint32_t attr_flags=decode_uint32(&p_manifest[iofs+12]); uint32_t attr_resid=decode_uint32(&p_manifest[iofs+16]); String value; if (attr_value!=0xFFFFFFFF) value=string_table[attr_value]; else value="Res #"+itos(attr_resid); String attrname = string_table[attr_name]; String nspace; if (attr_nspace!=0xFFFFFFFF) nspace=string_table[attr_nspace]; else nspace=""; printf("ATTR %i NSPACE: %i\n",i,attr_nspace); printf("ATTR %i NAME: %i (%s)\n",i,attr_name,attrname.utf8().get_data()); printf("ATTR %i VALUE: %i (%s)\n",i,attr_value,value.utf8().get_data()); printf("ATTR %i FLAGS: %x\n",i,attr_flags); printf("ATTR %i RESID: %x\n",i,attr_resid); //replace project information if (tname=="manifest" && attrname=="package") { print_line("FOUND PACKAGE"); string_table[attr_value]=get_package_name(); } //print_line("tname: "+tname); //print_line("nspace: "+nspace); //print_line("attrname: "+attrname); if (tname=="manifest" && /*nspace=="android" &&*/ attrname=="versionCode") { print_line("FOUND versioncode"); encode_uint32(version_code,&p_manifest[iofs+16]); } if (tname=="manifest" && /*nspace=="android" &&*/ attrname=="versionName") { print_line("FOUND versionname"); if (attr_value==0xFFFFFFFF) { WARN_PRINT("Version name in a resource, should be plaintext") } else string_table[attr_value]=version_name; } if (tname=="activity" && /*nspace=="android" &&*/ attrname=="screenOrientation") { encode_uint32(orientation==0?0:1,&p_manifest[iofs+16]); /* print_line("FOUND screen orientation"); if (attr_value==0xFFFFFFFF) { WARN_PRINT("Version name in a resource, should be plaintext") } else { string_table[attr_value]=(orientation==0?"landscape":"portrait"); }*/ } if (tname=="uses-permission" && /*nspace=="android" &&*/ attrname=="name") { if (value.begins_with("godot.custom")) { int which = value.get_slice(".",2).to_int(); if (which>=0 && which<MAX_USER_PERMISSIONS && user_perms[which].strip_edges()!="") { string_table[attr_value]=user_perms[which].strip_edges(); } } else if (value.begins_with("godot.")) { String perm = value.get_slice(".",1); print_line("PERM: "+perm+" HAS: "+itos(perms.has(perm))); if (perms.has(perm) || (p_give_internet && perm=="INTERNET")) { string_table[attr_value]="android.permission."+perm; } } } if (tname=="supports-screens" ) { if (attrname=="smallScreens") { encode_uint32(screen_support[SCREEN_SMALL]?0xFFFFFFFF:0,&p_manifest[iofs+16]); } else if (attrname=="normalScreens") { encode_uint32(screen_support[SCREEN_NORMAL]?0xFFFFFFFF:0,&p_manifest[iofs+16]); } else if (attrname=="largeScreens") { encode_uint32(screen_support[SCREEN_LARGE]?0xFFFFFFFF:0,&p_manifest[iofs+16]); } else if (attrname=="xlargeScreens") { encode_uint32(screen_support[SCREEN_XLARGE]?0xFFFFFFFF:0,&p_manifest[iofs+16]); } } iofs+=20; } } break; } printf("chunk %x: size: %d\n",chunk,size); ofs+=size; }
void AnimationCache::_update_cache() { cache_valid = false; ERR_FAIL_COND(!root); ERR_FAIL_COND(!root->is_inside_tree()); ERR_FAIL_COND(animation.is_null()); for (int i = 0; i < animation->get_track_count(); i++) { NodePath np = animation->track_get_path(i); Node *node = root->get_node(np); if (!node) { path_cache.push_back(Path()); ERR_EXPLAIN("Invalid Track Path in Animation: " + np); ERR_CONTINUE(!node); } Path path; Ref<Resource> res; if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM) { if (np.get_subname_count() > 1) { path_cache.push_back(Path()); ERR_EXPLAIN("Transform tracks can't have a subpath: " + np); ERR_CONTINUE(animation->track_get_type(i) == Animation::TYPE_TRANSFORM); } Spatial *sp = Object::cast_to<Spatial>(node); if (!sp) { path_cache.push_back(Path()); ERR_EXPLAIN("Transform track not of type Spatial: " + np); ERR_CONTINUE(!sp); } if (np.get_subname_count() == 1) { StringName property = np.get_subname(0); String ps = property; Skeleton *sk = Object::cast_to<Skeleton>(node); if (!sk) { path_cache.push_back(Path()); ERR_EXPLAIN("Property defined in Transform track, but not a Skeleton!: " + np); ERR_CONTINUE(!sk); } int idx = sk->find_bone(ps); if (idx == -1) { path_cache.push_back(Path()); ERR_EXPLAIN("Property defined in Transform track, but not a Skeleton Bone!: " + np); ERR_CONTINUE(idx == -1); } path.bone_idx = idx; path.skeleton = sk; } path.spatial = sp; } else { if (np.get_subname_count() > 0) { RES res2; Vector<StringName> leftover_subpath; // We don't want to cache the last resource unless it is a method call bool is_method = animation->track_get_type(i) == Animation::TYPE_METHOD; root->get_node_and_resource(np, res2, leftover_subpath, is_method); if (res2.is_valid()) { path.resource = res2; } else { path.node = node; } path.object = res2.is_valid() ? res2.ptr() : (Object *)node; path.subpath = leftover_subpath; } else { path.node = node; path.object = node; path.subpath = np.get_subnames(); } } if (animation->track_get_type(i) == Animation::TYPE_VALUE) { if (np.get_subname_count() == 0) { path_cache.push_back(Path()); ERR_EXPLAIN("Value Track lacks property: " + np); ERR_CONTINUE(np.get_subname_count() == 0); } } else if (animation->track_get_type(i) == Animation::TYPE_METHOD) { if (path.subpath.size() != 0) { // Trying to call a method of a non-resource path_cache.push_back(Path()); ERR_EXPLAIN("Method Track has property: " + np); ERR_CONTINUE(path.subpath.size() != 0); } } path.valid = true; path_cache.push_back(path); if (!connected_nodes.has(path.node)) { connected_nodes.insert(path.node); path.node->connect("tree_exiting", this, "_node_exit_tree", Node::make_binds(path.node), CONNECT_ONESHOT); } } cache_dirty = false; cache_valid = true; }
bool PackedSourcePCK::try_open_pack(const String& p_path) { FileAccess *f = FileAccess::open(p_path,FileAccess::READ); if (!f) return false; uint32_t magic= f->get_32(); if (magic != 0x4b435047) { //maybe at he end.... self contained exe f->seek_end(); f->seek( f->get_pos() -4 ); magic = f->get_32(); if (magic != 0x4b435047) { memdelete(f); return false; } f->seek( f->get_pos() -12 ); uint64_t ds = f->get_64(); f->seek( f->get_pos() -ds-8 ); magic = f->get_32(); if (magic != 0x4b435047) { memdelete(f); return false; } } uint32_t ver_major = f->get_32(); uint32_t ver_minor = f->get_32(); uint32_t ver_rev = f->get_32(); ERR_EXPLAIN("Pack created with a newer version of the engine: "+itos(ver_major)+"."+itos(ver_minor)+"."+itos(ver_rev)); ERR_FAIL_COND_V( ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), ERR_INVALID_DATA); for(int i=0;i<16;i++) { //reserved f->get_32(); } int file_count = f->get_32(); for(int i=0;i<file_count;i++) { uint32_t sl = f->get_32(); CharString cs; cs.resize(sl+1); f->get_buffer((uint8_t*)cs.ptr(),sl); cs[sl]=0; String path; path.parse_utf8(cs.ptr()); uint64_t ofs = f->get_64(); uint64_t size = f->get_64(); uint8_t md5[16]; f->get_buffer(md5,16); PackedData::get_singleton()->add_path(p_path, path, ofs, size, md5,this); }; return true; };
void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) { //this function is called when there is a debugger break (bug on script) //or when execution is paused from editor if (!tcp_client->is_connected_to_host()) { ERR_EXPLAIN("Script Debugger failed to connect, but being used anyway."); ERR_FAIL(); } packet_peer_stream->put_var("debug_enter"); packet_peer_stream->put_var(2); packet_peer_stream->put_var(p_can_continue); packet_peer_stream->put_var(p_script->debug_get_error()); skip_profile_frame = true; // to avoid super long frame time for the frame Input::MouseMode mouse_mode = Input::get_singleton()->get_mouse_mode(); if (mouse_mode != Input::MOUSE_MODE_VISIBLE) Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); while (true) { _get_output(); if (packet_peer_stream->get_available_packet_count() > 0) { Variant var; Error err = packet_peer_stream->get_var(var); ERR_CONTINUE(err != OK); ERR_CONTINUE(var.get_type() != Variant::ARRAY); Array cmd = var; ERR_CONTINUE(cmd.size() == 0); ERR_CONTINUE(cmd[0].get_type() != Variant::STRING); String command = cmd[0]; if (command == "get_stack_dump") { packet_peer_stream->put_var("stack_dump"); int slc = p_script->debug_get_stack_level_count(); packet_peer_stream->put_var(slc); for (int i = 0; i < slc; i++) { Dictionary d; d["file"] = p_script->debug_get_stack_level_source(i); d["line"] = p_script->debug_get_stack_level_line(i); d["function"] = p_script->debug_get_stack_level_function(i); //d["id"]=p_script->debug_get_stack_level_ d["id"] = 0; packet_peer_stream->put_var(d); } } else if (command == "get_stack_frame_vars") { cmd.remove(0); ERR_CONTINUE(cmd.size() != 1); int lv = cmd[0]; List<String> members; List<Variant> member_vals; p_script->debug_get_stack_level_members(lv, &members, &member_vals); ERR_CONTINUE(members.size() != member_vals.size()); List<String> locals; List<Variant> local_vals; p_script->debug_get_stack_level_locals(lv, &locals, &local_vals); ERR_CONTINUE(locals.size() != local_vals.size()); packet_peer_stream->put_var("stack_frame_vars"); packet_peer_stream->put_var(2 + locals.size() * 2 + members.size() * 2); { //members packet_peer_stream->put_var(members.size()); List<String>::Element *E = members.front(); List<Variant>::Element *F = member_vals.front(); while (E) { _put_variable(E->get(), F->get()); E = E->next(); F = F->next(); } } { //locals packet_peer_stream->put_var(locals.size()); List<String>::Element *E = locals.front(); List<Variant>::Element *F = local_vals.front(); while (E) { _put_variable(E->get(), F->get()); E = E->next(); F = F->next(); } } } else if (command == "step") { set_depth(-1); set_lines_left(1); break; } else if (command == "next") { set_depth(0); set_lines_left(1); break; } else if (command == "continue") { set_depth(-1); set_lines_left(-1); OS::get_singleton()->move_window_to_foreground(); break; } else if (command == "break") { ERR_PRINT("Got break when already broke!"); break; } else if (command == "request_scene_tree") { if (request_scene_tree) request_scene_tree(request_scene_tree_ud); } else if (command == "request_video_mem") { _send_video_memory(); } else if (command == "inspect_object") { ObjectID id = cmd[1]; _send_object_id(id); } else if (command == "set_object_property") { _set_object_property(cmd[1], cmd[2], cmd[3]); } else if (command == "reload_scripts") { reload_all_scripts = true; } else if (command == "breakpoint") { bool set = cmd[3]; if (set) insert_breakpoint(cmd[2], cmd[1]); else remove_breakpoint(cmd[2], cmd[1]); } else { _parse_live_edit(cmd); } } else { OS::get_singleton()->delay_usec(10000); } } packet_peer_stream->put_var("debug_exit"); packet_peer_stream->put_var(0); if (mouse_mode != Input::MOUSE_MODE_VISIBLE) Input::get_singleton()->set_mouse_mode(mouse_mode); }
static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &methods) { String section = parser->get_node_name(); String element = section.substr(0, section.length() - 1); while (parser->read() == OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { if (parser->get_node_name() == element) { DocData::MethodDoc method; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); method.name = parser->get_attribute_value("name"); if (parser->has_attribute("qualifiers")) method.qualifiers = parser->get_attribute_value("qualifiers"); while (parser->read() == OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { String name = parser->get_node_name(); if (name == "return") { ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT); method.return_type = parser->get_attribute_value("type"); if (parser->has_attribute("enum")) { method.return_enum = parser->get_attribute_value("enum"); } } else if (name == "argument") { DocData::ArgumentDoc argument; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); argument.name = parser->get_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT); argument.type = parser->get_attribute_value("type"); if (parser->has_attribute("enum")) { argument.enumeration = parser->get_attribute_value("enum"); } method.arguments.push_back(argument); } else if (name == "description") { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) method.description = parser->get_node_data(); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == element) break; } methods.push_back(method); } else { ERR_EXPLAIN("Invalid tag in doc file: " + parser->get_node_name()); ERR_FAIL_V(ERR_FILE_CORRUPT); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == section) break; } return OK; }
MethodBind* ObjectTypeDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind , const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) { StringName mdname=method_name.name; #else MethodBind* ObjectTypeDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind , const char *method_name, const Variant **p_defs, int p_defcount) { StringName mdname=StaticCString::create(method_name); #endif StringName rettype; if (mdname.operator String().find(":")!=-1) { rettype = mdname.operator String().get_slice(":",1); mdname = mdname.operator String().get_slice(":",0); } OBJTYPE_LOCK; ERR_FAIL_COND_V(!p_bind,NULL); p_bind->set_name(mdname); String instance_type=p_bind->get_instance_type(); TypeInfo *type=types.getptr(instance_type); if (!type) { print_line("couldn't bind method "+mdname+" for instance: "+instance_type); memdelete(p_bind); ERR_FAIL_COND_V(!type,NULL); } if (type->method_map.has(mdname)) { memdelete(p_bind); // overloading not supported ERR_EXPLAIN("Method already bound: "+instance_type+"::"+mdname); ERR_FAIL_V(NULL); } #ifdef DEBUG_METHODS_ENABLED p_bind->set_argument_names(method_name.args); p_bind->set_return_type(rettype); type->method_order.push_back(mdname); #endif type->method_map[mdname]=p_bind; Vector<Variant> defvals; #define PARSE_DEFVAL(m_defval)\ if (d##m_defval.used) defvals.insert(0,d##m_defval.val);\ else goto set_defvals; defvals.resize(p_defcount); for(int i=0;i<p_defcount;i++) { defvals[i]=*p_defs[p_defcount-i-1]; } set_defvals: p_bind->set_default_arguments(defvals); p_bind->set_hint_flags(p_flags); #undef PARSE_DEFVAL return p_bind; }
Error DocData::_load(Ref<XMLParser> parser) { Error err = OK; while ((err = parser->read()) == OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "?xml") { parser->skip_section(); } if (parser->get_node_type() != XMLParser::NODE_ELEMENT) continue; //no idea what this may be, but skipping anyway ERR_FAIL_COND_V(parser->get_node_name() != "class", ERR_FILE_CORRUPT); ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); String name = parser->get_attribute_value("name"); class_list[name] = ClassDoc(); ClassDoc &c = class_list[name]; //print_line("class: "+name); c.name = name; if (parser->has_attribute("inherits")) c.inherits = parser->get_attribute_value("inherits"); if (parser->has_attribute("category")) c.category = parser->get_attribute_value("category"); while (parser->read() == OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { String name = parser->get_node_name(); if (name == "brief_description") { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) c.brief_description = parser->get_node_data(); } else if (name == "description") { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) c.description = parser->get_node_data(); } else if (name == "tutorials") { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) c.tutorials = parser->get_node_data(); } else if (name == "demos") { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) c.demos = parser->get_node_data(); } else if (name == "methods") { Error err = _parse_methods(parser, c.methods); ERR_FAIL_COND_V(err, err); } else if (name == "signals") { Error err = _parse_methods(parser, c.signals); ERR_FAIL_COND_V(err, err); } else if (name == "members") { while (parser->read() == OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { String name = parser->get_node_name(); if (name == "member") { PropertyDoc prop; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); prop.name = parser->get_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT); prop.type = parser->get_attribute_value("type"); if (parser->has_attribute("setter")) prop.setter = parser->get_attribute_value("setter"); if (parser->has_attribute("getter")) prop.getter = parser->get_attribute_value("getter"); if (parser->has_attribute("enum")) prop.enumeration = parser->get_attribute_value("enum"); parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) prop.description = parser->get_node_data(); c.properties.push_back(prop); } else { ERR_EXPLAIN("Invalid tag in doc file: " + name); ERR_FAIL_V(ERR_FILE_CORRUPT); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "members") break; //end of <constants> } } else if (name == "theme_items") { while (parser->read() == OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { String name = parser->get_node_name(); if (name == "theme_item") { PropertyDoc prop; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); prop.name = parser->get_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT); prop.type = parser->get_attribute_value("type"); parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) prop.description = parser->get_node_data(); c.theme_properties.push_back(prop); } else { ERR_EXPLAIN("Invalid tag in doc file: " + name); ERR_FAIL_V(ERR_FILE_CORRUPT); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "theme_items") break; //end of <constants> } } else if (name == "constants") { while (parser->read() == OK) { if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { String name = parser->get_node_name(); if (name == "constant") { ConstantDoc constant; ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); constant.name = parser->get_attribute_value("name"); ERR_FAIL_COND_V(!parser->has_attribute("value"), ERR_FILE_CORRUPT); constant.value = parser->get_attribute_value("value"); if (parser->has_attribute("enum")) { constant.enumeration = parser->get_attribute_value("enum"); } parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) constant.description = parser->get_node_data(); c.constants.push_back(constant); } else { ERR_EXPLAIN("Invalid tag in doc file: " + name); ERR_FAIL_V(ERR_FILE_CORRUPT); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "constants") break; //end of <constants> } } else { ERR_EXPLAIN("Invalid tag in doc file: " + name); ERR_FAIL_V(ERR_FILE_CORRUPT); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "class") break; //end of <asset> } } return OK; }
MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) { StringName mdname = method_name.name; #else MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount) { StringName mdname = StaticCString::create(method_name); #endif OBJTYPE_WLOCK; ERR_FAIL_COND_V(!p_bind, NULL); p_bind->set_name(mdname); String instance_type = p_bind->get_instance_class(); #ifdef DEBUG_ENABLED if (has_method(instance_type, mdname)) { ERR_EXPLAIN("Class " + String(instance_type) + " already has a method " + String(mdname)); ERR_FAIL_V(NULL); } #endif ClassInfo *type = classes.getptr(instance_type); if (!type) { ERR_PRINTS("Couldn't bind method '" + mdname + "' for instance: " + instance_type); memdelete(p_bind); ERR_FAIL_V(NULL); } if (type->method_map.has(mdname)) { memdelete(p_bind); // overloading not supported ERR_EXPLAIN("Method already bound: " + instance_type + "::" + mdname); ERR_FAIL_V(NULL); } #ifdef DEBUG_METHODS_ENABLED if (method_name.args.size() > p_bind->get_argument_count()) { memdelete(p_bind); ERR_EXPLAIN("Method definition provides more arguments than the method actually has: " + instance_type + "::" + mdname); ERR_FAIL_V(NULL); } p_bind->set_argument_names(method_name.args); type->method_order.push_back(mdname); #endif type->method_map[mdname] = p_bind; Vector<Variant> defvals; defvals.resize(p_defcount); for (int i = 0; i < p_defcount; i++) { defvals.write[i] = *p_defs[p_defcount - i - 1]; } p_bind->set_default_arguments(defvals); p_bind->set_hint_flags(p_flags); return p_bind; }
Error DocData::save_classes(const String &p_default_path, const Map<String, String> &p_class_path) { for (Map<String, ClassDoc>::Element *E = class_list.front(); E; E = E->next()) { ClassDoc &c = E->get(); String save_path; if (p_class_path.has(c.name)) { save_path = p_class_path[c.name]; } else { save_path = p_default_path; } Error err; String save_file = save_path.plus_file(c.name + ".xml"); FileAccessRef f = FileAccess::open(save_file, FileAccess::WRITE, &err); if (err) { ERR_EXPLAIN("Can't write doc file: " + save_file); ERR_FAIL_V(err); } _write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); String header = "<class name=\"" + c.name + "\""; if (c.inherits != "") header += " inherits=\"" + c.inherits + "\""; String category = c.category; if (c.category == "") category = "Core"; header += " category=\"" + category + "\""; header += String(" version=\"") + itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + VERSION_STATUS + "\""; header += ">"; _write_string(f, 0, header); _write_string(f, 1, "<brief_description>"); _write_string(f, 2, c.brief_description.strip_edges().xml_escape()); _write_string(f, 1, "</brief_description>"); _write_string(f, 1, "<description>"); _write_string(f, 2, c.description.strip_edges().xml_escape()); _write_string(f, 1, "</description>"); _write_string(f, 1, "<tutorials>"); _write_string(f, 2, c.tutorials.strip_edges().xml_escape()); _write_string(f, 1, "</tutorials>"); _write_string(f, 1, "<demos>"); _write_string(f, 2, c.demos.strip_edges().xml_escape()); _write_string(f, 1, "</demos>"); _write_string(f, 1, "<methods>"); c.methods.sort(); for (int i = 0; i < c.methods.size(); i++) { MethodDoc &m = c.methods[i]; String qualifiers; if (m.qualifiers != "") qualifiers += " qualifiers=\"" + m.qualifiers.xml_escape() + "\""; _write_string(f, 2, "<method name=\"" + m.name + "\"" + qualifiers + ">"); if (m.return_type != "") { String enum_text; if (m.return_enum != String()) { enum_text = " enum=\"" + m.return_enum + "\""; } _write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + ">"); _write_string(f, 3, "</return>"); } for (int j = 0; j < m.arguments.size(); j++) { ArgumentDoc &a = m.arguments[j]; String enum_text; if (a.enumeration != String()) { enum_text = " enum=\"" + a.enumeration + "\""; } if (a.default_value != "") _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\">"); else _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + ">"); _write_string(f, 3, "</argument>"); } _write_string(f, 3, "<description>"); _write_string(f, 4, m.description.strip_edges().xml_escape()); _write_string(f, 3, "</description>"); _write_string(f, 2, "</method>"); } _write_string(f, 1, "</methods>"); if (c.properties.size()) { _write_string(f, 1, "<members>"); c.properties.sort(); for (int i = 0; i < c.properties.size(); i++) { String enum_text; if (c.properties[i].enumeration != String()) { enum_text = " enum=\"" + c.properties[i].enumeration + "\""; } PropertyDoc &p = c.properties[i]; _write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\"" + enum_text + ">"); _write_string(f, 3, p.description.strip_edges().xml_escape()); _write_string(f, 2, "</member>"); } _write_string(f, 1, "</members>"); } if (c.signals.size()) { c.signals.sort(); _write_string(f, 1, "<signals>"); for (int i = 0; i < c.signals.size(); i++) { MethodDoc &m = c.signals[i]; _write_string(f, 2, "<signal name=\"" + m.name + "\">"); for (int j = 0; j < m.arguments.size(); j++) { ArgumentDoc &a = m.arguments[j]; _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\">"); _write_string(f, 3, "</argument>"); } _write_string(f, 3, "<description>"); _write_string(f, 4, m.description.strip_edges().xml_escape()); _write_string(f, 3, "</description>"); _write_string(f, 2, "</signal>"); } _write_string(f, 1, "</signals>"); } _write_string(f, 1, "<constants>"); for (int i = 0; i < c.constants.size(); i++) { ConstantDoc &k = c.constants[i]; if (k.enumeration != String()) { _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">"); } else { _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">"); } _write_string(f, 3, k.description.strip_edges().xml_escape()); _write_string(f, 2, "</constant>"); } _write_string(f, 1, "</constants>"); if (c.theme_properties.size()) { c.theme_properties.sort(); _write_string(f, 1, "<theme_items>"); for (int i = 0; i < c.theme_properties.size(); i++) { PropertyDoc &p = c.theme_properties[i]; _write_string(f, 2, "<theme_item name=\"" + p.name + "\" type=\"" + p.type + "\">"); _write_string(f, 2, "</theme_item>"); } _write_string(f, 1, "</theme_items>"); } _write_string(f, 0, "</class>"); } return OK; }
void ResourceFormatSaverBinaryInstance::write_variant(const Variant& p_property,const PropertyInfo& p_hint) { switch(p_property.get_type()) { case Variant::NIL: { f->store_32(VARIANT_NIL); // don't store anything } break; case Variant::BOOL: { f->store_32(VARIANT_BOOL); bool val=p_property; f->store_32(val); } break; case Variant::INT: { f->store_32(VARIANT_INT); int val=p_property; f->store_32(val); } break; case Variant::REAL: { f->store_32(VARIANT_REAL); real_t val=p_property; f->store_real(val); } break; case Variant::STRING: { f->store_32(VARIANT_STRING); String val=p_property; save_unicode_string(val); } break; case Variant::VECTOR2: { f->store_32(VARIANT_VECTOR2); Vector2 val=p_property; f->store_real(val.x); f->store_real(val.y); } break; case Variant::RECT2: { f->store_32(VARIANT_RECT2); Rect2 val=p_property; f->store_real(val.pos.x); f->store_real(val.pos.y); f->store_real(val.size.x); f->store_real(val.size.y); } break; case Variant::VECTOR3: { f->store_32(VARIANT_VECTOR3); Vector3 val=p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); } break; case Variant::PLANE: { f->store_32(VARIANT_PLANE); Plane val=p_property; f->store_real(val.normal.x); f->store_real(val.normal.y); f->store_real(val.normal.z); f->store_real(val.d); } break; case Variant::QUAT: { f->store_32(VARIANT_QUAT); Quat val=p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); f->store_real(val.w); } break; case Variant::_AABB: { f->store_32(VARIANT_AABB); AABB val=p_property; f->store_real(val.pos.x); f->store_real(val.pos.y); f->store_real(val.pos.z); f->store_real(val.size.x); f->store_real(val.size.y); f->store_real(val.size.z); } break; case Variant::MATRIX32: { f->store_32(VARIANT_MATRIX32); Matrix32 val=p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); f->store_real(val.elements[1].x); f->store_real(val.elements[1].y); f->store_real(val.elements[2].x); f->store_real(val.elements[2].y); } break; case Variant::MATRIX3: { f->store_32(VARIANT_MATRIX3); Matrix3 val=p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); f->store_real(val.elements[0].z); f->store_real(val.elements[1].x); f->store_real(val.elements[1].y); f->store_real(val.elements[1].z); f->store_real(val.elements[2].x); f->store_real(val.elements[2].y); f->store_real(val.elements[2].z); } break; case Variant::TRANSFORM: { f->store_32(VARIANT_TRANSFORM); Transform val=p_property; f->store_real(val.basis.elements[0].x); f->store_real(val.basis.elements[0].y); f->store_real(val.basis.elements[0].z); f->store_real(val.basis.elements[1].x); f->store_real(val.basis.elements[1].y); f->store_real(val.basis.elements[1].z); f->store_real(val.basis.elements[2].x); f->store_real(val.basis.elements[2].y); f->store_real(val.basis.elements[2].z); f->store_real(val.origin.x); f->store_real(val.origin.y); f->store_real(val.origin.z); } break; case Variant::COLOR: { f->store_32(VARIANT_COLOR); Color val=p_property; f->store_real(val.r); f->store_real(val.g); f->store_real(val.b); f->store_real(val.a); } break; case Variant::IMAGE: { f->store_32(VARIANT_IMAGE); Image val =p_property; if (val.empty()) { f->store_32(IMAGE_ENCODING_EMPTY); break; } int encoding=IMAGE_ENCODING_RAW; float quality=0.7; if (val.get_format() <= Image::FORMAT_INDEXED_ALPHA) { //can only compress uncompressed stuff if (p_hint.hint==PROPERTY_HINT_IMAGE_COMPRESS_LOSSY && Image::lossy_packer) { encoding=IMAGE_ENCODING_LOSSY; float qs=p_hint.hint_string.to_double(); if (qs!=0.0) quality=qs; } else if (p_hint.hint==PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS && Image::lossless_packer) { encoding=IMAGE_ENCODING_LOSSLESS; } } f->store_32(encoding); //raw encoding if (encoding==IMAGE_ENCODING_RAW) { f->store_32(val.get_width()); f->store_32(val.get_height()); f->store_32(val.get_mipmaps()); switch(val.get_format()) { case Image::FORMAT_GRAYSCALE: f->store_32(IMAGE_FORMAT_GRAYSCALE ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 case Image::FORMAT_INTENSITY: f->store_32(IMAGE_FORMAT_INTENSITY ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 case Image::FORMAT_GRAYSCALE_ALPHA: f->store_32(IMAGE_FORMAT_GRAYSCALE_ALPHA ); break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255 case Image::FORMAT_RGB: f->store_32(IMAGE_FORMAT_RGB ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B case Image::FORMAT_RGBA: f->store_32(IMAGE_FORMAT_RGBA ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A case Image::FORMAT_INDEXED: f->store_32(IMAGE_FORMAT_INDEXED ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*3 bytes of palette case Image::FORMAT_INDEXED_ALPHA: f->store_32(IMAGE_FORMAT_INDEXED_ALPHA ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*4 bytes of palette (alpha) case Image::FORMAT_BC1: f->store_32(IMAGE_FORMAT_BC1 ); break; // DXT1 case Image::FORMAT_BC2: f->store_32(IMAGE_FORMAT_BC2 ); break; // DXT3 case Image::FORMAT_BC3: f->store_32(IMAGE_FORMAT_BC3 ); break; // DXT5 case Image::FORMAT_BC4: f->store_32(IMAGE_FORMAT_BC4 ); break; // ATI1 case Image::FORMAT_BC5: f->store_32(IMAGE_FORMAT_BC5 ); break; // ATI2 case Image::FORMAT_PVRTC2: f->store_32(IMAGE_FORMAT_PVRTC2 ); break; case Image::FORMAT_PVRTC2_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC2_ALPHA ); break; 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: {} } int dlen = val.get_data().size(); f->store_32(dlen); DVector<uint8_t>::Read r = val.get_data().read(); f->store_buffer(r.ptr(),dlen); _pad_buffer(dlen); } else { DVector<uint8_t> data; if (encoding==IMAGE_ENCODING_LOSSY) { data=Image::lossy_packer(val,quality); } else if (encoding==IMAGE_ENCODING_LOSSLESS) { data=Image::lossless_packer(val); } int ds=data.size(); f->store_32(ds); if (ds>0) { DVector<uint8_t>::Read r = data.read(); f->store_buffer(r.ptr(),ds); _pad_buffer(ds); } } } break; case Variant::NODE_PATH: { f->store_32(VARIANT_NODE_PATH); NodePath np=p_property; f->store_16(np.get_name_count()); uint16_t snc = np.get_subname_count(); if (np.is_absolute()) snc|=0x8000; f->store_16(snc); for(int i=0;i<np.get_name_count();i++) f->store_32(get_string_index(np.get_name(i))); for(int i=0;i<np.get_subname_count();i++) f->store_32(get_string_index(np.get_subname(i))); f->store_32(get_string_index(np.get_property())); } break; case Variant::_RID: { f->store_32(VARIANT_RID); WARN_PRINT("Can't save RIDs"); RID val = p_property; f->store_32(val.get_id()); } break; case Variant::OBJECT: { f->store_32(VARIANT_OBJECT); RES res = p_property; if (res.is_null()) { f->store_32(OBJECT_EMPTY); return; // don't save it } if (res->get_path().length() && res->get_path().find("::")==-1) { f->store_32(OBJECT_EXTERNAL_RESOURCE); save_unicode_string(res->get_save_type()); String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); save_unicode_string(path); } else { if (!resource_set.has(res)) { f->store_32(OBJECT_EMPTY); ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); ERR_FAIL(); } f->store_32(OBJECT_INTERNAL_RESOURCE); f->store_32(res->get_subindex()); //internal resource } } break; case Variant::INPUT_EVENT: { f->store_32(VARIANT_INPUT_EVENT); WARN_PRINT("Can't save InputEvent (maybe it could..)"); } break; case Variant::DICTIONARY: { f->store_32(VARIANT_DICTIONARY); Dictionary d = p_property; f->store_32(uint32_t(d.size())|(d.is_shared()?0x80000000:0)); List<Variant> keys; d.get_key_list(&keys); for(List<Variant>::Element *E=keys.front();E;E=E->next()) { //if (!_check_type(dict[E->get()])) // continue; write_variant(E->get()); write_variant(d[E->get()]); } } break; case Variant::ARRAY: { f->store_32(VARIANT_ARRAY); Array a=p_property; f->store_32(uint32_t(a.size())|(a.is_shared()?0x80000000:0)); for(int i=0;i<a.size();i++) { write_variant(a[i]); } } break; case Variant::RAW_ARRAY: { f->store_32(VARIANT_RAW_ARRAY); DVector<uint8_t> arr = p_property; int len=arr.size(); f->store_32(len); DVector<uint8_t>::Read r = arr.read(); f->store_buffer(r.ptr(),len); _pad_buffer(len); } break; case Variant::INT_ARRAY: { f->store_32(VARIANT_INT_ARRAY); DVector<int> arr = p_property; int len=arr.size(); f->store_32(len); DVector<int>::Read r = arr.read(); for(int i=0;i<len;i++) f->store_32(r[i]); } break; case Variant::REAL_ARRAY: { f->store_32(VARIANT_REAL_ARRAY); DVector<real_t> arr = p_property; int len=arr.size(); f->store_32(len); DVector<real_t>::Read r = arr.read(); for(int i=0;i<len;i++) { f->store_real(r[i]); } } break; case Variant::STRING_ARRAY: { f->store_32(VARIANT_STRING_ARRAY); DVector<String> arr = p_property; int len=arr.size(); f->store_32(len); DVector<String>::Read r = arr.read(); for(int i=0;i<len;i++) { save_unicode_string(r[i]); } } break; case Variant::VECTOR3_ARRAY: { f->store_32(VARIANT_VECTOR3_ARRAY); DVector<Vector3> arr = p_property; int len=arr.size(); f->store_32(len); DVector<Vector3>::Read r = arr.read(); for(int i=0;i<len;i++) { f->store_real(r[i].x); f->store_real(r[i].y); f->store_real(r[i].z); } } break; case Variant::VECTOR2_ARRAY: { f->store_32(VARIANT_VECTOR2_ARRAY); DVector<Vector2> arr = p_property; int len=arr.size(); f->store_32(len); DVector<Vector2>::Read r = arr.read(); for(int i=0;i<len;i++) { f->store_real(r[i].x); f->store_real(r[i].y); } } break; case Variant::COLOR_ARRAY: { f->store_32(VARIANT_COLOR_ARRAY); DVector<Color> arr = p_property; int len=arr.size(); f->store_32(len); DVector<Color>::Read r = arr.read(); for(int i=0;i<len;i++) { f->store_real(r[i].r); f->store_real(r[i].g); f->store_real(r[i].b); f->store_real(r[i].a); } } break; default: { ERR_EXPLAIN("Invalid variant"); ERR_FAIL(); } } }
int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expression, int p_stack_level,bool p_root) { switch(p_expression->type) { //should parse variable declaration and adjust stack accordingly... case GDParser::Node::TYPE_IDENTIFIER: { //return identifier //wait, identifier could be a local variable or something else... careful here, must reference properly //as stack may be more interesting to work with //This could be made much simpler by just indexing "self", but done this way (with custom self-addressing modes) increases peformance a lot. const GDParser::IdentifierNode *in = static_cast<const GDParser::IdentifierNode*>(p_expression); StringName identifier = in->name; // TRY STACK! if (codegen.stack_identifiers.has(identifier)) { int pos = codegen.stack_identifiers[identifier]; return pos|(GDFunction::ADDR_TYPE_STACK_VARIABLE<<GDFunction::ADDR_BITS); } //TRY ARGUMENTS! if (!codegen.function_node || !codegen.function_node->_static) { // TRY MEMBER VARIABLES! //static function if (codegen.script->member_indices.has(identifier)) { int idx = codegen.script->member_indices[identifier]; return idx|(GDFunction::ADDR_TYPE_MEMBER<<GDFunction::ADDR_BITS); //argument (stack root) } } //TRY CLASS CONSTANTS GDScript *owner = codegen.script; while (owner) { GDScript *scr = owner; GDNativeClass *nc=NULL; while(scr) { if (scr->constants.has(identifier)) { //int idx=scr->constants[identifier]; int idx = codegen.get_name_map_pos(identifier); return idx|(GDFunction::ADDR_TYPE_CLASS_CONSTANT<<GDFunction::ADDR_BITS); //argument (stack root) } if (scr->native.is_valid()) nc=scr->native.ptr(); scr=scr->_base; } // CLASS C++ Integer Constant if (nc) { bool success=false; int constant = ObjectTypeDB::get_integer_constant(nc->get_name(),identifier,&success); if (success) { Variant key=constant; int idx; if (!codegen.constant_map.has(key)) { idx=codegen.constant_map.size(); codegen.constant_map[key]=idx; } else { idx=codegen.constant_map[key]; } return idx|(GDFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDFunction::ADDR_BITS); //make it a local constant (faster access) } } owner=owner->_owner; } /* handled in constants now if (codegen.script->subclasses.has(identifier)) { //same with a subclass, make it a local constant. int idx = codegen.get_constant_pos(codegen.script->subclasses[identifier]); return idx|(GDFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDFunction::ADDR_BITS); //make it a local constant (faster access) }*/ if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; return idx|(GDFunction::ADDR_TYPE_GLOBAL<<GDFunction::ADDR_BITS); //argument (stack root) } //not found, error _set_error("Identifier not found: "+String(identifier),p_expression); return -1; } break; case GDParser::Node::TYPE_CONSTANT: { //return constant const GDParser::ConstantNode *cn = static_cast<const GDParser::ConstantNode*>(p_expression); int idx; if (!codegen.constant_map.has(cn->value)) { idx=codegen.constant_map.size(); codegen.constant_map[cn->value]=idx; } else { idx=codegen.constant_map[cn->value]; } return idx|(GDFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDFunction::ADDR_BITS); //argument (stack root) } break; case GDParser::Node::TYPE_SELF: { //return constant if (codegen.function_node && codegen.function_node->_static) { _set_error("'self' not present in static function!",p_expression); return -1; } return (GDFunction::ADDR_TYPE_SELF<<GDFunction::ADDR_BITS); } break; case GDParser::Node::TYPE_ARRAY: { const GDParser::ArrayNode *an = static_cast<const GDParser::ArrayNode*>(p_expression); Vector<int> values; int slevel=p_stack_level; for(int i=0;i<an->elements.size();i++) { int ret = _parse_expression(codegen,an->elements[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } values.push_back(ret); } codegen.opcodes.push_back(GDFunction::OPCODE_CONSTRUCT_ARRAY); codegen.opcodes.push_back(values.size()); for(int i=0;i<values.size();i++) codegen.opcodes.push_back(values[i]); int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode codegen.alloc_stack(p_stack_level); return dst_addr; } break; case GDParser::Node::TYPE_DICTIONARY: { const GDParser::DictionaryNode *dn = static_cast<const GDParser::DictionaryNode*>(p_expression); Vector<int> values; int slevel=p_stack_level; for(int i=0;i<dn->elements.size();i++) { int ret = _parse_expression(codegen,dn->elements[i].key,slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } values.push_back(ret); ret = _parse_expression(codegen,dn->elements[i].value,slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } values.push_back(ret); } codegen.opcodes.push_back(GDFunction::OPCODE_CONSTRUCT_DICTIONARY); codegen.opcodes.push_back(dn->elements.size()); for(int i=0;i<values.size();i++) codegen.opcodes.push_back(values[i]); int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode codegen.alloc_stack(p_stack_level); return dst_addr; } break; case GDParser::Node::TYPE_OPERATOR: { //hell breaks loose const GDParser::OperatorNode *on = static_cast<const GDParser::OperatorNode*>(p_expression); switch(on->op) { //call/constructor operator case GDParser::OperatorNode::OP_PARENT_CALL: { ERR_FAIL_COND_V(on->arguments.size()<1,-1); const GDParser::IdentifierNode *in = (const GDParser::IdentifierNode *)on->arguments[0]; Vector<int> arguments; int slevel = p_stack_level; for(int i=1;i<on->arguments.size();i++) { int ret = _parse_expression(codegen,on->arguments[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } arguments.push_back(ret); } //push call bytecode codegen.opcodes.push_back(GDFunction::OPCODE_CALL_SELF_BASE); // basic type constructor codegen.opcodes.push_back(codegen.get_name_map_pos(in->name)); //instance codegen.opcodes.push_back(arguments.size()); //argument count codegen.alloc_call(arguments.size()); for(int i=0;i<arguments.size();i++) codegen.opcodes.push_back(arguments[i]); //arguments } break; case GDParser::OperatorNode::OP_CALL: { if (on->arguments[0]->type==GDParser::Node::TYPE_TYPE) { //construct a basic type ERR_FAIL_COND_V(on->arguments.size()<1,-1); const GDParser::TypeNode *tn = (const GDParser::TypeNode *)on->arguments[0]; int vtype = tn->vtype; Vector<int> arguments; int slevel = p_stack_level; for(int i=1;i<on->arguments.size();i++) { int ret = _parse_expression(codegen,on->arguments[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } arguments.push_back(ret); } //push call bytecode codegen.opcodes.push_back(GDFunction::OPCODE_CONSTRUCT); // basic type constructor codegen.opcodes.push_back(vtype); //instance codegen.opcodes.push_back(arguments.size()); //argument count codegen.alloc_call(arguments.size()); for(int i=0;i<arguments.size();i++) codegen.opcodes.push_back(arguments[i]); //arguments } else if (on->arguments[0]->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) { //built in function ERR_FAIL_COND_V(on->arguments.size()<1,-1); Vector<int> arguments; int slevel = p_stack_level; for(int i=1;i<on->arguments.size();i++) { int ret = _parse_expression(codegen,on->arguments[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } arguments.push_back(ret); } codegen.opcodes.push_back(GDFunction::OPCODE_CALL_BUILT_IN); codegen.opcodes.push_back(static_cast<const GDParser::BuiltInFunctionNode*>(on->arguments[0])->function); codegen.opcodes.push_back(on->arguments.size()-1); codegen.alloc_call(on->arguments.size()-1); for(int i=0;i<arguments.size();i++) codegen.opcodes.push_back(arguments[i]); } else { //regular function ERR_FAIL_COND_V(on->arguments.size()<2,-1); const GDParser::Node *instance = on->arguments[0]; bool in_static=false; if (instance->type==GDParser::Node::TYPE_SELF) { //room for optimization } Vector<int> arguments; int slevel = p_stack_level; for(int i=0;i<on->arguments.size();i++) { int ret; if (i==0 && on->arguments[i]->type==GDParser::Node::TYPE_SELF && codegen.function_node && codegen.function_node->_static) { //static call to self ret=(GDFunction::ADDR_TYPE_CLASS<<GDFunction::ADDR_BITS); } else if (i==1) { if (on->arguments[i]->type!=GDParser::Node::TYPE_IDENTIFIER) { _set_error("Attempt to call a non-identifier.",on); return -1; } GDParser::IdentifierNode *id = static_cast<GDParser::IdentifierNode*>(on->arguments[i]); ret=codegen.get_name_map_pos(id->name); } else { ret = _parse_expression(codegen,on->arguments[i],slevel); if (ret<0) return ret; if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } } arguments.push_back(ret); } codegen.opcodes.push_back(p_root?GDFunction::OPCODE_CALL:GDFunction::OPCODE_CALL_RETURN); // perform operator codegen.opcodes.push_back(on->arguments.size()-2); codegen.alloc_call(on->arguments.size()-2); for(int i=0;i<arguments.size();i++) codegen.opcodes.push_back(arguments[i]); } } break; //indexing operator case GDParser::OperatorNode::OP_INDEX: case GDParser::OperatorNode::OP_INDEX_NAMED: { ERR_FAIL_COND_V(on->arguments.size()!=2,-1); int slevel = p_stack_level; bool named=(on->op==GDParser::OperatorNode::OP_INDEX_NAMED); int from = _parse_expression(codegen,on->arguments[0],slevel); if (from<0) return from; int index; if (named) { index=codegen.get_name_map_pos(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name); } else { if (on->arguments[1]->type==GDParser::Node::TYPE_CONSTANT && static_cast<const GDParser::ConstantNode*>(on->arguments[1])->value.get_type()==Variant::STRING) { //also, somehow, named (speed up anyway) StringName name = static_cast<const GDParser::ConstantNode*>(on->arguments[1])->value; index=codegen.get_name_map_pos(name); named=true; } else { //regular indexing if (from&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } index = _parse_expression(codegen,on->arguments[1],slevel); if (index<0) return index; } } codegen.opcodes.push_back(named?GDFunction::OPCODE_GET_NAMED:GDFunction::OPCODE_GET); // perform operator codegen.opcodes.push_back(from); // argument 1 codegen.opcodes.push_back(index); // argument 2 (unary only takes one parameter) } break; case GDParser::OperatorNode::OP_AND: { // AND operator with early out on failure int res = _parse_expression(codegen,on->arguments[0],p_stack_level); if (res<0) return res; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(res); int jump_fail_pos=codegen.opcodes.size(); codegen.opcodes.push_back(0); res = _parse_expression(codegen,on->arguments[1],p_stack_level); if (res<0) return res; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(res); int jump_fail_pos2=codegen.opcodes.size(); codegen.opcodes.push_back(0); codegen.alloc_stack(p_stack_level); //it will be used.. codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_TRUE); codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(codegen.opcodes.size()+3); codegen.opcodes[jump_fail_pos]=codegen.opcodes.size(); codegen.opcodes[jump_fail_pos2]=codegen.opcodes.size(); codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_FALSE); codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); return p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS; } break; case GDParser::OperatorNode::OP_OR: { // OR operator with early out on success int res = _parse_expression(codegen,on->arguments[0],p_stack_level); if (res<0) return res; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF); codegen.opcodes.push_back(res); int jump_success_pos=codegen.opcodes.size(); codegen.opcodes.push_back(0); res = _parse_expression(codegen,on->arguments[1],p_stack_level); if (res<0) return res; codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF); codegen.opcodes.push_back(res); int jump_success_pos2=codegen.opcodes.size(); codegen.opcodes.push_back(0); codegen.alloc_stack(p_stack_level); //it will be used.. codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_FALSE); codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); codegen.opcodes.push_back(codegen.opcodes.size()+3); codegen.opcodes[jump_success_pos]=codegen.opcodes.size(); codegen.opcodes[jump_success_pos2]=codegen.opcodes.size(); codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_TRUE); codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); return p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS; } break; //unary operators case GDParser::OperatorNode::OP_NEG: { if (!_create_unary_operator(codegen,on,Variant::OP_NEGATE,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_NOT: { if (!_create_unary_operator(codegen,on,Variant::OP_NOT,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_BIT_INVERT: { if (!_create_unary_operator(codegen,on,Variant::OP_BIT_NEGATE,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_PREINC: { } break; //? case GDParser::OperatorNode::OP_PREDEC: { } break; case GDParser::OperatorNode::OP_INC: { } break; case GDParser::OperatorNode::OP_DEC: { } break; //binary operators (in precedence order) case GDParser::OperatorNode::OP_IN: { if (!_create_binary_operator(codegen,on,Variant::OP_IN,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_EQUAL,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_NOT_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_NOT_EQUAL,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_LESS: { if (!_create_binary_operator(codegen,on,Variant::OP_LESS,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_LESS_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_LESS_EQUAL,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_GREATER: { if (!_create_binary_operator(codegen,on,Variant::OP_GREATER,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_GREATER_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_GREATER_EQUAL,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_ADD: { if (!_create_binary_operator(codegen,on,Variant::OP_ADD,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_SUB: { if (!_create_binary_operator(codegen,on,Variant::OP_SUBSTRACT,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_MUL: { if (!_create_binary_operator(codegen,on,Variant::OP_MULTIPLY,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_DIV: { if (!_create_binary_operator(codegen,on,Variant::OP_DIVIDE,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_MOD: { if (!_create_binary_operator(codegen,on,Variant::OP_MODULE,p_stack_level)) return -1;} break; //case GDParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break; //case GDParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_BIT_AND: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_AND,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_BIT_OR: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_OR,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_BIT_XOR: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_XOR,p_stack_level)) return -1;} break; //shift case GDParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break; case GDParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break; //assignment operators case GDParser::OperatorNode::OP_ASSIGN_ADD: case GDParser::OperatorNode::OP_ASSIGN_SUB: case GDParser::OperatorNode::OP_ASSIGN_MUL: case GDParser::OperatorNode::OP_ASSIGN_DIV: case GDParser::OperatorNode::OP_ASSIGN_MOD: case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: case GDParser::OperatorNode::OP_ASSIGN: { ERR_FAIL_COND_V(on->arguments.size()!=2,-1); 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!! int slevel=p_stack_level; GDParser::OperatorNode* op = static_cast<GDParser::OperatorNode*>(on->arguments[0]); /* Find chain of sets */ List<GDParser::OperatorNode*> chain; { //create get/set chain GDParser::OperatorNode* n=op; while(true) { chain.push_back(n); if (n->arguments[0]->type!=GDParser::Node::TYPE_OPERATOR) break; n = static_cast<GDParser::OperatorNode*>(n->arguments[0]); if (n->op!=GDParser::OperatorNode::OP_INDEX && n->op!=GDParser::OperatorNode::OP_INDEX_NAMED) break; } } /* Chain of gets */ //get at (potential) root stack pos, so it can be returned int prev_pos = _parse_expression(codegen,chain.back()->get()->arguments[0],slevel); if (prev_pos<0) return prev_pos; int retval=prev_pos; if (retval&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } Vector<int> setchain; for(List<GDParser::OperatorNode*>::Element *E=chain.back();E;E=E->prev()) { if (E==chain.front()) //ignore first break; bool named = E->get()->op==GDParser::OperatorNode::OP_INDEX_NAMED; int key_idx; if (named) { key_idx = codegen.get_name_map_pos(static_cast<const GDParser::IdentifierNode*>(E->get()->arguments[1])->name); } else { GDParser::Node *key = E->get()->arguments[1]; key_idx = _parse_expression(codegen,key,slevel); if (retval&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } } if (key_idx<0) return key_idx; codegen.opcodes.push_back(named ? GDFunction::OPCODE_GET_NAMED : GDFunction::OPCODE_GET); codegen.opcodes.push_back(prev_pos); codegen.opcodes.push_back(key_idx); slevel++; codegen.alloc_stack(slevel); int dst_pos = (GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)|slevel; codegen.opcodes.push_back(dst_pos); //add in reverse order, since it will be reverted setchain.push_back(dst_pos); setchain.push_back(key_idx); setchain.push_back(prev_pos); setchain.push_back(named ? GDFunction::OPCODE_SET_NAMED : GDFunction::OPCODE_SET); prev_pos=dst_pos; } setchain.invert(); int set_index; bool named=false; if (static_cast<const GDParser::OperatorNode*>(op)->op==GDParser::OperatorNode::OP_INDEX_NAMED) { set_index=codegen.get_name_map_pos(static_cast<const GDParser::IdentifierNode*>(op->arguments[1])->name); named=true; } else { set_index = _parse_expression(codegen,op->arguments[1],slevel+1); named=false; } if (set_index<0) return set_index; if (set_index&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } int set_value = _parse_assign_right_expression(codegen,on,slevel+1); if (set_value<0) return set_value; codegen.opcodes.push_back(named?GDFunction::OPCODE_SET_NAMED:GDFunction::OPCODE_SET); codegen.opcodes.push_back(prev_pos); codegen.opcodes.push_back(set_index); codegen.opcodes.push_back(set_value); for(int i=0;i<setchain.size();i+=4) { codegen.opcodes.push_back(setchain[i+0]); codegen.opcodes.push_back(setchain[i+1]); codegen.opcodes.push_back(setchain[i+2]); codegen.opcodes.push_back(setchain[i+3]); } return retval; } else { //ASSIGNMENT MODE!! int slevel = p_stack_level; int dst_address_a = _parse_expression(codegen,on->arguments[0],slevel); if (dst_address_a<0) return -1; if (dst_address_a&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); } int src_address_b = _parse_assign_right_expression(codegen,on,slevel); if (src_address_b<0) return -1; codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN); // perform operator codegen.opcodes.push_back(dst_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) return dst_address_a; //if anything, returns wathever was assigned or correct stack position } } break; case GDParser::OperatorNode::OP_EXTENDS: { ERR_FAIL_COND_V(on->arguments.size()!=2,false); int slevel = p_stack_level; int src_address_a = _parse_expression(codegen,on->arguments[0],slevel); if (src_address_a<0) return -1; if (src_address_a&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) slevel++; //uses stack for return, increase stack int src_address_b = _parse_expression(codegen,on->arguments[1],slevel); if (src_address_b<0) return -1; codegen.opcodes.push_back(GDFunction::OPCODE_EXTENDS_TEST); // perform operator codegen.opcodes.push_back(src_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) } break; default: { ERR_EXPLAIN("Bug in bytecode compiler, unexpected operator #"+itos(on->op)+" in parse tree while parsing expression."); ERR_FAIL_V(0); //unreachable code } break; } int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode codegen.alloc_stack(p_stack_level); return dst_addr; } break; //TYPE_TYPE, default: { ERR_EXPLAIN("Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); ERR_FAIL_V(-1); //unreachable code } break; } ERR_FAIL_V(-1); //unreachable code }