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 OK;
	}

	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;

}
Exemple #2
0
Error PoolAllocator::resize(ID p_mem,int p_new_size) {

	mt_lock();
	Entry *e=get_entry(p_mem);

	if (!e) {
		mt_unlock();
		ERR_FAIL_COND_V(!e,ERR_INVALID_PARAMETER);
	}

	if (needs_locking && e->lock) {
		mt_unlock();
		ERR_FAIL_COND_V(e->lock,ERR_ALREADY_IN_USE);
	}

	int alloc_size = aligned(p_new_size);

	if (aligned(e->len)==alloc_size) {

		e->len=p_new_size;
		mt_unlock();
		return OK;
	} else if (e->len>(uint32_t)p_new_size) {

		free_mem += aligned(e->len);
		free_mem -= alloc_size;
		e->len=p_new_size;
		mt_unlock();
		return OK;
	}

	//p_new_size = align(p_new_size)
	int _total = pool_size; // - static_area_size;
	int _free = free_mem; // - static_area_size;

	if ((_free + aligned(e->len)) - alloc_size < 0) {
		mt_unlock();
		ERR_FAIL_V( ERR_OUT_OF_MEMORY );
	};

	EntryIndicesPos entry_indices_pos;

	bool index_found = find_entry_index(&entry_indices_pos,e);

	if (!index_found) {

		mt_unlock();
		ERR_FAIL_COND_V(!index_found,ERR_BUG);
	}

	//no need to move stuff around, it fits before the next block
	int next_pos;
	if (entry_indices_pos+1 == entry_count) {
		next_pos = pool_size; // - static_area_size;
	} else {
		next_pos = entry_array[entry_indices[entry_indices_pos+1]].pos;
	};

	if ((next_pos - e->pos) > alloc_size) {
		free_mem+=aligned(e->len);
		e->len=p_new_size;
		free_mem-=alloc_size;
		mt_unlock();
		return OK;
	}
	//it doesn't fit, compact around BEFORE current index (make room behind)

	compact(entry_indices_pos+1);


	if ((next_pos - e->pos) > alloc_size) {
		//now fits! hooray!
		free_mem+=aligned(e->len);
		e->len=p_new_size;
		free_mem-=alloc_size;
		mt_unlock();
		if (free_mem<free_mem_peak)
			free_mem_peak=free_mem;
		return OK;
	}

	//STILL doesn't fit, compact around AFTER current index (make room after)

	compact_up(entry_indices_pos+1);

	if ((entry_array[entry_indices[entry_indices_pos+1]].pos - e->pos) > alloc_size) {
		//now fits! hooray!
		free_mem+=aligned(e->len);
		e->len=p_new_size;
		free_mem-=alloc_size;
		mt_unlock();
		if (free_mem<free_mem_peak)
			free_mem_peak=free_mem;
		return OK;
	}

	mt_unlock();
	ERR_FAIL_V(ERR_OUT_OF_MEMORY);

}
Exemple #3
0
bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set<RID>& p_exclude,uint32_t p_user_mask) {


	ERR_FAIL_COND_V(space->locked,false);

	Vector2 begin,end;
	Vector2 normal;
	begin=p_from;
	end=p_to;
	normal=(end-begin).normalized();

	int amount = space->broadphase->cull_segment(begin,end,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);

	//todo, create another array tha references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision

	bool collided=false;
	Vector2 res_point,res_normal;
	int res_shape;
	const CollisionObject2DSW *res_obj;
	real_t min_d=1e10;


	for(int i=0;i<amount;i++) {

		if (space->intersection_query_results[i]->get_type()==CollisionObject2DSW::TYPE_AREA)
			continue; //ignore area

		if (p_exclude.has( space->intersection_query_results[i]->get_self()))
			continue;

		const CollisionObject2DSW *col_obj=space->intersection_query_results[i];

		int shape_idx=space->intersection_query_subindex_results[i];
		Matrix32 inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform();

		Vector2 local_from = inv_xform.xform(begin);
		Vector2 local_to = inv_xform.xform(end);

		/*local_from = col_obj->get_inv_transform().xform(begin);
		local_from = col_obj->get_shape_inv_transform(shape_idx).xform(local_from);

		local_to = col_obj->get_inv_transform().xform(end);
		local_to = col_obj->get_shape_inv_transform(shape_idx).xform(local_to);*/

		const Shape2DSW *shape = col_obj->get_shape(shape_idx);

		Vector2 shape_point,shape_normal;


		if (shape->intersect_segment(local_from,local_to,shape_point,shape_normal)) {


			//print_line("inters sgment!");
			Matrix32 xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
			shape_point=xform.xform(shape_point);

			real_t ld = normal.dot(shape_point);


			if (ld<min_d) {

				min_d=ld;
				res_point=shape_point;
				res_normal=inv_xform.basis_xform_inv(shape_normal).normalized();
				res_shape=shape_idx;
				res_obj=col_obj;
				collided=true;
			}
		}

	}

	if (!collided)
		return false;


	r_result.collider_id=res_obj->get_instance_id();
	if (r_result.collider_id!=0)
		r_result.collider=ObjectDB::get_instance(r_result.collider_id);
	r_result.normal=res_normal;
	r_result.position=res_point;
	r_result.rid=res_obj->get_self();
	r_result.shape=res_shape;

	return true;

}
Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &texture,int format, float quality,int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,float shrink)  {


	if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) {

		Image image=texture->get_data();
		ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA);

		bool has_alpha=image.detect_alpha();
		if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) {

			image.convert(Image::FORMAT_RGB);

		}

		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) {

			image.fix_alpha_edges();
		}

		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {

			image.premultiply_alpha();
		}

		if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
			image.normalmap_to_xy();
		}

		//if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {

		//	image.srgb_to_linear();
		//}

		if (shrink>1) {

			int orig_w=image.get_width();
			int orig_h=image.get_height();
			image.resize(orig_w/shrink,orig_h/shrink,Image::INTERPOLATE_CUBIC);
			texture->create_from_image(image,tex_flags);
			texture->set_size_override(Size2(orig_w,orig_h));


		} else {

			texture->create_from_image(image,tex_flags);
		}


		if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS) {
			texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSLESS);
		} else {
			texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
		}



		texture->set_lossy_storage_quality(quality);


	} else {


		Image image=texture->get_data();
		ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA);


		bool has_alpha=image.detect_alpha();
		if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) {

			image.convert(Image::FORMAT_RGB);

		}

		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) {

			image.fix_alpha_edges();
		}

		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {

			image.premultiply_alpha();
		}

		if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
			image.normalmap_to_xy();
		}

		//if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
