Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;

}
Example #6
0
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;

}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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();
	}

}
Example #11
0
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;
}
Example #12
0
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;

}
Example #13
0
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;
Example #15
0
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;
}
Example #16
0
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

}
Example #17
0
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();
}
Example #18
0
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);
	}
}
Example #20
0
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;
	}
Example #21
0
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;
}
Example #22
0
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);
}
Example #24
0
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;
}
Example #25
0
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;

}
Example #26
0
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;
}
Example #27
0
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;
}
Example #28
0
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;
}
Example #29
0
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();
		}
	}
}
Example #30
0
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
}