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