//
		//	print_line("CONVERT BECAUSE: "+itos(flags));
		//	image.srgb_to_linear();
		//}

		int orig_w=image.get_width();
		int orig_h=image.get_height();

		if (shrink>1) {
			image.resize(orig_w/shrink,orig_h/shrink,Image::INTERPOLATE_CUBIC);
			texture->create_from_image(image,tex_flags);
			texture->set_size_override(Size2(orig_w,orig_h));
		}

		if (!(flags&IMAGE_FLAG_NO_MIPMAPS)) {
			image.generate_mipmaps();

		}

		if (format!=IMAGE_FORMAT_UNCOMPRESSED) {

			compress_image(p_compr,image,flags&IMAGE_FLAG_COMPRESS_EXTRA);
		}


		texture->create_from_image(image,tex_flags);


		if (shrink>1 || (format!=IMAGE_FORMAT_UNCOMPRESSED && (image.get_width()!=orig_w || image.get_height()!=orig_h))) {
			texture->set_size_override(Size2(orig_w,orig_h));
		}

		//uint32_t save_flags=ResourceSaver::FLAG_COMPRESS;
	}

	return OK;
}
Exemple #5
0
Transform2D Camera2D::get_camera_transform() {

	if (!get_tree())
		return Transform2D();

	ERR_FAIL_COND_V(custom_viewport && !ObjectDB::get_instance(custom_viewport_id), Transform2D());

	Size2 screen_size = viewport->get_visible_rect().size;

	Point2 new_camera_pos = get_global_transform().get_origin();
	Point2 ret_camera_pos;

	if (!first) {

		if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) {

			if (h_drag_enabled && !Engine::get_singleton()->is_editor_hint()) {
				camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT]));
				camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_LEFT]));
			} else {

				if (h_ofs < 0) {
					camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs;
				} else {
					camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs;
				}
			}

			if (v_drag_enabled && !Engine::get_singleton()->is_editor_hint()) {

				camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM]));
				camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_TOP]));

			} else {

				if (v_ofs < 0) {
					camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs;
				} else {
					camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs;
				}
			}

		} else if (anchor_mode == ANCHOR_MODE_FIXED_TOP_LEFT) {

			camera_pos = new_camera_pos;
		}

		Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2());
		Rect2 screen_rect(-screen_offset + camera_pos, screen_size * zoom);

		if (offset != Vector2())
			screen_rect.position += offset;

		if (limit_smoothing_enabled) {
			if (screen_rect.position.x < limit[MARGIN_LEFT])
				camera_pos.x -= screen_rect.position.x - limit[MARGIN_LEFT];

			if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT])
				camera_pos.x -= screen_rect.position.x + screen_rect.size.x - limit[MARGIN_RIGHT];

			if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM])
				camera_pos.y -= screen_rect.position.y + screen_rect.size.y - limit[MARGIN_BOTTOM];

			if (screen_rect.position.y < limit[MARGIN_TOP])
				camera_pos.y -= screen_rect.position.y - limit[MARGIN_TOP];
		}

		if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {

			float c = smoothing * get_fixed_process_delta_time();
			smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos;
			ret_camera_pos = smoothed_camera_pos;
			//camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
		} else {

			ret_camera_pos = smoothed_camera_pos = camera_pos;
		}

	} else {
		ret_camera_pos = smoothed_camera_pos = camera_pos = new_camera_pos;
		first = false;
	}

	Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2());

	float angle = get_global_transform().get_rotation();
	if (rotating) {
		screen_offset = screen_offset.rotated(angle);
	}

	Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom);
	if (screen_rect.position.x < limit[MARGIN_LEFT])
		screen_rect.position.x = limit[MARGIN_LEFT];

	if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT])
		screen_rect.position.x = limit[MARGIN_RIGHT] - screen_rect.size.x;

	if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM])
		screen_rect.position.y = limit[MARGIN_BOTTOM] - screen_rect.size.y;

	if (screen_rect.position.y < limit[MARGIN_TOP])
		screen_rect.position.y = limit[MARGIN_TOP];

	if (offset != Vector2()) {

		screen_rect.position += offset;
		if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT])
			screen_rect.position.x = limit[MARGIN_RIGHT] - screen_rect.size.x;

		if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM])
			screen_rect.position.y = limit[MARGIN_BOTTOM] - screen_rect.size.y;

		if (screen_rect.position.x < limit[MARGIN_LEFT])
			screen_rect.position.x = limit[MARGIN_LEFT];

		if (screen_rect.position.y < limit[MARGIN_TOP])
			screen_rect.position.y = limit[MARGIN_TOP];
	}

	camera_screen_center = screen_rect.position + screen_rect.size * 0.5;

	Transform2D xform;
	if (rotating) {
		xform.set_rotation(angle);
	}
	xform.scale_basis(zoom);
	xform.set_origin(screen_rect.position /*.floor()*/);

	/*
	if (0) {
		xform = get_global_transform() * xform;
	} else {
		xform.elements[2]+=get_global_transform().get_origin();
	}
*/

	return (xform).affine_inverse();
}
Exemple #6
0
Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const PoolVector<uint8_t> &p_body) {

	ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
	ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER);
	ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
	ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA);

	String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n";
	if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
		// Don't append the standard ports
		request += "Host: " + conn_host + "\r\n";
	} else {
		request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
	}
	bool add_clen = p_body.size() > 0;
	bool add_uagent = true;
	bool add_accept = true;
	for (int i = 0; i < p_headers.size(); i++) {
		request += p_headers[i] + "\r\n";
		if (add_clen && p_headers[i].findn("Content-Length:") == 0) {
			add_clen = false;
		}
		if (add_uagent && p_headers[i].findn("User-Agent:") == 0) {
			add_uagent = false;
		}
		if (add_accept && p_headers[i].findn("Accept:") == 0) {
			add_accept = false;
		}
	}
	if (add_clen) {
		request += "Content-Length: " + itos(p_body.size()) + "\r\n";
		// Should it add utf8 encoding?
	}
	if (add_uagent) {
		request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n";
	}
	if (add_accept) {
		request += "Accept: */*\r\n";
	}
	request += "\r\n";
	CharString cs = request.utf8();

	PoolVector<uint8_t> data;
	data.resize(cs.length());
	{
		PoolVector<uint8_t>::Write data_write = data.write();
		for (int i = 0; i < cs.length(); i++) {
			data_write[i] = cs[i];
		}
	}

	data.append_array(p_body);

	PoolVector<uint8_t>::Read r = data.read();
	Error err = connection->put_data(&r[0], data.size());

	if (err) {
		close();
		status = STATUS_CONNECTION_ERROR;
		return err;
	}

	status = STATUS_REQUESTING;

	return OK;
}
Exemple #7
0
PoolByteArray HTTPClient::read_response_body_chunk() {

	ERR_FAIL_COND_V(status != STATUS_BODY, PoolByteArray());

	Error err = OK;

	if (chunked) {

		while (true) {

			if (chunk_left == 0) {
				// Reading length
				uint8_t b;
				int rec = 0;
				err = _get_http_data(&b, 1, rec);

				if (rec == 0)
					break;

				chunk.push_back(b);

				if (chunk.size() > 32) {
					ERR_PRINT("HTTP Invalid chunk hex len");
					status = STATUS_CONNECTION_ERROR;
					return PoolByteArray();
				}

				if (chunk.size() > 2 && chunk[chunk.size() - 2] == '\r' && chunk[chunk.size() - 1] == '\n') {

					int len = 0;
					for (int i = 0; i < chunk.size() - 2; i++) {
						char c = chunk[i];
						int v = 0;
						if (c >= '0' && c <= '9')
							v = c - '0';
						else if (c >= 'a' && c <= 'f')
							v = c - 'a' + 10;
						else if (c >= 'A' && c <= 'F')
							v = c - 'A' + 10;
						else {
							ERR_PRINT("HTTP Chunk len not in hex!!");
							status = STATUS_CONNECTION_ERROR;
							return PoolByteArray();
						}
						len <<= 4;
						len |= v;
						if (len > (1 << 24)) {
							ERR_PRINT("HTTP Chunk too big!! >16mb");
							status = STATUS_CONNECTION_ERROR;
							return PoolByteArray();
						}
					}

					if (len == 0) {
						// End reached!
						status = STATUS_CONNECTED;
						chunk.clear();
						return PoolByteArray();
					}

					chunk_left = len + 2;
					chunk.resize(chunk_left);
				}
			} else {

				int rec = 0;
				err = _get_http_data(&chunk.write[chunk.size() - chunk_left], chunk_left, rec);
				if (rec == 0) {
					break;
				}
				chunk_left -= rec;

				if (chunk_left == 0) {

					if (chunk[chunk.size() - 2] != '\r' || chunk[chunk.size() - 1] != '\n') {
						ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)");
						status = STATUS_CONNECTION_ERROR;
						return PoolByteArray();
					}

					PoolByteArray ret;
					ret.resize(chunk.size() - 2);
					{
						PoolByteArray::Write w = ret.write();
						copymem(w.ptr(), chunk.ptr(), chunk.size() - 2);
					}
					chunk.clear();

					return ret;
				}

				break;
			}
		}

	} else {

		int to_read = !read_until_eof ? MIN(body_left, read_chunk_size) : read_chunk_size;
		PoolByteArray ret;
		ret.resize(to_read);
		int _offset = 0;
		while (read_until_eof || to_read > 0) {
			int rec = 0;
			{
				PoolByteArray::Write w = ret.write();
				err = _get_http_data(w.ptr() + _offset, to_read, rec);
			}
			if (rec < 0) {
				if (to_read > 0) // Ended up reading less
					ret.resize(_offset);
				break;
			} else {
				_offset += rec;
				if (!read_until_eof) {
					body_left -= rec;
					to_read -= rec;
				} else {
					if (rec < to_read) {
						ret.resize(_offset);
						err = ERR_FILE_EOF;
						break;
					}
					ret.resize(_offset + to_read);
				}
			}
		}
		if (!read_until_eof) {
			if (body_left == 0) {
				status = STATUS_CONNECTED;
			}
			return ret;
		} else {
			if (err == ERR_FILE_EOF) {
				err = OK; // EOF is expected here
				close();
				return ret;
			}
		}
	}

	if (err != OK) {

		close();

		if (err == ERR_FILE_EOF) {

			status = STATUS_DISCONNECTED; // Server disconnected
		} else {

			status = STATUS_CONNECTION_ERROR;
		}
	} else if (body_left == 0 && !chunked) {

		status = STATUS_CONNECTED;
	}

	return PoolByteArray();
}
Exemple #8
0
Variant Object::get_meta(const String& p_name) const {

	ERR_FAIL_COND_V(!metadata.has(p_name),Variant());
	return metadata[p_name];
}
Exemple #9
0
Mutex *Mutex::create(bool p_recursive) {

	ERR_FAIL_COND_V( !create_func, 0 );

	return create_func(p_recursive);
}
Exemple #10
0
Array VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channel, Vector3i min, Vector3i max) {
	uint64_t time_before = OS::get_singleton()->get_ticks_usec();

	ERR_FAIL_COND_V(_library.is_null(), Array());
	ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Array());

	const VoxelLibrary &library = **_library;

	for (unsigned int i = 0; i < MAX_MATERIALS; ++i) {
		Arrays &a = _arrays[i];
		a.positions.clear();
		a.normals.clear();
		a.uvs.clear();
		a.colors.clear();
		a.indices.clear();
	}

	float baked_occlusion_darkness;
	if (_bake_occlusion)
		baked_occlusion_darkness = _baked_occlusion_darkness / 3.0;

	// The technique is Culled faces.
	// Could be improved with greedy meshing: https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/
	// However I don't feel it's worth it yet:
	// - Not so much gain for organic worlds with lots of texture variations
	// - Works well with cubes but not with any shape
	// - Slower
	// => Could be implemented in a separate class?

	// Data must be padded, hence the off-by-one
	Vector3i::sort_min_max(min, max);
	const Vector3i pad(1, 1, 1);
	min.clamp_to(pad, max);
	max.clamp_to(min, buffer.get_size() - pad);

	int index_offset = 0;

	// Iterate 3D padded data to extract voxel faces.
	// This is the most intensive job in this class, so all required data should be as fit as possible.

	// The buffer we receive MUST be dense (i.e not compressed, and channels allocated).
	// That means we can use raw pointers to voxel data inside instead of using the higher-level getters,
	// and then save a lot of time.

	uint8_t *type_buffer = buffer.get_channel_raw(Voxel::CHANNEL_TYPE);
	//       _
	//      | \
	//     /\ \\
	//    / /|\\\
	//    | |\ \\\
	//    | \_\ \\|
	//    |    |  )
	//     \   |  |
	//      \    /
	CRASH_COND(type_buffer == NULL);


	//CRASH_COND(memarr_len(type_buffer) != buffer.get_volume() * sizeof(uint8_t));

	// Build lookup tables so to speed up voxel access.
	// These are values to add to an address in order to get given neighbor.

	int row_size = buffer.get_size().y;
	int deck_size = buffer.get_size().x * row_size;

	int side_neighbor_lut[Cube::SIDE_COUNT];
	side_neighbor_lut[Cube::SIDE_LEFT] = row_size;
	side_neighbor_lut[Cube::SIDE_RIGHT] = -row_size;
	side_neighbor_lut[Cube::SIDE_BACK] = -deck_size;
	side_neighbor_lut[Cube::SIDE_FRONT] = deck_size;
	side_neighbor_lut[Cube::SIDE_BOTTOM] = -1;
	side_neighbor_lut[Cube::SIDE_TOP] = 1;

	int edge_neighbor_lut[Cube::EDGE_COUNT];
	edge_neighbor_lut[Cube::EDGE_BOTTOM_BACK] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK];
	edge_neighbor_lut[Cube::EDGE_BOTTOM_FRONT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT];
	edge_neighbor_lut[Cube::EDGE_BOTTOM_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_LEFT];
	edge_neighbor_lut[Cube::EDGE_BOTTOM_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_RIGHT];
	edge_neighbor_lut[Cube::EDGE_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT];
	edge_neighbor_lut[Cube::EDGE_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT];
	edge_neighbor_lut[Cube::EDGE_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT];
	edge_neighbor_lut[Cube::EDGE_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT];
	edge_neighbor_lut[Cube::EDGE_TOP_BACK] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK];
	edge_neighbor_lut[Cube::EDGE_TOP_FRONT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT];
	edge_neighbor_lut[Cube::EDGE_TOP_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_LEFT];
	edge_neighbor_lut[Cube::EDGE_TOP_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_RIGHT];

	int corner_neighbor_lut[Cube::CORNER_COUNT];
	corner_neighbor_lut[Cube::CORNER_BOTTOM_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT];
	corner_neighbor_lut[Cube::CORNER_BOTTOM_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT];
	corner_neighbor_lut[Cube::CORNER_BOTTOM_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT];
	corner_neighbor_lut[Cube::CORNER_BOTTOM_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT];
	corner_neighbor_lut[Cube::CORNER_TOP_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT];
	corner_neighbor_lut[Cube::CORNER_TOP_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT];
	corner_neighbor_lut[Cube::CORNER_TOP_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT];
	corner_neighbor_lut[Cube::CORNER_TOP_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT];

	uint64_t time_prep = OS::get_singleton()->get_ticks_usec() - time_before;
	time_before = OS::get_singleton()->get_ticks_usec();

	for (unsigned int z = min.z; z < max.z; ++z) {
		for (unsigned int x = min.x; x < max.x; ++x) {
			for (unsigned int y = min.y; y < max.y; ++y) {
				// min and max are chosen such that you can visit 1 neighbor away from the current voxel without size check

				// TODO In this intensive routine, there is a way to make voxel access fastest by getting a pointer to the channel,
				// and using offset lookup to get neighbors rather than going through get_voxel validations
				int voxel_index = y + x * row_size + z * deck_size;
				int voxel_id = type_buffer[voxel_index];

				if (voxel_id != 0 && library.has_voxel(voxel_id)) {

					const Voxel &voxel = library.get_voxel_const(voxel_id);

					Arrays &arrays = _arrays[voxel.get_material_id()];

					// Hybrid approach: extract cube faces and decimate those that aren't visible,
					// and still allow voxels to have geometry that is not a cube

					// Sides
					for (unsigned int side = 0; side < Cube::SIDE_COUNT; ++side) {

						const PoolVector<Vector3> &positions = voxel.get_model_side_positions(side);
						int vertex_count = positions.size();

						if (vertex_count != 0) {

							int neighbor_voxel_id = type_buffer[voxel_index + side_neighbor_lut[side]];

							// TODO Better face visibility test
							if (is_face_visible(library, voxel, neighbor_voxel_id)) {

								// The face is visible

								int shaded_corner[8] = { 0 };

								if (_bake_occlusion) {

									// Combinatory solution for https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/

									for (unsigned int j = 0; j < 4; ++j) {
										unsigned int edge = Cube::g_side_edges[side][j];
										int edge_neighbor_id = type_buffer[voxel_index + edge_neighbor_lut[edge]];
										if (!is_transparent(library, edge_neighbor_id)) {
											shaded_corner[Cube::g_edge_corners[edge][0]] += 1;
											shaded_corner[Cube::g_edge_corners[edge][1]] += 1;
										}
									}
									for (unsigned int j = 0; j < 4; ++j) {
										unsigned int corner = Cube::g_side_corners[side][j];
										if (shaded_corner[corner] == 2) {
											shaded_corner[corner] = 3;
										} else {
											int corner_neigbor_id = type_buffer[voxel_index + corner_neighbor_lut[corner]];
											if (!is_transparent(library, corner_neigbor_id)) {
												shaded_corner[corner] += 1;
											}
										}
									}
								}

								PoolVector<Vector3>::Read rv = positions.read();
								PoolVector<Vector2>::Read rt = voxel.get_model_side_uv(side).read();

								// Subtracting 1 because the data is padded
								Vector3 pos(x - 1, y - 1, z - 1);

								// Append vertices of the faces in one go, don't use push_back

								{
									int append_index = arrays.positions.size();
									arrays.positions.resize(arrays.positions.size() + vertex_count);
									Vector3 *w = arrays.positions.ptrw() + append_index;
									for (unsigned int i = 0; i < vertex_count; ++i) {
										w[i] = rv[i] + pos;
									}
								}

								{
									int append_index = arrays.uvs.size();
									arrays.uvs.resize(arrays.uvs.size() + vertex_count);
									memcpy(arrays.uvs.ptrw() + append_index, rt.ptr(), vertex_count * sizeof(Vector2));
								}

								{
									int append_index = arrays.normals.size();
									arrays.normals.resize(arrays.normals.size() + vertex_count);
									Vector3 *w = arrays.normals.ptrw() + append_index;
									for (unsigned int i = 0; i < vertex_count; ++i) {
										w[i] = Cube::g_side_normals[side].to_vec3();
									}
								}

								if (_bake_occlusion) {
									// Use color array

									int append_index = arrays.colors.size();
									arrays.colors.resize(arrays.colors.size() + vertex_count);
									Color *w = arrays.colors.ptrw() + append_index;

									for (unsigned int i = 0; i < vertex_count; ++i) {
										Vector3 v = rv[i];

										// General purpose occlusion colouring.
										// TODO Optimize for cubes
										// TODO Fix occlusion inconsistency caused by triangles orientation? Not sure if worth it
										float shade = 0;
										for (unsigned int j = 0; j < 4; ++j) {
											unsigned int corner = Cube::g_side_corners[side][j];
											if (shaded_corner[corner]) {
												float s = baked_occlusion_darkness * static_cast<float>(shaded_corner[corner]);
												float k = 1.0 - Cube::g_corner_position[corner].distance_to(v);
												if (k < 0.0)
													k = 0.0;
												s *= k;
												if (s > shade)
													shade = s;
											}
										}
										float gs = 1.0 - shade;
										w[i] = Color(gs, gs, gs);
									}
								}

								const PoolVector<int> &side_indices = voxel.get_model_side_indices(side);
								PoolVector<int>::Read ri = side_indices.read();
								unsigned int index_count = side_indices.size();

								{
									int i = arrays.indices.size();
									arrays.indices.resize(arrays.indices.size() + index_count);
									int *w = arrays.indices.ptrw();
									for(unsigned int j = 0; j < index_count; ++j) {
										w[i++] = index_offset + ri[j];
									}
								}

								index_offset += vertex_count;
							}
						}
					}

					// Inside
					if (voxel.get_model_positions().size() != 0) {
						// TODO Get rid of push_backs

						const PoolVector<Vector3> &vertices = voxel.get_model_positions();
						int vertex_count = vertices.size();

						PoolVector<Vector3>::Read rv = vertices.read();
						PoolVector<Vector3>::Read rn = voxel.get_model_normals().read();
						PoolVector<Vector2>::Read rt = voxel.get_model_uv().read();

						Vector3 pos(x - 1, y - 1, z - 1);

						for (unsigned int i = 0; i < vertex_count; ++i) {
							arrays.normals.push_back(rn[i]);
							arrays.uvs.push_back(rt[i]);
							arrays.positions.push_back(rv[i] + pos);
						}

						if(_bake_occlusion) {
							// TODO handle ambient occlusion on inner parts
							arrays.colors.push_back(Color(1,1,1));
						}

						const PoolVector<int> &indices = voxel.get_model_indices();
						PoolVector<int>::Read ri = indices.read();
						unsigned int index_count = indices.size();

						for(unsigned int i = 0; i < index_count; ++i) {
							arrays.indices.push_back(index_offset + ri[i]);
						}

						index_offset += vertex_count;
					}
				}
			}
		}
	}

	uint64_t time_meshing = OS::get_singleton()->get_ticks_usec() - time_before;
	time_before = OS::get_singleton()->get_ticks_usec();

	// Commit mesh

