summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/astcenc/SCsub55
-rw-r--r--modules/astcenc/config.py6
-rw-r--r--modules/astcenc/image_compress_astcenc.cpp251
-rw-r--r--modules/astcenc/image_compress_astcenc.h39
-rw-r--r--modules/astcenc/register_types.cpp48
-rw-r--r--modules/astcenc/register_types.h39
-rw-r--r--modules/etcpak/image_compress_etcpak.cpp12
-rw-r--r--modules/gltf/gltf_document.cpp3
-rw-r--r--modules/ogg/ogg_packet_sequence.cpp2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp44
-rw-r--r--modules/text_server_adv/text_server_adv.h2
-rw-r--r--modules/text_server_fb/text_server_fb.cpp27
12 files changed, 489 insertions, 39 deletions
diff --git a/modules/astcenc/SCsub b/modules/astcenc/SCsub
new file mode 100644
index 0000000000..0f04f2bc28
--- /dev/null
+++ b/modules/astcenc/SCsub
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_astcenc = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+thirdparty_dir = "#thirdparty/astcenc/"
+thirdparty_sources = [
+ "astcenc_averages_and_directions.cpp",
+ "astcenc_block_sizes.cpp",
+ "astcenc_color_quantize.cpp",
+ "astcenc_color_unquantize.cpp",
+ "astcenc_compress_symbolic.cpp",
+ "astcenc_compute_variance.cpp",
+ "astcenc_decompress_symbolic.cpp",
+ "astcenc_diagnostic_trace.cpp",
+ "astcenc_entry.cpp",
+ "astcenc_find_best_partitioning.cpp",
+ "astcenc_ideal_endpoints_and_weights.cpp",
+ "astcenc_image.cpp",
+ "astcenc_integer_sequence.cpp",
+ "astcenc_mathlib.cpp",
+ "astcenc_mathlib_softfloat.cpp",
+ "astcenc_partition_tables.cpp",
+ "astcenc_percentile_tables.cpp",
+ "astcenc_pick_best_endpoint_format.cpp",
+ "astcenc_platform_isa_detection.cpp",
+ "astcenc_quantization.cpp",
+ "astcenc_symbolic_physical.cpp",
+ "astcenc_weight_align.cpp",
+ "astcenc_weight_quant_xfer_tables.cpp",
+]
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_astcenc.Prepend(CPPPATH=[thirdparty_dir])
+
+env_thirdparty = env_astcenc.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_astcenc.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/astcenc/config.py b/modules/astcenc/config.py
new file mode 100644
index 0000000000..eb565b85b9
--- /dev/null
+++ b/modules/astcenc/config.py
@@ -0,0 +1,6 @@
+def can_build(env, platform):
+ return env.editor_build
+
+
+def configure(env):
+ pass
diff --git a/modules/astcenc/image_compress_astcenc.cpp b/modules/astcenc/image_compress_astcenc.cpp
new file mode 100644
index 0000000000..ce10201343
--- /dev/null
+++ b/modules/astcenc/image_compress_astcenc.cpp
@@ -0,0 +1,251 @@
+/**************************************************************************/
+/* image_compress_astcenc.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "image_compress_astcenc.h"
+
+#include "core/os/os.h"
+#include "core/string/print_string.h"
+
+#include <astcenc.h>
+
+void _compress_astc(Image *r_img, float p_lossy_quality, Image::ASTCFormat p_format) {
+ uint64_t start_time = OS::get_singleton()->get_ticks_msec();
+
+ // TODO: See how to handle lossy quality.
+
+ Image::Format img_format = r_img->get_format();
+ if (img_format >= Image::FORMAT_DXT1) {
+ return; // Do not compress, already compressed.
+ }
+
+ bool is_hdr = false;
+ if ((img_format >= Image::FORMAT_RH) && (img_format <= Image::FORMAT_RGBE9995)) {
+ is_hdr = true;
+ r_img->convert(Image::FORMAT_RGBAF);
+ } else {
+ r_img->convert(Image::FORMAT_RGBA8);
+ }
+
+ // Determine encoder output format from our enum.
+
+ Image::Format target_format = Image::FORMAT_RGBA8;
+ astcenc_profile profile = ASTCENC_PRF_LDR;
+ unsigned int block_x = 4;
+ unsigned int block_y = 4;
+
+ if (p_format == Image::ASTCFormat::ASTC_FORMAT_4x4) {
+ if (is_hdr) {
+ target_format = Image::FORMAT_ASTC_4x4_HDR;
+ profile = ASTCENC_PRF_HDR;
+ } else {
+ target_format = Image::FORMAT_ASTC_4x4;
+ }
+ } else if (p_format == Image::ASTCFormat::ASTC_FORMAT_8x8) {
+ if (is_hdr) {
+ target_format = Image::FORMAT_ASTC_8x8_HDR;
+ profile = ASTCENC_PRF_HDR;
+ } else {
+ target_format = Image::FORMAT_ASTC_8x8;
+ }
+ block_x = 8;
+ block_y = 8;
+ }
+
+ // Compress image data and (if required) mipmaps.
+
+ const bool mipmaps = r_img->has_mipmaps();
+ int width = r_img->get_width();
+ int height = r_img->get_height();
+
+ print_verbose(vformat("astcenc: Encoding image size %dx%d to format %s%s.", width, height, Image::get_format_name(target_format), mipmaps ? ", with mipmaps" : ""));
+
+ // Initialize astcenc.
+
+ astcenc_config config;
+ config.block_x = block_x;
+ config.block_y = block_y;
+ config.profile = profile;
+ const float quality = ASTCENC_PRE_MEDIUM;
+
+ astcenc_error status = astcenc_config_init(profile, block_x, block_y, block_x, quality, 0, &config);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: Configuration initialization failed: %s.", astcenc_get_error_string(status)));
+
+ // Context allocation.
+
+ astcenc_context *context;
+ const unsigned int thread_count = OS::get_singleton()->get_processor_count();
+
+ status = astcenc_context_alloc(&config, thread_count, &context);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: Context allocation failed: %s.", astcenc_get_error_string(status)));
+
+ // Compress image.
+
+ Vector<uint8_t> image_data = r_img->get_data();
+ uint8_t *slices = image_data.ptrw();
+
+ astcenc_image image;
+ image.dim_x = width;
+ image.dim_y = height;
+ image.dim_z = 1;
+ image.data_type = ASTCENC_TYPE_U8;
+ if (is_hdr) {
+ image.data_type = ASTCENC_TYPE_F32;
+ }
+ image.data = reinterpret_cast<void **>(&slices);
+
+ // Compute the number of ASTC blocks in each dimension.
+ unsigned int block_count_x = (width + block_x - 1) / block_x;
+ unsigned int block_count_y = (height + block_y - 1) / block_y;
+ size_t comp_len = block_count_x * block_count_y * 16;
+
+ Vector<uint8_t> compressed_data;
+ compressed_data.resize(comp_len);
+ compressed_data.fill(0);
+
+ const astcenc_swizzle swizzle = {
+ ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A
+ };
+
+ status = astcenc_compress_image(context, &image, &swizzle, compressed_data.ptrw(), comp_len, 0);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: ASTC image compression failed: %s.", astcenc_get_error_string(status)));
+
+ // Replace original image with compressed one.
+
+ r_img->set_data(width, height, mipmaps, target_format, compressed_data);
+
+ print_verbose(vformat("astcenc: Encoding took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
+}
+
+void _decompress_astc(Image *r_img) {
+ uint64_t start_time = OS::get_singleton()->get_ticks_msec();
+
+ // Determine decompression parameters from image format.
+
+ Image::Format img_format = r_img->get_format();
+ bool is_hdr = false;
+ unsigned int block_x = 0;
+ unsigned int block_y = 0;
+ if (img_format == Image::FORMAT_ASTC_4x4) {
+ block_x = 4;
+ block_y = 4;
+ is_hdr = false;
+ } else if (img_format == Image::FORMAT_ASTC_4x4_HDR) {
+ block_x = 4;
+ block_y = 4;
+ is_hdr = true;
+ } else if (img_format == Image::FORMAT_ASTC_8x8) {
+ block_x = 8;
+ block_y = 8;
+ is_hdr = false;
+ } else if (img_format == Image::FORMAT_ASTC_8x8_HDR) {
+ block_x = 8;
+ block_y = 8;
+ is_hdr = true;
+ } else {
+ ERR_FAIL_MSG("astcenc: Cannot decompress Image with a non-ASTC format.");
+ }
+
+ // Initialize astcenc.
+
+ astcenc_profile profile = ASTCENC_PRF_LDR;
+ if (is_hdr) {
+ profile = ASTCENC_PRF_HDR;
+ }
+ astcenc_config config;
+ const float quality = ASTCENC_PRE_MEDIUM;
+
+ astcenc_error status = astcenc_config_init(profile, block_x, block_y, block_x, quality, 0, &config);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: Configuration initialization failed: %s.", astcenc_get_error_string(status)));
+
+ // Context allocation.
+
+ astcenc_context *context = nullptr;
+ const unsigned int thread_count = OS::get_singleton()->get_processor_count();
+
+ status = astcenc_context_alloc(&config, thread_count, &context);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: Context allocation failed: %s.", astcenc_get_error_string(status)));
+
+ // Decompress image.
+
+ const bool mipmaps = r_img->has_mipmaps();
+ int width = r_img->get_width();
+ int height = r_img->get_height();
+
+ astcenc_image image;
+ image.dim_x = width;
+ image.dim_y = height;
+ image.dim_z = 1;
+ image.data_type = ASTCENC_TYPE_U8;
+ Image::Format target_format = Image::FORMAT_RGBA8;
+ if (is_hdr) {
+ target_format = Image::FORMAT_RGBAF;
+ image.data_type = ASTCENC_TYPE_F32;
+ }
+
+ Vector<uint8_t> image_data = r_img->get_data();
+
+ Vector<uint8_t> new_image_data;
+ new_image_data.resize(Image::get_image_data_size(width, height, target_format, false));
+ new_image_data.fill(0);
+ uint8_t *slices = new_image_data.ptrw();
+ image.data = reinterpret_cast<void **>(&slices);
+
+ const astcenc_swizzle swizzle = {
+ ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A
+ };
+
+ status = astcenc_decompress_image(context, image_data.ptr(), image_data.size(), &image, &swizzle, 0);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: ASTC decompression failed: %s.", astcenc_get_error_string(status)));
+ ERR_FAIL_COND_MSG(image.dim_z > 1,
+ "astcenc: ASTC decompression failed because this is a 3D texture, which is not supported.");
+
+ // Replace original image with compressed one.
+
+ Image::Format image_format = Image::FORMAT_RGBA8;
+ if (image.data_type == ASTCENC_TYPE_F32) {
+ image_format = Image::FORMAT_RGBAF;
+ } else if (image.data_type == ASTCENC_TYPE_U8) {
+ image_format = Image::FORMAT_RGBA8;
+ } else if (image.data_type == ASTCENC_TYPE_F16) {
+ image_format = Image::FORMAT_RGBAH;
+ } else {
+ ERR_FAIL_MSG("astcenc: ASTC decompression failed with an unknown format.");
+ }
+
+ r_img->set_data(image.dim_x, image.dim_y, mipmaps, image_format, new_image_data);
+
+ print_verbose(vformat("astcenc: Decompression took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
+}
diff --git a/modules/astcenc/image_compress_astcenc.h b/modules/astcenc/image_compress_astcenc.h
new file mode 100644
index 0000000000..a197a91e0d
--- /dev/null
+++ b/modules/astcenc/image_compress_astcenc.h
@@ -0,0 +1,39 @@
+/**************************************************************************/
+/* image_compress_astcenc.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef IMAGE_COMPRESS_ASTCENC_H
+#define IMAGE_COMPRESS_ASTCENC_H
+
+#include "core/io/image.h"
+
+void _compress_astc(Image *r_img, float p_lossy_quality, Image::ASTCFormat p_format);
+void _decompress_astc(Image *r_img);
+
+#endif // IMAGE_COMPRESS_ASTCENC_H
diff --git a/modules/astcenc/register_types.cpp b/modules/astcenc/register_types.cpp
new file mode 100644
index 0000000000..0bb1c3432f
--- /dev/null
+++ b/modules/astcenc/register_types.cpp
@@ -0,0 +1,48 @@
+/**************************************************************************/
+/* register_types.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "register_types.h"
+
+#include "image_compress_astcenc.h"
+
+void initialize_astcenc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
+ Image::_image_compress_astc_func = _compress_astc;
+ Image::_image_decompress_astc = _decompress_astc;
+}
+
+void uninitialize_astcenc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/astcenc/register_types.h b/modules/astcenc/register_types.h
new file mode 100644
index 0000000000..636da9ff8b
--- /dev/null
+++ b/modules/astcenc/register_types.h
@@ -0,0 +1,39 @@
+/**************************************************************************/
+/* register_types.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef ASTCENC_REGISTER_TYPES_H
+#define ASTCENC_REGISTER_TYPES_H
+
+#include "modules/register_module_types.h"
+
+void initialize_astcenc_module(ModuleInitializationLevel p_level);
+void uninitialize_astcenc_module(ModuleInitializationLevel p_level);
+
+#endif // ASTCENC_REGISTER_TYPES_H
diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp
index b5192bd664..a6aeec54cc 100644
--- a/modules/etcpak/image_compress_etcpak.cpp
+++ b/modules/etcpak/image_compress_etcpak.cpp
@@ -33,8 +33,8 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-#include "thirdparty/etcpak/ProcessDxtc.hpp"
-#include "thirdparty/etcpak/ProcessRGB.hpp"
+#include <ProcessDxtc.hpp>
+#include <ProcessRGB.hpp>
EtcpakType _determine_etc_type(Image::UsedChannels p_channels) {
switch (p_channels) {
@@ -130,7 +130,7 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua
} else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5) {
target_format = Image::FORMAT_DXT5;
} else {
- ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format.");
+ ERR_FAIL_MSG("Invalid or unsupported etcpak compression format, not ETC or DXT.");
}
// Compress image data and (if required) mipmaps.
@@ -171,7 +171,7 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua
const uint8_t *src_read = r_img->get_data().ptr();
- print_verbose(vformat("ETCPAK: Encoding image size %dx%d to format %s.", width, height, Image::get_format_name(target_format)));
+ print_verbose(vformat("etcpak: Encoding image size %dx%d to format %s%s.", width, height, Image::get_format_name(target_format), mipmaps ? ", with mipmaps" : ""));
int dest_size = Image::get_image_data_size(width, height, target_format, mipmaps);
Vector<uint8_t> dest_data;
@@ -232,12 +232,12 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua
} else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5 || p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) {
CompressDxt5(src_mip_read, dest_mip_write, blocks, mip_w);
} else {
- ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format.");
+ ERR_FAIL_MSG("etcpak: Invalid or unsupported compression format.");
}
}
// Replace original image with compressed one.
r_img->set_data(width, height, mipmaps, target_format, dest_data);
- print_verbose(vformat("ETCPAK encode took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
+ print_verbose(vformat("etcpak: Encoding took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
}
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 788a70f640..5634c51c61 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -3124,10 +3124,11 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
// API for that in Godot, so we'd have to load as a buffer (i.e. embedded in
// the material), so we do this only as fallback.
Ref<Texture2D> texture = ResourceLoader::load(uri);
+ String extension = uri.get_extension().to_lower();
if (texture.is_valid()) {
p_state->images.push_back(texture);
continue;
- } else if (mimetype == "image/png" || mimetype == "image/jpeg") {
+ } else if (mimetype == "image/png" || mimetype == "image/jpeg" || extension == "png" || extension == "jpg" || extension == "jpeg") {
// Fallback to loading as byte array.
// This enables us to support the spec's requirement that we honor mimetype
// regardless of file URI.
diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp
index 0acaaf5fc9..d473f3b4a0 100644
--- a/modules/ogg/ogg_packet_sequence.cpp
+++ b/modules/ogg/ogg_packet_sequence.cpp
@@ -136,6 +136,8 @@ bool OggPacketSequencePlayback::next_ogg_packet(ogg_packet **p_packet) const {
ERR_FAIL_COND_V(data_version != ogg_packet_sequence->data_version, false);
ERR_FAIL_COND_V(ogg_packet_sequence->page_data.is_empty(), false);
ERR_FAIL_COND_V(ogg_packet_sequence->page_granule_positions.is_empty(), false);
+ ERR_FAIL_COND_V(page_cursor >= ogg_packet_sequence->page_data.size(), false);
+
// Move on to the next page if need be. This happens first to help simplify seek logic.
while (packet_cursor >= ogg_packet_sequence->page_data[page_cursor].size()) {
packet_cursor = 0;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 8e9ff61ad0..79ca4a7024 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -3654,6 +3654,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
sd->hb_buffer = hb_buffer_create();
@@ -3679,6 +3680,7 @@ void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) {
void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -3738,8 +3740,12 @@ void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, con
}
sd->bidi_override.clear();
for (int i = 0; i < p_override.size(); i++) {
- if (p_override[i].get_type() == Variant::VECTOR2I) {
- sd->bidi_override.push_back(p_override[i]);
+ if (p_override[i].get_type() == Variant::VECTOR3I) {
+ const Vector3i &r = p_override[i];
+ sd->bidi_override.push_back(r);
+ } else if (p_override[i].get_type() == Variant::VECTOR2I) {
+ const Vector2i &r = p_override[i];
+ sd->bidi_override.push_back(Vector3i(r.x, r.y, DIRECTION_INHERITED));
}
}
invalidate(sd, false);
@@ -5544,8 +5550,31 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));
}
+ int base_para_direction = UBIDI_DEFAULT_LTR;
+ switch (sd->direction) {
+ case DIRECTION_LTR: {
+ sd->para_direction = DIRECTION_LTR;
+ base_para_direction = UBIDI_LTR;
+ } break;
+ case DIRECTION_RTL: {
+ sd->para_direction = DIRECTION_RTL;
+ base_para_direction = UBIDI_RTL;
+ } break;
+ case DIRECTION_INHERITED:
+ case DIRECTION_AUTO: {
+ UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length());
+ if (direction != UBIDI_NEUTRAL) {
+ sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
+ base_para_direction = direction;
+ } else {
+ sd->para_direction = DIRECTION_LTR;
+ base_para_direction = UBIDI_DEFAULT_LTR;
+ }
+ } break;
+ }
+
if (sd->bidi_override.is_empty()) {
- sd->bidi_override.push_back(Vector2i(sd->start, sd->end));
+ sd->bidi_override.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED));
}
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
@@ -5561,23 +5590,22 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
UBiDi *bidi_iter = ubidi_openSized(end, 0, &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
- switch (sd->direction) {
+ switch (static_cast<TextServer::Direction>(sd->bidi_override[ov].z)) {
case DIRECTION_LTR: {
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
- sd->para_direction = DIRECTION_LTR;
} break;
case DIRECTION_RTL: {
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
- sd->para_direction = DIRECTION_RTL;
+ } break;
+ case DIRECTION_INHERITED: {
+ ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err);
} break;
case DIRECTION_AUTO: {
UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
if (direction != UBIDI_NEUTRAL) {
ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
- sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
} else {
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_DEFAULT_LTR, nullptr, &err);
- sd->para_direction = DIRECTION_LTR;
}
} break;
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 5920ddaa50..c7fe46d554 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -499,7 +499,7 @@ class TextServerAdvanced : public TextServerExtension {
/* Intermediate data */
Char16String utf16;
Vector<UBiDi *> bidi_iter;
- Vector<Vector2i> bidi_override;
+ Vector<Vector3i> bidi_override;
ScriptIterator *script_iter = nullptr;
hb_buffer_t *hb_buffer = nullptr;
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index ece34f56d6..b5d7d3a3cf 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -51,7 +51,6 @@ using namespace godot;
#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
-#include "core/string/ucaps.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
@@ -2665,6 +2664,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
sd->direction = p_direction;
@@ -2688,6 +2688,7 @@ void TextServerFallback::_shaped_text_clear(const RID &p_shaped) {
}
void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
+ ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
if (p_direction == DIRECTION_RTL) {
ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server.");
}
@@ -4060,31 +4061,11 @@ double TextServerFallback::_shaped_text_get_underline_thickness(const RID &p_sha
}
String TextServerFallback::_string_to_upper(const String &p_string, const String &p_language) const {
- String upper = p_string;
-
- for (int i = 0; i <= upper.length(); i++) {
- const char32_t s = upper[i];
- const char32_t t = _find_upper(s);
- if (s != t) { // avoid copy on write
- upper[i] = t;
- }
- }
-
- return upper;
+ return p_string.to_upper();
}
String TextServerFallback::_string_to_lower(const String &p_string, const String &p_language) const {
- String lower = p_string;
-
- for (int i = 0; i <= lower.length(); i++) {
- const char32_t s = lower[i];
- const char32_t t = _find_lower(s);
- if (s != t) { // avoid copy on write
- lower[i] = t;
- }
- }
-
- return lower;
+ return p_string.to_lower();
}
PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int p_chars_per_line) const {