1 /*************************************************************************/
2 /*  texture.cpp                                                          */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 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 #include "texture.h"
31 #include "core/os/os.h"
32 #include "io/image_loader.h"
33 
get_size() const34 Size2 Texture::get_size() const {
35 
36 	return Size2(get_width(), get_height());
37 }
38 
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose) const39 void Texture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
40 
41 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose);
42 }
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose) const43 void Texture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
44 
45 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose);
46 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose) const47 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 {
48 
49 	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose);
50 }
51 
get_rect_region_uv_rect(const Rect2 & p_rect,const Rect2 & p_src_rect,Rect2 & r_rect,Rect2 & r_uv_rect) const52 bool Texture::get_rect_region_uv_rect(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_uv_rect) const {
53 
54 	Size2 size = get_size();
55 
56 	if (size.width == 0 || size.height == 0)
57 		return false;
58 
59 	r_rect = p_rect;
60 	r_uv_rect = Rect2(p_src_rect.get_pos() / size, p_src_rect.get_size() / size);
61 
62 	return true;
63 }
64 
_bind_methods()65 void Texture::_bind_methods() {
66 
67 	ObjectTypeDB::bind_method(_MD("get_width"), &Texture::get_width);
68 	ObjectTypeDB::bind_method(_MD("get_height"), &Texture::get_height);
69 	ObjectTypeDB::bind_method(_MD("get_size"), &Texture::get_size);
70 	ObjectTypeDB::bind_method(_MD("get_rid"), &Texture::get_rid);
71 	ObjectTypeDB::bind_method(_MD("has_alpha"), &Texture::has_alpha);
72 	ObjectTypeDB::bind_method(_MD("set_flags", "flags"), &Texture::set_flags);
73 	ObjectTypeDB::bind_method(_MD("get_flags"), &Texture::get_flags);
74 	ObjectTypeDB::bind_method(_MD("draw", "canvas_item", "pos", "modulate", "transpose"), &Texture::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false));
75 	ObjectTypeDB::bind_method(_MD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose"), &Texture::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false));
76 	ObjectTypeDB::bind_method(_MD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose"), &Texture::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false));
77 
78 	BIND_CONSTANT(FLAG_MIPMAPS);
79 	BIND_CONSTANT(FLAG_REPEAT);
80 	BIND_CONSTANT(FLAG_FILTER);
81 	BIND_CONSTANT(FLAG_VIDEO_SURFACE);
82 	BIND_CONSTANT(FLAGS_DEFAULT);
83 	BIND_CONSTANT(FLAG_ANISOTROPIC_FILTER);
84 	BIND_CONSTANT(FLAG_CONVERT_TO_LINEAR);
85 	BIND_CONSTANT(FLAG_MIRRORED_REPEAT);
86 }
87 
Texture()88 Texture::Texture() {
89 }
90 
91 /////////////////////
92 
reload_from_file()93 void ImageTexture::reload_from_file() {
94 
95 	String path = get_path();
96 	if (!path.is_resource_file())
97 		return;
98 
99 	uint32_t flags = get_flags();
100 	Image img;
101 
102 	Error err = ImageLoader::load_image(path, &img);
103 	ERR_FAIL_COND(err != OK);
104 
105 	create_from_image(img, flags);
106 }
107 
_set(const StringName & p_name,const Variant & p_value)108 bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
109 
110 	if (p_name == "image" && p_value.get_type() == Variant::IMAGE)
111 		create_from_image(p_value, flags);
112 	else if (p_name == "flags")
113 		if (w * h == 0)
114 			flags = p_value;
115 		else
116 			set_flags(p_value);
117 	else if (p_name == "size") {
118 		Size2 s = p_value;
119 		w = s.width;
120 		h = s.height;
121 		VisualServer::get_singleton()->texture_set_size_override(texture, w, h);
122 	} else if (p_name == "storage") {
123 		storage = Storage(p_value.operator int());
124 	} else if (p_name == "lossy_quality") {
125 		lossy_storage_quality = p_value;
126 	} else if (p_name == "_data") {
127 		_set_data(p_value);
128 	} else
129 		return false;
130 
131 	return true;
132 }
133 
_get(const StringName & p_name,Variant & r_ret) const134 bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
135 
136 	if (p_name == "image_data") {
137 
138 	} else if (p_name == "image")
139 		r_ret = get_data();
140 	else if (p_name == "flags")
141 		r_ret = flags;
142 	else if (p_name == "size")
143 		r_ret = Size2(w, h);
144 	else if (p_name == "storage")
145 		r_ret = storage;
146 	else if (p_name == "lossy_quality")
147 		r_ret = lossy_storage_quality;
148 	else
149 		return false;
150 
151 	return true;
152 }
153 
_get_property_list(List<PropertyInfo> * p_list) const154 void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
155 
156 	PropertyHint img_hint = PROPERTY_HINT_NONE;
157 	if (storage == STORAGE_COMPRESS_LOSSY) {
158 		img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
159 	} else if (storage == STORAGE_COMPRESS_LOSSLESS) {
160 		img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
161 	}
162 
163 	p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat"));
164 	p_list->push_back(PropertyInfo(Variant::IMAGE, "image", img_hint, String::num(lossy_storage_quality)));
165 	p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, ""));
166 	p_list->push_back(PropertyInfo(Variant::INT, "storage", PROPERTY_HINT_ENUM, "Uncompressed,Compress Lossy,Compress Lossless"));
167 	p_list->push_back(PropertyInfo(Variant::REAL, "lossy_quality", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"));
168 }
169 
_reload_hook(const RID & p_hook)170 void ImageTexture::_reload_hook(const RID &p_hook) {
171 
172 	String path = get_path();
173 	if (!path.is_resource_file())
174 		return;
175 
176 	Image img;
177 	Error err = ImageLoader::load_image(path, &img);
178 
179 	ERR_FAIL_COND(err != OK);
180 
181 	VisualServer::get_singleton()->texture_set_data(texture, img);
182 
183 	_change_notify();
184 }
185 
create(int p_width,int p_height,Image::Format p_format,uint32_t p_flags)186 void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uint32_t p_flags) {
187 
188 	flags = p_flags;
189 	VisualServer::get_singleton()->texture_allocate(texture, p_width, p_height, p_format, p_flags);
190 	format = p_format;
191 	w = p_width;
192 	h = p_height;
193 }
create_from_image(const Image & p_image,uint32_t p_flags)194 void ImageTexture::create_from_image(const Image &p_image, uint32_t p_flags) {
195 
196 	ERR_FAIL_COND(p_image.empty());
197 	flags = p_flags;
198 	w = p_image.get_width();
199 	h = p_image.get_height();
200 	format = p_image.get_format();
201 
202 	VisualServer::get_singleton()->texture_allocate(texture, p_image.get_width(), p_image.get_height(), p_image.get_format(), p_flags);
203 	VisualServer::get_singleton()->texture_set_data(texture, p_image);
204 	_change_notify();
205 }
206 
set_flags(uint32_t p_flags)207 void ImageTexture::set_flags(uint32_t p_flags) {
208 
209 	/*	uint32_t cube = flags & FLAG_CUBEMAP;
210 	if (flags == p_flags&cube)
211 		return;
212 
213 	flags=p_flags|cube;	*/
214 	flags = p_flags;
215 	VisualServer::get_singleton()->texture_set_flags(texture, p_flags);
216 }
217 
get_flags() const218 uint32_t ImageTexture::get_flags() const {
219 
220 	return ImageTexture::flags;
221 }
222 
get_format() const223 Image::Format ImageTexture::get_format() const {
224 
225 	return format;
226 }
227 
load(const String & p_path)228 void ImageTexture::load(const String &p_path) {
229 
230 	Image img;
231 	img.load(p_path);
232 	create_from_image(img);
233 }
234 
set_data(const Image & p_image)235 void ImageTexture::set_data(const Image &p_image) {
236 
237 	VisualServer::get_singleton()->texture_set_data(texture, p_image);
238 	VisualServer::get_singleton()->texture_set_reload_hook(texture, 0, StringName()); //hook is erased if data is changed
239 	_change_notify();
240 }
241 
_resource_path_changed()242 void ImageTexture::_resource_path_changed() {
243 
244 	String path = get_path();
245 	if (VS::get_singleton()->has_feature(VS::FEATURE_NEEDS_RELOAD_HOOK)) {
246 		//this needs to be done much better, but probably will end up being deprecated as technology advances
247 		if (path.is_resource_file() && ImageLoader::recognize(path.extension())) {
248 
249 			//hook is set only if path is hookable
250 			VisualServer::get_singleton()->texture_set_reload_hook(texture, get_instance_ID(), "_reload_hook");
251 		} else {
252 			VisualServer::get_singleton()->texture_set_reload_hook(texture, 0, StringName());
253 		}
254 	}
255 }
256 
get_data() const257 Image ImageTexture::get_data() const {
258 
259 	return VisualServer::get_singleton()->texture_get_data(texture);
260 }
261 
get_width() const262 int ImageTexture::get_width() const {
263 
264 	return w;
265 }
266 
get_height() const267 int ImageTexture::get_height() const {
268 
269 	return h;
270 }
271 
get_rid() const272 RID ImageTexture::get_rid() const {
273 
274 	return texture;
275 }
276 
fix_alpha_edges()277 void ImageTexture::fix_alpha_edges() {
278 
279 	if (format == Image::FORMAT_RGBA /*&& !(flags&FLAG_CUBEMAP)*/) {
280 
281 		Image img = get_data();
282 		img.fix_alpha_edges();
283 		set_data(img);
284 	}
285 }
286 
premultiply_alpha()287 void ImageTexture::premultiply_alpha() {
288 
289 	if (format == Image::FORMAT_RGBA /*&& !(flags&FLAG_CUBEMAP)*/) {
290 
291 		Image img = get_data();
292 		img.premultiply_alpha();
293 		set_data(img);
294 	}
295 }
296 
normal_to_xy()297 void ImageTexture::normal_to_xy() {
298 
299 	Image img = get_data();
300 	img.normalmap_to_xy();
301 	create_from_image(img, flags);
302 }
303 
shrink_x2_and_keep_size()304 void ImageTexture::shrink_x2_and_keep_size() {
305 
306 	Size2 sizeov = get_size();
307 	Image img = get_data();
308 	img.resize(img.get_width() / 2, img.get_height() / 2, Image::INTERPOLATE_BILINEAR);
309 	create_from_image(img, flags);
310 	set_size_override(sizeov);
311 }
312 
has_alpha() const313 bool ImageTexture::has_alpha() const {
314 
315 	return (format == Image::FORMAT_GRAYSCALE_ALPHA || format == Image::FORMAT_INDEXED_ALPHA || format == Image::FORMAT_RGBA);
316 }
317 
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose) const318 void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
319 
320 	if ((w | h) == 0)
321 		return;
322 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose);
323 }
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose) const324 void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
325 
326 	if ((w | h) == 0)
327 		return;
328 	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);
329 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose) const330 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 {
331 
332 	if ((w | h) == 0)
333 		return;
334 	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose);
335 }
336 
set_size_override(const Size2 & p_size)337 void ImageTexture::set_size_override(const Size2 &p_size) {
338 
339 	Size2 s = p_size;
340 	if (s.x != 0)
341 		w = s.x;
342 	if (s.y != 0)
343 		h = s.y;
344 	VisualServer::get_singleton()->texture_set_size_override(texture, w, h);
345 }
346 
set_path(const String & p_path,bool p_take_over)347 void ImageTexture::set_path(const String &p_path, bool p_take_over) {
348 
349 	if (texture.is_valid()) {
350 		VisualServer::get_singleton()->texture_set_path(texture, p_path);
351 	}
352 
353 	Resource::set_path(p_path, p_take_over);
354 }
355 
set_storage(Storage p_storage)356 void ImageTexture::set_storage(Storage p_storage) {
357 
358 	storage = p_storage;
359 }
360 
get_storage() const361 ImageTexture::Storage ImageTexture::get_storage() const {
362 
363 	return storage;
364 }
365 
set_lossy_storage_quality(float p_lossy_storage_quality)366 void ImageTexture::set_lossy_storage_quality(float p_lossy_storage_quality) {
367 
368 	lossy_storage_quality = p_lossy_storage_quality;
369 }
370 
get_lossy_storage_quality() const371 float ImageTexture::get_lossy_storage_quality() const {
372 
373 	return lossy_storage_quality;
374 }
375 
_set_data(Dictionary p_data)376 void ImageTexture::_set_data(Dictionary p_data) {
377 
378 	Image img = p_data["image"];
379 	uint32_t flags = p_data["flags"];
380 
381 	create_from_image(img, flags);
382 
383 	set_storage(Storage(p_data["storage"].operator int()));
384 	set_lossy_storage_quality(p_data["lossy_quality"]);
385 
386 	set_size_override(p_data["size"]);
387 };
388 
_bind_methods()389 void ImageTexture::_bind_methods() {
390 
391 	ObjectTypeDB::bind_method(_MD("create", "width", "height", "format", "flags"), &ImageTexture::create, DEFVAL(FLAGS_DEFAULT));
392 	ObjectTypeDB::bind_method(_MD("create_from_image", "image", "flags"), &ImageTexture::create_from_image, DEFVAL(FLAGS_DEFAULT));
393 	ObjectTypeDB::bind_method(_MD("get_format"), &ImageTexture::get_format);
394 	ObjectTypeDB::bind_method(_MD("load", "path"), &ImageTexture::load);
395 	ObjectTypeDB::bind_method(_MD("set_data", "image"), &ImageTexture::set_data);
396 	ObjectTypeDB::bind_method(_MD("get_data", "cube_side"), &ImageTexture::get_data);
397 	ObjectTypeDB::bind_method(_MD("set_storage", "mode"), &ImageTexture::set_storage);
398 	ObjectTypeDB::bind_method(_MD("get_storage"), &ImageTexture::get_storage);
399 	ObjectTypeDB::bind_method(_MD("set_lossy_storage_quality", "quality"), &ImageTexture::set_lossy_storage_quality);
400 	ObjectTypeDB::bind_method(_MD("get_lossy_storage_quality"), &ImageTexture::get_lossy_storage_quality);
401 	ObjectTypeDB::bind_method(_MD("fix_alpha_edges"), &ImageTexture::fix_alpha_edges);
402 	ObjectTypeDB::bind_method(_MD("premultiply_alpha"), &ImageTexture::premultiply_alpha);
403 	ObjectTypeDB::bind_method(_MD("normal_to_xy"), &ImageTexture::normal_to_xy);
404 	ObjectTypeDB::bind_method(_MD("shrink_x2_and_keep_size"), &ImageTexture::shrink_x2_and_keep_size);
405 
406 	ObjectTypeDB::bind_method(_MD("set_size_override", "size"), &ImageTexture::set_size_override);
407 	ObjectTypeDB::set_method_flags(get_type_static(), _SCS("fix_alpha_edges"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
408 	ObjectTypeDB::set_method_flags(get_type_static(), _SCS("premultiply_alpha"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
409 	ObjectTypeDB::set_method_flags(get_type_static(), _SCS("normal_to_xy"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
410 	ObjectTypeDB::set_method_flags(get_type_static(), _SCS("shrink_x2_and_keep_size"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
411 	ObjectTypeDB::bind_method(_MD("_reload_hook", "rid"), &ImageTexture::_reload_hook);
412 
413 	BIND_CONSTANT(STORAGE_RAW);
414 	BIND_CONSTANT(STORAGE_COMPRESS_LOSSY);
415 	BIND_CONSTANT(STORAGE_COMPRESS_LOSSLESS);
416 }
417 
ImageTexture()418 ImageTexture::ImageTexture() {
419 
420 	w = h = 0;
421 	flags = FLAGS_DEFAULT;
422 	texture = VisualServer::get_singleton()->texture_create();
423 	storage = STORAGE_RAW;
424 	lossy_storage_quality = 0.7;
425 }
426 
~ImageTexture()427 ImageTexture::~ImageTexture() {
428 
429 	VisualServer::get_singleton()->free(texture);
430 }
431 
432 //////////////////////////////////////////
433 
get_width() const434 int AtlasTexture::get_width() const {
435 
436 	if (region.size.width == 0) {
437 		if (atlas.is_valid())
438 			return atlas->get_width();
439 		return 1;
440 	} else {
441 		return region.size.width + margin.size.width;
442 	}
443 }
get_height() const444 int AtlasTexture::get_height() const {
445 
446 	if (region.size.height == 0) {
447 		if (atlas.is_valid())
448 			return atlas->get_height();
449 		return 1;
450 	} else {
451 		return region.size.height + margin.size.height;
452 	}
453 }
get_rid() const454 RID AtlasTexture::get_rid() const {
455 
456 	if (atlas.is_valid())
457 		return atlas->get_rid();
458 
459 	return RID();
460 }
461 
has_alpha() const462 bool AtlasTexture::has_alpha() const {
463 
464 	if (atlas.is_valid())
465 		return atlas->has_alpha();
466 
467 	return false;
468 }
469 
set_flags(uint32_t p_flags)470 void AtlasTexture::set_flags(uint32_t p_flags) {
471 
472 	if (atlas.is_valid())
473 		atlas->set_flags(p_flags);
474 }
475 
get_flags() const476 uint32_t AtlasTexture::get_flags() const {
477 
478 	if (atlas.is_valid())
479 		return atlas->get_flags();
480 
481 	return 0;
482 }
483 
set_atlas(const Ref<Texture> & p_atlas)484 void AtlasTexture::set_atlas(const Ref<Texture> &p_atlas) {
485 
486 	if (atlas == p_atlas)
487 		return;
488 	atlas = p_atlas;
489 	emit_changed();
490 	emit_signal("atlas_changed");
491 }
get_atlas() const492 Ref<Texture> AtlasTexture::get_atlas() const {
493 
494 	return atlas;
495 }
496 
set_region(const Rect2 & p_region)497 void AtlasTexture::set_region(const Rect2 &p_region) {
498 
499 	region = p_region;
500 	emit_changed();
501 }
502 
get_region() const503 Rect2 AtlasTexture::get_region() const {
504 
505 	return region;
506 }
507 
set_margin(const Rect2 & p_margin)508 void AtlasTexture::set_margin(const Rect2 &p_margin) {
509 
510 	margin = p_margin;
511 	emit_changed();
512 }
513 
get_margin() const514 Rect2 AtlasTexture::get_margin() const {
515 
516 	return margin;
517 }
518 
_bind_methods()519 void AtlasTexture::_bind_methods() {
520 
521 	ObjectTypeDB::bind_method(_MD("set_atlas", "atlas:Texture"), &AtlasTexture::set_atlas);
522 	ObjectTypeDB::bind_method(_MD("get_atlas:Texture"), &AtlasTexture::get_atlas);
523 
524 	ObjectTypeDB::bind_method(_MD("set_region", "region"), &AtlasTexture::set_region);
525 	ObjectTypeDB::bind_method(_MD("get_region"), &AtlasTexture::get_region);
526 
527 	ObjectTypeDB::bind_method(_MD("set_margin", "margin"), &AtlasTexture::set_margin);
528 	ObjectTypeDB::bind_method(_MD("get_margin"), &AtlasTexture::get_margin);
529 
530 	ADD_SIGNAL(MethodInfo("atlas_changed"));
531 
532 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_atlas"), _SCS("get_atlas"));
533 	ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region"), _SCS("set_region"), _SCS("get_region"));
534 	ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin"), _SCS("set_margin"), _SCS("get_margin"));
535 }
536 
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose) const537 void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
538 
539 	Rect2 rc = region;
540 
541 	if (!atlas.is_valid())
542 		return;
543 
544 	if (rc.size.width == 0) {
545 		rc.size.width = atlas->get_width();
546 	}
547 
548 	if (rc.size.height == 0) {
549 		rc.size.height = atlas->get_height();
550 	}
551 
552 	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.pos, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose);
553 }
554 
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose) const555 void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
556 
557 	Rect2 rc = region;
558 
559 	if (!atlas.is_valid())
560 		return;
561 
562 	if (rc.size.width == 0) {
563 		rc.size.width = atlas->get_width();
564 	}
565 
566 	if (rc.size.height == 0) {
567 		rc.size.height = atlas->get_height();
568 	}
569 
570 	Vector2 scale = p_rect.size / (region.size + margin.size);
571 	Rect2 dr(p_rect.pos + margin.pos * scale, rc.size * scale);
572 
573 	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose);
574 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose) const575 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 {
576 
577 	//this might not necesarily work well if using a rect, needs to be fixed properly
578 	Rect2 rc = region;
579 
580 	if (!atlas.is_valid())
581 		return;
582 
583 	Rect2 src = p_src_rect;
584 	src.pos += (rc.pos - margin.pos);
585 	Rect2 src_c = rc.clip(src);
586 	if (src_c.size == Size2())
587 		return;
588 	Vector2 ofs = (src_c.pos - src.pos);
589 
590 	Vector2 scale = p_rect.size / p_src_rect.size;
591 	if (scale.x < 0) {
592 		float mx = (margin.size.width - margin.pos.x);
593 		mx -= margin.pos.x;
594 		ofs.x = -(ofs.x + mx);
595 	}
596 	if (scale.y < 0) {
597 		float my = margin.size.height - margin.pos.y;
598 		my -= margin.pos.y;
599 		ofs.y = -(ofs.y + my);
600 	}
601 	Rect2 dr(p_rect.pos + ofs * scale, src_c.size * scale);
602 
603 	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose);
604 }
605 
get_rect_region_uv_rect(const Rect2 & p_rect,const Rect2 & p_src_rect,Rect2 & r_rect,Rect2 & r_uv_rect) const606 bool AtlasTexture::get_rect_region_uv_rect(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_uv_rect) const {
607 
608 	Rect2 rc = region;
609 
610 	if (!atlas.is_valid())
611 		return false;
612 
613 	Size2 atlas_size = atlas->get_size();
614 
615 	if (atlas_size.width == 0 || atlas_size.height == 0)
616 		return false;
617 
618 	Rect2 src = p_src_rect;
619 	src.pos += (rc.pos - margin.pos);
620 	Rect2 src_c = rc.clip(src);
621 	if (src_c.size == Size2())
622 		return false;
623 	Vector2 ofs = (src_c.pos - src.pos);
624 
625 	Vector2 scale = p_rect.size / p_src_rect.size;
626 	if (scale.x < 0) {
627 		float mx = (margin.size.width - margin.pos.x);
628 		mx -= margin.pos.x;
629 		ofs.x = -(ofs.x + mx);
630 	}
631 	if (scale.y < 0) {
632 		float my = margin.size.height - margin.pos.y;
633 		my -= margin.pos.y;
634 		ofs.y = -(ofs.y + my);
635 	}
636 	Rect2 dr(p_rect.pos + ofs * scale, src_c.size * scale);
637 
638 	r_rect = dr;
639 	r_uv_rect = Rect2(src_c.get_pos() / atlas_size, src_c.get_size() / atlas_size);
640 	return true;
641 }
642 
AtlasTexture()643 AtlasTexture::AtlasTexture() {
644 }
645 
646 //////////////////////////////////////////
647 
get_width() const648 int LargeTexture::get_width() const {
649 
650 	return size.width;
651 }
get_height() const652 int LargeTexture::get_height() const {
653 
654 	return size.height;
655 }
get_rid() const656 RID LargeTexture::get_rid() const {
657 
658 	return RID();
659 }
660 
has_alpha() const661 bool LargeTexture::has_alpha() const {
662 
663 	for (int i = 0; i < pieces.size(); i++) {
664 		if (pieces[i].texture->has_alpha())
665 			return true;
666 	}
667 
668 	return false;
669 }
670 
set_flags(uint32_t p_flags)671 void LargeTexture::set_flags(uint32_t p_flags) {
672 
673 	for (int i = 0; i < pieces.size(); i++) {
674 		pieces[i].texture->set_flags(p_flags);
675 	}
676 }
677 
get_flags() const678 uint32_t LargeTexture::get_flags() const {
679 
680 	if (pieces.size())
681 		return pieces[0].texture->get_flags();
682 
683 	return 0;
684 }
685 
add_piece(const Point2 & p_offset,const Ref<Texture> & p_texture)686 int LargeTexture::add_piece(const Point2 &p_offset, const Ref<Texture> &p_texture) {
687 
688 	ERR_FAIL_COND_V(p_texture.is_null(), -1);
689 	Piece p;
690 	p.offset = p_offset;
691 	p.texture = p_texture;
692 	pieces.push_back(p);
693 
694 	return pieces.size() - 1;
695 }
696 
set_piece_offset(int p_idx,const Point2 & p_offset)697 void LargeTexture::set_piece_offset(int p_idx, const Point2 &p_offset) {
698 
699 	ERR_FAIL_INDEX(p_idx, pieces.size());
700 	pieces[p_idx].offset = p_offset;
701 };
702 
set_piece_texture(int p_idx,const Ref<Texture> & p_texture)703 void LargeTexture::set_piece_texture(int p_idx, const Ref<Texture> &p_texture) {
704 
705 	ERR_FAIL_INDEX(p_idx, pieces.size());
706 	pieces[p_idx].texture = p_texture;
707 };
708 
set_size(const Size2 & p_size)709 void LargeTexture::set_size(const Size2 &p_size) {
710 
711 	size = p_size;
712 }
clear()713 void LargeTexture::clear() {
714 
715 	pieces.clear();
716 	size = Size2i();
717 }
718 
_get_data() const719 Array LargeTexture::_get_data() const {
720 
721 	Array arr;
722 	for (int i = 0; i < pieces.size(); i++) {
723 		arr.push_back(pieces[i].offset);
724 		arr.push_back(pieces[i].texture);
725 	}
726 	arr.push_back(Size2(size));
727 	return arr;
728 }
_set_data(const Array & p_array)729 void LargeTexture::_set_data(const Array &p_array) {
730 
731 	ERR_FAIL_COND(p_array.size() < 1);
732 	ERR_FAIL_COND(!(p_array.size() & 1));
733 	clear();
734 	for (int i = 0; i < p_array.size() - 1; i += 2) {
735 		add_piece(p_array[i], p_array[i + 1]);
736 	}
737 	size = Size2(p_array[p_array.size() - 1]);
738 }
739 
get_piece_count() const740 int LargeTexture::get_piece_count() const {
741 
742 	return pieces.size();
743 }
get_piece_offset(int p_idx) const744 Vector2 LargeTexture::get_piece_offset(int p_idx) const {
745 
746 	ERR_FAIL_INDEX_V(p_idx, pieces.size(), Vector2());
747 	return pieces[p_idx].offset;
748 }
get_piece_texture(int p_idx) const749 Ref<Texture> LargeTexture::get_piece_texture(int p_idx) const {
750 
751 	ERR_FAIL_INDEX_V(p_idx, pieces.size(), Ref<Texture>());
752 	return pieces[p_idx].texture;
753 }
754 
_bind_methods()755 void LargeTexture::_bind_methods() {
756 
757 	ObjectTypeDB::bind_method(_MD("add_piece", "ofs", "texture:Texture"), &LargeTexture::add_piece);
758 	ObjectTypeDB::bind_method(_MD("set_piece_offset", "idx", "ofs"), &LargeTexture::set_piece_offset);
759 	ObjectTypeDB::bind_method(_MD("set_piece_texture", "idx", "texture:Texture"), &LargeTexture::set_piece_texture);
760 	ObjectTypeDB::bind_method(_MD("set_size", "size"), &LargeTexture::set_size);
761 	ObjectTypeDB::bind_method(_MD("clear"), &LargeTexture::clear);
762 
763 	ObjectTypeDB::bind_method(_MD("get_piece_count"), &LargeTexture::get_piece_count);
764 	ObjectTypeDB::bind_method(_MD("get_piece_offset", "idx"), &LargeTexture::get_piece_offset);
765 	ObjectTypeDB::bind_method(_MD("get_piece_texture:Texture", "idx"), &LargeTexture::get_piece_texture);
766 
767 	ObjectTypeDB::bind_method(_MD("_set_data", "data"), &LargeTexture::_set_data);
768 	ObjectTypeDB::bind_method(_MD("_get_data"), &LargeTexture::_get_data);
769 
770 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"), _SCS("_get_data"));
771 }
772 
draw(RID p_canvas_item,const Point2 & p_pos,const Color & p_modulate,bool p_transpose) const773 void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
774 
775 	for (int i = 0; i < pieces.size(); i++) {
776 
777 		// TODO
778 		pieces[i].texture->draw(p_canvas_item, pieces[i].offset + p_pos, p_modulate, p_transpose);
779 	}
780 }
781 
draw_rect(RID p_canvas_item,const Rect2 & p_rect,bool p_tile,const Color & p_modulate,bool p_transpose) const782 void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
783 
784 	//tiling not supported for this
785 	if (size.x == 0 || size.y == 0)
786 		return;
787 
788 	Size2 scale = p_rect.size / size;
789 
790 	for (int i = 0; i < pieces.size(); i++) {
791 
792 		// TODO
793 		pieces[i].texture->draw_rect(p_canvas_item, Rect2(pieces[i].offset * scale + p_rect.pos, pieces[i].texture->get_size() * scale), false, p_modulate, p_transpose);
794 	}
795 }
draw_rect_region(RID p_canvas_item,const Rect2 & p_rect,const Rect2 & p_src_rect,const Color & p_modulate,bool p_transpose) const796 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 {
797 
798 	//tiling not supported for this
799 	if (p_src_rect.size.x == 0 || p_src_rect.size.y == 0)
800 		return;
801 
802 	Size2 scale = p_rect.size / p_src_rect.size;
803 
804 	for (int i = 0; i < pieces.size(); i++) {
805 
806 		// TODO
807 		Rect2 rect(pieces[i].offset, pieces[i].texture->get_size());
808 		if (!p_src_rect.intersects(rect))
809 			continue;
810 		Rect2 local = p_src_rect.clip(rect);
811 		Rect2 target = local;
812 		target.size *= scale;
813 		target.pos = p_rect.pos + (p_src_rect.pos + rect.pos) * scale;
814 		local.pos -= rect.pos;
815 		pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose);
816 	}
817 }
818 
LargeTexture()819 LargeTexture::LargeTexture() {
820 }
821 
822 ///////////////////////////////////////////////
823 
set_flags(uint32_t p_flags)824 void CubeMap::set_flags(uint32_t p_flags) {
825 
826 	flags = p_flags;
827 	if (_is_valid())
828 		VS::get_singleton()->texture_set_flags(cubemap, flags | VS::TEXTURE_FLAG_CUBEMAP);
829 }
830 
get_flags() const831 uint32_t CubeMap::get_flags() const {
832 
833 	return flags;
834 }
835 
set_side(Side p_side,const Image & p_image)836 void CubeMap::set_side(Side p_side, const Image &p_image) {
837 
838 	ERR_FAIL_COND(p_image.empty());
839 	ERR_FAIL_INDEX(p_side, 6);
840 	if (!_is_valid()) {
841 		format = p_image.get_format();
842 		w = p_image.get_width();
843 		h = p_image.get_height();
844 		VS::get_singleton()->texture_allocate(cubemap, w, h, p_image.get_format(), flags | VS::TEXTURE_FLAG_CUBEMAP);
845 	}
846 
847 	VS::get_singleton()->texture_set_data(cubemap, p_image, VS::CubeMapSide(p_side));
848 	valid[p_side] = true;
849 }
850 
get_side(Side p_side) const851 Image CubeMap::get_side(Side p_side) const {
852 
853 	if (!valid[p_side])
854 		return Image();
855 	return VS::get_singleton()->texture_get_data(cubemap, VS::CubeMapSide(p_side));
856 }
857 
get_format() const858 Image::Format CubeMap::get_format() const {
859 
860 	return format;
861 }
get_width() const862 int CubeMap::get_width() const {
863 
864 	return w;
865 }
get_height() const866 int CubeMap::get_height() const {
867 
868 	return h;
869 }
870 
get_rid() const871 RID CubeMap::get_rid() const {
872 
873 	return cubemap;
874 }
875 
set_storage(Storage p_storage)876 void CubeMap::set_storage(Storage p_storage) {
877 
878 	storage = p_storage;
879 }
880 
get_storage() const881 CubeMap::Storage CubeMap::get_storage() const {
882 
883 	return storage;
884 }
885 
set_lossy_storage_quality(float p_lossy_storage_quality)886 void CubeMap::set_lossy_storage_quality(float p_lossy_storage_quality) {
887 
888 	lossy_storage_quality = p_lossy_storage_quality;
889 }
890 
get_lossy_storage_quality() const891 float CubeMap::get_lossy_storage_quality() const {
892 
893 	return lossy_storage_quality;
894 }
895 
set_path(const String & p_path,bool p_take_over)896 void CubeMap::set_path(const String &p_path, bool p_take_over) {
897 
898 	if (cubemap.is_valid()) {
899 		VisualServer::get_singleton()->texture_set_path(cubemap, p_path);
900 	}
901 
902 	Resource::set_path(p_path, p_take_over);
903 }
904 
_set(const StringName & p_name,const Variant & p_value)905 bool CubeMap::_set(const StringName &p_name, const Variant &p_value) {
906 
907 	if (p_name == "side/left") {
908 		set_side(SIDE_LEFT, p_value);
909 	} else if (p_name == "side/right") {
910 		set_side(SIDE_RIGHT, p_value);
911 	} else if (p_name == "side/bottom") {
912 		set_side(SIDE_BOTTOM, p_value);
913 	} else if (p_name == "side/top") {
914 		set_side(SIDE_TOP, p_value);
915 	} else if (p_name == "side/front") {
916 		set_side(SIDE_FRONT, p_value);
917 	} else if (p_name == "side/back") {
918 		set_side(SIDE_BACK, p_value);
919 	} else if (p_name == "flags") {
920 		set_flags(p_value);
921 	} else if (p_name == "storage") {
922 		storage = Storage(p_value.operator int());
923 	} else if (p_name == "lossy_quality") {
924 		lossy_storage_quality = p_value;
925 	} else
926 		return false;
927 
928 	return true;
929 }
930 
_get(const StringName & p_name,Variant & r_ret) const931 bool CubeMap::_get(const StringName &p_name, Variant &r_ret) const {
932 
933 	if (p_name == "side/left") {
934 		r_ret = get_side(SIDE_LEFT);
935 	} else if (p_name == "side/right") {
936 		r_ret = get_side(SIDE_RIGHT);
937 	} else if (p_name == "side/bottom") {
938 		r_ret = get_side(SIDE_BOTTOM);
939 	} else if (p_name == "side/top") {
940 		r_ret = get_side(SIDE_TOP);
941 	} else if (p_name == "side/front") {
942 		r_ret = get_side(SIDE_FRONT);
943 	} else if (p_name == "side/back") {
944 		r_ret = get_side(SIDE_BACK);
945 	} else if (p_name == "flags") {
946 		r_ret = flags;
947 	} else if (p_name == "storage") {
948 		r_ret = storage;
949 	} else if (p_name == "lossy_quality") {
950 		r_ret = lossy_storage_quality;
951 	} else
952 		return false;
953 
954 	return true;
955 }
956 
_get_property_list(List<PropertyInfo> * p_list) const957 void CubeMap::_get_property_list(List<PropertyInfo> *p_list) const {
958 
959 	PropertyHint img_hint = PROPERTY_HINT_NONE;
960 	if (storage == STORAGE_COMPRESS_LOSSY) {
961 		img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
962 	} else if (storage == STORAGE_COMPRESS_LOSSLESS) {
963 		img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
964 	}
965 
966 	p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"));
967 	p_list->push_back(PropertyInfo(Variant::IMAGE, "side/left", img_hint, String::num(lossy_storage_quality)));
968 	p_list->push_back(PropertyInfo(Variant::IMAGE, "side/right", img_hint, String::num(lossy_storage_quality)));
969 	p_list->push_back(PropertyInfo(Variant::IMAGE, "side/bottom", img_hint, String::num(lossy_storage_quality)));
970 	p_list->push_back(PropertyInfo(Variant::IMAGE, "side/top", img_hint, String::num(lossy_storage_quality)));
971 	p_list->push_back(PropertyInfo(Variant::IMAGE, "side/front", img_hint, String::num(lossy_storage_quality)));
972 	p_list->push_back(PropertyInfo(Variant::IMAGE, "side/back", img_hint, String::num(lossy_storage_quality)));
973 	p_list->push_back(PropertyInfo(Variant::INT, "storage", PROPERTY_HINT_ENUM, "Uncompressed,Compress Lossy,Compress Lossless", PROPERTY_USAGE_EDITOR));
974 	p_list->push_back(PropertyInfo(Variant::REAL, "lossy_quality", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"));
975 }
976 
_bind_methods()977 void CubeMap::_bind_methods() {
978 
979 	ObjectTypeDB::bind_method(_MD("get_width"), &CubeMap::get_width);
980 	ObjectTypeDB::bind_method(_MD("get_height"), &CubeMap::get_height);
981 	ObjectTypeDB::bind_method(_MD("get_rid"), &CubeMap::get_rid);
982 	ObjectTypeDB::bind_method(_MD("set_flags", "flags"), &CubeMap::set_flags);
983 	ObjectTypeDB::bind_method(_MD("get_flags"), &CubeMap::get_flags);
984 
985 	ObjectTypeDB::bind_method(_MD("set_side", "side", "image"), &CubeMap::set_side);
986 	ObjectTypeDB::bind_method(_MD("get_side", "side"), &CubeMap::get_side);
987 	ObjectTypeDB::bind_method(_MD("set_storage", "mode"), &CubeMap::set_storage);
988 	ObjectTypeDB::bind_method(_MD("get_storage"), &CubeMap::get_storage);
989 	ObjectTypeDB::bind_method(_MD("set_lossy_storage_quality", "quality"), &CubeMap::set_lossy_storage_quality);
990 	ObjectTypeDB::bind_method(_MD("get_lossy_storage_quality"), &CubeMap::get_lossy_storage_quality);
991 
992 	BIND_CONSTANT(STORAGE_RAW);
993 	BIND_CONSTANT(STORAGE_COMPRESS_LOSSY);
994 	BIND_CONSTANT(STORAGE_COMPRESS_LOSSLESS);
995 	BIND_CONSTANT(SIDE_LEFT);
996 	BIND_CONSTANT(SIDE_RIGHT);
997 	BIND_CONSTANT(SIDE_BOTTOM);
998 	BIND_CONSTANT(SIDE_TOP);
999 	BIND_CONSTANT(SIDE_FRONT);
1000 	BIND_CONSTANT(SIDE_BACK);
1001 	BIND_CONSTANT(FLAG_MIPMAPS);
1002 	BIND_CONSTANT(FLAG_REPEAT);
1003 	BIND_CONSTANT(FLAG_FILTER);
1004 	BIND_CONSTANT(FLAGS_DEFAULT);
1005 }
1006 
CubeMap()1007 CubeMap::CubeMap() {
1008 
1009 	w = h = 0;
1010 	flags = FLAGS_DEFAULT;
1011 	for (int i = 0; i < 6; i++)
1012 		valid[i] = false;
1013 	cubemap = VisualServer::get_singleton()->texture_create();
1014 	storage = STORAGE_RAW;
1015 	lossy_storage_quality = 0.7;
1016 }
1017 
~CubeMap()1018 CubeMap::~CubeMap() {
1019 
1020 	VisualServer::get_singleton()->free(cubemap);
1021 }
1022 
1023 /*	BIND_CONSTANT( FLAG_CUBEMAP );
1024 	BIND_CONSTANT( CUBEMAP_LEFT );
1025 	BIND_CONSTANT( CUBEMAP_RIGHT );
1026 	BIND_CONSTANT( CUBEMAP_BOTTOM );
1027 	BIND_CONSTANT( CUBEMAP_TOP );
1028 	BIND_CONSTANT( CUBEMAP_FRONT );
1029 	BIND_CONSTANT( CUBEMAP_BACK );
1030 */
1031