//	print_line(String("Made mesh v: ") + String::num(_arrays[0].positions.size())
//			+ String(", i: ") + String::num(_arrays[0].indices.size()));

	Array surfaces;

	// TODO We could return a single byte array and use Mesh::add_surface down the line?

	for (int i = 0; i < MAX_MATERIALS; ++i) {

		const Arrays &arrays = _arrays[i];
		if (arrays.positions.size() != 0) {

			/*print_line("Arrays:");
			for(int i = 0; i < arrays.positions.size(); ++i)
				print_line(String("  P {0}").format(varray(arrays.positions[i])));
			for(int i = 0; i < arrays.normals.size(); ++i)
				print_line(String("  N {0}").format(varray(arrays.normals[i])));
			for(int i = 0; i < arrays.uvs.size(); ++i)
				print_line(String("  UV {0}").format(varray(arrays.uvs[i])));*/

			Array mesh_arrays;
			mesh_arrays.resize(Mesh::ARRAY_MAX);

			{
				PoolVector<Vector3> positions;
				PoolVector<Vector2> uvs;
				PoolVector<Vector3> normals;
				PoolVector<Color> colors;
				PoolVector<int> indices;

				raw_copy_to(positions, arrays.positions);
				raw_copy_to(uvs, arrays.uvs);
				raw_copy_to(normals, arrays.normals);
				raw_copy_to(colors, arrays.colors);
				raw_copy_to(indices, arrays.indices);

				mesh_arrays[Mesh::ARRAY_VERTEX] = positions;
				mesh_arrays[Mesh::ARRAY_TEX_UV] = uvs;
				mesh_arrays[Mesh::ARRAY_NORMAL] = normals;
				mesh_arrays[Mesh::ARRAY_COLOR] = colors;
				mesh_arrays[Mesh::ARRAY_INDEX] = indices;
			}

			surfaces.append(mesh_arrays);
		}
	}

	uint64_t time_commit = OS::get_singleton()->get_ticks_usec() - time_before;

	//print_line(String("P: {0}, M: {1}, C: {2}").format(varray(time_prep, time_meshing, time_commit)));

	return surfaces;
}
Exemple #11
0
Variant Object::_call_bind(const StringName& p_name, const Variant& p_arg1, const Variant& p_arg2, const Variant& p_arg3, const Variant& p_arg4) {

	ERR_FAIL_COND_V(p_argcount<1,Variant());

	return call(p_name, p_arg1, p_arg2, p_arg3, p_arg4);
};
Exemple #12
0
bool Main::start() {

	ERR_FAIL_COND_V(!_start_success,false);

	bool editor=false;
	String doc_tool;
	bool doc_base=true;
	String game_path;
	String script;
	String test;
	String screen;
	String optimize;
	String optimize_preset;
	String _export_platform;
	String _import;
	String _import_script;
	String dumpstrings;
	bool noquit=false;
	bool convert_old=false;
	bool export_debug=false;
	List<String> args = OS::get_singleton()->get_cmdline_args();
	for (int i=0;i<args.size();i++) {
		

		if (args[i]=="-doctool" && i <(args.size()-1)) {

			doc_tool=args[i+1];
			i++;
		}else if (args[i]=="-nodocbase") {

			doc_base=false;
		} else if ((args[i]=="-script" || args[i]=="-s") && i <(args.size()-1)) {
		
			script=args[i+1];
			i++;
		} else if ((args[i]=="-level" || args[i]=="-l") && i <(args.size()-1)) {

			OS::get_singleton()->_custom_level=args[i+1];
			i++;
		} else if (args[i]=="-test" && i <(args.size()-1)) {
			test=args[i+1];
			i++;
		} else if (args[i]=="-optimize" && i <(args.size()-1)) {
			optimize=args[i+1];
			i++;
		} else if (args[i]=="-optimize_preset" && i <(args.size()-1)) {
			optimize_preset=args[i+1];
			i++;
		} else if (args[i]=="-export" && i <(args.size()-1)) {
			editor=true; //needs editor
			_export_platform=args[i+1];
			i++;
		} else if (args[i]=="-export_debug" && i <(args.size()-1)) {
			editor=true; //needs editor
			_export_platform=args[i+1];
			export_debug=true;
			i++;
		} else if (args[i]=="-import" && i <(args.size()-1)) {
			editor=true; //needs editor
			_import=args[i+1];
			i++;
		} else if (args[i]=="-import_script" && i <(args.size()-1)) {
			editor=true; //needs editor
			_import_script=args[i+1];
			i++;
		} else if (args[i]=="-noquit" ) {
			noquit=true;
		} else if (args[i]=="-dumpstrings" && i <(args.size()-1)) {
			editor=true; //needs editor
			dumpstrings=args[i+1];
			i++;
		} else if (args[i]=="-editor" || args[i]=="-e") {
			editor=true;
		} else if (args[i]=="-convert_old") {
			convert_old=true;
		} else if (args[i].length() && args[i][0] != '-' && game_path == "") {

			game_path=args[i];
		}
	}

	if (editor)
		Globals::get_singleton()->set("editor_active",true);


	String main_loop_type;
#ifdef TOOLS_ENABLED
	if(doc_tool!="") {

		DocData doc;
		doc.generate(doc_base);

		DocData docsrc;
		if (docsrc.load(doc_tool)==OK) {
			print_line("Doc exists. Merging..");
			doc.merge_from(docsrc);
		} else {
			print_line("No Doc exists. Generating empty.");

		}

		doc.save(doc_tool);

		return false;
	}

	if (optimize!="")
		editor=true; //need editor



#endif

	if(script=="" && game_path=="" && !editor && String(GLOBAL_DEF("application/main_scene",""))!="") {
		game_path=GLOBAL_DEF("application/main_scene","");
	}


	MainLoop *main_loop=NULL;
	if (editor) {
		main_loop = memnew(SceneTree);
	};

	if (test!="") {
#ifdef DEBUG_ENABLED
		main_loop = test_main(test,args);

		if (!main_loop)
			return false;

#endif

	} else if (script!="") {

		Ref<Script> script_res = ResourceLoader::load(script);
		ERR_EXPLAIN("Can't load script: "+script);
		ERR_FAIL_COND_V(script_res.is_null(),false);
		
		if( script_res->can_instance() /*&& script_res->inherits_from("SceneTreeScripted")*/) {
		

			StringName instance_type=script_res->get_instance_base_type();
			Object *obj = ObjectTypeDB::instance(instance_type);
			MainLoop *script_loop = obj?obj->cast_to<MainLoop>():NULL;
			if (!script_loop) {
				if (obj)
					memdelete(obj);
				ERR_EXPLAIN("Can't load script '"+script+"', it does not inherit from a MainLoop type");
				ERR_FAIL_COND_V(!script_loop,false);
			}


			script_loop->set_init_script(script_res);
			main_loop=script_loop;
		} else {

			return false;
		}

	} else {
		main_loop_type=GLOBAL_DEF("application/main_loop_type","");
	}
	
	if (!main_loop && main_loop_type=="")
		main_loop_type="SceneTree";
	
	if (!main_loop) {
		if (!ObjectTypeDB::type_exists(main_loop_type)) {
			OS::get_singleton()->alert("godot: error: MainLoop type doesn't exist: "+main_loop_type);
			return false;
		} else {

			Object *ml = ObjectTypeDB::instance(main_loop_type);
			if (!ml) {
				ERR_EXPLAIN("Can't instance MainLoop type");
				ERR_FAIL_V(false);
			}

			main_loop=ml->cast_to<MainLoop>();
			if (!main_loop) {
				
				memdelete(ml);
				ERR_EXPLAIN("Invalid MainLoop type");
				ERR_FAIL_V(false);
				
			}
		}
	}

	if (main_loop->is_type("SceneTree")) {
		
		SceneTree *sml = main_loop->cast_to<SceneTree>();

#ifdef TOOLS_ENABLED

		EditorNode *editor_node=NULL;
		if (editor) {

			editor_node = memnew( EditorNode );			
			sml->get_root()->add_child(editor_node);

			//root_node->set_editor(editor);
			//startup editor

			if (_export_platform!="") {

				editor_node->export_platform(_export_platform,game_path,export_debug,"",true);
				game_path=""; //no load anything
			}
		}
#endif

		if (!editor) {
			//standard helpers that can be changed from main config

			String stretch_mode = GLOBAL_DEF("display/stretch_mode","disabled");
			String stretch_aspect = GLOBAL_DEF("display/stretch_aspect","ignore");
			Size2i stretch_size = Size2(GLOBAL_DEF("display/width",0),GLOBAL_DEF("display/height",0));

			SceneTree::StretchMode sml_sm=SceneTree::STRETCH_MODE_DISABLED;
			if (stretch_mode=="2d")
				sml_sm=SceneTree::STRETCH_MODE_2D;
			else if (stretch_mode=="viewport")
				sml_sm=SceneTree::STRETCH_MODE_VIEWPORT;

			SceneTree::StretchAspect sml_aspect=SceneTree::STRETCH_ASPECT_IGNORE;
			if (stretch_aspect=="keep")
				sml_aspect=SceneTree::STRETCH_ASPECT_KEEP;
			else if (stretch_aspect=="keep_width")
				sml_aspect=SceneTree::STRETCH_ASPECT_KEEP_WIDTH;
			else if (stretch_aspect=="keep_height")
				sml_aspect=SceneTree::STRETCH_ASPECT_KEEP_HEIGHT;

			sml->set_screen_stretch(sml_sm,sml_aspect,stretch_size);

			sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true));
			String appname = Globals::get_singleton()->get("application/name");
			appname = TranslationServer::get_singleton()->translate(appname);
			OS::get_singleton()->set_window_title(appname);


		} else {
			GLOBAL_DEF("display/stretch_mode","disabled");
			Globals::get_singleton()->set_custom_property_info("display/stretch_mode",PropertyInfo(Variant::STRING,"display/stretch_mode",PROPERTY_HINT_ENUM,"disabled,2d,viewport"));
			GLOBAL_DEF("display/stretch_aspect","ignore");
			Globals::get_singleton()->set_custom_property_info("display/stretch_aspect",PropertyInfo(Variant::STRING,"display/stretch_aspect",PROPERTY_HINT_ENUM,"ignore,keep,keep_width,keep_height"));
			sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true));


		}


		if (game_path!="") {

			String local_game_path=game_path.replace("\\","/");

			if (!local_game_path.begins_with("res://")) {
				bool absolute=(local_game_path.size()>1) && (local_game_path[0]=='/' || local_game_path[1]==':');

				if (!absolute) {

					if (Globals::get_singleton()->is_using_datapack()) {

						local_game_path="res://"+local_game_path;

					} else {
						int sep=local_game_path.find_last("/");

						if (sep==-1) {
							DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
							local_game_path=da->get_current_dir()+"/"+local_game_path;
							memdelete(da)						;
						} else {

							DirAccess *da = DirAccess::open(local_game_path.substr(0,sep));
							if (da) {
								local_game_path=da->get_current_dir()+"/"+local_game_path.substr(sep+1,local_game_path.length());;
								memdelete(da);
							}
						}
					}

				}
			}

			local_game_path=Globals::get_singleton()->localize_path(local_game_path);

#ifdef TOOLS_ENABLED
			if (editor) {


				if (_import!="") {

					//editor_node->import_scene(_import,local_game_path,_import_script);
					if (!noquit)
						sml->quit();
					game_path=""; //no load anything
				} else {

					Error serr = editor_node->load_scene(local_game_path);

					if (serr==OK) {

						if (optimize!="") {

							editor_node->save_optimized_copy(optimize,optimize_preset);
							if (!noquit)
								sml->quit();
						}

						if (dumpstrings!="") {

							editor_node->save_translatable_strings(dumpstrings);
							if (!noquit)
								sml->quit();
						}
					}
				}

				//editor_node->set_edited_scene(game);
			} else {
#endif

				{
					//autoload
					List<PropertyInfo> props;
					Globals::get_singleton()->get_property_list(&props);
					for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {

						String s = E->get().name;
						if (!s.begins_with("autoload/"))
							continue;
						String name = s.get_slicec('/',1);
						String path = Globals::get_singleton()->get(s);
						RES res = ResourceLoader::load(path);
						ERR_EXPLAIN("Can't autoload: "+path);
						ERR_CONTINUE(res.is_null());
						Node *n=NULL;
						if (res->is_type("PackedScene")) {
							Ref<PackedScene> ps = res;
							n=ps->instance();
						} else if (res->is_type("Script")) {
							Ref<Script> s = res;
							StringName ibt = s->get_instance_base_type();
							ERR_EXPLAIN("Script does not inherit a Node: "+path);
							ERR_CONTINUE( !ObjectTypeDB::is_type(ibt,"Node") );

							Object *obj = ObjectTypeDB::instance(ibt);

							ERR_EXPLAIN("Cannot instance node for autoload type: "+String(ibt));
							ERR_CONTINUE( obj==NULL );

							n = obj->cast_to<Node>();
							n->set_script(s.get_ref_ptr());
						}

						ERR_EXPLAIN("Path in autoload not a node or script: "+path);
						ERR_CONTINUE(!n);
						n->set_name(name);
						sml->get_root()->add_child(n);
					}

				}

				Node *scene=NULL;
				Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path);
				if (scenedata.is_valid())
					scene=scenedata->instance();

				ERR_EXPLAIN("Failed loading scene: "+local_game_path);
				ERR_FAIL_COND_V(!scene,false)
				//sml->get_root()->add_child(scene);
				sml->add_current_scene(scene);

				String iconpath = GLOBAL_DEF("application/icon","Variant()""");
				if (iconpath!="") {
					Image icon;
					if (icon.load(iconpath)==OK)
						OS::get_singleton()->set_icon(icon);
				}


				//singletons
#ifdef TOOLS_ENABLED
			}
