diff options
51 files changed, 1321 insertions, 264 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index d81ccf0265..095f058ed9 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -31,6 +31,7 @@ #include "core/global_config.h" #include "geometry.h" +#include "io/file_access_compressed.h" #include "io/file_access_encrypted.h" #include "io/marshalls.h" #include "os/keyboard.h" @@ -1395,6 +1396,24 @@ Error _File::open_encrypted_pass(const String &p_path, int p_mode_flags, const S return OK; } +Error _File::open_compressed(const String &p_path, int p_mode_flags, int p_compress_mode) { + + FileAccessCompressed *fac = memnew(FileAccessCompressed); + Error err = OK; + + fac->configure("GCPF", (Compression::Mode)p_compress_mode); + + err = fac->_open(p_path, p_mode_flags); + + if (err) { + memdelete(fac); + return err; + } + + f = fac; + return OK; +} + Error _File::open(const String &p_path, int p_mode_flags) { close(); @@ -1700,6 +1719,7 @@ void _File::_bind_methods() { ClassDB::bind_method(D_METHOD("open_encrypted", "path", "mode_flags", "key"), &_File::open_encrypted); ClassDB::bind_method(D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &_File::open_encrypted_pass); + ClassDB::bind_method(D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &_File::open_compressed, DEFVAL(0)); ClassDB::bind_method(D_METHOD("open", "path", "flags"), &_File::open); ClassDB::bind_method(D_METHOD("close"), &_File::close); @@ -1749,6 +1769,10 @@ void _File::_bind_methods() { BIND_CONSTANT(WRITE); BIND_CONSTANT(READ_WRITE); BIND_CONSTANT(WRITE_READ); + + BIND_CONSTANT(COMPRESSION_FASTLZ); + BIND_CONSTANT(COMPRESSION_DEFLATE); + BIND_CONSTANT(COMPRESSION_ZSTD); } _File::_File() { diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index a2fb6c966c..87d84c0732 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -31,6 +31,7 @@ #define CORE_BIND_H #include "image.h" +#include "io/compression.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/dir_access.h" @@ -366,8 +367,15 @@ public: WRITE_READ = 7, }; + enum CompressionMode { + COMPRESSION_FASTLZ = Compression::MODE_FASTLZ, + COMPRESSION_DEFLATE = Compression::MODE_DEFLATE, + COMPRESSION_ZSTD = Compression::MODE_ZSTD + }; + Error open_encrypted(const String &p_path, int p_mode_flags, const Vector<uint8_t> &p_key); Error open_encrypted_pass(const String &p_path, int p_mode_flags, const String &p_pass); + Error open_compressed(const String &p_path, int p_mode_flags, int p_compress_mode = 0); Error open(const String &p_path, int p_mode_flags); ///< open a file void close(); ///< close a file diff --git a/core/image.cpp b/core/image.cpp index ad52447935..ec21260b19 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1646,6 +1646,133 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po } } +void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest) { + + ERR_FAIL_COND(p_src.is_null()); + int dsize = data.size(); + int srcdsize = p_src->data.size(); + ERR_FAIL_COND(dsize == 0); + ERR_FAIL_COND(srcdsize == 0); + ERR_FAIL_COND(format != p_src->format); + + Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect); + if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) + return; + + Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest, clipped_src_rect.size)); + + lock(); + Ref<Image> img = p_src; + img->lock(); + + for (int i = 0; i < dest_rect.size.y; i++) { + + for (int j = 0; j < dest_rect.size.x; j++) { + + int src_x = clipped_src_rect.position.x + j; + int src_y = clipped_src_rect.position.y + i; + + int dst_x = dest_rect.position.x + j; + int dst_y = dest_rect.position.y + i; + + Color sc = img->get_pixel(src_x, src_y); + Color dc = get_pixel(dst_x, dst_y); + dc.r = (double)(sc.a * sc.r + dc.a * (1.0 - sc.a) * dc.r); + dc.g = (double)(sc.a * sc.g + dc.a * (1.0 - sc.a) * dc.g); + dc.b = (double)(sc.a * sc.b + dc.a * (1.0 - sc.a) * dc.b); + dc.a = (double)(sc.a + dc.a * (1.0 - sc.a)); + put_pixel(dst_x, dst_y, dc); + } + } + + img->unlock(); + unlock(); +} + +void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest) { + + ERR_FAIL_COND(p_src.is_null()); + ERR_FAIL_COND(p_mask.is_null()); + int dsize = data.size(); + int srcdsize = p_src->data.size(); + int maskdsize = p_mask->data.size(); + ERR_FAIL_COND(dsize == 0); + ERR_FAIL_COND(srcdsize == 0); + ERR_FAIL_COND(maskdsize == 0); + ERR_FAIL_COND(p_src->width != p_mask->width); + ERR_FAIL_COND(p_src->height != p_mask->height); + ERR_FAIL_COND(format != p_src->format); + + Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect); + if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) + return; + + Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest, clipped_src_rect.size)); + + lock(); + Ref<Image> img = p_src; + Ref<Image> msk = p_mask; + img->lock(); + msk->lock(); + + for (int i = 0; i < dest_rect.size.y; i++) { + + for (int j = 0; j < dest_rect.size.x; j++) { + + int src_x = clipped_src_rect.position.x + j; + int src_y = clipped_src_rect.position.y + i; + + // If the mask's pixel is transparent then we skip it + //Color c = msk->get_pixel(src_x, src_y); + //if (c.a == 0) continue; + if (msk->get_pixel(src_x, src_y).a != 0) { + + int dst_x = dest_rect.position.x + j; + int dst_y = dest_rect.position.y + i; + + Color sc = img->get_pixel(src_x, src_y); + Color dc = get_pixel(dst_x, dst_y); + dc.r = (double)(sc.a * sc.r + dc.a * (1.0 - sc.a) * dc.r); + dc.g = (double)(sc.a * sc.g + dc.a * (1.0 - sc.a) * dc.g); + dc.b = (double)(sc.a * sc.b + dc.a * (1.0 - sc.a) * dc.b); + dc.a = (double)(sc.a + dc.a * (1.0 - sc.a)); + put_pixel(dst_x, dst_y, dc); + } + } + } + + msk->unlock(); + img->unlock(); + unlock(); +} + +void Image::fill(const Color &c) { + + lock(); + + PoolVector<uint8_t>::Write wp = data.write(); + uint8_t *dst_data_ptr = wp.ptr(); + + int pixel_size = get_format_pixel_size(format); + + // put first pixel with the format-aware API + put_pixel(0, 0, c); + + for (int y = 0; y < height; y++) { + + for (int x = 0; x < width; x++) { + + uint8_t *dst = &dst_data_ptr[(y * width + x) * pixel_size]; + + for (int k = 0; k < pixel_size; k++) { + dst[k] = dst_data_ptr[k]; + } + } + } + + unlock(); +} + Ref<Image> (*Image::_png_mem_loader_func)(const uint8_t *, int) = NULL; Ref<Image> (*Image::_jpg_mem_loader_func)(const uint8_t *, int) = NULL; @@ -2072,6 +2199,9 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("normalmap_to_xy"), &Image::normalmap_to_xy); ClassDB::bind_method(D_METHOD("blit_rect", "src:Image", "src_rect", "dst"), &Image::blit_rect); + ClassDB::bind_method(D_METHOD("blend_rect", "src:Image", "src_rect", "dst"), &Image::blend_rect); + ClassDB::bind_method(D_METHOD("blend_rect_mask", "src:Image", "mask:Image", "src_rect", "dst"), &Image::blend_rect_mask); + ClassDB::bind_method(D_METHOD("fill", "color"), &Image::fill); ClassDB::bind_method(D_METHOD("get_used_rect"), &Image::get_used_rect); ClassDB::bind_method(D_METHOD("get_rect:Image", "rect"), &Image::get_rect); diff --git a/core/image.h b/core/image.h index 838b37352d..3323afdc4b 100644 --- a/core/image.h +++ b/core/image.h @@ -283,6 +283,9 @@ public: void normalmap_to_xy(); void blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest); + void blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest); + void blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest); + void fill(const Color &c); Rect2 get_used_rect() const; Ref<Image> get_rect(const Rect2 &p_area) const; diff --git a/core/math/matrix3.h b/core/math/matrix3.h index c3eeb1f705..8897c692f7 100644 --- a/core/math/matrix3.h +++ b/core/math/matrix3.h @@ -145,6 +145,12 @@ public: elements[2][1] = zy; elements[2][2] = zz; } + _FORCE_INLINE_ void set(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) { + + set_axis(0, p_x); + set_axis(1, p_y); + set_axis(2, p_z); + } _FORCE_INLINE_ Vector3 get_column(int i) const { return Vector3(elements[0][i], elements[1][i], elements[2][i]); diff --git a/core/math/transform.cpp b/core/math/transform.cpp index e53e6cf519..7a50214596 100644 --- a/core/math/transform.cpp +++ b/core/math/transform.cpp @@ -82,7 +82,10 @@ Transform Transform::looking_at(const Vector3 &p_target, const Vector3 &p_up) co } void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { - +#ifdef MATH_CHECKS + ERR_FAIL_COND(p_eye == p_target); + ERR_FAIL_COND(p_up.length() == 0); +#endif // Reference: MESA source code Vector3 v_x, v_y, v_z; @@ -96,6 +99,9 @@ void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const v_y = p_up; v_x = v_y.cross(v_z); +#ifdef MATH_CHECKS + ERR_FAIL_COND(v_x.length() == 0); +#endif /* Recompute Y = Z cross X */ v_y = v_z.cross(v_x); @@ -103,9 +109,8 @@ void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const v_x.normalize(); v_y.normalize(); - basis.set_axis(0, v_x); - basis.set_axis(1, v_y); - basis.set_axis(2, v_z); + basis.set(v_x, v_y, v_z); + origin = p_eye; } diff --git a/core/math/transform.h b/core/math/transform.h index c39ea7826f..48467f2ed7 100644 --- a/core/math/transform.h +++ b/core/math/transform.h @@ -97,15 +97,7 @@ public: void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz) { - basis.elements[0][0] = xx; - basis.elements[0][1] = xy; - basis.elements[0][2] = xz; - basis.elements[1][0] = yx; - basis.elements[1][1] = yy; - basis.elements[1][2] = yz; - basis.elements[2][0] = zx; - basis.elements[2][1] = zy; - basis.elements[2][2] = zz; + basis.set(xx, xy, xz, yx, yy, yz, zx, zy, zz); origin.x = tx; origin.y = ty; origin.z = tz; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 9ead727a80..6936a362e1 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -30,6 +30,7 @@ #include "variant.h" #include "core_string_names.h" +#include "io/compression.h" #include "object.h" #include "os/os.h" #include "script_language.h" @@ -509,6 +510,44 @@ struct _VariantCall { r_ret = s; } + static void _call_PoolByteArray_compress(Variant &r_ret, Variant &p_self, const Variant **p_args) { + + PoolByteArray *ba = reinterpret_cast<PoolByteArray *>(p_self._data._mem); + PoolByteArray compressed; + Compression::Mode mode = (Compression::Mode)(int)(*p_args[0]); + + compressed.resize(Compression::get_max_compressed_buffer_size(ba->size())); + int result = Compression::compress(compressed.write().ptr(), ba->read().ptr(), ba->size(), mode); + + result = result >= 0 ? result : 0; + compressed.resize(result); + + r_ret = compressed; + } + + static void _call_PoolByteArray_decompress(Variant &r_ret, Variant &p_self, const Variant **p_args) { + + PoolByteArray *ba = reinterpret_cast<PoolByteArray *>(p_self._data._mem); + PoolByteArray decompressed; + Compression::Mode mode = (Compression::Mode)(int)(*p_args[1]); + + int buffer_size = (int)(*p_args[0]); + + if (buffer_size < 0) { + r_ret = decompressed; + ERR_EXPLAIN("Decompression buffer size is less than zero"); + ERR_FAIL(); + } + + decompressed.resize(buffer_size); + int result = Compression::decompress(decompressed.write().ptr(), buffer_size, ba->read().ptr(), ba->size(), mode); + + result = result >= 0 ? result : 0; + decompressed.resize(result); + + r_ret = decompressed; + } + VCALL_LOCALMEM0R(PoolByteArray, size); VCALL_LOCALMEM2(PoolByteArray, set); VCALL_LOCALMEM1R(PoolByteArray, get); @@ -1552,6 +1591,8 @@ void register_variant_methods() { ADDFUNC0(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_ascii, varray()); ADDFUNC0(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_utf8, varray()); + ADDFUNC1(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, compress, INT, "compression_mode", varray(0)); + ADDFUNC2(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, decompress, INT, "buffer_size", INT, "compression_mode", varray(0)); ADDFUNC0(POOL_INT_ARRAY, INT, PoolIntArray, size, varray()); ADDFUNC2(POOL_INT_ARRAY, NIL, PoolIntArray, set, INT, "idx", INT, "integer", varray()); diff --git a/doc/base/classes.xml b/doc/base/classes.xml index 2331d49c1f..c2c8d3e8dd 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -15299,6 +15299,19 @@ Open the file for writing or reading, depending on the flags. </description> </method> + <method name="open_compressed"> + <return type="int"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="mode_flags" type="int"> + </argument> + <argument index="2" name="compression_mode" type="int" default="0"> + </argument> + <description> + Open a compressed file for reading or writing. The compression_mode can be set as one of the COMPRESSION_* constants. + </description> + </method> <method name="open_encrypted"> <return type="int"> </return> @@ -15445,6 +15458,15 @@ <constant name="WRITE_READ" value="7"> Open the file for reading and writing. Create it if the file not exists and truncate if it exists. </constant> + <constant name="COMPRESSION_FASTLZ" value="0"> + Use the FastLZ compression method. + </constant> + <constant name="COMPRESSION_DEFLATE" value="1"> + Use the Deflate compression method. + </constant> + <constant name="COMPRESSION_ZSTD" value="2"> + Use the Zstd compression method. + </constant> </constants> </class> <class name="FileDialog" inherits="ConfirmationDialog" category="Core"> @@ -18949,6 +18971,30 @@ Native image datatype. Contains image data, which can be converted to a texture, and several functions to interact with it. </description> <methods> + <method name="blend_rect"> + <argument index="0" name="src" type="Image"> + </argument> + <argument index="1" name="src_rect" type="Rect2"> + </argument> + <argument index="2" name="dst" type="Vector2"> + </argument> + <description> + Alpha-blends a "src_rect" [Rect2] from "src" [Image] to this [Image] on coordinates "dest". + </description> + </method> + <method name="blend_rect_mask"> + <argument index="0" name="src" type="Image"> + </argument> + <argument index="1" name="mask" type="Image"> + </argument> + <argument index="2" name="src_rect" type="Rect2"> + </argument> + <argument index="3" name="dst" type="Vector2"> + </argument> + <description> + Alpha-blends a "src_rect" [Rect2] from "src" [Image] to this [Image] using a "mask" [Image] on coordinates "dest". Alpha channels are required for both "src" and "mask", dest pixels and src pixels will blend if the corresponding mask pixel's alpha value is not 0. "src" [Image] and "mask" [Image] *must* have the same size (width and height) but they can have different formats + </description> + </method> <method name="blit_rect"> <argument index="0" name="src" type="Image"> </argument> @@ -19039,6 +19085,13 @@ <description> </description> </method> + <method name="fill"> + <argument index="0" name="color" type="Color"> + </argument> + <description> + Fills an [Image] with a specified [Color] + </description> + </method> <method name="fix_alpha_edges"> <description> </description> @@ -33733,6 +33786,26 @@ Append an [PoolByteArray] at the end of this array. </description> </method> + <method name="compress"> + <return type="PoolByteArray"> + </return> + <argument index="0" name="compression_mode" type="int" default="0"> + </argument> + <description> + Returns a new [PoolByteArray] with the data compressed. The compression mode can be set using one of the COMPRESS_* constants of [File]. + </description> + </method> + <method name="decompress"> + <return type="PoolByteArray"> + </return> + <argument index="0" name="buffer_size" type="int"> + </argument> + <argument index="1" name="compression_mode" type="int" default="0"> + </argument> + <description> + Returns a new [PoolByteArray] with the data decompressed. The buffer_size should be set as the size of the uncompressed data. The compression mode can be set using one of the COMPRESS_* constants of [File]. + </description> + </method> <method name="get_string_from_ascii"> <return type="String"> </return> @@ -34651,6 +34724,13 @@ Returns a boolean that indicates whether or not the PopupMenu will hide on item selection. </description> </method> + <method name="is_hide_on_checkable_item_selection"> + <return type="bool"> + </return> + <description> + Returns a boolean that indicates whether or not the PopupMenu will hide on checkable item selection. + </description> + </method> <method name="is_item_checkable" qualifiers="const"> <return type="bool"> </return> @@ -34701,6 +34781,13 @@ Sets whether or not the PopupMenu will hide on item selection. </description> </method> + <method name="set_hide_on_checkable_item_selection"> + <argument index="0" name="enable" type="bool"> + </argument> + <description> + Sets whether or not the PopupMenu will hide on checkable item selection. + </description> + </method> <method name="set_item_ID"> <argument index="0" name="idx" type="int"> </argument> diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 0c07abb002..a8895f7bfc 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -466,8 +466,10 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - glVertexAttrib4f(1, rect->rect.position.x, rect->rect.position.y, rect->rect.size.x, rect->rect.size.y); - glVertexAttrib4f(2, src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y); + state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(rect->rect.position.x, rect->rect.position.y, rect->rect.size.x, rect->rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, (rect->flags & CANVAS_RECT_CLIP_UV) ? true : false); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); if (untile) { @@ -477,8 +479,9 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur } else { - glVertexAttrib4f(1, rect->rect.position.x, rect->rect.position.y, rect->rect.size.x, rect->rect.size.y); - glVertexAttrib4f(2, 0, 0, 1, 1); + state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(rect->rect.position.x, rect->rect.position.y, rect->rect.size.x, rect->rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(0, 0, 1, 1)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } @@ -507,9 +510,10 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false); -#define DSTRECT(m_x, m_y, m_w, m_h) glVertexAttrib4f(1, m_x, m_y, m_w, m_h) -#define SRCRECT(m_x, m_y, m_w, m_h) glVertexAttrib4f(2, (m_x)*texpixel_size.x, (m_y)*texpixel_size.y, (m_w)*texpixel_size.x, (m_h)*texpixel_size.y) +#define DSTRECT(m_x, m_y, m_w, m_h) state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(m_x, m_y, m_w, m_h)) +#define SRCRECT(m_x, m_y, m_w, m_h) state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color((m_x)*texpixel_size.x, (m_y)*texpixel_size.y, (m_w)*texpixel_size.x, (m_h)*texpixel_size.y)) //top left DSTRECT(np->rect.position.x, np->rect.position.y, np->margin[MARGIN_LEFT], np->margin[MARGIN_TOP]); @@ -1312,8 +1316,10 @@ void RasterizerCanvasGLES3::reset_canvas() { void RasterizerCanvasGLES3::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) { - glVertexAttrib4f(1, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y); - glVertexAttrib4f(2, p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y); + state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index b0ce38cb68..7be6ee857a 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -6,8 +6,8 @@ layout(location=3) in vec4 color_attrib; #ifdef USE_TEXTURE_RECT -layout(location=1) in highp vec4 dst_rect; -layout(location=2) in highp vec4 src_rect; +uniform vec4 dst_rect; +uniform vec4 src_rect; #else @@ -65,6 +65,7 @@ const bool at_light_pass = false; #endif + VERTEX_SHADER_GLOBALS #if defined(USE_MATERIAL) @@ -228,22 +229,39 @@ LIGHT_SHADER_CODE } +#ifdef USE_TEXTURE_RECT + +uniform vec4 dst_rect; +uniform vec4 src_rect; +uniform bool clip_rect_uv; + +#endif + uniform bool use_default_normal; void main() { vec4 color = color_interp; + vec2 uv = uv_interp; +#ifdef USE_TEXTURE_RECT + if (clip_rect_uv) { + + vec2 half_texpixel = color_texpixel_size * 0.5; + uv = clamp(uv,src_rect.xy+half_texpixel,src_rect.xy+abs(src_rect.zw)-color_texpixel_size); + } + +#endif #if !defined(COLOR_USED) //default behavior, texture by color #ifdef USE_DISTANCE_FIELD const float smoothing = 1.0/32.0; - float distance = textureLod(color_texture, uv_interp,0.0).a; + float distance = textureLod(color_texture, uv,0.0).a; color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance) * color.a; #else - color *= texture( color_texture, uv_interp ); + color *= texture( color_texture, uv ); #endif @@ -259,7 +277,7 @@ void main() { #endif if (use_default_normal) { - normal.xy = textureLod(normal_texture, uv_interp,0.0).xy * 2.0 - 1.0; + normal.xy = textureLod(normal_texture, uv,0.0).xy * 2.0 - 1.0; normal.z = sqrt(1.0-dot(normal.xy,normal.xy)); normal_used=true; } else { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 3a0825be9b..56b62cdf6e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6142,6 +6142,7 @@ EditorNode::EditorNode() { editor_plugin_screen = NULL; editor_plugins_over = memnew(EditorPluginList); + editor_plugins_force_input_forwarding = memnew(EditorPluginList); //force_top_viewport(true); _edit_current(); @@ -6290,6 +6291,7 @@ EditorNode::~EditorNode() { memdelete(EditorHelp::get_doc_data()); memdelete(editor_selection); memdelete(editor_plugins_over); + memdelete(editor_plugins_force_input_forwarding); memdelete(file_server); EditorSettings::destroy(); } @@ -6325,10 +6327,14 @@ bool EditorPluginList::forward_gui_input(const Transform2D &p_canvas_xform, cons return discard; } -bool EditorPluginList::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { +bool EditorPluginList::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled) { bool discard = false; for (int i = 0; i < plugins_list.size(); i++) { + if ((!serve_when_force_input_enabled) && plugins_list[i]->is_input_event_forwarding_always_enabled()) { + continue; + } + if (plugins_list[i]->forward_spatial_gui_input(p_camera, p_event)) { discard = true; } @@ -6344,6 +6350,10 @@ void EditorPluginList::forward_draw_over_canvas(const Transform2D &p_canvas_xfor } } +void EditorPluginList::add_plugin(EditorPlugin *p_plugin) { + plugins_list.push_back(p_plugin); +} + bool EditorPluginList::empty() { return plugins_list.empty(); } diff --git a/editor/editor_node.h b/editor/editor_node.h index 0f4561572a..3870edb7c6 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -398,6 +398,7 @@ private: Vector<EditorPlugin *> editor_plugins; EditorPlugin *editor_plugin_screen; EditorPluginList *editor_plugins_over; + EditorPluginList *editor_plugins_force_input_forwarding; EditorHistory editor_history; EditorData editor_data; @@ -647,6 +648,7 @@ public: EditorPlugin *get_editor_plugin_screen() { return editor_plugin_screen; } EditorPluginList *get_editor_plugins_over() { return editor_plugins_over; } + EditorPluginList *get_editor_plugins_force_input_forwarding() { return editor_plugins_force_input_forwarding; } PropertyEditor *get_property_editor() { return property_editor; } VBoxContainer *get_property_editor_vb() { return prop_editor_vb; } @@ -823,8 +825,9 @@ public: void make_visible(bool p_visible); void edit(Object *p_object); bool forward_gui_input(const Transform2D &p_canvas_xform, const Ref<InputEvent> &p_event); - bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event); + bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled); void forward_draw_over_canvas(const Transform2D &p_canvas_xform, Control *p_canvas); + void add_plugin(EditorPlugin *p_plugin); void clear(); bool empty(); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 6fcea98e32..75ab1e8a44 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -147,6 +147,12 @@ void EditorPlugin::remove_tool_menu_item(const String &p_name) { //EditorNode::get_singleton()->remove_tool_menu_item(p_name); } +void EditorPlugin::set_input_event_forwarding_always_enabled() { + input_event_forwarding_always_enabled = true; + EditorPluginList *always_input_forwarding_list = EditorNode::get_singleton()->get_editor_plugins_force_input_forwarding(); + always_input_forwarding_list->add_plugin(this); +} + Ref<SpatialEditorGizmo> EditorPlugin::create_spatial_gizmo(Spatial *p_spatial) { //?? if (get_script_instance() && get_script_instance()->has_method("create_spatial_gizmo")) { @@ -372,6 +378,7 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("edit_resource"), &EditorPlugin::edit_resource); ClassDB::bind_method(D_METHOD("add_import_plugin"), &EditorPlugin::add_import_plugin); ClassDB::bind_method(D_METHOD("remove_import_plugin"), &EditorPlugin::remove_import_plugin); + ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_canvas_gui_input", PropertyInfo(Variant::TRANSFORM2D, "canvas_xform"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_draw_over_canvas", PropertyInfo(Variant::TRANSFORM2D, "canvas_xform"), PropertyInfo(Variant::OBJECT, "canvas:Control"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); @@ -414,6 +421,7 @@ void EditorPlugin::_bind_methods() { EditorPlugin::EditorPlugin() { undo_redo = NULL; + input_event_forwarding_always_enabled = false; } EditorPlugin::~EditorPlugin() { diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index c607846ec9..57a22a8b2f 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -61,6 +61,8 @@ class EditorPlugin : public Node { UndoRedo *_get_undo_redo() { return undo_redo; } + bool input_event_forwarding_always_enabled; + protected: static void _bind_methods(); UndoRedo &get_undo_redo() { return *undo_redo; } @@ -106,6 +108,9 @@ public: void add_tool_submenu_item(const String &p_name, Object *p_submenu); void remove_tool_menu_item(const String &p_name); + void set_input_event_forwarding_always_enabled(); + bool is_input_event_forwarding_always_enabled() { return input_event_forwarding_always_enabled; } + virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); virtual bool forward_canvas_gui_input(const Transform2D &p_canvas_xform, const Ref<InputEvent> &p_event); virtual void forward_draw_over_canvas(const Transform2D &p_canvas_xform, Control *p_canvas); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 803e59469c..4313c1a91b 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3270,6 +3270,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { PopupMenu *p; p = edit_menu->get_popup(); + p->set_hide_on_checkable_item_selection(false); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_snap", TTR("Use Snap")), SNAP_USE); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Show Grid")), SNAP_SHOW_GRID); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_rotation_snap", TTR("Use Rotation Snap")), SNAP_USE_ROTATION); @@ -3291,6 +3292,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { skeleton_menu->add_separator(); skeleton_menu->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_set_ik_chain", TTR("Make IK Chain")), SKELETON_SET_IK_CHAIN); skeleton_menu->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_ik_chain", TTR("Clear IK Chain")), SKELETON_CLEAR_IK_CHAIN); + skeleton_menu->set_hide_on_checkable_item_selection(false); skeleton_menu->connect("id_pressed", this, "_popup_callback"); /* diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 7f8b98e1d3..11d804422a 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -427,13 +427,14 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from) { Color text_color = EditorSettings::get_singleton()->get("text_editor/highlighting/text_color"); Color symbol_color = EditorSettings::get_singleton()->get("text_editor/highlighting/symbol_color"); + img->lock(); + for (int i = 0; i < thumbnail_size; i++) { for (int j = 0; j < thumbnail_size; j++) { img->put_pixel(i, j, bg_color); } } - img->lock(); bool prev_is_text = false; bool in_keyword = false; for (int i = 0; i < code.length(); i++) { diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 5da242ffaa..2d27e218ec 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -696,12 +696,19 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { return; //do NONE { - + EditorNode *en = editor; + EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding(); + if (!force_input_forwarding_list->empty()) { + bool discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true); + if (discard) + return; + } + } + { EditorNode *en = editor; EditorPluginList *over_plugin_list = en->get_editor_plugins_over(); - if (!over_plugin_list->empty()) { - bool discard = over_plugin_list->forward_spatial_gui_input(camera, p_event); + bool discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false); if (discard) return; } diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 976a7b6271..ea5bf437ff 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -792,6 +792,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { hb_tools->add_child(snap_mode_button); snap_mode_button->set_text(TTR("<None>")); PopupMenu *p = snap_mode_button->get_popup(); + p->set_hide_on_checkable_item_selection(false); p->add_item(TTR("<None>"), 0); p->add_item(TTR("Pixel Snap"), 1); p->add_item(TTR("Grid Snap"), 2); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 3d3fecc8f9..da26c84e45 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -65,6 +65,9 @@ void CustomPropertyEditor::_notification(int p_what) { VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2( 10,10,60, get_size().height-20 ), v ); }*/ } + if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) { + hide(); + } } void CustomPropertyEditor::_menu_option(int p_which) { diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index ae00fb429e..9df26f1471 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -46,14 +46,12 @@ #define DOM_BUTTON_RIGHT 2 template <typename T> -static InputModifierState dom2godot_mod(T emscripten_event_ptr) { +static void dom2godot_mod(T emscripten_event_ptr, Ref<InputEventWithModifiers> godot_event) { - InputModifierState mod; - mod.shift = emscripten_event_ptr->shiftKey; - mod.alt = emscripten_event_ptr->altKey; - mod.control = emscripten_event_ptr->ctrlKey; - mod.meta = emscripten_event_ptr->metaKey; - return mod; + godot_event->set_shift(emscripten_event_ptr->shiftKey); + godot_event->set_alt(emscripten_event_ptr->altKey); + godot_event->set_control(emscripten_event_ptr->ctrlKey); + godot_event->set_metakey(emscripten_event_ptr->metaKey); } int OS_JavaScript::get_video_driver_count() const { @@ -151,26 +149,26 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_MOUSEDOWN && event_type != EMSCRIPTEN_EVENT_MOUSEUP, false); - Ref<InputEvent> ev; - ev.type = Ref<InputEvent>::MOUSE_BUTTON; - ev->is_pressed() = event_type == EMSCRIPTEN_EVENT_MOUSEDOWN; - ev.mouse_button.global_x = ev->get_pos().x = mouse_event->canvasX; - ev.mouse_button.global_y = ev->get_pos().y = mouse_event->canvasY; - ev.mouse_button.mod = dom2godot_mod(mouse_event); + Ref<InputEventMouseButton> ev; + ev.instance(); + ev->set_pressed(event_type == EMSCRIPTEN_EVENT_MOUSEDOWN); + ev->set_position(Point2(mouse_event->canvasX, mouse_event->canvasY)); + ev->set_global_position(ev->get_position()); + dom2godot_mod(mouse_event, ev); switch (mouse_event->button) { - case DOM_BUTTON_LEFT: ev->get_button_index() = BUTTON_LEFT; break; - case DOM_BUTTON_MIDDLE: ev->get_button_index() = BUTTON_MIDDLE; break; - case DOM_BUTTON_RIGHT: ev->get_button_index() = BUTTON_RIGHT; break; + case DOM_BUTTON_LEFT: ev->set_button_index(BUTTON_LEFT); break; + case DOM_BUTTON_MIDDLE: ev->set_button_index(BUTTON_MIDDLE); break; + case DOM_BUTTON_RIGHT: ev->set_button_index(BUTTON_RIGHT); break; default: return false; } - ev->get_button_mask() = _input->get_mouse_button_mask(); + int mask = _input->get_mouse_button_mask(); if (ev->is_pressed()) - ev->get_button_mask() |= 1 << ev->get_button_index(); + mask |= 1 << ev->get_button_index(); else - ev->get_button_mask() &= ~(1 << ev->get_button_index()); - ev->get_button_mask() >>= 1; + mask &= ~(1 << ev->get_button_index()); + ev->set_button_mask(mask >> 1); _input->parse_input_event(ev); return true; @@ -180,20 +178,17 @@ static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *m ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_MOUSEMOVE, false); - Ref<InputEvent> ev; - ev.type = Ref<InputEvent>::MOUSE_MOTION; - ev.mouse_motion.mod = dom2godot_mod(mouse_event); - ev->get_button_mask() = _input->get_mouse_button_mask() >> 1; + Ref<InputEventMouseMotion> ev; + ev.instance(); + dom2godot_mod(mouse_event, ev); + ev->set_button_mask(_input->get_mouse_button_mask() >> 1); - ev.mouse_motion.global_x = ev.mouse_motion.x = mouse_event->canvasX; - ev.mouse_motion.global_y = ev.mouse_motion.y = mouse_event->canvasY; + ev->set_position(Point2(mouse_event->canvasX, mouse_event->canvasY)); + ev->set_global_position(ev->get_position()); - ev->get_relative().x = _input->get_mouse_position().x - ev.mouse_motion.x; - ev->get_relative().y = _input->get_mouse_position().y - ev.mouse_motion.y; - - _input->set_mouse_position(Point2(ev.mouse_motion.x, ev.mouse_motion.y)); - ev.mouse_motion.speed_x = _input->get_last_mouse_speed().x; - ev.mouse_motion.speed_y = _input->get_last_mouse_speed().y; + ev->set_relative(_input->get_mouse_position() - ev->get_position()); + _input->set_mouse_position(ev->get_position()); + ev->set_speed(_input->get_last_mouse_speed()); _input->parse_input_event(ev); return true; @@ -203,31 +198,35 @@ static EM_BOOL _wheel_callback(int event_type, const EmscriptenWheelEvent *wheel ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_WHEEL, false); - Ref<InputEvent> ev; - ev.type = Ref<InputEvent>::MOUSE_BUTTON; - ev->get_button_mask() = _input->get_mouse_button_mask() >> 1; - ev.mouse_button.global_x = ev->get_pos().x = _input->get_mouse_position().x; - ev.mouse_button.global_y = ev->get_pos().y = _input->get_mouse_position().y; - ev.mouse_button->get_shift() = _input->is_key_pressed(KEY_SHIFT); - ev.mouse_button->get_alt() = _input->is_key_pressed(KEY_ALT); - ev.mouse_button->get_control() = _input->is_key_pressed(KEY_CONTROL); - ev.mouse_button->get_metakey() = _input->is_key_pressed(KEY_META); + Ref<InputEventMouseButton> ev; + ev.instance(); + ev->set_button_mask(_input->get_mouse_button_mask() >> 1); + ev->set_position(_input->get_mouse_position()); + ev->set_global_position(ev->get_position()); + + ev->set_shift(_input->is_key_pressed(KEY_SHIFT)); + ev->set_alt(_input->is_key_pressed(KEY_ALT)); + ev->set_control(_input->is_key_pressed(KEY_CONTROL)); + ev->set_metakey(_input->is_key_pressed(KEY_META)); if (wheel_event->deltaY < 0) - ev->get_button_index() = BUTTON_WHEEL_UP; + ev->set_button_index(BUTTON_WHEEL_UP); else if (wheel_event->deltaY > 0) - ev->get_button_index() = BUTTON_WHEEL_DOWN; + ev->set_button_index(BUTTON_WHEEL_DOWN); else if (wheel_event->deltaX > 0) - ev->get_button_index() = BUTTON_WHEEL_LEFT; + ev->set_button_index(BUTTON_WHEEL_LEFT); else if (wheel_event->deltaX < 0) - ev->get_button_index() = BUTTON_WHEEL_RIGHT; + ev->set_button_index(BUTTON_WHEEL_RIGHT); else return false; - ev->is_pressed() = true; + // Different browsers give wildly different delta values, and we can't + // interpret deltaMode, so use default value for wheel events' factor + + ev->set_pressed(true); _input->parse_input_event(ev); - ev->is_pressed() = false; + ev->set_pressed(false); _input->parse_input_event(ev); return true; @@ -243,8 +242,8 @@ static EM_BOOL _touchpress_callback(int event_type, const EmscriptenTouchEvent * event_type != EMSCRIPTEN_EVENT_TOUCHCANCEL, false); - Ref<InputEvent> ev; - ev.type = Ref<InputEvent>::SCREEN_TOUCH; + Ref<InputEventScreenTouch> ev; + ev.instance(); int lowest_id_index = -1; for (int i = 0; i < touch_event->numTouches; ++i) { @@ -253,25 +252,29 @@ static EM_BOOL _touchpress_callback(int event_type, const EmscriptenTouchEvent * lowest_id_index = i; if (!touch.isChanged) continue; - ev.screen_touch.index = touch.identifier; - _prev_touches[i].x = ev.screen_touch.x = touch.canvasX; - _prev_touches[i].y = ev.screen_touch.y = touch.canvasY; - ev.screen_touch->is_pressed() = event_type == EMSCRIPTEN_EVENT_TOUCHSTART; + ev->set_index(touch.identifier); + ev->set_position(Point2(touch.canvasX, touch.canvasY)); + _prev_touches[i] = ev->get_position(); + ev->set_pressed(event_type == EMSCRIPTEN_EVENT_TOUCHSTART); _input->parse_input_event(ev); } if (touch_event->touches[lowest_id_index].isChanged) { - ev.type = Ref<InputEvent>::MOUSE_BUTTON; - ev.mouse_button.mod = dom2godot_mod(touch_event); - ev->get_button_mask() = _input->get_mouse_button_mask() >> 1; - ev.mouse_button.global_x = ev->get_pos().x = touch_event->touches[lowest_id_index].canvasX; - ev.mouse_button.global_y = ev->get_pos().y = touch_event->touches[lowest_id_index].canvasY; - ev->get_button_index() = BUTTON_LEFT; - ev->is_pressed() = event_type == EMSCRIPTEN_EVENT_TOUCHSTART; + Ref<InputEventMouseButton> ev_mouse; + ev_mouse.instance(); + ev_mouse->set_button_mask(_input->get_mouse_button_mask() >> 1); + dom2godot_mod(touch_event, ev_mouse); - _input->parse_input_event(ev); + const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index]; + ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY)); + ev_mouse->set_global_position(ev_mouse->get_position()); + + ev_mouse->set_button_index(BUTTON_LEFT); + ev_mouse->set_pressed(event_type == EMSCRIPTEN_EVENT_TOUCHSTART); + + _input->parse_input_event(ev_mouse); } return true; } @@ -280,8 +283,8 @@ static EM_BOOL _touchmove_callback(int event_type, const EmscriptenTouchEvent *t ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_TOUCHMOVE, false); - Ref<InputEvent> ev; - ev.type = Ref<InputEvent>::SCREEN_DRAG; + Ref<InputEventScreenDrag> ev; + ev.instance(); int lowest_id_index = -1; for (int i = 0; i < touch_event->numTouches; ++i) { @@ -290,44 +293,42 @@ static EM_BOOL _touchmove_callback(int event_type, const EmscriptenTouchEvent *t lowest_id_index = i; if (!touch.isChanged) continue; - ev.screen_drag.index = touch.identifier; - ev.screen_drag.x = touch.canvasX; - ev.screen_drag.y = touch.canvasY; + ev->set_index(touch.identifier); + ev->set_position(Point2(touch.canvasX, touch.canvasY)); Point2 &prev = _prev_touches[i]; - ev.screen_drag.relative_x = touch.canvasX - prev.x; - ev.screen_drag.relative_y = touch.canvasY - prev.y; - prev.x = ev.screen_drag.x; - prev.y = ev.screen_drag.y; + ev->set_relative(ev->get_position() - prev); + prev = ev->get_position(); _input->parse_input_event(ev); } if (touch_event->touches[lowest_id_index].isChanged) { - ev.type = Ref<InputEvent>::MOUSE_MOTION; - ev.mouse_motion.mod = dom2godot_mod(touch_event); - ev->get_button_mask() = _input->get_mouse_button_mask() >> 1; - ev.mouse_motion.global_x = ev.mouse_motion.x = touch_event->touches[lowest_id_index].canvasX; - ev.mouse_motion.global_y = ev.mouse_motion.y = touch_event->touches[lowest_id_index].canvasY; - ev->get_relative().x = _input->get_mouse_position().x - ev.mouse_motion.x; - ev->get_relative().y = _input->get_mouse_position().y - ev.mouse_motion.y; + Ref<InputEventMouseMotion> ev_mouse; + ev_mouse.instance(); + dom2godot_mod(touch_event, ev_mouse); + ev_mouse->set_button_mask(_input->get_mouse_button_mask() >> 1); - _input->set_mouse_position(Point2(ev.mouse_motion.x, ev.mouse_motion.y)); - ev.mouse_motion.speed_x = _input->get_last_mouse_speed().x; - ev.mouse_motion.speed_y = _input->get_last_mouse_speed().y; + const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index]; + ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY)); + ev_mouse->set_global_position(ev_mouse->get_position()); - _input->parse_input_event(ev); + ev_mouse->set_relative(_input->get_mouse_position() - ev_mouse->get_position()); + _input->set_mouse_position(ev_mouse->get_position()); + ev_mouse->set_speed(_input->get_last_mouse_speed()); + + _input->parse_input_event(ev_mouse); } return true; } -static Ref<InputEvent> _setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) { +static Ref<InputEventKey> _setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) { - Ref<InputEvent> ev; - ev.type = Ref<InputEvent>::KEY; - ev->is_echo() = emscripten_event->repeat; - ev.key.mod = dom2godot_mod(emscripten_event); - ev->get_scancode() = dom2godot_scancode(emscripten_event->keyCode); + Ref<InputEventKey> ev; + ev.instance(); + ev->set_echo(emscripten_event->repeat); + dom2godot_mod(emscripten_event, ev); + ev->set_scancode(dom2godot_scancode(emscripten_event->keyCode)); String unicode = String::utf8(emscripten_event->key); // check if empty or multi-character (e.g. `CapsLock`) @@ -336,21 +337,21 @@ static Ref<InputEvent> _setup_key_event(const EmscriptenKeyboardEvent *emscripte unicode = String::utf8(emscripten_event->charValue); } if (unicode.length() == 1) { - ev.key.unicode = unicode[0]; + ev->set_unicode(unicode[0]); } return ev; } -static Ref<InputEvent> deferred_key_event; +static Ref<InputEventKey> deferred_key_event; static EM_BOOL _keydown_callback(int event_type, const EmscriptenKeyboardEvent *key_event, void *user_data) { ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_KEYDOWN, false); - Ref<InputEvent> ev = _setup_key_event(key_event); - ev->is_pressed() = true; - if (ev.key.unicode == 0 && keycode_has_unicode(ev->get_scancode())) { + Ref<InputEventKey> ev = _setup_key_event(key_event); + ev->set_pressed(true); + if (ev->get_unicode() == 0 && keycode_has_unicode(ev->get_scancode())) { // defer to keypress event for legacy unicode retrieval deferred_key_event = ev; return false; // do not suppress keypress event @@ -363,7 +364,7 @@ static EM_BOOL _keypress_callback(int event_type, const EmscriptenKeyboardEvent ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_KEYPRESS, false); - deferred_key_event.key.unicode = key_event->charCode; + deferred_key_event->set_unicode(key_event->charCode); _input->parse_input_event(deferred_key_event); return true; } @@ -372,8 +373,8 @@ static EM_BOOL _keyup_callback(int event_type, const EmscriptenKeyboardEvent *ke ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_KEYUP, false); - Ref<InputEvent> ev = _setup_key_event(key_event); - ev->is_pressed() = false; + Ref<InputEventKey> ev = _setup_key_event(key_event); + ev->set_pressed(false); _input->parse_input_event(ev); return ev->get_scancode() != KEY_UNKNOWN && ev->get_scancode() != 0; } diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h index 2274450647..80defac079 100644 --- a/scene/2d/animated_sprite.h +++ b/scene/2d/animated_sprite.h @@ -99,7 +99,7 @@ public: const Map<StringName, Anim>::Element *EN = animations.find(E->get().normal_name); - if (p_idx >= EN->get().frames.size()) + if (!EN || p_idx >= EN->get().frames.size()) return Ref<Texture>(); return EN->get().frames[p_idx]; diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index aca7a8c736..db22a38cec 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -29,7 +29,9 @@ /*************************************************************************/ #include "area_2d.h" #include "scene/scene_string_names.h" +#include "servers/audio_server.h" #include "servers/physics_2d_server.h" + void Area2D::set_space_override_mode(SpaceOverride p_mode) { space_override = p_mode; @@ -542,6 +544,47 @@ bool Area2D::get_collision_layer_bit(int p_bit) const { return get_collision_layer() & (1 << p_bit); } +void Area2D::set_audio_bus_override(bool p_override) { + + audio_bus_override = p_override; +} + +bool Area2D::is_overriding_audio_bus() const { + + return audio_bus_override; +} + +void Area2D::set_audio_bus(const StringName &p_audio_bus) { + + audio_bus = p_audio_bus; +} + +StringName Area2D::get_audio_bus() const { + + for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { + if (AudioServer::get_singleton()->get_bus_name(i) == audio_bus) { + return audio_bus; + } + } + return "Master"; +} + +void Area2D::_validate_property(PropertyInfo &property) const { + + if (property.name == "audio_bus_name") { + + String options; + for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { + if (i > 0) + options += ","; + String name = AudioServer::get_singleton()->get_bus_name(i); + options += name; + } + + property.hint_string = options; + } +} + void Area2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_body_enter_tree", "id"), &Area2D::_body_enter_tree); @@ -598,6 +641,12 @@ void Area2D::_bind_methods() { ClassDB::bind_method(D_METHOD("overlaps_body", "body"), &Area2D::overlaps_body); ClassDB::bind_method(D_METHOD("overlaps_area", "area"), &Area2D::overlaps_area); + ClassDB::bind_method(D_METHOD("set_audio_bus", "name"), &Area2D::set_audio_bus); + ClassDB::bind_method(D_METHOD("get_audio_bus"), &Area2D::get_audio_bus); + + ClassDB::bind_method(D_METHOD("set_audio_bus_override", "enable"), &Area2D::set_audio_bus_override); + ClassDB::bind_method(D_METHOD("is_overriding_audio_bus"), &Area2D::is_overriding_audio_bus); + ClassDB::bind_method(D_METHOD("_body_inout"), &Area2D::_body_inout); ClassDB::bind_method(D_METHOD("_area_inout"), &Area2D::_area_inout); @@ -624,6 +673,10 @@ void Area2D::_bind_methods() { ADD_GROUP("Collision", "collision_"); ADD_PROPERTYNO(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTYNO(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); + + ADD_GROUP("Audio Bus", "audio_bus_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus", "get_audio_bus"); } Area2D::Area2D() @@ -642,6 +695,7 @@ Area2D::Area2D() monitorable = false; collision_mask = 1; collision_layer = 1; + audio_bus_override = false; set_monitoring(true); set_monitorable(true); } diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index f0eb1e9240..12d71f3911 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -126,9 +126,13 @@ private: Map<ObjectID, AreaState> area_map; void _clear_monitoring(); + bool audio_bus_override; + StringName audio_bus; + protected: void _notification(int p_what); static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; public: void set_space_override_mode(SpaceOverride p_mode); @@ -179,6 +183,12 @@ public: bool overlaps_area(Node *p_area) const; bool overlaps_body(Node *p_body) const; + void set_audio_bus_override(bool p_override); + bool is_overriding_audio_bus() const; + + void set_audio_bus(const StringName &p_audio_bus); + StringName get_audio_bus() const; + Area2D(); ~Area2D(); }; diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp new file mode 100644 index 0000000000..3d9e64ae79 --- /dev/null +++ b/scene/2d/audio_stream_player_2d.cpp @@ -0,0 +1,463 @@ + +#include "audio_stream_player_2d.h" +#include "scene/2d/area_2d.h" +#include "scene/main/viewport.h" +void AudioStreamPlayer2D::_mix_audio() { + + if (!stream_playback.is_valid()) { + return; + } + + if (!active) { + return; + } + + if (setseek >= 0.0) { + stream_playback->start(setseek); + setseek = -1.0; //reset seek + } + + //get data + AudioFrame *buffer = mix_buffer.ptr(); + int buffer_size = mix_buffer.size(); + + //mix + stream_playback->mix(buffer, 1.0, buffer_size); + + //write all outputs + for (int i = 0; i < output_count; i++) { + + Output current = outputs[i]; + + //see if current output exists, to keep volume ramp + bool found = false; + for (int j = i; j < prev_output_count; j++) { + if (prev_outputs[j].viewport == current.viewport) { + if (j != i) { + SWAP(prev_outputs[j], prev_outputs[i]); + } + found = true; + break; + } + } + + if (!found) { + //create new if was not used before + if (prev_output_count < MAX_OUTPUTS) { + prev_outputs[prev_output_count] = prev_outputs[i]; //may be owned by another viewport + prev_output_count++; + } + prev_outputs[i] = current; + } + + //mix! + AudioFrame vol_inc = (current.vol - prev_outputs[i].vol) / float(buffer_size); + AudioFrame vol = current.vol; + + switch (AudioServer::get_singleton()->get_speaker_mode()) { + + case AudioServer::SPEAKER_MODE_STEREO: { + AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 0); + + for (int j = 0; j < buffer_size; j++) { + + target[j] = buffer[j] * vol; + vol += vol_inc; + } + + } break; + case AudioServer::SPEAKER_SURROUND_51: { + + AudioFrame *targets[2] = { + AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 1), + AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 2), + }; + + for (int j = 0; j < buffer_size; j++) { + + AudioFrame frame = buffer[j] * vol; + targets[0][j] = frame; + targets[1][j] = frame; + vol += vol_inc; + } + + } break; + case AudioServer::SPEAKER_SURROUND_71: { + + AudioFrame *targets[3] = { + AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 1), + AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 2), + AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 3) + }; + + for (int j = 0; j < buffer_size; j++) { + + AudioFrame frame = buffer[j] * vol; + targets[0][j] = frame; + targets[1][j] = frame; + targets[2][j] = frame; + vol += vol_inc; + } + + } break; + } + + prev_outputs[i] = current; + } + + prev_output_count = output_count; + + //stream is no longer active, disable this. + if (!stream_playback->is_playing()) { + active = false; + } + + output_ready = false; +} + +void AudioStreamPlayer2D::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + + AudioServer::get_singleton()->add_callback(_mix_audios, this); + if (autoplay && !get_tree()->is_editor_hint()) { + play(); + } + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + + AudioServer::get_singleton()->remove_callback(_mix_audios, this); + } + + if (p_what == NOTIFICATION_INTERNAL_FIXED_PROCESS) { + + //update anything related to position first, if possible of course + + if (!output_ready) { + List<Viewport *> viewports; + Ref<World2D> world_2d = get_world_2d(); + ERR_FAIL_COND(world_2d.is_null()); + + int new_output_count = 0; + + Vector2 global_pos = get_global_position(); + + int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus); + + //check if any area is diverting sound into a bus + + Physics2DDirectSpaceState *space_state = Physics2DServer::get_singleton()->space_get_direct_state(world_2d->get_space()); + + Physics2DDirectSpaceState::ShapeResult sr[MAX_INTERSECT_AREAS]; + + int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, Physics2DDirectSpaceState::TYPE_MASK_AREA); + + for (int i = 0; i < areas; i++) { + if (!sr[i].collider) + continue; + + Area2D *area2d = sr[i].collider->cast_to<Area2D>(); + if (!area2d) + continue; + + if (!area2d->is_overriding_audio_bus()) + continue; + + StringName bus_name = area2d->get_audio_bus(); + bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name); + break; + } + + world_2d->get_viewport_list(&viewports); + for (List<Viewport *>::Element *E = viewports.front(); E; E = E->next()) { + + Viewport *vp = E->get(); + if (vp->is_audio_listener_2d()) { + + //compute matrix to convert to screen + Transform2D to_screen = vp->get_global_canvas_transform() * vp->get_canvas_transform(); + Vector2 screen_size = vp->get_visible_rect().size; + + //screen in global is used for attenuation + Vector2 screen_in_global = to_screen.affine_inverse().xform(screen_size * 0.5); + + float dist = global_pos.distance_to(screen_in_global); //distance to screen center + + if (dist > max_distance) + continue; //cant hear this sound in this viewport + + float multiplier = Math::pow(1.0f - dist / max_distance, attenuation); + multiplier *= Math::db2linear(volume_db); //also apply player volume! + + //point in screen is used for panning + Vector2 point_in_screen = to_screen.xform(global_pos); + + float pan = CLAMP(point_in_screen.x / screen_size.width, 0.0, 1.0); + + float l = 1.0 - pan; + float r = pan; + + outputs[new_output_count].vol = AudioFrame(l, r) * multiplier; + outputs[new_output_count].bus_index = bus_index; + outputs[new_output_count].viewport = vp; //keep pointer only for reference + new_output_count++; + if (new_output_count == MAX_OUTPUTS) + break; + } + } + + output_count = new_output_count; + output_ready = true; + } + + //start playing if requested + if (setplay >= 0.0) { + setseek = setplay; + active = true; + setplay = -1; + _change_notify("playing"); //update property in editor + } + + //stop playing if no longer active + if (!active) { + set_fixed_process_internal(false); + _change_notify("playing"); //update property in editor + } + } +} + +void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) { + + ERR_FAIL_COND(!p_stream.is_valid()); + AudioServer::get_singleton()->lock(); + + mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size()); + + if (stream_playback.is_valid()) { + stream_playback.unref(); + stream.unref(); + active = false; + setseek = -1; + } + + stream = p_stream; + stream_playback = p_stream->instance_playback(); + + if (stream_playback.is_null()) { + stream.unref(); + ERR_FAIL_COND(stream_playback.is_null()); + } + + AudioServer::get_singleton()->unlock(); +} + +Ref<AudioStream> AudioStreamPlayer2D::get_stream() const { + + return stream; +} + +void AudioStreamPlayer2D::set_volume_db(float p_volume) { + + volume_db = p_volume; +} +float AudioStreamPlayer2D::get_volume_db() const { + + return volume_db; +} + +void AudioStreamPlayer2D::play(float p_from_pos) { + + if (stream_playback.is_valid()) { + setplay = p_from_pos; + output_ready = false; + set_fixed_process_internal(true); + } +} + +void AudioStreamPlayer2D::seek(float p_seconds) { + + if (stream_playback.is_valid()) { + setseek = p_seconds; + } +} + +void AudioStreamPlayer2D::stop() { + + if (stream_playback.is_valid()) { + active = false; + set_fixed_process_internal(false); + setplay = -1; + } +} + +bool AudioStreamPlayer2D::is_playing() const { + + if (stream_playback.is_valid()) { + return active; // && stream_playback->is_playing(); + } + + return false; +} + +float AudioStreamPlayer2D::get_pos() { + + if (stream_playback.is_valid()) { + return stream_playback->get_pos(); + } + + return 0; +} + +void AudioStreamPlayer2D::set_bus(const StringName &p_bus) { + + //if audio is active, must lock this + AudioServer::get_singleton()->lock(); + bus = p_bus; + AudioServer::get_singleton()->unlock(); +} +StringName AudioStreamPlayer2D::get_bus() const { + + for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { + if (AudioServer::get_singleton()->get_bus_name(i) == bus) { + return bus; + } + } + return "Master"; +} + +void AudioStreamPlayer2D::set_autoplay(bool p_enable) { + + autoplay = p_enable; +} +bool AudioStreamPlayer2D::is_autoplay_enabled() { + + return autoplay; +} + +void AudioStreamPlayer2D::_set_playing(bool p_enable) { + + if (p_enable) + play(); + else + stop(); +} +bool AudioStreamPlayer2D::_is_active() const { + + return active; +} + +void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const { + + if (property.name == "bus") { + + String options; + for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { + if (i > 0) + options += ","; + String name = AudioServer::get_singleton()->get_bus_name(i); + options += name; + } + + property.hint_string = options; + } +} + +void AudioStreamPlayer2D::_bus_layout_changed() { + + _change_notify(); +} + +void AudioStreamPlayer2D::set_max_distance(float p_pixels) { + + ERR_FAIL_COND(p_pixels <= 0.0); + max_distance = p_pixels; +} + +float AudioStreamPlayer2D::get_max_distance() const { + + return max_distance; +} + +void AudioStreamPlayer2D::set_attenuation(float p_curve) { + + attenuation = p_curve; +} +float AudioStreamPlayer2D::get_attenuation() const { + + return attenuation; +} + +void AudioStreamPlayer2D::set_area_mask(uint32_t p_mask) { + + area_mask = p_mask; +} + +uint32_t AudioStreamPlayer2D::get_area_mask() const { + + return area_mask; +} + +void AudioStreamPlayer2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_stream", "stream:AudioStream"), &AudioStreamPlayer2D::set_stream); + ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer2D::get_stream); + + ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer2D::set_volume_db); + ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer2D::get_volume_db); + + ClassDB::bind_method(D_METHOD("play", "from_pos"), &AudioStreamPlayer2D::play, DEFVAL(0.0)); + ClassDB::bind_method(D_METHOD("seek", "to_pos"), &AudioStreamPlayer2D::seek); + ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer2D::stop); + + ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayer2D::is_playing); + ClassDB::bind_method(D_METHOD("get_pos"), &AudioStreamPlayer2D::get_pos); + + ClassDB::bind_method(D_METHOD("set_bus", "bus"), &AudioStreamPlayer2D::set_bus); + ClassDB::bind_method(D_METHOD("get_bus"), &AudioStreamPlayer2D::get_bus); + + ClassDB::bind_method(D_METHOD("set_autoplay", "enable"), &AudioStreamPlayer2D::set_autoplay); + ClassDB::bind_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer2D::is_autoplay_enabled); + + ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer2D::_set_playing); + ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer2D::_is_active); + + ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &AudioStreamPlayer2D::set_max_distance); + ClassDB::bind_method(D_METHOD("get_max_distance"), &AudioStreamPlayer2D::get_max_distance); + + ClassDB::bind_method(D_METHOD("set_attenuation", "curve"), &AudioStreamPlayer2D::set_attenuation); + ClassDB::bind_method(D_METHOD("get_attenuation"), &AudioStreamPlayer2D::get_attenuation); + + ClassDB::bind_method(D_METHOD("set_area_mask", "mask"), &AudioStreamPlayer2D::set_area_mask); + ClassDB::bind_method(D_METHOD("get_area_mask"), &AudioStreamPlayer2D::get_area_mask); + + ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer2D::_bus_layout_changed); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "_is_active"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "1,65536,1"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING), "set_attenuation", "get_attenuation"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask"); +} + +AudioStreamPlayer2D::AudioStreamPlayer2D() { + + volume_db = 0; + autoplay = false; + setseek = -1; + active = false; + output_count = 0; + prev_output_count = 0; + max_distance = 2000; + attenuation = 1; + setplay = -1; + output_ready = false; + area_mask = 1; + AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); +} + +AudioStreamPlayer2D::~AudioStreamPlayer2D() { +} diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h new file mode 100644 index 0000000000..25eff61b76 --- /dev/null +++ b/scene/2d/audio_stream_player_2d.h @@ -0,0 +1,96 @@ +#ifndef AUDIO_STREAM_PLAYER_2D_H +#define AUDIO_STREAM_PLAYER_2D_H + +#include "scene/2d/node_2d.h" +#include "servers/audio/audio_stream.h" +#include "servers/audio_server.h" + +class AudioStreamPlayer2D : public Node2D { + + GDCLASS(AudioStreamPlayer2D, Node2D) + +private: + enum { + MAX_OUTPUTS = 8, + MAX_INTERSECT_AREAS = 32 + + }; + + struct Output { + + AudioFrame vol; + int bus_index; + Viewport *viewport; //pointer only used for reference to previous mix + }; + + Output outputs[MAX_OUTPUTS]; + volatile int output_count; + volatile bool output_ready; + + //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks) + Output prev_outputs[MAX_OUTPUTS]; + int prev_output_count; + + Ref<AudioStreamPlayback> stream_playback; + Ref<AudioStream> stream; + Vector<AudioFrame> mix_buffer; + + volatile float setseek; + volatile bool active; + volatile float setplay; + + float volume_db; + bool autoplay; + StringName bus; + + void _mix_audio(); + static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->_mix_audio(); } + + void _set_playing(bool p_enable); + bool _is_active() const; + + void _bus_layout_changed(); + + uint32_t area_mask; + + float max_distance; + float attenuation; + +protected: + void _validate_property(PropertyInfo &property) const; + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_stream(Ref<AudioStream> p_stream); + Ref<AudioStream> get_stream() const; + + void set_volume_db(float p_volume); + float get_volume_db() const; + + void play(float p_from_pos = 0.0); + void seek(float p_seconds); + void stop(); + bool is_playing() const; + float get_pos(); + + void set_bus(const StringName &p_bus); + StringName get_bus() const; + + void set_autoplay(bool p_enable); + bool is_autoplay_enabled(); + + void set_max_distance(float p_pixels); + float get_max_distance() const; + + void set_attenuation(float p_curve); + float get_attenuation() const; + + void set_area_mask(uint32_t p_mask); + uint32_t get_area_mask() const; + + AudioStreamPlayer2D(); + ~AudioStreamPlayer2D(); +}; + +#endif diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 4f3a20d61f..471f529713 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -459,14 +459,14 @@ void CanvasItem::draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p ERR_FAIL_COND(p_texture.is_null()); p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose, p_normal_map); } -void CanvasItem::draw_texture_rect_region(const Ref<Texture> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) { +void CanvasItem::draw_texture_rect_region(const Ref<Texture> &p_texture, 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) { if (!drawing) { ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); ERR_FAIL(); } ERR_FAIL_COND(p_texture.is_null()); - p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_normal_map); + p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_normal_map, p_clip_uv); } void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) { @@ -758,7 +758,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_circle", "pos", "radius", "color"), &CanvasItem::draw_circle); ClassDB::bind_method(D_METHOD("draw_texture", "texture:Texture", "pos", "modulate", "normal_map:Texture"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture:Texture", "rect", "tile", "modulate", "transpose", "normal_map:Texture"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture:Texture", "rect", "src_rect", "modulate", "transpose", "normal_map:Texture"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture:Texture", "rect", "src_rect", "modulate", "transpose", "normal_map:Texture", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(true)); ClassDB::bind_method(D_METHOD("draw_style_box", "style_box:StyleBox", "rect"), &CanvasItem::draw_style_box); ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture:Texture", "width", "normal_map:Texture"), &CanvasItem::draw_primitive, DEFVAL(Variant()), DEFVAL(1.0), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture:Texture", "normal_map:Texture"), &CanvasItem::draw_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant())); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index b47dbd00fa..595dd03057 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -160,7 +160,7 @@ public: void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color); void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>()); void draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()); - void draw_texture_rect_region(const Ref<Texture> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()); + void draw_texture_rect_region(const Ref<Texture> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true); void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect); void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture> p_texture = Ref<Texture>(), float p_width = 1, const Ref<Texture> &p_normal_map = Ref<Texture>()); void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>()); diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index dedec2dd49..ff574a6bd6 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -65,11 +65,13 @@ void Sprite::_notification(int p_what) { Size2 s; Rect2 src_rect; + bool filter_clip = false; if (region) { s = region_rect.size; src_rect = region_rect; + filter_clip = region_filter_clip; } else { s = Size2(texture->get_size()); s = s / Size2(hframes, vframes); @@ -93,7 +95,7 @@ void Sprite::_notification(int p_what) { if (vflip) dst_rect.size.y = -dst_rect.size.y; - texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map); + texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, filter_clip); } break; } @@ -214,6 +216,15 @@ Rect2 Sprite::get_region_rect() const { return region_rect; } +void Sprite::set_region_filter_clip(bool p_enable) { + region_filter_clip = p_enable; + update(); +} + +bool Sprite::is_region_filter_clip_enabled() const { + return region_filter_clip; +} + void Sprite::set_frame(int p_frame) { ERR_FAIL_INDEX(p_frame, vframes * hframes); @@ -323,6 +334,9 @@ void Sprite::_bind_methods() { ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite::set_region_rect); ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite::get_region_rect); + ClassDB::bind_method(D_METHOD("set_region_filter_clip", "enabled"), &Sprite::set_region_filter_clip); + ClassDB::bind_method(D_METHOD("is_region_filter_clip_enabled"), &Sprite::is_region_filter_clip_enabled); + ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite::set_frame); ClassDB::bind_method(D_METHOD("get_frame"), &Sprite::get_frame); @@ -344,8 +358,11 @@ void Sprite::_bind_methods() { ADD_PROPERTYNO(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTYNO(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame"); - ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "region"), "set_region", "is_region"); + + ADD_GROUP("Region", "region_"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region"); ADD_PROPERTYNZ(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "region_filter_clip"), "set_region_filter_clip", "is_region_filter_clip_enabled"); } Sprite::Sprite() { @@ -354,6 +371,7 @@ Sprite::Sprite() { hflip = false; vflip = false; region = false; + region_filter_clip = false; frame = 0; diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h index 3b5d031e92..d3f9a5f032 100644 --- a/scene/2d/sprite.h +++ b/scene/2d/sprite.h @@ -47,6 +47,7 @@ class Sprite : public Node2D { bool vflip; bool region; Rect2 region_rect; + bool region_filter_clip; int frame; @@ -86,6 +87,9 @@ public: void set_region(bool p_region); bool is_region() const; + void set_region_filter_clip(bool p_enable); + bool is_region_filter_clip_enabled() const; + void set_region_rect(const Rect2 &p_region_rect); Rect2 get_region_rect() const; diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index d535c545a8..5c29918118 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -108,40 +108,58 @@ void PathFollow::_update_transform() { Vector3 pos = c->interpolate_baked(o, cubic); Transform t = get_transform(); - if (rotation_mode != ROTATION_NONE) { - - Vector3 n = (c->interpolate_baked(o + lookahead, cubic) - pos).normalized(); - - if (rotation_mode == ROTATION_Y) { + t.origin = pos; + Vector3 pos_offset = Vector3(h_offset, v_offset, 0); - n.y = 0; - n.normalize(); - } + if (rotation_mode != ROTATION_NONE) { + // perform parallel transport + // + // see C. Dougan, The Parallel Transport Frame, Game Programming Gems 2 for example + // for a discussion about why not Frenet frame. + + Vector3 t_prev = pos - c->interpolate_baked(o - lookahead, cubic); + Vector3 t_cur = c->interpolate_baked(o + lookahead, cubic) - pos; + + Vector3 axis = t_prev.cross(t_cur); + float dot = t_prev.normalized().dot(t_cur.normalized()); + float angle = Math::acos(CLAMP(dot, -1, 1)); + + if (axis.length() > CMP_EPSILON && angle > CMP_EPSILON) { + if (rotation_mode == ROTATION_Y) { + // assuming we're referring to global Y-axis. is this correct? + axis.x = 0; + axis.z = 0; + } else if (rotation_mode == ROTATION_XY) { + axis.z = 0; + } else if (rotation_mode == ROTATION_XYZ) { + // all components are OK + } - if (n.length() < CMP_EPSILON) { //nothing, use previous - n = -t.get_basis().get_axis(2).normalized(); + t.rotate_basis(axis.normalized(), angle); } - Vector3 up = Vector3(0, 1, 0); - - if (rotation_mode == ROTATION_XYZ) { - - float tilt = c->interpolate_baked_tilt(o); - if (tilt != 0) { - - Basis rot(-n, tilt); //remember.. lookat will be znegative.. znegative!! we abide by opengl clan. - up = rot.xform(up); + // do the additional tilting + float tilt_angle = c->interpolate_baked_tilt(o); + Vector3 tilt_axis = t_cur; // is this correct?? + + if (tilt_axis.length() > CMP_EPSILON && tilt_angle > CMP_EPSILON) { + if (rotation_mode == ROTATION_Y) { + tilt_axis.x = 0; + tilt_axis.z = 0; + } else if (rotation_mode == ROTATION_XY) { + tilt_axis.z = 0; + } else if (rotation_mode == ROTATION_XYZ) { + // all components are OK } - } - t.set_look_at(pos, pos + n, up); + t.rotate_basis(tilt_axis.normalized(), tilt_angle); + } + t.translate(pos_offset); } else { - - t.origin = pos; + t.origin += pos_offset; } - t.origin += t.basis.get_axis(0) * h_offset + t.basis.get_axis(1) * v_offset; set_transform(t); } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index a95bb4a67f..b6c59ba277 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -273,10 +273,12 @@ void SpriteBase3D::_bind_methods() { ADD_GROUP("Flags", ""); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_draw_flag", "get_draw_flag", FLAG_TRANSPARENT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "shaded"), "set_draw_flag", "get_draw_flag", FLAG_SHADED); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "double_sided"), "set_draw_flag", "get_draw_flag", FLAG_DOUBLE_SIDED); ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass"), "set_alpha_cut_mode", "get_alpha_cut_mode"); BIND_CONSTANT(FLAG_TRANSPARENT); BIND_CONSTANT(FLAG_SHADED); + BIND_CONSTANT(FLAG_DOUBLE_SIDED); BIND_CONSTANT(FLAG_MAX); BIND_CONSTANT(ALPHA_CUT_DISABLED); @@ -294,7 +296,7 @@ SpriteBase3D::SpriteBase3D() { pI = NULL; for (int i = 0; i < FLAG_MAX; i++) - flags[i] = i == FLAG_TRANSPARENT; + flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED; axis = Vector3::AXIS_Z; pixel_size = 0.01; @@ -387,7 +389,7 @@ void Sprite3D::_draw() { int axis = get_axis(); normal[axis] = 1.0; - RID mat = VS::get_singleton()->material_2d_get(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS); + RID mat = VS::get_singleton()->material_2d_get(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS); VS::get_singleton()->immediate_set_material(immediate, mat); VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid()); @@ -888,7 +890,7 @@ void AnimatedSprite3D::_draw() { int axis = get_axis(); normal[axis] = 1.0; - RID mat = VS::get_singleton()->material_2d_get(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS); + RID mat = VS::get_singleton()->material_2d_get(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS); VS::get_singleton()->immediate_set_material(immediate, mat); VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLE_FAN, texture->get_rid()); diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 625b37c32e..b4600c00b8 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -41,6 +41,7 @@ public: enum DrawFlags { FLAG_TRANSPARENT, FLAG_SHADED, + FLAG_DOUBLE_SIDED, FLAG_MAX }; diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp index ad72a512d8..bcca834642 100644 --- a/scene/audio/audio_player.cpp +++ b/scene/audio/audio_player.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "audio_player.h" -void AudioPlayer::_mix_audio() { +void AudioStreamPlayer::_mix_audio() { if (!stream_playback.is_valid()) { return; @@ -95,7 +95,7 @@ void AudioPlayer::_mix_audio() { } } -void AudioPlayer::_notification(int p_what) { +void AudioStreamPlayer::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { @@ -111,7 +111,7 @@ void AudioPlayer::_notification(int p_what) { } } -void AudioPlayer::set_stream(Ref<AudioStream> p_stream) { +void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) { ERR_FAIL_COND(!p_stream.is_valid()); AudioServer::get_singleton()->lock(); @@ -136,21 +136,21 @@ void AudioPlayer::set_stream(Ref<AudioStream> p_stream) { AudioServer::get_singleton()->unlock(); } -Ref<AudioStream> AudioPlayer::get_stream() const { +Ref<AudioStream> AudioStreamPlayer::get_stream() const { return stream; } -void AudioPlayer::set_volume_db(float p_volume) { +void AudioStreamPlayer::set_volume_db(float p_volume) { volume_db = p_volume; } -float AudioPlayer::get_volume_db() const { +float AudioStreamPlayer::get_volume_db() const { return volume_db; } -void AudioPlayer::play(float p_from_pos) { +void AudioStreamPlayer::play(float p_from_pos) { if (stream_playback.is_valid()) { mix_volume_db = volume_db; //reset volume ramp @@ -159,21 +159,21 @@ void AudioPlayer::play(float p_from_pos) { } } -void AudioPlayer::seek(float p_seconds) { +void AudioStreamPlayer::seek(float p_seconds) { if (stream_playback.is_valid()) { setseek = p_seconds; } } -void AudioPlayer::stop() { +void AudioStreamPlayer::stop() { if (stream_playback.is_valid()) { active = false; } } -bool AudioPlayer::is_playing() const { +bool AudioStreamPlayer::is_playing() const { if (stream_playback.is_valid()) { return active && stream_playback->is_playing(); @@ -182,7 +182,7 @@ bool AudioPlayer::is_playing() const { return false; } -float AudioPlayer::get_pos() { +float AudioStreamPlayer::get_pos() { if (stream_playback.is_valid()) { return stream_playback->get_pos(); @@ -191,14 +191,14 @@ float AudioPlayer::get_pos() { return 0; } -void AudioPlayer::set_bus(const StringName &p_bus) { +void AudioStreamPlayer::set_bus(const StringName &p_bus) { //if audio is active, must lock this AudioServer::get_singleton()->lock(); bus = p_bus; AudioServer::get_singleton()->unlock(); } -StringName AudioPlayer::get_bus() const { +StringName AudioStreamPlayer::get_bus() const { for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { if (AudioServer::get_singleton()->get_bus_name(i) == bus) { @@ -208,38 +208,38 @@ StringName AudioPlayer::get_bus() const { return "Master"; } -void AudioPlayer::set_autoplay(bool p_enable) { +void AudioStreamPlayer::set_autoplay(bool p_enable) { autoplay = p_enable; } -bool AudioPlayer::is_autoplay_enabled() { +bool AudioStreamPlayer::is_autoplay_enabled() { return autoplay; } -void AudioPlayer::set_mix_target(MixTarget p_target) { +void AudioStreamPlayer::set_mix_target(MixTarget p_target) { mix_target = p_target; } -AudioPlayer::MixTarget AudioPlayer::get_mix_target() const { +AudioStreamPlayer::MixTarget AudioStreamPlayer::get_mix_target() const { return mix_target; } -void AudioPlayer::_set_playing(bool p_enable) { +void AudioStreamPlayer::_set_playing(bool p_enable) { if (p_enable) play(); else stop(); } -bool AudioPlayer::_is_active() const { +bool AudioStreamPlayer::_is_active() const { return active; } -void AudioPlayer::_validate_property(PropertyInfo &property) const { +void AudioStreamPlayer::_validate_property(PropertyInfo &property) const { if (property.name == "bus") { @@ -255,39 +255,39 @@ void AudioPlayer::_validate_property(PropertyInfo &property) const { } } -void AudioPlayer::_bus_layout_changed() { +void AudioStreamPlayer::_bus_layout_changed() { _change_notify(); } -void AudioPlayer::_bind_methods() { +void AudioStreamPlayer::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_stream", "stream:AudioStream"), &AudioPlayer::set_stream); - ClassDB::bind_method(D_METHOD("get_stream"), &AudioPlayer::get_stream); + ClassDB::bind_method(D_METHOD("set_stream", "stream:AudioStream"), &AudioStreamPlayer::set_stream); + ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer::get_stream); - ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioPlayer::set_volume_db); - ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioPlayer::get_volume_db); + ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer::set_volume_db); + ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer::get_volume_db); - ClassDB::bind_method(D_METHOD("play", "from_pos"), &AudioPlayer::play, DEFVAL(0.0)); - ClassDB::bind_method(D_METHOD("seek", "to_pos"), &AudioPlayer::seek); - ClassDB::bind_method(D_METHOD("stop"), &AudioPlayer::stop); + ClassDB::bind_method(D_METHOD("play", "from_pos"), &AudioStreamPlayer::play, DEFVAL(0.0)); + ClassDB::bind_method(D_METHOD("seek", "to_pos"), &AudioStreamPlayer::seek); + ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer::stop); - ClassDB::bind_method(D_METHOD("is_playing"), &AudioPlayer::is_playing); - ClassDB::bind_method(D_METHOD("get_pos"), &AudioPlayer::get_pos); + ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayer::is_playing); + ClassDB::bind_method(D_METHOD("get_pos"), &AudioStreamPlayer::get_pos); - ClassDB::bind_method(D_METHOD("set_bus", "bus"), &AudioPlayer::set_bus); - ClassDB::bind_method(D_METHOD("get_bus"), &AudioPlayer::get_bus); + ClassDB::bind_method(D_METHOD("set_bus", "bus"), &AudioStreamPlayer::set_bus); + ClassDB::bind_method(D_METHOD("get_bus"), &AudioStreamPlayer::get_bus); - ClassDB::bind_method(D_METHOD("set_autoplay", "enable"), &AudioPlayer::set_autoplay); - ClassDB::bind_method(D_METHOD("is_autoplay_enabled"), &AudioPlayer::is_autoplay_enabled); + ClassDB::bind_method(D_METHOD("set_autoplay", "enable"), &AudioStreamPlayer::set_autoplay); + ClassDB::bind_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer::is_autoplay_enabled); - ClassDB::bind_method(D_METHOD("set_mix_target", "mix_target"), &AudioPlayer::set_mix_target); - ClassDB::bind_method(D_METHOD("get_mix_target"), &AudioPlayer::get_mix_target); + ClassDB::bind_method(D_METHOD("set_mix_target", "mix_target"), &AudioStreamPlayer::set_mix_target); + ClassDB::bind_method(D_METHOD("get_mix_target"), &AudioStreamPlayer::get_mix_target); - ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioPlayer::_set_playing); - ClassDB::bind_method(D_METHOD("_is_active"), &AudioPlayer::_is_active); + ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer::_set_playing); + ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer::_is_active); - ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioPlayer::_bus_layout_changed); + ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer::_bus_layout_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db"); @@ -297,7 +297,7 @@ void AudioPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); } -AudioPlayer::AudioPlayer() { +AudioStreamPlayer::AudioStreamPlayer() { mix_volume_db = 0; volume_db = 0; @@ -309,5 +309,5 @@ AudioPlayer::AudioPlayer() { AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); } -AudioPlayer::~AudioPlayer() { +AudioStreamPlayer::~AudioStreamPlayer() { } diff --git a/scene/audio/audio_player.h b/scene/audio/audio_player.h index 5a8a8494e1..8bd6844dec 100644 --- a/scene/audio/audio_player.h +++ b/scene/audio/audio_player.h @@ -33,9 +33,9 @@ #include "scene/main/node.h" #include "servers/audio/audio_stream.h" -class AudioPlayer : public Node { +class AudioStreamPlayer : public Node { - GDCLASS(AudioPlayer, Node) + GDCLASS(AudioStreamPlayer, Node) public: enum MixTarget { @@ -60,7 +60,7 @@ private: MixTarget mix_target; void _mix_audio(); - static void _mix_audios(void *self) { reinterpret_cast<AudioPlayer *>(self)->_mix_audio(); } + static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer *>(self)->_mix_audio(); } void _set_playing(bool p_enable); bool _is_active() const; @@ -94,9 +94,9 @@ public: void set_mix_target(MixTarget p_target); MixTarget get_mix_target() const; - AudioPlayer(); - ~AudioPlayer(); + AudioStreamPlayer(); + ~AudioStreamPlayer(); }; -VARIANT_ENUM_CAST(AudioPlayer::MixTarget) +VARIANT_ENUM_CAST(AudioStreamPlayer::MixTarget) #endif // AUDIOPLAYER_H diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index bc1b16bea8..ee6af21dbd 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -48,7 +48,15 @@ void ColorPicker::_notification(int p_what) { btn_pick->set_icon(get_icon("screen_picker", "ColorPicker")); _update_color(); - } + } break; + + case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { + if (screen != NULL) { + if (screen->is_visible()) { + screen->hide(); + } + } + } break; } } @@ -84,9 +92,6 @@ void ColorPicker::set_pick_color(const Color &p_color) { if (!is_inside_tree()) return; - return; //it crashes, so returning - uv_edit->get_child(0)->cast_to<Control>()->update(); - w_edit->get_child(0)->cast_to<Control>()->update(); _update_color(); } @@ -427,19 +432,12 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &ev) { Viewport *r = get_tree()->get_root(); if (!r->get_visible_rect().has_point(Point2(mev->get_global_position().x, mev->get_global_position().y))) return; - Ref<Image> img; //= r->get_screen_capture(); - if (!img.is_null()) { - last_capture = img; - //r->queue_screen_capture(); - } - if (last_capture.is_valid() && !last_capture->empty()) { - int pw = last_capture->get_format() == Image::FORMAT_RGBA8 ? 4 : 3; - int ofs = (mev->get_global_position().y * last_capture->get_width() + mev->get_global_position().x) * pw; - - PoolVector<uint8_t>::Read r = last_capture->get_data().read(); - - Color c(r[ofs + 0] / 255.0, r[ofs + 1] / 255.0, r[ofs + 2] / 255.0); - + Ref<Image> img = r->get_texture()->get_data(); + if (img.is_valid() && !img->empty()) { + img->lock(); + Vector2 ofs = mev->get_global_position() - r->get_visible_rect().get_position(); + Color c = img->get_pixel(ofs.x, r->get_visible_rect().size.height - ofs.y); + img->unlock(); set_pick_color(c); } } @@ -456,11 +454,11 @@ void ColorPicker::_screen_pick_pressed() { r->add_child(screen); screen->set_as_toplevel(true); screen->set_area_as_parent_rect(); + screen->set_default_cursor_shape(CURSOR_POINTING_HAND); screen->connect("gui_input", this, "_screen_input"); } screen->raise(); screen->show_modal(); - // r->queue_screen_capture(); } void ColorPicker::_bind_methods() { @@ -632,6 +630,10 @@ void ColorPickerButton::_notification(int p_what) { Ref<StyleBox> normal = get_stylebox("normal"); draw_rect(Rect2(normal->get_offset(), get_size() - normal->get_minimum_size()), picker->get_pick_color()); } + + if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) { + popup->hide(); + } } void ColorPickerButton::set_pick_color(const Color &p_color) { diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index ca47c3a5f4..de624fd029 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -47,7 +47,6 @@ class ColorPicker : public BoxContainer { private: Control *screen; - Ref<Image> last_capture; Control *uv_edit; Control *w_edit; TextureRect *sample; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index c4991700aa..74b26da580 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -884,7 +884,7 @@ void PopupMenu::activate_item(int p_item) { while (pop) { // We close all parents that are chained together, // with hide_on_item_selection enabled - if (hide_on_item_selection && pop->is_hide_on_item_selection()) { + if ((items[p_item].checkable && hide_on_checkable_item_selection && pop->is_hide_on_checkable_item_selection()) || (!items[p_item].checkable && hide_on_item_selection && pop->is_hide_on_item_selection())) { pop->hide(); next = next->get_parent(); pop = next->cast_to<PopupMenu>(); @@ -895,8 +895,8 @@ void PopupMenu::activate_item(int p_item) { } } // Hides popup by default; unless otherwise specified - // by using set_hide_on_item_selection - if (hide_on_item_selection) { + // by using set_hide_on_item_selection and set_hide_on_checkable_item_selection + if ((items[p_item].checkable && hide_on_checkable_item_selection) || (!items[p_item].checkable && hide_on_item_selection)) { hide(); } } @@ -1019,6 +1019,16 @@ bool PopupMenu::is_hide_on_item_selection() { return hide_on_item_selection; } +void PopupMenu::set_hide_on_checkable_item_selection(bool p_enabled) { + + hide_on_checkable_item_selection = p_enabled; +} + +bool PopupMenu::is_hide_on_checkable_item_selection() { + + return hide_on_checkable_item_selection; +} + String PopupMenu::get_tooltip(const Point2 &p_pos) const { int over = _get_mouse_over(p_pos); @@ -1107,10 +1117,14 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hide_on_item_selection", "enable"), &PopupMenu::set_hide_on_item_selection); ClassDB::bind_method(D_METHOD("is_hide_on_item_selection"), &PopupMenu::is_hide_on_item_selection); + ClassDB::bind_method(D_METHOD("set_hide_on_checkable_item_selection", "enable"), &PopupMenu::set_hide_on_checkable_item_selection); + ClassDB::bind_method(D_METHOD("is_hide_on_checkable_item_selection"), &PopupMenu::is_hide_on_checkable_item_selection); + ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_item_selection"), "set_hide_on_item_selection", "is_hide_on_item_selection"); + ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection"); ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "ID"))); ADD_SIGNAL(MethodInfo("index_pressed", PropertyInfo(Variant::INT, "index"))); @@ -1128,6 +1142,7 @@ PopupMenu::PopupMenu() { set_focus_mode(FOCUS_ALL); set_as_toplevel(true); set_hide_on_item_selection(true); + set_hide_on_checkable_item_selection(true); submenu_timer = memnew(Timer); submenu_timer->set_wait_time(0.3); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 7ef532453d..a9bd8f7e50 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -85,6 +85,7 @@ class PopupMenu : public Popup { bool invalidated_click; bool hide_on_item_selection; + bool hide_on_checkable_item_selection; Vector2 moved; Array _get_items() const; @@ -168,6 +169,9 @@ public: void set_hide_on_item_selection(bool p_enabled); bool is_hide_on_item_selection(); + void set_hide_on_checkable_item_selection(bool p_enabled); + bool is_hide_on_checkable_item_selection(); + PopupMenu(); ~PopupMenu(); }; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index df3729c50b..b2737353fb 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -111,6 +111,7 @@ #include "scene/2d/ray_cast_2d.h" //#include "scene/2d/sound_player_2d.h" //#include "scene/2d/sample_player_2d.h" +#include "scene/2d/audio_stream_player_2d.h" #include "scene/2d/canvas_modulate.h" #include "scene/2d/navigation2d.h" #include "scene/2d/remote_transform_2d.h" @@ -591,7 +592,8 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init - ClassDB::register_class<AudioPlayer>(); + ClassDB::register_class<AudioStreamPlayer>(); + ClassDB::register_class<AudioStreamPlayer2D>(); ClassDB::register_virtual_class<VideoStream>(); ClassDB::register_class<AudioStreamSample>(); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 1682971f9c..2120b37497 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -46,10 +46,10 @@ void Texture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, con RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose, normal_rid); } -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) const { +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 { RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - 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); + 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); } bool Texture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { @@ -70,7 +70,7 @@ void Texture::_bind_methods() { ClassDB::bind_method(D_METHOD("get_flags"), &Texture::get_flags); ClassDB::bind_method(D_METHOD("draw", "canvas_item", "pos", "modulate", "transpose", "normal_map:Texture"), &Texture::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose", "normal_map:Texture"), &Texture::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map:Texture"), &Texture::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map:Texture", "clip_uv"), &Texture::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(true)); BIND_CONSTANT(FLAG_MIPMAPS); BIND_CONSTANT(FLAG_REPEAT); @@ -282,12 +282,12 @@ void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid); } -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) const { +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 { if ((w | h) == 0) return; RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid); + 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); } void ImageTexture::set_size_override(const Size2 &p_size) { @@ -685,12 +685,12 @@ void StreamTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_til RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid); } -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) const { +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 { if ((w | h) == 0) return; RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid); + 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); } bool StreamTexture::has_alpha() const { @@ -912,7 +912,7 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid); } -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) const { +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 { //this might not necessarily work well if using a rect, needs to be fixed properly Rect2 rc = region; @@ -941,7 +941,7 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons Rect2 dr(p_rect.position + ofs * scale, src_c.size * scale); RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); - VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid); + VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, p_clip_uv); } bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { @@ -1130,7 +1130,7 @@ void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile 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); } } -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) const { +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 { //tiling not supported for this if (p_src_rect.size.x == 0 || p_src_rect.size.y == 0) @@ -1150,7 +1150,7 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons target.size *= scale; target.position = p_rect.position + (p_src_rect.position + rect.position) * scale; local.position -= rect.position; - pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose, p_normal_map); + pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose, p_normal_map, false); } } diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 78693b07ac..2b82dbd21f 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -70,7 +70,7 @@ public: virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const; virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const; virtual Ref<Image> get_data() const { return Ref<Image>(); } @@ -133,7 +133,7 @@ public: bool has_alpha() const; virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const; void set_storage(Storage p_storage); Storage get_storage() const; @@ -205,7 +205,7 @@ public: virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const; virtual bool has_alpha() const; virtual void set_flags(uint32_t p_flags); @@ -259,7 +259,7 @@ public: virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const; virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const; AtlasTexture(); @@ -307,7 +307,7 @@ public: virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; - virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const; + virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const; LargeTexture(); }; diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index ec9ec96e50..36d2a38b3d 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -360,16 +360,17 @@ RID World2D::get_space() { return space; } -RID World2D::get_sound_space() { +void World2D::get_viewport_list(List<Viewport *> *r_viewports) { - return sound_space; + for (Map<Viewport *, SpatialIndexer2D::ViewportData>::Element *E = indexer->viewports.front(); E; E = E->next()) { + r_viewports->push_back(E->key()); + } } void World2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_canvas"), &World2D::get_canvas); ClassDB::bind_method(D_METHOD("get_space"), &World2D::get_space); - ClassDB::bind_method(D_METHOD("get_sound_space"), &World2D::get_sound_space); ClassDB::bind_method(D_METHOD("get_direct_space_state:Physics2DDirectSpaceState"), &World2D::get_direct_space_state); } diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index 2b6e7e7383..35c8ce390f 100644 --- a/scene/resources/world_2d.h +++ b/scene/resources/world_2d.h @@ -44,7 +44,6 @@ class World2D : public Resource { RID canvas; RID space; - RID sound_space; SpatialIndexer2D *indexer; @@ -66,10 +65,11 @@ protected: public: RID get_canvas(); RID get_space(); - RID get_sound_space(); Physics2DDirectSpaceState *get_direct_space_state(); + void get_viewport_list(List<Viewport *> *r_viewports); + World2D(); ~World2D(); }; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index a56cdcdc50..07d6542b62 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -525,7 +525,8 @@ public: CANVAS_RECT_TILE = 2, CANVAS_RECT_FLIP_H = 4, CANVAS_RECT_FLIP_V = 8, - CANVAS_RECT_TRANSPOSE = 16 + CANVAS_RECT_TRANSPOSE = 16, + CANVAS_RECT_CLIP_UV = 32 }; struct Light : public RID_Data { diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 0ae86cd389..2ef1fd417b 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -461,7 +461,7 @@ void VisualServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p canvas_item->commands.push_back(rect); } -void VisualServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, RID p_normal_map) { +void VisualServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, RID p_normal_map, bool p_clip_uv) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -490,6 +490,10 @@ void VisualServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const R SWAP(rect->rect.size.x, rect->rect.size.y); } + if (p_clip_uv) { + rect->flags |= RasterizerCanvas::CANVAS_RECT_CLIP_UV; + } + canvas_item->rect_dirty = true; canvas_item->commands.push_back(rect); diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 0808bf72ad..2c86b14c70 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -166,7 +166,7 @@ public: void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()); - void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()); + void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), bool p_clip_uv = true); void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, VS::NinePatchAxisMode p_x_axis_mode = VS::NINE_PATCH_STRETCH, VS::NinePatchAxisMode p_y_axis_mode = VS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID()); void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID()); void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID()); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 504d836913..c48bee7fa4 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -1042,7 +1042,7 @@ public: BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &) BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) BIND7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID) - BIND7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID) + BIND8(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, bool) BIND11(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID) BIND7(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID) BIND6(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID) diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index e60a478bd9..94cbfc815e 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -469,7 +469,7 @@ public: FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &) FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) FUNC7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID) - FUNC7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID) + FUNC8(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, bool) FUNC11(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID) FUNC7(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID) FUNC6(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 6c57275b3a..c3ae58cf4f 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -137,7 +137,7 @@ void VisualServer::_free_internal_rids() { if (test_material.is_valid()) free(test_material); - for (int i = 0; i < 16; i++) { + for (int i = 0; i < 32; i++) { if (material_2d[i].is_valid()) free(material_2d[i]); } @@ -284,7 +284,7 @@ RID VisualServer::make_sphere_mesh(int p_lats, int p_lons, float p_radius) { return mesh; } -RID VisualServer::material_2d_get(bool p_shaded, bool p_transparent, bool p_cut_alpha, bool p_opaque_prepass) { +RID VisualServer::material_2d_get(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass) { int version = 0; if (p_shaded) @@ -295,6 +295,8 @@ RID VisualServer::material_2d_get(bool p_shaded, bool p_transparent, bool p_cut_ version |= 4; if (p_opaque_prepass) version |= 8; + if (p_double_sided) + version |= 16; if (material_2d[version].is_valid()) return material_2d[version]; @@ -305,7 +307,7 @@ RID VisualServer::material_2d_get(bool p_shaded, bool p_transparent, bool p_cut_ fixed_material_set_flag(material_2d[version],FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true); fixed_material_set_flag(material_2d[version],FIXED_MATERIAL_FLAG_DISCARD_ALPHA,p_cut_alpha); material_set_flag(material_2d[version],MATERIAL_FLAG_UNSHADED,!p_shaded); - material_set_flag(material_2d[version],MATERIAL_FLAG_DOUBLE_SIDED,true); + material_set_flag(material_2d[version], MATERIAL_FLAG_DOUBLE_SIDED, p_double_sided); material_set_depth_draw_mode(material_2d[version],p_opaque_prepass?MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA:MATERIAL_DEPTH_DRAW_OPAQUE_ONLY); fixed_material_set_texture(material_2d[version],FIXED_MATERIAL_PARAM_DIFFUSE,get_white_texture()); //material cut alpha?*/ diff --git a/servers/visual_server.h b/servers/visual_server.h index 22f91f6a73..589fa80084 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -60,7 +60,7 @@ protected: RID test_texture; RID white_texture; RID test_material; - RID material_2d[16]; + RID material_2d[32]; Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, PoolVector<uint8_t> &r_vertex_array, int p_vertex_array_len, PoolVector<uint8_t> &r_index_array, int p_index_array_len, Rect3 &r_aabb, Vector<Rect3> r_bone_aabb); @@ -786,7 +786,7 @@ public: virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0; virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()) = 0; - virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()) = 0; + virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), bool p_clip_uv = true) = 0; virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID()) = 0; virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID()) = 0; virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID()) = 0; @@ -909,7 +909,7 @@ public: /* Materials for 2D on 3D */ - RID material_2d_get(bool p_shaded, bool p_transparent, bool p_cut_alpha, bool p_opaque_prepass); + RID material_2d_get(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass); /* TESTING */ |