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