#endif
		}

#ifdef TOOLS_ENABLED

		/*if (_export_platform!="") {

			sml->quit();
		}*/

		/*
		if (sml->get_root_node()) {

			Console *console = memnew( Console );

			sml->get_root_node()->cast_to<RootNode>()->set_console(console);
			if (GLOBAL_DEF("console/visible_default",false).operator bool()) {

				console->show();
			} else {P

				console->hide();
			};
		}
*/
		if (script=="" && test=="" && game_path=="" && !editor) {

			ProjectManager *pmanager = memnew( ProjectManager );
			sml->get_root()->add_child(pmanager);
		}

#endif
	}

	OS::get_singleton()->set_main_loop( main_loop );

	return true;
}
Exemple #13
0
Vector<uint8_t> GDTokenizerBuffer::parse_code_string(const String& p_code) {

	Vector<uint8_t> buf;


	Map<StringName,int> identifier_map;
	HashMap<Variant,int,VariantHasher> constant_map;
	Map<uint32_t,int> line_map;
	Vector<uint32_t> token_array;

	GDTokenizerText tt;
	tt.set_code(p_code);
	int line=-1;

	while(true) {

		if (tt.get_token_line()!=line) {

			line=tt.get_token_line();
			line_map[line]=token_array.size();
		}

		uint32_t token=tt.get_token();
		switch(tt.get_token()) {

			case TK_IDENTIFIER: {
				StringName id = tt.get_token_identifier();
				if (!identifier_map.has(id)) {
					int idx = identifier_map.size();
					identifier_map[id]=idx;
				}
				token|=identifier_map[id]<<TOKEN_BITS;
			} break;
			case TK_CONSTANT: {

				Variant c = tt.get_token_constant();
				if (!constant_map.has(c)) {
					int idx = constant_map.size();
					constant_map[c]=idx;
				}
				token|=constant_map[c]<<TOKEN_BITS;
			} break;
			case TK_BUILT_IN_TYPE: {

				token|=tt.get_token_type()<<TOKEN_BITS;
			} break;
			case TK_BUILT_IN_FUNC: {

				token|=tt.get_token_built_in_func()<<TOKEN_BITS;

			} break;
			case TK_NEWLINE: {

				token|=tt.get_token_line_indent()<<TOKEN_BITS;
			} break;
			case TK_ERROR: {

				ERR_FAIL_V(Vector<uint8_t>());
			} break;
			default: {}

		};

		token_array.push_back(token);

		if (tt.get_token()==TK_EOF)
			break;
		tt.advance();

	}

	//reverse maps

	Map<int,StringName> rev_identifier_map;
	for(Map<StringName,int>::Element *E=identifier_map.front();E;E=E->next()) {
		rev_identifier_map[E->get()]=E->key();
	}

	Map<int,Variant> rev_constant_map;
	const Variant *K =NULL;
	while((K=constant_map.next(K))) {
		rev_constant_map[constant_map[*K]]=*K;
	}

	Map<int,uint32_t> rev_line_map;
	for(Map<uint32_t,int>::Element *E=line_map.front();E;E=E->next()) {
		rev_line_map[E->get()]=E->key();
	}

	//save header
	buf.resize(24);
	buf[0]='G';
	buf[1]='D';
	buf[2]='S';
	buf[3]='C';
	encode_uint32(BYTECODE_VERSION,&buf[4]);
	encode_uint32(identifier_map.size(),&buf[8]);
	encode_uint32(constant_map.size(),&buf[12]);
	encode_uint32(line_map.size(),&buf[16]);
	encode_uint32(token_array.size(),&buf[20]);

	//save identifiers

	for(Map<int,StringName>::Element *E=rev_identifier_map.front();E;E=E->next()) {

		CharString cs = String(E->get()).utf8();
		int len = cs.length()+1;
		int extra = 4-(len%4);
		if (extra==4)
			extra=0;

		uint8_t ibuf[4];
		encode_uint32(len+extra,ibuf);
		for(int i=0;i<4;i++) {
			buf.push_back(ibuf[i]);
		}
		for(int i=0;i<len;i++) {
			buf.push_back(cs[i]^0xb6);
		}
		for(int i=0;i<extra;i++) {
			buf.push_back(0^0xb6);
		}
	}

	for(Map<int,Variant>::Element *E=rev_constant_map.front();E;E=E->next()) {

		int len;
		Error err = encode_variant(E->get(),NULL,len);
		ERR_FAIL_COND_V(err!=OK,Vector<uint8_t>());
		int pos=buf.size();
		buf.resize(pos+len);
		encode_variant(E->get(),&buf[pos],len);
	}

	for(Map<int,uint32_t>::Element *E=rev_line_map.front();E;E=E->next()) {

		uint8_t ibuf[8];
		encode_uint32(E->key(),&ibuf[0]);
		encode_uint32(E->get(),&ibuf[4]);
		for(int i=0;i<8;i++)
			buf.push_back(ibuf[i]);
	}

	for(int i=0;i<token_array.size();i++) {

		uint32_t token = token_array[i];

		if (token&~TOKEN_MASK) {
			uint8_t buf4[4];
			encode_uint32(token_array[i]|TOKEN_BYTE_MASK,&buf4[0]);
			for(int j=0;j<4;j++) {
				buf.push_back(buf4[j]);
			}
		} else {
			buf.push_back(token);
		}
	}

	return buf;

}
Exemple #14
0
Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {


	const uint8_t *buf=p_buffer.ptr();
	int total_len=p_buffer.size();
	ERR_FAIL_COND_V( p_buffer.size()<24 || p_buffer[0]!='G' || p_buffer[1]!='D' || p_buffer[2]!='S' || p_buffer[3]!='C',ERR_INVALID_DATA);

	int version = decode_uint32(&buf[4]);
	if (version>BYTECODE_VERSION) {
		ERR_EXPLAIN("Bytecode is too New! Please use a newer engine version.");
		ERR_FAIL_COND_V(version>BYTECODE_VERSION,ERR_INVALID_DATA);
	}
	int identifier_count = decode_uint32(&buf[8]);
	int constant_count = decode_uint32(&buf[12]);
	int line_count = decode_uint32(&buf[16]);
	int token_count = decode_uint32(&buf[20]);

	const uint8_t *b=buf;

	b=&buf[24];
	total_len-=24;

	identifiers.resize(identifier_count);
	for(int i=0;i<identifier_count;i++) {

		int len = decode_uint32(b);
		ERR_FAIL_COND_V(len>total_len,ERR_INVALID_DATA);
		b+=4;
		Vector<uint8_t> cs;
		cs.resize(len);
		for(int j=0;j<len;j++) {
			cs[j]=b[j]^0xb6;
		}

		cs[cs.size()-1]=0;
		String s;
		s.parse_utf8((const char*)cs.ptr());
		b+=len;
		total_len-=len+4;
		identifiers[i]=s;
	}

	constants.resize(constant_count);
	for(int i=0;i<constant_count;i++) {

		Variant v;
		int len;
		Error err = decode_variant(v,b,total_len,&len);
		if (err)
			return err;
		b+=len;
		total_len-=len;
		constants[i]=v;

	}

	ERR_FAIL_COND_V(line_count*8>total_len,ERR_INVALID_DATA);

	for(int i=0;i<line_count;i++) {

		uint32_t token=decode_uint32(b);
		b+=4;
		uint32_t linecol=decode_uint32(b);
		b+=4;

		lines.insert(token,linecol);
		total_len-=8;
	}

	tokens.resize(token_count);

	for(int i=0;i<token_count;i++) {

		ERR_FAIL_COND_V( total_len < 1, ERR_INVALID_DATA);

		if ((*b)&TOKEN_BYTE_MASK) { //little endian always
			ERR_FAIL_COND_V( total_len < 4, ERR_INVALID_DATA);

			tokens[i]=decode_uint32(b)&~TOKEN_BYTE_MASK;
			b+=4;
		} else {
			tokens[i]=*b;
			b+=1;
			total_len--;
		}
	}

	token=0;

	return OK;

}
float AnimationPlayer::get_current_animation_length() const {

    ERR_FAIL_COND_V(!playback.current.from,0);
    return playback.current.from->animation->get_length();
}
Exemple #16
0
Ref<World> Spatial::get_world() const {

    ERR_FAIL_COND_V(!is_inside_world(),Ref<World>());
    return data.viewport->find_world();

}
Exemple #17
0
DVector<DVector<Face3> > Geometry::separate_objects(DVector<Face3> p_array) {

	DVector<DVector<Face3> > objects;

	int len = p_array.size();

	DVector<Face3>::Read r = p_array.read();

	const Face3 *arrayptr = r.ptr();

	DVector<_FaceClassify> fc;

	fc.resize(len);

	DVector<_FaceClassify>::Write fcw = fc.write();

	_FaceClassify *_fcptr = fcw.ptr();

	for (int i = 0; i < len; i++) {

		_fcptr[i].face = arrayptr[i];
	}

	bool error = _connect_faces(_fcptr, len, -1);

	if (error) {

		ERR_FAIL_COND_V(error, DVector<DVector<Face3> >()); // invalid geometry
	}

	/* group connected faces in separate objects */

	int group = 0;
	for (int i = 0; i < len; i++) {

		if (!_fcptr[i].valid)
			continue;
		if (_group_face(_fcptr, len, i, group)) {
			group++;
		}
	}

	/* group connected faces in separate objects */

	for (int i = 0; i < len; i++) {

		_fcptr[i].face = arrayptr[i];
	}

	if (group >= 0) {

		objects.resize(group);
		DVector<DVector<Face3> >::Write obw = objects.write();
		DVector<Face3> *group_faces = obw.ptr();

		for (int i = 0; i < len; i++) {
			if (!_fcptr[i].valid)
				continue;
			if (_fcptr[i].group >= 0 && _fcptr[i].group < group) {

				group_faces[_fcptr[i].group].push_back(_fcptr[i].face);
			}
		}
	}

	return objects;
}
Exemple #18
0
int MultiplayerAPI::get_network_unique_id() const {

	ERR_FAIL_COND_V(!network_peer.is_valid(), 0);
	return network_peer->get_unique_id();
}
Exemple #19
0
Error HTTPClient::poll() {

	switch (status) {

		case STATUS_RESOLVING: {
			ERR_FAIL_COND_V(resolving == IP::RESOLVER_INVALID_ID, ERR_BUG);

			IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving);
			switch (rstatus) {
				case IP::RESOLVER_STATUS_WAITING:
					return OK; // Still resolving

				case IP::RESOLVER_STATUS_DONE: {

					IP_Address host = IP::get_singleton()->get_resolve_item_address(resolving);
					Error err = tcp_connection->connect_to_host(host, conn_port);
					IP::get_singleton()->erase_resolve_item(resolving);
					resolving = IP::RESOLVER_INVALID_ID;
					if (err) {
						status = STATUS_CANT_CONNECT;
						return err;
					}

					status = STATUS_CONNECTING;
				} break;
				case IP::RESOLVER_STATUS_NONE:
				case IP::RESOLVER_STATUS_ERROR: {

					IP::get_singleton()->erase_resolve_item(resolving);
					resolving = IP::RESOLVER_INVALID_ID;
					close();
					status = STATUS_CANT_RESOLVE;
					return ERR_CANT_RESOLVE;
				} break;
			}
		} break;
		case STATUS_CONNECTING: {

			StreamPeerTCP::Status s = tcp_connection->get_status();
			switch (s) {

				case StreamPeerTCP::STATUS_CONNECTING: {
					return OK;
				} break;
				case StreamPeerTCP::STATUS_CONNECTED: {
					if (ssl) {
						Ref<StreamPeerSSL> ssl;
						if (!handshaking) {
							// Connect the StreamPeerSSL and start handshaking
							ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
							ssl->set_blocking_handshake_enabled(false);
							Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host);
							if (err != OK) {
								close();
								status = STATUS_SSL_HANDSHAKE_ERROR;
								return ERR_CANT_CONNECT;
							}
							connection = ssl;
							handshaking = true;
						} else {
							// We are already handshaking, which means we can use your already active SSL connection
							ssl = static_cast<Ref<StreamPeerSSL> >(connection);
							ssl->poll(); // Try to finish the handshake
						}

						if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) {
							// Handshake has been successful
							handshaking = false;
							status = STATUS_CONNECTED;
							return OK;
						} else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) {
							// Handshake has failed
							close();
							status = STATUS_SSL_HANDSHAKE_ERROR;
							return ERR_CANT_CONNECT;
						}
						// ... we will need to poll more for handshake to finish
					} else {
						status = STATUS_CONNECTED;
					}
					return OK;
				} break;
				case StreamPeerTCP::STATUS_ERROR:
				case StreamPeerTCP::STATUS_NONE: {

					close();
					status = STATUS_CANT_CONNECT;
					return ERR_CANT_CONNECT;
				} break;
			}
		} break;
		case STATUS_BODY:
		case STATUS_CONNECTED: {
			// Check if we are still connected
			if (ssl) {
				Ref<StreamPeerSSL> tmp = connection;
				tmp->poll();
				if (tmp->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
					status = STATUS_CONNECTION_ERROR;
					return ERR_CONNECTION_ERROR;
				}
			} else if (tcp_connection->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
				status = STATUS_CONNECTION_ERROR;
				return ERR_CONNECTION_ERROR;
			}
			// Connection established, requests can now be made
			return OK;
		} break;
		case STATUS_REQUESTING: {

			while (true) {
				uint8_t byte;
				int rec = 0;
				Error err = _get_http_data(&byte, 1, rec);
				if (err != OK) {
					close();
					status = STATUS_CONNECTION_ERROR;
					return ERR_CONNECTION_ERROR;
				}

				if (rec == 0)
					return OK; // Still requesting, keep trying!

				response_str.push_back(byte);
				int rs = response_str.size();
				if (
						(rs >= 2 && response_str[rs - 2] == '\n' && response_str[rs - 1] == '\n') ||
						(rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) {

					// End of response, parse.
					response_str.push_back(0);
					String response;
					response.parse_utf8((const char *)response_str.ptr());
					Vector<String> responses = response.split("\n");
					body_size = -1;
					chunked = false;
					body_left = 0;
					chunk_left = 0;
					read_until_eof = false;
					response_str.clear();
					response_headers.clear();
					response_num = RESPONSE_OK;

					// Per the HTTP 1.1 spec, keep-alive is the default, but in practice
					// it's safe to assume it only if the explicit header is found, allowing
					// to handle body-up-to-EOF responses on naive servers; that's what Curl
					// and browsers do
					bool keep_alive = false;

					for (int i = 0; i < responses.size(); i++) {

						String header = responses[i].strip_edges();
						String s = header.to_lower();
						if (s.length() == 0)
							continue;
						if (s.begins_with("content-length:")) {
							body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int();
							body_left = body_size;

						} else if (s.begins_with("transfer-encoding:")) {
							String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges();
							if (encoding == "chunked") {
								chunked = true;
							}
						} else if (s.begins_with("connection: keep-alive")) {
							keep_alive = true;
						}

						if (i == 0 && responses[i].begins_with("HTTP")) {

							String num = responses[i].get_slicec(' ', 1);
							response_num = num.to_int();
						} else {

							response_headers.push_back(header);
						}
					}

					if (body_size != -1 || chunked) {

						status = STATUS_BODY;
					} else if (!keep_alive) {

						read_until_eof = true;
						status = STATUS_BODY;
					} else {

						status = STATUS_CONNECTED;
					}
					return OK;
				}
			}
			// Wait for response
			return OK;
		} break;
		case STATUS_DISCONNECTED: {
			return ERR_UNCONFIGURED;
		} break;
		case STATUS_CONNECTION_ERROR:
		case STATUS_SSL_HANDSHAKE_ERROR: {
			return ERR_CONNECTION_ERROR;
		} break;
		case STATUS_CANT_CONNECT: {
			return ERR_CANT_CONNECT;
		} break;
		case STATUS_CANT_RESOLVE: {
			return ERR_CANT_RESOLVE;
		} break;
	}

	return OK;
}
Exemple #20
0
bool MultiplayerAPI::is_network_server() const {

	ERR_FAIL_COND_V(!network_peer.is_valid(), false);
	return network_peer->is_server();
}
void* MemoryPoolStaticMalloc::_alloc(size_t p_bytes,const char *p_description) {
 
 	ERR_FAIL_COND_V(p_bytes==0,0);
	
	MutexLock lock(mutex);
	
#ifdef DEBUG_MEMORY_ENABLED

	size_t total;
	#if defined(_add_overflow)
		if (_add_overflow(p_bytes, sizeof(RingPtr), &total)) return NULL;
	#else
		total = p_bytes + sizeof(RingPtr);
	#endif
	void *mem=malloc(total); /// add for size and ringlist

	if (!mem) {
		printf("**ERROR: out of memory while allocating %lu bytes by %s?\n", (unsigned long) p_bytes, p_description);
		printf("**ERROR: memory usage is %lu\n", (unsigned long) get_total_usage());
	};
	
	ERR_FAIL_COND_V(!mem,0); //out of memory, or unreasonable request
		
	/* setup the ringlist element */
	
	RingPtr *ringptr = (RingPtr*)mem;
	
	/* setup the ringlist element data (description and size ) */
	
	ringptr->size = p_bytes;
	ringptr->descr=p_description;
	
	if (ringlist) { /* existing ringlist */
		
		/* assign next */
		ringptr->next = ringlist->next;
		ringlist->next = ringptr;
		/* assign prev */
		ringptr->prev = ringlist;
		ringptr->next->prev = ringptr;
	} else { /* non existing ringlist */
		
		ringptr->next=ringptr;
		ringptr->prev=ringptr;
		ringlist=ringptr;
		
	}
	
	total_mem+=p_bytes;
	
	/* update statistics */
	if (total_mem > max_mem )
		max_mem = total_mem;
	
	total_pointers++;
	
	if (total_pointers > max_pointers)
		max_pointers=total_pointers;
	
	return ringptr + 1; /* return memory after ringptr */
		
#else		
	void *mem=malloc(p_bytes);

	ERR_FAIL_COND_V(!mem,0); //out of memory, or unreasonable request
	return mem;			
#endif	
}
Exemple #22
0
bool MultiplayerAPI::is_refusing_new_network_connections() const {

	ERR_FAIL_COND_V(!network_peer.is_valid(), false);
	return network_peer->is_refusing_new_connections();
}
Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<ResourceImportMetadata>& p_from,EditorExportPlatform::ImageCompression p_compr, bool p_external){



	ERR_FAIL_COND_V(p_from->get_source_count()==0,ERR_INVALID_PARAMETER);

	Ref<ResourceImportMetadata> from=p_from;

	Ref<ImageTexture> texture;
	Vector<Ref<AtlasTexture> > atlases;
	bool atlas = from->get_option("atlas");
	bool large = from->get_option("large");

	int flags=from->get_option("flags");
	int format=from->get_option("format");
	float quality=from->get_option("quality");

	uint32_t tex_flags=0;

	if (flags&EditorTextureImportPlugin::IMAGE_FLAG_REPEAT)
		tex_flags|=Texture::FLAG_REPEAT;
	if (flags&EditorTextureImportPlugin::IMAGE_FLAG_FILTER)
		tex_flags|=Texture::FLAG_FILTER;
	if (!(flags&EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS))
		tex_flags|=Texture::FLAG_MIPMAPS;
	if (flags&EditorTextureImportPlugin::IMAGE_FLAG_CONVERT_TO_LINEAR)
		tex_flags|=Texture::FLAG_CONVERT_TO_LINEAR;
	if (flags&EditorTextureImportPlugin::IMAGE_FLAG_USE_ANISOTROPY)
		tex_flags|=Texture::FLAG_ANISOTROPIC_FILTER;

	print_line("path: "+p_path+" flags: "+itos(tex_flags));
	float shrink=1;
	if (from->has_option("shrink"))
		shrink=from->get_option("shrink");

	if (large) {
		ERR_FAIL_COND_V(from->get_source_count()!=1,ERR_INVALID_PARAMETER);

		String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0));


		int cell_size=from->get_option("large_cell_size");
		ERR_FAIL_COND_V(cell_size<128 || cell_size>16384,ERR_CANT_OPEN);

		EditorProgress pg("ltex","Import Large Texture",3);

		pg.step("Load Source Image",0);
		Image img;
		Error err = ImageLoader::load_image(src_path,&img);
		if (err) {
			return err;
		}

		pg.step("Slicing",1);

		Map<Vector2,Image> pieces;
		for(int i=0;i<img.get_width();i+=cell_size) {
			int w = MIN(img.get_width()-i,cell_size);
			for(int j=0;j<img.get_height();j+=cell_size) {
				int h = MIN(img.get_height()-j,cell_size);

				Image piece(w,h,0,img.get_format());
				piece.blit_rect(img,Rect2(i,j,w,h),Point2(0,0));
				if (!piece.is_invisible()) {
					pieces[Vector2(i,j)]=piece;
					//print_line("ADDING PIECE AT "+Vector2(i,j));
				}
			}
		}

		Ref<LargeTexture> existing;
		if (ResourceCache::has(p_path)) {
			existing = ResourceCache::get(p_path);
		}

		if (existing.is_valid()) {
			existing->clear();
		} else {
			existing = Ref<LargeTexture>(memnew( LargeTexture ));
		}

		existing->set_size(Size2(img.get_width(),img.get_height()));
		pg.step("Inserting",2);

		for (Map<Vector2,Image>::Element *E=pieces.front();E;E=E->next()) {

			Ref<ImageTexture> imgtex = Ref<ImageTexture>( memnew( ImageTexture ) );
			imgtex->create_from_image(E->get(),tex_flags);
			_process_texture_data(imgtex,format,quality,flags,p_compr,tex_flags,shrink);
			existing->add_piece(E->key(),imgtex);
		}

		if (!p_external) {
			from->set_editor(get_name());
			existing->set_path(p_path);
			existing->set_import_metadata(from);
		}
		pg.step("Saving",3);

		err = ResourceSaver::save(p_path,existing);
		if (err!=OK) {
			EditorNode::add_io_error("Couldn't save large texture: "+p_path);
			return err;
		}

		return OK;


	} else if (atlas) {

		//prepare atlas!
		Vector< Image > sources;
		Vector< Image > tsources;
		bool alpha=false;
		bool crop = from->get_option("crop");

		EditorProgress ep("make_atlas","Build Atlas For: "+p_path.get_file(),from->get_source_count()+3);

		print_line("sources: "+itos(from->get_source_count()));

		for(int i=0;i<from->get_source_count();i++) {

			String path = EditorImportPlugin::expand_source_path(from->get_source_path(i));
			String md5 = FileAccess::get_md5(path);
			from->set_source_md5(i,FileAccess::get_md5(path));
			ep.step("Loading Image: "+path,i);
			print_line("source path: "+path+" md5 "+md5);
			Image src;
			Error err = ImageLoader::load_image(path,&src);
			if (err) {
				EditorNode::add_io_error("Couldn't load image: "+path);
				return err;
			}

			if (src.detect_alpha())
				alpha=true;

			tsources.push_back(src);
		}
		ep.step("Converting Images",sources.size());

		int base_index=0;


		Map<uint64_t,int> source_md5;
		Map<int,List<int> > source_map;

		for(int i=0;i<tsources.size();i++) {

			Image src = tsources[i];

			if (alpha) {
				src.convert(Image::FORMAT_RGBA);
			} else {
				src.convert(Image::FORMAT_RGB);
			}

			DVector<uint8_t> data = src.get_data();
			MD5_CTX md5;
			DVector<uint8_t>::Read r=data.read();
			MD5Init(&md5);
			int len=data.size();
			for(int j=0;j<len;j++) {
				uint8_t b = r[j];
				b>>=2; //to aid in comparing
				MD5Update(&md5,(unsigned char*)&b,1);
			}
			MD5Final(&md5);
			uint64_t *cmp = (uint64_t*)md5.digest; //less bits, but still useful for this

			tsources[i]=Image(); //clear

			if (source_md5.has(*cmp)) {
				int sidx=source_md5[*cmp];
				source_map[sidx].push_back(i);
				print_line("REUSING "+from->get_source_path(i));

			} else {
				int sidx=sources.size();
				source_md5[*cmp]=sidx;
				sources.push_back(src);
				List<int> sm;
				sm.push_back(i);
				source_map[sidx]=sm;

			}


		}

		//texturepacker is not really good for optimizing, so..
		//will at some point likely replace with my own
		//first, will find the nearest to a square packing
		int border=1;

		Vector<Size2i> src_sizes;
		Vector<Rect2> crops;

		ep.step("Cropping Images",sources.size()+1);

		for(int j=0;j<sources.size();j++) {

			Size2i s;
			if (crop) {
				Rect2 crop = sources[j].get_used_rect();
				print_line("CROP: "+crop);
				s=crop.size;
				crops.push_back(crop);
			} else {

				s=Size2i(sources[j].get_width(),sources[j].get_height());
			}
			s+=Size2i(border*2,border*2);
			src_sizes.push_back(s); //add a line to constraint width
		}

		Vector<Point2i> dst_positions;
		Size2i dst_size;
		EditorAtlas::fit(src_sizes,dst_positions,dst_size);

		print_line("size that workeD: "+itos(dst_size.width)+","+itos(dst_size.height));

		ep.step("Blitting Images",sources.size()+2);

		bool blit_to_po2=tex_flags&Texture::FLAG_MIPMAPS;
		int atlas_w=dst_size.width;
		int atlas_h=dst_size.height;
		if (blit_to_po2) {
			atlas_w=nearest_power_of_2(dst_size.width);
			atlas_h=nearest_power_of_2(dst_size.height);
		}
		Image atlas;
		atlas.create(atlas_w,atlas_h,0,alpha?Image::FORMAT_RGBA:Image::FORMAT_RGB);


		atlases.resize(from->get_source_count());

		for(int i=0;i<sources.size();i++) {

			int x=dst_positions[i].x;
			int y=dst_positions[i].y;

			Size2 sz = Size2(sources[i].get_width(),sources[i].get_height());

			Rect2 region;
			Rect2 margin;

			if (crop && sz!=crops[i].size) {
				Rect2 rect = crops[i];
				rect.size=sz-rect.size;
				region=Rect2(x+border,y+border,crops[i].size.width,crops[i].size.height);
				margin=rect;
				atlas.blit_rect(sources[i],crops[i],Point2(x+border,y+border));
			} else {
				region=Rect2(x+border,y+border,sz.x,sz.y);
				atlas.blit_rect(sources[i],Rect2(0,0,sources[i].get_width(),sources[i].get_height()),Point2(x+border,y+border));
			}

			ERR_CONTINUE( !source_map.has(i) );
			for (List<int>::Element *E=source_map[i].front();E;E=E->next()) {

				String apath = p_path.get_base_dir().plus_file(from->get_source_path(E->get()).get_file().basename()+".atex");

				Ref<AtlasTexture> at;

				if (ResourceCache::has(apath)) {
					at = Ref<AtlasTexture>( ResourceCache::get(apath)->cast_to<AtlasTexture>() );
				} else {

					at = Ref<AtlasTexture>( memnew( AtlasTexture ) );
				}
				at->set_region(region);
				at->set_margin(margin);
				at->set_path(apath);
				atlases[E->get()]=at;
				print_line("Atlas Tex: "+apath);
			}
		}
		if (ResourceCache::has(p_path)) {
			texture = Ref<ImageTexture> ( ResourceCache::get(p_path)->cast_to<ImageTexture>() );
		} else {
			texture = Ref<ImageTexture>( memnew( ImageTexture ) );
		}
		texture->create_from_image(atlas,tex_flags);

	} else {
Exemple #24
0
Node *Node::duplicate(bool p_use_instancing) const {


	Node *node=NULL;

	bool instanced=false;

	if (cast_to<InstancePlaceholder>()) {

		const InstancePlaceholder *ip = cast_to<const InstancePlaceholder>();
		InstancePlaceholder *nip = memnew( InstancePlaceholder );
		nip->set_instance_path( ip->get_instance_path() );
		node=nip;

	} else if (p_use_instancing && get_filename()!=String()) {

		Ref<PackedScene> res = ResourceLoader::load(get_filename());
		ERR_FAIL_COND_V(res.is_null(),NULL);
		node=res->instance();
		ERR_FAIL_COND_V(!node,NULL);

		instanced=true;

	} else {

		Object *obj = ObjectTypeDB::instance(get_type());
		ERR_FAIL_COND_V(!obj,NULL);
		node = obj->cast_to<Node>();
		if (!node)
			memdelete(obj);
		ERR_FAIL_COND_V(!node,NULL);
	}


	if (get_filename()!="") { //an instance
		node->set_filename(get_filename());
	}

	List<PropertyInfo> plist;

	get_property_list(&plist);

	for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {

		if (!(E->get().usage&PROPERTY_USAGE_STORAGE))
			continue;
		String name = E->get().name;
		node->set( name, get(name) );

	}

	node->set_name(get_name());

	List<GroupInfo> gi;
	get_groups(&gi);
	for (List<GroupInfo>::Element *E=gi.front();E;E=E->next()) {

		node->add_to_group(E->get().name, E->get().persistent);
	}

	_duplicate_signals(this, node);

	for(int i=0;i<get_child_count();i++) {

		if (get_child(i)->data.parent_owned)
			continue;
		if (instanced && get_child(i)->data.owner==this)
			continue; //part of instance

		Node *dup = get_child(i)->duplicate(p_use_instancing);
		if (!dup) {

			memdelete(node);
			return NULL;
		}

		node->add_child(dup);
	}

	return node;
}
Exemple #25
0
PoolAllocator::ID PoolAllocator::alloc(int p_size) {

	ERR_FAIL_COND_V(p_size<1,POOL_ALLOCATOR_INVALID_ID);
#ifdef DEBUG_ENABLED
	if (p_size > free_mem) OS::get_singleton()->debug_break();
#endif
	ERR_FAIL_COND_V(p_size>free_mem,POOL_ALLOCATOR_INVALID_ID);

	mt_lock();

	if (entry_count==entry_max) {
		mt_unlock();
		ERR_PRINT("entry_count==entry_max");
		return POOL_ALLOCATOR_INVALID_ID;
	}


	int size_to_alloc=aligned(p_size);

	EntryIndicesPos new_entry_indices_pos;

	if (!find_hole(&new_entry_indices_pos, size_to_alloc)) {
		/* No hole could be found, try compacting mem */
		compact();
		/* Then search again */

		if (!find_hole(&new_entry_indices_pos, size_to_alloc)) {

			mt_unlock();
			ERR_PRINT("memory can't be compacted further");
			return POOL_ALLOCATOR_INVALID_ID;
		}
	}

	EntryArrayPos new_entry_array_pos;

	bool found_free_entry=get_free_entry(&new_entry_array_pos);

	if (!found_free_entry) {
		mt_unlock();
		ERR_FAIL_COND_V( !found_free_entry , POOL_ALLOCATOR_INVALID_ID );
	}

	/* move all entry indices up, make room for this one */
	for (int i=entry_count;i>new_entry_indices_pos;i--  ) {

		entry_indices[i]=entry_indices[i-1];
	}

	entry_indices[new_entry_indices_pos]=new_entry_array_pos;

	entry_count++;

	Entry &entry=entry_array[ entry_indices[ new_entry_indices_pos ] ];

	entry.len=p_size;
	entry.pos=(new_entry_indices_pos==0)?0:entry_end(entry_array[ entry_indices[ new_entry_indices_pos-1 ] ]); //alloc either at begining or end of previous
	entry.lock=0;
	entry.check=(check_count++)&CHECK_MASK;
	free_mem-=size_to_alloc;
	if (free_mem<free_mem_peak)
		free_mem_peak=free_mem;

	ID retval = (entry_indices[ new_entry_indices_pos ]<<CHECK_BITS)|entry.check;
	mt_unlock();

	//ERR_FAIL_COND_V( (uintptr_t)get(retval)%align != 0, retval );

	return retval;

}
Exemple #26
0
bool Node::is_greater_than(const Node *p_node) const {

	ERR_FAIL_NULL_V(p_node,false);
	ERR_FAIL_COND_V( !data.inside_tree, false );
	ERR_FAIL_COND_V( !p_node->data.inside_tree, false );

	ERR_FAIL_COND_V( data.depth<0, false);
	ERR_FAIL_COND_V( p_node->data.depth<0, false);
#ifdef NO_ALLOCA

	Vector<int> this_stack;
	Vector<int> that_stack;
	this_stack.resize(data.depth);
	that_stack.resize(p_node->data.depth);

#else

	int *this_stack=(int*)alloca(sizeof(int)*data.depth);
	int *that_stack=(int*)alloca(sizeof(int)*p_node->data.depth);

#endif

	const Node *n = this;

	int idx=data.depth-1;
	while(n) {
		ERR_FAIL_INDEX_V(idx, data.depth,false);
		this_stack[idx--]=n->data.pos;
		n=n->data.parent;
	}
	ERR_FAIL_COND_V(idx!=-1,false);
	n = p_node;
	idx=p_node->data.depth-1;
	while(n) {
		ERR_FAIL_INDEX_V(idx, p_node->data.depth,false);
		that_stack[idx--]=n->data.pos;

		n=n->data.parent;
	}
	ERR_FAIL_COND_V(idx!=-1,false);
	idx=0;

	bool res;
	while(true) {

		// using -2 since out-of-tree or nonroot nodes have -1
		int this_idx = (idx >= data.depth)? -2 : this_stack[idx];
		int that_idx = (idx >= p_node->data.depth)? -2 : that_stack[idx];

		if (this_idx > that_idx) {
			res=true;
			break;
		} else if (this_idx < that_idx) {
			res=false;
			break;
		} else if (this_idx == -2 ) {
			res=false; // equal
			break;
		}
		idx++;
	}

	return res;
}
Exemple #27
0
bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion, MotionCastCollision &r_result, const Set<RID>& p_exclude,uint32_t p_user_mask) {

	Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape);
	ERR_FAIL_COND_V(!shape,0);

	Rect2 aabb = p_xform.xform(shape->get_aabb());
	aabb=aabb.merge(Rect2(aabb.pos+p_motion,aabb.size)); //motion

	int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);

	bool collided=false;
	r_result.travel=1;

	MotionCallbackRayCastData best_normal;
	best_normal.best_len=1e20;
	for(int i=0;i<amount;i++) {


		if (space->intersection_query_results[i]->get_type()==CollisionObject2DSW::TYPE_AREA)
			continue; //ignore area

		if (p_exclude.has( space->intersection_query_results[i]->get_self()))
			continue; //ignore excluded


		const CollisionObject2DSW *col_obj=space->intersection_query_results[i];
		int shape_idx=space->intersection_query_subindex_results[i];


		Matrix32 col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
		//test initial overlap, does it collide if going all the way?
		if (!CollisionSolver2DSW::solve(shape,p_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL)) {

			continue;
		}


		//test initial overlap
		if (CollisionSolver2DSW::solve(shape,p_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL)) {

			r_result.collider_id=col_obj->get_instance_id();
			r_result.collider=r_result.collider_id!=0 ? ObjectDB::get_instance(col_obj->get_instance_id()) : NULL;
			r_result.shape=shape_idx;
			r_result.rid=col_obj->get_self();
			r_result.travel=0;
			r_result.point=Vector2();
			r_result.normal=Vector2();
			return true;
		}

#if 0
		Vector2 mnormal=p_motion.normalized();
		Matrix32 col_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
		ShapeSW *col_shape = col_obj->get_shape(shape_idx);

		real_t min,max;
		col_shape->project_rangev(mnormal,col_shape_xform,min,max);
		real_t width = max-min;

		int a;
		Vector2 s[2];
		col_shape->get_supports(col_shape_xform.basis_xform(mnormal).normalized(),s,a);
		Vector2 from = col_shape_xform.xform(s[0]);
		Vector2 to = from + p_motion;

		Matrix32 from_inv = col_shape_xform.affine_inverse();

		Vector2 local_from = from_inv.xform(from-mnormal*width*0.1); //start from a little inside the bounding box
		Vector2 local_to = from_inv.xform(to);

		Vector2 rpos,rnorm;
		if (!col_shape->intersect_segment(local_from,local_to,rpos,rnorm))
			return false;

		//ray hit something


		Vector2 hitpos = p_xform_B.xform(rpos);
#endif

		//just do kinematic solving
		float low=0;
		float hi=1;
		Vector2 mnormal=p_motion.normalized();

		for(int i=0;i<8;i++) { //steps should be customizable..

			Matrix32 xfa = p_xform;
			float ofs = (low+hi)*0.5;

			Vector2 sep=mnormal; //important optimization for this to work fast enough
			bool collided = CollisionSolver2DSW::solve(shape,p_xform,p_motion*ofs,col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),NULL,NULL,&sep);

			if (collided) {

				hi=ofs;
			} else {

				low=ofs;
			}
		}


		best_normal.shape_B=col_obj->get_shape(shape_idx);
		best_normal.motion=p_motion*hi;
		best_normal.b_xform=col_obj_xform;
		best_normal.b_xform_inv=col_obj_xform.affine_inverse();

		bool sc = CollisionSolver2DSW::solve(shape,p_xform,p_motion*hi,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2() ,_motion_cbk_result,&best_normal);
		print_line("CLD: "+itos(sc));


		if (collided && low>=r_result.travel)
			continue;

		collided=true;
		r_result.travel=low;

		r_result.collider_id=col_obj->get_instance_id();
		r_result.collider=r_result.collider_id!=0 ? ObjectDB::get_instance(col_obj->get_instance_id()) : NULL;
		r_result.shape=shape_idx;
		r_result.rid=col_obj->get_self();

	}

	if (collided) {
		ERR_FAIL_COND_V(best_normal.best_normal==Vector2(),false);
		r_result.normal=best_normal.best_normal;
		r_result.point=best_normal.best_contact;
	}

	return collided;


}
float AnimationPlayer::get_current_animation_pos() const {

    ERR_FAIL_COND_V(!playback.current.from,0);
    return playback.current.pos;
}
int BroadPhase2DHashGrid::get_subindex(ID p_id) const {

	const Map<ID,Element>::Element *E=element_map.find(p_id);
	ERR_FAIL_COND_V(!E,-1);
	return E->get().subindex;
}
Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {

	Error err;
	if (p_flags&ResourceSaver::FLAG_COMPRESS) {
		FileAccessCompressed *fac = memnew( FileAccessCompressed );
		fac->configure("RSCC");
		f=fac;
		err = fac->_open(p_path,FileAccess::WRITE);
		if (err)
			memdelete(f);

	} else {
		f=FileAccess::open(p_path,FileAccess::WRITE,&err);
	}


	ERR_FAIL_COND_V(err,err);
	FileAccessRef _fref(f);


	relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS;
	skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
	bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES;
	big_endian=p_flags&ResourceSaver::FLAG_SAVE_BIG_ENDIAN;
	no_extensions=p_flags&ResourceSaver::FLAG_NO_EXTENSION;

	local_path=p_path.get_base_dir();
	//bin_meta_idx = get_string_index("__bin_meta__"); //is often used, so create

	_find_resources(p_resource,true);

	if (!(p_flags&ResourceSaver::FLAG_COMPRESS)) {
		//save header compressed
		static const uint8_t header[4]={'R','S','R','C'};
		f->store_buffer(header,4);
	}

	if (big_endian) {
		f->store_32(1);
		f->set_endian_swap(true);
	} else
		f->store_32(0);

	f->store_32(0); //64 bits file, false for now
	f->store_32(VERSION_MAJOR);
	f->store_32(VERSION_MINOR);
	f->store_32(FORMAT_VERSION);

	//f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed
	save_unicode_string(p_resource->get_type());
	uint64_t md_at = f->get_pos();
	f->store_64(0); //offset to impoty metadata
	for(int i=0;i<14;i++)
		f->store_32(0); // reserved


	List<ResourceData> resources;


	{


		for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {


			ResourceData &rd = resources.push_back(ResourceData())->get();
			rd.type=E->get()->get_type();

			List<PropertyInfo> property_list;
			E->get()->get_property_list( &property_list );

			for(List<PropertyInfo>::Element *F=property_list.front();F;F=F->next()) {

				if (skip_editor && F->get().name.begins_with("__editor"))
					continue;
				if (F->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && F->get().usage&PROPERTY_USAGE_BUNDLE)) {
					Property p;
					p.name_idx=get_string_index(F->get().name);
					p.value=E->get()->get(F->get().name);
					if (F->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && p.value.is_zero())
						continue;
					p.pi=F->get();										

					rd.properties.push_back(p);

				}
			}



		}
	}


	f->store_32(strings.size()); //string table size
	for(int i=0;i<strings.size();i++) {
		//print_bl("saving string: "+strings[i]);
		save_unicode_string(strings[i]);
	}

	// save external resource table
	f->store_32(external_resources.size()); //amount of external resources
	for(Set<RES>::Element *E=external_resources.front();E;E=E->next()) {

		save_unicode_string(E->get()->get_save_type());
		String path = E->get()->get_path();
		if (no_extensions)
			path=path.basename()+".*";
		save_unicode_string(path);
	}
	// save internal resource table
	f->store_32(saved_resources.size()); //amount of internal resources
	Vector<uint64_t> ofs_pos;
	for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {

		RES r = E->get();
		if (r->get_path()=="" || r->get_path().find("::")!=-1)
			save_unicode_string("local://"+itos(ofs_pos.size()));
		else
			save_unicode_string(r->get_path()); //actual external
		ofs_pos.push_back(f->get_pos());
		f->store_64(0); //offset in 64 bits
	}

	Vector<uint64_t> ofs_table;
