1 /*************************************************************************/
2 /*  texture.cpp                                                          */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "texture.h"
32 
33 #include "core/core_string_names.h"
34 #include "core/io/image_loader.h"
35 #include "core/method_bind_ext.gen.inc"
36 #include "core/os/os.h"
37 #include "mesh.h"
38 #include "scene/resources/bit_map.h"
39 #include "servers/camera/camera_feed.h"
40 
get_size() const41 Size2 Texture::get_size() const {
42 
43 	return Size2(get_width(), get_height());
44 }
45 
is_pixel_opaque(int p_x,int p_y) const46 bool Texture::is_pixel_opaque(int p_x, int p_y) const {
47 	return true;
48 }
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const49 void Texture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
50 
51 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
52 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose, normal_rid);
53 }
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const54 void Texture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
55 
56 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
57 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose, normal_rid);
58 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map,bool p_clip_uv) const59 void Texture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
60 
61 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
62 	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, normal_rid, p_clip_uv);
63 }
64 
get_rect_region(const Rect2 & p_rect,const Rect2 & p_src_rect,Rect2 & r_rect,Rect2 & r_src_rect) const65 bool Texture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
66 
67 	r_rect = p_rect;
68 	r_src_rect = p_src_rect;
69 
70 	return true;
71 }
72 
_bind_methods()73 void Texture::_bind_methods() {
74 
75 	ClassDB::bind_method(D_METHOD("get_width"), &Texture::get_width);
76 	ClassDB::bind_method(D_METHOD("get_height"), &Texture::get_height);
77 	ClassDB::bind_method(D_METHOD("get_size"), &Texture::get_size);
78 	ClassDB::bind_method(D_METHOD("has_alpha"), &Texture::has_alpha);
79 	ClassDB::bind_method(D_METHOD("set_flags", "flags"), &Texture::set_flags);
80 	ClassDB::bind_method(D_METHOD("get_flags"), &Texture::get_flags);
81 	ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "modulate", "transpose", "normal_map"), &Texture::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()));
82 	ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose", "normal_map"), &Texture::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()));
83 	ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map", "clip_uv"), &Texture::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(true));
84 	ClassDB::bind_method(D_METHOD("get_data"), &Texture::get_data);
85 
86 	ADD_GROUP("Flags", "");
87 	ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic Linear,Convert to Linear,Mirrored Repeat,Video Surface"), "set_flags", "get_flags");
88 	ADD_GROUP("", "");
89 
90 	BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
91 	BIND_ENUM_CONSTANT(FLAG_MIPMAPS);
92 	BIND_ENUM_CONSTANT(FLAG_REPEAT);
93 	BIND_ENUM_CONSTANT(FLAG_FILTER);
94 	BIND_ENUM_CONSTANT(FLAG_ANISOTROPIC_FILTER);
95 	BIND_ENUM_CONSTANT(FLAG_CONVERT_TO_LINEAR);
96 	BIND_ENUM_CONSTANT(FLAG_MIRRORED_REPEAT);
97 	BIND_ENUM_CONSTANT(FLAG_VIDEO_SURFACE);
98 }
99 
Texture()100 Texture::Texture() {
101 }
102 
103 /////////////////////
104 
reload_from_file()105 void ImageTexture::reload_from_file() {
106 
107 	String path = ResourceLoader::path_remap(get_path());
108 	if (!path.is_resource_file())
109 		return;
110 
111 	uint32_t flags = get_flags();
112 	Ref<Image> img;
113 	img.instance();
114 
115 	if (ImageLoader::load_image(path, img) == OK) {
116 		create_from_image(img, flags);
117 	} else {
118 		Resource::reload_from_file();
119 		_change_notify();
120 		emit_changed();
121 	}
122 }
123 
_set(const StringName & p_name,const Variant & p_value)124 bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
125 
126 	if (p_name == "image")
127 		create_from_image(p_value, flags);
128 	else if (p_name == "flags")
129 		if (w * h == 0)
130 			flags = p_value;
131 		else
132 			set_flags(p_value);
133 	else if (p_name == "size") {
134 		Size2 s = p_value;
135 		w = s.width;
136 		h = s.height;
137 		VisualServer::get_singleton()->texture_set_size_override(texture, w, h, 0);
138 	} else if (p_name == "_data") {
139 		_set_data(p_value);
140 	} else
141 		return false;
142 
143 	return true;
144 }
145 
_get(const StringName & p_name,Variant & r_ret) const146 bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
147 
148 	if (p_name == "image_data") {
149 
150 	} else if (p_name == "image")
151 		r_ret = get_data();
152 	else if (p_name == "flags")
153 		r_ret = flags;
154 	else if (p_name == "size")
155 		r_ret = Size2(w, h);
156 	else
157 		return false;
158 
159 	return true;
160 }
161 
_get_property_list(List<PropertyInfo> * p_list) const162 void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
163 
164 	p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat"));
165 	p_list->push_back(PropertyInfo(Variant::OBJECT, "image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
166 	p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, ""));
167 }
168 
_reload_hook(const RID & p_hook)169 void ImageTexture::_reload_hook(const RID &p_hook) {
170 
171 	String path = get_path();
172 	if (!path.is_resource_file())
173 		return;
174 
175 	Ref<Image> img;
176 	img.instance();
177 	Error err = ImageLoader::load_image(path, img);
178 
179 	ERR_FAIL_COND_MSG(err != OK, "Cannot load image from path '" + path + "'.");
180 
181 	VisualServer::get_singleton()->texture_set_data(texture, img);
182 
183 	_change_notify();
184 	emit_changed();
185 }
186 
create(int p_width,int p_height,Image::Format p_format,uint32_t p_flags)187 void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uint32_t p_flags) {
188 
189 	flags = p_flags;
190 	VisualServer::get_singleton()->texture_allocate(texture, p_width, p_height, 0, p_format, VS::TEXTURE_TYPE_2D, p_flags);
191 	format = p_format;
192 	w = p_width;
193 	h = p_height;
194 	_change_notify();
195 	emit_changed();
196 }
create_from_image(const Ref<Image> & p_image,uint32_t p_flags)197 void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags) {
198 
199 	ERR_FAIL_COND(p_image.is_null());
200 	flags = p_flags;
201 	w = p_image->get_width();
202 	h = p_image->get_height();
203 	format = p_image->get_format();
204 
205 	VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags);
206 	VisualServer::get_singleton()->texture_set_data(texture, p_image);
207 	_change_notify();
208 	emit_changed();
209 
210 	image_stored = true;
211 }
212 
set_flags(uint32_t p_flags)213 void ImageTexture::set_flags(uint32_t p_flags) {
214 
215 	if (flags == p_flags)
216 		return;
217 
218 	flags = p_flags;
219 	if (w == 0 || h == 0) {
220 		return; //uninitialized, do not set to texture
221 	}
222 	VisualServer::get_singleton()->texture_set_flags(texture, p_flags);
223 	_change_notify("flags");
224 	emit_changed();
225 }
226 
get_flags() const227 uint32_t ImageTexture::get_flags() const {
228 
229 	return ImageTexture::flags;
230 }
231 
get_format() const232 Image::Format ImageTexture::get_format() const {
233 
234 	return format;
235 }
236 #ifndef DISABLE_DEPRECATED
load(const String & p_path)237 Error ImageTexture::load(const String &p_path) {
238 
239 	WARN_DEPRECATED;
240 	Ref<Image> img;
241 	img.instance();
242 	Error err = img->load(p_path);
243 	if (err == OK) {
244 		create_from_image(img);
245 	}
246 	return err;
247 }
248 #endif
set_data(const Ref<Image> & p_image)249 void ImageTexture::set_data(const Ref<Image> &p_image) {
250 
251 	ERR_FAIL_COND(p_image.is_null());
252 
253 	VisualServer::get_singleton()->texture_set_data(texture, p_image);
254 
255 	_change_notify();
256 	emit_changed();
257 
258 	alpha_cache.unref();
259 	image_stored = true;
260 }
261 
_resource_path_changed()262 void ImageTexture::_resource_path_changed() {
263 
264 	String path = get_path();
265 }
266 
get_data() const267 Ref<Image> ImageTexture::get_data() const {
268 
269 	if (image_stored) {
270 		return VisualServer::get_singleton()->texture_get_data(texture);
271 	} else {
272 		return Ref<Image>();
273 	}
274 }
275 
get_width() const276 int ImageTexture::get_width() const {
277 
278 	return w;
279 }
280 
get_height() const281 int ImageTexture::get_height() const {
282 
283 	return h;
284 }
285 
get_rid() const286 RID ImageTexture::get_rid() const {
287 
288 	return texture;
289 }
290 
has_alpha() const291 bool ImageTexture::has_alpha() const {
292 
293 	return (format == Image::FORMAT_LA8 || format == Image::FORMAT_RGBA8);
294 }
295 
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const296 void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
297 
298 	if ((w | h) == 0)
299 		return;
300 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
301 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid);
302 }
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const303 void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
304 
305 	if ((w | h) == 0)
306 		return;
307 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
308 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid);
309 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map,bool p_clip_uv) const310 void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
311 
312 	if ((w | h) == 0)
313 		return;
314 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
315 	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, p_clip_uv);
316 }
317 
is_pixel_opaque(int p_x,int p_y) const318 bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
319 
320 	if (!alpha_cache.is_valid()) {
321 		Ref<Image> img = get_data();
322 		if (img.is_valid()) {
323 			if (img->is_compressed()) { //must decompress, if compressed
324 				Ref<Image> decom = img->duplicate();
325 				decom->decompress();
326 				img = decom;
327 			}
328 			alpha_cache.instance();
329 			alpha_cache->create_from_image_alpha(img);
330 		}
331 	}
332 
333 	if (alpha_cache.is_valid()) {
334 
335 		int aw = int(alpha_cache->get_size().width);
336 		int ah = int(alpha_cache->get_size().height);
337 		if (aw == 0 || ah == 0) {
338 			return true;
339 		}
340 
341 		int x = p_x * aw / w;
342 		int y = p_y * ah / h;
343 
344 		x = CLAMP(x, 0, aw);
345 		y = CLAMP(y, 0, ah);
346 
347 		return alpha_cache->get_bit(Point2(x, y));
348 	}
349 
350 	return true;
351 }
352 
set_size_override(const Size2 & p_size)353 void ImageTexture::set_size_override(const Size2 &p_size) {
354 
355 	Size2 s = p_size;
356 	if (s.x != 0)
357 		w = s.x;
358 	if (s.y != 0)
359 		h = s.y;
360 	VisualServer::get_singleton()->texture_set_size_override(texture, w, h, 0);
361 }
362 
set_path(const String & p_path,bool p_take_over)363 void ImageTexture::set_path(const String &p_path, bool p_take_over) {
364 
365 	if (texture.is_valid()) {
366 		VisualServer::get_singleton()->texture_set_path(texture, p_path);
367 	}
368 
369 	Resource::set_path(p_path, p_take_over);
370 }
371 
set_storage(Storage p_storage)372 void ImageTexture::set_storage(Storage p_storage) {
373 
374 	storage = p_storage;
375 }
376 
get_storage() const377 ImageTexture::Storage ImageTexture::get_storage() const {
378 
379 	return storage;
380 }
381 
set_lossy_storage_quality(float p_lossy_storage_quality)382 void ImageTexture::set_lossy_storage_quality(float p_lossy_storage_quality) {
383 
384 	lossy_storage_quality = p_lossy_storage_quality;
385 }
386 
get_lossy_storage_quality() const387 float ImageTexture::get_lossy_storage_quality() const {
388 
389 	return lossy_storage_quality;
390 }
391 
_set_data(Dictionary p_data)392 void ImageTexture::_set_data(Dictionary p_data) {
393 
394 	Ref<Image> img = p_data["image"];
395 	ERR_FAIL_COND(!img.is_valid());
396 	uint32_t flags = p_data["flags"];
397 
398 	create_from_image(img, flags);
399 
400 	set_storage(Storage(p_data["storage"].operator int()));
401 	set_lossy_storage_quality(p_data["lossy_quality"]);
402 
403 	set_size_override(p_data["size"]);
404 };
405 
_bind_methods()406 void ImageTexture::_bind_methods() {
407 
408 	ClassDB::bind_method(D_METHOD("create", "width", "height", "format", "flags"), &ImageTexture::create, DEFVAL(FLAGS_DEFAULT));
409 	ClassDB::bind_method(D_METHOD("create_from_image", "image", "flags"), &ImageTexture::create_from_image, DEFVAL(FLAGS_DEFAULT));
410 	ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format);
411 #ifndef DISABLE_DEPRECATED
412 	ClassDB::bind_method(D_METHOD("load", "path"), &ImageTexture::load);
413 #endif
414 	ClassDB::bind_method(D_METHOD("set_data", "image"), &ImageTexture::set_data);
415 	ClassDB::bind_method(D_METHOD("set_storage", "mode"), &ImageTexture::set_storage);
416 	ClassDB::bind_method(D_METHOD("get_storage"), &ImageTexture::get_storage);
417 	ClassDB::bind_method(D_METHOD("set_lossy_storage_quality", "quality"), &ImageTexture::set_lossy_storage_quality);
418 	ClassDB::bind_method(D_METHOD("get_lossy_storage_quality"), &ImageTexture::get_lossy_storage_quality);
419 
420 	ClassDB::bind_method(D_METHOD("set_size_override", "size"), &ImageTexture::set_size_override);
421 	ClassDB::bind_method(D_METHOD("_reload_hook", "rid"), &ImageTexture::_reload_hook);
422 
423 	ADD_PROPERTY(PropertyInfo(Variant::INT, "storage", PROPERTY_HINT_ENUM, "Uncompressed,Compress Lossy,Compress Lossless"), "set_storage", "get_storage");
424 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "lossy_quality", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_lossy_storage_quality", "get_lossy_storage_quality");
425 
426 	BIND_ENUM_CONSTANT(STORAGE_RAW);
427 	BIND_ENUM_CONSTANT(STORAGE_COMPRESS_LOSSY);
428 	BIND_ENUM_CONSTANT(STORAGE_COMPRESS_LOSSLESS);
429 }
430 
ImageTexture()431 ImageTexture::ImageTexture() {
432 
433 	w = h = 0;
434 	flags = FLAGS_DEFAULT;
435 	texture = VisualServer::get_singleton()->texture_create();
436 	storage = STORAGE_RAW;
437 	lossy_storage_quality = 0.7;
438 	image_stored = false;
439 	format = Image::FORMAT_L8;
440 }
441 
~ImageTexture()442 ImageTexture::~ImageTexture() {
443 
444 	VisualServer::get_singleton()->free(texture);
445 }
446 
447 //////////////////////////////////////////
448 
set_path(const String & p_path,bool p_take_over)449 void StreamTexture::set_path(const String &p_path, bool p_take_over) {
450 
451 	if (texture.is_valid()) {
452 		VisualServer::get_singleton()->texture_set_path(texture, p_path);
453 	}
454 
455 	Resource::set_path(p_path, p_take_over);
456 }
457 
_requested_3d(void * p_ud)458 void StreamTexture::_requested_3d(void *p_ud) {
459 
460 	StreamTexture *st = (StreamTexture *)p_ud;
461 	Ref<StreamTexture> stex(st);
462 	ERR_FAIL_COND(!request_3d_callback);
463 	request_3d_callback(stex);
464 }
465 
_requested_srgb(void * p_ud)466 void StreamTexture::_requested_srgb(void *p_ud) {
467 
468 	StreamTexture *st = (StreamTexture *)p_ud;
469 	Ref<StreamTexture> stex(st);
470 	ERR_FAIL_COND(!request_srgb_callback);
471 	request_srgb_callback(stex);
472 }
473 
_requested_normal(void * p_ud)474 void StreamTexture::_requested_normal(void *p_ud) {
475 
476 	StreamTexture *st = (StreamTexture *)p_ud;
477 	Ref<StreamTexture> stex(st);
478 	ERR_FAIL_COND(!request_normal_callback);
479 	request_normal_callback(stex);
480 }
481 
482 StreamTexture::TextureFormatRequestCallback StreamTexture::request_3d_callback = NULL;
483 StreamTexture::TextureFormatRequestCallback StreamTexture::request_srgb_callback = NULL;
484 StreamTexture::TextureFormatRequestCallback StreamTexture::request_normal_callback = NULL;
485 
get_flags() const486 uint32_t StreamTexture::get_flags() const {
487 
488 	return flags;
489 }
get_format() const490 Image::Format StreamTexture::get_format() const {
491 
492 	return format;
493 }
494 
_load_data(const String & p_path,int & tw,int & th,int & tw_custom,int & th_custom,int & flags,Ref<Image> & image,int p_size_limit)495 Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, int &flags, Ref<Image> &image, int p_size_limit) {
496 
497 	alpha_cache.unref();
498 
499 	ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER);
500 
501 	FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
502 	ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
503 
504 	uint8_t header[4];
505 	f->get_buffer(header, 4);
506 	if (header[0] != 'G' || header[1] != 'D' || header[2] != 'S' || header[3] != 'T') {
507 		memdelete(f);
508 		ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'D' || header[2] != 'S' || header[3] != 'T', ERR_FILE_CORRUPT);
509 	}
510 
511 	tw = f->get_16();
512 	tw_custom = f->get_16();
513 	th = f->get_16();
514 	th_custom = f->get_16();
515 
516 	flags = f->get_32(); //texture flags!
517 	uint32_t df = f->get_32(); //data format
518 
519 	/*
520 	print_line("width: " + itos(tw));
521 	print_line("height: " + itos(th));
522 	print_line("flags: " + itos(flags));
523 	print_line("df: " + itos(df));
524 	*/
525 #ifdef TOOLS_ENABLED
526 
527 	if (request_3d_callback && df & FORMAT_BIT_DETECT_3D) {
528 		//print_line("request detect 3D at " + p_path);
529 		VS::get_singleton()->texture_set_detect_3d_callback(texture, _requested_3d, this);
530 	} else {
531 		//print_line("not requesting detect 3D at " + p_path);
532 		VS::get_singleton()->texture_set_detect_3d_callback(texture, NULL, NULL);
533 	}
534 
535 	if (request_srgb_callback && df & FORMAT_BIT_DETECT_SRGB) {
536 		//print_line("request detect srgb at " + p_path);
537 		VS::get_singleton()->texture_set_detect_srgb_callback(texture, _requested_srgb, this);
538 	} else {
539 		//print_line("not requesting detect srgb at " + p_path);
540 		VS::get_singleton()->texture_set_detect_srgb_callback(texture, NULL, NULL);
541 	}
542 
543 	if (request_srgb_callback && df & FORMAT_BIT_DETECT_NORMAL) {
544 		//print_line("request detect srgb at " + p_path);
545 		VS::get_singleton()->texture_set_detect_normal_callback(texture, _requested_normal, this);
546 	} else {
547 		//print_line("not requesting detect normal at " + p_path);
548 		VS::get_singleton()->texture_set_detect_normal_callback(texture, NULL, NULL);
549 	}
550 #endif
551 	if (!(df & FORMAT_BIT_STREAM)) {
552 		p_size_limit = 0;
553 	}
554 
555 	if (df & FORMAT_BIT_LOSSLESS || df & FORMAT_BIT_LOSSY) {
556 		//look for a PNG or WEBP file inside
557 
558 		int sw = tw;
559 		int sh = th;
560 
561 		uint32_t mipmaps = f->get_32();
562 		uint32_t size = f->get_32();
563 
564 		//print_line("mipmaps: " + itos(mipmaps));
565 
566 		while (mipmaps > 1 && p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) {
567 
568 			f->seek(f->get_position() + size);
569 			mipmaps = f->get_32();
570 			size = f->get_32();
571 
572 			sw = MAX(sw >> 1, 1);
573 			sh = MAX(sh >> 1, 1);
574 			mipmaps--;
575 		}
576 
577 		//mipmaps need to be read independently, they will be later combined
578 		Vector<Ref<Image> > mipmap_images;
579 		int total_size = 0;
580 
581 		for (uint32_t i = 0; i < mipmaps; i++) {
582 
583 			if (i) {
584 				size = f->get_32();
585 			}
586 
587 			PoolVector<uint8_t> pv;
588 			pv.resize(size);
589 			{
590 				PoolVector<uint8_t>::Write w = pv.write();
591 				f->get_buffer(w.ptr(), size);
592 			}
593 
594 			Ref<Image> img;
595 			if (df & FORMAT_BIT_LOSSLESS) {
596 				img = Image::lossless_unpacker(pv);
597 			} else {
598 				img = Image::lossy_unpacker(pv);
599 			}
600 
601 			if (img.is_null() || img->empty()) {
602 				memdelete(f);
603 				ERR_FAIL_COND_V(img.is_null() || img->empty(), ERR_FILE_CORRUPT);
604 			}
605 
606 			total_size += img->get_data().size();
607 
608 			mipmap_images.push_back(img);
609 		}
610 
611 		//print_line("mipmap read total: " + itos(mipmap_images.size()));
612 
613 		memdelete(f); //no longer needed
614 
615 		if (mipmap_images.size() == 1) {
616 
617 			image = mipmap_images[0];
618 			return OK;
619 
620 		} else {
621 			PoolVector<uint8_t> img_data;
622 			img_data.resize(total_size);
623 
624 			{
625 				PoolVector<uint8_t>::Write w = img_data.write();
626 
627 				int ofs = 0;
628 				for (int i = 0; i < mipmap_images.size(); i++) {
629 
630 					PoolVector<uint8_t> id = mipmap_images[i]->get_data();
631 					int len = id.size();
632 					PoolVector<uint8_t>::Read r = id.read();
633 					copymem(&w[ofs], r.ptr(), len);
634 					ofs += len;
635 				}
636 			}
637 
638 			image->create(sw, sh, true, mipmap_images[0]->get_format(), img_data);
639 			return OK;
640 		}
641 
642 	} else {
643 
644 		//look for regular format
645 		Image::Format format = (Image::Format)(df & FORMAT_MASK_IMAGE_FORMAT);
646 		bool mipmaps = df & FORMAT_BIT_HAS_MIPMAPS;
647 
648 		if (!mipmaps) {
649 			int size = Image::get_image_data_size(tw, th, format, false);
650 
651 			PoolVector<uint8_t> img_data;
652 			img_data.resize(size);
653 
654 			{
655 				PoolVector<uint8_t>::Write w = img_data.write();
656 				f->get_buffer(w.ptr(), size);
657 			}
658 
659 			memdelete(f);
660 
661 			image->create(tw, th, false, format, img_data);
662 			return OK;
663 		} else {
664 
665 			int sw = tw;
666 			int sh = th;
667 
668 			int mipmaps2 = Image::get_image_required_mipmaps(tw, th, format);
669 			int total_size = Image::get_image_data_size(tw, th, format, true);
670 			int idx = 0;
671 
672 			while (mipmaps2 > 1 && p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) {
673 
674 				sw = MAX(sw >> 1, 1);
675 				sh = MAX(sh >> 1, 1);
676 				mipmaps2--;
677 				idx++;
678 			}
679 
680 			int ofs = Image::get_image_mipmap_offset(tw, th, format, idx);
681 
682 			if (total_size - ofs <= 0) {
683 				memdelete(f);
684 				ERR_FAIL_V(ERR_FILE_CORRUPT);
685 			}
686 
687 			f->seek(f->get_position() + ofs);
688 
689 			PoolVector<uint8_t> img_data;
690 			img_data.resize(total_size - ofs);
691 
692 			{
693 				PoolVector<uint8_t>::Write w = img_data.write();
694 				int bytes = f->get_buffer(w.ptr(), total_size - ofs);
695 				//print_line("requested read: " + itos(total_size - ofs) + " but got: " + itos(bytes));
696 
697 				memdelete(f);
698 
699 				int expected = total_size - ofs;
700 				if (bytes < expected) {
701 					//this is a compatibility workaround for older format, which saved less mipmaps2. It is still recommended the image is reimported.
702 					zeromem(w.ptr() + bytes, (expected - bytes));
703 				} else if (bytes != expected) {
704 					ERR_FAIL_V(ERR_FILE_CORRUPT);
705 				}
706 			}
707 
708 			image->create(sw, sh, true, format, img_data);
709 
710 			return OK;
711 		}
712 	}
713 
714 	return ERR_BUG; //unreachable
715 }
716 
load(const String & p_path)717 Error StreamTexture::load(const String &p_path) {
718 
719 	int lw, lh, lwc, lhc, lflags;
720 	Ref<Image> image;
721 	image.instance();
722 	Error err = _load_data(p_path, lw, lh, lwc, lhc, lflags, image);
723 	if (err)
724 		return err;
725 
726 	if (get_path() == String()) {
727 		//temporarily set path if no path set for resource, helps find errors
728 		VisualServer::get_singleton()->texture_set_path(texture, p_path);
729 	}
730 	VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, image->get_format(), VS::TEXTURE_TYPE_2D, lflags);
731 	VS::get_singleton()->texture_set_data(texture, image);
732 	if (lwc || lhc) {
733 		VS::get_singleton()->texture_set_size_override(texture, lwc, lhc, 0);
734 	} else {
735 	}
736 
737 	w = lwc ? lwc : lw;
738 	h = lhc ? lhc : lh;
739 	flags = lflags;
740 	path_to_file = p_path;
741 	format = image->get_format();
742 
743 	_change_notify();
744 	emit_changed();
745 	return OK;
746 }
get_load_path() const747 String StreamTexture::get_load_path() const {
748 
749 	return path_to_file;
750 }
751 
get_width() const752 int StreamTexture::get_width() const {
753 
754 	return w;
755 }
get_height() const756 int StreamTexture::get_height() const {
757 
758 	return h;
759 }
get_rid() const760 RID StreamTexture::get_rid() const {
761 
762 	return texture;
763 }
764 
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const765 void StreamTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
766 
767 	if ((w | h) == 0)
768 		return;
769 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
770 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid);
771 }
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const772 void StreamTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
773 
774 	if ((w | h) == 0)
775 		return;
776 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
777 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid);
778 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map,bool p_clip_uv) const779 void StreamTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
780 
781 	if ((w | h) == 0)
782 		return;
783 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
784 	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, p_clip_uv);
785 }
786 
has_alpha() const787 bool StreamTexture::has_alpha() const {
788 
789 	return false;
790 }
791 
get_data() const792 Ref<Image> StreamTexture::get_data() const {
793 
794 	return VS::get_singleton()->texture_get_data(texture);
795 }
796 
is_pixel_opaque(int p_x,int p_y) const797 bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const {
798 
799 	if (!alpha_cache.is_valid()) {
800 		Ref<Image> img = get_data();
801 		if (img.is_valid()) {
802 			if (img->is_compressed()) { //must decompress, if compressed
803 				Ref<Image> decom = img->duplicate();
804 				decom->decompress();
805 				img = decom;
806 			}
807 
808 			alpha_cache.instance();
809 			alpha_cache->create_from_image_alpha(img);
810 		}
811 	}
812 
813 	if (alpha_cache.is_valid()) {
814 
815 		int aw = int(alpha_cache->get_size().width);
816 		int ah = int(alpha_cache->get_size().height);
817 		if (aw == 0 || ah == 0) {
818 			return true;
819 		}
820 
821 		int x = p_x * aw / w;
822 		int y = p_y * ah / h;
823 
824 		x = CLAMP(x, 0, aw);
825 		y = CLAMP(y, 0, ah);
826 
827 		return alpha_cache->get_bit(Point2(x, y));
828 	}
829 
830 	return true;
831 }
set_flags(uint32_t p_flags)832 void StreamTexture::set_flags(uint32_t p_flags) {
833 	flags = p_flags;
834 	VS::get_singleton()->texture_set_flags(texture, flags);
835 	_change_notify("flags");
836 	emit_changed();
837 }
838 
reload_from_file()839 void StreamTexture::reload_from_file() {
840 
841 	String path = get_path();
842 	if (!path.is_resource_file())
843 		return;
844 
845 	path = ResourceLoader::path_remap(path); //remap for translation
846 	path = ResourceLoader::import_remap(path); //remap for import
847 	if (!path.is_resource_file())
848 		return;
849 
850 	load(path);
851 }
852 
_validate_property(PropertyInfo & property) const853 void StreamTexture::_validate_property(PropertyInfo &property) const {
854 	if (property.name == "flags") {
855 		property.usage = PROPERTY_USAGE_NOEDITOR;
856 	}
857 }
858 
_bind_methods()859 void StreamTexture::_bind_methods() {
860 
861 	ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture::load);
862 	ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture::get_load_path);
863 
864 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path");
865 }
866 
StreamTexture()867 StreamTexture::StreamTexture() {
868 
869 	format = Image::FORMAT_MAX;
870 	flags = 0;
871 	w = 0;
872 	h = 0;
873 
874 	texture = VS::get_singleton()->texture_create();
875 }
876 
~StreamTexture()877 StreamTexture::~StreamTexture() {
878 
879 	VS::get_singleton()->free(texture);
880 }
881 
load(const String & p_path,const String & p_original_path,Error * r_error)882 RES ResourceFormatLoaderStreamTexture::load(const String &p_path, const String &p_original_path, Error *r_error) {
883 
884 	Ref<StreamTexture> st;
885 	st.instance();
886 	Error err = st->load(p_path);
887 	if (r_error)
888 		*r_error = err;
889 	if (err != OK)
890 		return RES();
891 
892 	return st;
893 }
894 
get_recognized_extensions(List<String> * p_extensions) const895 void ResourceFormatLoaderStreamTexture::get_recognized_extensions(List<String> *p_extensions) const {
896 
897 	p_extensions->push_back("stex");
898 }
handles_type(const String & p_type) const899 bool ResourceFormatLoaderStreamTexture::handles_type(const String &p_type) const {
900 	return p_type == "StreamTexture";
901 }
get_resource_type(const String & p_path) const902 String ResourceFormatLoaderStreamTexture::get_resource_type(const String &p_path) const {
903 
904 	if (p_path.get_extension().to_lower() == "stex")
905 		return "StreamTexture";
906 	return "";
907 }
908 
909 //////////////////////////////////////////
910 
get_width() const911 int AtlasTexture::get_width() const {
912 
913 	if (region.size.width == 0) {
914 		if (atlas.is_valid())
915 			return atlas->get_width();
916 		return 1;
917 	} else {
918 		return region.size.width + margin.size.width;
919 	}
920 }
get_height() const921 int AtlasTexture::get_height() const {
922 
923 	if (region.size.height == 0) {
924 		if (atlas.is_valid())
925 			return atlas->get_height();
926 		return 1;
927 	} else {
928 		return region.size.height + margin.size.height;
929 	}
930 }
get_rid() const931 RID AtlasTexture::get_rid() const {
932 
933 	if (atlas.is_valid())
934 		return atlas->get_rid();
935 
936 	return RID();
937 }
938 
has_alpha() const939 bool AtlasTexture::has_alpha() const {
940 
941 	if (atlas.is_valid())
942 		return atlas->has_alpha();
943 
944 	return false;
945 }
946 
set_flags(uint32_t p_flags)947 void AtlasTexture::set_flags(uint32_t p_flags) {
948 
949 	if (atlas.is_valid())
950 		atlas->set_flags(p_flags);
951 }
952 
get_flags() const953 uint32_t AtlasTexture::get_flags() const {
954 
955 	if (atlas.is_valid())
956 		return atlas->get_flags();
957 
958 	return 0;
959 }
960 
set_atlas(const Ref<Texture> & p_atlas)961 void AtlasTexture::set_atlas(const Ref<Texture> &p_atlas) {
962 
963 	ERR_FAIL_COND(p_atlas == this);
964 	if (atlas == p_atlas)
965 		return;
966 	atlas = p_atlas;
967 	emit_changed();
968 	_change_notify("atlas");
969 }
get_atlas() const970 Ref<Texture> AtlasTexture::get_atlas() const {
971 
972 	return atlas;
973 }
974 
set_region(const Rect2 & p_region)975 void AtlasTexture::set_region(const Rect2 &p_region) {
976 
977 	if (region == p_region)
978 		return;
979 	region = p_region;
980 	emit_changed();
981 	_change_notify("region");
982 }
983 
get_region() const984 Rect2 AtlasTexture::get_region() const {
985 
986 	return region;
987 }
988 
set_margin(const Rect2 & p_margin)989 void AtlasTexture::set_margin(const Rect2 &p_margin) {
990 
991 	if (margin == p_margin)
992 		return;
993 	margin = p_margin;
994 	emit_changed();
995 	_change_notify("margin");
996 }
997 
get_margin() const998 Rect2 AtlasTexture::get_margin() const {
999 
1000 	return margin;
1001 }
1002 
set_filter_clip(const bool p_enable)1003 void AtlasTexture::set_filter_clip(const bool p_enable) {
1004 
1005 	filter_clip = p_enable;
1006 	emit_changed();
1007 	_change_notify("filter_clip");
1008 }
1009 
has_filter_clip() const1010 bool AtlasTexture::has_filter_clip() const {
1011 
1012 	return filter_clip;
1013 }
1014 
_bind_methods()1015 void AtlasTexture::_bind_methods() {
1016 
1017 	ClassDB::bind_method(D_METHOD("set_atlas", "atlas"), &AtlasTexture::set_atlas);
1018 	ClassDB::bind_method(D_METHOD("get_atlas"), &AtlasTexture::get_atlas);
1019 
1020 	ClassDB::bind_method(D_METHOD("set_region", "region"), &AtlasTexture::set_region);
1021 	ClassDB::bind_method(D_METHOD("get_region"), &AtlasTexture::get_region);
1022 
1023 	ClassDB::bind_method(D_METHOD("set_margin", "margin"), &AtlasTexture::set_margin);
1024 	ClassDB::bind_method(D_METHOD("get_margin"), &AtlasTexture::get_margin);
1025 
1026 	ClassDB::bind_method(D_METHOD("set_filter_clip", "enable"), &AtlasTexture::set_filter_clip);
1027 	ClassDB::bind_method(D_METHOD("has_filter_clip"), &AtlasTexture::has_filter_clip);
1028 
1029 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_atlas", "get_atlas");
1030 	ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region"), "set_region", "get_region");
1031 	ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin"), "set_margin", "get_margin");
1032 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_clip"), "set_filter_clip", "has_filter_clip");
1033 }
1034 
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const1035 void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
1036 
1037 	if (!atlas.is_valid())
1038 		return;
1039 
1040 	Rect2 rc = region;
1041 
1042 	if (rc.size.width == 0) {
1043 		rc.size.width = atlas->get_width();
1044 	}
1045 
1046 	if (rc.size.height == 0) {
1047 		rc.size.height = atlas->get_height();
1048 	}
1049 
1050 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
1051 	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, filter_clip);
1052 }
1053 
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const1054 void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
1055 
1056 	if (!atlas.is_valid())
1057 		return;
1058 
1059 	Rect2 rc = region;
1060 
1061 	if (rc.size.width == 0) {
1062 		rc.size.width = atlas->get_width();
1063 	}
1064 
1065 	if (rc.size.height == 0) {
1066 		rc.size.height = atlas->get_height();
1067 	}
1068 
1069 	Vector2 scale = p_rect.size / (region.size + margin.size);
1070 	Rect2 dr(p_rect.position + margin.position * scale, rc.size * scale);
1071 
1072 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
1073 	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, filter_clip);
1074 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map,bool p_clip_uv) const1075 void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
1076 
1077 	//this might not necessarily work well if using a rect, needs to be fixed properly
1078 	if (!atlas.is_valid())
1079 		return;
1080 
1081 	Rect2 dr;
1082 	Rect2 src_c;
1083 	get_rect_region(p_rect, p_src_rect, dr, src_c);
1084 
1085 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
1086 	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, filter_clip);
1087 }
1088 
get_rect_region(const Rect2 & p_rect,const Rect2 & p_src_rect,Rect2 & r_rect,Rect2 & r_src_rect) const1089 bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
1090 
1091 	if (!atlas.is_valid())
1092 		return false;
1093 
1094 	Rect2 rc = region;
1095 
1096 	Rect2 src = p_src_rect;
1097 	if (src.size == Size2()) {
1098 		src.size = rc.size;
1099 	}
1100 	Vector2 scale = p_rect.size / src.size;
1101 
1102 	src.position += (rc.position - margin.position);
1103 	Rect2 src_c = rc.clip(src);
1104 	if (src_c.size == Size2())
1105 		return false;
1106 	Vector2 ofs = (src_c.position - src.position);
1107 
1108 	if (scale.x < 0) {
1109 		float mx = (margin.size.width - margin.position.x);
1110 		mx -= margin.position.x;
1111 		ofs.x = -(ofs.x + mx);
1112 	}
1113 	if (scale.y < 0) {
1114 		float my = margin.size.height - margin.position.y;
1115 		my -= margin.position.y;
1116 		ofs.y = -(ofs.y + my);
1117 	}
1118 	Rect2 dr(p_rect.position + ofs * scale, src_c.size * scale);
1119 
1120 	r_rect = dr;
1121 	r_src_rect = src_c;
1122 	return true;
1123 }
1124 
is_pixel_opaque(int p_x,int p_y) const1125 bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const {
1126 
1127 	if (!atlas.is_valid())
1128 		return true;
1129 
1130 	int x = p_x + region.position.x - margin.position.x;
1131 	int y = p_y + region.position.y - margin.position.y;
1132 
1133 	// margin edge may outside of atlas
1134 	if (x < 0 || x >= atlas->get_width()) return false;
1135 	if (y < 0 || y >= atlas->get_height()) return false;
1136 
1137 	return atlas->is_pixel_opaque(x, y);
1138 }
1139 
AtlasTexture()1140 AtlasTexture::AtlasTexture() {
1141 	filter_clip = false;
1142 }
1143 
1144 /////////////////////////////////////////
1145 
get_width() const1146 int MeshTexture::get_width() const {
1147 	return size.width;
1148 }
get_height() const1149 int MeshTexture::get_height() const {
1150 	return size.height;
1151 }
get_rid() const1152 RID MeshTexture::get_rid() const {
1153 	return RID();
1154 }
1155 
has_alpha() const1156 bool MeshTexture::has_alpha() const {
1157 	return false;
1158 }
1159 
set_flags(uint32_t p_flags)1160 void MeshTexture::set_flags(uint32_t p_flags) {
1161 }
1162 
get_flags() const1163 uint32_t MeshTexture::get_flags() const {
1164 	return 0;
1165 }
1166 
set_mesh(const Ref<Mesh> & p_mesh)1167 void MeshTexture::set_mesh(const Ref<Mesh> &p_mesh) {
1168 	mesh = p_mesh;
1169 }
get_mesh() const1170 Ref<Mesh> MeshTexture::get_mesh() const {
1171 	return mesh;
1172 }
1173 
set_image_size(const Size2 & p_size)1174 void MeshTexture::set_image_size(const Size2 &p_size) {
1175 	size = p_size;
1176 }
1177 
get_image_size() const1178 Size2 MeshTexture::get_image_size() const {
1179 
1180 	return size;
1181 }
1182 
set_base_texture(const Ref<Texture> & p_texture)1183 void MeshTexture::set_base_texture(const Ref<Texture> &p_texture) {
1184 	base_texture = p_texture;
1185 }
1186 
get_base_texture() const1187 Ref<Texture> MeshTexture::get_base_texture() const {
1188 	return base_texture;
1189 }
1190 
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const1191 void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
1192 
1193 	if (mesh.is_null() || base_texture.is_null()) {
1194 		return;
1195 	}
1196 	Transform2D xform;
1197 	xform.set_origin(p_pos);
1198 	if (p_transpose) {
1199 		SWAP(xform.elements[0][1], xform.elements[1][0]);
1200 		SWAP(xform.elements[0][0], xform.elements[1][1]);
1201 	}
1202 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
1203 	VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid);
1204 }
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const1205 void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
1206 	if (mesh.is_null() || base_texture.is_null()) {
1207 		return;
1208 	}
1209 	Transform2D xform;
1210 	Vector2 origin = p_rect.position;
1211 	if (p_rect.size.x < 0) {
1212 		origin.x += size.x;
1213 	}
1214 	if (p_rect.size.y < 0) {
1215 		origin.y += size.y;
1216 	}
1217 	xform.set_origin(origin);
1218 	xform.set_scale(p_rect.size / size);
1219 
1220 	if (p_transpose) {
1221 		SWAP(xform.elements[0][1], xform.elements[1][0]);
1222 		SWAP(xform.elements[0][0], xform.elements[1][1]);
1223 	}
1224 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
1225 	VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid);
1226 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map,bool p_clip_uv) const1227 void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
1228 
1229 	if (mesh.is_null() || base_texture.is_null()) {
1230 		return;
1231 	}
1232 	Transform2D xform;
1233 	Vector2 origin = p_rect.position;
1234 	if (p_rect.size.x < 0) {
1235 		origin.x += size.x;
1236 	}
1237 	if (p_rect.size.y < 0) {
1238 		origin.y += size.y;
1239 	}
1240 	xform.set_origin(origin);
1241 	xform.set_scale(p_rect.size / size);
1242 
1243 	if (p_transpose) {
1244 		SWAP(xform.elements[0][1], xform.elements[1][0]);
1245 		SWAP(xform.elements[0][0], xform.elements[1][1]);
1246 	}
1247 	RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
1248 	VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid);
1249 }
get_rect_region(const Rect2 & p_rect,const Rect2 & p_src_rect,Rect2 & r_rect,Rect2 & r_src_rect) const1250 bool MeshTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
1251 	r_rect = p_rect;
1252 	r_src_rect = p_src_rect;
1253 	return true;
1254 }
1255 
is_pixel_opaque(int p_x,int p_y) const1256 bool MeshTexture::is_pixel_opaque(int p_x, int p_y) const {
1257 	return true;
1258 }
1259 
_bind_methods()1260 void MeshTexture::_bind_methods() {
1261 	ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshTexture::set_mesh);
1262 	ClassDB::bind_method(D_METHOD("get_mesh"), &MeshTexture::get_mesh);
1263 	ClassDB::bind_method(D_METHOD("set_image_size", "size"), &MeshTexture::set_image_size);
1264 	ClassDB::bind_method(D_METHOD("get_image_size"), &MeshTexture::get_image_size);
1265 	ClassDB::bind_method(D_METHOD("set_base_texture", "texture"), &MeshTexture::set_base_texture);
1266 	ClassDB::bind_method(D_METHOD("get_base_texture"), &MeshTexture::get_base_texture);
1267 
1268 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
1269 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_base_texture", "get_base_texture");
1270 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1"), "set_image_size", "get_image_size");
1271 }
1272 
MeshTexture()1273 MeshTexture::MeshTexture() {
1274 }
1275 
1276 //////////////////////////////////////////
1277 
get_width() const1278 int LargeTexture::get_width() const {
1279 
1280 	return size.width;
1281 }
get_height() const1282 int LargeTexture::get_height() const {
1283 
1284 	return size.height;
1285 }
get_rid() const1286 RID LargeTexture::get_rid() const {
1287 
1288 	return RID();
1289 }
1290 
has_alpha() const1291 bool LargeTexture::has_alpha() const {
1292 
1293 	for (int i = 0; i < pieces.size(); i++) {
1294 		if (pieces[i].texture->has_alpha())
1295 			return true;
1296 	}
1297 
1298 	return false;
1299 }
1300 
set_flags(uint32_t p_flags)1301 void LargeTexture::set_flags(uint32_t p_flags) {
1302 
1303 	for (int i = 0; i < pieces.size(); i++) {
1304 		pieces.write[i].texture->set_flags(p_flags);
1305 	}
1306 }
1307 
get_flags() const1308 uint32_t LargeTexture::get_flags() const {
1309 
1310 	if (pieces.size())
1311 		return pieces[0].texture->get_flags();
1312 
1313 	return 0;
1314 }
1315 
add_piece(const Point2 & p_offset,const Ref<Texture> & p_texture)1316 int LargeTexture::add_piece(const Point2 &p_offset, const Ref<Texture> &p_texture) {
1317 
1318 	ERR_FAIL_COND_V(p_texture.is_null(), -1);
1319 	Piece p;
1320 	p.offset = p_offset;
1321 	p.texture = p_texture;
1322 	pieces.push_back(p);
1323 
1324 	return pieces.size() - 1;
1325 }
1326 
set_piece_offset(int p_idx,const Point2 & p_offset)1327 void LargeTexture::set_piece_offset(int p_idx, const Point2 &p_offset) {
1328 
1329 	ERR_FAIL_INDEX(p_idx, pieces.size());
1330 	pieces.write[p_idx].offset = p_offset;
1331 };
1332 
set_piece_texture(int p_idx,const Ref<Texture> & p_texture)1333 void LargeTexture::set_piece_texture(int p_idx, const Ref<Texture> &p_texture) {
1334 
1335 	ERR_FAIL_COND(p_texture == this);
1336 	ERR_FAIL_COND(p_texture.is_null());
1337 	ERR_FAIL_INDEX(p_idx, pieces.size());
1338 	pieces.write[p_idx].texture = p_texture;
1339 };
1340 
set_size(const Size2 & p_size)1341 void LargeTexture::set_size(const Size2 &p_size) {
1342 
1343 	size = p_size;
1344 }
clear()1345 void LargeTexture::clear() {
1346 
1347 	pieces.clear();
1348 	size = Size2i();
1349 }
1350 
_get_data() const1351 Array LargeTexture::_get_data() const {
1352 
1353 	Array arr;
1354 	for (int i = 0; i < pieces.size(); i++) {
1355 		arr.push_back(pieces[i].offset);
1356 		arr.push_back(pieces[i].texture);
1357 	}
1358 	arr.push_back(Size2(size));
1359 	return arr;
1360 }
_set_data(const Array & p_array)1361 void LargeTexture::_set_data(const Array &p_array) {
1362 
1363 	ERR_FAIL_COND(p_array.size() < 1);
1364 	ERR_FAIL_COND(!(p_array.size() & 1));
1365 	clear();
1366 	for (int i = 0; i < p_array.size() - 1; i += 2) {
1367 		add_piece(p_array[i], p_array[i + 1]);
1368 	}
1369 	size = Size2(p_array[p_array.size() - 1]);
1370 }
1371 
get_piece_count() const1372 int LargeTexture::get_piece_count() const {
1373 
1374 	return pieces.size();
1375 }
get_piece_offset(int p_idx) const1376 Vector2 LargeTexture::get_piece_offset(int p_idx) const {
1377 
1378 	ERR_FAIL_INDEX_V(p_idx, pieces.size(), Vector2());
1379 	return pieces[p_idx].offset;
1380 }
get_piece_texture(int p_idx) const1381 Ref<Texture> LargeTexture::get_piece_texture(int p_idx) const {
1382 
1383 	ERR_FAIL_INDEX_V(p_idx, pieces.size(), Ref<Texture>());
1384 	return pieces[p_idx].texture;
1385 }
to_image() const1386 Ref<Image> LargeTexture::to_image() const {
1387 
1388 	Ref<Image> img = memnew(Image(this->get_width(), this->get_height(), false, Image::FORMAT_RGBA8));
1389 	for (int i = 0; i < pieces.size(); i++) {
1390 
1391 		Ref<Image> src_img = pieces[i].texture->get_data();
1392 		img->blit_rect(src_img, Rect2(0, 0, src_img->get_width(), src_img->get_height()), pieces[i].offset);
1393 	}
1394 
1395 	return img;
1396 }
1397 
_bind_methods()1398 void LargeTexture::_bind_methods() {
1399 
1400 	ClassDB::bind_method(D_METHOD("add_piece", "ofs", "texture"), &LargeTexture::add_piece);
1401 	ClassDB::bind_method(D_METHOD("set_piece_offset", "idx", "ofs"), &LargeTexture::set_piece_offset);
1402 	ClassDB::bind_method(D_METHOD("set_piece_texture", "idx", "texture"), &LargeTexture::set_piece_texture);
1403 	ClassDB::bind_method(D_METHOD("set_size", "size"), &LargeTexture::set_size);
1404 	ClassDB::bind_method(D_METHOD("clear"), &LargeTexture::clear);
1405 
1406 	ClassDB::bind_method(D_METHOD("get_piece_count"), &LargeTexture::get_piece_count);
1407 	ClassDB::bind_method(D_METHOD("get_piece_offset", "idx"), &LargeTexture::get_piece_offset);
1408 	ClassDB::bind_method(D_METHOD("get_piece_texture", "idx"), &LargeTexture::get_piece_texture);
1409 
1410 	ClassDB::bind_method(D_METHOD("_set_data", "data"), &LargeTexture::_set_data);
1411 	ClassDB::bind_method(D_METHOD("_get_data"), &LargeTexture::_get_data);
1412 
1413 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
1414 }
1415 
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const1416 void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
1417 
1418 	for (int i = 0; i < pieces.size(); i++) {
1419 
1420 		// TODO
1421 		pieces[i].texture->draw(p_canvas_item, pieces[i].offset + p_pos, p_modulate, p_transpose, p_normal_map);
1422 	}
1423 }
1424 
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map) const1425 void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
1426 
1427 	//tiling not supported for this
1428 	if (size.x == 0 || size.y == 0)
1429 		return;
1430 
1431 	Size2 scale = p_rect.size / size;
1432 
1433 	for (int i = 0; i < pieces.size(); i++) {
1434 
1435 		// TODO
1436 		pieces[i].texture->draw_rect(p_canvas_item, Rect2(pieces[i].offset * scale + p_rect.position, pieces[i].texture->get_size() * scale), false, p_modulate, p_transpose, p_normal_map);
1437 	}
1438 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose,const Ref<Texture> & p_normal_map,bool p_clip_uv) const1439 void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
1440 
1441 	//tiling not supported for this
1442 	if (p_src_rect.size.x == 0 || p_src_rect.size.y == 0)
1443 		return;
1444 
1445 	Size2 scale = p_rect.size / p_src_rect.size;
1446 
1447 	for (int i = 0; i < pieces.size(); i++) {
1448 
1449 		// TODO
1450 		Rect2 rect(pieces[i].offset, pieces[i].texture->get_size());
1451 		if (!p_src_rect.intersects(rect))
1452 			continue;
1453 		Rect2 local = p_src_rect.clip(rect);
1454 		Rect2 target = local;
1455 		target.size *= scale;
1456 		target.position = p_rect.position + (p_src_rect.position + rect.position) * scale;
1457 		local.position -= rect.position;
1458 		pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose, p_normal_map, false);
1459 	}
1460 }
1461 
is_pixel_opaque(int p_x,int p_y) const1462 bool LargeTexture::is_pixel_opaque(int p_x, int p_y) const {
1463 
1464 	for (int i = 0; i < pieces.size(); i++) {
1465 
1466 		// TODO
1467 		if (!pieces[i].texture.is_valid())
1468 			continue;
1469 
1470 		Rect2 rect(pieces[i].offset, pieces[i].texture->get_size());
1471 		if (rect.has_point(Point2(p_x, p_y))) {
1472 			return pieces[i].texture->is_pixel_opaque(p_x - rect.position.x, p_y - rect.position.y);
1473 		}
1474 	}
1475 
1476 	return true;
1477 }
1478 
LargeTexture()1479 LargeTexture::LargeTexture() {
1480 }
1481 
1482 ///////////////////////////////////////////////
1483 
set_flags(uint32_t p_flags)1484 void CubeMap::set_flags(uint32_t p_flags) {
1485 
1486 	flags = p_flags;
1487 	if (_is_valid())
1488 		VS::get_singleton()->texture_set_flags(cubemap, flags);
1489 }
1490 
get_flags() const1491 uint32_t CubeMap::get_flags() const {
1492 
1493 	return flags;
1494 }
1495 
set_side(Side p_side,const Ref<Image> & p_image)1496 void CubeMap::set_side(Side p_side, const Ref<Image> &p_image) {
1497 
1498 	ERR_FAIL_COND(p_image.is_null());
1499 	ERR_FAIL_COND(p_image->empty());
1500 	ERR_FAIL_INDEX(p_side, 6);
1501 
1502 	if (!_is_valid()) {
1503 		format = p_image->get_format();
1504 		w = p_image->get_width();
1505 		h = p_image->get_height();
1506 		VS::get_singleton()->texture_allocate(cubemap, w, h, 0, p_image->get_format(), VS::TEXTURE_TYPE_CUBEMAP, flags);
1507 	}
1508 
1509 	VS::get_singleton()->texture_set_data(cubemap, p_image, VS::CubeMapSide(p_side));
1510 	valid[p_side] = true;
1511 }
1512 
get_side(Side p_side) const1513 Ref<Image> CubeMap::get_side(Side p_side) const {
1514 
1515 	ERR_FAIL_INDEX_V(p_side, 6, Ref<Image>());
1516 	if (!valid[p_side])
1517 		return Ref<Image>();
1518 	return VS::get_singleton()->texture_get_data(cubemap, VS::CubeMapSide(p_side));
1519 }
1520 
get_format() const1521 Image::Format CubeMap::get_format() const {
1522 
1523 	return format;
1524 }
get_width() const1525 int CubeMap::get_width() const {
1526 
1527 	return w;
1528 }
get_height() const1529 int CubeMap::get_height() const {
1530 
1531 	return h;
1532 }
1533 
get_rid() const1534 RID CubeMap::get_rid() const {
1535 
1536 	return cubemap;
1537 }
1538 
set_storage(Storage p_storage)1539 void CubeMap::set_storage(Storage p_storage) {
1540 
1541 	storage = p_storage;
1542 }
1543 
get_storage() const1544 CubeMap::Storage CubeMap::get_storage() const {
1545 
1546 	return storage;
1547 }
1548 
set_lossy_storage_quality(float p_lossy_storage_quality)1549 void CubeMap::set_lossy_storage_quality(float p_lossy_storage_quality) {
1550 
1551 	lossy_storage_quality = p_lossy_storage_quality;
1552 }
1553 
get_lossy_storage_quality() const1554 float CubeMap::get_lossy_storage_quality() const {
1555 
1556 	return lossy_storage_quality;
1557 }
1558 
set_path(const String & p_path,bool p_take_over)1559 void CubeMap::set_path(const String &p_path, bool p_take_over) {
1560 
1561 	if (cubemap.is_valid()) {
1562 		VisualServer::get_singleton()->texture_set_path(cubemap, p_path);
1563 	}
1564 
1565 	Resource::set_path(p_path, p_take_over);
1566 }
1567 
_set(const StringName & p_name,const Variant & p_value)1568 bool CubeMap::_set(const StringName &p_name, const Variant &p_value) {
1569 
1570 	if (p_name == "side/left") {
1571 		set_side(SIDE_LEFT, p_value);
1572 	} else if (p_name == "side/right") {
1573 		set_side(SIDE_RIGHT, p_value);
1574 	} else if (p_name == "side/bottom") {
1575 		set_side(SIDE_BOTTOM, p_value);
1576 	} else if (p_name == "side/top") {
1577 		set_side(SIDE_TOP, p_value);
1578 	} else if (p_name == "side/front") {
1579 		set_side(SIDE_FRONT, p_value);
1580 	} else if (p_name == "side/back") {
1581 		set_side(SIDE_BACK, p_value);
1582 	} else if (p_name == "storage") {
1583 		storage = Storage(p_value.operator int());
1584 	} else if (p_name == "lossy_quality") {
1585 		lossy_storage_quality = p_value;
1586 	} else
1587 		return false;
1588 
1589 	return true;
1590 }
1591 
_get(const StringName & p_name,Variant & r_ret) const1592 bool CubeMap::_get(const StringName &p_name, Variant &r_ret) const {
1593 
1594 	if (p_name == "side/left") {
1595 		r_ret = get_side(SIDE_LEFT);
1596 	} else if (p_name == "side/right") {
1597 		r_ret = get_side(SIDE_RIGHT);
1598 	} else if (p_name == "side/bottom") {
1599 		r_ret = get_side(SIDE_BOTTOM);
1600 	} else if (p_name == "side/top") {
1601 		r_ret = get_side(SIDE_TOP);
1602 	} else if (p_name == "side/front") {
1603 		r_ret = get_side(SIDE_FRONT);
1604 	} else if (p_name == "side/back") {
1605 		r_ret = get_side(SIDE_BACK);
1606 	} else if (p_name == "storage") {
1607 		r_ret = storage;
1608 	} else if (p_name == "lossy_quality") {
1609 		r_ret = lossy_storage_quality;
1610 	} else
1611 		return false;
1612 
1613 	return true;
1614 }
1615 
_get_property_list(List<PropertyInfo> * p_list) const1616 void CubeMap::_get_property_list(List<PropertyInfo> *p_list) const {
1617 
1618 	p_list->push_back(PropertyInfo(Variant::OBJECT, "side/left", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
1619 	p_list->push_back(PropertyInfo(Variant::OBJECT, "side/right", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
1620 	p_list->push_back(PropertyInfo(Variant::OBJECT, "side/bottom", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
1621 	p_list->push_back(PropertyInfo(Variant::OBJECT, "side/top", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
1622 	p_list->push_back(PropertyInfo(Variant::OBJECT, "side/front", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
1623 	p_list->push_back(PropertyInfo(Variant::OBJECT, "side/back", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
1624 }
1625 
_bind_methods()1626 void CubeMap::_bind_methods() {
1627 
1628 	ClassDB::bind_method(D_METHOD("get_width"), &CubeMap::get_width);
1629 	ClassDB::bind_method(D_METHOD("get_height"), &CubeMap::get_height);
1630 	ClassDB::bind_method(D_METHOD("set_flags", "flags"), &CubeMap::set_flags);
1631 	ClassDB::bind_method(D_METHOD("get_flags"), &CubeMap::get_flags);
1632 	ClassDB::bind_method(D_METHOD("set_side", "side", "image"), &CubeMap::set_side);
1633 	ClassDB::bind_method(D_METHOD("get_side", "side"), &CubeMap::get_side);
1634 	ClassDB::bind_method(D_METHOD("set_storage", "mode"), &CubeMap::set_storage);
1635 	ClassDB::bind_method(D_METHOD("get_storage"), &CubeMap::get_storage);
1636 	ClassDB::bind_method(D_METHOD("set_lossy_storage_quality", "quality"), &CubeMap::set_lossy_storage_quality);
1637 	ClassDB::bind_method(D_METHOD("get_lossy_storage_quality"), &CubeMap::get_lossy_storage_quality);
1638 
1639 	ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"), "set_flags", "get_flags");
1640 	ADD_PROPERTY(PropertyInfo(Variant::INT, "storage_mode", PROPERTY_HINT_ENUM, "Raw,Lossy Compressed,Lossless Compressed"), "set_storage", "get_storage");
1641 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "lossy_storage_quality"), "set_lossy_storage_quality", "get_lossy_storage_quality");
1642 
1643 	BIND_ENUM_CONSTANT(STORAGE_RAW);
1644 	BIND_ENUM_CONSTANT(STORAGE_COMPRESS_LOSSY);
1645 	BIND_ENUM_CONSTANT(STORAGE_COMPRESS_LOSSLESS);
1646 
1647 	BIND_ENUM_CONSTANT(SIDE_LEFT);
1648 	BIND_ENUM_CONSTANT(SIDE_RIGHT);
1649 	BIND_ENUM_CONSTANT(SIDE_BOTTOM);
1650 	BIND_ENUM_CONSTANT(SIDE_TOP);
1651 	BIND_ENUM_CONSTANT(SIDE_FRONT);
1652 	BIND_ENUM_CONSTANT(SIDE_BACK);
1653 
1654 	BIND_ENUM_CONSTANT(FLAG_MIPMAPS);
1655 	BIND_ENUM_CONSTANT(FLAG_REPEAT);
1656 	BIND_ENUM_CONSTANT(FLAG_FILTER);
1657 	BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
1658 }
1659 
CubeMap()1660 CubeMap::CubeMap() {
1661 
1662 	w = h = 0;
1663 	flags = FLAGS_DEFAULT;
1664 	for (int i = 0; i < 6; i++)
1665 		valid[i] = false;
1666 	cubemap = VisualServer::get_singleton()->texture_create();
1667 	storage = STORAGE_RAW;
1668 	lossy_storage_quality = 0.7;
1669 	format = Image::FORMAT_BPTC_RGBA;
1670 }
1671 
~CubeMap()1672 CubeMap::~CubeMap() {
1673 
1674 	VisualServer::get_singleton()->free(cubemap);
1675 }
1676 
1677 /*	BIND_ENUM(CubeMapSize);
1678 	BIND_ENUM_CONSTANT( FLAG_CUBEMAP );
1679 	BIND_ENUM_CONSTANT( CUBEMAP_LEFT );
1680 	BIND_ENUM_CONSTANT( CUBEMAP_RIGHT );
1681 	BIND_ENUM_CONSTANT( CUBEMAP_BOTTOM );
1682 	BIND_ENUM_CONSTANT( CUBEMAP_TOP );
1683 	BIND_ENUM_CONSTANT( CUBEMAP_FRONT );
1684 	BIND_ENUM_CONSTANT( CUBEMAP_BACK );
1685 */
1686 ///////////////////////////
1687 
_bind_methods()1688 void CurveTexture::_bind_methods() {
1689 
1690 	ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
1691 
1692 	ClassDB::bind_method(D_METHOD("set_curve", "curve"), &CurveTexture::set_curve);
1693 	ClassDB::bind_method(D_METHOD("get_curve"), &CurveTexture::get_curve);
1694 
1695 	ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update);
1696 
1697 	ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width");
1698 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
1699 }
1700 
set_width(int p_width)1701 void CurveTexture::set_width(int p_width) {
1702 
1703 	ERR_FAIL_COND(p_width < 32 || p_width > 4096);
1704 	_width = p_width;
1705 	_update();
1706 }
1707 
get_width() const1708 int CurveTexture::get_width() const {
1709 
1710 	return _width;
1711 }
1712 
ensure_default_setup(float p_min,float p_max)1713 void CurveTexture::ensure_default_setup(float p_min, float p_max) {
1714 	if (_curve.is_null()) {
1715 		Ref<Curve> curve = Ref<Curve>(memnew(Curve));
1716 		curve->add_point(Vector2(0, 1));
1717 		curve->add_point(Vector2(1, 1));
1718 		curve->set_min_value(p_min);
1719 		curve->set_max_value(p_max);
1720 		set_curve(curve);
1721 		// Min and max is 0..1 by default
1722 	}
1723 }
1724 
set_curve(Ref<Curve> p_curve)1725 void CurveTexture::set_curve(Ref<Curve> p_curve) {
1726 	if (_curve != p_curve) {
1727 		if (_curve.is_valid()) {
1728 			_curve->disconnect(CoreStringNames::get_singleton()->changed, this, "_update");
1729 		}
1730 		_curve = p_curve;
1731 		if (_curve.is_valid()) {
1732 			_curve->connect(CoreStringNames::get_singleton()->changed, this, "_update");
1733 		}
1734 		_update();
1735 	}
1736 }
1737 
_update()1738 void CurveTexture::_update() {
1739 
1740 	PoolVector<uint8_t> data;
1741 	data.resize(_width * sizeof(float));
1742 
1743 	// The array is locked in that scope
1744 	{
1745 		PoolVector<uint8_t>::Write wd8 = data.write();
1746 		float *wd = (float *)wd8.ptr();
1747 
1748 		if (_curve.is_valid()) {
1749 			Curve &curve = **_curve;
1750 			for (int i = 0; i < _width; ++i) {
1751 				float t = i / static_cast<float>(_width);
1752 				wd[i] = curve.interpolate_baked(t);
1753 			}
1754 
1755 		} else {
1756 			for (int i = 0; i < _width; ++i) {
1757 				wd[i] = 0;
1758 			}
1759 		}
1760 	}
1761 
1762 	Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data));
1763 
1764 	VS::get_singleton()->texture_allocate(_texture, _width, 1, 0, Image::FORMAT_RF, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
1765 	VS::get_singleton()->texture_set_data(_texture, image);
1766 
1767 	emit_changed();
1768 }
1769 
get_curve() const1770 Ref<Curve> CurveTexture::get_curve() const {
1771 
1772 	return _curve;
1773 }
1774 
get_rid() const1775 RID CurveTexture::get_rid() const {
1776 
1777 	return _texture;
1778 }
1779 
CurveTexture()1780 CurveTexture::CurveTexture() {
1781 	_width = 2048;
1782 	_texture = VS::get_singleton()->texture_create();
1783 }
~CurveTexture()1784 CurveTexture::~CurveTexture() {
1785 	VS::get_singleton()->free(_texture);
1786 }
1787 //////////////////
1788 
1789 //setter and getter names for property serialization
1790 #define COLOR_RAMP_GET_OFFSETS "get_offsets"
1791 #define COLOR_RAMP_GET_COLORS "get_colors"
1792 #define COLOR_RAMP_SET_OFFSETS "set_offsets"
1793 #define COLOR_RAMP_SET_COLORS "set_colors"
1794 
GradientTexture()1795 GradientTexture::GradientTexture() {
1796 	update_pending = false;
1797 	width = 2048;
1798 
1799 	texture = VS::get_singleton()->texture_create();
1800 	_queue_update();
1801 }
1802 
~GradientTexture()1803 GradientTexture::~GradientTexture() {
1804 	VS::get_singleton()->free(texture);
1805 }
1806 
_bind_methods()1807 void GradientTexture::_bind_methods() {
1808 
1809 	ClassDB::bind_method(D_METHOD("set_gradient", "gradient"), &GradientTexture::set_gradient);
1810 	ClassDB::bind_method(D_METHOD("get_gradient"), &GradientTexture::get_gradient);
1811 
1812 	ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture::set_width);
1813 
1814 	ClassDB::bind_method(D_METHOD("_update"), &GradientTexture::_update);
1815 
1816 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
1817 	ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width");
1818 }
1819 
set_gradient(Ref<Gradient> p_gradient)1820 void GradientTexture::set_gradient(Ref<Gradient> p_gradient) {
1821 	if (p_gradient == gradient)
1822 		return;
1823 	if (gradient.is_valid()) {
1824 		gradient->disconnect(CoreStringNames::get_singleton()->changed, this, "_update");
1825 	}
1826 	gradient = p_gradient;
1827 	if (gradient.is_valid()) {
1828 		gradient->connect(CoreStringNames::get_singleton()->changed, this, "_update");
1829 	}
1830 	_update();
1831 	emit_changed();
1832 }
1833 
get_gradient() const1834 Ref<Gradient> GradientTexture::get_gradient() const {
1835 	return gradient;
1836 }
1837 
_queue_update()1838 void GradientTexture::_queue_update() {
1839 
1840 	if (update_pending)
1841 		return;
1842 
1843 	update_pending = true;
1844 	call_deferred("_update");
1845 }
1846 
_update()1847 void GradientTexture::_update() {
1848 
1849 	update_pending = false;
1850 
1851 	if (gradient.is_null())
1852 		return;
1853 
1854 	PoolVector<uint8_t> data;
1855 	data.resize(width * 4);
1856 	{
1857 		PoolVector<uint8_t>::Write wd8 = data.write();
1858 		Gradient &g = **gradient;
1859 
1860 		for (int i = 0; i < width; i++) {
1861 
1862 			float ofs = float(i) / (width - 1);
1863 			Color color = g.get_color_at_offset(ofs);
1864 
1865 			wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255));
1866 			wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255));
1867 			wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255));
1868 			wd8[i * 4 + 3] = uint8_t(CLAMP(color.a * 255.0, 0, 255));
1869 		}
1870 	}
1871 
1872 	Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
1873 
1874 	VS::get_singleton()->texture_allocate(texture, width, 1, 0, Image::FORMAT_RGBA8, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
1875 	VS::get_singleton()->texture_set_data(texture, image);
1876 
1877 	emit_changed();
1878 }
1879 
set_width(int p_width)1880 void GradientTexture::set_width(int p_width) {
1881 
1882 	width = p_width;
1883 	_queue_update();
1884 }
get_width() const1885 int GradientTexture::get_width() const {
1886 
1887 	return width;
1888 }
1889 
get_data() const1890 Ref<Image> GradientTexture::get_data() const {
1891 	return VisualServer::get_singleton()->texture_get_data(texture);
1892 }
1893 
1894 //////////////////////////////////////
1895 
_bind_methods()1896 void ProxyTexture::_bind_methods() {
1897 
1898 	ClassDB::bind_method(D_METHOD("set_base", "base"), &ProxyTexture::set_base);
1899 	ClassDB::bind_method(D_METHOD("get_base"), &ProxyTexture::get_base);
1900 
1901 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_base", "get_base");
1902 }
1903 
set_base(const Ref<Texture> & p_texture)1904 void ProxyTexture::set_base(const Ref<Texture> &p_texture) {
1905 
1906 	ERR_FAIL_COND(p_texture == this);
1907 	base = p_texture;
1908 	if (base.is_valid()) {
1909 		VS::get_singleton()->texture_set_proxy(proxy, base->get_rid());
1910 	} else {
1911 		VS::get_singleton()->texture_set_proxy(proxy, RID());
1912 	}
1913 }
1914 
get_base() const1915 Ref<Texture> ProxyTexture::get_base() const {
1916 
1917 	return base;
1918 }
1919 
get_width() const1920 int ProxyTexture::get_width() const {
1921 
1922 	if (base.is_valid())
1923 		return base->get_width();
1924 	return 1;
1925 }
get_height() const1926 int ProxyTexture::get_height() const {
1927 
1928 	if (base.is_valid())
1929 		return base->get_height();
1930 	return 1;
1931 }
get_rid() const1932 RID ProxyTexture::get_rid() const {
1933 
1934 	return proxy;
1935 }
1936 
has_alpha() const1937 bool ProxyTexture::has_alpha() const {
1938 
1939 	if (base.is_valid())
1940 		return base->has_alpha();
1941 	return false;
1942 }
1943 
set_flags(uint32_t p_flags)1944 void ProxyTexture::set_flags(uint32_t p_flags) {
1945 }
1946 
get_flags() const1947 uint32_t ProxyTexture::get_flags() const {
1948 
1949 	if (base.is_valid())
1950 		return base->get_flags();
1951 	return 0;
1952 }
1953 
ProxyTexture()1954 ProxyTexture::ProxyTexture() {
1955 
1956 	proxy = VS::get_singleton()->texture_create();
1957 }
1958 
~ProxyTexture()1959 ProxyTexture::~ProxyTexture() {
1960 
1961 	VS::get_singleton()->free(proxy);
1962 }
1963 //////////////////////////////////////////////
1964 
_update_proxy()1965 void AnimatedTexture::_update_proxy() {
1966 
1967 	RWLockRead r(rw_lock);
1968 
1969 	float delta;
1970 	if (prev_ticks == 0) {
1971 		delta = 0;
1972 		prev_ticks = OS::get_singleton()->get_ticks_usec();
1973 	} else {
1974 		uint64_t ticks = OS::get_singleton()->get_ticks_usec();
1975 		delta = float(double(ticks - prev_ticks) / 1000000.0);
1976 		prev_ticks = ticks;
1977 	}
1978 
1979 	time += delta;
1980 
1981 	float limit;
1982 
1983 	if (fps == 0) {
1984 		limit = 0;
1985 	} else {
1986 		limit = 1.0 / fps;
1987 	}
1988 
1989 	int iter_max = frame_count;
1990 	while (iter_max && !pause) {
1991 		float frame_limit = limit + frames[current_frame].delay_sec;
1992 
1993 		if (time > frame_limit) {
1994 			current_frame++;
1995 			if (current_frame >= frame_count) {
1996 				if (oneshot) {
1997 					current_frame = frame_count - 1;
1998 				} else {
1999 					current_frame = 0;
2000 				}
2001 			}
2002 			time -= frame_limit;
2003 			_change_notify("current_frame");
2004 		} else {
2005 			break;
2006 		}
2007 		iter_max--;
2008 	}
2009 
2010 	if (frames[current_frame].texture.is_valid()) {
2011 		VisualServer::get_singleton()->texture_set_proxy(proxy, frames[current_frame].texture->get_rid());
2012 	}
2013 }
2014 
set_frames(int p_frames)2015 void AnimatedTexture::set_frames(int p_frames) {
2016 	ERR_FAIL_COND(p_frames < 1 || p_frames > MAX_FRAMES);
2017 
2018 	RWLockWrite r(rw_lock);
2019 
2020 	frame_count = p_frames;
2021 }
get_frames() const2022 int AnimatedTexture::get_frames() const {
2023 	return frame_count;
2024 }
2025 
set_current_frame(int p_frame)2026 void AnimatedTexture::set_current_frame(int p_frame) {
2027 	ERR_FAIL_COND(p_frame < 0 || p_frame >= frame_count);
2028 
2029 	RWLockWrite r(rw_lock);
2030 
2031 	current_frame = p_frame;
2032 }
get_current_frame() const2033 int AnimatedTexture::get_current_frame() const {
2034 	return current_frame;
2035 }
2036 
set_pause(bool p_pause)2037 void AnimatedTexture::set_pause(bool p_pause) {
2038 	RWLockWrite r(rw_lock);
2039 	pause = p_pause;
2040 }
get_pause() const2041 bool AnimatedTexture::get_pause() const {
2042 	return pause;
2043 }
2044 
set_oneshot(bool p_oneshot)2045 void AnimatedTexture::set_oneshot(bool p_oneshot) {
2046 	RWLockWrite r(rw_lock);
2047 	oneshot = p_oneshot;
2048 }
get_oneshot() const2049 bool AnimatedTexture::get_oneshot() const {
2050 	return oneshot;
2051 }
2052 
set_frame_texture(int p_frame,const Ref<Texture> & p_texture)2053 void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture> &p_texture) {
2054 
2055 	ERR_FAIL_COND(p_texture == this);
2056 	ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
2057 
2058 	RWLockWrite w(rw_lock);
2059 
2060 	frames[p_frame].texture = p_texture;
2061 }
get_frame_texture(int p_frame) const2062 Ref<Texture> AnimatedTexture::get_frame_texture(int p_frame) const {
2063 	ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, Ref<Texture>());
2064 
2065 	RWLockRead r(rw_lock);
2066 
2067 	return frames[p_frame].texture;
2068 }
2069 
set_frame_delay(int p_frame,float p_delay_sec)2070 void AnimatedTexture::set_frame_delay(int p_frame, float p_delay_sec) {
2071 	ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
2072 
2073 	RWLockRead r(rw_lock);
2074 
2075 	frames[p_frame].delay_sec = p_delay_sec;
2076 }
get_frame_delay(int p_frame) const2077 float AnimatedTexture::get_frame_delay(int p_frame) const {
2078 	ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0);
2079 
2080 	RWLockRead r(rw_lock);
2081 
2082 	return frames[p_frame].delay_sec;
2083 }
2084 
set_fps(float p_fps)2085 void AnimatedTexture::set_fps(float p_fps) {
2086 	ERR_FAIL_COND(p_fps < 0 || p_fps >= 1000);
2087 
2088 	fps = p_fps;
2089 }
get_fps() const2090 float AnimatedTexture::get_fps() const {
2091 	return fps;
2092 }
2093 
get_width() const2094 int AnimatedTexture::get_width() const {
2095 	RWLockRead r(rw_lock);
2096 
2097 	if (!frames[current_frame].texture.is_valid()) {
2098 		return 1;
2099 	}
2100 
2101 	return frames[current_frame].texture->get_width();
2102 }
get_height() const2103 int AnimatedTexture::get_height() const {
2104 	RWLockRead r(rw_lock);
2105 
2106 	if (!frames[current_frame].texture.is_valid()) {
2107 		return 1;
2108 	}
2109 
2110 	return frames[current_frame].texture->get_height();
2111 }
get_rid() const2112 RID AnimatedTexture::get_rid() const {
2113 	return proxy;
2114 }
2115 
has_alpha() const2116 bool AnimatedTexture::has_alpha() const {
2117 
2118 	RWLockRead r(rw_lock);
2119 
2120 	if (!frames[current_frame].texture.is_valid()) {
2121 		return false;
2122 	}
2123 
2124 	return frames[current_frame].texture->has_alpha();
2125 }
2126 
get_data() const2127 Ref<Image> AnimatedTexture::get_data() const {
2128 
2129 	RWLockRead r(rw_lock);
2130 
2131 	if (!frames[current_frame].texture.is_valid()) {
2132 		return Ref<Image>();
2133 	}
2134 
2135 	return frames[current_frame].texture->get_data();
2136 }
2137 
is_pixel_opaque(int p_x,int p_y) const2138 bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
2139 
2140 	RWLockRead r(rw_lock);
2141 
2142 	if (frames[current_frame].texture.is_valid()) {
2143 		return frames[current_frame].texture->is_pixel_opaque(p_x, p_y);
2144 	}
2145 	return true;
2146 }
2147 
set_flags(uint32_t p_flags)2148 void AnimatedTexture::set_flags(uint32_t p_flags) {
2149 }
get_flags() const2150 uint32_t AnimatedTexture::get_flags() const {
2151 
2152 	RWLockRead r(rw_lock);
2153 
2154 	if (!frames[current_frame].texture.is_valid()) {
2155 		return 0;
2156 	}
2157 
2158 	return frames[current_frame].texture->get_flags();
2159 }
2160 
_validate_property(PropertyInfo & property) const2161 void AnimatedTexture::_validate_property(PropertyInfo &property) const {
2162 
2163 	String prop = property.name;
2164 	if (prop.begins_with("frame_")) {
2165 		int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int();
2166 		if (frame >= frame_count) {
2167 			property.usage = 0;
2168 		}
2169 	}
2170 }
2171 
_bind_methods()2172 void AnimatedTexture::_bind_methods() {
2173 	ClassDB::bind_method(D_METHOD("set_frames", "frames"), &AnimatedTexture::set_frames);
2174 	ClassDB::bind_method(D_METHOD("get_frames"), &AnimatedTexture::get_frames);
2175 
2176 	ClassDB::bind_method(D_METHOD("set_current_frame", "frame"), &AnimatedTexture::set_current_frame);
2177 	ClassDB::bind_method(D_METHOD("get_current_frame"), &AnimatedTexture::get_current_frame);
2178 
2179 	ClassDB::bind_method(D_METHOD("set_pause", "pause"), &AnimatedTexture::set_pause);
2180 	ClassDB::bind_method(D_METHOD("get_pause"), &AnimatedTexture::get_pause);
2181 
2182 	ClassDB::bind_method(D_METHOD("set_oneshot", "oneshot"), &AnimatedTexture::set_oneshot);
2183 	ClassDB::bind_method(D_METHOD("get_oneshot"), &AnimatedTexture::get_oneshot);
2184 
2185 	ClassDB::bind_method(D_METHOD("set_fps", "fps"), &AnimatedTexture::set_fps);
2186 	ClassDB::bind_method(D_METHOD("get_fps"), &AnimatedTexture::get_fps);
2187 
2188 	ClassDB::bind_method(D_METHOD("set_frame_texture", "frame", "texture"), &AnimatedTexture::set_frame_texture);
2189 	ClassDB::bind_method(D_METHOD("get_frame_texture", "frame"), &AnimatedTexture::get_frame_texture);
2190 
2191 	ClassDB::bind_method(D_METHOD("set_frame_delay", "frame", "delay"), &AnimatedTexture::set_frame_delay);
2192 	ClassDB::bind_method(D_METHOD("get_frame_delay", "frame"), &AnimatedTexture::get_frame_delay);
2193 
2194 	ClassDB::bind_method(D_METHOD("_update_proxy"), &AnimatedTexture::_update_proxy);
2195 
2196 	ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames");
2197 	ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", 0), "set_current_frame", "get_current_frame");
2198 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause");
2199 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "oneshot"), "set_oneshot", "get_oneshot");
2200 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps");
2201 
2202 	for (int i = 0; i < MAX_FRAMES; i++) {
2203 		ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i);
2204 		ADD_PROPERTYI(PropertyInfo(Variant::REAL, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_delay", "get_frame_delay", i);
2205 	}
2206 
2207 	BIND_CONSTANT(MAX_FRAMES);
2208 }
2209 
AnimatedTexture()2210 AnimatedTexture::AnimatedTexture() {
2211 	proxy = VS::get_singleton()->texture_create();
2212 	VisualServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true);
2213 	time = 0;
2214 	frame_count = 1;
2215 	fps = 4;
2216 	prev_ticks = 0;
2217 	current_frame = 0;
2218 	pause = false;
2219 	oneshot = false;
2220 	VisualServer::get_singleton()->connect("frame_pre_draw", this, "_update_proxy");
2221 
2222 #ifndef NO_THREADS
2223 	rw_lock = RWLock::create();
2224 #else
2225 	rw_lock = NULL;
2226 #endif
2227 }
2228 
~AnimatedTexture()2229 AnimatedTexture::~AnimatedTexture() {
2230 	VS::get_singleton()->free(proxy);
2231 	if (rw_lock) {
2232 		memdelete(rw_lock);
2233 	}
2234 }
2235 ///////////////////////////////
2236 
set_flags(uint32_t p_flags)2237 void TextureLayered::set_flags(uint32_t p_flags) {
2238 	flags = p_flags;
2239 
2240 	if (texture.is_valid()) {
2241 		VS::get_singleton()->texture_set_flags(texture, flags);
2242 	}
2243 }
2244 
get_flags() const2245 uint32_t TextureLayered::get_flags() const {
2246 	return flags;
2247 }
2248 
get_format() const2249 Image::Format TextureLayered::get_format() const {
2250 	return format;
2251 }
2252 
get_width() const2253 uint32_t TextureLayered::get_width() const {
2254 	return width;
2255 }
2256 
get_height() const2257 uint32_t TextureLayered::get_height() const {
2258 	return height;
2259 }
2260 
get_depth() const2261 uint32_t TextureLayered::get_depth() const {
2262 	return depth;
2263 }
2264 
_set_data(const Dictionary & p_data)2265 void TextureLayered::_set_data(const Dictionary &p_data) {
2266 	ERR_FAIL_COND(!p_data.has("width"));
2267 	ERR_FAIL_COND(!p_data.has("height"));
2268 	ERR_FAIL_COND(!p_data.has("depth"));
2269 	ERR_FAIL_COND(!p_data.has("format"));
2270 	ERR_FAIL_COND(!p_data.has("flags"));
2271 	ERR_FAIL_COND(!p_data.has("layers"));
2272 	int w = p_data["width"];
2273 	int h = p_data["height"];
2274 	int d = p_data["depth"];
2275 	Image::Format format = Image::Format(int(p_data["format"]));
2276 	int flags = p_data["flags"];
2277 	Array layers = p_data["layers"];
2278 	ERR_FAIL_COND(layers.size() != d);
2279 
2280 	create(w, h, d, format, flags);
2281 
2282 	for (int i = 0; i < layers.size(); i++) {
2283 		Ref<Image> img = layers[i];
2284 		ERR_CONTINUE(!img.is_valid());
2285 		ERR_CONTINUE(img->get_format() != format);
2286 		ERR_CONTINUE(img->get_width() != w);
2287 		ERR_CONTINUE(img->get_height() != h);
2288 		set_layer_data(img, i);
2289 	}
2290 }
2291 
_get_data() const2292 Dictionary TextureLayered::_get_data() const {
2293 	Dictionary d;
2294 	d["width"] = width;
2295 	d["height"] = height;
2296 	d["depth"] = depth;
2297 	d["flags"] = flags;
2298 	d["format"] = format;
2299 
2300 	Array layers;
2301 	for (int i = 0; i < depth; i++) {
2302 		layers.push_back(get_layer_data(i));
2303 	}
2304 	d["layers"] = layers;
2305 	return d;
2306 }
2307 
create(uint32_t p_width,uint32_t p_height,uint32_t p_depth,Image::Format p_format,uint32_t p_flags)2308 void TextureLayered::create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags) {
2309 	VS::get_singleton()->texture_allocate(texture, p_width, p_height, p_depth, p_format, is_3d ? VS::TEXTURE_TYPE_3D : VS::TEXTURE_TYPE_2D_ARRAY, p_flags);
2310 
2311 	width = p_width;
2312 	height = p_height;
2313 	depth = p_depth;
2314 	format = p_format;
2315 	flags = p_flags;
2316 }
2317 
set_layer_data(const Ref<Image> & p_image,int p_layer)2318 void TextureLayered::set_layer_data(const Ref<Image> &p_image, int p_layer) {
2319 	ERR_FAIL_COND(!texture.is_valid());
2320 	ERR_FAIL_COND(!p_image.is_valid());
2321 	VS::get_singleton()->texture_set_data(texture, p_image, p_layer);
2322 }
2323 
get_layer_data(int p_layer) const2324 Ref<Image> TextureLayered::get_layer_data(int p_layer) const {
2325 
2326 	ERR_FAIL_COND_V(!texture.is_valid(), Ref<Image>());
2327 	return VS::get_singleton()->texture_get_data(texture, p_layer);
2328 }
2329 
set_data_partial(const Ref<Image> & p_image,int p_x_ofs,int p_y_ofs,int p_z,int p_mipmap)2330 void TextureLayered::set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_z, int p_mipmap) {
2331 	ERR_FAIL_COND(!texture.is_valid());
2332 	ERR_FAIL_COND(!p_image.is_valid());
2333 	VS::get_singleton()->texture_set_data_partial(texture, p_image, 0, 0, p_image->get_width(), p_image->get_height(), p_x_ofs, p_y_ofs, p_mipmap, p_z);
2334 }
2335 
get_rid() const2336 RID TextureLayered::get_rid() const {
2337 	return texture;
2338 }
2339 
set_path(const String & p_path,bool p_take_over)2340 void TextureLayered::set_path(const String &p_path, bool p_take_over) {
2341 	if (texture.is_valid()) {
2342 		VS::get_singleton()->texture_set_path(texture, p_path);
2343 	}
2344 
2345 	Resource::set_path(p_path, p_take_over);
2346 }
2347 
_bind_methods()2348 void TextureLayered::_bind_methods() {
2349 	ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextureLayered::set_flags);
2350 	ClassDB::bind_method(D_METHOD("get_flags"), &TextureLayered::get_flags);
2351 
2352 	ClassDB::bind_method(D_METHOD("get_format"), &TextureLayered::get_format);
2353 
2354 	ClassDB::bind_method(D_METHOD("get_width"), &TextureLayered::get_width);
2355 	ClassDB::bind_method(D_METHOD("get_height"), &TextureLayered::get_height);
2356 	ClassDB::bind_method(D_METHOD("get_depth"), &TextureLayered::get_depth);
2357 
2358 	ClassDB::bind_method(D_METHOD("create", "width", "height", "depth", "format", "flags"), &TextureLayered::create, DEFVAL(FLAGS_DEFAULT));
2359 	ClassDB::bind_method(D_METHOD("set_layer_data", "image", "layer"), &TextureLayered::set_layer_data);
2360 	ClassDB::bind_method(D_METHOD("get_layer_data", "layer"), &TextureLayered::get_layer_data);
2361 	ClassDB::bind_method(D_METHOD("set_data_partial", "image", "x_offset", "y_offset", "layer", "mipmap"), &TextureLayered::set_data_partial, DEFVAL(0));
2362 
2363 	ClassDB::bind_method(D_METHOD("_set_data", "data"), &TextureLayered::_set_data);
2364 	ClassDB::bind_method(D_METHOD("_get_data"), &TextureLayered::_get_data);
2365 
2366 	ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"), "set_flags", "get_flags");
2367 	ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
2368 
2369 	BIND_ENUM_CONSTANT(FLAG_MIPMAPS);
2370 	BIND_ENUM_CONSTANT(FLAG_REPEAT);
2371 	BIND_ENUM_CONSTANT(FLAG_FILTER);
2372 	BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
2373 }
2374 
TextureLayered(bool p_3d)2375 TextureLayered::TextureLayered(bool p_3d) {
2376 	is_3d = p_3d;
2377 	format = Image::FORMAT_MAX;
2378 	flags = FLAGS_DEFAULT;
2379 
2380 	width = 0;
2381 	height = 0;
2382 	depth = 0;
2383 
2384 	texture = VS::get_singleton()->texture_create();
2385 }
2386 
~TextureLayered()2387 TextureLayered::~TextureLayered() {
2388 	if (texture.is_valid()) {
2389 		VS::get_singleton()->free(texture);
2390 	}
2391 }
2392 
load(const String & p_path,const String & p_original_path,Error * r_error)2393 RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error) {
2394 
2395 	if (r_error) {
2396 		*r_error = ERR_CANT_OPEN;
2397 	}
2398 
2399 	Ref<TextureLayered> lt;
2400 	Ref<Texture3D> tex3d;
2401 	Ref<TextureArray> texarr;
2402 
2403 	if (p_path.ends_with("tex3d")) {
2404 		tex3d.instance();
2405 		lt = tex3d;
2406 	} else if (p_path.ends_with("texarr")) {
2407 		texarr.instance();
2408 		lt = texarr;
2409 	} else {
2410 		ERR_FAIL_V_MSG(RES(), "Unrecognized layered texture extension.");
2411 	}
2412 
2413 	FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
2414 	ERR_FAIL_COND_V_MSG(!f, RES(), "Cannot open file '" + p_path + "'.");
2415 
2416 	uint8_t header[5] = { 0, 0, 0, 0, 0 };
2417 	f->get_buffer(header, 4);
2418 
2419 	if (header[0] == 'G' && header[1] == 'D' && header[2] == '3' && header[3] == 'T') {
2420 		if (tex3d.is_null()) {
2421 			f->close();
2422 			memdelete(f);
2423 			ERR_FAIL_COND_V(tex3d.is_null(), RES())
2424 		}
2425 	} else if (header[0] == 'G' && header[1] == 'D' && header[2] == 'A' && header[3] == 'T') {
2426 		if (texarr.is_null()) {
2427 			f->close();
2428 			memdelete(f);
2429 			ERR_FAIL_COND_V(texarr.is_null(), RES())
2430 		}
2431 	} else {
2432 
2433 		f->close();
2434 		memdelete(f);
2435 		ERR_FAIL_V_MSG(RES(), "Unrecognized layered texture file format '" + String((const char *)header) + "'.");
2436 	}
2437 
2438 	int tw = f->get_32();
2439 	int th = f->get_32();
2440 	int td = f->get_32();
2441 	int flags = f->get_32(); //texture flags!
2442 	Image::Format format = Image::Format(f->get_32());
2443 	uint32_t compression = f->get_32(); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
2444 
2445 	lt->create(tw, th, td, format, flags);
2446 
2447 	for (int layer = 0; layer < td; layer++) {
2448 
2449 		Ref<Image> image;
2450 		image.instance();
2451 
2452 		if (compression == COMPRESSION_LOSSLESS) {
2453 			//look for a PNG file inside
2454 
2455 			int mipmaps = f->get_32();
2456 			Vector<Ref<Image> > mipmap_images;
2457 
2458 			for (int i = 0; i < mipmaps; i++) {
2459 				uint32_t size = f->get_32();
2460 
2461 				PoolVector<uint8_t> pv;
2462 				pv.resize(size);
2463 				{
2464 					PoolVector<uint8_t>::Write w = pv.write();
2465 					f->get_buffer(w.ptr(), size);
2466 				}
2467 
2468 				Ref<Image> img = Image::lossless_unpacker(pv);
2469 
2470 				if (img.is_null() || img->empty() || format != img->get_format()) {
2471 					if (r_error) {
2472 						*r_error = ERR_FILE_CORRUPT;
2473 					}
2474 					f->close();
2475 					memdelete(f);
2476 					ERR_FAIL_V(RES());
2477 				}
2478 
2479 				mipmap_images.push_back(img);
2480 			}
2481 
2482 			if (mipmap_images.size() == 1) {
2483 
2484 				image = mipmap_images[0];
2485 
2486 			} else {
2487 				int total_size = Image::get_image_data_size(tw, th, format, true);
2488 				PoolVector<uint8_t> img_data;
2489 				img_data.resize(total_size);
2490 
2491 				{
2492 					PoolVector<uint8_t>::Write w = img_data.write();
2493 
2494 					int ofs = 0;
2495 					for (int i = 0; i < mipmap_images.size(); i++) {
2496 
2497 						PoolVector<uint8_t> id = mipmap_images[i]->get_data();
2498 						int len = id.size();
2499 						PoolVector<uint8_t>::Read r = id.read();
2500 						copymem(&w[ofs], r.ptr(), len);
2501 						ofs += len;
2502 					}
2503 				}
2504 
2505 				image->create(tw, th, true, format, img_data);
2506 				if (image->empty()) {
2507 					if (r_error) {
2508 						*r_error = ERR_FILE_CORRUPT;
2509 					}
2510 					f->close();
2511 					memdelete(f);
2512 					ERR_FAIL_V(RES());
2513 				}
2514 			}
2515 
2516 		} else {
2517 
2518 			//look for regular format
2519 			bool mipmaps = (flags & Texture::FLAG_MIPMAPS);
2520 			int total_size = Image::get_image_data_size(tw, th, format, mipmaps);
2521 
2522 			PoolVector<uint8_t> img_data;
2523 			img_data.resize(total_size);
2524 
2525 			{
2526 				PoolVector<uint8_t>::Write w = img_data.write();
2527 				int bytes = f->get_buffer(w.ptr(), total_size);
2528 				if (bytes != total_size) {
2529 					if (r_error) {
2530 						*r_error = ERR_FILE_CORRUPT;
2531 					}
2532 					f->close();
2533 					memdelete(f);
2534 					ERR_FAIL_V(RES());
2535 				}
2536 			}
2537 
2538 			image->create(tw, th, mipmaps, format, img_data);
2539 		}
2540 
2541 		lt->set_layer_data(image, layer);
2542 	}
2543 
2544 	if (r_error)
2545 		*r_error = OK;
2546 
2547 	return lt;
2548 }
2549 
get_recognized_extensions(List<String> * p_extensions) const2550 void ResourceFormatLoaderTextureLayered::get_recognized_extensions(List<String> *p_extensions) const {
2551 
2552 	p_extensions->push_back("tex3d");
2553 	p_extensions->push_back("texarr");
2554 }
handles_type(const String & p_type) const2555 bool ResourceFormatLoaderTextureLayered::handles_type(const String &p_type) const {
2556 	return p_type == "Texture3D" || p_type == "TextureArray";
2557 }
get_resource_type(const String & p_path) const2558 String ResourceFormatLoaderTextureLayered::get_resource_type(const String &p_path) const {
2559 
2560 	if (p_path.get_extension().to_lower() == "tex3d")
2561 		return "Texture3D";
2562 	if (p_path.get_extension().to_lower() == "texarr")
2563 		return "TextureArray";
2564 	return "";
2565 }
2566 
_bind_methods()2567 void CameraTexture::_bind_methods() {
2568 	ClassDB::bind_method(D_METHOD("set_camera_feed_id", "feed_id"), &CameraTexture::set_camera_feed_id);
2569 	ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &CameraTexture::get_camera_feed_id);
2570 
2571 	ClassDB::bind_method(D_METHOD("set_which_feed", "which_feed"), &CameraTexture::set_which_feed);
2572 	ClassDB::bind_method(D_METHOD("get_which_feed"), &CameraTexture::get_which_feed);
2573 
2574 	ClassDB::bind_method(D_METHOD("set_camera_active", "active"), &CameraTexture::set_camera_active);
2575 	ClassDB::bind_method(D_METHOD("get_camera_active"), &CameraTexture::get_camera_active);
2576 
2577 	ADD_PROPERTY(PropertyInfo(Variant::INT, "camera_feed_id"), "set_camera_feed_id", "get_camera_feed_id");
2578 	ADD_PROPERTY(PropertyInfo(Variant::INT, "which_feed"), "set_which_feed", "get_which_feed");
2579 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "camera_is_active"), "set_camera_active", "get_camera_active");
2580 }
2581 
get_width() const2582 int CameraTexture::get_width() const {
2583 	Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
2584 	if (feed.is_valid()) {
2585 		return feed->get_base_width();
2586 	} else {
2587 		return 0;
2588 	}
2589 }
2590 
get_height() const2591 int CameraTexture::get_height() const {
2592 	Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
2593 	if (feed.is_valid()) {
2594 		return feed->get_base_height();
2595 	} else {
2596 		return 0;
2597 	}
2598 }
2599 
has_alpha() const2600 bool CameraTexture::has_alpha() const {
2601 	return false;
2602 }
2603 
get_rid() const2604 RID CameraTexture::get_rid() const {
2605 	Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
2606 	if (feed.is_valid()) {
2607 		return feed->get_texture(which_feed);
2608 	} else {
2609 		return RID();
2610 	}
2611 }
2612 
set_flags(uint32_t p_flags)2613 void CameraTexture::set_flags(uint32_t p_flags) {
2614 	// not supported
2615 }
2616 
get_flags() const2617 uint32_t CameraTexture::get_flags() const {
2618 	// not supported
2619 	return 0;
2620 }
2621 
get_data() const2622 Ref<Image> CameraTexture::get_data() const {
2623 	// not (yet) supported
2624 	return Ref<Image>();
2625 }
2626 
set_camera_feed_id(int p_new_id)2627 void CameraTexture::set_camera_feed_id(int p_new_id) {
2628 	camera_feed_id = p_new_id;
2629 	_change_notify();
2630 }
2631 
get_camera_feed_id() const2632 int CameraTexture::get_camera_feed_id() const {
2633 	return camera_feed_id;
2634 }
2635 
set_which_feed(CameraServer::FeedImage p_which)2636 void CameraTexture::set_which_feed(CameraServer::FeedImage p_which) {
2637 	which_feed = p_which;
2638 	_change_notify();
2639 }
2640 
get_which_feed() const2641 CameraServer::FeedImage CameraTexture::get_which_feed() const {
2642 	return which_feed;
2643 }
2644 
set_camera_active(bool p_active)2645 void CameraTexture::set_camera_active(bool p_active) {
2646 	Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
2647 	if (feed.is_valid()) {
2648 		feed->set_active(p_active);
2649 		_change_notify();
2650 	}
2651 }
2652 
get_camera_active() const2653 bool CameraTexture::get_camera_active() const {
2654 	Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
2655 	if (feed.is_valid()) {
2656 		return feed->is_active();
2657 	} else {
2658 		return false;
2659 	}
2660 }
2661 
CameraTexture()2662 CameraTexture::CameraTexture() {
2663 	camera_feed_id = 0;
2664 	which_feed = CameraServer::FEED_RGBA_IMAGE;
2665 }
2666 
~CameraTexture()2667 CameraTexture::~CameraTexture() {
2668 	// nothing to do here yet
2669 }
2670 
_bind_methods()2671 void ExternalTexture::_bind_methods() {
2672 	ClassDB::bind_method(D_METHOD("set_size", "size"), &ExternalTexture::set_size);
2673 	ClassDB::bind_method(D_METHOD("get_external_texture_id"), &ExternalTexture::get_external_texture_id);
2674 
2675 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
2676 }
2677 
get_external_texture_id()2678 uint32_t ExternalTexture::get_external_texture_id() {
2679 	return VisualServer::get_singleton()->texture_get_texid(texture);
2680 }
2681 
set_size(const Size2 & p_size)2682 void ExternalTexture::set_size(const Size2 &p_size) {
2683 
2684 	if (p_size.width > 0 && p_size.height > 0) {
2685 		size = p_size;
2686 		VisualServer::get_singleton()->texture_set_size_override(texture, size.width, size.height, 0);
2687 	}
2688 }
2689 
get_width() const2690 int ExternalTexture::get_width() const {
2691 	return size.width;
2692 }
2693 
get_height() const2694 int ExternalTexture::get_height() const {
2695 	return size.height;
2696 }
2697 
get_size() const2698 Size2 ExternalTexture::get_size() const {
2699 	return size;
2700 }
2701 
get_rid() const2702 RID ExternalTexture::get_rid() const {
2703 	return texture;
2704 }
2705 
has_alpha() const2706 bool ExternalTexture::has_alpha() const {
2707 	return true;
2708 }
2709 
set_flags(uint32_t p_flags)2710 void ExternalTexture::set_flags(uint32_t p_flags) {
2711 	// not supported
2712 }
2713 
get_flags() const2714 uint32_t ExternalTexture::get_flags() const {
2715 	// not supported
2716 	return 0;
2717 }
2718 
ExternalTexture()2719 ExternalTexture::ExternalTexture() {
2720 	size = Size2(1.0, 1.0);
2721 	texture = VisualServer::get_singleton()->texture_create();
2722 
2723 	VisualServer::get_singleton()->texture_allocate(texture, size.width, size.height, 0, Image::FORMAT_RGBA8, VS::TEXTURE_TYPE_EXTERNAL, 0);
2724 	_change_notify();
2725 	emit_changed();
2726 }
2727 
~ExternalTexture()2728 ExternalTexture::~ExternalTexture() {
2729 	VisualServer::get_singleton()->free(texture);
2730 }
2731