//	int saved_idx=0;
	//now actually save the resources

	for(List<ResourceData>::Element *E=resources.front();E;E=E->next()) {

		ResourceData & rd = E->get();

		ofs_table.push_back(f->get_pos());
		save_unicode_string(rd.type);
		f->store_32(rd.properties.size());

		for (List<Property>::Element *F=rd.properties.front();F;F=F->next()) {

			Property &p=F->get();
			f->store_32(p.name_idx);
			write_variant(p.value,F->get().pi);
		}

	}

	for(int i=0;i<ofs_table.size();i++) {
		f->seek(ofs_pos[i]);
		f->store_64(ofs_table[i]);
	}

	f->seek_end();
	if (p_resource->get_import_metadata().is_valid()) {
		uint64_t md_pos = f->get_pos();
		Ref<ResourceImportMetadata> imd=p_resource->get_import_metadata();
		save_unicode_string(imd->get_editor());
		f->store_32(imd->get_source_count());
		for(int i=0;i<imd->get_source_count();i++) {
			save_unicode_string(imd->get_source_path(i));
			save_unicode_string(imd->get_source_md5(i));
		}
		List<String> options;
		imd->get_options(&options);
		f->store_32(options.size());
		for(List<String>::Element *E=options.front();E;E=E->next()) {
			save_unicode_string(E->get());
			write_variant(imd->get_option(E->get()));
		}

		f->seek(md_at);
		f->store_64(md_pos);
		f->seek_end();
	}


	f->store_buffer((const uint8_t*)"RSRC",4); //magic at end

	f->close();


	return OK;
}