diff options
514 files changed, 24982 insertions, 8047 deletions
@@ -72,6 +72,7 @@ Liz Haas <27thLiz@gmail.com> <hinsbart@gmail.com> Liz Haas <27thLiz@gmail.com> <hinsbart@users.noreply.github.com> Liz Haas <27thLiz@gmail.com> <entenflugstuhl@gmail.com> Manuel Strey <manuel.strey@gmx.de> +Marcel Admiraal <madmiraal@users.noreply.github.com> Marcelo Fernandez <marcelofg55@gmail.com> Marcin Zawiejski <dragmz@gmail.com> Marcus Elg <marcusaccounts@yahoo.se> @@ -30,15 +30,16 @@ generous deed immortalized in the next stable release of Godot Engine. Brandon Lamb Garry Newman + Gordon MacPherson Hunter Dickson ## Mini sponsors AD Ford - albinaask Alejandro Saucedo alex brown Andrew Dunai + CD Christian Baune Christoffer Sundbom Christopher Montesano @@ -47,6 +48,7 @@ generous deed immortalized in the next stable release of Godot Engine. Digital Grows Dov Zimring Edward Flick + Franz Silva Gamechuck GameDev.net Hein-Pieter van Braam @@ -77,9 +79,9 @@ generous deed immortalized in the next stable release of Godot Engine. ## Gold donors - Andrew Morsillo + Acheron + albinaask Asher Glick - Austen McRae Bernhard Werner Carlo Cabanilla Chris Goddard @@ -88,18 +90,20 @@ generous deed immortalized in the next stable release of Godot Engine. David Gehrig David Snopek Ed Morley - eggs Ellen Poe - Florian Breisch + Florian Neumann Florian Rämisch Forge Gamejunkey Grady + Hoojib Jakub Grzesik Javier Roman Jeff Nyte Joan Fons + Johnny IV Young Jon Woodward + Kai Klyden Karl Werf Klavdij Voncina Lex Steers @@ -114,6 +118,7 @@ generous deed immortalized in the next stable release of Godot Engine. Mohamed Ikbel Boulabiar Monster Vial Officine Pixel S.n.c. + Pixel Booty Rami Rene Rene Tailleur @@ -123,9 +128,9 @@ generous deed immortalized in the next stable release of Godot Engine. Ronan Zeegers Sandro Jenny Sarksus + Scott B Sean Sergey - SIM KIM SIA Sofox Taylor Ritenour Tom Langwaldt @@ -133,20 +138,24 @@ generous deed immortalized in the next stable release of Godot Engine. tukon William Wold xagonist + Xeno Coliseum Zaven Muradyan Aaron Winter Adam Nakonieczny + Adrian Adamiak Alexander J Maynard Alex de la Mare Alex Khayrullin alice gambrell Andreas Funke - Andrew Harris + André Frélicot Antoni Batchelli Arisaka Mayuki + Aubin Detrez Barugon Ben Botwin + Can Eris Charlie Whitfield Chase Taranto Chelsea Hash @@ -154,7 +163,6 @@ generous deed immortalized in the next stable release of Godot Engine. Chris Serino Christian Leth Jeppesen Cody Brooks - Cody Parker Conrad Curry Craig Ostrin Craig Smith @@ -167,6 +175,7 @@ generous deed immortalized in the next stable release of Godot Engine. Edgar Sun Eugenio Hugo Salgüero Jáñez flesk + Francisco Arámburo F S Gabrielius VaiÅ¡kÅ«nas Gary Hulst @@ -175,10 +184,11 @@ generous deed immortalized in the next stable release of Godot Engine. GiulianoB Green Fox Guilherme Felipe de C. G. da Silva + Harvey Fong Heath Hayes - Hoai Nam Tran Horváth Péter Hu Hund + Idilio Alfaro James Couzens Jared Jared White @@ -206,19 +216,24 @@ generous deed immortalized in the next stable release of Godot Engine. luka duren MadScientistCarl Marcelo Dornbusch Lopes + Marcus Dobler + Marcus Richter Marisa Clardy + Mark Barrett Markus Fehr Martin Eigel Martin Kotz Martin Soucek Matt Eunson + Matt Greene Michael Michael Dürwald - Mikado069 + MikadoSC MuffinManKen Nick Abousselam Oliver Dick Oscar Campos + Patrick Brock Patrick Ting Paul Hocker Paul Von Zimmerman @@ -227,41 +242,44 @@ generous deed immortalized in the next stable release of Godot Engine. Petr Malac PhaineOfCatz pl - Ranoller Raymond Harris - razmie + Raz A Ricardo Alcantara Robert Willes Rob McInroy Rocknight Studios + Rodrigo Favarete Ronnie Ashlock + Ronny Mühle Ryan Wilson Samuel Judd Scott Pilet Sean Morgan - Sean Robertson Sébastien + Serban Serafimescu Sergey Minakov Shishir Tandale SKison spilldata + Stephan Hennion Steven Landow Stoned Xander TheLevelOfDetail . Thomas Bjarnelöf Thomas Kurz Tim Howard - Timothy Pulliam Tobias Bocanegra Trent Fehl + Turntsnaco Valryia - VikFro Vincent Cloutier - VojtÄ›ch + Vlad Ceru Opran + VoidPointer voxelv William Foster Wojciech Chojnacki xzibiting + Yuancheng Zhang Zhou Tuizhi Zie Weaver Zoran Kukulj @@ -271,7 +289,6 @@ generous deed immortalized in the next stable release of Godot Engine. 1D_Inc Aaron Passchier Abraham Haskins - Acheron Adam Adam Brunnmeier Adam Carr @@ -285,6 +302,7 @@ generous deed immortalized in the next stable release of Godot Engine. Agustinus Arya Ahmet Kalyoncu Aidan O'Flannagain + AJ Austinson Aki Mimoto Alan Beauchamp Albin Jonasson Svärdsby @@ -297,6 +315,8 @@ generous deed immortalized in the next stable release of Godot Engine. Ali Al-Khalifa Allan Davis Allen Schade + Ancient Phoenix + Anders Marstein Kruke Andreas Krampitz André Simões Andre Stackhouse @@ -306,15 +326,17 @@ generous deed immortalized in the next stable release of Godot Engine. Andrew Thomas Ano Nim Anthony Avina + aomimezura11 AP Condomines + Arch Toasty Arda Erol Armin Preiml Arseniy M Arthur S. Muszynski Ashley Claymore - Ashton Scott Snapp Astier Mickael Aubrey Falconer + AzulCrescent B A Balázs Batári Balázs Kondákor @@ -331,8 +353,9 @@ generous deed immortalized in the next stable release of Godot Engine. Boyd Trolinger Bram brian - Brian mc gowan + Brian Klein Brodie Fairhall + Bronson Zgeb Burney Waring Caleb Gartner Cameron Meyer @@ -346,25 +369,27 @@ generous deed immortalized in the next stable release of Godot Engine. Chris Jagusch Chris Langford Christian Clavet + Christian Mauduit Christian Winter Christoffer Dahlblom Christophe Gagnier Christopher Schmitt Christoph Woinke + Chris Truebe Clay Heaton Conall O - Curt King Cyrelouyea CzechBlueBear + Daniel Cheney Daniel Johnson DanielMaximiano - Daniel Tebbutt - Danny Welch Daren Scot Wilson Dave Walker David Bôle David May + David Maziarka David Woodard + Devin Carraway Dmitry Fisher Dmytro Korchynskyi Dominik Wetzel @@ -400,6 +425,7 @@ generous deed immortalized in the next stable release of Godot Engine. gamedev by Celio Gary Thomas George Marques + Gerard Ruiz Torruella Greg Lincoln Greg Olson GREGORY C FEIN @@ -412,12 +438,15 @@ generous deed immortalized in the next stable release of Godot Engine. Hal A helija Heribert Hirth + Hoai Nam Tran Hunter Jones Hylpher Ian Williams Iiari iKlem IndustrialRobot + iveks + Ivica Å imić Jackson Harmer Jacob Jaguar @@ -431,7 +460,6 @@ generous deed immortalized in the next stable release of Godot Engine. James Thomas Jamiee H Jamie Massey - Janders JARKKO PARVIAINEN Jason Uechi Jean-Baptiste LEPESME @@ -452,15 +480,17 @@ generous deed immortalized in the next stable release of Godot Engine. Jon Sully Jordy Goodridge Jorge Antunes + Jorge Javier Araya Navarro Jose C. Rubio Joseph Catrambone Josh Mitchell + Josh Taylor Joshua Southerland Juanfran + Jueast Julian Murgia June Little JungleRobba - Justin Calleja Justin Oaksford Justin Spedding KaDokta @@ -470,27 +500,36 @@ generous deed immortalized in the next stable release of Godot Engine. Keedong Park Keinan Powers Keith Bradner + Kenji Kawabata + Kenneth Lee Kent Jofur Kevin McPhillips Kiri Jolly + Kiyohiro Kawamura (kyorohiro) Kjetil Haugland Kristian Nygaard Jensen KsyTek Games Kuan Cheang kycho + Kyle Jacobs Kyle Szklenski Kyuppin Laurent CHEA Laurent Tréguier + Lee Meichin LEMMiNO + Lenny Leonardo Dimano Lin Chear Linus Lind Lundgren Lionel Gaillard Luigi Renna + Luis Gaemperle + Luis M LunaticInAHat Lurkars Major Haul + makoto asano Malcolm Marco Lardelli Mark Jad @@ -500,7 +539,6 @@ generous deed immortalized in the next stable release of Godot Engine. Martin FIbik Martin Holas Martin Linklater - Martin LiÅ¡ka Martin Trbola Marvin Mathieu @@ -513,6 +551,7 @@ generous deed immortalized in the next stable release of Godot Engine. Megasploot Melissa Mears mewin + Michael Michael Haney MichaÅ‚ Skwarek Mikayla @@ -539,6 +578,7 @@ generous deed immortalized in the next stable release of Godot Engine. Nicolas Goll-Perrier Nicolás Montaña Nicolas SAN AGUSTIN + Nima Farid NZ OKV Oleg Reva @@ -548,6 +588,7 @@ generous deed immortalized in the next stable release of Godot Engine. Oscar Domingo Oscar Norlander Parinya Teerakasemsuk + patricio lara briones Patrick Dully Patrick Nafarrete Paul Gieske @@ -555,7 +596,6 @@ generous deed immortalized in the next stable release of Godot Engine. PaweÅ‚ Kowal PaweÅ‚ Åyczkowski Pedro Assuncao - Penguin Petrus Prinsloo Philip Cohoe Piotr Góral @@ -570,6 +610,7 @@ generous deed immortalized in the next stable release of Godot Engine. Reneator Richard Diss Richard Ivánek + Riley Robert Farr (Larington) Robert Larnach Rob Ruana @@ -578,10 +619,8 @@ generous deed immortalized in the next stable release of Godot Engine. Roman Tinkov Ronald Ho Hip (CrimsonZA) Ronan - Ronny Mühle Ross Squires Ryan Groom - Sam Caulfield Sam Edson Samuele Zolfanelli sayaks @@ -590,11 +629,12 @@ generous deed immortalized in the next stable release of Godot Engine. ScottMakesGames Sebastian Michailidis Sebastian Vetter + SeongWan Kim + Sergiy Onenko Shaher Shane Shane Sicienski Shane Spoor - Shiomi - Duy Kevin Nguyen Siim Raidma Simon Jonas Larsen Simon Schoenenberger @@ -606,6 +646,7 @@ generous deed immortalized in the next stable release of Godot Engine. Squirrel Stefano Caronia Steve Cloete + Sung soo Choi Svenne Krap tadashi endo tannhauser_gate @@ -643,6 +684,7 @@ generous deed immortalized in the next stable release of Godot Engine. Victor Vigilant Watch Viktor Ismagilov + Vitaliy Sapronenko Vitor Balbio Vladimir Savin Vladislav Smirnov @@ -656,8 +698,10 @@ generous deed immortalized in the next stable release of Godot Engine. William F Siqueira William Hogben Wyatt Goodin + xenomat Yegor Smirnov YiYin Gu + Zack Yang Zak Stephens ΒΑΣΙΛΗΣ ΓΕΩΡΓΑΚΟΠΟΥΛΟΣ è•æƒŸå… diff --git a/SConstruct b/SConstruct index 10f961cff8..6aeb79e483 100644 --- a/SConstruct +++ b/SConstruct @@ -530,13 +530,13 @@ if selected_platform in platform_list: doc_path = config.get_doc_path() for c in doc_classes: env.doc_class_path[c] = path + "/" + doc_path - except: + except Exception: pass # Get icon paths (if present) try: icons_path = config.get_icons_path() env.module_icons_paths.append(path + "/" + icons_path) - except: + except Exception: # Default path for module icons env.module_icons_paths.append(path + "/" + "icons") modules_enabled[name] = path diff --git a/core/SCsub b/core/SCsub index 78a4395619..45918fb520 100644 --- a/core/SCsub +++ b/core/SCsub @@ -25,7 +25,7 @@ if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ: txts = "0x" + e[i * 2 : i * 2 + 2] try: int(txts, 16) - except: + except Exception: ec_valid = False txt += txts if not ec_valid: diff --git a/core/doc_data.h b/core/doc_data.h index bf016792ea..65b57d1381 100644 --- a/core/doc_data.h +++ b/core/doc_data.h @@ -89,7 +89,7 @@ public: struct ConstantDoc { String name; String value; - bool is_value_valid; + bool is_value_valid = false; String enumeration; String description; bool operator<(const ConstantDoc &p_const) const { diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index e04e642f6b..82bfaa82a5 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -213,7 +213,7 @@ String InputEventWithModifiers::as_text() const { if (!mod_names.empty()) { return String("+").join(mod_names); } else { - return "None"; + return ""; } } @@ -369,11 +369,19 @@ String InputEventKey::to_string() { String p = is_pressed() ? "true" : "false"; String e = is_echo() ? "true" : "false"; + String kc = ""; + String physical = "false"; if (keycode == 0) { - return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", itos(physical_keycode) + " " + keycode_get_string(physical_keycode), InputEventWithModifiers::as_text(), "true", p, e); + kc = itos(physical_keycode) + " " + keycode_get_string(physical_keycode); + physical = "true"; } else { - return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", itos(keycode) + " " + keycode_get_string(keycode), InputEventWithModifiers::as_text(), "false", p, e); + kc = itos(keycode) + " " + keycode_get_string(keycode); } + + String mods = InputEventWithModifiers::as_text(); + mods = mods == "" ? TTR("None") : mods; + + return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", kc, mods, physical, p, e); } bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const { @@ -633,7 +641,12 @@ String InputEventMouseButton::to_string() { break; } - return vformat("InputEventMouseButton: button_index=%s pressed=%s position=(%s) button_mask=%s doubleclick=%s", button_index, p, String(get_position()), itos(get_button_mask()), d); + String mods = InputEventWithModifiers::as_text(); + mods = mods == "" ? TTR("None") : mods; + + // Work around the fact vformat can only take 5 substitutions but 6 need to be passed. + String index_and_mods = vformat("button_index=%s mods=%s", button_index, mods); + return vformat("InputEventMouseButton: %s pressed=%s position=(%s) button_mask=%s doubleclick=%s", index_and_mods, p, String(get_position()), itos(get_button_mask()), d); } void InputEventMouseButton::_bind_methods() { diff --git a/core/io/compression.cpp b/core/io/compression.cpp index cd8793bb0a..8e613cb3ce 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -257,13 +257,13 @@ int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_s } while (ret != Z_STREAM_END); // If all done successfully, resize the output if it's larger than the actual output - if (ret == Z_STREAM_END && (unsigned long)p_dst_vect->size() > strm.total_out) { + if ((unsigned long)p_dst_vect->size() > strm.total_out) { p_dst_vect->resize(strm.total_out); } // clean up and return (void)inflateEnd(&strm); - return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; + return Z_OK; } int Compression::zlib_level = Z_DEFAULT_COMPRESSION; diff --git a/core/io/file_access_buffered.cpp b/core/io/file_access_buffered.cpp deleted file mode 100644 index 714f3b6099..0000000000 --- a/core/io/file_access_buffered.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/*************************************************************************/ -/* file_access_buffered.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "file_access_buffered.h" - -#include "core/error/error_macros.h" - -Error FileAccessBuffered::set_error(Error p_error) const { - return (last_error = p_error); -} - -void FileAccessBuffered::set_cache_size(int p_size) { - cache_size = p_size; -} - -int FileAccessBuffered::get_cache_size() { - return cache_size; -} - -int FileAccessBuffered::cache_data_left() const { - if (file.offset >= file.size) { - return 0; - } - - if (cache.offset == -1 || file.offset < cache.offset || file.offset >= cache.offset + cache.buffer.size()) { - return read_data_block(file.offset, cache_size); - } - - return cache.buffer.size() - (file.offset - cache.offset); -} - -void FileAccessBuffered::seek(size_t p_position) { - file.offset = p_position; -} - -void FileAccessBuffered::seek_end(int64_t p_position) { - file.offset = file.size + p_position; -} - -size_t FileAccessBuffered::get_position() const { - return file.offset; -} - -size_t FileAccessBuffered::get_len() const { - return file.size; -} - -bool FileAccessBuffered::eof_reached() const { - return file.offset > file.size; -} - -uint8_t FileAccessBuffered::get_8() const { - ERR_FAIL_COND_V_MSG(!file.open, 0, "Can't get data, when file is not opened."); - - uint8_t byte = 0; - if (cache_data_left() >= 1) { - byte = cache.buffer[file.offset - cache.offset]; - } - - ++file.offset; - - return byte; -} - -int FileAccessBuffered::get_buffer(uint8_t *p_dest, int p_length) const { - ERR_FAIL_COND_V_MSG(!file.open, -1, "Can't get buffer, when file is not opened."); - - if (p_length > cache_size) { - int total_read = 0; - - if (!(cache.offset == -1 || file.offset < cache.offset || file.offset >= cache.offset + cache.buffer.size())) { - int size = (cache.buffer.size() - (file.offset - cache.offset)); - size = size - (size % 4); - //const uint8_t* read = cache.buffer.ptr(); - //memcpy(p_dest, read.ptr() + (file.offset - cache.offset), size); - memcpy(p_dest, cache.buffer.ptr() + (file.offset - cache.offset), size); - p_dest += size; - p_length -= size; - file.offset += size; - total_read += size; - } - - int err = read_data_block(file.offset, p_length, p_dest); - if (err >= 0) { - total_read += err; - file.offset += err; - } - - return total_read; - } - - int to_read = p_length; - int total_read = 0; - while (to_read > 0) { - int left = cache_data_left(); - if (left == 0) { - file.offset += to_read; - return total_read; - } - if (left < 0) { - return left; - } - - int r = MIN(left, to_read); - //const uint8_t* read = cache.buffer.ptr(); - //memcpy(p_dest+total_read, &read.ptr()[file.offset - cache.offset], r); - memcpy(p_dest + total_read, cache.buffer.ptr() + (file.offset - cache.offset), r); - - file.offset += r; - total_read += r; - to_read -= r; - } - - return p_length; -} - -bool FileAccessBuffered::is_open() const { - return file.open; -} - -Error FileAccessBuffered::get_error() const { - return last_error; -} diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h deleted file mode 100644 index f22e54e154..0000000000 --- a/core/io/file_access_buffered_fa.h +++ /dev/null @@ -1,139 +0,0 @@ -/*************************************************************************/ -/* file_access_buffered_fa.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 FILE_ACCESS_BUFFERED_FA_H -#define FILE_ACCESS_BUFFERED_FA_H - -#include "core/io/file_access_buffered.h" - -template <class T> -class FileAccessBufferedFA : public FileAccessBuffered { - T f; - - int read_data_block(int p_offset, int p_size, uint8_t *p_dest = 0) const { - ERR_FAIL_COND_V_MSG(!f.is_open(), -1, "Can't read data block when file is not opened."); - - ((T *)&f)->seek(p_offset); - - if (p_dest) { - f.get_buffer(p_dest, p_size); - return p_size; - - } else { - cache.offset = p_offset; - cache.buffer.resize(p_size); - - // on Vector - //uint8_t* write = cache.buffer.ptrw(); - //f.get_buffer(write.ptrw(), p_size); - - // on vector - f.get_buffer(cache.buffer.ptrw(), p_size); - - return p_size; - } - } - - static FileAccess *create() { - return memnew(FileAccessBufferedFA<T>()); - } - -protected: - virtual void _set_access_type(AccessType p_access) { - f._set_access_type(p_access); - FileAccessBuffered::_set_access_type(p_access); - } - -public: - void flush() { - f.flush(); - } - - void store_8(uint8_t p_dest) { - f.store_8(p_dest); - } - - void store_buffer(const uint8_t *p_src, int p_length) { - f.store_buffer(p_src, p_length); - } - - bool file_exists(const String &p_name) { - return f.file_exists(p_name); - } - - Error _open(const String &p_path, int p_mode_flags) { - close(); - - Error ret = f._open(p_path, p_mode_flags); - if (ret != OK) - return ret; - //ERR_FAIL_COND_V( ret != OK, ret ); - - file.size = f.get_len(); - file.offset = 0; - file.open = true; - file.name = p_path; - file.access_flags = p_mode_flags; - - cache.buffer.resize(0); - cache.offset = 0; - - return set_error(OK); - } - - void close() { - f.close(); - - file.offset = 0; - file.size = 0; - file.open = false; - file.name = ""; - - cache.buffer.resize(0); - cache.offset = 0; - set_error(OK); - } - - virtual uint64_t _get_modified_time(const String &p_file) { - return f._get_modified_time(p_file); - } - - virtual uint32_t _get_unix_permissions(const String &p_file) { - return f._get_unix_permissions(p_file); - } - - virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { - return f._set_unix_permissions(p_file, p_permissions); - } - - FileAccessBufferedFA() {} -}; - -#endif // FILE_ACCESS_BUFFERED_FA_H diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index eff07c60e2..f8e7c1e587 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -59,8 +59,6 @@ private: static ZipArchive *instance; - FileAccess::CreateFunc fa_create_func; - public: void close_handle(unzFile p_file) const; unzFile get_file_handle(String p_file) const; diff --git a/core/io/image.cpp b/core/io/image.cpp index 6dde25af32..7c32c02701 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -66,10 +66,10 @@ const char *Image::format_names[Image::FORMAT_MAX] = { "BPTC_RGBA", "BPTC_RGBF", "BPTC_RGBFU", - "PVRTC2", //pvrtc - "PVRTC2A", - "PVRTC4", - "PVRTC4A", + "PVRTC1_2", //pvrtc + "PVRTC1_2A", + "PVRTC1_4", + "PVRTC1_4A", "ETC", //etc1 "ETC2_R11", //etc2 "ETC2_R11S", //signed", NOT srgb. @@ -155,13 +155,13 @@ int Image::get_format_pixel_size(Format p_format) { return 1; //float / case FORMAT_BPTC_RGBFU: return 1; //unsigned float - case FORMAT_PVRTC2: + case FORMAT_PVRTC1_2: return 1; //pvrtc - case FORMAT_PVRTC2A: + case FORMAT_PVRTC1_2A: return 1; - case FORMAT_PVRTC4: + case FORMAT_PVRTC1_4: return 1; - case FORMAT_PVRTC4A: + case FORMAT_PVRTC1_4A: return 1; case FORMAT_ETC: return 1; //etc1 @@ -200,13 +200,13 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) { r_w = 4; r_h = 4; } break; - case FORMAT_PVRTC2: - case FORMAT_PVRTC2A: { + case FORMAT_PVRTC1_2: + case FORMAT_PVRTC1_2A: { r_w = 16; r_h = 8; } break; - case FORMAT_PVRTC4A: - case FORMAT_PVRTC4: { + case FORMAT_PVRTC1_4A: + case FORMAT_PVRTC1_4: { r_w = 8; r_h = 8; } break; @@ -242,9 +242,9 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) { } int Image::get_format_pixel_rshift(Format p_format) { - if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_PVRTC4 || p_format == FORMAT_PVRTC4A || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) { + if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_PVRTC1_4 || p_format == FORMAT_PVRTC1_4A || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) { return 1; - } else if (p_format == FORMAT_PVRTC2 || p_format == FORMAT_PVRTC2A) { + } else if (p_format == FORMAT_PVRTC1_2 || p_format == FORMAT_PVRTC1_2A) { return 2; } else { return 0; @@ -261,12 +261,12 @@ int Image::get_format_block_size(Format p_format) { return 4; } - case FORMAT_PVRTC2: - case FORMAT_PVRTC2A: { + case FORMAT_PVRTC1_2: + case FORMAT_PVRTC1_2A: { return 4; } - case FORMAT_PVRTC4A: - case FORMAT_PVRTC4: { + case FORMAT_PVRTC1_4A: + case FORMAT_PVRTC1_4: { return 4; } case FORMAT_ETC: { @@ -2216,8 +2216,8 @@ bool Image::is_invisible() const { } break; - case FORMAT_PVRTC2A: - case FORMAT_PVRTC4A: + case FORMAT_PVRTC1_2A: + case FORMAT_PVRTC1_4A: case FORMAT_DXT3: case FORMAT_DXT5: { detected = true; @@ -2258,8 +2258,8 @@ Image::AlphaMode Image::detect_alpha() const { } } break; - case FORMAT_PVRTC2A: - case FORMAT_PVRTC4A: + case FORMAT_PVRTC1_2A: + case FORMAT_PVRTC1_4A: case FORMAT_DXT3: case FORMAT_DXT5: { detected = true; @@ -2355,7 +2355,7 @@ Error Image::decompress() { _image_decompress_bc(this); } else if (format >= FORMAT_BPTC_RGBA && format <= FORMAT_BPTC_RGBFU && _image_decompress_bptc) { _image_decompress_bptc(this); - } else if (format >= FORMAT_PVRTC2 && format <= FORMAT_PVRTC4A && _image_decompress_pvrtc) { + } else if (format >= FORMAT_PVRTC1_2 && format <= FORMAT_PVRTC1_4A && _image_decompress_pvrtc) { _image_decompress_pvrtc(this); } else if (format == FORMAT_ETC && _image_decompress_etc1) { _image_decompress_etc1(this); @@ -2377,13 +2377,9 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE); _image_compress_bc_func(this, p_lossy_quality, p_channels); } break; - case COMPRESS_PVRTC2: { - ERR_FAIL_COND_V(!_image_compress_pvrtc2_func, ERR_UNAVAILABLE); - _image_compress_pvrtc2_func(this); - } break; - case COMPRESS_PVRTC4: { - ERR_FAIL_COND_V(!_image_compress_pvrtc4_func, ERR_UNAVAILABLE); - _image_compress_pvrtc4_func(this); + case COMPRESS_PVRTC1_4: { + ERR_FAIL_COND_V(!_image_compress_pvrtc1_4bpp_func, ERR_UNAVAILABLE); + _image_compress_pvrtc1_4bpp_func(this); } break; case COMPRESS_ETC: { ERR_FAIL_COND_V(!_image_compress_etc1_func, ERR_UNAVAILABLE); @@ -2714,8 +2710,7 @@ ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr; void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = nullptr; void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = nullptr; -void (*Image::_image_compress_pvrtc2_func)(Image *) = nullptr; -void (*Image::_image_compress_pvrtc4_func)(Image *) = nullptr; +void (*Image::_image_compress_pvrtc1_4bpp_func)(Image *) = nullptr; void (*Image::_image_compress_etc1_func)(Image *, float) = nullptr; void (*Image::_image_compress_etc2_func)(Image *, float, Image::UsedChannels) = nullptr; void (*Image::_image_decompress_pvrtc)(Image *) = nullptr; @@ -3173,10 +3168,10 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBA); //btpc bc6h BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBF); //float / BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBFU); //unsigned float - BIND_ENUM_CONSTANT(FORMAT_PVRTC2); //pvrtc - BIND_ENUM_CONSTANT(FORMAT_PVRTC2A); - BIND_ENUM_CONSTANT(FORMAT_PVRTC4); - BIND_ENUM_CONSTANT(FORMAT_PVRTC4A); + BIND_ENUM_CONSTANT(FORMAT_PVRTC1_2); //pvrtc + BIND_ENUM_CONSTANT(FORMAT_PVRTC1_2A); + BIND_ENUM_CONSTANT(FORMAT_PVRTC1_4); + BIND_ENUM_CONSTANT(FORMAT_PVRTC1_4A); BIND_ENUM_CONSTANT(FORMAT_ETC); //etc1 BIND_ENUM_CONSTANT(FORMAT_ETC2_R11); //etc2 BIND_ENUM_CONSTANT(FORMAT_ETC2_R11S); //signed ); NOT srgb. @@ -3200,10 +3195,10 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(ALPHA_BLEND); BIND_ENUM_CONSTANT(COMPRESS_S3TC); - BIND_ENUM_CONSTANT(COMPRESS_PVRTC2); - BIND_ENUM_CONSTANT(COMPRESS_PVRTC4); + BIND_ENUM_CONSTANT(COMPRESS_PVRTC1_4); BIND_ENUM_CONSTANT(COMPRESS_ETC); BIND_ENUM_CONSTANT(COMPRESS_ETC2); + BIND_ENUM_CONSTANT(COMPRESS_BPTC); BIND_ENUM_CONSTANT(USED_CHANNELS_L); BIND_ENUM_CONSTANT(USED_CHANNELS_LA); diff --git a/core/io/image.h b/core/io/image.h index c4c84589e5..0151df0cf9 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -91,10 +91,10 @@ public: FORMAT_BPTC_RGBA, //btpc bc7 FORMAT_BPTC_RGBF, //float bc6h FORMAT_BPTC_RGBFU, //unsigned float bc6hu - FORMAT_PVRTC2, //pvrtc - FORMAT_PVRTC2A, - FORMAT_PVRTC4, - FORMAT_PVRTC4A, + FORMAT_PVRTC1_2, //pvrtc1 + FORMAT_PVRTC1_2A, + FORMAT_PVRTC1_4, + FORMAT_PVRTC1_4A, FORMAT_ETC, //etc1 FORMAT_ETC2_R11, //etc2 FORMAT_ETC2_R11S, //signed, NOT srgb. @@ -138,8 +138,7 @@ public: static void (*_image_compress_bc_func)(Image *, float, UsedChannels p_channels); static void (*_image_compress_bptc_func)(Image *, float p_lossy_quality, UsedChannels p_channels); - static void (*_image_compress_pvrtc2_func)(Image *); - static void (*_image_compress_pvrtc4_func)(Image *); + static void (*_image_compress_pvrtc1_4bpp_func)(Image *); static void (*_image_compress_etc1_func)(Image *, float); static void (*_image_compress_etc2_func)(Image *, float, UsedChannels p_channels); @@ -332,11 +331,10 @@ public: enum CompressMode { COMPRESS_S3TC, - COMPRESS_PVRTC2, - COMPRESS_PVRTC4, + COMPRESS_PVRTC1_4, COMPRESS_ETC, COMPRESS_ETC2, - COMPRESS_BPTC + COMPRESS_BPTC, }; enum CompressSource { COMPRESS_SOURCE_GENERIC, diff --git a/core/io/logger.cpp b/core/io/logger.cpp index 0e6a2e2c9f..f5cea00f28 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -152,7 +152,7 @@ void RotatedFileLogger::rotate_file() { char timestamp[21]; OS::Date date = OS::get_singleton()->get_date(); OS::Time time = OS::get_singleton()->get_time(); - sprintf(timestamp, "_%04d-%02d-%02d_%02d-%02d-%02d", date.year, date.month, date.day, time.hour, time.min, time.sec); + sprintf(timestamp, "_%04d-%02d-%02d_%02d.%02d.%02d", date.year, date.month, date.day, time.hour, time.min, time.sec); String backup_name = base_path.get_basename() + timestamp; if (base_path.get_extension() != String()) { diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 3cf4acaf39..db12fcb7f7 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -1003,10 +1003,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } } break; - case Variant::STRING: { - _encode_string(p_variant, buf, r_len); - - } break; + case Variant::STRING: case Variant::STRING_NAME: { _encode_string(p_variant, buf, r_len); diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index b6cc5bf42a..3da494a8ef 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -151,11 +151,6 @@ void PacketPeer::_bind_methods() { /***************/ -void PacketPeerStream::_set_stream_peer(REF p_peer) { - ERR_FAIL_COND_MSG(p_peer.is_null(), "It's not a reference to a valid Resource object."); - set_stream_peer(p_peer); -} - void PacketPeerStream::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream_peer", "peer"), &PacketPeerStream::set_stream_peer); ClassDB::bind_method(D_METHOD("get_stream_peer"), &PacketPeerStream::get_stream_peer); @@ -263,10 +258,8 @@ int PacketPeerStream::get_max_packet_size() const { } void PacketPeerStream::set_stream_peer(const Ref<StreamPeer> &p_peer) { - //ERR_FAIL_COND(p_peer.is_null()); - if (p_peer.ptr() != peer.ptr()) { - ring_buffer.advance_read(ring_buffer.data_left()); // reset the ring buffer + ring_buffer.advance_read(ring_buffer.data_left()); // Reset the ring buffer. } peer = p_peer; diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index f7f080aa43..a25fa03875 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -86,7 +86,6 @@ class PacketPeerStream : public PacketPeer { Error _poll_buffer() const; protected: - void _set_stream_peer(REF p_peer); static void _bind_methods(); public: diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index c88331cf9e..9b14d2c763 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -192,10 +192,6 @@ bool ResourceFormatImporter::recognize_path(const String &p_path, const String & return FileAccess::exists(p_path + ".import"); } -bool ResourceFormatImporter::can_be_imported(const String &p_path) const { - return ResourceFormatLoader::recognize_path(p_path); -} - int ResourceFormatImporter::get_import_order(const String &p_path) const { Ref<ResourceImporter> importer; diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index 30bbd43c18..1b300bf656 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -70,7 +70,6 @@ public: virtual String get_import_group_file(const String &p_path) const; virtual bool exists(const String &p_path) const; - virtual bool can_be_imported(const String &p_path) const; virtual int get_import_order(const String &p_path) const; String get_internal_resource_path(const String &p_path) const; diff --git a/core/math/basis.cpp b/core/math/basis.cpp index c6030d9757..a64f29517d 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -1017,15 +1017,15 @@ void Basis::set_diagonal(const Vector3 &p_diag) { elements[2][2] = p_diag.z; } -Basis Basis::slerp(const Basis &target, const real_t &t) const { +Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const { //consider scale Quat from(*this); - Quat to(target); + Quat to(p_to); - Basis b(from.slerp(to, t)); - b.elements[0] *= Math::lerp(elements[0].length(), target.elements[0].length(), t); - b.elements[1] *= Math::lerp(elements[1].length(), target.elements[1].length(), t); - b.elements[2] *= Math::lerp(elements[2].length(), target.elements[2].length(), t); + Basis b(from.slerp(to, p_weight)); + b.elements[0] *= Math::lerp(elements[0].length(), p_to.elements[0].length(), p_weight); + b.elements[1] *= Math::lerp(elements[1].length(), p_to.elements[1].length(), p_weight); + b.elements[2] *= Math::lerp(elements[2].length(), p_to.elements[2].length(), p_weight); return b; } diff --git a/core/math/basis.h b/core/math/basis.h index 2584f1ff48..4cb3d55200 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -170,7 +170,7 @@ public: bool is_diagonal() const; bool is_rotation() const; - Basis slerp(const Basis &target, const real_t &t) const; + Basis slerp(const Basis &p_to, const real_t &p_weight) const; void rotate_sh(real_t *p_values); operator String() const; diff --git a/core/math/color.h b/core/math/color.h index a9be9e9035..b928ff8592 100644 --- a/core/math/color.h +++ b/core/math/color.h @@ -92,13 +92,13 @@ struct Color { void invert(); Color inverted() const; - _FORCE_INLINE_ Color lerp(const Color &p_b, float p_t) const { + _FORCE_INLINE_ Color lerp(const Color &p_to, float p_weight) const { Color res = *this; - res.r += (p_t * (p_b.r - r)); - res.g += (p_t * (p_b.g - g)); - res.b += (p_t * (p_b.b - b)); - res.a += (p_t * (p_b.a - a)); + res.r += (p_weight * (p_to.r - r)); + res.g += (p_weight * (p_to.g - g)); + res.b += (p_weight * (p_to.b - b)); + res.a += (p_weight * (p_to.a - a)); return res; } diff --git a/core/math/expression.cpp b/core/math/expression.cpp index d1f15caa5e..29b706a3a9 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -1003,31 +1003,19 @@ Expression::ENode *Expression::_parse_expression() { priority = 1; unary = true; break; - case Variant::OP_MULTIPLY: - priority = 2; - break; case Variant::OP_DIVIDE: - priority = 2; - break; case Variant::OP_MODULE: priority = 2; break; - case Variant::OP_ADD: - priority = 3; - break; case Variant::OP_SUBTRACT: priority = 3; break; - case Variant::OP_SHIFT_LEFT: - priority = 4; - break; case Variant::OP_SHIFT_RIGHT: priority = 4; break; - case Variant::OP_BIT_AND: priority = 5; break; @@ -1037,31 +1025,17 @@ Expression::ENode *Expression::_parse_expression() { case Variant::OP_BIT_OR: priority = 7; break; - case Variant::OP_LESS: - priority = 8; - break; case Variant::OP_LESS_EQUAL: - priority = 8; - break; case Variant::OP_GREATER: - priority = 8; - break; case Variant::OP_GREATER_EQUAL: - priority = 8; - break; - case Variant::OP_EQUAL: - priority = 8; - break; case Variant::OP_NOT_EQUAL: priority = 8; break; - case Variant::OP_IN: priority = 10; break; - case Variant::OP_NOT: priority = 11; unary = true; @@ -1072,7 +1046,6 @@ Expression::ENode *Expression::_parse_expression() { case Variant::OP_OR: priority = 13; break; - default: { _set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op)); return nullptr; diff --git a/core/math/quat.cpp b/core/math/quat.cpp index b6a017dd41..fc2d71c377 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -106,16 +106,16 @@ Vector3 Quat::get_euler_yxz() const { return m.get_euler_yxz(); } -void Quat::operator*=(const Quat &q) { - set(w * q.x + x * q.w + y * q.z - z * q.y, - w * q.y + y * q.w + z * q.x - x * q.z, - w * q.z + z * q.w + x * q.y - y * q.x, - w * q.w - x * q.x - y * q.y - z * q.z); +void Quat::operator*=(const Quat &p_q) { + set(w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y, + w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z, + w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x, + w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z); } -Quat Quat::operator*(const Quat &q) const { +Quat Quat::operator*(const Quat &p_q) const { Quat r = *this; - r *= q; + r *= p_q; return r; } @@ -146,29 +146,29 @@ Quat Quat::inverse() const { return Quat(-x, -y, -z, w); } -Quat Quat::slerp(const Quat &q, const real_t &t) const { +Quat Quat::slerp(const Quat &p_to, const real_t &p_weight) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!q.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized."); #endif Quat to1; real_t omega, cosom, sinom, scale0, scale1; // calc cosine - cosom = dot(q); + cosom = dot(p_to); // adjust signs (if necessary) if (cosom < 0.0) { cosom = -cosom; - to1.x = -q.x; - to1.y = -q.y; - to1.z = -q.z; - to1.w = -q.w; + to1.x = -p_to.x; + to1.y = -p_to.y; + to1.z = -p_to.z; + to1.w = -p_to.w; } else { - to1.x = q.x; - to1.y = q.y; - to1.z = q.z; - to1.w = q.w; + to1.x = p_to.x; + to1.y = p_to.y; + to1.z = p_to.z; + to1.w = p_to.w; } // calculate coefficients @@ -177,13 +177,13 @@ Quat Quat::slerp(const Quat &q, const real_t &t) const { // standard case (slerp) omega = Math::acos(cosom); sinom = Math::sin(omega); - scale0 = Math::sin((1.0 - t) * omega) / sinom; - scale1 = Math::sin(t * omega) / sinom; + scale0 = Math::sin((1.0 - p_weight) * omega) / sinom; + scale1 = Math::sin(p_weight * omega) / sinom; } else { // "from" and "to" quaternions are very close // ... so we can do a linear interpolation - scale0 = 1.0 - t; - scale1 = t; + scale0 = 1.0 - p_weight; + scale1 = p_weight; } // calculate final values return Quat( @@ -193,14 +193,14 @@ Quat Quat::slerp(const Quat &q, const real_t &t) const { scale0 * w + scale1 * to1.w); } -Quat Quat::slerpni(const Quat &q, const real_t &t) const { +Quat Quat::slerpni(const Quat &p_to, const real_t &p_weight) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!q.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized."); #endif const Quat &from = *this; - real_t dot = from.dot(q); + real_t dot = from.dot(p_to); if (Math::absf(dot) > 0.9999) { return from; @@ -208,24 +208,24 @@ Quat Quat::slerpni(const Quat &q, const real_t &t) const { real_t theta = Math::acos(dot), sinT = 1.0 / Math::sin(theta), - newFactor = Math::sin(t * theta) * sinT, - invFactor = Math::sin((1.0 - t) * theta) * sinT; + newFactor = Math::sin(p_weight * theta) * sinT, + invFactor = Math::sin((1.0 - p_weight) * theta) * sinT; - return Quat(invFactor * from.x + newFactor * q.x, - invFactor * from.y + newFactor * q.y, - invFactor * from.z + newFactor * q.z, - invFactor * from.w + newFactor * q.w); + return Quat(invFactor * from.x + newFactor * p_to.x, + invFactor * from.y + newFactor * p_to.y, + invFactor * from.z + newFactor * p_to.z, + invFactor * from.w + newFactor * p_to.w); } -Quat Quat::cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const { +Quat Quat::cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!q.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quat(), "The end quaternion must be normalized."); #endif //the only way to do slerp :| - real_t t2 = (1.0 - t) * t * 2; - Quat sp = this->slerp(q, t); - Quat sq = prep.slerpni(postq, t); + real_t t2 = (1.0 - p_weight) * p_weight * 2; + Quat sp = this->slerp(p_b, p_weight); + Quat sq = p_pre_a.slerpni(p_post_b, p_weight); return sp.slerpni(sq, t2); } diff --git a/core/math/quat.h b/core/math/quat.h index f8ab537d7b..bb980f7677 100644 --- a/core/math/quat.h +++ b/core/math/quat.h @@ -63,7 +63,7 @@ public: Quat normalized() const; bool is_normalized() const; Quat inverse() const; - _FORCE_INLINE_ real_t dot(const Quat &q) const; + _FORCE_INLINE_ real_t dot(const Quat &p_q) const; void set_euler_xyz(const Vector3 &p_euler); Vector3 get_euler_xyz() const; @@ -73,9 +73,9 @@ public: void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }; Vector3 get_euler() const { return get_euler_yxz(); }; - Quat slerp(const Quat &q, const real_t &t) const; - Quat slerpni(const Quat &q, const real_t &t) const; - Quat cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const; + Quat slerp(const Quat &p_to, const real_t &p_weight) const; + Quat slerpni(const Quat &p_to, const real_t &p_weight) const; + Quat cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const; void set_axis_angle(const Vector3 &axis, const real_t &angle); _FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { @@ -86,8 +86,8 @@ public: r_axis.z = z * r; } - void operator*=(const Quat &q); - Quat operator*(const Quat &q) const; + void operator*=(const Quat &p_q); + Quat operator*(const Quat &p_q) const; Quat operator*(const Vector3 &v) const { return Quat(w * v.x + y * v.z - z * v.y, @@ -109,8 +109,8 @@ public: return inverse().xform(v); } - _FORCE_INLINE_ void operator+=(const Quat &q); - _FORCE_INLINE_ void operator-=(const Quat &q); + _FORCE_INLINE_ void operator+=(const Quat &p_q); + _FORCE_INLINE_ void operator-=(const Quat &p_q); _FORCE_INLINE_ void operator*=(const real_t &s); _FORCE_INLINE_ void operator/=(const real_t &s); _FORCE_INLINE_ Quat operator+(const Quat &q2) const; @@ -141,18 +141,18 @@ public: Quat(const Vector3 &axis, const real_t &angle) { set_axis_angle(axis, angle); } Quat(const Vector3 &euler) { set_euler(euler); } - Quat(const Quat &q) : - x(q.x), - y(q.y), - z(q.z), - w(q.w) { + Quat(const Quat &p_q) : + x(p_q.x), + y(p_q.y), + z(p_q.z), + w(p_q.w) { } - Quat &operator=(const Quat &q) { - x = q.x; - y = q.y; - z = q.z; - w = q.w; + Quat &operator=(const Quat &p_q) { + x = p_q.x; + y = p_q.y; + z = p_q.z; + w = p_q.w; return *this; } @@ -178,26 +178,26 @@ public: } }; -real_t Quat::dot(const Quat &q) const { - return x * q.x + y * q.y + z * q.z + w * q.w; +real_t Quat::dot(const Quat &p_q) const { + return x * p_q.x + y * p_q.y + z * p_q.z + w * p_q.w; } real_t Quat::length_squared() const { return dot(*this); } -void Quat::operator+=(const Quat &q) { - x += q.x; - y += q.y; - z += q.z; - w += q.w; +void Quat::operator+=(const Quat &p_q) { + x += p_q.x; + y += p_q.y; + z += p_q.z; + w += p_q.w; } -void Quat::operator-=(const Quat &q) { - x -= q.x; - y -= q.y; - z -= q.z; - w -= q.w; +void Quat::operator-=(const Quat &p_q) { + x -= p_q.x; + y -= p_q.y; + z -= p_q.z; + w -= p_q.w; } void Quat::operator*=(const real_t &s) { diff --git a/core/math/random_number_generator.cpp b/core/math/random_number_generator.cpp index a124f63030..f045213fb9 100644 --- a/core/math/random_number_generator.cpp +++ b/core/math/random_number_generator.cpp @@ -34,6 +34,9 @@ void RandomNumberGenerator::_bind_methods() { ClassDB::bind_method(D_METHOD("set_seed", "seed"), &RandomNumberGenerator::set_seed); ClassDB::bind_method(D_METHOD("get_seed"), &RandomNumberGenerator::get_seed); + ClassDB::bind_method(D_METHOD("set_state", "state"), &RandomNumberGenerator::set_state); + ClassDB::bind_method(D_METHOD("get_state"), &RandomNumberGenerator::get_state); + ClassDB::bind_method(D_METHOD("randi"), &RandomNumberGenerator::randi); ClassDB::bind_method(D_METHOD("randf"), &RandomNumberGenerator::randf); ClassDB::bind_method(D_METHOD("randfn", "mean", "deviation"), &RandomNumberGenerator::randfn, DEFVAL(0.0), DEFVAL(1.0)); @@ -42,6 +45,8 @@ void RandomNumberGenerator::_bind_methods() { ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize); ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed"); - // Default value is non-deterministic, override it for doc generation purposes. + ADD_PROPERTY(PropertyInfo(Variant::INT, "state"), "set_state", "get_state"); + // Default values are non-deterministic, override for doc generation purposes. ADD_PROPERTY_DEFAULT("seed", 0); + ADD_PROPERTY_DEFAULT("state", 0); } diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h index 0d0ea17205..7728fd09c0 100644 --- a/core/math/random_number_generator.h +++ b/core/math/random_number_generator.h @@ -44,19 +44,17 @@ protected: public: _FORCE_INLINE_ void set_seed(uint64_t p_seed) { randbase.seed(p_seed); } - _FORCE_INLINE_ uint64_t get_seed() { return randbase.get_seed(); } + _FORCE_INLINE_ void set_state(uint64_t p_state) { randbase.set_state(p_state); } + _FORCE_INLINE_ uint64_t get_state() const { return randbase.get_state(); } + _FORCE_INLINE_ void randomize() { randbase.randomize(); } _FORCE_INLINE_ uint32_t randi() { return randbase.rand(); } - _FORCE_INLINE_ real_t randf() { return randbase.randf(); } - _FORCE_INLINE_ real_t randf_range(real_t p_from, real_t p_to) { return randbase.random(p_from, p_to); } - _FORCE_INLINE_ real_t randfn(real_t p_mean = 0.0, real_t p_deviation = 1.0) { return randbase.randfn(p_mean, p_deviation); } - _FORCE_INLINE_ int randi_range(int p_from, int p_to) { return randbase.random(p_from, p_to); } RandomNumberGenerator() {} diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h index fe6b1b5639..2e257cb5b7 100644 --- a/core/math/random_pcg.h +++ b/core/math/random_pcg.h @@ -61,7 +61,7 @@ static int __bsr_clz32(uint32_t x) { class RandomPCG { pcg32_random_t pcg; - uint64_t current_seed; // seed with this to get the same state + uint64_t current_seed; // The seed the current generator state started from. uint64_t current_inc; public: @@ -76,13 +76,14 @@ public: } _FORCE_INLINE_ uint64_t get_seed() { return current_seed; } + _FORCE_INLINE_ void set_state(uint64_t p_state) { pcg.state = p_state; } + _FORCE_INLINE_ uint64_t get_state() const { return pcg.state; } + void randomize(); _FORCE_INLINE_ uint32_t rand() { - current_seed = pcg.state; return pcg32_random_r(&pcg); } _FORCE_INLINE_ uint32_t rand(uint32_t bounds) { - current_seed = pcg.state; return pcg32_boundedrand_r(&pcg, bounds); } diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index 75e742a5f1..f9c2eeb57d 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -118,8 +118,8 @@ Vector2 Vector2::posmodv(const Vector2 &p_modv) const { return Vector2(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y)); } -Vector2 Vector2::project(const Vector2 &p_b) const { - return p_b * (dot(p_b) / p_b.length_squared()); +Vector2 Vector2::project(const Vector2 &p_to) const { + return p_to * (dot(p_to) / p_to.length_squared()); } Vector2 Vector2::snapped(const Vector2 &p_by) const { @@ -139,13 +139,13 @@ Vector2 Vector2::clamped(real_t p_len) const { return v; } -Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const { +Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const { Vector2 p0 = p_pre_a; Vector2 p1 = *this; Vector2 p2 = p_b; Vector2 p3 = p_post_b; - real_t t = p_t; + real_t t = p_weight; real_t t2 = t * t; real_t t3 = t2 * t; diff --git a/core/math/vector2.h b/core/math/vector2.h index 8cb63b2fb5..33f815a39c 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -77,21 +77,21 @@ struct Vector2 { real_t distance_squared_to(const Vector2 &p_vector2) const; real_t angle_to(const Vector2 &p_vector2) const; real_t angle_to_point(const Vector2 &p_vector2) const; - _FORCE_INLINE_ Vector2 direction_to(const Vector2 &p_b) const; + _FORCE_INLINE_ Vector2 direction_to(const Vector2 &p_to) const; real_t dot(const Vector2 &p_other) const; real_t cross(const Vector2 &p_other) const; Vector2 posmod(const real_t p_mod) const; Vector2 posmodv(const Vector2 &p_modv) const; - Vector2 project(const Vector2 &p_b) const; + Vector2 project(const Vector2 &p_to) const; Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const; Vector2 clamped(real_t p_len) const; - _FORCE_INLINE_ Vector2 lerp(const Vector2 &p_b, real_t p_t) const; - _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_b, real_t p_t) const; - Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const; + _FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, real_t p_weight) const; + Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const; Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const; Vector2 slide(const Vector2 &p_normal) const; @@ -230,25 +230,25 @@ _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { return x != p_vec2.x || y != p_vec2.y; } -Vector2 Vector2::lerp(const Vector2 &p_b, real_t p_t) const { +Vector2 Vector2::lerp(const Vector2 &p_to, real_t p_weight) const { Vector2 res = *this; - res.x += (p_t * (p_b.x - x)); - res.y += (p_t * (p_b.y - y)); + res.x += (p_weight * (p_to.x - x)); + res.y += (p_weight * (p_to.y - y)); return res; } -Vector2 Vector2::slerp(const Vector2 &p_b, real_t p_t) const { +Vector2 Vector2::slerp(const Vector2 &p_to, real_t p_weight) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(!is_normalized(), Vector2(), "The start Vector2 must be normalized."); #endif - real_t theta = angle_to(p_b); - return rotated(theta * p_t); + real_t theta = angle_to(p_to); + return rotated(theta * p_weight); } -Vector2 Vector2::direction_to(const Vector2 &p_b) const { - Vector2 ret(p_b.x - x, p_b.y - y); +Vector2 Vector2::direction_to(const Vector2 &p_to) const { + Vector2 ret(p_to.x - x, p_to.y - y); ret.normalize(); return ret; } diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index 568df48c62..09354d8e79 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -72,46 +72,13 @@ Vector3 Vector3::snapped(Vector3 p_val) const { return v; } -Vector3 Vector3::cubic_interpolaten(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_t) const { +Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const { Vector3 p0 = p_pre_a; Vector3 p1 = *this; Vector3 p2 = p_b; Vector3 p3 = p_post_b; - { - //normalize - - real_t ab = p0.distance_to(p1); - real_t bc = p1.distance_to(p2); - real_t cd = p2.distance_to(p3); - - if (ab > 0) { - p0 = p1 + (p0 - p1) * (bc / ab); - } - if (cd > 0) { - p3 = p2 + (p3 - p2) * (bc / cd); - } - } - - real_t t = p_t; - real_t t2 = t * t; - real_t t3 = t2 * t; - - Vector3 out; - out = 0.5 * ((p1 * 2.0) + - (-p0 + p2) * t + - (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + - (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); - return out; -} - -Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_t) const { - Vector3 p0 = p_pre_a; - Vector3 p1 = *this; - Vector3 p2 = p_b; - Vector3 p3 = p_post_b; - - real_t t = p_t; + real_t t = p_weight; real_t t2 = t * t; real_t t3 = t2 * t; diff --git a/core/math/vector3.h b/core/math/vector3.h index ae8b9376cf..5af84377fd 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -86,10 +86,9 @@ struct Vector3 { /* Static Methods between 2 vector3s */ - _FORCE_INLINE_ Vector3 lerp(const Vector3 &p_b, real_t p_t) const; - _FORCE_INLINE_ Vector3 slerp(const Vector3 &p_b, real_t p_t) const; - Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_t) const; - Vector3 cubic_interpolaten(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_t) const; + _FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, real_t p_weight) const; + Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const; Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const; _FORCE_INLINE_ Vector3 cross(const Vector3 &p_b) const; @@ -103,15 +102,15 @@ struct Vector3 { _FORCE_INLINE_ Vector3 ceil() const; _FORCE_INLINE_ Vector3 round() const; - _FORCE_INLINE_ real_t distance_to(const Vector3 &p_b) const; - _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_b) const; + _FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const; + _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const; _FORCE_INLINE_ Vector3 posmod(const real_t p_mod) const; _FORCE_INLINE_ Vector3 posmodv(const Vector3 &p_modv) const; - _FORCE_INLINE_ Vector3 project(const Vector3 &p_b) const; + _FORCE_INLINE_ Vector3 project(const Vector3 &p_to) const; - _FORCE_INLINE_ real_t angle_to(const Vector3 &p_b) const; - _FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_b) const; + _FORCE_INLINE_ real_t angle_to(const Vector3 &p_to) const; + _FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_to) const; _FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const; _FORCE_INLINE_ Vector3 bounce(const Vector3 &p_normal) const; @@ -195,24 +194,24 @@ Vector3 Vector3::round() const { return Vector3(Math::round(x), Math::round(y), Math::round(z)); } -Vector3 Vector3::lerp(const Vector3 &p_b, real_t p_t) const { +Vector3 Vector3::lerp(const Vector3 &p_to, real_t p_weight) const { return Vector3( - x + (p_t * (p_b.x - x)), - y + (p_t * (p_b.y - y)), - z + (p_t * (p_b.z - z))); + x + (p_weight * (p_to.x - x)), + y + (p_weight * (p_to.y - y)), + z + (p_weight * (p_to.z - z))); } -Vector3 Vector3::slerp(const Vector3 &p_b, real_t p_t) const { - real_t theta = angle_to(p_b); - return rotated(cross(p_b).normalized(), theta * p_t); +Vector3 Vector3::slerp(const Vector3 &p_to, real_t p_weight) const { + real_t theta = angle_to(p_to); + return rotated(cross(p_to).normalized(), theta * p_weight); } -real_t Vector3::distance_to(const Vector3 &p_b) const { - return (p_b - *this).length(); +real_t Vector3::distance_to(const Vector3 &p_to) const { + return (p_to - *this).length(); } -real_t Vector3::distance_squared_to(const Vector3 &p_b) const { - return (p_b - *this).length_squared(); +real_t Vector3::distance_squared_to(const Vector3 &p_to) const { + return (p_to - *this).length_squared(); } Vector3 Vector3::posmod(const real_t p_mod) const { @@ -223,16 +222,16 @@ Vector3 Vector3::posmodv(const Vector3 &p_modv) const { return Vector3(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z)); } -Vector3 Vector3::project(const Vector3 &p_b) const { - return p_b * (dot(p_b) / p_b.length_squared()); +Vector3 Vector3::project(const Vector3 &p_to) const { + return p_to * (dot(p_to) / p_to.length_squared()); } -real_t Vector3::angle_to(const Vector3 &p_b) const { - return Math::atan2(cross(p_b).length(), dot(p_b)); +real_t Vector3::angle_to(const Vector3 &p_to) const { + return Math::atan2(cross(p_to).length(), dot(p_to)); } -Vector3 Vector3::direction_to(const Vector3 &p_b) const { - Vector3 ret(p_b.x - x, p_b.y - y, p_b.z - z); +Vector3 Vector3::direction_to(const Vector3 &p_to) const { + Vector3 ret(p_to.x - x, p_to.y - y, p_to.z - z); ret.normalize(); return ret; } diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index dc28fa10de..f5171f60ec 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -243,8 +243,11 @@ HashMap<StringName, StringName> ClassDB::resource_base_extensions; HashMap<StringName, StringName> ClassDB::compat_classes; bool ClassDB::_is_parent_class(const StringName &p_class, const StringName &p_inherits) { - StringName inherits = p_class; + if (!classes.has(p_class)) { + return false; + } + StringName inherits = p_class; while (inherits.operator String().length()) { if (inherits == p_inherits) { return true; diff --git a/core/object/object.cpp b/core/object/object.cpp index a642647853..681e1188ff 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -823,10 +823,6 @@ void Object::property_list_changed_notify() { _change_notify(); } -void Object::cancel_delete() { - _predelete_ok = true; -} - void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) { //this function is not meant to be used in any of these ways ERR_FAIL_COND(p_script.is_null()); @@ -1266,10 +1262,6 @@ void Object::get_signals_connected_to_this(List<Connection> *p_connections) cons } } -Error Object::connect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds, uint32_t p_flags) { - return connect(p_signal, Callable(p_to_object, p_to_method), p_binds, p_flags); -} - Error Object::connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) { ERR_FAIL_COND_V(p_callable.is_null(), ERR_INVALID_PARAMETER); @@ -1331,10 +1323,6 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, co return OK; } -bool Object::is_connected_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const { - return is_connected(p_signal, Callable(p_to_object, p_to_method)); -} - bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const { ERR_FAIL_COND_V(p_callable.is_null(), false); const SignalData *s = signal_map.getptr(p_signal); @@ -1358,10 +1346,6 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable //return (E!=nullptr ); } -void Object::disconnect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) { - _disconnect(p_signal, Callable(p_to_object, p_to_method)); -} - void Object::disconnect(const StringName &p_signal, const Callable &p_callable) { _disconnect(p_signal, p_callable); } diff --git a/core/object/object.h b/core/object/object.h index 0bcfa42e3d..dc004f38a9 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -525,8 +525,6 @@ protected: static void get_valid_parents_static(List<String> *p_parents); static void _get_valid_parents_static(List<String> *p_parents); - void cancel_delete(); - virtual void _changed_callback(Object *p_changed, const char *p_prop); //Variant _call_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant()); @@ -697,10 +695,6 @@ public: int get_persistent_signal_connection_count() const; void get_signals_connected_to_this(List<Connection> *p_connections) const; - Error connect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); - void disconnect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method); - bool is_connected_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const; - Error connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); void disconnect(const StringName &p_signal, const Callable &p_callable); bool is_connected(const StringName &p_signal, const Callable &p_callable) const; diff --git a/core/object/script_language.h b/core/object/script_language.h index 72586780ae..f5d65cf42d 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -274,8 +274,6 @@ class ScriptCodeCompletionCache { static ScriptCodeCompletionCache *singleton; public: - virtual RES get_cached_resource(const String &p_path) = 0; - static ScriptCodeCompletionCache *get_singleton() { return singleton; } ScriptCodeCompletionCache(); @@ -316,7 +314,7 @@ public: virtual bool has_named_classes() const = 0; virtual bool supports_builtin_mode() const = 0; virtual bool supports_documentation() const { return false; } - virtual bool can_inherit_from_file() { return false; } + virtual bool can_inherit_from_file() const { return false; } virtual int find_function(const String &p_function, const String &p_code) const = 0; virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const = 0; virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; } diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index b962f61e1f..aa95f06cff 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -349,7 +349,7 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const { strings.push_back(current); current = String(); } else if (c == '"') { - if (l[i + 1] == '"') { + if (l[i + 1] == '"' && in_quote) { s[0] = '"'; current += s; i++; diff --git a/core/os/os.cpp b/core/os/os.cpp index 552bf043bf..9400565484 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -505,12 +505,8 @@ void OS::add_frame_delay(bool p_can_draw) { } OS::OS() { - void *volatile stack_bottom; - singleton = this; - _stack_bottom = (void *)(&stack_bottom); - Vector<Logger *> loggers; loggers.push_back(memnew(StdLogger)); _set_logger(memnew(CompositeLogger(loggers))); diff --git a/core/os/os.h b/core/os/os.h index 40104b479b..3c79d7bb87 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -62,8 +62,6 @@ class OS { char *last_error; - void *_stack_bottom; - CompositeLogger *_logger = nullptr; bool restart_on_exit = false; diff --git a/core/string/node_path.cpp b/core/string/node_path.cpp index 4d152d9258..a63dde5b41 100644 --- a/core/string/node_path.cpp +++ b/core/string/node_path.cpp @@ -288,7 +288,7 @@ void NodePath::simplify() { if (data->path[i].operator String() == ".") { data->path.remove(i); i--; - } else if (data->path[i].operator String() == ".." && i > 0 && data->path[i - 1].operator String() != "." && data->path[i - 1].operator String() != "..") { + } else if (i > 0 && data->path[i].operator String() == ".." && data->path[i - 1].operator String() != "." && data->path[i - 1].operator String() != "..") { //remove both data->path.remove(i - 1); data->path.remove(i - 1); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 214c424013..d588c83809 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -987,9 +987,9 @@ static void _register_variant_builtin_methods() { bind_method(Vector2, posmod, sarray("mod"), varray()); bind_method(Vector2, posmodv, sarray("modv"), varray()); bind_method(Vector2, project, sarray("b"), varray()); - bind_method(Vector2, lerp, sarray("with", "t"), varray()); - bind_method(Vector2, slerp, sarray("with", "t"), varray()); - bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "t"), varray()); + bind_method(Vector2, lerp, sarray("to", "weight"), varray()); + bind_method(Vector2, slerp, sarray("to", "weight"), varray()); + bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray()); bind_method(Vector2, move_toward, sarray("to", "delta"), varray()); bind_method(Vector2, rotated, sarray("phi"), varray()); bind_method(Vector2, tangent, sarray(), varray()); @@ -1060,9 +1060,9 @@ static void _register_variant_builtin_methods() { bind_method(Vector3, inverse, sarray(), varray()); bind_method(Vector3, snapped, sarray("by"), varray()); bind_method(Vector3, rotated, sarray("by_axis", "phi"), varray()); - bind_method(Vector3, lerp, sarray("b", "t"), varray()); - bind_method(Vector3, slerp, sarray("b", "t"), varray()); - bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "t"), varray()); + bind_method(Vector3, lerp, sarray("to", "weight"), varray()); + bind_method(Vector3, slerp, sarray("to", "weight"), varray()); + bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray()); bind_method(Vector3, move_toward, sarray("to", "delta"), varray()); bind_method(Vector3, dot, sarray("with"), varray()); bind_method(Vector3, cross, sarray("with"), varray()); @@ -1109,9 +1109,9 @@ static void _register_variant_builtin_methods() { bind_method(Quat, is_equal_approx, sarray("to"), varray()); bind_method(Quat, inverse, sarray(), varray()); bind_method(Quat, dot, sarray("with"), varray()); - bind_method(Quat, slerp, sarray("b", "t"), varray()); - bind_method(Quat, slerpni, sarray("b", "t"), varray()); - bind_method(Quat, cubic_slerp, sarray("b", "pre_a", "post_b", "t"), varray()); + bind_method(Quat, slerp, sarray("to", "weight"), varray()); + bind_method(Quat, slerpni, sarray("to", "weight"), varray()); + bind_method(Quat, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray()); bind_method(Quat, get_euler, sarray(), varray()); // FIXME: Quat is atomic, this should be done via construcror @@ -1128,7 +1128,7 @@ static void _register_variant_builtin_methods() { bind_method(Color, to_rgba64, sarray(), varray()); bind_method(Color, inverted, sarray(), varray()); - bind_method(Color, lerp, sarray("b", "t"), varray()); + bind_method(Color, lerp, sarray("to", "weight"), varray()); bind_method(Color, lightened, sarray("amount"), varray()); bind_method(Color, darkened, sarray("amount"), varray()); bind_method(Color, to_html, sarray("with_alpha"), varray(true)); @@ -1195,7 +1195,7 @@ static void _register_variant_builtin_methods() { bind_method(Transform2D, translated, sarray("offset"), varray()); bind_method(Transform2D, basis_xform, sarray("v"), varray()); bind_method(Transform2D, basis_xform_inv, sarray("v"), varray()); - bind_method(Transform2D, interpolate_with, sarray("xform", "t"), varray()); + bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray()); bind_method(Transform2D, is_equal_approx, sarray("xform"), varray()); /* Basis */ @@ -1212,7 +1212,7 @@ static void _register_variant_builtin_methods() { bind_method(Basis, tdoty, sarray("with"), varray()); bind_method(Basis, tdotz, sarray("with"), varray()); bind_method(Basis, get_orthogonal_index, sarray(), varray()); - bind_method(Basis, slerp, sarray("b", "t"), varray()); + bind_method(Basis, slerp, sarray("to", "weight"), varray()); bind_method(Basis, is_equal_approx, sarray("b"), varray()); bind_method(Basis, get_rotation_quat, sarray(), varray()); diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml index 92a8465762..2f8042bb1e 100644 --- a/doc/classes/Area3D.xml +++ b/doc/classes/Area3D.xml @@ -92,7 +92,7 @@ The rate at which objects stop spinning in this area. Represents the angular velocity lost per second. See [member ProjectSettings.physics/3d/default_angular_damp] for more details about damping. </member> - <member name="audio_bus_name" type="StringName" setter="set_audio_bus" getter="get_audio_bus" default="@"Master""> + <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="@"Master""> The name of the area's audio bus. </member> <member name="audio_bus_override" type="bool" setter="set_audio_bus_override" getter="is_overriding_audio_bus" default="false"> diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml index 3f9083ed6e..ef33d7ea77 100644 --- a/doc/classes/ArrayMesh.xml +++ b/doc/classes/ArrayMesh.xml @@ -209,13 +209,19 @@ </method> </methods> <members> - <member name="blend_shape_mode" type="int" setter="set_blend_shape_mode" getter="get_blend_shape_mode" enum="Mesh.BlendShapeMode" default="1"> - Sets the blend shape mode to one of [enum Mesh.BlendShapeMode]. + <member name="blend_shape_mode" type="int" setter="set_blend_shape_mode" getter="get_blend_shape_mode" enum="ArrayMesh.BlendShapeMode" default="1"> + Sets the blend shape mode to one of [enum ArrayMesh.BlendShapeMode]. </member> <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB( 0, 0, 0, 0, 0, 0 )"> Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices. </member> </members> <constants> + <constant name="BLEND_SHAPE_MODE_NORMALIZED" value="0" enum="BlendShapeMode"> + Blend shapes are normalized. + </constant> + <constant name="BLEND_SHAPE_MODE_RELATIVE" value="1" enum="BlendShapeMode"> + Blend shapes are relative to base weight. + </constant> </constants> </class> diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index 877d3ca85a..4c9cd5702e 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -201,9 +201,9 @@ <method name="slerp"> <return type="Basis"> </return> - <argument index="0" name="b" type="Basis"> + <argument index="0" name="to" type="Basis"> </argument> - <argument index="1" name="t" type="float"> + <argument index="1" name="weight" type="float"> </argument> <description> Assuming that the matrix is a proper rotation matrix, slerp performs a spherical-linear interpolation with another rotation matrix. diff --git a/doc/classes/CubeMesh.xml b/doc/classes/BoxMesh.xml index 1f64b4a21f..88d22ac899 100644 --- a/doc/classes/CubeMesh.xml +++ b/doc/classes/BoxMesh.xml @@ -1,11 +1,11 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CubeMesh" inherits="PrimitiveMesh" version="4.0"> +<class name="BoxMesh" inherits="PrimitiveMesh" version="4.0"> <brief_description> - Generate an axis-aligned cuboid [PrimitiveMesh]. + Generate an axis-aligned box [PrimitiveMesh]. </brief_description> <description> - Generate an axis-aligned cuboid [PrimitiveMesh]. - The cube's UV layout is arranged in a 3×2 layout that allows texturing each face individually. To apply the same texture on all faces, change the material's UV property to [code]Vector3(3, 2, 1)[/code]. + Generate an axis-aligned box [PrimitiveMesh]. + The box's UV layout is arranged in a 3×2 layout that allows texturing each face individually. To apply the same texture on all faces, change the material's UV property to [code]Vector3(3, 2, 1)[/code]. </description> <tutorials> </tutorials> @@ -13,7 +13,7 @@ </methods> <members> <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3( 2, 2, 2 )"> - Size of the cuboid mesh. + Size of the box mesh. </member> <member name="subdivide_depth" type="int" setter="set_subdivide_depth" getter="get_subdivide_depth" default="0"> Number of extra edge loops inserted along the Z axis. diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml index fcf2feb3b9..aa9f99a31e 100644 --- a/doc/classes/CPUParticles2D.xml +++ b/doc/classes/CPUParticles2D.xml @@ -50,10 +50,10 @@ <method name="get_particle_flag" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="flag" type="int" enum="CPUParticles2D.Flags"> + <argument index="0" name="particle_flag" type="int" enum="CPUParticles2D.ParticleFlags"> </argument> <description> - Returns the enabled state of the given flag (see [enum Flags] for options). + Returns the enabled state of the given flag (see [enum ParticleFlags] for options). </description> </method> <method name="restart"> @@ -99,12 +99,12 @@ <method name="set_particle_flag"> <return type="void"> </return> - <argument index="0" name="flag" type="int" enum="CPUParticles2D.Flags"> + <argument index="0" name="particle_flag" type="int" enum="CPUParticles2D.ParticleFlags"> </argument> <argument index="1" name="enable" type="bool"> </argument> <description> - Enables or disables the given flag (see [enum Flags] for options). + Enables or disables the given flag (see [enum ParticleFlags] for options). </description> </method> </methods> @@ -196,9 +196,6 @@ <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0"> The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself. </member> - <member name="flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> - Align Y axis of particle with the direction of its velocity. - </member> <member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true"> If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect. </member> @@ -250,6 +247,9 @@ <member name="orbit_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0"> Orbital velocity randomness ratio. </member> + <member name="particle_flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> + Align Y axis of particle with the direction of its velocity. + </member> <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0"> Particle system starts as if it had already run for this many seconds. </member> @@ -339,17 +339,17 @@ <constant name="PARAM_MAX" value="12" enum="Parameter"> Represents the size of the [enum Parameter] enum. </constant> - <constant name="FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="Flags"> - Use with [method set_particle_flag] to set [member flag_align_y]. + <constant name="PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="ParticleFlags"> + Use with [method set_particle_flag] to set [member particle_flag_align_y]. </constant> - <constant name="FLAG_ROTATE_Y" value="1" enum="Flags"> + <constant name="PARTICLE_FLAG_ROTATE_Y" value="1" enum="ParticleFlags"> Present for consistency with 3D particle nodes, not used in 2D. </constant> - <constant name="FLAG_DISABLE_Z" value="2" enum="Flags"> + <constant name="PARTICLE_FLAG_DISABLE_Z" value="2" enum="ParticleFlags"> Present for consistency with 3D particle nodes, not used in 2D. </constant> - <constant name="FLAG_MAX" value="3" enum="Flags"> - Represents the size of the [enum Flags] enum. + <constant name="PARTICLE_FLAG_MAX" value="3" enum="ParticleFlags"> + Represents the size of the [enum ParticleFlags] enum. </constant> <constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape"> All particles will be emitted from a single point. diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml index 07da066bd9..0512efa8c2 100644 --- a/doc/classes/CPUParticles3D.xml +++ b/doc/classes/CPUParticles3D.xml @@ -49,10 +49,10 @@ <method name="get_particle_flag" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="flag" type="int" enum="CPUParticles3D.Flags"> + <argument index="0" name="particle_flag" type="int" enum="CPUParticles3D.ParticleFlags"> </argument> <description> - Returns the enabled state of the given flag (see [enum Flags] for options). + Returns the enabled state of the given particle flag (see [enum ParticleFlags] for options). </description> </method> <method name="restart"> @@ -98,12 +98,12 @@ <method name="set_particle_flag"> <return type="void"> </return> - <argument index="0" name="flag" type="int" enum="CPUParticles3D.Flags"> + <argument index="0" name="particle_flag" type="int" enum="CPUParticles3D.ParticleFlags"> </argument> <argument index="1" name="enable" type="bool"> </argument> <description> - Enables or disables the given flag (see [enum Flags] for options). + Enables or disables the given particle flag (see [enum ParticleFlags] for options). </description> </method> </methods> @@ -195,15 +195,6 @@ <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0"> The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the particle system itself. </member> - <member name="flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> - Align Y axis of particle with the direction of its velocity. - </member> - <member name="flag_disable_z" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> - If [code]true[/code], particles will not move on the z axis. - </member> - <member name="flag_rotate_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> - If [code]true[/code], particles rotate around Y axis by [member angle]. - </member> <member name="flatness" type="float" setter="set_flatness" getter="get_flatness" default="0.0"> Amount of [member spread] in Y/Z plane. A value of [code]1[/code] restricts particles to X/Z plane. </member> @@ -254,7 +245,7 @@ </member> <member name="orbit_velocity" type="float" setter="set_param" getter="get_param"> Orbital velocity applied to each particle. Makes the particles circle around origin in the local XY plane. Specified in number of full rotations around origin per second. - This property is only available when [member flag_disable_z] is [code]true[/code]. + This property is only available when [member particle_flag_disable_z] is [code]true[/code]. </member> <member name="orbit_velocity_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> Each particle's orbital velocity will vary along this [Curve]. @@ -262,6 +253,15 @@ <member name="orbit_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> Orbital velocity randomness ratio. </member> + <member name="particle_flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> + Align Y axis of particle with the direction of its velocity. + </member> + <member name="particle_flag_disable_z" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> + If [code]true[/code], particles will not move on the Z axis. + </member> + <member name="particle_flag_rotate_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> + If [code]true[/code], particles rotate around Y axis by [member angle]. + </member> <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0"> Particle system starts as if it had already run for this many seconds. </member> @@ -351,17 +351,17 @@ <constant name="PARAM_MAX" value="12" enum="Parameter"> Represents the size of the [enum Parameter] enum. </constant> - <constant name="FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="Flags"> - Use with [method set_particle_flag] to set [member flag_align_y]. + <constant name="PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="ParticleFlags"> + Use with [method set_particle_flag] to set [member particle_flag_align_y]. </constant> - <constant name="FLAG_ROTATE_Y" value="1" enum="Flags"> - Use with [method set_particle_flag] to set [member flag_rotate_y]. + <constant name="PARTICLE_FLAG_ROTATE_Y" value="1" enum="ParticleFlags"> + Use with [method set_particle_flag] to set [member particle_flag_rotate_y]. </constant> - <constant name="FLAG_DISABLE_Z" value="2" enum="Flags"> - Use with [method set_particle_flag] to set [member flag_disable_z]. + <constant name="PARTICLE_FLAG_DISABLE_Z" value="2" enum="ParticleFlags"> + Use with [method set_particle_flag] to set [member particle_flag_disable_z]. </constant> - <constant name="FLAG_MAX" value="3" enum="Flags"> - Represents the size of the [enum Flags] enum. + <constant name="PARTICLE_FLAG_MAX" value="3" enum="ParticleFlags"> + Represents the size of the [enum ParticleFlags] enum. </constant> <constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape"> All particles will be emitted from a single point. diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index bd648c6de0..fcdd072c80 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -608,7 +608,7 @@ Emitted when the [CanvasItem] must redraw. This can only be connected realtime, as deferred will not allow drawing. </description> </signal> - <signal name="hide"> + <signal name="hidden"> <description> Emitted when becoming hidden. </description> diff --git a/doc/classes/CharFXTransform.xml b/doc/classes/CharFXTransform.xml index d1759adf30..b4cb110337 100644 --- a/doc/classes/CharFXTransform.xml +++ b/doc/classes/CharFXTransform.xml @@ -13,24 +13,6 @@ <methods> </methods> <members> - <member name="absolute_index" type="int" setter="set_absolute_index" getter="get_absolute_index" default="0"> - The index of the current character (starting from 0). Setting this property won't affect drawing. - </member> - <member name="character" type="int" setter="set_character" getter="get_character" default="0"> - The Unicode codepoint the character will use. This only affects non-whitespace characters. [method @GDScript.ord] can be useful here. For example, the following will replace all characters with asterisks: - [codeblocks] - [gdscript] - # `char_fx` is the CharFXTransform parameter from `_process_custom_fx()`. - # See the RichTextEffect documentation for details. - char_fx.character = ord("*") - [/gdscript] - [csharp] - // `char_fx` is the CharFXTransform parameter from `_process_custom_fx()`. - // See the RichTextEffect documentation for details. - charFx.Character = char.GetNumericValue('*'); - [/csharp] - [/codeblocks] - </member> <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 0, 0, 0, 1 )"> The color the character will be drawn with. </member> @@ -45,11 +27,20 @@ {"foo": "hello", "bar": true, "baz": 42, "color": Color(1, 1, 1, 1)} [/codeblock] </member> + <member name="font" type="RID" setter="set_font" getter="get_font"> + Font resource used to render glyph. + </member> + <member name="glyph_index" type="int" setter="set_glyph_index" getter="get_glyph_index" default="0"> + Font specific glyph index. + </member> <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )"> The position offset the character will be drawn with (in pixels). </member> - <member name="relative_index" type="int" setter="set_relative_index" getter="get_relative_index" default="0"> - The index of the current character (starting from 0). Setting this property won't affect drawing. + <member name="outline" type="bool" setter="set_outline" getter="is_outline" default="false"> + If [code]ture[/code], FX transform is called for outline drawing. Setting this property won't affect drawing. + </member> + <member name="range" type="Vector2i" setter="set_range" getter="get_range" default="Vector2i( 0, 0 )"> + Absolute character range in the string, corresponding to the glyph. Setting this property won't affect drawing. </member> <member name="visible" type="bool" setter="set_visibility" getter="is_visible" default="true"> If [code]true[/code], the character will be drawn. If [code]false[/code], the character will be hidden. Characters around hidden characters will reflow to take the space of hidden characters. If this is not desired, set their [member color] to [code]Color(1, 1, 1, 0)[/code] instead. diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index 89c5e355ec..755fd7eea2 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -164,9 +164,9 @@ <method name="lerp"> <return type="Color"> </return> - <argument index="0" name="b" type="Color"> + <argument index="0" name="to" type="Color"> </argument> - <argument index="1" name="t" type="float"> + <argument index="1" name="weight" type="float"> </argument> <description> Returns the linear interpolation with another color. The interpolation factor [code]t[/code] is between 0 and 1. diff --git a/doc/classes/FontData.xml b/doc/classes/FontData.xml index cee424394a..e2c35f9ce7 100644 --- a/doc/classes/FontData.xml +++ b/doc/classes/FontData.xml @@ -179,6 +179,23 @@ Returns underline thickness in pixels. </description> </method> + <method name="get_variation" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="tag" type="String"> + </argument> + <description> + Returns variation coordinate [code]tag[/code]. + </description> + </method> + <method name="get_variation_list" qualifiers="const"> + <return type="Dictionary"> + </return> + <description> + Returns list of supported [url=https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg]variation coordinates[/url], each coordinate is returned as [code]tag: Vector3i(min_value,max_value,default_value)[/code]. + Font variations allow for continuous change of glyph characteristics along some given design axis, such as weight, width or slant. + </description> + </method> <method name="has_char" qualifiers="const"> <return type="bool"> </return> @@ -279,6 +296,17 @@ Adds override for [method is_script_supported]. </description> </method> + <method name="set_variation"> + <return type="void"> + </return> + <argument index="0" name="tag" type="String"> + </argument> + <argument index="1" name="value" type="float"> + </argument> + <description> + Sets variation coordinate [code]tag[/code]. + </description> + </method> </methods> <members> <member name="antialiased" type="bool" setter="set_antialiased" getter="get_antialiased" default="false"> diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml index 4ff54d15ce..2c0d9b54d1 100644 --- a/doc/classes/Geometry2D.xml +++ b/doc/classes/Geometry2D.xml @@ -91,7 +91,7 @@ <argument index="3" name="q2" type="Vector2"> </argument> <description> - Given the two 2D segments ([code]p1[/code], [code]p2[/code]) and ([code]q1[/code], [code]q2[/code]), finds those two points on the two segments that are closest to each other. Returns a [PackedVector2Array] that contains this point on ([code]p1[/code], [code]p2[/code]) as well the accompanying point on ([code]q1[/code], [code]q2[/code]). + Given the two 2D segments ([code]p1[/code], [code]q1[/code]) and ([code]p2[/code], [code]q2[/code]), finds those two points on the two segments that are closest to each other. Returns a [PackedVector2Array] that contains this point on ([code]p1[/code], [code]q1[/code]) as well the accompanying point on ([code]p2[/code], [code]q2[/code]). </description> </method> <method name="intersect_polygons"> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index b4325e822c..71db1e5106 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -636,18 +636,19 @@ <constant name="FORMAT_BPTC_RGBFU" value="24" enum="Format"> Texture format that uses [url=https://www.khronos.org/opengl/wiki/BPTC_Texture_Compression]BPTC[/url] compression with unsigned floating-point RGB components. </constant> - <constant name="FORMAT_PVRTC2" value="25" enum="Format"> + <constant name="FORMAT_PVRTC1_2" value="25" enum="Format"> Texture format used on PowerVR-supported mobile platforms, uses 2-bit color depth with no alpha. More information can be found [url=https://en.wikipedia.org/wiki/PVRTC]here[/url]. [b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space conversion is performed. </constant> - <constant name="FORMAT_PVRTC2A" value="26" enum="Format"> - Same as [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC2[/url], but with an alpha component. + <constant name="FORMAT_PVRTC1_2A" value="26" enum="Format"> + Same as [constant FORMAT_PVRTC1_2], but with an alpha component. </constant> - <constant name="FORMAT_PVRTC4" value="27" enum="Format"> - Similar to [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC2[/url], but with 4-bit color depth and no alpha. + <constant name="FORMAT_PVRTC1_4" value="27" enum="Format"> + Texture format used on PowerVR-supported mobile platforms, uses 4-bit color depth with no alpha. More information can be found [url=https://en.wikipedia.org/wiki/PVRTC]here[/url]. + [b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space conversion is performed. </constant> - <constant name="FORMAT_PVRTC4A" value="28" enum="Format"> - Same as [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC4[/url], but with an alpha component. + <constant name="FORMAT_PVRTC1_4A" value="28" enum="Format"> + Same as [constant FORMAT_PVRTC1_4], but with an alpha component. </constant> <constant name="FORMAT_ETC" value="29" enum="Format"> [url=https://en.wikipedia.org/wiki/Ericsson_Texture_Compression#ETC1]Ericsson Texture Compression format 1[/url], also referred to as "ETC1", and is part of the OpenGL ES graphics standard. This format cannot store an alpha channel. @@ -714,18 +715,18 @@ <constant name="COMPRESS_S3TC" value="0" enum="CompressMode"> Use S3TC compression. </constant> - <constant name="COMPRESS_PVRTC2" value="1" enum="CompressMode"> - Use PVRTC2 compression. - </constant> - <constant name="COMPRESS_PVRTC4" value="2" enum="CompressMode"> - Use PVRTC4 compression. + <constant name="COMPRESS_PVRTC1_4" value="1" enum="CompressMode"> + Use PVRTC1 4-bpp compression. </constant> - <constant name="COMPRESS_ETC" value="3" enum="CompressMode"> + <constant name="COMPRESS_ETC" value="2" enum="CompressMode"> Use ETC compression. </constant> - <constant name="COMPRESS_ETC2" value="4" enum="CompressMode"> + <constant name="COMPRESS_ETC2" value="3" enum="CompressMode"> Use ETC2 compression. </constant> + <constant name="COMPRESS_BPTC" value="4" enum="CompressMode"> + Use BPTC compression. + </constant> <constant name="USED_CHANNELS_L" value="0" enum="UsedChannels"> </constant> <constant name="USED_CHANNELS_LA" value="1" enum="UsedChannels"> diff --git a/doc/classes/LightOccluder2D.xml b/doc/classes/LightOccluder2D.xml index 45925dee96..550daf9225 100644 --- a/doc/classes/LightOccluder2D.xml +++ b/doc/classes/LightOccluder2D.xml @@ -12,12 +12,12 @@ <methods> </methods> <members> - <member name="light_mask" type="int" setter="set_occluder_light_mask" getter="get_occluder_light_mask" default="1"> - The LightOccluder2D's light mask. The LightOccluder2D will cast shadows only from Light2D(s) that have the same light mask(s). - </member> <member name="occluder" type="OccluderPolygon2D" setter="set_occluder_polygon" getter="get_occluder_polygon"> The [OccluderPolygon2D] used to compute the shadow. </member> + <member name="occluder_light_mask" type="int" setter="set_occluder_light_mask" getter="get_occluder_light_mask" default="1"> + The LightOccluder2D's occluder light mask. The LightOccluder2D will cast shadows only from Light2D(s) that have the same light mask(s). + </member> <member name="sdf_collision" type="bool" setter="set_as_sdf_collision" getter="is_set_as_sdf_collision" default="true"> </member> </members> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index e6643ef578..dff4b4f7ab 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -126,29 +126,23 @@ <constant name="PRIMITIVE_TRIANGLE_STRIP" value="4" enum="PrimitiveType"> Render array as triangle strips. </constant> - <constant name="BLEND_SHAPE_MODE_NORMALIZED" value="0" enum="BlendShapeMode"> - Blend shapes are normalized. - </constant> - <constant name="BLEND_SHAPE_MODE_RELATIVE" value="1" enum="BlendShapeMode"> - Blend shapes are relative to base weight. - </constant> <constant name="ARRAY_VERTEX" value="0" enum="ArrayType"> - Array of vertices. + [PackedVector3Array], [PackedVector2Array], or [Array] of vertex positions. </constant> <constant name="ARRAY_NORMAL" value="1" enum="ArrayType"> - Array of normals. + [PackedVector3Array] of vertex normals. </constant> <constant name="ARRAY_TANGENT" value="2" enum="ArrayType"> - Array of tangents as an array of floats, 4 floats per tangent. + [PackedFloat32Array] of vertex tangents. Each element in groups of 4 floats, first 3 floats determine the tangent, and the last the binormal direction as -1 or 1. </constant> <constant name="ARRAY_COLOR" value="3" enum="ArrayType"> - Array of colors. + [PackedColorArray] of vertex colors. </constant> <constant name="ARRAY_TEX_UV" value="4" enum="ArrayType"> - Array of UV coordinates. + [PackedVector2Array] for UV coordinates. </constant> <constant name="ARRAY_TEX_UV2" value="5" enum="ArrayType"> - Array of second set of UV coordinates. + [PackedVector2Array] for second UV coordinates. </constant> <constant name="ARRAY_CUSTOM0" value="6" enum="ArrayType"> </constant> @@ -159,13 +153,14 @@ <constant name="ARRAY_CUSTOM3" value="9" enum="ArrayType"> </constant> <constant name="ARRAY_BONES" value="10" enum="ArrayType"> - Array of bone data. + [PackedFloat32Array] or [PackedInt32Array] of bone indices. Each element is a group of 4 numbers. </constant> <constant name="ARRAY_WEIGHTS" value="11" enum="ArrayType"> - Array of weights. + [PackedFloat32Array] of bone weights. Each element in groups of 4 floats. </constant> <constant name="ARRAY_INDEX" value="12" enum="ArrayType"> - Array of indices. + [PackedInt32Array] of integers used as indices referencing vertices, colors, normals, tangents, and textures. All of those arrays must have the same number of elements as the vertex array. No index can be beyond the vertex array size. When this index array is present, it puts the function into "index mode," where the index selects the *i*'th vertex, normal, tangent, color, UV, etc. This means if you want to have different normals or colors along an edge, you have to duplicate the vertices. + For triangles, the index array is interpreted as triples, referring to the vertices of each triangle. For lines, the index array is in pairs indicating the start and end of each line. </constant> <constant name="ARRAY_MAX" value="13" enum="ArrayType"> Represents the size of the [enum ArrayType] enum. @@ -187,6 +182,7 @@ <constant name="ARRAY_CUSTOM_RGBA_FLOAT" value="7" enum="ArrayCustomFormat"> </constant> <constant name="ARRAY_CUSTOM_MAX" value="8" enum="ArrayCustomFormat"> + Represents the size of the [enum ArrayCustomFormat] enum. </constant> <constant name="ARRAY_FORMAT_VERTEX" value="1" enum="ArrayFormat"> Mesh array contains vertices. All meshes require a vertex array so this should always be present. @@ -223,7 +219,7 @@ <constant name="ARRAY_FORMAT_INDEX" value="4096" enum="ArrayFormat"> Mesh array uses indices. </constant> - <constant name="ARRAY_FORMAT_BLEND_SHAPE_MASK" value="-8185" enum="ArrayFormat"> + <constant name="ARRAY_FORMAT_BLEND_SHAPE_MASK" value="2147475463" enum="ArrayFormat"> </constant> <constant name="ARRAY_FORMAT_CUSTOM_BASE" value="13" enum="ArrayFormat"> </constant> diff --git a/doc/classes/MeshDataTool.xml b/doc/classes/MeshDataTool.xml index d4157dd4c9..db7a3187f0 100644 --- a/doc/classes/MeshDataTool.xml +++ b/doc/classes/MeshDataTool.xml @@ -10,7 +10,7 @@ [codeblocks] [gdscript] var mesh = ArrayMesh.new() - mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, CubeMesh.new().get_mesh_arrays()) + mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, BoxMesh.new().get_mesh_arrays()) var mdt = MeshDataTool.new() mdt.create_from_surface(mesh, 0) for i in range(mdt.get_vertex_count()): @@ -27,7 +27,7 @@ [/gdscript] [csharp] var mesh = new ArrayMesh(); - mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, new CubeMesh().GetMeshArrays()); + mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, new BoxMesh().GetMeshArrays()); var mdt = new MeshDataTool(); mdt.CreateFromSurface(mesh, 0); for (var i = 0; i < mdt.GetVertexCount(); i++) diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 1d80695798..ec47d455a9 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -233,7 +233,12 @@ <return type="String"> </return> <description> - Returns the host OS locale. + Returns the host OS locale as a string of the form [code]language_Script_COUNTRY_VARIANT@extra[/code]. + [code]language[/code] - 2 or 3 letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case. + [code]Script[/code] - optional, 4 letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case. + [code]COUNTRY[/code] - optional, 2 or 3 letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case. + [code]VARIANT[/code] - optional, language variant, region and sort order. Variant can have any number of underscored key words. + [code]extra[/code] - optional, semicolon separated list of additional key words. Currency, calendar, sort order and numbering system information. </description> </method> <method name="get_model_name" qualifiers="const"> diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml index 77df6245e9..85058cb9d4 100644 --- a/doc/classes/ParticlesMaterial.xml +++ b/doc/classes/ParticlesMaterial.xml @@ -11,15 +11,6 @@ <tutorials> </tutorials> <methods> - <method name="get_flag" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="flag" type="int" enum="ParticlesMaterial.Flags"> - </argument> - <description> - Returns [code]true[/code] if the specified flag is enabled. - </description> - </method> <method name="get_param" qualifiers="const"> <return type="float"> </return> @@ -47,15 +38,13 @@ Returns the [Texture2D] used by the specified parameter. </description> </method> - <method name="set_flag"> - <return type="void"> + <method name="get_particle_flag" qualifiers="const"> + <return type="bool"> </return> - <argument index="0" name="flag" type="int" enum="ParticlesMaterial.Flags"> - </argument> - <argument index="1" name="enable" type="bool"> + <argument index="0" name="particle_flag" type="int" enum="ParticlesMaterial.ParticleFlags"> </argument> <description> - If [code]true[/code], enables the specified flag. See [enum Flags] for options. + Returns [code]true[/code] if the specified particle flag is enabled. See [enum ParticleFlags] for options. </description> </method> <method name="set_param"> @@ -91,11 +80,22 @@ Sets the [Texture2D] for the specified [enum Parameter]. </description> </method> + <method name="set_particle_flag"> + <return type="void"> + </return> + <argument index="0" name="particle_flag" type="int" enum="ParticlesMaterial.ParticleFlags"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <description> + If [code]true[/code], enables the specified particle flag. See [enum ParticleFlags] for options. + </description> + </method> </methods> <members> <member name="angle" type="float" setter="set_param" getter="get_param" default="0.0"> Initial rotation applied to each particle, in degrees. - Only applied when [member flag_disable_z] or [member flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. + Only applied when [member particle_flag_disable_z] or [member particle_flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. </member> <member name="angle_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's rotation will be animated along this [CurveTexture]. @@ -105,7 +105,7 @@ </member> <member name="angular_velocity" type="float" setter="set_param" getter="get_param" default="0.0"> Initial angular velocity applied to each particle. Sets the speed of rotation of the particle. - Only applied when [member flag_disable_z] or [member flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. + Only applied when [member particle_flag_disable_z] or [member particle_flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. </member> <member name="angular_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's angular velocity will vary along this [CurveTexture]. @@ -180,15 +180,6 @@ <member name="emission_sphere_radius" type="float" setter="set_emission_sphere_radius" getter="get_emission_sphere_radius"> The sphere's radius if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_SPHERE]. </member> - <member name="flag_align_y" type="bool" setter="set_flag" getter="get_flag" default="false"> - Align Y axis of particle with the direction of its velocity. - </member> - <member name="flag_disable_z" type="bool" setter="set_flag" getter="get_flag" default="false"> - If [code]true[/code], particles will not move on the z axis. - </member> - <member name="flag_rotate_y" type="bool" setter="set_flag" getter="get_flag" default="false"> - If [code]true[/code], particles rotate around Y axis by [member angle]. - </member> <member name="flatness" type="float" setter="set_flatness" getter="get_flatness" default="0.0"> Amount of [member spread] in Y/Z plane. A value of [code]1[/code] restricts particles to X/Z plane. </member> @@ -224,7 +215,7 @@ </member> <member name="orbit_velocity" type="float" setter="set_param" getter="get_param"> Orbital velocity applied to each particle. Makes the particles circle around origin. Specified in number of full rotations around origin per second. - Only available when [member flag_disable_z] is [code]true[/code]. + Only available when [member particle_flag_disable_z] is [code]true[/code]. </member> <member name="orbit_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's orbital velocity will vary along this [CurveTexture]. @@ -232,6 +223,15 @@ <member name="orbit_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> Orbital velocity randomness ratio. </member> + <member name="particle_flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> + Align Y axis of particle with the direction of its velocity. + </member> + <member name="particle_flag_disable_z" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> + If [code]true[/code], particles will not move on the z axis. + </member> + <member name="particle_flag_rotate_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> + If [code]true[/code], particles rotate around Y axis by [member angle]. + </member> <member name="radial_accel" type="float" setter="set_param" getter="get_param" default="0.0"> Radial acceleration applied to each particle. Makes particle accelerate away from origin. </member> @@ -311,17 +311,17 @@ <constant name="PARAM_MAX" value="12" enum="Parameter"> Represents the size of the [enum Parameter] enum. </constant> - <constant name="FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="Flags"> - Use with [method set_flag] to set [member flag_align_y]. + <constant name="PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="ParticleFlags"> + Use with [method set_particle_flag] to set [member particle_flag_align_y]. </constant> - <constant name="FLAG_ROTATE_Y" value="1" enum="Flags"> - Use with [method set_flag] to set [member flag_rotate_y]. + <constant name="PARTICLE_FLAG_ROTATE_Y" value="1" enum="ParticleFlags"> + Use with [method set_particle_flag] to set [member particle_flag_rotate_y]. </constant> - <constant name="FLAG_DISABLE_Z" value="2" enum="Flags"> - Use with [method set_flag] to set [member flag_disable_z]. + <constant name="PARTICLE_FLAG_DISABLE_Z" value="2" enum="ParticleFlags"> + Use with [method set_particle_flag] to set [member particle_flag_disable_z]. </constant> - <constant name="FLAG_MAX" value="3" enum="Flags"> - Represents the size of the [enum Flags] enum. + <constant name="PARTICLE_FLAG_MAX" value="3" enum="ParticleFlags"> + Represents the size of the [enum ParticleFlags] enum. </constant> <constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape"> All particles will be emitted from a single point. diff --git a/doc/classes/PathFollow2D.xml b/doc/classes/PathFollow2D.xml index bbaeca12da..4b55e7b781 100644 --- a/doc/classes/PathFollow2D.xml +++ b/doc/classes/PathFollow2D.xml @@ -29,8 +29,8 @@ <member name="offset" type="float" setter="set_offset" getter="get_offset" default="0.0"> The distance along the path in pixels. </member> - <member name="rotate" type="bool" setter="set_rotate" getter="is_rotating" default="true"> - If [code]true[/code], this node rotates to follow the path, making its descendants rotate. + <member name="rotates" type="bool" setter="set_rotates" getter="is_rotating" default="true"> + If [code]true[/code], this node rotates to follow the path, with the +X direction facing forward on the path. </member> <member name="unit_offset" type="float" setter="set_unit_offset" getter="get_unit_offset" default="0.0"> The distance along the path as a number in the range 0.0 (for the first vertex) to 1.0 (for the last). This is just another way of expressing the offset within the path, as the offset supplied is multiplied internally by the path's length. diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index c663f26d84..04798c04e9 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -207,6 +207,7 @@ </argument> <description> Adds a separator between items. Separators also occupy an index. + A [code]label[/code] can optionally be provided, which will appear at the center of the separator. </description> </method> <method name="add_shortcut"> @@ -726,6 +727,9 @@ <theme_item name="font_color_hover" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> [Color] used for the hovered text. </theme_item> + <theme_item name="font_color_separator" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + [Color] used for labeled separators' text. See [method add_separator]. + </theme_item> <theme_item name="font_size" type="int"> Font size of the menu items. </theme_item> diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml index 7e9bccc1d7..25943f6d47 100644 --- a/doc/classes/PrimitiveMesh.xml +++ b/doc/classes/PrimitiveMesh.xml @@ -4,7 +4,7 @@ Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh. </brief_description> <description> - Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh. Examples include [CapsuleMesh], [CubeMesh], [CylinderMesh], [PlaneMesh], [PrismMesh], [QuadMesh], and [SphereMesh]. + Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh. Examples include [BoxMesh], [CapsuleMesh], [CylinderMesh], [PlaneMesh], [PrismMesh], [QuadMesh], and [SphereMesh]. </description> <tutorials> </tutorials> diff --git a/doc/classes/Quat.xml b/doc/classes/Quat.xml index 00ad4ee934..425e82c744 100644 --- a/doc/classes/Quat.xml +++ b/doc/classes/Quat.xml @@ -92,10 +92,10 @@ </argument> <argument index="2" name="post_b" type="Quat"> </argument> - <argument index="3" name="t" type="float"> + <argument index="3" name="weight" type="float"> </argument> <description> - Performs a cubic spherical interpolation between quaternions [code]preA[/code], this vector, [code]b[/code], and [code]postB[/code], by the given amount [code]t[/code]. + Performs a cubic spherical interpolation between quaternions [code]pre_a[/code], this vector, [code]b[/code], and [code]post_b[/code], by the given amount [code]weight[/code]. </description> </method> <method name="dot"> @@ -261,9 +261,9 @@ <method name="slerp"> <return type="Quat"> </return> - <argument index="0" name="b" type="Quat"> + <argument index="0" name="to" type="Quat"> </argument> - <argument index="1" name="t" type="float"> + <argument index="1" name="weight" type="float"> </argument> <description> Returns the result of the spherical linear interpolation between this quaternion and [code]to[/code] by amount [code]weight[/code]. @@ -273,9 +273,9 @@ <method name="slerpni"> <return type="Quat"> </return> - <argument index="0" name="b" type="Quat"> + <argument index="0" name="to" type="Quat"> </argument> - <argument index="1" name="t" type="float"> + <argument index="1" name="weight" type="float"> </argument> <description> Returns the result of the spherical linear interpolation between this quaternion and [code]to[/code] by amount [code]weight[/code], but without checking if the rotation path is not bigger than 90 degrees. diff --git a/doc/classes/RDTextureFormat.xml b/doc/classes/RDTextureFormat.xml index 664d4cadff..e41ddff368 100644 --- a/doc/classes/RDTextureFormat.xml +++ b/doc/classes/RDTextureFormat.xml @@ -37,7 +37,7 @@ </member> <member name="samples" type="int" setter="set_samples" getter="get_samples" enum="RenderingDevice.TextureSamples" default="0"> </member> - <member name="type" type="int" setter="set_type" getter="get_type" enum="RenderingDevice.TextureType" default="1"> + <member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="RenderingDevice.TextureType" default="1"> </member> <member name="usage_bits" type="int" setter="set_usage_bits" getter="get_usage_bits" default="0"> </member> diff --git a/doc/classes/RDUniform.xml b/doc/classes/RDUniform.xml index e5bace32af..bc8a21e985 100644 --- a/doc/classes/RDUniform.xml +++ b/doc/classes/RDUniform.xml @@ -31,7 +31,7 @@ <members> <member name="binding" type="int" setter="set_binding" getter="get_binding" default="0"> </member> - <member name="type" type="int" setter="set_type" getter="get_type" enum="RenderingDevice.UniformType" default="3"> + <member name="uniform_type" type="int" setter="set_uniform_type" getter="get_uniform_type" enum="RenderingDevice.UniformType" default="3"> </member> </members> <constants> diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml index dcb75dc275..6312cd18aa 100644 --- a/doc/classes/RandomNumberGenerator.xml +++ b/doc/classes/RandomNumberGenerator.xml @@ -13,6 +13,7 @@ rng.randomize() var my_random_number = rng.randf_range(-10.0, 10.0) [/codeblock] + [b]Note:[/b] The default values of [member seed] and [member state] properties are pseudo-random, and changes when calling [method randomize]. The [code]0[/code] value documented here is a placeholder, and not the actual default seed. </description> <tutorials> <link title="Random number generation">https://docs.godotengine.org/en/latest/tutorials/math/random_number_generation.html</link> @@ -75,9 +76,26 @@ </methods> <members> <member name="seed" type="int" setter="set_seed" getter="get_seed" default="0"> - The seed used by the random number generator. A given seed will give a reproducible sequence of pseudo-random numbers. + Initializes the random number generator state based on the given seed value. A given seed will give a reproducible sequence of pseudo-random numbers. [b]Note:[/b] The RNG does not have an avalanche effect, and can output similar random streams given similar seeds. Consider using a hash function to improve your seed quality if they're sourced externally. - [b]Note:[/b] The default value of this property is pseudo-random, and changes when calling [method randomize]. The [code]0[/code] value documented here is a placeholder, and not the actual default seed. + [b]Note:[/b] Setting this property produces a side effect of changing the internal [member state], so make sure to initialize the seed [i]before[/i] modifying the [member state]: + [codeblock] + var rng = RandomNumberGenerator.new() + rng.seed = hash("Godot") + rng.state = 100 # Restore to some previously saved state. + [/codeblock] + </member> + <member name="state" type="int" setter="set_state" getter="get_state" default="0"> + The current state of the random number generator. Save and restore this property to restore the generator to a previous state: + [codeblock] + var rng = RandomNumberGenerator.new() + print(rng.randf()) + var saved_state = rng.state # Store current state. + print(rng.randf()) # Advance internal state. + rng.state = saved_state # Restore the state. + print(rng.randf()) # Prints the same value as in previous. + [/codeblock] + [b]Note:[/b] Do not set state to arbitrary values, since the random number generator requires the state to have certain qualities to behave properly. It should only be set to values that came from the state property itself. To initialize the random number generator with arbitrary input, use [member seed] instead. </member> </members> <constants> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index f36713a81a..74eb6a17e5 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3123,7 +3123,7 @@ <constant name="ARRAY_FORMAT_INDEX" value="4096" enum="ArrayFormat"> Flag used to mark an index array. </constant> - <constant name="ARRAY_FORMAT_BLEND_SHAPE_MASK" value="-8185" enum="ArrayFormat"> + <constant name="ARRAY_FORMAT_BLEND_SHAPE_MASK" value="2147475463" enum="ArrayFormat"> </constant> <constant name="ARRAY_FORMAT_CUSTOM_BASE" value="13" enum="ArrayFormat"> </constant> diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml index 1ce2c376dd..54984b7785 100644 --- a/doc/classes/Resource.xml +++ b/doc/classes/Resource.xml @@ -76,6 +76,7 @@ <signal name="changed"> <description> Emitted whenever the resource changes. + [b]Note:[/b] This signal is not emitted automatically for custom resources, which means that you need to create a setter and emit the signal yourself. </description> </signal> </signals> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index faf0d97766..0fd440fa75 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -25,6 +25,8 @@ </argument> <argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> </argument> + <argument index="4" name="inline_align" type="int" enum="VAlign" default="0"> + </argument> <description> Adds an image's opening and closing tags to the tag stack, optionally providing a [code]width[/code] and [code]height[/code] to resize the image and a [code]color[/code] to tint the image. If [code]width[/code] or [code]height[/code] is set to 0, the image size will be adjusted in order to keep the original aspect ratio. @@ -132,15 +134,6 @@ Terminates the current tag. Use after [code]push_*[/code] methods to close BBCodes manually. Does not need to follow [code]add_*[/code] methods. </description> </method> - <method name="push_align"> - <return type="void"> - </return> - <argument index="0" name="align" type="int" enum="RichTextLabel.Align"> - </argument> - <description> - Adds an [code][align][/code] tag based on the given [code]align[/code] value. See [enum Align] for possible values. - </description> - </method> <method name="push_bold"> <return type="void"> </return> @@ -180,6 +173,24 @@ Adds a [code][font][/code] tag to the tag stack. Overrides default fonts for its duration. </description> </method> + <method name="push_font_features"> + <return type="void"> + </return> + <argument index="0" name="opentype_features" type="Dictionary"> + </argument> + <description> + Adds a [code][ot_feature][/code] tag to the tag stack. Overrides default OpenType font feature for its duration. + </description> + </method> + <method name="push_font_size"> + <return type="void"> + </return> + <argument index="0" name="font_size" type="int"> + </argument> + <description> + Adds a [code][font_size][/code] tag to the tag stack. Overrides default font size for its duration. + </description> + </method> <method name="push_indent"> <return type="void"> </return> @@ -199,10 +210,14 @@ <method name="push_list"> <return type="void"> </return> - <argument index="0" name="type" type="int" enum="RichTextLabel.ListType"> + <argument index="0" name="level" type="int"> + </argument> + <argument index="1" name="type" type="int" enum="RichTextLabel.ListType"> + </argument> + <argument index="2" name="capitalize" type="bool"> </argument> <description> - Adds a [code][list][/code] tag to the tag stack. Similar to the BBCodes [code][ol][/code] or [code][ul][/code], but supports more list types. Not fully implemented! + Adds [code][ol][/code] or [code][ul][/code] tag to the tag stack. Multiplies [code]level[/code] by current [member tab_size] to determine new margin length. </description> </method> <method name="push_meta"> @@ -228,6 +243,39 @@ Adds a [code][font][/code] tag with a normal font to the tag stack. </description> </method> + <method name="push_outline_color"> + <return type="void"> + </return> + <argument index="0" name="color" type="Color"> + </argument> + <description> + Adds a [code][outline_color][/code] tag to the tag stack. Adds text outline for its duration. + </description> + </method> + <method name="push_outline_size"> + <return type="void"> + </return> + <argument index="0" name="outline_size" type="int"> + </argument> + <description> + Adds a [code][outline_size][/code] tag to the tag stack. Overrides default text outline size for its duration. + </description> + </method> + <method name="push_paragraph"> + <return type="void"> + </return> + <argument index="0" name="align" type="int" enum="RichTextLabel.Align"> + </argument> + <argument index="1" name="base_direction" type="int" enum="Control.TextDirection" default="0"> + </argument> + <argument index="2" name="language" type="String" default=""""> + </argument> + <argument index="3" name="st_parser" type="int" enum="Control.StructuredTextParser" default="0"> + </argument> + <description> + Adds a [code][p][/code] tag to the tag stack. + </description> + </method> <method name="push_strikethrough"> <return type="void"> </return> @@ -240,8 +288,10 @@ </return> <argument index="0" name="columns" type="int"> </argument> + <argument index="1" name="inline_align" type="int" enum="VAlign" default="0"> + </argument> <description> - Adds a [code][table=columns][/code] tag to the tag stack. + Adds a [code][table=columns,inline_align][/code] tag to the tag stack. </description> </method> <method name="push_underline"> @@ -270,6 +320,46 @@ Scrolls the window's top line to match [code]line[/code]. </description> </method> + <method name="set_cell_border_color"> + <return type="void"> + </return> + <argument index="0" name="color" type="Color"> + </argument> + <description> + Sets color of a table cell border. + </description> + </method> + <method name="set_cell_padding"> + <return type="void"> + </return> + <argument index="0" name="padding" type="Rect2"> + </argument> + <description> + Sets inner padding of a table cell. + </description> + </method> + <method name="set_cell_row_background_color"> + <return type="void"> + </return> + <argument index="0" name="odd_row_bg" type="Color"> + </argument> + <argument index="1" name="even_row_bg" type="Color"> + </argument> + <description> + Sets color of a table cell. Separate colors for alternating rows can be specified. + </description> + </method> + <method name="set_cell_size_override"> + <return type="void"> + </return> + <argument index="0" name="min_size" type="Vector2"> + </argument> + <argument index="1" name="max_size" type="Vector2"> + </argument> + <description> + Sets minimum and maximum size overrides for a table cell. + </description> + </method> <method name="set_table_column_expand"> <return type="void"> </return> @@ -302,6 +392,9 @@ If [code]true[/code], the label's height will be automatically updated to fit its content. [b]Note:[/b] This property is used as a workaround to fix issues with [RichTextLabel] in [Container]s, but it's unreliable in some cases and will be removed in future versions. </member> + <member name="language" type="String" setter="set_language" getter="get_language" default=""""> + Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. + </member> <member name="meta_underlined" type="bool" setter="set_meta_underline" getter="is_meta_underlined" default="true"> If [code]true[/code], the label underlines meta tags such as [code][url]{text}[/url][/code]. </member> @@ -322,6 +415,12 @@ <member name="selection_enabled" type="bool" setter="set_selection_enabled" getter="is_selection_enabled" default="false"> If [code]true[/code], the label allows text selection. </member> + <member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="Control.StructuredTextParser" default="0"> + Set BiDi algorithm override for the structured text. + </member> + <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[ ]"> + Set additional options for BiDi override. + </member> <member name="tab_size" type="int" setter="set_tab_size" getter="get_tab_size" default="4"> The number of spaces associated with a single tab length. Does not affect [code]\t[/code] in text tags, only indent tags. </member> @@ -329,6 +428,9 @@ The raw text of the label. When set, clears the tag stack and adds a raw text tag to the top of it. Does not parse BBCodes. Does not modify [member bbcode_text]. </member> + <member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" enum="Control.TextDirection" default="0"> + Base text writing direction. + </member> <member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1"> The restricted number of characters to display in the label. If [code]-1[/code], all characters will be displayed. </member> @@ -375,7 +477,10 @@ <constant name="LIST_LETTERS" value="1" enum="ListType"> Each list item has a letter marker. </constant> - <constant name="LIST_DOTS" value="2" enum="ListType"> + <constant name="LIST_ROMAN" value="2" enum="ListType"> + Each list item has a roman number marker. + </constant> + <constant name="LIST_DOTS" value="3" enum="ListType"> Each list item has a filled circle marker. </constant> <constant name="ITEM_FRAME" value="0" enum="ItemType"> @@ -388,42 +493,56 @@ </constant> <constant name="ITEM_FONT" value="4" enum="ItemType"> </constant> - <constant name="ITEM_COLOR" value="5" enum="ItemType"> + <constant name="ITEM_FONT_SIZE" value="5" enum="ItemType"> + </constant> + <constant name="ITEM_FONT_FEATURES" value="6" enum="ItemType"> </constant> - <constant name="ITEM_UNDERLINE" value="6" enum="ItemType"> + <constant name="ITEM_COLOR" value="7" enum="ItemType"> </constant> - <constant name="ITEM_STRIKETHROUGH" value="7" enum="ItemType"> + <constant name="ITEM_OUTLINE_SIZE" value="8" enum="ItemType"> </constant> - <constant name="ITEM_ALIGN" value="8" enum="ItemType"> + <constant name="ITEM_OUTLINE_COLOR" value="9" enum="ItemType"> </constant> - <constant name="ITEM_INDENT" value="9" enum="ItemType"> + <constant name="ITEM_UNDERLINE" value="10" enum="ItemType"> </constant> - <constant name="ITEM_LIST" value="10" enum="ItemType"> + <constant name="ITEM_STRIKETHROUGH" value="11" enum="ItemType"> </constant> - <constant name="ITEM_TABLE" value="11" enum="ItemType"> + <constant name="ITEM_PARAGRAPH" value="12" enum="ItemType"> </constant> - <constant name="ITEM_FADE" value="12" enum="ItemType"> + <constant name="ITEM_INDENT" value="13" enum="ItemType"> </constant> - <constant name="ITEM_SHAKE" value="13" enum="ItemType"> + <constant name="ITEM_LIST" value="14" enum="ItemType"> </constant> - <constant name="ITEM_WAVE" value="14" enum="ItemType"> + <constant name="ITEM_TABLE" value="15" enum="ItemType"> </constant> - <constant name="ITEM_TORNADO" value="15" enum="ItemType"> + <constant name="ITEM_FADE" value="16" enum="ItemType"> </constant> - <constant name="ITEM_RAINBOW" value="16" enum="ItemType"> + <constant name="ITEM_SHAKE" value="17" enum="ItemType"> </constant> - <constant name="ITEM_CUSTOMFX" value="18" enum="ItemType"> + <constant name="ITEM_WAVE" value="18" enum="ItemType"> </constant> - <constant name="ITEM_META" value="17" enum="ItemType"> + <constant name="ITEM_TORNADO" value="19" enum="ItemType"> + </constant> + <constant name="ITEM_RAINBOW" value="20" enum="ItemType"> + </constant> + <constant name="ITEM_CUSTOMFX" value="22" enum="ItemType"> + </constant> + <constant name="ITEM_META" value="21" enum="ItemType"> </constant> </constants> <theme_items> <theme_item name="bold_font" type="Font"> The font used for bold text. </theme_item> + <theme_item name="bold_font_size" type="int"> + The font size used for bold text. + </theme_item> <theme_item name="bold_italics_font" type="Font"> The font used for bold italics text. </theme_item> + <theme_item name="bold_italics_font_size" type="int"> + The font size used for bold italics text. + </theme_item> <theme_item name="default_color" type="Color" default="Color( 1, 1, 1, 1 )"> The default text color. </theme_item> @@ -439,18 +558,27 @@ <theme_item name="italics_font" type="Font"> The font used for italics text. </theme_item> + <theme_item name="italics_font_size" type="int"> + The font size used for italics text. + </theme_item> <theme_item name="line_separation" type="int" default="1"> The vertical space between lines. </theme_item> <theme_item name="mono_font" type="Font"> The font used for monospace text. </theme_item> + <theme_item name="mono_font_size" type="int"> + The font size used for monospace text. + </theme_item> <theme_item name="normal" type="StyleBox"> The normal background for the [RichTextLabel]. </theme_item> <theme_item name="normal_font" type="Font"> The default text font. </theme_item> + <theme_item name="normal_font_size" type="int"> + The default text font size. + </theme_item> <theme_item name="selection_color" type="Color" default="Color( 0.1, 0.1, 1, 0.8 )"> The color of the selection box. </theme_item> @@ -463,9 +591,18 @@ <theme_item name="shadow_offset_y" type="int" default="1"> The vertical offset of the font's shadow. </theme_item> + <theme_item name="table_border" type="Color" default="Color( 0, 0, 0, 0 )"> + The default cell border color. + </theme_item> + <theme_item name="table_even_row_bg" type="Color" default="Color( 0, 0, 0, 0 )"> + The default background color for even rows. + </theme_item> <theme_item name="table_hseparation" type="int" default="3"> The horizontal separation of elements in a table. </theme_item> + <theme_item name="table_odd_row_bg" type="Color" default="Color( 0, 0, 0, 0 )"> + The default background color for odd rows. + </theme_item> <theme_item name="table_vseparation" type="int" default="3"> The vertical separation of elements in a table. </theme_item> diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml index 4736401395..376082f417 100644 --- a/doc/classes/SubViewport.xml +++ b/doc/classes/SubViewport.xml @@ -45,8 +45,8 @@ <constant name="CLEAR_MODE_NEVER" value="1" enum="ClearMode"> Never clear the render target. </constant> - <constant name="CLEAR_MODE_ONLY_NEXT_FRAME" value="2" enum="ClearMode"> - Clear the render target next frame, then switch to [constant CLEAR_MODE_NEVER]. + <constant name="CLEAR_MODE_ONCE" value="2" enum="ClearMode"> + Clear the render target on the next frame, then switch to [constant CLEAR_MODE_NEVER]. </constant> <constant name="UPDATE_DISABLED" value="0" enum="UpdateMode"> Do not update the render target. @@ -58,7 +58,7 @@ Update the render target only when it is visible. This is the default value. </constant> <constant name="UPDATE_WHEN_PARENT_VISIBLE" value="3" enum="UpdateMode"> - Update the render target only when the its parent is visible. + Update the render target only when its parent is visible. </constant> <constant name="UPDATE_ALWAYS" value="4" enum="UpdateMode"> Always update the render target. diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml index 9f45a361f3..c9ed1aaec9 100644 --- a/doc/classes/TabContainer.xml +++ b/doc/classes/TabContainer.xml @@ -149,6 +149,9 @@ <member name="tabs_visible" type="bool" setter="set_tabs_visible" getter="are_tabs_visible" default="true"> If [code]true[/code], tabs are visible. If [code]false[/code], tabs' content and titles are hidden. </member> + <member name="all_tabs_in_front" type="bool" setter="set_all_tabs_in_front" getter="is_all_tabs_in_front" default="false"> + If [code]true[/code], all tabs are drawn in front of the panel. If [code]false[/code], inactive tabs are drawn behind the panel. + </member> <member name="use_hidden_tabs_for_min_size" type="bool" setter="set_use_hidden_tabs_for_min_size" getter="get_use_hidden_tabs_for_min_size" default="false"> If [code]true[/code], children [Control] nodes that are hidden have their minimum size take into account in the total, instead of only the currently visible one. </member> diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml index 5c698a4aa8..47cf869fe9 100644 --- a/doc/classes/Tabs.xml +++ b/doc/classes/Tabs.xml @@ -299,14 +299,14 @@ Emitted when a tab is clicked, even if it is the current tab. </description> </signal> - <signal name="tab_close"> + <signal name="tab_closed"> <argument index="0" name="tab" type="int"> </argument> <description> Emitted when a tab is closed. </description> </signal> - <signal name="tab_hover"> + <signal name="tab_hovered"> <argument index="0" name="tab" type="int"> </argument> <description> diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index 9c34c63e2f..31ea108e46 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -326,6 +326,27 @@ Returns underline thickness in pixels. </description> </method> + <method name="font_get_variation" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="font" type="RID"> + </argument> + <argument index="1" name="tag" type="String"> + </argument> + <description> + Returns variation coordinate [code]tag[/code]. + </description> + </method> + <method name="font_get_variation_list" qualifiers="const"> + <return type="Dictionary"> + </return> + <argument index="0" name="font" type="RID"> + </argument> + <description> + Returns list of supported [url=https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg]variation coordinates[/url], each coordinate is returned as [code]tag: Vector3i(min_value,max_value,default_value)[/code]. + Font variations allow for continuous change of glyph characteristics along some given design axis, such as weight, width or slant. + </description> + </method> <method name="font_has_char" qualifiers="const"> <return type="bool"> </return> @@ -469,6 +490,19 @@ Adds override for [method font_is_script_supported]. </description> </method> + <method name="font_set_variation"> + <return type="void"> + </return> + <argument index="0" name="font" type="RID"> + </argument> + <argument index="1" name="tag" type="String"> + </argument> + <argument index="2" name="value" type="float"> + </argument> + <description> + Sets variation coordinate [code]name[/code]. Unsupported coordinates will be silently ignored. + </description> + </method> <method name="format_number" qualifiers="const"> <return type="String"> </return> @@ -1160,7 +1194,10 @@ <constant name="FEATURE_FONT_SYSTEM" value="32" enum="Feature"> TextServer supports loading system fonts. </constant> - <constant name="FEATURE_USE_SUPPORT_DATA" value="64" enum="Feature"> + <constant name="FEATURE_FONT_VARIABLE" value="64" enum="Feature"> + TextServer supports variable fonts. + </constant> + <constant name="FEATURE_USE_SUPPORT_DATA" value="128" enum="Feature"> TextServer require external data file for some features. </constant> </constants> diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml index ff291663fa..406774cbfe 100644 --- a/doc/classes/Transform2D.xml +++ b/doc/classes/Transform2D.xml @@ -107,10 +107,10 @@ </return> <argument index="0" name="xform" type="Transform2D"> </argument> - <argument index="1" name="t" type="float"> + <argument index="1" name="weight" type="float"> </argument> <description> - Returns a transform interpolated between this transform and another by a given weight (on the range of 0.0 to 1.0). + Returns a transform interpolated between this transform and another by a given [code]weight[/code] (on the range of 0.0 to 1.0). </description> </method> <method name="inverse"> diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index f99231de39..4e79560f3e 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -137,10 +137,10 @@ </argument> <argument index="2" name="post_b" type="Vector2"> </argument> - <argument index="3" name="t" type="float"> + <argument index="3" name="weight" type="float"> </argument> <description> - Cubically interpolates between this vector and [code]b[/code] using [code]pre_a[/code] and [code]post_b[/code] as handles, and returns the result at position [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. + Cubically interpolates between this vector and [code]b[/code] using [code]pre_a[/code] and [code]post_b[/code] as handles, and returns the result at position [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. </description> </method> <method name="direction_to"> @@ -224,9 +224,9 @@ <method name="lerp"> <return type="Vector2"> </return> - <argument index="0" name="with" type="Vector2"> + <argument index="0" name="to" type="Vector2"> </argument> - <argument index="1" name="t" type="float"> + <argument index="1" name="weight" type="float"> </argument> <description> Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. @@ -452,9 +452,9 @@ <method name="slerp"> <return type="Vector2"> </return> - <argument index="0" name="with" type="Vector2"> + <argument index="0" name="to" type="Vector2"> </argument> - <argument index="1" name="t" type="float"> + <argument index="1" name="weight" type="float"> </argument> <description> Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index 6ba0d6ab8d..2c2b30a644 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -105,10 +105,10 @@ </argument> <argument index="2" name="post_b" type="Vector3"> </argument> - <argument index="3" name="t" type="float"> + <argument index="3" name="weight" type="float"> </argument> <description> - Performs a cubic interpolation between vectors [code]pre_a[/code], [code]a[/code], [code]b[/code], [code]post_b[/code] ([code]a[/code] is current), by the given amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. + Performs a cubic interpolation between vectors [code]pre_a[/code], [code]a[/code], [code]b[/code], [code]post_b[/code] ([code]a[/code] is current), by the given amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. </description> </method> <method name="direction_to"> @@ -199,12 +199,12 @@ <method name="lerp"> <return type="Vector3"> </return> - <argument index="0" name="b" type="Vector3"> + <argument index="0" name="to" type="Vector3"> </argument> - <argument index="1" name="t" type="float"> + <argument index="1" name="weight" type="float"> </argument> <description> - Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. + Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. </description> </method> <method name="max_axis"> @@ -468,9 +468,9 @@ <method name="slerp"> <return type="Vector3"> </return> - <argument index="0" name="b" type="Vector3"> + <argument index="0" name="to" type="Vector3"> </argument> - <argument index="1" name="t" type="float"> + <argument index="1" name="weight" type="float"> </argument> <description> Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. diff --git a/doc/classes/VideoPlayer.xml b/doc/classes/VideoPlayer.xml index 60f0a40159..80f97c3419 100644 --- a/doc/classes/VideoPlayer.xml +++ b/doc/classes/VideoPlayer.xml @@ -6,6 +6,7 @@ <description> Control node for playing video streams using [VideoStream] resources. Supported video formats are [url=https://www.webmproject.org/]WebM[/url] ([code].webm[/code], [VideoStreamWebm]), [url=https://www.theora.org/]Ogg Theora[/url] ([code].ogv[/code], [VideoStreamTheora]), and any format exposed via a GDNative plugin using [VideoStreamGDNative]. + [b]Note:[/b] Due to a bug, VideoPlayer does not support localization remapping yet. </description> <tutorials> </tutorials> diff --git a/doc/classes/XRController3D.xml b/doc/classes/XRController3D.xml index c0f64d9e27..78684d10ee 100644 --- a/doc/classes/XRController3D.xml +++ b/doc/classes/XRController3D.xml @@ -86,7 +86,7 @@ Emitted when a button on this controller is pressed. </description> </signal> - <signal name="button_release"> + <signal name="button_released"> <argument index="0" name="button" type="int"> </argument> <description> diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml index 0b57c9478f..5ed7a26b19 100644 --- a/doc/classes/XRPositionalTracker.xml +++ b/doc/classes/XRPositionalTracker.xml @@ -33,13 +33,6 @@ Returns the mesh related to a controller or anchor point if one is available. </description> </method> - <method name="get_name" qualifiers="const"> - <return type="StringName"> - </return> - <description> - Returns the controller or anchor point's name if available. - </description> - </method> <method name="get_orientation" qualifiers="const"> <return type="Basis"> </return> @@ -61,6 +54,20 @@ Returns the internal tracker ID. This uniquely identifies the tracker per tracker type and matches the ID you need to specify for nodes such as the [XRController3D] and [XRAnchor3D] nodes. </description> </method> + <method name="get_tracker_name" qualifiers="const"> + <return type="StringName"> + </return> + <description> + Returns the controller or anchor point's name, if applicable. + </description> + </method> + <method name="get_tracker_type" qualifiers="const"> + <return type="int" enum="XRServer.TrackerType"> + </return> + <description> + Returns the tracker's type, which will be one of the values from the [enum XRServer.TrackerType] enum. + </description> + </method> <method name="get_tracks_orientation" qualifiers="const"> <return type="bool"> </return> @@ -84,13 +91,6 @@ Returns the transform combining this device's orientation and position. </description> </method> - <method name="get_type" qualifiers="const"> - <return type="int" enum="XRServer.TrackerType"> - </return> - <description> - Returns the tracker's type. - </description> - </method> </methods> <members> <member name="rumble" type="float" setter="set_rumble" getter="get_rumble" default="0.0"> diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 39525cecc8..bc34d2df9a 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -175,6 +175,8 @@ public: void update() override {} void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override {} + bool is_low_end() const override { return true; } + RasterizerSceneDummy() {} ~RasterizerSceneDummy() {} }; @@ -383,7 +385,7 @@ public: bool material_is_animated(RID p_material) override { return false; } bool material_casts_shadows(RID p_material) override { return false; } void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override {} - void material_update_dependency(RID p_material, RendererSceneRender::InstanceBase *p_instance) override {} + void material_update_dependency(RID p_material, InstanceBaseDependency *p_instance) override {} /* MESH API */ @@ -642,8 +644,8 @@ public: float reflection_probe_get_origin_max_distance(RID p_probe) const override { return 0.0; } bool reflection_probe_renders_shadows(RID p_probe) const override { return false; } - void base_update_dependency(RID p_base, RendererSceneRender::InstanceBase *p_instance) override {} - void skeleton_update_dependency(RID p_base, RendererSceneRender::InstanceBase *p_instance) override {} + void base_update_dependency(RID p_base, InstanceBaseDependency *p_instance) override {} + void skeleton_update_dependency(RID p_base, InstanceBaseDependency *p_instance) override {} /* DECAL API */ @@ -826,8 +828,8 @@ public: int particles_get_draw_passes(RID p_particles) const override { return 0; } RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override { return RID(); } - void particles_add_collision(RID p_particles, RendererSceneRender::InstanceBase *p_instance) override {} - void particles_remove_collision(RID p_particles, RendererSceneRender::InstanceBase *p_instance) override {} + void particles_add_collision(RID p_particles, InstanceBaseDependency *p_instance) override {} + void particles_remove_collision(RID p_particles, InstanceBaseDependency *p_instance) override {} void update_particles() override {} diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 318638e5d0..ca08d689b9 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -127,7 +127,6 @@ void OS_Unix::initialize_core() { FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM); - //FileAccessBufferedFA<FileAccessUnix>::make_default(); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM); diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index bf27342b74..ecc689bd2b 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1692,16 +1692,16 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T #endif } - if (p_format.type == TEXTURE_TYPE_CUBE || p_format.type == TEXTURE_TYPE_CUBE_ARRAY) { + if (p_format.texture_type == TEXTURE_TYPE_CUBE || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY) { image_create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; } /*if (p_format.type == TEXTURE_TYPE_2D || p_format.type == TEXTURE_TYPE_2D_ARRAY) { image_create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; }*/ - ERR_FAIL_INDEX_V(p_format.type, TEXTURE_TYPE_MAX, RID()); + ERR_FAIL_INDEX_V(p_format.texture_type, TEXTURE_TYPE_MAX, RID()); - image_create_info.imageType = vulkan_image_type[p_format.type]; + image_create_info.imageType = vulkan_image_type[p_format.texture_type]; ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures"); @@ -1726,10 +1726,10 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_create_info.mipLevels = p_format.mipmaps; - if (p_format.type == TEXTURE_TYPE_1D_ARRAY || p_format.type == TEXTURE_TYPE_2D_ARRAY || p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) { + if (p_format.texture_type == TEXTURE_TYPE_1D_ARRAY || p_format.texture_type == TEXTURE_TYPE_2D_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) { ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, RID(), "Amount of layers must be equal or greater than 1 for arrays and cubemaps."); - ERR_FAIL_COND_V_MSG((p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0, RID(), + ERR_FAIL_COND_V_MSG((p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0, RID(), "Cubemap and cubemap array textures must provide a layer number that is multiple of 6"); image_create_info.arrayLayers = p_format.array_layers; } else { @@ -1859,7 +1859,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &texture.image, &texture.allocation, &texture.allocation_info); ERR_FAIL_COND_V_MSG(err, RID(), "vmaCreateImage failed with error " + itos(err) + "."); - texture.type = p_format.type; + texture.type = p_format.texture_type; texture.format = p_format.format; texture.width = image_create_info.extent.width; texture.height = image_create_info.extent.height; @@ -1927,7 +1927,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, }; - image_view_create_info.viewType = view_types[p_format.type]; + image_view_create_info.viewType = view_types[p_format.texture_type]; if (p_view.format_override == DATA_FORMAT_MAX) { image_view_create_info.format = image_create_info.format; } else { @@ -4612,8 +4612,8 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, const Uniform &uniform = uniforms[uniform_idx]; - ERR_FAIL_COND_V_MSG(uniform.type != set_uniform.type, RID(), - "Mismatch uniform type for binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.type] + "'."); + ERR_FAIL_COND_V_MSG(uniform.uniform_type != set_uniform.type, RID(), + "Mismatch uniform type for binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.uniform_type] + "'."); VkWriteDescriptorSet write; //common header write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -4628,7 +4628,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, write.pTexelBufferView = nullptr; uint32_t type_size = 1; - switch (uniform.type) { + switch (uniform.uniform_type) { case UNIFORM_TYPE_SAMPLER: { if (uniform.ids.size() != set_uniform.length) { if (set_uniform.length > 1) { @@ -6130,7 +6130,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) { #ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index > MAX_UNIFORM_SETS, + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index >= MAX_UNIFORM_SETS, "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); #endif DrawList *dl = _get_draw_list_ptr(p_list); @@ -6552,7 +6552,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, ComputeList *cl = compute_list; #ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index > MAX_UNIFORM_SETS, + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index >= MAX_UNIFORM_SETS, "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); #endif diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 22adf4f267..25ff7f884a 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -507,14 +507,14 @@ Ref<Animation> AnimationBezierTrackEdit::get_animation() const { void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track) { animation = p_animation; track = p_track; - if (is_connected_compat("select_key", editor, "_key_selected")) { - disconnect_compat("select_key", editor, "_key_selected"); + if (is_connected("select_key", Callable(editor, "_key_selected"))) { + disconnect("select_key", Callable(editor, "_key_selected")); } - if (is_connected_compat("deselect_key", editor, "_key_deselected")) { - disconnect_compat("deselect_key", editor, "_key_deselected"); + if (is_connected("deselect_key", Callable(editor, "_key_deselected"))) { + disconnect("deselect_key", Callable(editor, "_key_deselected")); } - connect_compat("select_key", editor, "_key_selected", varray(p_track), CONNECT_DEFERRED); - connect_compat("deselect_key", editor, "_key_deselected", varray(p_track), CONNECT_DEFERRED); + connect("select_key", Callable(editor, "_key_selected"), varray(p_track), CONNECT_DEFERRED); + connect("deselect_key", Callable(editor, "_key_deselected"), varray(p_track), CONNECT_DEFERRED); update(); } @@ -533,7 +533,7 @@ void AnimationBezierTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) { void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) { editor = p_editor; - connect_compat("clear_selection", editor, "_clear_selection", varray(false)); + connect("clear_selection", Callable(editor, "_clear_selection"), varray(false)); } void AnimationBezierTrackEdit::_play_position_draw() { diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h index 217393a3b3..1b7ed8f06c 100644 --- a/editor/animation_bezier_editor.h +++ b/editor/animation_bezier_editor.h @@ -111,10 +111,10 @@ class AnimationBezierTrackEdit : public Control { Vector2 menu_insert_key; struct AnimMoveRestore { - int track; - float time; + int track = 0; + float time = 0; Variant key; - float transition; + float transition = 0; }; AnimationTrackEditor *editor; diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index b1ffb1dc52..7411af2280 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -44,7 +44,7 @@ class AnimationTrackKeyEdit : public Object { GDCLASS(AnimationTrackKeyEdit, Object); public: - bool setting; + bool setting = false; bool _hide_script_from_inspector() { return true; @@ -622,15 +622,15 @@ public: } } - UndoRedo *undo_redo; + UndoRedo *undo_redo = nullptr; Ref<Animation> animation; - int track; - float key_ofs; - Node *root_path; + int track = -1; + float key_ofs = 0; + Node *root_path = nullptr; PropertyInfo hint; NodePath base; - bool use_fps; + bool use_fps = false; void notify_change() { _change_notify(); @@ -644,21 +644,13 @@ public: use_fps = p_enable; _change_notify(); } - - AnimationTrackKeyEdit() { - use_fps = false; - key_ofs = 0; - track = -1; - setting = false; - root_path = nullptr; - } }; class AnimationMultiTrackKeyEdit : public Object { GDCLASS(AnimationMultiTrackKeyEdit, Object); public: - bool setting; + bool setting = false; bool _hide_script_from_inspector() { return true; @@ -1276,11 +1268,11 @@ public: Map<int, NodePath> base_map; PropertyInfo hint; - Node *root_path; + Node *root_path = nullptr; - bool use_fps; + bool use_fps = false; - UndoRedo *undo_redo; + UndoRedo *undo_redo = nullptr; void notify_change() { _change_notify(); @@ -1294,12 +1286,6 @@ public: use_fps = p_enable; _change_notify(); } - - AnimationMultiTrackKeyEdit() { - use_fps = false; - setting = false; - root_path = nullptr; - } }; void AnimationTimelineEdit::_zoom_changed(double) { @@ -2231,10 +2217,6 @@ void AnimationTrackEdit::draw_bg(int p_clip_left, int p_clip_right) { void AnimationTrackEdit::draw_fg(int p_clip_left, int p_clip_right) { } -void AnimationTrackEdit::draw_texture_clipped(const Ref<Texture2D> &p_texture, const Vector2 &p_pos) { - draw_texture_region_clipped(p_texture, Rect2(p_pos, p_texture->get_size()), Rect2(Point2(), p_texture->get_size())); -} - void AnimationTrackEdit::draw_texture_region_clipped(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_region) { int clip_left = timeline->get_name_limit(); int clip_right = get_size().width - timeline->get_buttons_width(); @@ -4669,10 +4651,10 @@ void AnimationTrackEditor::_move_selection(float p_offset) { } struct _AnimMoveRestore { - int track; - float time; + int track = 0; + float time = 0; Variant key; - float transition; + float transition = 0; }; //used for undo/redo diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index a31ca892ef..3cb31fe21e 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -207,7 +207,6 @@ public: virtual void draw_fg(int p_clip_left, int p_clip_right); //helper - void draw_texture_clipped(const Ref<Texture2D> &p_texture, const Vector2 &p_pos); void draw_texture_region_clipped(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_region); void draw_rect_clipped(const Rect2 &p_rect, const Color &p_color, bool p_filled = true); @@ -253,8 +252,8 @@ class AnimationTrackEditGroup : public Control { Ref<Texture2D> icon; String node_name; NodePath node; - Node *root; - AnimationTimelineEdit *timeline; + Node *root = nullptr; + AnimationTimelineEdit *timeline = nullptr; void _zoom_changed(); @@ -354,10 +353,10 @@ class AnimationTrackEditor : public VBoxContainer { struct InsertData { Animation::TrackType type; NodePath path; - int track_idx; + int track_idx = 0; Variant value; String query; - bool advance; + bool advance = false; }; /* insert_data;*/ Label *insert_confirm_text; @@ -392,13 +391,13 @@ class AnimationTrackEditor : public VBoxContainer { //selection struct SelectedKey { - int track; - int key; + int track = 0; + int key = 0; bool operator<(const SelectedKey &p_key) const { return track == p_key.track ? key < p_key.key : track < p_key.track; }; }; struct KeyInfo { - float pos; + float pos = 0; }; Map<SelectedKey, KeyInfo> selection; @@ -467,15 +466,15 @@ class AnimationTrackEditor : public VBoxContainer { struct TrackClipboard { NodePath full_path; NodePath base_path; - Animation::TrackType track_type; - Animation::InterpolationType interp_type; - Animation::UpdateMode update_mode; - bool loop_wrap; - bool enabled; + Animation::TrackType track_type = Animation::TrackType::TYPE_ANIMATION; + Animation::InterpolationType interp_type = Animation::InterpolationType::INTERPOLATION_CUBIC; + Animation::UpdateMode update_mode = Animation::UpdateMode::UPDATE_CAPTURE; + bool loop_wrap = false; + bool enabled = false; struct Key { - float time; - float transition; + float time = 0; + float transition = 0; Variant value; }; Vector<Key> keys; diff --git a/editor/audio_stream_preview.h b/editor/audio_stream_preview.h index 97a582836c..300f1dc5ca 100644 --- a/editor/audio_stream_preview.h +++ b/editor/audio_stream_preview.h @@ -60,9 +60,9 @@ class AudioStreamPreviewGenerator : public Node { Ref<AudioStreamPreview> preview; Ref<AudioStream> base_stream; Ref<AudioStreamPlayback> playback; - volatile bool generating; + volatile bool generating = false; ObjectID id; - Thread *thread; + Thread *thread = nullptr; }; Map<ObjectID, Preview> previews; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 823fd7e852..3dd0977478 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -81,6 +81,8 @@ GotoLineDialog::GotoLineDialog() { register_text_enter(line); text_editor = nullptr; + line_label = nullptr; + set_hide_on_ok(false); } @@ -873,7 +875,7 @@ Ref<Texture2D> CodeTextEditor::_get_completion_icon(const ScriptCodeCompletionOp tex = get_theme_icon("MemberMethod", "EditorIcons"); break; case ScriptCodeCompletionOption::KIND_PLAIN_TEXT: - tex = get_theme_icon("CubeMesh", "EditorIcons"); + tex = get_theme_icon("BoxMesh", "EditorIcons"); break; default: tex = get_theme_icon("String", "EditorIcons"); diff --git a/editor/debugger/editor_profiler.h b/editor/debugger/editor_profiler.h index aa2ef58db4..637f732b0b 100644 --- a/editor/debugger/editor_profiler.h +++ b/editor/debugger/editor_profiler.h @@ -45,27 +45,27 @@ class EditorProfiler : public VBoxContainer { public: struct Metric { - bool valid; + bool valid = false; - int frame_number; - float frame_time; - float idle_time; - float physics_time; - float physics_frame_time; + int frame_number = 0; + float frame_time = 0; + float idle_time = 0; + float physics_time = 0; + float physics_frame_time = 0; struct Category { StringName signature; String name; - float total_time; //total for category + float total_time = 0; //total for category struct Item { StringName signature; String name; String script; - int line; - float self; - float total; - int calls; + int line = 0; + float self = 0; + float total = 0; + int calls = 0; }; Vector<Item> items; @@ -75,11 +75,6 @@ public: Map<StringName, Category *> category_ptrs; Map<StringName, Category::Item *> item_ptrs; - - Metric() { - valid = false; - frame_number = 0; - } }; enum DisplayMode { diff --git a/editor/debugger/editor_visual_profiler.h b/editor/debugger/editor_visual_profiler.h index 3c1a55dc38..49a2d5c53a 100644 --- a/editor/debugger/editor_visual_profiler.h +++ b/editor/debugger/editor_visual_profiler.h @@ -46,9 +46,9 @@ class EditorVisualProfiler : public VBoxContainer { public: struct Metric { - bool valid; + bool valid = false; - uint64_t frame_number; + uint64_t frame_number = 0; struct Area { String name; @@ -59,10 +59,6 @@ public: }; Vector<Area> areas; - - Metric() { - valid = false; - } }; enum DisplayTimeMode { diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 527286583e..1a7a30ba4e 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -626,6 +626,8 @@ DependencyErrorDialog::DependencyErrorDialog() { vb->add_child(text); text->set_text(TTR("Which action should be taken?")); + mode = Mode::MODE_RESOURCE; + fdep = add_button(TTR("Fix Dependencies"), true, "fixdeps"); set_title(TTR("Errors loading!")); diff --git a/editor/editor_atlas_packer.h b/editor/editor_atlas_packer.h index 52ac9524ae..4a9c3a776b 100644 --- a/editor/editor_atlas_packer.h +++ b/editor/editor_atlas_packer.h @@ -41,23 +41,23 @@ public: struct Chart { Vector<Vector2> vertices; struct Face { - int vertex[3]; + int vertex[3] = { 0 }; }; Vector<Face> faces; - bool can_transpose; + bool can_transpose = false; Vector2 final_offset; - bool transposed; + bool transposed = false; }; private: struct PlottedBitmap { - int chart_index; + int chart_index = 0; Vector2i offset; - int area; + int area = 0; Vector<int> top_heights; Vector<int> bottom_heights; - bool transposed; + bool transposed = false; Vector2 final_pos; diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h index 01221ad6ef..f72541100d 100644 --- a/editor/editor_audio_buses.h +++ b/editor/editor_audio_buses.h @@ -61,13 +61,13 @@ class EditorAudioBus : public PanelContainer { static const int CHANNELS_MAX = 4; struct { - bool prev_active; + bool prev_active = false; - float peak_l; - float peak_r; + float peak_l = 0; + float peak_r = 0; - TextureProgress *vu_l; - TextureProgress *vu_r; + TextureProgress *vu_l = nullptr; + TextureProgress *vu_r = nullptr; } channel[CHANNELS_MAX]; OptionButton *send; @@ -214,9 +214,9 @@ class EditorAudioMeterNotches : public Control { private: struct AudioNotch { - float relative_position; - float db_value; - bool render_db_value; + float relative_position = 0; + float db_value = 0; + bool render_db_value = false; _FORCE_INLINE_ AudioNotch(float r_pos, float db_v, bool rndr_val) { relative_position = r_pos; diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h index 646fe3992c..845f86fbb9 100644 --- a/editor/editor_autoload_settings.h +++ b/editor/editor_autoload_settings.h @@ -50,20 +50,14 @@ class EditorAutoloadSettings : public VBoxContainer { struct AutoLoadInfo { String name; String path; - bool is_singleton; - bool in_editor; - int order; - Node *node; + bool is_singleton = false; + bool in_editor = false; + int order = 0; + Node *node = nullptr; bool operator==(const AutoLoadInfo &p_info) const { return order == p_info.order; } - - AutoLoadInfo() { - is_singleton = false; - in_editor = false; - node = nullptr; - } }; List<AutoLoadInfo> autoload_cache; diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 975405aec4..eab1ecf373 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -691,11 +691,6 @@ void EditorData::set_edited_scene_version(uint64_t version, int p_scene_idx) { } } -uint64_t EditorData::get_edited_scene_version() const { - ERR_FAIL_INDEX_V(current_edited_scene, edited_scene.size(), 0); - return edited_scene[current_edited_scene].version; -} - uint64_t EditorData::get_scene_version(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), 0); return edited_scene[p_idx].version; diff --git a/editor/editor_data.h b/editor/editor_data.h index eec95554be..0d27e06987 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -47,12 +47,12 @@ class EditorHistory { REF ref; ObjectID object; String property; - bool inspector_only; + bool inspector_only = false; }; struct History { Vector<Obj> path; - int level; + int level = 0; }; friend class EditorData; @@ -109,14 +109,14 @@ public: }; struct EditedScene { - Node *root; + Node *root = nullptr; String path; Dictionary editor_states; List<Node *> selection; Vector<EditorHistory::History> history_stored; - int history_current; + int history_current = 0; Dictionary custom_state; - uint64_t version; + uint64_t version = 0; NodePath live_edit_root; }; @@ -190,7 +190,6 @@ public: void set_scene_path(int p_idx, const String &p_path); Ref<Script> get_scene_root_script(int p_idx) const; void set_edited_scene_version(uint64_t version, int p_scene_idx = -1); - uint64_t get_edited_scene_version() const; uint64_t get_scene_version(int p_idx) const; void clear_edited_scenes(); void set_edited_scene_live_edit_root(const NodePath &p_root); diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index f7cb5428ce..07318c14bc 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -1835,17 +1835,10 @@ void EditorExportPlatformPC::set_debug_32(const String &p_file) { debug_file_32 = p_file; } -void EditorExportPlatformPC::add_platform_feature(const String &p_feature) { - extra_features.insert(p_feature); -} - void EditorExportPlatformPC::get_platform_features(List<String> *r_features) { r_features->push_back("pc"); //all pcs support "pc" r_features->push_back("s3tc"); //all pcs support "s3tc" compression r_features->push_back(get_os_name()); //OS name is a feature - for (Set<String>::Element *E = extra_features.front(); E; E = E->next()) { - r_features->push_back(E->get()); - } } void EditorExportPlatformPC::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) { diff --git a/editor/editor_export.h b/editor/editor_export.h index 09feaad255..584ef17035 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -169,9 +169,9 @@ public: private: struct SavedData { - uint64_t ofs; - uint64_t size; - bool encrypted; + uint64_t ofs = 0; + uint64_t size = 0; + bool encrypted = false; Vector<uint8_t> md5; CharString path_utf8; @@ -181,15 +181,15 @@ private: }; struct PackData { - FileAccess *f; + FileAccess *f = nullptr; Vector<SavedData> file_ofs; - EditorProgress *ep; - Vector<SharedObject> *so_files; + EditorProgress *ep = nullptr; + Vector<SharedObject> *so_files = nullptr; }; struct ZipData { - void *zip; - EditorProgress *ep; + void *zip = nullptr; + EditorProgress *ep = nullptr; }; struct FeatureContainers { @@ -294,7 +294,7 @@ class EditorExportPlugin : public Reference { struct ExtraFile { String path; Vector<uint8_t> data; - bool remap; + bool remap = false; }; Vector<ExtraFile> extra_files; bool skipped; @@ -424,8 +424,6 @@ private: String debug_file_32; String debug_file_64; - Set<String> extra_features; - int chmod_flags; FixUpEmbeddedPckFunc fixup_embedded_pck_func; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 738b88a86b..43f0c9e2bb 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1044,10 +1044,6 @@ void EditorFileSystem::_thread_func_sources(void *_userdata) { efs->scanning_changes_done = true; } -void EditorFileSystem::get_changed_sources(List<String> *r_changed) { - *r_changed = sources_changed; -} - void EditorFileSystem::scan_changes() { if (first_scan || // Prevent a premature changes scan from inhibiting the first full scan scanning || scanning_changes || thread) { diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index d5ae046c36..a7ab4d6a9a 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -52,12 +52,12 @@ class EditorFileSystemDirectory : public Object { struct FileInfo { String file; StringName type; - uint64_t modified_time; - uint64_t import_modified_time; - bool import_valid; + uint64_t modified_time = 0; + uint64_t import_modified_time = 0; + bool import_valid = false; String import_group_file; Vector<String> deps; - bool verified; //used for checking changes + bool verified = false; //used for checking changes String script_class_name; String script_class_extends; String script_class_icon_path; @@ -119,18 +119,11 @@ class EditorFileSystem : public Node { ACTION_FILE_RELOAD }; - Action action; - EditorFileSystemDirectory *dir; + Action action = ACTION_NONE; + EditorFileSystemDirectory *dir = nullptr; String file; - EditorFileSystemDirectory *new_dir; - EditorFileSystemDirectory::FileInfo *new_file; - - ItemAction() { - action = ACTION_NONE; - dir = nullptr; - new_dir = nullptr; - new_file = nullptr; - } + EditorFileSystemDirectory *new_dir = nullptr; + EditorFileSystemDirectory::FileInfo *new_file = nullptr; }; bool use_threads; @@ -162,10 +155,10 @@ class EditorFileSystem : public Node { /* Used for reading the filesystem cache file */ struct FileCache { String type; - uint64_t modification_time; - uint64_t import_modification_time; + uint64_t modification_time = 0; + uint64_t import_modification_time = 0; Vector<String> deps; - bool import_valid; + bool import_valid = false; String import_group_file; String script_class_name; String script_class_extends; @@ -175,9 +168,9 @@ class EditorFileSystem : public Node { HashMap<String, FileCache> file_cache; struct ScanProgress { - float low; - float hi; - mutable EditorProgressBG *progress; + float low = 0; + float hi = 0; + mutable EditorProgressBG *progress = nullptr; void update(int p_current, int p_total) const; ScanProgress get_sub(int p_current, int p_total) const; }; @@ -220,7 +213,7 @@ class EditorFileSystem : public Node { struct ImportFile { String path; - int order; + int order = 0; bool operator<(const ImportFile &p_if) const { return order < p_if.order; } @@ -255,7 +248,6 @@ public: float get_scanning_progress() const; void scan(); void scan_changes(); - void get_changed_sources(List<String> *r_changed); void update_file(const String &p_file); EditorFileSystemDirectory *get_filesystem_path(const String &p_path); diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index f5bb4921d4..23dc69af12 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -161,6 +161,14 @@ void editor_register_fonts(Ref<Theme> p_theme) { CustomFontSource->load_resource(custom_font_path_source, default_font_size); CustomFontSource->set_antialiased(font_antialiased); CustomFontSource->set_hinting(font_hinting); + + Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations")).split(","); + for (int i = 0; i < subtag.size(); i++) { + Vector<String> subtag_a = subtag[i].split("="); + if (subtag_a.size() == 2) { + CustomFontSource->set_variation(subtag_a[0], subtag_a[1].to_float()); + } + } } else { EditorSettings::get_singleton()->set_manually("interface/editor/code_font", ""); } @@ -282,6 +290,15 @@ void editor_register_fonts(Ref<Theme> p_theme) { dfmono->set_antialiased(font_antialiased); dfmono->set_hinting(font_hinting); + Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations")).split(","); + Dictionary ftrs; + for (int i = 0; i < subtag.size(); i++) { + Vector<String> subtag_a = subtag[i].split("="); + if (subtag_a.size() == 2) { + dfmono->set_variation(subtag_a[0], subtag_a[1].to_float()); + } + } + // Default font MAKE_DEFAULT_FONT(df); p_theme->set_default_theme_font(df); // Default theme font diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 4c553950a7..41010b6a86 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -230,7 +230,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview if (p_overview) { class_desc->push_cell(); - class_desc->push_align(RichTextLabel::ALIGN_RIGHT); + class_desc->push_paragraph(RichTextLabel::ALIGN_RIGHT, Control::TEXT_DIRECTION_AUTO, ""); } else { static const char32_t prefix[3] = { 0x25CF /* filled circle */, ' ', 0 }; class_desc->add_text(String(prefix)); @@ -528,7 +528,7 @@ void EditorHelp::_update_doc() { property_line[cd.properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description class_desc->push_cell(); - class_desc->push_align(RichTextLabel::ALIGN_RIGHT); + class_desc->push_paragraph(RichTextLabel::ALIGN_RIGHT, Control::TEXT_DIRECTION_AUTO, ""); class_desc->push_font(doc_code_font); _add_type(cd.properties[i].type, cd.properties[i].enumeration); class_desc->pop(); @@ -729,7 +729,7 @@ void EditorHelp::_update_doc() { theme_property_line[cd.theme_properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description class_desc->push_cell(); - class_desc->push_align(RichTextLabel::ALIGN_RIGHT); + class_desc->push_paragraph(RichTextLabel::ALIGN_RIGHT, Control::TEXT_DIRECTION_AUTO, ""); class_desc->push_font(doc_code_font); _add_type(cd.theme_properties[i].type); class_desc->pop(); @@ -1500,7 +1500,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { tag_stack.push_front(tag); } else if (tag == "center") { //align to center - p_rt->push_align(RichTextLabel::ALIGN_CENTER); + p_rt->push_paragraph(RichTextLabel::ALIGN_CENTER, Control::TEXT_DIRECTION_AUTO, ""); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "br") { diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h index f1aab6cc81..cb52c515de 100644 --- a/editor/editor_help_search.h +++ b/editor/editor_help_search.h @@ -98,7 +98,7 @@ class EditorHelpSearch::Runner : public Reference { struct ClassMatch { DocData::ClassDoc *doc; - bool name; + bool name = false; Vector<DocData::MethodDoc *> methods; Vector<DocData::MethodDoc *> signals; Vector<DocData::ConstantDoc *> constants; @@ -118,12 +118,12 @@ class EditorHelpSearch::Runner : public Reference { Ref<Texture2D> empty_icon; Color disabled_color; - Map<String, DocData::ClassDoc>::Element *iterator_doc; + Map<String, DocData::ClassDoc>::Element *iterator_doc = nullptr; Map<String, ClassMatch> matches; - Map<String, ClassMatch>::Element *iterator_match; - TreeItem *root_item; + Map<String, ClassMatch>::Element *iterator_match = nullptr; + TreeItem *root_item = nullptr; Map<String, TreeItem *> class_items; - TreeItem *matched_item; + TreeItem *matched_item = nullptr; bool _is_class_disabled_by_feature_profile(const StringName &p_class); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index d88a0e3ff8..dd136c046f 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -963,6 +963,7 @@ EditorProperty::EditorProperty() { selected_focusable = -1; label_reference = nullptr; bottom_editor = nullptr; + delete_hover = false; } //////////////////////////////////////////////// diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 10b1013486..d901bb4ecf 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -176,7 +176,7 @@ class EditorInspectorPlugin : public Reference { friend class EditorInspector; struct AddedEditor { - Control *property_editor; + Control *property_editor = nullptr; Vector<String> properties; String label; }; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 27be3bcc14..8cdb865937 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -58,7 +58,9 @@ #include "scene/gui/tab_container.h" #include "scene/gui/tabs.h" #include "scene/gui/texture_progress.h" +#include "scene/main/window.h" #include "scene/resources/packed_scene.h" +#include "servers/display_server.h" #include "servers/navigation_server_2d.h" #include "servers/navigation_server_3d.h" #include "servers/physics_server_2d.h" @@ -172,13 +174,10 @@ #include "editor/progress_dialog.h" #include "editor/project_export.h" #include "editor/project_settings_editor.h" -#include "editor/pvrtc_compress.h" #include "editor/quick_open.h" #include "editor/register_exporters.h" -#include "editor/run_settings_dialog.h" #include "editor/settings_config_dialog.h" -#include "scene/main/window.h" -#include "servers/display_server.h" + #include <stdio.h> #include <stdlib.h> @@ -2557,9 +2556,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { run_play_current(); } break; - case RUN_SCENE_SETTINGS: { - run_settings_dialog->popup_run_settings(); - } break; case RUN_SETTINGS: { project_settings->popup_project_settings(); } break; @@ -3658,6 +3654,9 @@ void EditorNode::register_editor_types() { ClassDB::register_class<ScriptCreateDialog>(); ClassDB::register_class<EditorFeatureProfile>(); ClassDB::register_class<EditorSpinSlider>(); + ClassDB::register_class<EditorSceneImporterMesh>(); + ClassDB::register_class<EditorSceneImporterMeshNode>(); + ClassDB::register_virtual_class<FileSystemDock>(); // FIXME: Is this stuff obsolete, or should it be ported to new APIs? @@ -4708,7 +4707,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) { _update_scene_tabs(); } -void EditorNode::_scene_tab_hover(int p_tab) { +void EditorNode::_scene_tab_hovered(int p_tab) { if (!bool(EDITOR_GET("interface/scene_tabs/show_thumbnail_on_hover"))) { return; } @@ -4836,16 +4835,6 @@ Button *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) { return tb; } -bool EditorNode::are_bottom_panels_hidden() const { - for (int i = 0; i < bottom_panel_items.size(); i++) { - if (bottom_panel_items[i].button->is_pressed()) { - return false; - } - } - - return true; -} - void EditorNode::hide_bottom_panel() { for (int i = 0; i < bottom_panel_items.size(); i++) { if (bottom_panel_items[i].control->is_visible()) { @@ -5740,8 +5729,6 @@ EditorNode::EditorNode() { EditorInspector::add_inspector_plugin(smp); } - _pvrtc_register_compressors(); - editor_selection = memnew(EditorSelection); EditorFileSystem *efs = memnew(EditorFileSystem); @@ -5996,8 +5983,8 @@ EditorNode::EditorNode() { scene_tabs->set_drag_to_rearrange_enabled(true); scene_tabs->connect("tab_changed", callable_mp(this, &EditorNode::_scene_tab_changed)); scene_tabs->connect("right_button_pressed", callable_mp(this, &EditorNode::_scene_tab_script_edited)); - scene_tabs->connect("tab_close", callable_mp(this, &EditorNode::_scene_tab_closed), varray(SCENE_TAB_CLOSE)); - scene_tabs->connect("tab_hover", callable_mp(this, &EditorNode::_scene_tab_hover)); + scene_tabs->connect("tab_closed", callable_mp(this, &EditorNode::_scene_tab_closed), varray(SCENE_TAB_CLOSE)); + scene_tabs->connect("tab_hovered", callable_mp(this, &EditorNode::_scene_tab_hovered)); scene_tabs->connect("mouse_exited", callable_mp(this, &EditorNode::_scene_tab_exit)); scene_tabs->connect("gui_input", callable_mp(this, &EditorNode::_scene_tab_input)); scene_tabs->connect("reposition_active_tab_request", callable_mp(this, &EditorNode::_reposition_active_tab)); @@ -6091,9 +6078,6 @@ EditorNode::EditorNode() { project_settings = memnew(ProjectSettingsEditor(&editor_data)); gui_base->add_child(project_settings); - run_settings_dialog = memnew(RunSettingsDialog); - gui_base->add_child(run_settings_dialog); - export_template_manager = memnew(ExportTemplateManager); gui_base->add_child(export_template_manager); diff --git a/editor/editor_node.h b/editor/editor_node.h index dec28b0d2b..b727bce1e4 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -107,10 +107,10 @@ public: String path; List<String> args; String output; - Thread *execute_output_thread; + Thread *execute_output_thread = nullptr; Mutex execute_output_mutex; - int exitcode; - volatile bool done; + int exitcode = 0; + volatile bool done = false; }; private: @@ -161,7 +161,6 @@ private: RUN_STOP, RUN_PLAY_SCENE, RUN_PLAY_CUSTOM_SCENE, - RUN_SCENE_SETTINGS, RUN_SETTINGS, RUN_PROJECT_DATA_FOLDER, RUN_PROJECT_MANAGER, @@ -312,7 +311,6 @@ private: ConfirmationDialog *remove_android_build_template; EditorSettingsDialog *settings_config_dialog; - RunSettingsDialog *run_settings_dialog; ProjectSettingsEditor *project_settings; PopupMenu *vcs_actions_menu; EditorFileDialog *file; @@ -409,8 +407,8 @@ private: struct BottomPanelItem { String name; - Control *control; - Button *button; + Control *control = nullptr; + Button *button = nullptr; }; Vector<BottomPanelItem> bottom_panel_items; @@ -554,8 +552,8 @@ private: struct ExportDefer { String preset; String path; - bool debug; - bool pack_only; + bool debug = false; + bool pack_only = false; } export_defer; bool cmdline_export_mode; @@ -579,7 +577,7 @@ private: void _dock_make_float(); void _scene_tab_changed(int p_tab); void _scene_tab_closed(int p_tab, int option = SCENE_TAB_CLOSE); - void _scene_tab_hover(int p_tab); + void _scene_tab_hovered(int p_tab); void _scene_tab_exit(); void _scene_tab_input(const Ref<InputEvent> &p_input); void _reposition_active_tab(int idx_to); @@ -824,7 +822,6 @@ public: Button *get_pause_button() { return pause_button; } Button *add_bottom_panel_item(String p_text, Control *p_item); - bool are_bottom_panels_hidden() const; void make_bottom_panel_item_visible(Control *p_item); void raise_bottom_panel_item(Control *p_item); void hide_bottom_panel(); diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index f984f48c1c..1fdba10a74 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -42,7 +42,7 @@ void EditorPluginSettings::_notification(int p_what) { if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN) { update_plugins(); } else if (p_what == Node::NOTIFICATION_READY) { - plugin_config_dialog->connect_compat("plugin_ready", EditorNode::get_singleton(), "_on_plugin_ready"); + plugin_config_dialog->connect("plugin_ready", Callable(EditorNode::get_singleton(), "_on_plugin_ready")); plugin_list->connect("button_pressed", callable_mp(this, &EditorPluginSettings::_cell_button_pressed)); } } diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 828b639527..63dee9f6d6 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -41,7 +41,7 @@ class EditorPropertyNil : public EditorProperty { GDCLASS(EditorPropertyNil, EditorProperty); - LineEdit *text; + LineEdit *text = nullptr; public: virtual void update_property() override; diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index 2f4bc65de9..05a4e1bafb 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -77,9 +77,9 @@ class EditorResourcePreview : public Node { struct Item { Ref<Texture2D> preview; Ref<Texture2D> small_preview; - int order; - uint32_t last_hash; - uint64_t modified_time; + int order = 0; + uint32_t last_hash = 0; + uint64_t modified_time = 0; }; int order; diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index cf19b54cff..bc9ca15467 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -35,9 +35,9 @@ class SectionedInspectorFilter : public Object { GDCLASS(SectionedInspectorFilter, Object); - Object *edited; + Object *edited = nullptr; String section; - bool allow_sub; + bool allow_sub = false; bool _set(const StringName &p_name, const Variant &p_value) { if (!edited) { @@ -123,10 +123,6 @@ public: edited = p_edited; _change_notify(); } - - SectionedInspectorFilter() { - edited = nullptr; - } }; void SectionedInspector::_bind_methods() { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 0ea112d48c..0840707886 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -158,10 +158,10 @@ void EditorSettings::_initial_set(const StringName &p_name, const Variant &p_val struct _EVCSort { String name; - Variant::Type type; - int order; - bool save; - bool restart_if_changed; + Variant::Type type = Variant::Type::NIL; + int order = 0; + bool save = false; + bool restart_if_changed = false; bool operator<(const _EVCSort &p_vcs) const { return order < p_vcs.order; } }; @@ -336,6 +336,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("interface/editor/code_font_contextual_ligatures", 0); hints["interface/editor/code_font_contextual_ligatures"] = PropertyInfo(Variant::INT, "interface/editor/code_font_contextual_ligatures", PROPERTY_HINT_ENUM, "Default,Disable contextual alternates (coding ligatures),Use custom OpenType feature set", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/code_font_custom_opentype_features", ""); + _initial_set("interface/editor/code_font_custom_variations", ""); _initial_set("interface/editor/font_antialiased", true); _initial_set("interface/editor/font_hinting", 0); hints["interface/editor/font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/font_hinting", PROPERTY_HINT_ENUM, "Auto,None,Light,Normal", PROPERTY_USAGE_DEFAULT); @@ -407,15 +408,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("filesystem/file_dialog/thumbnail_size", 64); hints["filesystem/file_dialog/thumbnail_size"] = PropertyInfo(Variant::INT, "filesystem/file_dialog/thumbnail_size", PROPERTY_HINT_RANGE, "32,128,16"); - // Import - _initial_set("filesystem/import/pvrtc_texture_tool", ""); -#ifdef WINDOWS_ENABLED - hints["filesystem/import/pvrtc_texture_tool"] = PropertyInfo(Variant::STRING, "filesystem/import/pvrtc_texture_tool", PROPERTY_HINT_GLOBAL_FILE, "*.exe"); -#else - hints["filesystem/import/pvrtc_texture_tool"] = PropertyInfo(Variant::STRING, "filesystem/import/pvrtc_texture_tool", PROPERTY_HINT_GLOBAL_FILE, ""); -#endif - _initial_set("filesystem/import/pvrtc_fast_conversion", false); - /* Docks */ // SceneTree @@ -1539,11 +1531,6 @@ Ref<Shortcut> ED_GET_SHORTCUT(const String &p_path) { return sc; } -struct ShortcutMapping { - const char *path; - uint32_t keycode; -}; - Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, uint32_t p_keycode) { #ifdef OSX_ENABLED // Use Cmd+Backspace as a general replacement for Delete shortcuts on macOS diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 41e6bab4ba..3061da4d43 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -47,13 +47,13 @@ class EditorSettings : public Resource { public: struct Plugin { - EditorPlugin *instance; + EditorPlugin *instance = nullptr; String path; String name; String author; String version; String description; - bool installs; + bool installs = false; String script; Vector<String> install_files; }; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index c589a3c042..723499ca9a 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -692,6 +692,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color_hover", "PopupMenu", font_color_hl); theme->set_color("font_color_accel", "PopupMenu", font_color_disabled); theme->set_color("font_color_disabled", "PopupMenu", font_color_disabled); + theme->set_color("font_color_separator", "PopupMenu", font_color_disabled); theme->set_icon("checked", "PopupMenu", theme->get_icon("GuiChecked", "EditorIcons")); theme->set_icon("unchecked", "PopupMenu", theme->get_icon("GuiUnchecked", "EditorIcons")); theme->set_icon("radio_checked", "PopupMenu", theme->get_icon("GuiRadioChecked", "EditorIcons")); diff --git a/editor/fileserver/editor_file_server.h b/editor/fileserver/editor_file_server.h index ca5a891856..6d3c0d0d47 100644 --- a/editor/fileserver/editor_file_server.h +++ b/editor/fileserver/editor_file_server.h @@ -47,11 +47,11 @@ class EditorFileServer : public Object { }; struct ClientData { - Thread *thread; + Thread *thread = nullptr; Ref<StreamPeerTCP> connection; Map<int, FileAccess *> files; - EditorFileServer *efs; - bool quit; + EditorFileServer *efs = nullptr; + bool quit = false; }; Ref<TCP_Server> server; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index aa19bdf342..364c52d633 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1505,7 +1505,8 @@ void FileSystemDock::_move_with_overwrite() { _move_operation_confirm(to_move_path, true); } -bool FileSystemDock::_check_existing() { +Vector<String> FileSystemDock::_check_existing() { + Vector<String> conflicting_items; String &p_to_path = to_move_path; for (int i = 0; i < to_move.size(); i++) { String ol_pth = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path; @@ -1515,21 +1516,24 @@ bool FileSystemDock::_check_existing() { String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/"); String new_path = (p_item.is_file || p_new_path.ends_with("/")) ? p_new_path : (p_new_path + "/"); - if (p_item.is_file && FileAccess::exists(new_path)) { - return false; - } else if (!p_item.is_file && DirAccess::exists(new_path)) { - return false; + if ((p_item.is_file && FileAccess::exists(new_path)) || + (!p_item.is_file && DirAccess::exists(new_path))) { + conflicting_items.push_back(old_path); } } - return true; + return conflicting_items; } void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_overwrite) { if (!p_overwrite) { to_move_path = p_to_path; - bool can_move = _check_existing(); - if (!can_move) { + Vector<String> conflicting_items = _check_existing(); + if (!conflicting_items.empty()) { // Ask to do something. + overwrite_dialog->set_text(vformat( + TTR("The following files or folders conflict with items in the target location '%s':\n\n%s\n\nDo you wish to overwrite them?"), + to_move_path, + String("\n").join(conflicting_items))); overwrite_dialog->popup_centered(); return; } @@ -2849,7 +2853,6 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { rename_dialog->connect("confirmed", callable_mp(this, &FileSystemDock::_rename_operation_confirm)); overwrite_dialog = memnew(ConfirmationDialog); - overwrite_dialog->set_text(TTR("There is already file or folder with the same name in this location.")); overwrite_dialog->get_ok()->set_text(TTR("Overwrite")); add_child(overwrite_dialog); overwrite_dialog->connect("confirmed", callable_mp(this, &FileSystemDock::_move_with_overwrite)); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 1db1485426..4b93931ba7 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -236,7 +236,7 @@ private: void _rename_operation_confirm(); void _duplicate_operation_confirm(); void _move_with_overwrite(); - bool _check_existing(); + Vector<String> _check_existing(); void _move_operation_confirm(const String &p_to_path, bool p_overwrite = false); void _tree_rmb_option(int p_option); @@ -270,8 +270,8 @@ private: String path; StringName type; Vector<String> sources; - bool import_broken; - uint64_t modified_time; + bool import_broken = false; + uint64_t modified_time = 0; bool operator<(const FileInfo &fi) const { return NaturalNoCaseComparator()(name, fi.name); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 8d3f0eb21f..abcb7bbd93 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -86,11 +86,6 @@ static bool find_next(const String &line, String pattern, int from, bool match_c } //-------------------------------------------------------------------------------- -FindInFiles::FindInFiles() { - _searching = false; - _whole_words = true; - _match_case = true; -} void FindInFiles::set_search_text(String p_pattern) { _pattern = p_pattern; diff --git a/editor/find_in_files.h b/editor/find_in_files.h index 3b949a35b4..d4755c7b50 100644 --- a/editor/find_in_files.h +++ b/editor/find_in_files.h @@ -42,8 +42,6 @@ public: static const char *SIGNAL_RESULT_FOUND; static const char *SIGNAL_FINISHED; - FindInFiles(); - void set_search_text(String p_pattern); void set_whole_words(bool p_whole_word); void set_match_case(bool p_match_case); @@ -76,15 +74,15 @@ private: String _pattern; Set<String> _extension_filter; String _root_dir; - bool _whole_words; - bool _match_case; + bool _whole_words = true; + bool _match_case = true; // State - bool _searching; + bool _searching = false; String _current_dir; Vector<PackedStringArray> _folders_stack; Vector<String> _files_to_scan; - int _initial_files_count; + int _initial_files_count = 0; }; class LineEdit; @@ -188,10 +186,10 @@ private: void _on_replace_all_clicked(); struct Result { - int line_number; - int begin; - int end; - int begin_trimmed; + int line_number = 0; + int begin = 0; + int end = 0; + int begin_trimmed = 0; }; void apply_replaces_in_file(String fpath, const Vector<Result> &locations, String new_text); diff --git a/editor/icons/AudioStreamMP3.svg b/editor/icons/AudioStreamMP3.svg new file mode 100644 index 0000000000..900d5873fe --- /dev/null +++ b/editor/icons/AudioStreamMP3.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="8" x2="8" y1="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m11.971 1.002c-.08326.00207-.16593.014541-.24609.037109l-7 2c-.42881.12287-.7244.51487-.72461.96094v5.5508c-.16454-.033679-.33205-.050692-.5-.050781-1.3807 0-2.5 1.1193-2.5 2.5-.00000475 1.3807 1.1193 2.5 2.5 2.5 1.3456-.0013 2.4488-1.0674 2.4961-2.4121.0025906-.029226.003894-.058551.0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5c-.000916-.56314-.4664-1.0145-1.0293-.99805zm-1.4707 6.998c-.277 0-.5.223-.5.5v5c0 .277.223.5.5.5s.5-.223.5-.5v-5c0-.277-.223-.5-.5-.5zm2 1c-.277 0-.5.223-.5.5v3c0 .277.223.5.5.5s.5-.223.5-.5v-3c0-.277-.223-.5-.5-.5zm-4 1c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5zm6 0c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5z" fill="url(#a)"/></svg> diff --git a/editor/icons/CubeMesh.svg b/editor/icons/BoxMesh.svg index d540858248..d540858248 100644 --- a/editor/icons/CubeMesh.svg +++ b/editor/icons/BoxMesh.svg diff --git a/editor/import/collada.h b/editor/import/collada.h index 2f6db93dbc..3b6b508b28 100644 --- a/editor/import/collada.h +++ b/editor/import/collada.h @@ -128,7 +128,7 @@ public: String name; struct Source { Vector<float> array; - int stride; + int stride = 0; }; Map<String, Source> sources; @@ -142,15 +142,15 @@ public: struct Primitives { struct SourceRef { String source; - int offset; + int offset = 0; }; String material; Map<String, SourceRef> sources; Vector<float> polygons; Vector<float> indices; - int count; - int vertex_size; + int count = 0; + int vertex_size = 0; }; Vector<Primitives> primitives; @@ -168,7 +168,7 @@ public: struct Source { Vector<String> sarray; Vector<float> array; - int stride; + int stride = 0; }; Map<String, Source> sources; @@ -200,14 +200,14 @@ public: struct Weights { struct SourceRef { String source; - int offset; + int offset = 0; }; String material; Map<String, SourceRef> sources; Vector<float> sets; Vector<float> indices; - int count; + int count = 0; } weights; Map<String, Transform> bone_rest_map; @@ -242,8 +242,8 @@ public: Color color; int uid = 0; struct Weight { - int bone_idx; - float weight; + int bone_idx = 0; + float weight = 0; bool operator<(const Weight w) const { return weight > w.weight; } //heaviest first }; @@ -331,7 +331,7 @@ public: }; String id; - Op op; + Op op = OP_ROTATE; Vector<float> data; }; @@ -375,7 +375,7 @@ public: }; struct NodeGeometry : public Node { - bool controller; + bool controller = false; String source; struct Material { @@ -438,7 +438,7 @@ public: TYPE_MATRIX }; - float time; + float time = 0; Vector<float> data; Point2 in_tangent; Point2 out_tangent; @@ -463,10 +463,10 @@ public: float unit_scale = 1.0; Vector3::Axis up_axis = Vector3::AXIS_Y; - bool z_up; + bool z_up = false; struct Version { - int major, minor, rev; + int major = 0, minor = 0, rev = 0; bool operator<(const Version &p_ver) const { return (major == p_ver.major) ? ((minor == p_ver.minor) ? (rev < p_ver.rev) : minor < p_ver.minor) : major < p_ver.major; } Version(int p_major = 0, int p_minor = 0, int p_rev = 0) { diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 41099dc8ea..4e93fe6f12 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -46,33 +46,28 @@ struct ColladaImport { Collada collada; - Node3D *scene; + Node3D *scene = nullptr; Vector<Ref<Animation>> animations; struct NodeMap { //String path; - Node3D *node; - int bone; + Node3D *node = nullptr; + int bone = -1; List<int> anim_tracks; - - NodeMap() { - node = nullptr; - bone = -1; - } }; - bool found_ambient; + bool found_ambient = false; Color ambient; - bool found_directional; - bool force_make_tangents; - bool apply_mesh_xform_to_vertices; - bool use_mesh_builtin_materials; - float bake_fps; + bool found_directional = false; + bool force_make_tangents = false; + bool apply_mesh_xform_to_vertices = true; + bool use_mesh_builtin_materials = false; + float bake_fps = 15; Map<String, NodeMap> node_map; //map from collada node to engine node Map<String, String> node_name_map; //map from collada node to engine node - Map<String, Ref<ArrayMesh>> mesh_cache; + Map<String, Ref<EditorSceneImporterMesh>> mesh_cache; Map<String, Ref<Curve3D>> curve_cache; Map<String, Ref<Material>> material_cache; Map<Collada::Node *, Skeleton3D *> skeleton_map; @@ -88,7 +83,7 @@ struct ColladaImport { Error _create_scene(Collada::Node *p_node, Node3D *p_parent); Error _create_resources(Collada::Node *p_node, bool p_use_compression); Error _create_material(const String &p_target); - Error _create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes = Vector<Ref<ArrayMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false); + Error _create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes = Vector<Ref<EditorSceneImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false); Error load(const String &p_path, int p_flags, bool p_force_make_tangents = false, bool p_use_compression = false); void _fix_param_animation_tracks(); void create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks); @@ -98,14 +93,6 @@ struct ColladaImport { Vector<String> missing_textures; void _pre_process_lights(Collada::Node *p_node); - - ColladaImport() { - found_ambient = false; - found_directional = false; - force_make_tangents = false; - apply_mesh_xform_to_vertices = true; - bake_fps = 15; - } }; Error ColladaImport::_populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent) { @@ -291,8 +278,8 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) { node = memnew(Path3D); } else { //mesh since nothing else - node = memnew(MeshInstance3D); - //Object::cast_to<MeshInstance3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true); + node = memnew(EditorSceneImporterMeshNode); + //Object::cast_to<EditorSceneImporterMeshNode>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true); } } break; case Collada::Node::TYPE_SKELETON: { @@ -453,7 +440,7 @@ Error ColladaImport::_create_material(const String &p_target) { return OK; } -Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) { +Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) { bool local_xform_mirror = p_local_xform.basis.determinant() < 0; if (p_morph_data) { @@ -910,7 +897,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me //////////////////////////// for (int mi = 0; mi < p_morph_meshes.size(); mi++) { - Array a = p_morph_meshes[mi]->surface_get_arrays(surface); + Array a = p_morph_meshes[mi]->get_surface_arrays(surface); //add valid weight and bone arrays if they exist, TODO check if they are unique to shape (generally not) if (has_weights) { @@ -923,14 +910,15 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me mr.push_back(a); } - p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), 0); - + String surface_name; + Ref<Material> mat; if (material.is_valid()) { if (p_use_mesh_material) { - p_mesh->surface_set_material(surface, material); + mat = material; } - p_mesh->surface_set_name(surface, material->get_name()); + surface_name = material->get_name(); } + p_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), mat, surface_name); } /*****************/ @@ -1015,10 +1003,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres } } - if (Object::cast_to<MeshInstance3D>(node)) { + if (Object::cast_to<EditorSceneImporterMeshNode>(node)) { Collada::NodeGeometry *ng2 = static_cast<Collada::NodeGeometry *>(p_node); - MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(node); + EditorSceneImporterMeshNode *mi = Object::cast_to<EditorSceneImporterMeshNode>(node); ERR_FAIL_COND_V(!mi, ERR_BUG); @@ -1027,7 +1015,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres String meshid; Transform apply_xform; Vector<int> bone_remap; - Vector<Ref<ArrayMesh>> morphs; + Vector<Ref<EditorSceneImporterMesh>> morphs; if (ng2->controller) { String ngsource = ng2->source; @@ -1096,10 +1084,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres for (int i = 0; i < names.size(); i++) { String meshid2 = names[i]; if (collada.state.mesh_data_map.has(meshid2)) { - Ref<ArrayMesh> mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + Ref<EditorSceneImporterMesh> mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh)); const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid2]; mesh->set_name(meshdata.name); - Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<ArrayMesh>>(), false); + Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<EditorSceneImporterMesh>>(), false); ERR_FAIL_COND_V(err, err); morphs.push_back(mesh); @@ -1122,7 +1110,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres meshid = ng2->source; } - Ref<ArrayMesh> mesh; + Ref<EditorSceneImporterMesh> mesh; if (mesh_cache.has(meshid)) { mesh = mesh_cache[meshid]; } else { @@ -1130,7 +1118,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres //bleh, must ignore invalid ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA); - mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh)); const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid]; mesh->set_name(meshdata.name); Error err = _create_mesh_surfaces(morphs.size() == 0, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, morph, morphs, p_use_compression, use_mesh_builtin_materials); diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index c1877895ce..1059692ca0 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -970,8 +970,6 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { return OK; } - uint32_t mesh_flags = 0; - Array meshes = state.json["meshes"]; for (GLTFMeshIndex i = 0; i < meshes.size(); i++) { print_verbose("glTF: Parsing mesh: " + itos(i)); @@ -979,6 +977,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { GLTFMesh mesh; mesh.mesh.instance(); + bool has_vertex_color = false; ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR); @@ -1034,6 +1033,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { } if (a.has("COLOR_0")) { array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true); + has_vertex_color = true; } if (a.has("JOINTS_0")) { array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true); @@ -1226,21 +1226,25 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { } //just add it - mesh.mesh->add_surface_from_arrays(primitive, array, morphs, Dictionary(), mesh_flags); + Ref<Material> mat; if (p.has("material")) { const int material = p["material"]; ERR_FAIL_INDEX_V(material, state.materials.size(), ERR_FILE_CORRUPT); - const Ref<Material> &mat = state.materials[material]; - - mesh.mesh->surface_set_material(mesh.mesh->get_surface_count() - 1, mat); - } else { - Ref<StandardMaterial3D> mat; - mat.instance(); - mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + Ref<StandardMaterial3D> mat3d = state.materials[material]; + if (has_vertex_color) { + mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + } + mat = mat3d; - mesh.mesh->surface_set_material(mesh.mesh->get_surface_count() - 1, mat); + } else if (has_vertex_color) { + Ref<StandardMaterial3D> mat3d; + mat3d.instance(); + mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat = mat3d; } + + mesh.mesh->add_surface(primitive, array, morphs, Dictionary(), mat); } mesh.blend_weights.resize(mesh.mesh->get_blend_shape_count()); @@ -1440,7 +1444,8 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) { if (d.has("name")) { material->set_name(d["name"]); } - material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + //don't do this here only if vertex color exists + //material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); if (d.has("pbrMetallicRoughness")) { const Dictionary &mr = d["pbrMetallicRoughness"]; @@ -2586,12 +2591,12 @@ BoneAttachment3D *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState & return bone_attachment; } -MeshInstance3D *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { +EditorSceneImporterMeshNode *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { const GLTFNode *gltf_node = state.nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->mesh, state.meshes.size(), nullptr); - MeshInstance3D *mi = memnew(MeshInstance3D); + EditorSceneImporterMeshNode *mi = memnew(EditorSceneImporterMeshNode); print_verbose("glTF: Creating mesh for: " + gltf_node->name); GLTFMesh &mesh = state.meshes.write[gltf_node->mesh]; @@ -3058,7 +3063,7 @@ void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Node3D * const GLTFSkinIndex skin_i = node->skin; Map<GLTFNodeIndex, Node *>::Element *mi_element = state.scene_nodes.find(node_i); - MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get()); + EditorSceneImporterMeshNode *mi = Object::cast_to<EditorSceneImporterMeshNode>(mi_element->get()); ERR_FAIL_COND(mi == nullptr); const GLTFSkeletonIndex skel_i = state.skins[node->skin].skeleton; diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h index bd30f8f1dd..6390f46524 100644 --- a/editor/import/editor_scene_importer_gltf.h +++ b/editor/import/editor_scene_importer_gltf.h @@ -38,7 +38,7 @@ class AnimationPlayer; class BoneAttachment3D; -class MeshInstance3D; +class EditorSceneImporterMeshNode; class EditorSceneImporterGLTF : public EditorSceneImporter { GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter); @@ -116,8 +116,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { GLTFNodeIndex fake_joint_parent = -1; GLTFLightIndex light = -1; - - GLTFNode() {} }; struct GLTFBufferView { @@ -127,8 +125,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { int byte_stride = 0; bool indices = false; //matrices need to be transformed to this - - GLTFBufferView() {} }; struct GLTFAccessor { @@ -137,7 +133,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { int component_type = 0; bool normalized = false; int count = 0; - GLTFType type; + GLTFType type = GLTFType::TYPE_SCALAR; float min = 0; float max = 0; int sparse_count = 0; @@ -146,8 +142,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { int sparse_indices_component_type = 0; int sparse_values_buffer_view = 0; int sparse_values_byte_offset = 0; - - GLTFAccessor() {} }; struct GLTFTexture { GLTFImageIndex src_image; @@ -166,8 +160,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { // Set of unique bone names for the skeleton Set<String> unique_names; - - GLTFSkeleton() {} }; struct GLTFSkin { @@ -204,12 +196,10 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { // The Actual Skin that will be created as a mapping between the IBM's of this skin // to the generated skeleton for the mesh instances. Ref<Skin> godot_skin; - - GLTFSkin() {} }; struct GLTFMesh { - Ref<ArrayMesh> mesh; + Ref<EditorSceneImporterMesh> mesh; Vector<float> blend_weights; }; @@ -218,8 +208,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { float fov_size = 64; float zfar = 500; float znear = 0.1; - - GLTFCamera() {} }; struct GLTFLight { @@ -229,8 +217,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { float range = Math_INF; float inner_cone_angle = 0.0f; float outer_cone_angle = Math_PI / 4.0; - - GLTFLight() {} }; struct GLTFAnimation { @@ -264,11 +250,11 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { struct GLTFState { Dictionary json; - int major_version; - int minor_version; + int major_version = 0; + int minor_version = 0; Vector<uint8_t> glb_data; - bool use_named_skin_binds; + bool use_named_skin_binds = false; Vector<GLTFNode *> nodes; Vector<Vector<uint8_t>> buffers; @@ -276,7 +262,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Vector<GLTFAccessor> accessors; Vector<GLTFMesh> meshes; //meshes are loaded directly, no reason not to. - Vector<Ref<Material>> materials; + Vector<Ref<StandardMaterial3D>> materials; String scene_name; Vector<int> root_nodes; @@ -369,7 +355,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Error _parse_animations(GLTFState &state); BoneAttachment3D *_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index); - MeshInstance3D *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); + EditorSceneImporterMeshNode *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); Camera3D *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); Light3D *_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); Node3D *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index d4560a2984..30c7b2920a 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -225,6 +225,8 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ String current_material_library; String current_material; String current_group; + uint32_t smooth_group = 0; + bool smoothing = true; while (true) { String l = f->get_line().strip_edges(); @@ -315,6 +317,10 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ Vector3 vertex = vertices[vtx]; //if (weld_vertices) // vertex.snap(Vector3(weld_tolerance, weld_tolerance, weld_tolerance)); + if (!smoothing) { + smooth_group++; + } + surf_tool->set_smooth_group(smooth_group); surf_tool->add_vertex(vertex); } @@ -322,10 +328,15 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ } } else if (l.begins_with("s ")) { //smoothing String what = l.substr(2, l.length()).strip_edges(); + bool do_smooth; if (what == "off") { - surf_tool->add_smooth_group(false); + do_smooth = false; } else { - surf_tool->add_smooth_group(true); + do_smooth = true; + } + if (do_smooth != smoothing) { + smooth_group++; + smoothing = do_smooth; } } else if (/*l.begins_with("g ") ||*/ l.begins_with("usemtl ") || (l.begins_with("o ") || f->eof_reached())) { //commit group to mesh //groups are too annoying @@ -426,8 +437,15 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in Node3D *scene = memnew(Node3D); for (List<Ref<Mesh>>::Element *E = meshes.front(); E; E = E->next()) { - MeshInstance3D *mi = memnew(MeshInstance3D); - mi->set_mesh(E->get()); + Ref<EditorSceneImporterMesh> mesh; + mesh.instance(); + Ref<Mesh> m = E->get(); + for (int i = 0; i < m->get_surface_count(); i++) { + mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i)); + } + + EditorSceneImporterMeshNode *mi = memnew(EditorSceneImporterMeshNode); + mi->set_mesh(mesh); mi->set_name(E->get()->get_name()); scene->add_child(mi); mi->set_owner(scene); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index fc4f673ec4..5abae339df 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -119,6 +119,304 @@ void EditorSceneImporter::_bind_methods() { BIND_CONSTANT(IMPORT_USE_COMPRESSION); } +//////////////////////////////////////////////// + +void EditorSceneImporterMesh::add_blend_shape(const String &p_name) { + ERR_FAIL_COND(surfaces.size() > 0); + blend_shapes.push_back(p_name); +} + +int EditorSceneImporterMesh::get_blend_shape_count() const { + return blend_shapes.size(); +} + +String EditorSceneImporterMesh::get_blend_shape_name(int p_blend_shape) const { + ERR_FAIL_INDEX_V(p_blend_shape, blend_shapes.size(), String()); + return blend_shapes[p_blend_shape]; +} + +void EditorSceneImporterMesh::set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode) { + blend_shape_mode = p_blend_shape_mode; +} +Mesh::BlendShapeMode EditorSceneImporterMesh::get_blend_shape_mode() const { + return blend_shape_mode; +} + +void EditorSceneImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name) { + ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size()); + ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX); + Surface s; + s.primitive = p_primitive; + s.arrays = p_arrays; + s.name = p_name; + + for (int i = 0; i < blend_shapes.size(); i++) { + Array bsdata = p_blend_shapes[i]; + ERR_FAIL_COND(bsdata.size() != Mesh::ARRAY_MAX); + Surface::BlendShape bs; + bs.arrays = bsdata; + s.blend_shape_data.push_back(bs); + } + + List<Variant> lods; + p_lods.get_key_list(&lods); + for (List<Variant>::Element *E = lods.front(); E; E = E->next()) { + ERR_CONTINUE(!E->get().is_num()); + Surface::LOD lod; + lod.distance = E->get(); + lod.indices = p_lods[E->get()]; + ERR_CONTINUE(lod.indices.size() == 0); + s.lods.push_back(lod); + } + + s.material = p_material; + + surfaces.push_back(s); + mesh.unref(); +} +int EditorSceneImporterMesh::get_surface_count() const { + return surfaces.size(); +} + +Mesh::PrimitiveType EditorSceneImporterMesh::get_surface_primitive_type(int p_surface) { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Mesh::PRIMITIVE_MAX); + return surfaces[p_surface].primitive; +} +Array EditorSceneImporterMesh::get_surface_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); + return surfaces[p_surface].arrays; +} +String EditorSceneImporterMesh::get_surface_name(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), String()); + return surfaces[p_surface].name; +} +Array EditorSceneImporterMesh::get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); + ERR_FAIL_INDEX_V(p_blend_shape, surfaces[p_surface].blend_shape_data.size(), Array()); + return surfaces[p_surface].blend_shape_data[p_blend_shape].arrays; +} +int EditorSceneImporterMesh::get_surface_lod_count(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0); + return surfaces[p_surface].lods.size(); +} +Vector<int> EditorSceneImporterMesh::get_surface_lod_indices(int p_surface, int p_lod) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Vector<int>()); + ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), Vector<int>()); + + return surfaces[p_surface].lods[p_lod].indices; +} + +float EditorSceneImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0); + ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), 0); + return surfaces[p_surface].lods[p_lod].distance; +} + +Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Ref<Material>()); + return surfaces[p_surface].material; +} + +bool EditorSceneImporterMesh::has_mesh() const { + return mesh.is_valid(); +} + +Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() { + ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>()); + + if (mesh.is_null()) { + mesh.instance(); + for (int i = 0; i < blend_shapes.size(); i++) { + mesh->add_blend_shape(blend_shapes[i]); + } + mesh->set_blend_shape_mode(blend_shape_mode); + for (int i = 0; i < surfaces.size(); i++) { + Array bs_data; + if (surfaces[i].blend_shape_data.size()) { + for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) { + bs_data.push_back(surfaces[i].blend_shape_data[j].arrays); + } + } + Dictionary lods; + if (surfaces[i].lods.size()) { + for (int j = 0; j < surfaces[i].lods.size(); j++) { + lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices; + } + } + + mesh->add_surface_from_arrays(surfaces[i].primitive, surfaces[i].arrays, bs_data, lods); + if (surfaces[i].material.is_valid()) { + mesh->surface_set_material(mesh->get_surface_count() - 1, surfaces[i].material); + } + if (surfaces[i].name != String()) { + mesh->surface_set_name(mesh->get_surface_count() - 1, surfaces[i].name); + } + } + } + + return mesh; +} + +void EditorSceneImporterMesh::clear() { + surfaces.clear(); + blend_shapes.clear(); + mesh.unref(); +} + +void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) { + clear(); + if (p_data.has("blend_shape_names")) { + blend_shapes = p_data["blend_shape_names"]; + } + if (p_data.has("surfaces")) { + Array surface_arr = p_data["surfaces"]; + for (int i = 0; i < surface_arr.size(); i++) { + Dictionary s = surface_arr[i]; + ERR_CONTINUE(!s.has("primitive")); + ERR_CONTINUE(!s.has("arrays")); + Mesh::PrimitiveType prim = Mesh::PrimitiveType(int(s["primitive"])); + ERR_CONTINUE(prim >= Mesh::PRIMITIVE_MAX); + Array arr = s["arrays"]; + Dictionary lods; + String name; + if (s.has("name")) { + name = s["name"]; + } + if (s.has("lods")) { + lods = s["lods"]; + } + Array blend_shapes; + if (s.has("blend_shapes")) { + blend_shapes = s["blend_shapes"]; + } + Ref<Material> material; + if (s.has("material")) { + material = s["material"]; + } + add_surface(prim, arr, blend_shapes, lods, material, name); + } + } +} +Dictionary EditorSceneImporterMesh::_get_data() const { + Dictionary data; + if (blend_shapes.size()) { + data["blend_shape_names"] = blend_shapes; + } + Array surface_arr; + for (int i = 0; i < surfaces.size(); i++) { + Dictionary d; + d["primitive"] = surfaces[i].primitive; + d["arrays"] = surfaces[i].arrays; + if (surfaces[i].blend_shape_data.size()) { + Array bs_data; + for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) { + bs_data.push_back(surfaces[i].blend_shape_data[j].arrays); + } + d["blend_shapes"] = bs_data; + } + if (surfaces[i].lods.size()) { + Dictionary lods; + for (int j = 0; j < surfaces[i].lods.size(); j++) { + lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices; + } + d["lods"] = lods; + } + + if (surfaces[i].material.is_valid()) { + d["material"] = surfaces[i].material; + } + + if (surfaces[i].name != String()) { + d["name"] = surfaces[i].name; + } + + surface_arr.push_back(d); + } + data["surfaces"] = surface_arr; + return data; +} + +void EditorSceneImporterMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape); + ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count); + ClassDB::bind_method(D_METHOD("get_blend_shape_name", "blend_shape_idx"), &EditorSceneImporterMesh::get_blend_shape_name); + + ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &EditorSceneImporterMesh::set_blend_shape_mode); + ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &EditorSceneImporterMesh::get_blend_shape_mode); + + ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String())); + + ClassDB::bind_method(D_METHOD("get_surface_count"), &EditorSceneImporterMesh::get_surface_count); + ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &EditorSceneImporterMesh::get_surface_primitive_type); + ClassDB::bind_method(D_METHOD("get_surface_name", "surface_idx"), &EditorSceneImporterMesh::get_surface_name); + ClassDB::bind_method(D_METHOD("get_surface_arrays", "surface_idx"), &EditorSceneImporterMesh::get_surface_arrays); + ClassDB::bind_method(D_METHOD("get_surface_blend_shape_arrays", "surface_idx", "blend_shape_idx"), &EditorSceneImporterMesh::get_surface_blend_shape_arrays); + ClassDB::bind_method(D_METHOD("get_surface_lod_count", "surface_idx"), &EditorSceneImporterMesh::get_surface_lod_count); + ClassDB::bind_method(D_METHOD("get_surface_lod_size", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_size); + ClassDB::bind_method(D_METHOD("get_surface_lod_indices", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_indices); + ClassDB::bind_method(D_METHOD("get_surface_material", "surface_idx"), &EditorSceneImporterMesh::get_surface_material); + + ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMesh::get_mesh); + ClassDB::bind_method(D_METHOD("clear"), &EditorSceneImporterMesh::clear); + + ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data); + ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data"); +} + +void EditorSceneImporterMeshNode::set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh) { + mesh = p_mesh; +} +Ref<EditorSceneImporterMesh> EditorSceneImporterMeshNode::get_mesh() const { + return mesh; +} + +void EditorSceneImporterMeshNode::set_skin(const Ref<Skin> &p_skin) { + skin = p_skin; +} +Ref<Skin> EditorSceneImporterMeshNode::get_skin() const { + return skin; +} + +void EditorSceneImporterMeshNode::set_surface_material(int p_idx, const Ref<Material> &p_material) { + ERR_FAIL_COND(p_idx < 0); + if (p_idx >= surface_materials.size()) { + surface_materials.resize(p_idx + 1); + } + + surface_materials.write[p_idx] = p_material; +} +Ref<Material> EditorSceneImporterMeshNode::get_surface_material(int p_idx) const { + ERR_FAIL_COND_V(p_idx < 0, Ref<Material>()); + if (p_idx >= surface_materials.size()) { + return Ref<Material>(); + } + return surface_materials[p_idx]; +} + +void EditorSceneImporterMeshNode::set_skeleton_path(const NodePath &p_path) { + skeleton_path = p_path; +} +NodePath EditorSceneImporterMeshNode::get_skeleton_path() const { + return skeleton_path; +} + +void EditorSceneImporterMeshNode::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &EditorSceneImporterMeshNode::set_mesh); + ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMeshNode::get_mesh); + + ClassDB::bind_method(D_METHOD("set_skin", "skin"), &EditorSceneImporterMeshNode::set_skin); + ClassDB::bind_method(D_METHOD("get_skin"), &EditorSceneImporterMeshNode::get_skin); + + ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &EditorSceneImporterMeshNode::set_skeleton_path); + ClassDB::bind_method(D_METHOD("get_skeleton_path"), &EditorSceneImporterMeshNode::get_skeleton_path); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "EditorSceneImporterMesh"), "set_mesh", "get_mesh"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); +} + ///////////////////////////////// void EditorScenePostImport::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene"))); @@ -1219,6 +1517,34 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito return importer->import_animation(p_path, p_flags, p_bake_fps); } +void ResourceImporterScene::_generate_meshes(Node *p_node) { + EditorSceneImporterMeshNode *src_mesh = Object::cast_to<EditorSceneImporterMeshNode>(p_node); + if (src_mesh != nullptr) { + //is mesh + MeshInstance3D *mesh_node = memnew(MeshInstance3D); + mesh_node->set_transform(src_mesh->get_transform()); + mesh_node->set_skin(src_mesh->get_skin()); + mesh_node->set_skeleton_path(src_mesh->get_skeleton_path()); + + Ref<ArrayMesh> mesh; + if (!src_mesh->get_mesh()->has_mesh()) { + //do mesh processing + } + mesh = src_mesh->get_mesh()->get_mesh(); + mesh_node->set_mesh(mesh); + for (int i = 0; i < mesh->get_surface_count(); i++) { + mesh_node->set_surface_material(i, src_mesh->get_surface_material(i)); + } + + p_node->replace_by(mesh_node); + memdelete(p_node); + p_node = mesh_node; + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + _generate_meshes(p_node->get_child(i)); + } +} Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { const String &src_path = p_source_file; @@ -1315,6 +1641,8 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p scene->set_name(p_save_path.get_file().get_basename()); } + _generate_meshes(scene); + err = OK; String animation_filter = String(p_options["animation/filter_script"]).strip_edges(); diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index cd61ec01f2..758390b367 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -32,9 +32,11 @@ #define RESOURCEIMPORTERSCENE_H #include "core/io/resource_importer.h" +#include "scene/3d/node_3d.h" #include "scene/resources/animation.h" #include "scene/resources/mesh.h" #include "scene/resources/shape_3d.h" +#include "scene/resources/skin.h" class Material; @@ -88,6 +90,90 @@ public: EditorScenePostImport(); }; +// The following classes are used by importers instead of ArrayMesh and MeshInstance3D +// so the data is not reginstered (hence, quality loss), importing happens faster and +// its easier to modify before saving + +class EditorSceneImporterMesh : public Resource { + GDCLASS(EditorSceneImporterMesh, Resource) + + struct Surface { + Mesh::PrimitiveType primitive; + Array arrays; + struct BlendShape { + Array arrays; + }; + Vector<BlendShape> blend_shape_data; + struct LOD { + Vector<int> indices; + float distance; + }; + Vector<LOD> lods; + Ref<Material> material; + String name; + }; + Vector<Surface> surfaces; + Vector<String> blend_shapes; + Mesh::BlendShapeMode blend_shape_mode = Mesh::BLEND_SHAPE_MODE_NORMALIZED; + + Ref<ArrayMesh> mesh; + +protected: + void _set_data(const Dictionary &p_data); + Dictionary _get_data() const; + + static void _bind_methods(); + +public: + void add_blend_shape(const String &p_name); + int get_blend_shape_count() const; + String get_blend_shape_name(int p_blend_shape) const; + + void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String()); + int get_surface_count() const; + + void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode); + Mesh::BlendShapeMode get_blend_shape_mode() const; + + Mesh::PrimitiveType get_surface_primitive_type(int p_surface); + String get_surface_name(int p_surface) const; + Array get_surface_arrays(int p_surface) const; + Array get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const; + int get_surface_lod_count(int p_surface) const; + Vector<int> get_surface_lod_indices(int p_surface, int p_lod) const; + float get_surface_lod_size(int p_surface, int p_lod) const; + Ref<Material> get_surface_material(int p_surface) const; + + bool has_mesh() const; + Ref<ArrayMesh> get_mesh(); + void clear(); +}; + +class EditorSceneImporterMeshNode : public Node3D { + GDCLASS(EditorSceneImporterMeshNode, Node3D) + + Ref<EditorSceneImporterMesh> mesh; + Ref<Skin> skin; + NodePath skeleton_path; + Vector<Ref<Material>> surface_materials; + +protected: + static void _bind_methods(); + +public: + void set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh); + Ref<EditorSceneImporterMesh> get_mesh() const; + + void set_skin(const Ref<Skin> &p_skin); + Ref<Skin> get_skin() const; + + void set_surface_material(int p_idx, const Ref<Material> &p_material); + Ref<Material> get_surface_material(int p_idx) const; + + void set_skeleton_path(const NodePath &p_path); + NodePath get_skeleton_path() const; +}; + class ResourceImporterScene : public ResourceImporter { GDCLASS(ResourceImporterScene, ResourceImporter); @@ -119,6 +205,7 @@ class ResourceImporterScene : public ResourceImporter { }; void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner); + void _generate_meshes(Node *p_node); public: static ResourceImporterScene *get_singleton() { return singleton; } diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index ac2485fe31..c8dae53722 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -537,7 +537,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String } if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) { - _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel); + _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC1_4, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel); r_platform_variants->push_back("pvrtc"); formats_imported.push_back("pvrtc"); } diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h index 97c4622731..39036d4423 100644 --- a/editor/import/resource_importer_texture.h +++ b/editor/import/resource_importer_texture.h @@ -60,13 +60,9 @@ protected: Mutex mutex; struct MakeInfo { - int flags; + int flags = 0; String normal_path_for_roughness; - RS::TextureDetectRoughnessChannel channel_for_roughness; - MakeInfo() { - flags = 0; - channel_for_roughness = RS::TEXTURE_DETECT_ROUGNHESS_R; - } + RS::TextureDetectRoughnessChannel channel_for_roughness = RS::TEXTURE_DETECT_ROUGNHESS_R; }; Map<StringName, MakeInfo> make_flags; diff --git a/editor/import/resource_importer_texture_atlas.h b/editor/import/resource_importer_texture_atlas.h index 9d973c3d8d..d237b096d3 100644 --- a/editor/import/resource_importer_texture_atlas.h +++ b/editor/import/resource_importer_texture_atlas.h @@ -38,7 +38,7 @@ class ResourceImporterTextureAtlas : public ResourceImporter { struct PackData { Rect2 region; - bool is_mesh; + bool is_mesh = false; Vector<int> chart_pieces; //one for region, many for mesh Vector<Vector<Vector2>> chart_vertices; //for mesh Ref<Image> image; diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp index 1077aca7b3..a7d5e5149e 100644 --- a/editor/multi_node_edit.cpp +++ b/editor/multi_node_edit.cpp @@ -173,10 +173,6 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::OBJECT, "scripts", PROPERTY_HINT_RESOURCE_TYPE, "Script")); } -void MultiNodeEdit::clear_nodes() { - nodes.clear(); -} - void MultiNodeEdit::add_node(const NodePath &p_node) { nodes.push_back(p_node); } diff --git a/editor/multi_node_edit.h b/editor/multi_node_edit.h index 694dad76f1..7f0fb625ef 100644 --- a/editor/multi_node_edit.h +++ b/editor/multi_node_edit.h @@ -38,7 +38,7 @@ class MultiNodeEdit : public Reference { List<NodePath> nodes; struct PLData { - int uses; + int uses = 0; PropertyInfo info; }; @@ -50,7 +50,6 @@ protected: void _get_property_list(List<PropertyInfo> *p_list) const; public: - void clear_nodes(); void add_node(const NodePath &p_node); int get_node_count() const; diff --git a/editor/node_3d_editor_gizmos.cpp b/editor/node_3d_editor_gizmos.cpp index 97bafdd167..1f6c32ed70 100644 --- a/editor/node_3d_editor_gizmos.cpp +++ b/editor/node_3d_editor_gizmos.cpp @@ -398,10 +398,10 @@ void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref< void EditorNode3DGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position) { ERR_FAIL_COND(!spatial_node); - CubeMesh cubem; - cubem.set_size(p_size); + BoxMesh box_mesh; + box_mesh.set_size(p_size); - Array arrays = cubem.surface_get_arrays(0); + Array arrays = box_mesh.surface_get_arrays(0); PackedVector3Array vertex = arrays[RS::ARRAY_VERTEX]; Vector3 *w = vertex.ptrw(); @@ -412,7 +412,7 @@ void EditorNode3DGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size, arrays[RS::ARRAY_VERTEX] = vertex; Ref<ArrayMesh> m = memnew(ArrayMesh); - m->add_surface_from_arrays(cubem.surface_get_primitive_type(0), arrays); + m->add_surface_from_arrays(box_mesh.surface_get_primitive_type(0), arrays); m->surface_set_material(0, p_material); add_mesh(m); } @@ -792,7 +792,7 @@ bool Light3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<Light3D>(p_spatial) != nullptr; } -String Light3DGizmoPlugin::get_name() const { +String Light3DGizmoPlugin::get_gizmo_name() const { return "Light3D"; } @@ -1061,7 +1061,7 @@ bool AudioStreamPlayer3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<AudioStreamPlayer3D>(p_spatial) != nullptr; } -String AudioStreamPlayer3DGizmoPlugin::get_name() const { +String AudioStreamPlayer3DGizmoPlugin::get_gizmo_name() const { return "AudioStreamPlayer3D"; } @@ -1195,7 +1195,7 @@ bool Camera3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<Camera3D>(p_spatial) != nullptr; } -String Camera3DGizmoPlugin::get_name() const { +String Camera3DGizmoPlugin::get_gizmo_name() const { return "Camera3D"; } @@ -1432,7 +1432,7 @@ bool MeshInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<MeshInstance3D>(p_spatial) != nullptr && Object::cast_to<SoftBody3D>(p_spatial) == nullptr; } -String MeshInstance3DGizmoPlugin::get_name() const { +String MeshInstance3DGizmoPlugin::get_gizmo_name() const { return "MeshInstance3D"; } @@ -1469,7 +1469,7 @@ bool Sprite3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<Sprite3D>(p_spatial) != nullptr; } -String Sprite3DGizmoPlugin::get_name() const { +String Sprite3DGizmoPlugin::get_gizmo_name() const { return "Sprite3D"; } @@ -1531,7 +1531,7 @@ bool Position3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<Position3D>(p_spatial) != nullptr; } -String Position3DGizmoPlugin::get_name() const { +String Position3DGizmoPlugin::get_gizmo_name() const { return "Position3D"; } @@ -1556,7 +1556,7 @@ bool Skeleton3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<Skeleton3D>(p_spatial) != nullptr; } -String Skeleton3DGizmoPlugin::get_name() const { +String Skeleton3DGizmoPlugin::get_gizmo_name() const { return "Skeleton3D"; } @@ -1758,7 +1758,7 @@ bool PhysicalBone3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<PhysicalBone3D>(p_spatial) != nullptr; } -String PhysicalBone3DGizmoPlugin::get_name() const { +String PhysicalBone3DGizmoPlugin::get_gizmo_name() const { return "PhysicalBone3D"; } @@ -1895,7 +1895,7 @@ bool RayCast3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<RayCast3D>(p_spatial) != nullptr; } -String RayCast3DGizmoPlugin::get_name() const { +String RayCast3DGizmoPlugin::get_gizmo_name() const { return "RayCast3D"; } @@ -1947,7 +1947,7 @@ bool SpringArm3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<SpringArm3D>(p_spatial) != nullptr; } -String SpringArm3DGizmoPlugin::get_name() const { +String SpringArm3DGizmoPlugin::get_gizmo_name() const { return "SpringArm3D"; } @@ -1966,7 +1966,7 @@ bool VehicleWheel3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<VehicleWheel3D>(p_spatial) != nullptr; } -String VehicleWheel3DGizmoPlugin::get_name() const { +String VehicleWheel3DGizmoPlugin::get_gizmo_name() const { return "VehicleWheel3D"; } @@ -2038,7 +2038,7 @@ bool SoftBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<SoftBody3D>(p_spatial) != nullptr; } -String SoftBody3DGizmoPlugin::get_name() const { +String SoftBody3DGizmoPlugin::get_gizmo_name() const { return "SoftBody3D"; } @@ -2114,7 +2114,7 @@ bool VisibilityNotifier3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<VisibilityNotifier3D>(p_spatial) != nullptr; } -String VisibilityNotifier3DGizmoPlugin::get_name() const { +String VisibilityNotifier3DGizmoPlugin::get_gizmo_name() const { return "VisibilityNotifier3D"; } @@ -2270,7 +2270,7 @@ bool CPUParticles3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<CPUParticles3D>(p_spatial) != nullptr; } -String CPUParticles3DGizmoPlugin::get_name() const { +String CPUParticles3DGizmoPlugin::get_gizmo_name() const { return "CPUParticles3D"; } @@ -2302,7 +2302,7 @@ bool GPUParticles3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<GPUParticles3D>(p_spatial) != nullptr; } -String GPUParticles3DGizmoPlugin::get_name() const { +String GPUParticles3DGizmoPlugin::get_gizmo_name() const { return "GPUParticles3D"; } @@ -2469,7 +2469,7 @@ bool GPUParticlesCollision3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return (Object::cast_to<GPUParticlesCollision3D>(p_spatial) != nullptr) || (Object::cast_to<GPUParticlesAttractor3D>(p_spatial) != nullptr); } -String GPUParticlesCollision3DGizmoPlugin::get_name() const { +String GPUParticlesCollision3DGizmoPlugin::get_gizmo_name() const { return "GPUParticlesCollision3D"; } @@ -2733,7 +2733,7 @@ bool ReflectionProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<ReflectionProbe>(p_spatial) != nullptr; } -String ReflectionProbeGizmoPlugin::get_name() const { +String ReflectionProbeGizmoPlugin::get_gizmo_name() const { return "ReflectionProbe"; } @@ -2918,7 +2918,7 @@ bool DecalGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<Decal>(p_spatial) != nullptr; } -String DecalGizmoPlugin::get_name() const { +String DecalGizmoPlugin::get_gizmo_name() const { return "Decal"; } @@ -3059,7 +3059,7 @@ bool GIProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<GIProbe>(p_spatial) != nullptr; } -String GIProbeGizmoPlugin::get_name() const { +String GIProbeGizmoPlugin::get_gizmo_name() const { return "GIProbe"; } @@ -3254,7 +3254,7 @@ bool BakedLightmapGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<BakedLightmap>(p_spatial) != nullptr; } -String BakedLightmapGizmoPlugin::get_name() const { +String BakedLightmapGizmoPlugin::get_gizmo_name() const { return "BakedLightmap"; } @@ -3436,7 +3436,7 @@ bool LightmapProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<LightmapProbe>(p_spatial) != nullptr; } -String LightmapProbeGizmoPlugin::get_name() const { +String LightmapProbeGizmoPlugin::get_gizmo_name() const { return "LightmapProbe"; } @@ -3520,7 +3520,7 @@ bool CollisionShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<CollisionShape3D>(p_spatial) != nullptr; } -String CollisionShape3DGizmoPlugin::get_name() const { +String CollisionShape3DGizmoPlugin::get_gizmo_name() const { return "CollisionShape3D"; } @@ -4120,7 +4120,7 @@ bool CollisionPolygon3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<CollisionPolygon3D>(p_spatial) != nullptr; } -String CollisionPolygon3DGizmoPlugin::get_name() const { +String CollisionPolygon3DGizmoPlugin::get_gizmo_name() const { return "CollisionPolygon3D"; } @@ -4167,7 +4167,7 @@ bool NavigationRegion3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<NavigationRegion3D>(p_spatial) != nullptr; } -String NavigationRegion3DGizmoPlugin::get_name() const { +String NavigationRegion3DGizmoPlugin::get_gizmo_name() const { return "NavigationRegion3D"; } @@ -4532,7 +4532,7 @@ bool Joint3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<Joint3D>(p_spatial) != nullptr; } -String Joint3DGizmoPlugin::get_name() const { +String Joint3DGizmoPlugin::get_gizmo_name() const { return "Joint3D"; } diff --git a/editor/node_3d_editor_gizmos.h b/editor/node_3d_editor_gizmos.h index 4826054643..e418456d60 100644 --- a/editor/node_3d_editor_gizmos.h +++ b/editor/node_3d_editor_gizmos.h @@ -41,7 +41,7 @@ class Light3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const override; @@ -58,7 +58,7 @@ class AudioStreamPlayer3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const override; @@ -75,7 +75,7 @@ class Camera3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const override; @@ -92,7 +92,7 @@ class MeshInstance3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; bool can_be_hidden() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -105,7 +105,7 @@ class Sprite3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; bool can_be_hidden() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -121,7 +121,7 @@ class Position3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -133,7 +133,7 @@ class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -145,7 +145,7 @@ class PhysicalBone3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -157,7 +157,7 @@ class RayCast3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -169,7 +169,7 @@ class SpringArm3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -181,7 +181,7 @@ class VehicleWheel3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -193,7 +193,7 @@ class SoftBody3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; bool is_selectable_when_hidden() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -211,7 +211,7 @@ class VisibilityNotifier3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -228,7 +228,7 @@ class CPUParticles3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; bool is_selectable_when_hidden() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -240,7 +240,7 @@ class GPUParticles3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; bool is_selectable_when_hidden() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -258,7 +258,7 @@ class GPUParticlesCollision3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -275,7 +275,7 @@ class ReflectionProbeGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -292,7 +292,7 @@ class DecalGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -309,7 +309,7 @@ class GIProbeGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -326,7 +326,7 @@ class BakedLightmapGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -343,7 +343,7 @@ class LightmapProbeGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -360,7 +360,7 @@ class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -377,7 +377,7 @@ class CollisionPolygon3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; CollisionPolygon3DGizmoPlugin(); @@ -395,7 +395,7 @@ class NavigationRegion3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; @@ -427,7 +427,7 @@ class Joint3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index e11db1390b..17e554ee0d 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -113,9 +113,9 @@ class AnimationPlayerEditor : public VBoxContainer { int current_option; struct BlendEditor { - AcceptDialog *dialog; - Tree *tree; - OptionButton *next; + AcceptDialog *dialog = nullptr; + Tree *tree = nullptr; + OptionButton *next = nullptr; } blend_editor; @@ -131,13 +131,13 @@ class AnimationPlayerEditor : public VBoxContainer { // Onion skinning. struct { // Settings. - bool enabled; - bool past; - bool future; - int steps; - bool differences_only; - bool force_white_modulate; - bool include_gizmos; + bool enabled = false; + bool past = false; + bool future = false; + int steps = 0; + bool differences_only = false; + bool force_white_modulate = false; + bool include_gizmos = false; int get_needed_capture_count() const { // 'Differences only' needs a capture of the present. @@ -145,8 +145,8 @@ class AnimationPlayerEditor : public VBoxContainer { } // Rendering. - int64_t last_frame; - int can_overlay; + int64_t last_frame = 0; + int can_overlay = 0; Size2 capture_size; Vector<RID> captures; Vector<bool> captures_valid; diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index f78d90bdbf..119feb417d 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -126,10 +126,10 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { Vector2 to; AnimationNodeStateMachineTransition::SwitchMode mode; StringName advance_condition_name; - bool advance_condition_state; - bool disabled; - bool auto_advance; - float width; + bool advance_condition_state = false; + bool disabled = false; + bool auto_advance = false; + float width = 0; }; Vector<TransitionLine> transition_lines; diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 1bbb68d224..800df12199 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -142,9 +142,6 @@ void AnimationTreeEditor::enter_editor(const String &p_path) { edit_path(path); } -void AnimationTreeEditor::_about_to_show_root() { -} - void AnimationTreeEditor::_notification(int p_what) { if (p_what == NOTIFICATION_PROCESS) { ObjectID root; diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h index 356a078d99..fd3a449487 100644 --- a/editor/plugins/animation_tree_editor_plugin.h +++ b/editor/plugins/animation_tree_editor_plugin.h @@ -62,7 +62,6 @@ class AnimationTreeEditor : public VBoxContainer { Vector<AnimationTreeNodeEditorPlugin *> editors; void _update_path(); - void _about_to_show_root(); ObjectID current_root; void _path_button_pressed(int p_path); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 9ecf5193a2..f3aa11317e 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -1187,6 +1187,10 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const _request_image(item->get_instance_id(), r["icon_url"], IMAGE_QUEUE_ICON, 0); } } + + if (!result.empty()) { + library_scroll->set_v_scroll(0); + } } break; case REQUESTING_ASSET: { Dictionary r = d; diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index 9761dbba1e..b69dfc208e 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -89,10 +89,10 @@ class EditorAssetLibraryItemDescription : public ConfirmationDialog { PanelContainer *previews_bg; struct Preview { - int id; - bool is_video; + int id = 0; + bool is_video = false; String video_link; - Button *button; + Button *button = nullptr; Ref<Texture2D> image; }; @@ -234,12 +234,12 @@ class EditorAssetLibrary : public PanelContainer { }; struct ImageQueue { - bool active; - int queue_id; - ImageType image_type; - int image_index; + bool active = false; + int queue_id = 0; + ImageType image_type = ImageType::IMAGE_QUEUE_ICON; + int image_index = 0; String image_url; - HTTPRequest *request; + HTTPRequest *request = nullptr; ObjectID target; }; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index b1bac34f46..4227482ccc 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2356,12 +2356,12 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { (!Input::get_singleton()->is_key_pressed(KEY_DOWN)) && (!Input::get_singleton()->is_key_pressed(KEY_LEFT)) && (!Input::get_singleton()->is_key_pressed(KEY_RIGHT))) { - if (drag_selection.size() != 1) { + if (drag_selection.size() > 1) { _commit_canvas_item_state( drag_selection, vformat(TTR("Move %d CanvasItems"), drag_selection.size()), true); - } else { + } else if (drag_selection.size() == 1) { _commit_canvas_item_state( drag_selection, vformat(TTR("Move CanvasItem \"%s\" to (%d, %d)"), diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 859e80befe..c4a1dca593 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -288,9 +288,9 @@ private: MenuOption last_option; struct _SelectResult { - CanvasItem *item; - float z_index; - bool has_z; + CanvasItem *item = nullptr; + float z_index = 0; + bool has_z = true; _FORCE_INLINE_ bool operator<(const _SelectResult &p_rr) const { return has_z && p_rr.has_z ? p_rr.z_index < z_index : p_rr.has_z; } @@ -308,8 +308,6 @@ private: Transform2D xform; float length = 0.f; uint64_t last_pass = 0; - - BoneList() {} }; uint64_t bone_last_frame; @@ -331,7 +329,7 @@ private: struct PoseClipboard { Vector2 pos; Vector2 scale; - float rot; + float rot = 0; ObjectID id; }; List<PoseClipboard> pose_clipboard; diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index 105ac24950..23ab6a9de2 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -563,6 +563,8 @@ CollisionShape2DEditor::CollisionShape2DEditor(EditorNode *p_editor) { edit_handle = -1; pressed = false; + + shape_type = 0; } void CollisionShape2DEditorPlugin::edit(Object *p_obj) { diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index 9885efc2b5..04e6be2354 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/editor/plugins/editor_preview_plugins.h @@ -90,7 +90,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; - mutable volatile bool preview_done; + mutable volatile bool preview_done = false; void _preview_done(const Variant &p_udata); @@ -134,7 +134,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; - mutable volatile bool preview_done; + mutable volatile bool preview_done = false; void _preview_done(const Variant &p_udata); @@ -156,7 +156,7 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator { RID viewport_texture; RID canvas; RID canvas_item; - mutable volatile bool preview_done; + mutable volatile bool preview_done = false; void _preview_done(const Variant &p_udata); diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index a6df790620..570ba9ae03 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -55,7 +55,7 @@ class MaterialEditor : public Control { Camera3D *camera; Ref<SphereMesh> sphere_mesh; - Ref<CubeMesh> box_mesh; + Ref<BoxMesh> box_mesh; TextureButton *sphere_switch; TextureButton *box_switch; diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 374a8c8290..9d3498efa1 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -301,4 +301,6 @@ MeshLibraryEditorPlugin::MeshLibraryEditorPlugin(EditorNode *p_node) { mesh_library_editor->set_anchors_and_margins_preset(Control::PRESET_TOP_WIDE); mesh_library_editor->set_end(Point2(0, 22)); mesh_library_editor->hide(); + + editor = nullptr; } diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 2530b4ecfe..6493e0f953 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -2512,7 +2512,7 @@ void Node3DEditorViewport::_notification(int p_what) { gpu_time_history[i] = 0; } cpu_time_history_index = 0; - cpu_time_history_index = 0; + gpu_time_history_index = 0; } if (show_fps) { cpu_time_history[cpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_cpu(viewport->get_viewport_rid()); @@ -4999,9 +4999,6 @@ void Node3DEditor::_menu_item_pressed(int p_option) { for (int i = 0; i < 3; ++i) { if (grid_enable[i]) { grid_visible[i] = grid_enabled; - if (grid_instance[i].is_valid()) { - RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled); - } } } _finish_grid(); @@ -5829,13 +5826,25 @@ void Node3DEditor::snap_selected_nodes_to_floor() { Set<CollisionShape3D *> cs = _get_child_nodes<CollisionShape3D>(sp); if (cs.size()) { - AABB aabb = sp->get_global_transform().xform(cs.front()->get()->get_shape()->get_debug_mesh()->get_aabb()); + AABB aabb; + bool found_valid_shape = false; + if (cs.front()->get()->get_shape().is_valid()) { + aabb = sp->get_global_transform().xform(cs.front()->get()->get_shape()->get_debug_mesh()->get_aabb()); + found_valid_shape = true; + } for (Set<CollisionShape3D *>::Element *I = cs.front(); I; I = I->next()) { - aabb.merge_with(sp->get_global_transform().xform(I->get()->get_shape()->get_debug_mesh()->get_aabb())); + if (I->get()->get_shape().is_valid()) { + aabb.merge_with(sp->get_global_transform().xform(I->get()->get_shape()->get_debug_mesh()->get_aabb())); + found_valid_shape = true; + } + } + if (found_valid_shape) { + Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5); + from = aabb.position + size; + position_offset.y = from.y - sp->get_global_transform().origin.y; + } else { + from = sp->get_global_transform().origin; } - Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5); - from = aabb.position + size; - position_offset.y = from.y - sp->get_global_transform().origin.y; } else if (vi.size()) { AABB aabb = vi.front()->get()->get_transformed_aabb(); for (Set<VisualInstance3D *>::Element *I = vi.front(); I; I = I->next()) { @@ -6160,7 +6169,6 @@ void Node3DEditor::clear() { view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), true); for (int i = 0; i < 3; ++i) { if (grid_enable[i]) { - RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], true); grid_visible[i] = true; } } @@ -6667,7 +6675,7 @@ Node3DEditorPlugin::Node3DEditorPlugin(EditorNode *p_node) { editor->get_viewport()->add_child(spatial_editor); spatial_editor->hide(); - spatial_editor->connect_compat("transform_key_request", editor->get_inspector_dock(), "_transform_keyed"); + spatial_editor->connect("transform_key_request", Callable(editor->get_inspector_dock(), "_transform_keyed")); } Node3DEditorPlugin::~Node3DEditorPlugin() { @@ -6802,9 +6810,9 @@ Ref<StandardMaterial3D> EditorNode3DGizmoPlugin::get_material(const String &p_na return mat; } -String EditorNode3DGizmoPlugin::get_name() const { - if (get_script_instance() && get_script_instance()->has_method("get_name")) { - return get_script_instance()->call("get_name"); +String EditorNode3DGizmoPlugin::get_gizmo_name() const { + if (get_script_instance() && get_script_instance()->has_method("get_gizmo_name")) { + return get_script_instance()->call("get_gizmo_name"); } return TTR("Nameless gizmo"); } diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 12080ea1f0..66ee678154 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -61,16 +61,10 @@ public: Ref<Material> material; Ref<SkinReference> skin_reference; RID skeleton; - bool billboard; - bool unscaled; - bool can_intersect; - bool extra_margin; - Instance() { - billboard = false; - unscaled = false; - can_intersect = false; - extra_margin = false; - } + bool billboard = false; + bool unscaled = false; + bool can_intersect = false; + bool extra_margin = false; void create_instance(Node3D *p_base, bool p_hidden = false); }; @@ -80,7 +74,7 @@ public: struct Handle { Vector3 pos; - bool billboard; + bool billboard = false; }; Vector<Vector3> handles; @@ -297,9 +291,9 @@ private: Label *fps_label; struct _RayResult { - Node3D *item; - float depth; - int handle; + Node3D *item = nullptr; + float depth = 0; + int handle = 0; _FORCE_INLINE_ bool operator<(const _RayResult &p_rr) const { return depth < p_rr.depth; } }; @@ -376,11 +370,11 @@ private: Vector3 click_ray_pos; Vector3 center; Vector3 orig_gizmo_pos; - int edited_gizmo; + int edited_gizmo = 0; Point2 mouse_pos; - bool snap; + bool snap = false; Ref<EditorNode3DGizmo> gizmo; - int gizmo_handle; + int gizmo_handle = 0; Variant gizmo_initial_value; Vector3 gizmo_initial_pos; } _edit; @@ -626,8 +620,8 @@ private: AABB preview_bounds; struct Gizmo { - bool visible; - float scale; + bool visible = false; + float scale = 0; Transform transform; } gizmo; @@ -868,7 +862,7 @@ public: Ref<StandardMaterial3D> get_material(const String &p_name, const Ref<EditorNode3DGizmo> &p_gizmo = Ref<EditorNode3DGizmo>()); - virtual String get_name() const; + virtual String get_gizmo_name() const; virtual int get_priority() const; virtual bool can_be_hidden() const; virtual bool is_selectable_when_hidden() const; diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 280f6fafd8..043693801e 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -290,6 +290,8 @@ void Path3DGizmo::redraw() { Path3DGizmo::Path3DGizmo(Path3D *p_path) { path = p_path; set_spatial_node(p_path); + orig_in_length = 0; + orig_out_length = 0; } bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) { @@ -630,7 +632,7 @@ Ref<EditorNode3DGizmo> Path3DGizmoPlugin::create_gizmo(Node3D *p_spatial) { return ref; } -String Path3DGizmoPlugin::get_name() const { +String Path3DGizmoPlugin::get_gizmo_name() const { return "Path3D"; } diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h index be275944a6..3b92a59143 100644 --- a/editor/plugins/path_3d_editor_plugin.h +++ b/editor/plugins/path_3d_editor_plugin.h @@ -59,7 +59,7 @@ protected: Ref<EditorNode3DGizmo> create_gizmo(Node3D *p_spatial) override; public: - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; Path3DGizmoPlugin(); }; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 12790a6746..5982074750 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -234,15 +234,15 @@ static bool _is_built_in_script(Script *p_script) { class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache { struct Cache { - uint64_t time_loaded; + uint64_t time_loaded = 0; RES cache; }; Map<String, Cache> cached; public: - uint64_t max_time_cache; - int max_cache_size; + uint64_t max_time_cache = 5 * 60 * 1000; //minutes, five + int max_cache_size = 128; void cleanup() { List<Map<String, Cache>::Element *> to_clean; @@ -292,11 +292,6 @@ public: return E->get().cache; } - EditorScriptCodeCompletionCache() { - max_cache_size = 128; - max_time_cache = 5 * 60 * 1000; //minutes, five - } - virtual ~EditorScriptCodeCompletionCache() {} }; @@ -1646,17 +1641,6 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) { } } -void ScriptEditor::ensure_focus_current() { - if (!is_inside_tree()) { - return; - } - - ScriptEditorBase *current = _get_current_editor(); - if (current) { - current->ensure_focus(); - } -} - void ScriptEditor::_members_overview_selected(int p_idx) { ScriptEditorBase *se = _get_current_editor(); if (!se) { @@ -1723,11 +1707,11 @@ struct _ScriptEditorItemData { String name; String sort_key; Ref<Texture2D> icon; - int index; + int index = 0; String tooltip; - bool used; - int category; - Node *ref; + bool used = false; + int category = 0; + Node *ref = nullptr; bool operator<(const _ScriptEditorItemData &id) const { if (category == id.category) { diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index cc02a1ccbe..aafd8cba18 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -291,7 +291,7 @@ class ScriptEditor : public PanelContainer { Vector<Ref<EditorSyntaxHighlighter>> syntax_highlighters; struct ScriptHistory { - Control *control; + Control *control = nullptr; Variant state; }; @@ -453,7 +453,6 @@ public: bool toggle_scripts_panel(); bool is_scripts_panel_toggled(); - void ensure_focus_current(); void apply_scripts() const; void open_script_create_dialog(const String &p_base_name, const String &p_base_path); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 5b0e1ce5b5..6e174653f6 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -714,6 +714,8 @@ ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) { shader_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE); button = editor->add_bottom_panel_item(TTR("Shader"), shader_editor); button->hide(); + + _2d = false; } ShaderEditorPlugin::~ShaderEditorPlugin() { diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index d662714752..22f50c0689 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -264,12 +264,7 @@ void BoneTransformEditor::_update_transform_properties(Transform tform) { } BoneTransformEditor::BoneTransformEditor(Skeleton3D *p_skeleton) : - skeleton(p_skeleton), - key_button(nullptr), - enabled_checkbox(nullptr), - keyable(false), - toggle_enabled(false), - updating(false) { + skeleton(p_skeleton) { undo_redo = EditorNode::get_undo_redo(); } diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 7843fc1754..44dc1bc36e 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -47,13 +47,13 @@ class EditorPropertyVector3; class BoneTransformEditor : public VBoxContainer { GDCLASS(BoneTransformEditor, VBoxContainer); - EditorInspectorSection *section; + EditorInspectorSection *section = nullptr; - EditorPropertyVector3 *translation_property; - EditorPropertyVector3 *rotation_property; - EditorPropertyVector3 *scale_property; - EditorInspectorSection *transform_section; - EditorPropertyTransform *transform_property; + EditorPropertyVector3 *translation_property = nullptr; + EditorPropertyVector3 *rotation_property = nullptr; + EditorPropertyVector3 *scale_property = nullptr; + EditorInspectorSection *transform_section = nullptr; + EditorPropertyTransform *transform_property = nullptr; Rect2 background_rects[5]; @@ -62,12 +62,12 @@ class BoneTransformEditor : public VBoxContainer { UndoRedo *undo_redo; - Button *key_button; - CheckBox *enabled_checkbox; + Button *key_button = nullptr; + CheckBox *enabled_checkbox = nullptr; - bool keyable; - bool toggle_enabled; - bool updating; + bool keyable = false; + bool toggle_enabled = false; + bool updating = false; String label; @@ -128,7 +128,6 @@ class Skeleton3DEditor : public VBoxContainer { struct BoneInfo { PhysicalBone3D *physical_bone = nullptr; Transform relative_rest; // Relative to skeleton node - BoneInfo() {} }; EditorNode *editor; @@ -136,20 +135,20 @@ class Skeleton3DEditor : public VBoxContainer { Skeleton3D *skeleton; - Tree *joint_tree; - BoneTransformEditor *rest_editor; - BoneTransformEditor *pose_editor; - BoneTransformEditor *custom_pose_editor; + Tree *joint_tree = nullptr; + BoneTransformEditor *rest_editor = nullptr; + BoneTransformEditor *pose_editor = nullptr; + BoneTransformEditor *custom_pose_editor = nullptr; - MenuButton *options; - EditorFileDialog *file_dialog; + MenuButton *options = nullptr; + EditorFileDialog *file_dialog = nullptr; - UndoRedo *undo_redo; + UndoRedo *undo_redo = nullptr; void _on_click_option(int p_option); void _file_selected(const String &p_file); - EditorFileDialog *file_export_lib; + EditorFileDialog *file_export_lib = nullptr; void update_joint_tree(); void update_editors(); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 8ab82b63c3..dd53f60014 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -507,13 +507,6 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture2D>()); } - List<StringName> shaders; - base_theme->get_shader_list(type, &shaders); - - for (List<StringName>::Element *E = shaders.front(); E; E = E->next()) { - theme->set_shader(E->get(), type, import ? base_theme->get_shader(E->get(), type) : Ref<Shader>()); - } - List<StringName> styleboxs; base_theme->get_stylebox_list(type, &styleboxs); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 6c0efcb254..189e5ec442 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -409,7 +409,7 @@ void TileMapEditor::_sbox_input(const Ref<InputEvent> &p_ie) { // In modern C++ this could have been inside its body. namespace { struct _PaletteEntry { - int id; + int id = 0; String name; bool operator<(const _PaletteEntry &p_rhs) const { diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index 848704e830..3a4cb22ac1 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -131,8 +131,6 @@ class TileMapEditor : public VBoxContainer { bool yf = false; bool tr = false; Vector2 ac; - - CellOp() {} }; Map<Point2i, CellOp> paint_undo; @@ -144,8 +142,6 @@ class TileMapEditor : public VBoxContainer { bool flip_v = false; bool transpose = false; Point2i autotile_coord; - - TileData() {} }; List<TileData> copydata; diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 6d2fd65dd6..900a2c75a0 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -2359,8 +2359,8 @@ void TileSetEditor::_set_edited_collision_shape(const Ref<Shape2D> &p_shape) { } void TileSetEditor::_set_snap_step(Vector2 p_val) { - snap_step.x = CLAMP(p_val.x, 0, 256); - snap_step.y = CLAMP(p_val.y, 0, 256); + snap_step.x = CLAMP(p_val.x, 1, 256); + snap_step.y = CLAMP(p_val.y, 1, 256); workspace->update(); } @@ -3620,11 +3620,11 @@ void TileSetEditorPlugin::make_visible(bool p_visible) { if (p_visible) { tileset_editor_button->show(); editor->make_bottom_panel_item_visible(tileset_editor); - get_tree()->connect_compat("idle_frame", tileset_editor, "_on_workspace_process"); + get_tree()->connect("idle_frame", Callable(tileset_editor, "_on_workspace_process")); } else { editor->hide_bottom_panel(); tileset_editor_button->hide(); - get_tree()->disconnect_compat("idle_frame", tileset_editor, "_on_workspace_process"); + get_tree()->disconnect("idle_frame", Callable(tileset_editor, "_on_workspace_process")); } } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 6112e69299..07061a4bc5 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -49,7 +49,7 @@ struct FloatConstantDef { String name; - float value; + float value = 0; String desc; }; @@ -4062,9 +4062,6 @@ void VisualShaderNodePortPreview::_notification(int p_what) { void VisualShaderNodePortPreview::_bind_methods() { } -VisualShaderNodePortPreview::VisualShaderNodePortPreview() { -} - ////////////////////////////////// String VisualShaderConversionPlugin::converts_to() const { diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 2e7e9a8898..a5983410f9 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -56,26 +56,26 @@ class VisualShaderGraphPlugin : public Reference { private: struct InputPort { - Button *default_input_button; + Button *default_input_button = nullptr; }; struct Port { - TextureButton *preview_button; + TextureButton *preview_button = nullptr; }; struct Link { - VisualShader::Type type; - VisualShaderNode *visual_node; - GraphNode *graph_node; - bool preview_visible; - int preview_pos; + VisualShader::Type type = VisualShader::Type::TYPE_MAX; + VisualShaderNode *visual_node = nullptr; + GraphNode *graph_node = nullptr; + bool preview_visible = 0; + int preview_pos = 0; Map<int, InputPort> input_ports; Map<int, Port> output_ports; - VBoxContainer *preview_box; - LineEdit *uniform_name; - OptionButton *const_op; - CodeEdit *expression_edit; - CurveEditor *curve_editor; + VBoxContainer *preview_box = nullptr; + LineEdit *uniform_name = nullptr; + OptionButton *const_op = nullptr; + CodeEdit *expression_edit = nullptr; + CurveEditor *curve_editor = nullptr; }; Ref<VisualShader> visual_shader; @@ -206,16 +206,16 @@ class VisualShaderEditor : public VBoxContainer { String category; String type; String description; - int sub_func; + int sub_func = 0; String sub_func_str; Ref<Script> script; - int mode; - int return_type; - int func; - float value; - bool highend; - bool is_custom; - int temp_idx; + int mode = 0; + int return_type = 0; + int func = 0; + float value = 0; + bool highend = false; + bool is_custom = false; + int temp_idx = 0; AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1, bool p_highend = false) { name = p_name; @@ -283,8 +283,8 @@ class VisualShaderEditor : public VBoxContainer { static VisualShaderEditor *singleton; struct DragOp { - VisualShader::Type type; - int node; + VisualShader::Type type = VisualShader::Type::TYPE_MAX; + int node = 0; Vector2 from; Vector2 to; }; @@ -462,9 +462,9 @@ public: class VisualShaderNodePortPreview : public Control { GDCLASS(VisualShaderNodePortPreview, Control); Ref<VisualShader> shader; - VisualShader::Type type; - int node; - int port; + VisualShader::Type type = VisualShader::Type::TYPE_MAX; + int node = 0; + int port = 0; void _shader_changed(); //must regen protected: void _notification(int p_what); @@ -473,7 +473,6 @@ protected: public: virtual Size2 get_minimum_size() const override; void setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port); - VisualShaderNodePortPreview(); }; class VisualShaderConversionPlugin : public EditorResourceConversionPlugin { diff --git a/editor/progress_dialog.h b/editor/progress_dialog.h index 753b6ac955..d8a33cc2cc 100644 --- a/editor/progress_dialog.h +++ b/editor/progress_dialog.h @@ -43,8 +43,8 @@ class BackgroundProgress : public HBoxContainer { _THREAD_SAFE_CLASS_ struct Task { - HBoxContainer *hb; - ProgressBar *progress; + HBoxContainer *hb = nullptr; + ProgressBar *progress = nullptr; }; Map<String, Task> tasks; @@ -70,9 +70,9 @@ class ProgressDialog : public PopupPanel { GDCLASS(ProgressDialog, PopupPanel); struct Task { String task; - VBoxContainer *vb; - ProgressBar *progress; - Label *state; + VBoxContainer *vb = nullptr; + ProgressBar *progress = nullptr; + Label *state = nullptr; }; HBoxContainer *cancel_hb; Button *cancel; diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 75509c7544..8435dccf4a 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -865,10 +865,10 @@ void ProjectExportDialog::_validate_export_path(const String &p_path) { if (invalid_path) { export_project->get_ok()->set_disabled(true); - export_project->get_line_edit()->disconnect_compat("text_entered", export_project, "_file_entered"); + export_project->get_line_edit()->disconnect("text_entered", Callable(export_project, "_file_entered")); } else { export_project->get_ok()->set_disabled(false); - export_project->get_line_edit()->connect_compat("text_entered", export_project, "_file_entered"); + export_project->get_line_edit()->connect("text_entered", Callable(export_project, "_file_entered")); } } @@ -900,9 +900,9 @@ void ProjectExportDialog::_export_project() { // with _validate_export_path. // FIXME: This is a hack, we should instead change EditorFileDialog to allow // disabling validation by the "text_entered" signal. - if (!export_project->get_line_edit()->is_connected_compat("text_entered", export_project, "_file_entered")) { + if (!export_project->get_line_edit()->is_connected("text_entered", Callable(export_project, "_file_entered"))) { export_project->get_ok()->set_disabled(false); - export_project->get_line_edit()->connect_compat("text_entered", export_project, "_file_entered"); + export_project->get_line_edit()->connect("text_entered", Callable(export_project, "_file_entered")); } export_project->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 47b1135133..3ec0c5a6a4 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -984,13 +984,13 @@ public: String path; String icon; String main_scene; - uint64_t last_edited; - bool favorite; - bool grayed; - bool missing; - int version; + uint64_t last_edited = 0; + bool favorite = false; + bool grayed = false; + bool missing = false; + int version = 0; - ProjectListItemControl *control; + ProjectListItemControl *control = nullptr; Item() {} @@ -1076,7 +1076,7 @@ private: }; struct ProjectListComparator { - FilterOption order_option; + FilterOption order_option = FilterOption::EDIT_DATE; // operator< _FORCE_INLINE_ bool operator()(const ProjectList::Item &a, const ProjectList::Item &b) const { diff --git a/editor/pvrtc_compress.cpp b/editor/pvrtc_compress.cpp deleted file mode 100644 index 23bcf9540e..0000000000 --- a/editor/pvrtc_compress.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/*************************************************************************/ -/* pvrtc_compress.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "pvrtc_compress.h" - -#include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" -#include "core/os/os.h" -#include "editor_settings.h" -#include "scene/resources/texture.h" - -static void (*_base_image_compress_pvrtc2_func)(Image *) = nullptr; -static void (*_base_image_compress_pvrtc4_func)(Image *) = nullptr; - -static void _compress_image(Image::CompressMode p_mode, Image *p_image) { - String ttpath = EditorSettings::get_singleton()->get("filesystem/import/pvrtc_texture_tool"); - - if (ttpath.strip_edges() == "" || !FileAccess::exists(ttpath)) { - switch (p_mode) { - case Image::COMPRESS_PVRTC2: - if (_base_image_compress_pvrtc2_func) { - _base_image_compress_pvrtc2_func(p_image); - } else if (_base_image_compress_pvrtc4_func) { - _base_image_compress_pvrtc4_func(p_image); - } - break; - case Image::COMPRESS_PVRTC4: - if (_base_image_compress_pvrtc4_func) { - _base_image_compress_pvrtc4_func(p_image); - } - break; - default: - ERR_FAIL_MSG("Unsupported Image compress mode used in PVRTC module."); - } - return; - } - - String tmppath = EditorSettings::get_singleton()->get_cache_dir(); - String src_img = tmppath.plus_file("_tmp_src_img.png"); - String dst_img = tmppath.plus_file("_tmp_dst_img.pvr"); - - List<String> args; - args.push_back("-i"); - args.push_back(src_img); - args.push_back("-o"); - args.push_back(dst_img); - args.push_back("-f"); - - switch (p_mode) { - case Image::COMPRESS_PVRTC2: - args.push_back("PVRTC2"); - break; - case Image::COMPRESS_PVRTC4: - args.push_back("PVRTC4"); - break; - case Image::COMPRESS_ETC: - args.push_back("ETC"); - break; - default: - ERR_FAIL_MSG("Unsupported Image compress mode used in PVRTC module."); - } - - if (EditorSettings::get_singleton()->get("filesystem/import/pvrtc_fast_conversion").operator bool()) { - args.push_back("-pvrtcfast"); - } - if (p_image->has_mipmaps()) { - args.push_back("-m"); - } - - // Save source PNG. - Ref<ImageTexture> t = memnew(ImageTexture); - t->create_from_image(Ref<Image>(p_image)); - ResourceSaver::save(src_img, t); - - Error err = OS::get_singleton()->execute(ttpath, args, true); - if (err != OK) { - // Clean up generated files. - DirAccess::remove_file_or_error(src_img); - DirAccess::remove_file_or_error(dst_img); - ERR_FAIL_MSG("Could not execute PVRTC tool: " + ttpath); - } - - t = ResourceLoader::load(dst_img, "Texture2D"); - if (t.is_null()) { - // Clean up generated files. - DirAccess::remove_file_or_error(src_img); - DirAccess::remove_file_or_error(dst_img); - ERR_FAIL_MSG("Can't load back converted image using PVRTC tool."); - } - - p_image->copy_internals_from(t->get_data()); - - // Clean up generated files. - DirAccess::remove_file_or_error(src_img); - DirAccess::remove_file_or_error(dst_img); -} - -static void _compress_pvrtc2(Image *p_image) { - _compress_image(Image::COMPRESS_PVRTC2, p_image); -} - -static void _compress_pvrtc4(Image *p_image) { - _compress_image(Image::COMPRESS_PVRTC4, p_image); -} - -void _pvrtc_register_compressors() { - _base_image_compress_pvrtc2_func = Image::_image_compress_pvrtc2_func; - _base_image_compress_pvrtc4_func = Image::_image_compress_pvrtc4_func; - - Image::_image_compress_pvrtc2_func = _compress_pvrtc2; - Image::_image_compress_pvrtc4_func = _compress_pvrtc4; -} diff --git a/editor/quick_open.h b/editor/quick_open.h index 3b199f9561..a507a0da9c 100644 --- a/editor/quick_open.h +++ b/editor/quick_open.h @@ -49,7 +49,7 @@ class EditorQuickOpen : public ConfirmationDialog { struct Entry { String path; - float score; + float score = 0; }; struct EntryComparator { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index fafb90e864..91dffb504f 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1073,14 +1073,14 @@ void SceneTreeDock::_notification(int p_what) { CanvasItemEditorPlugin *canvas_item_plugin = Object::cast_to<CanvasItemEditorPlugin>(editor_data->get_editor("2D")); if (canvas_item_plugin) { - canvas_item_plugin->get_canvas_item_editor()->connect_compat("item_lock_status_changed", scene_tree, "_update_tree"); - canvas_item_plugin->get_canvas_item_editor()->connect_compat("item_group_status_changed", scene_tree, "_update_tree"); + canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree")); + canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree")); scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::update)); } Node3DEditorPlugin *spatial_editor_plugin = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor("3D")); - spatial_editor_plugin->get_spatial_editor()->connect_compat("item_lock_status_changed", scene_tree, "_update_tree"); - spatial_editor_plugin->get_spatial_editor()->connect_compat("item_group_status_changed", scene_tree, "_update_tree"); + spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree")); + spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree")); button_add->set_icon(get_theme_icon("Add", "EditorIcons")); button_instance->set_icon(get_theme_icon("Instance", "EditorIcons")); @@ -1934,23 +1934,6 @@ void SceneTreeDock::_selection_changed() { _update_script_button(); } -Node *SceneTreeDock::_get_selection_group_tail(Node *p_node, List<Node *> p_list) { - Node *tail = p_node; - Node *parent = tail->get_parent(); - - for (int i = p_node->get_index(); i < parent->get_child_count(); i++) { - Node *sibling = parent->get_child(i); - - if (p_list.find(sibling)) { - tail = sibling; - } else { - break; - } - } - - return tail; -} - void SceneTreeDock::_do_create(Node *p_parent) { Object *c = create_dialog->instance_selected(); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 119a499d0f..2b3593358e 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -203,7 +203,6 @@ class SceneTreeDock : public VBoxContainer { bool _validate_no_foreign(); void _selection_changed(); void _update_script_button(); - Node *_get_selection_group_tail(Node *p_node, List<Node *> p_list); void _fill_path_renames(Vector<StringName> base_path, Vector<StringName> new_base_path, Node *p_node, List<Pair<NodePath, NodePath>> *p_renames); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 3ec012ce3c..685833da55 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -829,10 +829,6 @@ void SceneTreeEditor::set_display_foreign_nodes(bool p_display) { _update_tree(); } -bool SceneTreeEditor::get_display_foreign_nodes() const { - return display_foreign; -} - void SceneTreeEditor::set_valid_types(const Vector<StringName> &p_valid) { valid_types = p_valid; } diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index 9373ef41f9..e2bf9bc41d 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -138,7 +138,6 @@ public: void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }; void set_display_foreign_nodes(bool p_display); - bool get_display_foreign_nodes() const; void set_marked(const Set<Node *> &p_marked, bool p_selectable = false, bool p_children_selectable = true); void set_marked(Node *p_marked, bool p_selectable = false, bool p_children_selectable = true); diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 40415ea209..a73be29259 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -86,8 +86,8 @@ class ScriptCreateDialog : public ConfirmationDialog { SCRIPT_ORIGIN_EDITOR, }; struct ScriptTemplateInfo { - int id; - ScriptOrigin origin; + int id = 0; + ScriptOrigin origin = ScriptOrigin::SCRIPT_ORIGIN_EDITOR; String dir; String name; String extension; diff --git a/editor/translations/af.po b/editor/translations/af.po index 3a699cee71..a42302460b 100644 --- a/editor/translations/af.po +++ b/editor/translations/af.po @@ -5,12 +5,13 @@ # Ray West <the.raxar@gmail.com>, 2017. # Julius Stopforth <jjstopforth@gmail.com>, 2018. # Isa Tippens <isatippens2@gmail.com>, 2019. +# Henry Geyser <thegoat187@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2019-03-28 09:36+0000\n" -"Last-Translator: Isa Tippens <isatippens2@gmail.com>\n" +"PO-Revision-Date: 2020-12-01 20:29+0000\n" +"Last-Translator: Henry Geyser <thegoat187@gmail.com>\n" "Language-Team: Afrikaans <https://hosted.weblate.org/projects/godot-engine/" "godot/af/>\n" "Language: af\n" @@ -18,7 +19,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.6-dev\n" +"X-Generator: Weblate 4.4-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -27,7 +28,7 @@ msgstr "Ongeldige tiepe argument om te omskep(), gebruik TYPE_* konstante" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." -msgstr "" +msgstr "Verwag 'n string van lengte 1 ('n karakter)." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp @@ -50,72 +51,71 @@ msgstr "Ongeldige operande vir operateur %s, %s en %s." #: core/math/expression.cpp msgid "Invalid index of type %s for base type %s" -msgstr "" +msgstr "Ongeldige indeks van tipe %s vir basiese tipe %s" #: core/math/expression.cpp msgid "Invalid named index '%s' for base type %s" -msgstr "" +msgstr "Ongeldige benaming van indeks '%s' vir basiese tipe %s" #: core/math/expression.cpp msgid "Invalid arguments to construct '%s'" -msgstr "" +msgstr "Ongeldige argument om '%s' te genereer" #: core/math/expression.cpp msgid "On call to '%s':" -msgstr "" +msgstr "Aan roep tot '%s':" #: core/ustring.cpp msgid "B" -msgstr "" +msgstr "B" #: core/ustring.cpp msgid "KiB" -msgstr "" +msgstr "KiB" #: core/ustring.cpp msgid "MiB" -msgstr "" +msgstr "MiB" #: core/ustring.cpp msgid "GiB" -msgstr "" +msgstr "GiB" #: core/ustring.cpp msgid "TiB" -msgstr "" +msgstr "TiB" #: core/ustring.cpp msgid "PiB" -msgstr "" +msgstr "PiB" #: core/ustring.cpp msgid "EiB" -msgstr "" +msgstr "EiB" #: editor/animation_bezier_editor.cpp msgid "Free" -msgstr "Bevry" +msgstr "Bevry / Verniet" #: editor/animation_bezier_editor.cpp msgid "Balanced" -msgstr "" +msgstr "Gebalanseer" #: editor/animation_bezier_editor.cpp msgid "Mirror" -msgstr "" +msgstr "Spieel" #: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp msgid "Time:" -msgstr "" +msgstr "Tyd:" #: editor/animation_bezier_editor.cpp msgid "Value:" -msgstr "" +msgstr "Waarde:" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Insert Key Here" -msgstr "Anim Voeg Sleutel by" +msgstr "Voeg Sleutel Hier" #: editor/animation_bezier_editor.cpp #, fuzzy @@ -123,18 +123,16 @@ msgid "Duplicate Selected Key(s)" msgstr "Dupliseer Seleksie" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Delete Selected Key(s)" -msgstr "Skrap gekose lêers?" +msgstr "Skrap gekose sleutels" #: editor/animation_bezier_editor.cpp msgid "Add Bezier Point" -msgstr "" +msgstr "Voeg Bezier Punt By" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Move Bezier Points" -msgstr "Skuif Gunsteling Op" +msgstr "Verskuif Bezier Punte" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Duplicate Keys" @@ -145,9 +143,8 @@ msgid "Anim Delete Keys" msgstr "Anim Skrap Sleutels" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Change Keyframe Time" -msgstr "Anim Verander Waarde" +msgstr "Anim Verander Sleutelraam Tyd" #: editor/animation_track_editor.cpp msgid "Anim Change Transition" @@ -155,51 +152,44 @@ msgstr "Anim Verander Oorgang" #: editor/animation_track_editor.cpp msgid "Anim Change Transform" -msgstr "Anim Verander Transform" +msgstr "Anim Verander Transformasie" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Change Keyframe Value" -msgstr "Anim Verander Waarde" +msgstr "Anim Verander Sleutelraam Waarde" #: editor/animation_track_editor.cpp msgid "Anim Change Call" msgstr "Anim Verander Roep" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Keyframe Time" -msgstr "Anim Verander Waarde" +msgstr "Anim Herhaalde Verandering Van Sleutelraam Tye" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Transition" -msgstr "Anim Verander Oorgang" +msgstr "Anim Herhaalde Veranderinde Transisie" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Transform" -msgstr "Anim Verander Transform" +msgstr "Anim Herhaalde Verandering van Transformasie" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Keyframe Value" -msgstr "Anim Verander Waarde" +msgstr "Anim Herhaalde Verandering Van Sleutelraam Waarde" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Call" -msgstr "Anim Verander Roep" +msgstr "Anim Herhaalde Verandering van Roep" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Change Animation Length" -msgstr "Verander Anim Lente" +msgstr "Verander Animasie Lente" #: editor/animation_track_editor.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Change Animation Loop" -msgstr "" +msgstr "Verander Animasie Omloop" #: editor/animation_track_editor.cpp msgid "Property Track" @@ -1136,7 +1126,7 @@ msgstr "Verweerde Hulpbron Verkenner" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3716,6 +3706,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3770,26 +3770,12 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "Dupliseer" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Skuif AutoLaai" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "Stoor Hulpbron As..." @@ -3814,10 +3800,17 @@ msgid "Collapse All" msgstr "Vervang Alles" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +#, fuzzy +msgid "Duplicate..." +msgstr "Dupliseer" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Skuif AutoLaai" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3855,7 +3848,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9870,6 +9866,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12366,6 +12366,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12626,6 +12646,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/ar.po b/editor/translations/ar.po index ff705883d5..2bd95e230b 100644 --- a/editor/translations/ar.po +++ b/editor/translations/ar.po @@ -50,8 +50,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-25 14:09+0000\n" -"Last-Translator: Omar Aglan <omar.aglan91@yahoo.com>\n" +"PO-Revision-Date: 2020-12-07 08:11+0000\n" +"Last-Translator: Musab Alasaifer <mousablasefer@gmail.com>\n" "Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/" "godot/ar/>\n" "Language: ar\n" @@ -1071,15 +1071,15 @@ msgstr "" "يمكنك إيجاد Ø§Ù„Ù…Ù„ÙØ§Øª Ø§Ù„Ù…ØØ°ÙˆÙØ© ÙÙŠ سلة مهملات النظام ØÙŠØ« يمكنك إسترجاعها." #: editor/dependency_editor.cpp -#, fuzzy msgid "" "The files being removed are required by other resources in order for them to " "work.\n" "Remove them anyway? (no undo)\n" "You can find the removed files in the system trash to restore them." msgstr "" -"المل٠الذي ÙŠÙÙ…Ø³Ø Ù…Ø·Ù„ÙˆØ¨ من موارد أخري لكل تعمل جيداً.\n" -"Ø¥Ù…Ø³Ø Ø¹Ù„ÙŠ أية ØØ§Ù„ØŸ (لا رجعة)" +"Ø§Ù„Ù…Ù„ÙØ§Øª التي يتم إزالتها مطلوبة من قبل موارد أخرى من اجل ان تعمل.\n" +"هل تريد إزالتها على أي ØØ§Ù„ØŸ (لا تراجع)\n" +"يمكنك العثور على Ø§Ù„Ù…Ù„ÙØ§Øª التي تمت إزالتها ÙÙŠ مهملات النظام لاستعادتها." #: editor/dependency_editor.cpp msgid "Cannot remove:" @@ -1123,7 +1123,7 @@ msgstr "Ù…ØªØµÙØ الموارد Ø£ÙˆØ±ÙØ§Ù†" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -1632,22 +1632,20 @@ msgstr "" "Driver Fallback Enabled'." #: editor/editor_export.cpp -#, fuzzy msgid "" "Target platform requires 'PVRTC' texture compression for GLES2. Enable " "'Import Pvrtc' in Project Settings." msgstr "" -"المنصة Ø§Ù„Ù…Ø³ØªÙ‡Ø¯ÙØ© ØªØØªØ§Ø¬ لتشÙير ملمس 'ETC' Ù„ GLES2. قم بتمكين 'Import Etc' ÙÙŠ " -"إعدادات المشروع." +"المنصة Ø§Ù„Ù…Ø³ØªÙ‡Ø¯ÙØ© ØªØØªØ§Ø¬ لتشÙير ملمس 'PVRTC' Ù„ GLES2. قم بتمكين 'Import Pvrtc' " +"ÙÙŠ إعدادات المشروع." #: editor/editor_export.cpp -#, fuzzy msgid "" "Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. " "Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings." msgstr "" -"المنصة Ø§Ù„Ù…Ø³ØªÙ‡Ø¯ÙØ© ØªØØªØ§Ø¬ لتشÙير ملمس \"ETC2\" Ù„ GLES3. قم بتمكين 'Import Etc " -"2' ÙÙŠ إعدادات المشروع." +"المنصة Ø§Ù„Ù…Ø³ØªÙ‡Ø¯ÙØ© ØªØØªØ§Ø¬ لتشÙير ملمس \"ETC2\" او 'PVRTC' Ù„ GLES3. قم بتمكين " +"'Import Etc 2' او 'Import Pvrtc' ÙÙŠ إعدادات المشروع." #: editor/editor_export.cpp #, fuzzy @@ -3721,6 +3719,16 @@ msgid "Name contains invalid characters." msgstr "الأسم ÙŠØØªÙˆÙŠ Ø¹Ù„ÙŠ Ø£ØØ±Ù غير ØµØ§Ù„ØØ©." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "إعادة تسمية ملÙ:" @@ -3768,24 +3776,11 @@ msgstr "تعديل التبعيات..." msgid "View Owners..." msgstr "أظهر المÙلاك..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "إعادة تسمية..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "تكرير..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "ØªØØ±ÙŠÙƒ إلي..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "نقل التØÙ…يل التلقائي" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "مشهد جديد..." @@ -3808,11 +3803,17 @@ msgid "Collapse All" msgstr "طوي الكل" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "إعادة التسمية" +msgid "Duplicate..." +msgstr "تكرير..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "نقل التØÙ…يل التلقائي" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "إعادة تسمية..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3847,8 +3848,11 @@ msgid "Move" msgstr "ØªØØ±ÙŠÙƒ" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "يوجد Ø¨Ø§Ù„ÙØ¹Ù„ مل٠أو مجلد Ø¨Ù†ÙØ³ الاسم ÙÙŠ هذا المكان." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "إعادة التسمية" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9827,6 +9831,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12393,6 +12401,26 @@ msgstr "" "(CPUParticles2D) استخدام Ù„ÙˆØØ©-مادة-العنصر (CanvasItemMaterial) مع ØªÙØ¹ÙŠÙ„" "\"الرسوم Ø§Ù„Ù…ØªØØ±ÙƒØ© للجزيئات\"." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12730,6 +12758,26 @@ msgstr "" "بواسطة Ù…ØØ±Ùƒ الÙيزياء عند التشغيل.\n" "قم بتغيير Ø§Ù„ØØ¬Ù… ÙÙŠ أشكال تصادم الأتباع (Children) بدلاً من ذلك." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12970,6 +13018,9 @@ msgstr "يمكن تعيين المتغيرات Ùقط ÙÙŠ الذروة ." msgid "Constants cannot be modified." msgstr "لا يمكن تعديل الثوابت." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "يوجد Ø¨Ø§Ù„ÙØ¹Ù„ مل٠أو مجلد Ø¨Ù†ÙØ³ الاسم ÙÙŠ هذا المكان." + #~ msgid "Error trying to save layout!" #~ msgstr "خطآ ÙÙŠ Ù…ØØ§ÙˆÙ„Ø© ØÙظ النسق!" diff --git a/editor/translations/bg.po b/editor/translations/bg.po index bbf679961c..2f1a9145e4 100644 --- a/editor/translations/bg.po +++ b/editor/translations/bg.po @@ -12,11 +12,12 @@ # Stoyan <stoyan.stoyanov99@protonmail.com>, 2020. # zooid <the.zooid@gmail.com>, 2020. # Любомир ВаÑилев <lyubomirv@gmx.com>, 2020. +# Ziv D <wizdavid@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-08 10:26+0000\n" +"PO-Revision-Date: 2020-12-07 08:11+0000\n" "Last-Translator: Любомир ВаÑилев <lyubomirv@gmx.com>\n" "Language-Team: Bulgarian <https://hosted.weblate.org/projects/godot-engine/" "godot/bg/>\n" @@ -25,7 +26,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.3.2\n" +"X-Generator: Weblate 4.4-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -889,9 +890,8 @@ msgid "Signals" msgstr "" #: editor/connections_dialog.cpp -#, fuzzy msgid "Filter signals" -msgstr "ПоÑтавÑне на възелите" +msgstr "Филтриране на Ñигналите" #: editor/connections_dialog.cpp msgid "Are you sure you want to remove all connections from this signal?" @@ -1015,12 +1015,12 @@ msgid "Owners Of:" msgstr "" #: editor/dependency_editor.cpp -#, fuzzy msgid "" "Remove selected files from the project? (no undo)\n" "You can find the removed files in the system trash to restore them." msgstr "" -"Да Ñе премахнат ли избраните файлове от проекта? (ДейÑтвието е необратимо)" +"Да Ñе премахнат ли избраните файлове от проекта? (ДейÑтвието е необратимо)\n" +"Ще можете да ги откриете в кошчето, ако иÑкате да ги възÑтановите." #: editor/dependency_editor.cpp msgid "" @@ -1072,7 +1072,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -1629,9 +1629,8 @@ msgid "Node Dock" msgstr "Панел за възлите" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "FileSystem Dock" -msgstr "Показване във файловата ÑиÑтема" +msgstr "Панел за файловата ÑиÑтема" #: editor/editor_feature_profile.cpp msgid "Import Dock" @@ -1938,7 +1937,7 @@ msgstr "ÐаÑледÑва:" #: editor/editor_help.cpp msgid "Inherited by:" -msgstr "" +msgstr "ÐаÑледÑва Ñе от:" #: editor/editor_help.cpp msgid "Description" @@ -2396,9 +2395,8 @@ msgid "Can't reload a scene that was never saved." msgstr "Сцена, коÑто никога не е била запазвана, не може да бъде презаредена." #: editor/editor_node.cpp -#, fuzzy msgid "Reload Saved Scene" -msgstr "Запазване на Ñцената" +msgstr "Презареждане на запазената Ñцена" #: editor/editor_node.cpp msgid "" @@ -2864,9 +2862,8 @@ msgid "Q&A" msgstr "" #: editor/editor_node.cpp -#, fuzzy msgid "Report a Bug" -msgstr "Повторно внаÑÑне" +msgstr "Докладване на проблем" #: editor/editor_node.cpp msgid "Send Docs Feedback" @@ -3552,6 +3549,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Преименуване на файла:" @@ -3568,9 +3575,8 @@ msgid "Duplicating folder:" msgstr "" #: editor/filesystem_dock.cpp -#, fuzzy msgid "New Inherited Scene" -msgstr "Ðов Ñкрипт" +msgstr "Ðова Ñцена – наÑледник" #: editor/filesystem_dock.cpp msgid "Set As Main Scene" @@ -3600,24 +3606,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "ПремеÑтване на кадъра" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Ðова Ñцена..." @@ -3640,10 +3633,15 @@ msgid "Collapse All" msgstr "Свиване на вÑичко" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "ПремеÑтване в кошчето" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3677,7 +3675,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -4460,7 +4461,7 @@ msgstr "" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Directions" -msgstr "УказаниÑ" +msgstr "ÐаправлениÑ" #: editor/plugins/animation_player_editor_plugin.cpp #, fuzzy @@ -5259,9 +5260,8 @@ msgid "Create Custom Bone(s) from Node(s)" msgstr "Възпроизвеждане на Ñцена по избор" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Clear Bones" -msgstr "Възпроизвеждане на Ñцена по избор" +msgstr "ИзчиÑтване на коÑтите" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Make IK Chain" @@ -5280,9 +5280,8 @@ msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/texture_region_editor_plugin.cpp #: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp -#, fuzzy msgid "Zoom Reset" -msgstr "Оригинално увеличение" +msgstr "Връщане на Ð¾Ñ€Ð¸Ð³Ð¸Ð½Ð°Ð»Ð½Ð¸Ñ Ð¼Ð°Ñ‰Ð°Ð±" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -5317,9 +5316,8 @@ msgstr "Режим на завъртане" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Scale Mode" -msgstr "Режим на Селектиране" +msgstr "Режим на Ñкалиране" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -6330,9 +6328,8 @@ msgid "Transform UV Map" msgstr "" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Transform Polygon" -msgstr "Създаване на папка" +msgstr "Преобразуване на полигона" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Paint Bone Weights" @@ -6367,22 +6364,20 @@ msgid "Move Points" msgstr "ПремеÑтване на точките" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Command: Rotate" -msgstr "Влачене: завъртане" +msgstr "Command: завъртане" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Shift: Move All" msgstr "Shift: премеÑтване на вÑичко" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Shift+Command: Scale" -msgstr "Shift+Ctrl: мащабиране" +msgstr "Shift+Command: мащабиране" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Ctrl: Rotate" -msgstr "Ctrl: Завъртане" +msgstr "Ctrl: завъртане" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Shift+Ctrl: Scale" @@ -6423,14 +6418,12 @@ msgid "Radius:" msgstr "РадиуÑ:" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Copy Polygon to UV" -msgstr "Полигон -> UV" +msgstr "Копиране на полигона в UV" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Copy UV to Polygon" -msgstr "Превръщане в Polygon2D" +msgstr "Копиране на UV в полигона" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Clear UV" @@ -6694,9 +6687,8 @@ msgid "Copy Script Path" msgstr "" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "History Previous" -msgstr "ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ðазад" +msgstr "Ðазад в иÑториÑта" #: editor/plugins/script_editor_plugin.cpp msgid "History Next" @@ -7018,9 +7010,8 @@ msgid "This skeleton has no bones, create some children Bone2D nodes." msgstr "" #: editor/plugins/skeleton_2d_editor_plugin.cpp -#, fuzzy msgid "Create Rest Pose from Bones" -msgstr "Възпроизвеждане на Ñцена по избор" +msgstr "Създаване на поза на Ð¿Ð¾ÐºÐ¾Ñ Ð¾Ñ‚ коÑтите" #: editor/plugins/skeleton_2d_editor_plugin.cpp msgid "Set Rest Pose to Bones" @@ -7231,9 +7222,8 @@ msgid "View Information" msgstr "" #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "View FPS" -msgstr "Преглед на файловете" +msgstr "Показване на кадри/Ñек" #: editor/plugins/spatial_editor_plugin.cpp msgid "Half Resolution" @@ -7244,9 +7234,8 @@ msgid "Audio Listener" msgstr "" #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "Enable Doppler" -msgstr "Позволи филтриране" +msgstr "Включване на Ð´Ð¾Ð¿Ð»ÐµÑ€Ð¾Ð²Ð¸Ñ ÐµÑ„ÐµÐºÑ‚" #: editor/plugins/spatial_editor_plugin.cpp msgid "Cinematic Preview" @@ -7502,14 +7491,12 @@ msgid "Create Mesh2D" msgstr "Създаване на Mesh2D" #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Mesh2D Preview" -msgstr "Преглед" +msgstr "Преглед на Mesh2D" #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Create Polygon2D" -msgstr "Създаване на папка" +msgstr "Създаване на Polygon2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "Polygon2D Preview" @@ -7560,9 +7547,8 @@ msgid "Invalid geometry, can't create collision polygon." msgstr "" #: editor/plugins/sprite_editor_plugin.cpp -#, fuzzy msgid "Create CollisionPolygon2D Sibling" -msgstr "Създаване на папка" +msgstr "Създаване на ÑÑŠÑеден CollisionPolygon2D" #: editor/plugins/sprite_editor_plugin.cpp msgid "Invalid geometry, can't create light occluder." @@ -7649,9 +7635,8 @@ msgid "New Animation" msgstr "Ðова анимациÑ" #: editor/plugins/sprite_frames_editor_plugin.cpp -#, fuzzy msgid "Speed:" -msgstr "СкороÑÑ‚ (кадри в Ñекунда):" +msgstr "СкороÑÑ‚:" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Loop" @@ -7789,20 +7774,19 @@ msgstr "" #: editor/plugins/theme_editor_plugin.cpp msgid "Create Empty Template" -msgstr "" +msgstr "Създаване на празен шаблон" #: editor/plugins/theme_editor_plugin.cpp msgid "Create Empty Editor Template" -msgstr "" +msgstr "Създаване на празен шаблон за редактора" #: editor/plugins/theme_editor_plugin.cpp msgid "Create From Current Editor Theme" -msgstr "" +msgstr "Създаване от текущата тема на редактора" #: editor/plugins/theme_editor_plugin.cpp -#, fuzzy msgid "Toggle Button" -msgstr "Средно копче" +msgstr "Бутон-превключвател" #: editor/plugins/theme_editor_plugin.cpp msgid "Disabled Button" @@ -7906,9 +7890,8 @@ msgid "Color" msgstr "" #: editor/plugins/theme_editor_plugin.cpp -#, fuzzy msgid "Theme File" -msgstr "Тема" +msgstr "Файл Ñ Ñ‚ÐµÐ¼Ð°" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Erase Selection" @@ -7920,18 +7903,16 @@ msgstr "" #: editor/plugins/tile_map_editor_plugin.cpp #: modules/gridmap/grid_map_editor_plugin.cpp -#, fuzzy msgid "Cut Selection" -msgstr "Центрирай върху СелекциÑта" +msgstr "ИзрÑзване на избраното" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Paint TileMap" msgstr "" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Line Draw" -msgstr "Линейно" +msgstr "Изчертаване на линиÑ" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Rectangle Paint" @@ -7958,14 +7939,12 @@ msgid "Disable Autotile" msgstr "" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Enable Priority" -msgstr "Промени Филтрите" +msgstr "Включване на приоритета" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Filter tiles" -msgstr "ПоÑтавÑне на възелите" +msgstr "Филтриране на плочките" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Give a TileSet resource to this TileMap to use its tiles." @@ -7992,14 +7971,12 @@ msgid "Pick Tile" msgstr "" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Rotate Left" -msgstr "Режим на Завъртане" +msgstr "Завъртане налÑво" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Rotate Right" -msgstr "Завъртане на Полигон" +msgstr "Завъртане надÑÑно" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Flip Horizontally" @@ -8010,9 +7987,8 @@ msgid "Flip Vertically" msgstr "" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "Clear Transform" -msgstr "ИзнаÑÑне към платформа" +msgstr "ИзчиÑтване на транÑформациÑта" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Add Texture(s) to TileSet." @@ -8045,27 +8021,24 @@ msgid "New Atlas" msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Next Coordinate" -msgstr "Следващ Ñкрипт" +msgstr "Следваща координата" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Select the next shape, subtile, or Tile." msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Previous Coordinate" -msgstr "Предишен подпрозорец" +msgstr "Предходна координата" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Select the previous shape, subtile, or Tile." msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Region" -msgstr "Режим на Завъртане" +msgstr "Регион" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Collision" @@ -8077,28 +8050,24 @@ msgid "Occlusion" msgstr "ПриÑтавки" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Navigation" -msgstr "Ðнимационен Възел" +msgstr "ÐавигациÑ" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Bitmask" -msgstr "Режим на Завъртане" +msgstr "Побитова маÑка" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Priority" msgstr "Приоритет" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Z Index" -msgstr "Панорамен режим на ОтмеÑтване (на Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€ÐµÑ†)" +msgstr "Ð˜Ð½Ð´ÐµÐºÑ Ð¿Ð¾ Z" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Region Mode" -msgstr "Режим на Завъртане" +msgstr "Режим на регион" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Collision Mode" @@ -8110,28 +8079,24 @@ msgid "Occlusion Mode" msgstr "ПриÑтавки" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Navigation Mode" -msgstr "Ðнимационен Възел" +msgstr "Режим на навигациÑ" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Bitmask Mode" -msgstr "Режим на Завъртане" +msgstr "Режим на побитова маÑка" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Priority Mode" msgstr "Режим на приоритет" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Icon Mode" -msgstr "Панорамен режим на ОтмеÑтване (на Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€ÐµÑ†)" +msgstr "Режим на иконки" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Z Index Mode" -msgstr "Панорамен режим на ОтмеÑтване (на Ñ€Ð°Ð±Ð¾Ñ‚Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€ÐµÑ†)" +msgstr "Режим на Ð¸Ð½Ð´ÐµÐºÑ Ð¿Ð¾ Z" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Copy bitmask." @@ -8142,34 +8107,28 @@ msgid "Paste bitmask." msgstr "ПоÑтавÑне на битова маÑка." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Erase bitmask." -msgstr "Изтрий точки." +msgstr "Изтриване на побитовата маÑка." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Create a new rectangle." -msgstr "Създай нови възли." +msgstr "Създаване на нов правоъгълник." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Ðова Ñцена" +msgstr "Ðов правоъгълник" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Create a new polygon." -msgstr "Създай нов полигон от нулата." +msgstr "Създаване на нов полигон." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "ПремеÑтване на полигона" +msgstr "Ðов полигон" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Изтриване на избран(и) ключ(ове)" +msgstr "Изтриване на избраната форма" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -8189,9 +8148,10 @@ msgid "" msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Remove selected texture? This will remove all tiles which use it." -msgstr "ПремеÑтване на пътечката нагоре." +msgstr "" +"ПремеÑтване на избраната текÑтура? Това ще премахне вÑички плочки, които Ñ " +"ползват." #: editor/plugins/tile_set_editor_plugin.cpp msgid "You haven't selected a texture to remove." @@ -8206,9 +8166,8 @@ msgid "Merge from scene?" msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Remove Texture" -msgstr "ВнаÑÑне на текÑтури" +msgstr "Премахване на текÑтурата" #: editor/plugins/tile_set_editor_plugin.cpp msgid "%s file(s) were not added because was already on the list." @@ -8270,23 +8229,20 @@ msgstr "" "Щракнете на друга плочка, за да Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð°Ñ‚Ðµ." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Set Tile Region" -msgstr "Двуизмерна текÑтура" +msgstr "Задаване на регион от плочки" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Create Tile" -msgstr "Създаване на папка" +msgstr "Създаване на плочка" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Set Tile Icon" msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Edit Tile Bitmask" -msgstr "Промени Филтрите" +msgstr "Редактиране на побитовата маÑка на плочката" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Edit Collision Polygon" @@ -8302,33 +8258,28 @@ msgid "Edit Navigation Polygon" msgstr "Редактиране на полигона за навигациÑ" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Paste Tile Bitmask" -msgstr "ПоÑтавÑне на възелите" +msgstr "ПоÑтавÑне на побитовата маÑка на плочката" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Clear Tile Bitmask" msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Make Polygon Concave" -msgstr "ПремеÑтване на Полигон" +msgstr "Преобразуване на полигона във вдлъбнат" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Make Polygon Convex" -msgstr "ПремеÑтване на Полигон" +msgstr "Преобразуване на полигона в изпъкнал" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Remove Tile" -msgstr "ЗатварÑне на вÑичко" +msgstr "Премахване на плочката" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Remove Collision Polygon" -msgstr "ПремеÑтване на Полигон" +msgstr "Премахване на полигона за колизии" #: editor/plugins/tile_set_editor_plugin.cpp #, fuzzy @@ -8336,28 +8287,24 @@ msgid "Remove Occlusion Polygon" msgstr "ПремеÑтване на Полигон" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Remove Navigation Polygon" -msgstr "Завъртане на Полигон" +msgstr "Премахване на полигона за навигациÑ" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Edit Tile Priority" -msgstr "Промени Филтрите" +msgstr "Редактиране на приоритета на плочката" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Edit Tile Z Index" msgstr "" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Make Convex" -msgstr "ПремеÑтване на Полигон" +msgstr "Преобразуване в изпъкнал" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Make Concave" -msgstr "ПремеÑтване на Полигон" +msgstr "Преобразуване във вдлъбнат" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create Collision Polygon" @@ -8404,9 +8351,8 @@ msgid "Version Control System" msgstr "" #: editor/plugins/version_control_editor_plugin.cpp -#, fuzzy msgid "Initialize" -msgstr "Ð’ÑÑка дума Ñ Ð“Ð»Ð°Ð²Ð½Ð° буква" +msgstr "Инициализиране" #: editor/plugins/version_control_editor_plugin.cpp msgid "Staging area" @@ -8425,14 +8371,12 @@ msgid "Modified" msgstr "" #: editor/plugins/version_control_editor_plugin.cpp -#, fuzzy msgid "Renamed" -msgstr "Възел" +msgstr "Преименуван" #: editor/plugins/version_control_editor_plugin.cpp -#, fuzzy msgid "Deleted" -msgstr "Изтрий" +msgstr "Изтрит" #: editor/plugins/version_control_editor_plugin.cpp msgid "Typechange" @@ -8486,9 +8430,8 @@ msgid "Scalar" msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Vector" -msgstr "ИнÑпектор" +msgstr "Вектор" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Boolean" @@ -8551,9 +8494,8 @@ msgid "Add Node to Visual Shader" msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Node(s) Moved" -msgstr "Възелът е премеÑтен" +msgstr "Възлите Ñа премеÑтени" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Duplicate Nodes" @@ -9573,6 +9515,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -10307,9 +10253,8 @@ msgid "Instance Child Scene" msgstr "" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Detach Script" -msgstr "Закачане на Ñкрипт" +msgstr "Разкачане на Ñкрипта" #: editor/scene_tree_dock.cpp msgid "This operation can't be done on the tree root." @@ -10344,9 +10289,8 @@ msgid "Make node as Root" msgstr "Превръщане на възела в корен" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Delete %d nodes and any children?" -msgstr "Изтриване на %d възела?" +msgstr "Изтриване на %d възела и дъщерните им елементи?" #: editor/scene_tree_dock.cpp msgid "Delete %d nodes?" @@ -12059,6 +12003,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp #, fuzzy msgid "" @@ -12338,6 +12302,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp #, fuzzy msgid "" diff --git a/editor/translations/bn.po b/editor/translations/bn.po index 0ff139a1f1..4526860a7a 100644 --- a/editor/translations/bn.po +++ b/editor/translations/bn.po @@ -1123,7 +1123,7 @@ msgstr "মালিকবিহীন রিসোরà§à¦¸à§‡à¦° অনà§à¦¸à #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3916,6 +3916,16 @@ msgid "Name contains invalid characters." msgstr "গà§à¦°à¦¹à¦¨à¦¯à§‹à¦—à§à¦¯ অকà§à¦·à¦°à¦¸à¦®à§‚হ:" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp #, fuzzy msgid "Renaming file:" msgstr "চলক/à¦à§‡à¦°à¦¿à§Ÿà§‡à¦¬à¦²-à¦à¦° নামানà§à¦¤à¦° করà§à¦¨" @@ -3972,27 +3982,12 @@ msgstr "নিরà§à¦à¦°à¦¤à¦¾à¦¸à¦®à§‚হ সমà§à¦ªà¦¾à¦¦à¦¨ করà§à¦¨. msgid "View Owners..." msgstr "সà§à¦¬à¦¤à§à¦¬à¦¾à¦§à¦¿à¦•ারীদের দেখà§à¦¨..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -#, fuzzy -msgid "Rename..." -msgstr "পà§à¦¨à¦ƒà¦¨à¦¾à¦®à¦•রণ করà§à¦¨" - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "ডà§à¦ªà§à¦²à¦¿à¦•েট" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "à¦à¦–ানে সরান..." #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Autoload সà§à¦¥à¦¾à¦¨à¦¾à¦¨à§à¦¤à¦° করà§à¦¨" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "নতà§à¦¨ দৃশà§à¦¯" @@ -4019,10 +4014,18 @@ msgid "Collapse All" msgstr "কলাপà§à¦¸ করà§à¦¨" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +#, fuzzy +msgid "Duplicate..." +msgstr "ডà§à¦ªà§à¦²à¦¿à¦•েট" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Autoload সà§à¦¥à¦¾à¦¨à¦¾à¦¨à§à¦¤à¦° করà§à¦¨" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +#, fuzzy +msgid "Rename..." msgstr "পà§à¦¨à¦ƒà¦¨à¦¾à¦®à¦•রণ করà§à¦¨" #: editor/filesystem_dock.cpp @@ -4062,9 +4065,11 @@ msgid "Move" msgstr "সরান" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "There is already file or folder with the same name in this location." -msgstr "গà§à¦°à§à¦ªà§‡à¦° নাম ইতিমধà§à¦¯à§‡à¦‡ আছে!" +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "পà§à¦¨à¦ƒà¦¨à¦¾à¦®à¦•রণ করà§à¦¨" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -10437,6 +10442,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -13134,6 +13143,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp #, fuzzy msgid "" @@ -13428,6 +13457,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp #, fuzzy msgid "" @@ -13653,6 +13702,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#, fuzzy +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "গà§à¦°à§à¦ªà§‡à¦° নাম ইতিমধà§à¦¯à§‡à¦‡ আছে!" + #~ msgid "Error trying to save layout!" #~ msgstr "লেআউট/নকশা সংরকà§à¦·à¦£à§‡à¦° চেষà§à¦Ÿà¦¾à§Ÿ সমসà§à¦¯à¦¾ হয়েছে!" diff --git a/editor/translations/ca.po b/editor/translations/ca.po index 36f6096591..d0921e2a61 100644 --- a/editor/translations/ca.po +++ b/editor/translations/ca.po @@ -1100,7 +1100,7 @@ msgstr "Navegador de Recursos Orfes" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3747,6 +3747,16 @@ msgid "Name contains invalid characters." msgstr "El Nom conté carà cters que no són và lids." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Reanomenant fitxer:" @@ -3795,24 +3805,11 @@ msgstr "Edita Dependències..." msgid "View Owners..." msgstr "Mostra Propietaris..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Reanomena..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplica..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Mou cap a..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Mou l'AutoCà rrega" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nova Escena..." @@ -3835,11 +3832,17 @@ msgid "Collapse All" msgstr "Col·lapsar tot" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Reanomena" +msgid "Duplicate..." +msgstr "Duplica..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Mou l'AutoCà rrega" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Reanomena..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3874,8 +3877,11 @@ msgid "Move" msgstr "Mou" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Ja hi existex un fitxer o directori amb aquest nom." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Reanomena" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -10086,6 +10092,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12752,6 +12762,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp #, fuzzy msgid "" @@ -13080,6 +13110,26 @@ msgstr "" "RigidBody(Carà cter o RÃgid). \n" "Modifica la mida de les Formes de Col. lisió Filles." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp #, fuzzy msgid "" @@ -13327,6 +13377,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Les constants no es poden modificar." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Ja hi existex un fitxer o directori amb aquest nom." + #~ msgid "Error trying to save layout!" #~ msgstr "Error en desar els canvis!" diff --git a/editor/translations/cs.po b/editor/translations/cs.po index fc0a47e554..4dd0050197 100644 --- a/editor/translations/cs.po +++ b/editor/translations/cs.po @@ -28,7 +28,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-20 23:08+0000\n" +"PO-Revision-Date: 2020-11-29 08:28+0000\n" "Last-Translator: Václav Blažej <vaclavblazej@seznam.cz>\n" "Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/" "cs/>\n" @@ -1107,7 +1107,7 @@ msgstr "PrůzkumnÃk osiÅ™elých zdrojů" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3709,6 +3709,16 @@ msgid "Name contains invalid characters." msgstr "Jméno obsahuje neplatné znaky." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "PÅ™ejmenovávánà souboru:" @@ -3756,23 +3766,11 @@ msgstr "Upravit závislosti..." msgid "View Owners..." msgstr "Zobrazit vlastnÃky..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "PÅ™ejmenovat..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplikovat..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "PÅ™esunout do..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "PÅ™esunout do koÅ¡e" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nová scéna..." @@ -3795,11 +3793,16 @@ msgid "Collapse All" msgstr "Sbalit vÅ¡e" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "PÅ™ejmenovat" +msgid "Duplicate..." +msgstr "Duplikovat..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "PÅ™esunout do koÅ¡e" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "PÅ™ejmenovat..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3834,8 +3837,11 @@ msgid "Move" msgstr "PÅ™esunout" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Soubor nebo složka se stejným názvem již na tomto mÃstÄ› existuje." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "PÅ™ejmenovat" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8305,23 +8311,20 @@ msgid "Create a new rectangle." msgstr "VytvoÅ™it nový obdélnÃk." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Nakreslit obdélnÃk" +msgstr "Nový obdélnÃk" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "VytvoÅ™it nový polygon." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "PÅ™esunout polygon" +msgstr "Nový polygon" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Smazat vybraný" +msgstr "Smazat vybraný tvar" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9790,6 +9793,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12344,6 +12351,26 @@ msgstr "" "Animace CPUParticles2D vyžaduje použità CanvasItemMaterial se zapnutým " "\"Particles Animation\"." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12664,6 +12691,26 @@ msgstr "" "pÅ™epsány fyzikálnÃm enginem.\n" "Změňte velikost koliznÃch tvarů v uzlech potomků." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12903,6 +12950,9 @@ msgstr "OdliÅ¡nosti mohou být pÅ™iÅ™azeny pouze ve vertex funkci." msgid "Constants cannot be modified." msgstr "Konstanty nenà možné upravovat." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Soubor nebo složka se stejným názvem již na tomto mÃstÄ› existuje." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "Chybà složka \"build-tools\"!" diff --git a/editor/translations/da.po b/editor/translations/da.po index d9f131db67..b8dfa199e8 100644 --- a/editor/translations/da.po +++ b/editor/translations/da.po @@ -1140,7 +1140,7 @@ msgstr "Forældreløs ressource udforsker" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3809,6 +3809,16 @@ msgid "Name contains invalid characters." msgstr "Navnet indeholder ugyldige karakterer." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Omdøb fil:" @@ -3863,26 +3873,12 @@ msgstr "Rediger Afhængigheder..." msgid "View Owners..." msgstr "Vis Ejere..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Omdøb..." - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "Duplikere" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Flyt Til..." #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Flyt Autoload" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "Ny Scene" @@ -3909,11 +3905,18 @@ msgid "Collapse All" msgstr "Klap alle sammen" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Omdøb" +#, fuzzy +msgid "Duplicate..." +msgstr "Duplikere" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Flyt Autoload" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Omdøb..." #: editor/filesystem_dock.cpp #, fuzzy @@ -3952,9 +3955,11 @@ msgid "Move" msgstr "Flyt" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "There is already file or folder with the same name in this location." -msgstr "En fil eller mappe med dette navn findes allerede." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Omdøb" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -10080,6 +10085,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12655,6 +12664,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp #, fuzzy msgid "" @@ -12948,6 +12977,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp #, fuzzy msgid "" @@ -13172,6 +13221,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Konstanter kan ikke ændres." +#, fuzzy +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "En fil eller mappe med dette navn findes allerede." + #~ msgid "Error trying to save layout!" #~ msgstr "Fejl, under forsøg pÃ¥ at gemme layout!" diff --git a/editor/translations/de.po b/editor/translations/de.po index 2e7b01f9bb..a7c6f3dddc 100644 --- a/editor/translations/de.po +++ b/editor/translations/de.po @@ -66,8 +66,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-20 23:08+0000\n" -"Last-Translator: Günther Bohn <ciscouser@gmx.de>\n" +"PO-Revision-Date: 2020-12-01 20:29+0000\n" +"Last-Translator: So Wieso <sowieso@dukun.de>\n" "Language-Team: German <https://hosted.weblate.org/projects/godot-engine/" "godot/de/>\n" "Language: de\n" @@ -1154,7 +1154,7 @@ msgstr "Unbenutzte Dateien ansehen" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3787,6 +3787,16 @@ msgid "Name contains invalid characters." msgstr "Name enthält ungültige Zeichen." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Benenne Datei um:" @@ -3834,23 +3844,11 @@ msgstr "Abhängigkeiten bearbeiten..." msgid "View Owners..." msgstr "Zeige Besitzer..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Umbenennen..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplizieren..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Verschiebe zu..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "In Papierkorb werfen" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Neue Szene…" @@ -3873,11 +3871,16 @@ msgid "Collapse All" msgstr "Alle einklappen" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Umbenennen" +msgid "Duplicate..." +msgstr "Duplizieren..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "In Papierkorb werfen" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Umbenennen..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3912,10 +3915,11 @@ msgid "Move" msgstr "Verschieben" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "" -"Es existiert bereits eine Datei oder ein Ordner an diesem Pfad mit dem " -"angegebenen Namen." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Umbenennen" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8421,23 +8425,20 @@ msgid "Create a new rectangle." msgstr "Neues Rechteck erstellen." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Rechteck zeichnen" +msgstr "Neues Rechteck" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Neues Polygon erstellen." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "Polygon verschieben" +msgstr "Neues Polygon" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Auswahl löschen" +msgstr "Ausgewählte Form löschen" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9919,6 +9920,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12509,6 +12514,26 @@ msgstr "" "CPUParticles2D-Animationen benötigen ein CanvasItemMaterial mit der " "Eigenschaft „Particles Animation“ aktiviert." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12852,6 +12877,26 @@ msgstr "" "Die Größe der entsprechenden Collisionshape-Unterobjekte sollte stattdessen " "geändert werden." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13105,6 +13150,11 @@ msgstr "Varyings können nur in Vertex-Funktion zugewiesen werden." msgid "Constants cannot be modified." msgstr "Konstanten können nicht verändert werden." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "" +#~ "Es existiert bereits eine Datei oder ein Ordner an diesem Pfad mit dem " +#~ "angegebenen Namen." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "‚build-tools‘-Verzeichnis fehlt!" diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot index bb04c064f0..23a0ea8480 100644 --- a/editor/translations/editor.pot +++ b/editor/translations/editor.pot @@ -1050,7 +1050,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3526,6 +3526,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3573,23 +3583,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3612,10 +3610,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3649,7 +3652,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9421,6 +9427,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11834,6 +11844,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12094,6 +12124,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/el.po b/editor/translations/el.po index 0b2c2fa7b4..fde979b618 100644 --- a/editor/translations/el.po +++ b/editor/translations/el.po @@ -1099,7 +1099,7 @@ msgstr "ΕξεÏευνητής αχÏησιμοποίητων πόÏων" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3731,6 +3731,16 @@ msgid "Name contains invalid characters." msgstr "Το όνομα πεÏιÎχει άκυÏους χαÏακτήÏες." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Μετονομασία αÏχείου:" @@ -3778,24 +3788,11 @@ msgstr "ΕπεξεÏγασία εξαÏτήσεων..." msgid "View Owners..." msgstr "Î Ïοβολή ιδιοκτητών..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Μετονομασία..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "ΑναπαÏαγωγή..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Μετακίνηση σε..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Μετακίνηση AutoLoad" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "ÎÎα Σκηνή..." @@ -3818,11 +3815,17 @@ msgid "Collapse All" msgstr "ΣÏμπτυξη Όλων" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Μετονομασία" +msgid "Duplicate..." +msgstr "ΑναπαÏαγωγή..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Μετακίνηση AutoLoad" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Μετονομασία..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3857,8 +3860,11 @@ msgid "Move" msgstr "Μετακίνηση" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "ΥπάÏχει ήδη αÏχείο ή φάκελος με το ίδιο όνομα στη διαδÏομή." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Μετονομασία" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9879,6 +9885,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12470,6 +12480,26 @@ msgstr "" "Η κίνηση CPUParticles2D απαιτεί την χÏήση CanvasItemMaterial με το " "«Particles Animation» ενεÏγό." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12805,6 +12835,26 @@ msgstr "" "αντικατασταθοÏνε από την μηχανή φυσικής κατά την εκτÎλεση.\n" "Αλλάξτε μÎγεθος στα σχήματα σÏγκÏουσης των παιδιών." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13051,6 +13101,9 @@ msgstr "Τα «varying» μποÏοÏν να ανατεθοÏν μόνο στηΠmsgid "Constants cannot be modified." msgstr "Οι σταθεÏÎÏ‚ δεν μποÏοÏν να Ï„ÏοποποιηθοÏν." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "ΥπάÏχει ήδη αÏχείο ή φάκελος με το ίδιο όνομα στη διαδÏομή." + #~ msgid "Error trying to save layout!" #~ msgstr "Σφάλμα κατά την αποθήκευση διάταξης!" diff --git a/editor/translations/eo.po b/editor/translations/eo.po index 671c2e1c6d..c4b2e447f1 100644 --- a/editor/translations/eo.po +++ b/editor/translations/eo.po @@ -1086,7 +1086,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3630,6 +3630,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3678,23 +3688,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nova sceno..." @@ -3717,11 +3715,16 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Renomi" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "" #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3754,8 +3757,11 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "" +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Renomi" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9561,6 +9567,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp #, fuzzy msgid "" "Higher visual quality\n" @@ -12012,6 +12022,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12272,6 +12302,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/es.po b/editor/translations/es.po index aea60effae..6920aa1bf7 100644 --- a/editor/translations/es.po +++ b/editor/translations/es.po @@ -54,12 +54,13 @@ # José Manuel Jurado Bujalance <darkbird@vivaldi.net>, 2020. # Skarline <lihue-molina@hotmail.com>, 2020. # Oxixes <oxixes@protonmail.com>, 2020. +# David Aroca Rojas <arocarojasdavid@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-24 16:44+0000\n" -"Last-Translator: Skarline <lihue-molina@hotmail.com>\n" +"PO-Revision-Date: 2020-12-07 08:11+0000\n" +"Last-Translator: Lisandro Lorea <lisandrolorea@gmail.com>\n" "Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/" "godot/es/>\n" "Language: es\n" @@ -1150,7 +1151,7 @@ msgstr "Explorador de Recursos Huérfanos" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -2384,6 +2385,9 @@ msgid "" "To restore the Default layout to its base settings, use the Delete Layout " "option and delete the Default layout." msgstr "" +"Layout por defecto del editor sobreescrita.\n" +"Para recuperar el layout por defecto, utiliza la opción Eliminar Layout y " +"borra el Layout por defecto." #: editor/editor_node.cpp msgid "Layout name not found!" @@ -3784,6 +3788,16 @@ msgid "Name contains invalid characters." msgstr "El nombre contiene caracteres inválidos." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Renombrar archivo:" @@ -3831,23 +3845,11 @@ msgstr "Editar Dependencias..." msgid "View Owners..." msgstr "Ver Propietarios..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Renombrar..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplicar..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Mover a..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "Mover a la papelera" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nueva Escena..." @@ -3870,11 +3872,16 @@ msgid "Collapse All" msgstr "Colapsar Todo" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Renombrar" +msgid "Duplicate..." +msgstr "Duplicar..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Mover a la papelera" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Renombrar..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3909,8 +3916,11 @@ msgid "Move" msgstr "Mover" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Ya hay un archivo o carpeta con el mismo nombre en esta ubicación." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Renombrar" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -6641,7 +6651,7 @@ msgstr "Mover Puntos" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Command: Rotate" -msgstr "Comando: Rotar" +msgstr "Command: Rotar" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Shift: Move All" @@ -8410,23 +8420,20 @@ msgid "Create a new rectangle." msgstr "Cree un nuevo rectángulo." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Dibujar Rectángulo" +msgstr "Nuevo Rectángulo" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Crear un nuevo polÃgono." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "Mover PolÃgono" +msgstr "Nuevo PolÃgono" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Eliminar Seleccionados" +msgstr "Eliminar Formas Seleccionadas" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9909,6 +9916,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12308,7 +12319,7 @@ msgid "" "outputs." msgstr "" "No se puede copiar y renombrar el archivo de exportación, comprueba el " -"directorio del proyecto de graduación para ver los resultados." +"directorio del proyecto de gradle para ver los resultados." #: platform/iphone/export/export.cpp msgid "Identifier is missing." @@ -12510,6 +12521,26 @@ msgstr "" "La animación CPUParticles2D requiere el uso de un CanvasItemMaterial con " "\"Particles Animation\" activado." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12844,6 +12875,26 @@ msgstr "" "anulado por el motor de la fÃsica cuando esté ejecutándose.\n" "En su lugar, cambia el tamaño en las formas de colisión de los hijos." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13089,6 +13140,9 @@ msgstr "Solo se pueden asignar variaciones en funciones de vértice." msgid "Constants cannot be modified." msgstr "Las constantes no pueden modificarse." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Ya hay un archivo o carpeta con el mismo nombre en esta ubicación." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "¡No se encontró el directorio 'build-tools'!" diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po index 83a1334dd6..49b2358aed 100644 --- a/editor/translations/es_AR.po +++ b/editor/translations/es_AR.po @@ -20,8 +20,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-20 23:08+0000\n" -"Last-Translator: Skarline <lihue-molina@hotmail.com>\n" +"PO-Revision-Date: 2020-12-07 08:11+0000\n" +"Last-Translator: Lisandro Lorea <lisandrolorea@gmail.com>\n" "Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/" "godot-engine/godot/es_AR/>\n" "Language: es_AR\n" @@ -34,7 +34,8 @@ msgstr "" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Invalid type argument to convert(), use TYPE_* constants." -msgstr "Argumento de tipo incorrecto en convert(), utilizá constantes TYPE_*." +msgstr "" +"Tipo de argumento inválido para 'convert()', utiliza constantes TYPE_*." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." @@ -1045,15 +1046,15 @@ msgid "Owners Of:" msgstr "Dueños De:" #: editor/dependency_editor.cpp -#, fuzzy msgid "" "Remove selected files from the project? (no undo)\n" "You can find the removed files in the system trash to restore them." msgstr "" -"¿Eliminar los archivos seleccionados del proyecto? (No puede ser restaurado)" +"¿Eliminar los archivos seleccionados del proyecto? (irreversible)\n" +"Podés encontrar los archivos eliminados en la papelera de reciclaje del " +"sistema para restaurarlos." #: editor/dependency_editor.cpp -#, fuzzy msgid "" "The files being removed are required by other resources in order for them to " "work.\n" @@ -1062,7 +1063,9 @@ msgid "" msgstr "" "Los archivos que se están removiendo son requeridos por otros recursos para " "funcionar.\n" -"Quitarlos de todos modos? (imposible deshacer)" +"¿Eliminarlos de todos modos? (irreversible)\n" +"Podés encontrar los archivos eliminados en la papelera de reciclaje del " +"sistema para restaurarlos." #: editor/dependency_editor.cpp msgid "Cannot remove:" @@ -1106,7 +1109,7 @@ msgstr "Explorador de Recursos Huérfanos" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -1168,14 +1171,12 @@ msgid "Gold Sponsors" msgstr "Sponsor Oro" #: editor/editor_about.cpp -#, fuzzy msgid "Silver Sponsors" -msgstr "Donantes Plata" +msgstr "Sponsors Plata" #: editor/editor_about.cpp -#, fuzzy msgid "Bronze Sponsors" -msgstr "Donantes Bronce" +msgstr "Sponsors Bronce" #: editor/editor_about.cpp msgid "Mini Sponsors" @@ -1617,35 +1618,32 @@ msgstr "" "Respaldo Activado\"." #: editor/editor_export.cpp -#, fuzzy msgid "" "Target platform requires 'PVRTC' texture compression for GLES2. Enable " "'Import Pvrtc' in Project Settings." msgstr "" -"La plataforma de destino requiere compresión de texturas 'ETC' para GLES2. " -"Activá 'Import Etc' en Ajustes del Proyecto." +"La plataforma de destino requiere compresión de texturas 'PVRTC' para GLES2. " +"Activá 'Import Pvrtc' en Ajustes del Proyecto." #: editor/editor_export.cpp -#, fuzzy msgid "" "Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. " "Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings." msgstr "" -"La plataforma de destino requiere compresión de texturas 'ETC2' para GLES3. " -"Activá 'Importar Etc 2' en Ajustes del Proyecto." +"La plataforma de destino requiere compresión de texturas 'ETC2' o 'PVRTC' " +"para GLES3. Activá 'Import Etc 2' o 'Import Pvrtc' en Ajustes del Proyecto." #: editor/editor_export.cpp -#, fuzzy msgid "" "Target platform requires 'PVRTC' texture compression for the driver fallback " "to GLES2.\n" "Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback " "Enabled'." msgstr "" -"La plataforma de destino requiere compresión de texturas 'ETC' para usar " -"GLES2 como controlador de respaldo.\n" -"Activá 'Importar Etc' en Ajustes del Proyecto, o desactivá \"Controlador de " -"Respaldo Activado\"." +"La plataforma del objetivo requiere compresión de texturas 'PVRTC' para el " +"driver fallback de GLES2.\n" +"Activá Import Pvrtc' en la Ajustes del Proyecto, o desactiva 'Driver " +"Fallback Enabled'." #: editor/editor_export.cpp platform/android/export/export.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp @@ -1689,9 +1687,8 @@ msgid "Node Dock" msgstr "Dock de Nodos" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "FileSystem Dock" -msgstr "Sistema de Archivos" +msgstr "Panel de Sistema de Archivos" #: editor/editor_feature_profile.cpp msgid "Import Dock" @@ -2335,6 +2332,9 @@ msgid "" "An error occurred while trying to save the editor layout.\n" "Make sure the editor's user data path is writable." msgstr "" +"Ocurrió un error mientras se intentaba guardar el layout del editor.\n" +"Chequeá que la ruta de datos de usuario del editor tenga permisos de " +"escritura." #: editor/editor_node.cpp msgid "" @@ -2342,15 +2342,17 @@ msgid "" "To restore the Default layout to its base settings, use the Delete Layout " "option and delete the Default layout." msgstr "" +"Se sobreescribió el layout de editor Por Defecto.\n" +"Para restaurar el layout Por Defecto a su configuración de base, usá la " +"opcion Eliminar Layout y eliminá el layout Por Defecto." #: editor/editor_node.cpp msgid "Layout name not found!" msgstr "Nombre de layout no encontrado!" #: editor/editor_node.cpp -#, fuzzy msgid "Restored the Default layout to its base settings." -msgstr "Se restauró el layout por defecto a su configuración básica." +msgstr "Se restauró el layout Por Defecto a su configuración básica." #: editor/editor_node.cpp msgid "" @@ -2862,14 +2864,18 @@ msgid "" "mobile device).\n" "You don't need to enable it to use the GDScript debugger locally." msgstr "" +"Cuando esta opción está activada, al utilizar el deploy en un click, el " +"ejecutable intentará conectarse a la IP de este equipo para que el proyecto " +"en ejecución pueda ser depurado.\n" +"Esta opción está pensada para ser usada en la depuración remota " +"( normalmente con un dispositivo móvil).\n" +"No es necesario habilitarla para usar el depurador GDScript localmente." #: editor/editor_node.cpp -#, fuzzy msgid "Small Deploy with Network Filesystem" -msgstr "Deploy Pequeño con recursos en red" +msgstr "Deploy Reducido con el Sistema de Archivos en Red" #: editor/editor_node.cpp -#, fuzzy msgid "" "When this option is enabled, using one-click deploy for Android will only " "export an executable without the project data.\n" @@ -2878,74 +2884,68 @@ msgid "" "On Android, deploying will use the USB cable for faster performance. This " "option speeds up testing for projects with large assets." msgstr "" -"Cuando esta opción está activa, exportar o hacer deploy producirá un " -"ejecutable mÃnimo.\n" -"El sistema de archivos sera proveÃdo desde el proyecto por el editor sobre " -"la red.\n" -"En Android, deploy usará el cable USB para mejor performance. Esta opción " -"acelera el testeo para juegos con footprint grande." +"Cuando esta opción está activada, al usar deploy en un click para Android " +"sólo se exportará un ejecutable sin los datos del proyecto.\n" +"El sistema de archivos será proporcionado desde el proyecto por el editor a " +"través de la red.\n" +"En Android, el deploy usará el cable USB para un rendimiento más rápido. " +"Esta opción acelera las pruebas de los proyectos con recursos grandes." #: editor/editor_node.cpp msgid "Visible Collision Shapes" msgstr "Collision Shapes Visibles" #: editor/editor_node.cpp -#, fuzzy msgid "" "When this option is enabled, collision shapes and raycast nodes (for 2D and " "3D) will be visible in the running project." msgstr "" -"Los Collision shapes y nodos raycast (para 2D y 3D) serán visibles durante " -"la ejecución del juego cuando esta opción queda activada." +"Cuando esta opción está activada, las formas de colisión y los nodos de " +"raycast (para 2D y 3D) serán visibles en el proyecto en ejecución." #: editor/editor_node.cpp msgid "Visible Navigation" msgstr "Navegación Visible" #: editor/editor_node.cpp -#, fuzzy msgid "" "When this option is enabled, navigation meshes and polygons will be visible " "in the running project." msgstr "" -"Los meshes de navegación y los polÃgonos serán visibles durante la ejecución " -"del juego si esta opción queda activada." +"Cuando esta opción está activada, las mallas de navegación y los polÃgonos " +"serán visibles en el proyecto en ejecución." #: editor/editor_node.cpp -#, fuzzy msgid "Synchronize Scene Changes" msgstr "Sincronizar Cambios de Escena" #: editor/editor_node.cpp -#, fuzzy msgid "" "When this option is enabled, any changes made to the scene in the editor " "will be replicated in the running project.\n" "When used remotely on a device, this is more efficient when the network " "filesystem option is enabled." msgstr "" -"Cuando esta opción esté encendida, cualquier cambio hecho a la escena en el " -"editor será replicado en el juego en ejecución.\n" -"Cuando se usa remotamente en un dispositivo, esto es más eficiente con un " -"sistema de archivos remoto." +"Cuando esta opción esté activada, cualquier cambio hecho a la escena en el " +"editor será replicado en el proyecto en ejecución.\n" +"Cuando se usa remotamente en un dispositivo, esto es más eficiente cuando el " +"sistema la opción de sistema de archivos de redes esta activada." #: editor/editor_node.cpp -#, fuzzy msgid "Synchronize Script Changes" msgstr "Sincronizar Cambios en Scripts" #: editor/editor_node.cpp -#, fuzzy msgid "" "When this option is enabled, any script that is saved will be reloaded in " "the running project.\n" "When used remotely on a device, this is more efficient when the network " "filesystem option is enabled." msgstr "" -"Cuando esta opción está activa, cualquier script que se guarde sera vuelto a " -"cargar en el juego en ejecución.\n" -"Cuando se use remotamente en un dispositivo, esto es más eficiente con un " -"sistema de archivos de red." +"Cuando esta opción está activada, cualquier script que se guarde se " +"recargará en el proyecto en ejecución.\n" +"Cuando se utiliza de forma remota en un dispositivo, esto es más eficiente " +"cuando la opción de sistema de archivos en red está activada." #: editor/editor_node.cpp editor/script_create_dialog.cpp msgid "Editor" @@ -3423,7 +3423,6 @@ msgid "Add Key/Value Pair" msgstr "Agregar Par Clave/Valor" #: editor/editor_run_native.cpp -#, fuzzy msgid "" "No runnable export preset found for this platform.\n" "Please add a runnable preset in the Export menu or define an existing preset " @@ -3431,7 +3430,8 @@ msgid "" msgstr "" "No se encontró ningún preset de exportación ejecutable para esta " "plataforma.\n" -"Por favor agregue un preset ejecutable en el menú de exportación." +"Por favor agregá un preset ejecutable en el menú Exportar o definà un preset " +"como ejecutable." #: editor/editor_run_script.cpp msgid "Write your logic in the _run() method." @@ -3742,6 +3742,16 @@ msgid "Name contains invalid characters." msgstr "El nombre indicado contiene caracteres inválidos." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Renombrando archivo:" @@ -3789,24 +3799,11 @@ msgstr "Editar Dependencias..." msgid "View Owners..." msgstr "Ver Dueños..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Renombrar..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplicar..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Mover A..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Mover Autoload" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nueva Escena..." @@ -3829,11 +3826,16 @@ msgid "Collapse All" msgstr "Colapsar Todos" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Renombrar" +msgid "Duplicate..." +msgstr "Duplicar..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Mover a La Papelera" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Renombrar..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3868,8 +3870,11 @@ msgid "Move" msgstr "Mover" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Ya hay un archivo o carpeta con el mismo nombre en esta ubicación." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Renombrar" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -5274,50 +5279,43 @@ msgstr "Crear GuÃas Horizontales y Verticales" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)" -msgstr "" +msgstr "Ajustar el Offfset del Pivote del CanvasItem \"%s\" a (%d, %d)" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Rotate %d CanvasItems" -msgstr "Rotar CanvasItem" +msgstr "Rotar %d CanvasItems" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Rotate CanvasItem \"%s\" to %d degrees" -msgstr "Rotar CanvasItem" +msgstr "Rotar CanvasItem \"%s\" a %d grados" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Move CanvasItem \"%s\" Anchor" -msgstr "Mover CanvasItem" +msgstr "Mover Ancla del CanvasItem \"%s\"" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Scale Node2D \"%s\" to (%s, %s)" -msgstr "" +msgstr "Escalar Node2D \"%s\" a (%s, %s)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Resize Control \"%s\" to (%d, %d)" -msgstr "" +msgstr "Redimensionar Control \"%s\" a (%d, %d)" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Scale %d CanvasItems" -msgstr "Escalar CanvasItem" +msgstr "Escalar %d CanvasItems" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Scale CanvasItem \"%s\" to (%s, %s)" -msgstr "Escalar CanvasItem" +msgstr "Escalar CanvasItem \"%s\" a (%s, %s)" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Move %d CanvasItems" -msgstr "Mover CanvasItem" +msgstr "Mover %d CanvasItems" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Move CanvasItem \"%s\" to (%d, %d)" -msgstr "Mover CanvasItem" +msgstr "Mover CanvasItem \"%s\" a (%d, %d)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" @@ -6600,18 +6598,16 @@ msgid "Move Points" msgstr "Mover Puntos" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Command: Rotate" -msgstr "Arrastrar: Rotar" +msgstr "Command: Rotar" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Shift: Move All" msgstr "Shift: Mover Todos" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Shift+Command: Scale" -msgstr "Shift+Ctrl: Escalar" +msgstr "Shift+Command: Escalar" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Ctrl: Rotate" @@ -6660,14 +6656,12 @@ msgid "Radius:" msgstr "Radio:" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Copy Polygon to UV" -msgstr "Crear PolÃgono y UV" +msgstr "Copiar PolÃgono a UV" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Copy UV to Polygon" -msgstr "Convertir a Polygon2D" +msgstr "Copiar UV al PolÃgono" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Clear UV" @@ -7894,9 +7888,8 @@ msgid "New Animation" msgstr "Nueva Animación" #: editor/plugins/sprite_frames_editor_plugin.cpp -#, fuzzy msgid "Speed:" -msgstr "Velocidad (FPS):" +msgstr "Velocidad:" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Loop" @@ -8214,13 +8207,12 @@ msgid "Paint Tile" msgstr "Pintar Tile" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "" "Shift+LMB: Line Draw\n" "Shift+Command+LMB: Rectangle Paint" msgstr "" -"Shift + Clic izq: Dibujar lÃnea\n" -"Shift + Ctrl + Clic izq: Pintar Rectángulo" +"Shift+Click izq: Dibujar lÃnea\n" +"Shift+Command+Click der: Pintar Rectángulo" #: editor/plugins/tile_map_editor_plugin.cpp msgid "" @@ -8375,23 +8367,20 @@ msgid "Create a new rectangle." msgstr "Crear un rectángulo nuevo." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Pintar Rectángulo" +msgstr "Nuevo Rectángulo" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Crear un nuevo polÃgono." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "Mover PolÃgono" +msgstr "Nuevo PolÃgono" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Eliminar Seleccionados" +msgstr "Eliminar Formas Seleccionadas" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -8761,9 +8750,8 @@ msgid "Add Node to Visual Shader" msgstr "Agregar Nodo al Visual Shader" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Node(s) Moved" -msgstr "Nodo Movido" +msgstr "Nodo(s) Movido(s)" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Duplicate Nodes" @@ -8783,9 +8771,8 @@ msgid "Visual Shader Input Type Changed" msgstr "Se cambió el Tipo de Entrada de Visual Shader" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "UniformRef Name Changed" -msgstr "Asignar Nombre a Uniform" +msgstr "Nombre de UniformRef Cambiado" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Vertex" @@ -9505,7 +9492,7 @@ msgstr "" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "A reference to an existing uniform." -msgstr "" +msgstr "Una referencia a un uniform existente." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "(Fragment/Light mode only) Scalar derivative function." @@ -9875,6 +9862,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -10484,19 +10475,16 @@ msgid "Batch Rename" msgstr "Renombrar en Masa" #: editor/rename_dialog.cpp -#, fuzzy msgid "Replace:" -msgstr "Reemplazar: " +msgstr "Reemplazar:" #: editor/rename_dialog.cpp -#, fuzzy msgid "Prefix:" -msgstr "Prefijo" +msgstr "Prefijo:" #: editor/rename_dialog.cpp -#, fuzzy msgid "Suffix:" -msgstr "Sufijo" +msgstr "Sufijo:" #: editor/rename_dialog.cpp msgid "Use Regular Expressions" @@ -10543,9 +10531,9 @@ msgid "Per-level Counter" msgstr "Contador Por Nivel" #: editor/rename_dialog.cpp -#, fuzzy msgid "If set, the counter restarts for each group of child nodes." -msgstr "Si esta activo el contador reinicia por cada grupo de nodos hijos" +msgstr "" +"Si está activado, el contador se reinicia por cada grupo de nodos hijos." #: editor/rename_dialog.cpp msgid "Initial value for the counter" @@ -10604,9 +10592,8 @@ msgid "Reset" msgstr "Resetear" #: editor/rename_dialog.cpp -#, fuzzy msgid "Regular Expression Error:" -msgstr "Error de Expresión Regular" +msgstr "Error de Expresión Regular:" #: editor/rename_dialog.cpp msgid "At character %s" @@ -12163,7 +12150,7 @@ msgstr "" #: platform/android/export/export.cpp msgid "Missing 'platform-tools' directory!" -msgstr "" +msgstr "¡No se encontró el directorio 'platform-tools'!" #: platform/android/export/export.cpp msgid "" @@ -12217,18 +12204,20 @@ msgstr "" #: platform/android/export/export.cpp msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled." msgstr "" +"\"Export AAB\" sólo es válido cuando \"Use Custom Build\" está activado." #: platform/android/export/export.cpp msgid "Invalid filename! Android App Bundle requires the *.aab extension." msgstr "" +"¡Nombre de archivo inválido! Android App Bundle requiere la extensión *.aab." #: platform/android/export/export.cpp msgid "APK Expansion not compatible with Android App Bundle." -msgstr "" +msgstr "La Expansión APK no es compatible con Android App Bundle." #: platform/android/export/export.cpp msgid "Invalid filename! Android APK requires the *.apk extension." -msgstr "" +msgstr "¡Nombre de archivo inválido! Android APK requiere la extensión *.apk." #: platform/android/export/export.cpp msgid "" @@ -12267,13 +12256,15 @@ msgstr "" #: platform/android/export/export.cpp msgid "Moving output" -msgstr "" +msgstr "Moviendo salida" #: platform/android/export/export.cpp msgid "" "Unable to copy and rename export file, check gradle project directory for " "outputs." msgstr "" +"No se puede copiar y renombrar el archivo de exportación, comprobá el " +"directorio del proyecto de gradle para ver los resultados." #: platform/iphone/export/export.cpp msgid "Identifier is missing." @@ -12472,6 +12463,26 @@ msgstr "" "Animar CPUParticles2D requiere el uso de un CanvasItemMaterial con " "\"Particles Animation\" activado." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12736,7 +12747,7 @@ msgstr "" #: scene/3d/interpolated_camera.cpp msgid "" "InterpolatedCamera has been deprecated and will be removed in Godot 4.0." -msgstr "" +msgstr "InterpolatedCamera ha sido deprecado y será eliminado en Godot 4.0." #: scene/3d/light.cpp msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows." @@ -12804,6 +12815,26 @@ msgstr "" "sobreescritos por el motor de fÃsica al ejecutar.\n" "Cambiá el tamaño de los collision shapes hijos." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13046,6 +13077,9 @@ msgstr "Solo se pueden asignar variaciones en funciones de vértice." msgid "Constants cannot be modified." msgstr "Las constantes no pueden modificarse." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Ya hay un archivo o carpeta con el mismo nombre en esta ubicación." + #~ msgid "Error trying to save layout!" #~ msgstr "Error al tratar de guardar el layout!" diff --git a/editor/translations/et.po b/editor/translations/et.po index 9c886f42d4..9ede0a7465 100644 --- a/editor/translations/et.po +++ b/editor/translations/et.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2020-09-01 10:38+0000\n" +"PO-Revision-Date: 2020-12-02 09:52+0000\n" "Last-Translator: StReef <streef.gtx@gmail.com>\n" "Language-Team: Estonian <https://hosted.weblate.org/projects/godot-engine/" "godot/et/>\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.2.1-dev\n" +"X-Generator: Weblate 4.4-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1064,7 +1064,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -2566,7 +2566,7 @@ msgstr "Vaikimisi" #: editor/editor_node.cpp editor/editor_properties.cpp #: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp msgid "Show in FileSystem" -msgstr "" +msgstr "Kuva failikuvajas" #: editor/editor_node.cpp msgid "Play This Scene" @@ -3582,6 +3582,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3629,23 +3639,11 @@ msgstr "Redigeeri sõltuvusi..." msgid "View Owners..." msgstr "Kuva omanikud..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Muuda nime..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplikeeri..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Teisalda..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Uus stseen..." @@ -3668,11 +3666,16 @@ msgid "Collapse All" msgstr "Ahenda kõik" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Nimeta ümber" +msgid "Duplicate..." +msgstr "Duplikeeri..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Muuda nime..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3705,8 +3708,11 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "" +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Nimeta ümber" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -3961,7 +3967,7 @@ msgstr "" #: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp #: editor/plugins/script_editor_plugin.cpp msgid "Save As..." -msgstr "" +msgstr "Salvest kui..." #: editor/inspector_dock.cpp msgid "Copy Params" @@ -5283,7 +5289,7 @@ msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Select Mode" -msgstr "" +msgstr "Valimisrežiim" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Drag: Rotate" @@ -5304,17 +5310,17 @@ msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Move Mode" -msgstr "" +msgstr "Liigutamisrežiim" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Rotate Mode" -msgstr "" +msgstr "Pööramisrežiim" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Scale Mode" -msgstr "" +msgstr "Skaleerimisrežiim" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -5349,7 +5355,7 @@ msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Use Grid Snap" -msgstr "" +msgstr "Kasuta ruudustiku naksamist" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snapping Options" @@ -5407,7 +5413,7 @@ msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Lock the selected object in place (can't be moved)." -msgstr "" +msgstr "Lukusta valitud objekt praegusele kohale (seda ei saa liigutada)." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -6555,7 +6561,7 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp msgid "New Text File..." -msgstr "" +msgstr "Uus tekstifail..." #: editor/plugins/script_editor_plugin.cpp msgid "Open File" @@ -6563,7 +6569,7 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp msgid "Save File As..." -msgstr "" +msgstr "Salvesta fail kui..." #: editor/plugins/script_editor_plugin.cpp msgid "Can't obtain the script for running." @@ -6596,7 +6602,7 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp msgid "Save Theme As..." -msgstr "" +msgstr "Salvesta teema kui..." #: editor/plugins/script_editor_plugin.cpp msgid "%s Class Reference" @@ -6650,19 +6656,19 @@ msgstr "Eelmine skript" #: editor/plugins/script_editor_plugin.cpp msgid "File" -msgstr "" +msgstr "Fail" #: editor/plugins/script_editor_plugin.cpp msgid "Open..." -msgstr "" +msgstr "Ava..." #: editor/plugins/script_editor_plugin.cpp msgid "Reopen Closed Script" -msgstr "" +msgstr "Taasava suletud skript" #: editor/plugins/script_editor_plugin.cpp msgid "Save All" -msgstr "" +msgstr "Salvesta kõik" #: editor/plugins/script_editor_plugin.cpp msgid "Soft Reload Script" @@ -7177,11 +7183,11 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Display Normal" -msgstr "" +msgstr "Kuva tavaliselt" #: editor/plugins/spatial_editor_plugin.cpp msgid "Display Wireframe" -msgstr "" +msgstr "Kuva traadiraamina" #: editor/plugins/spatial_editor_plugin.cpp msgid "Display Overdraw" @@ -7189,7 +7195,7 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Display Unshaded" -msgstr "" +msgstr "Kuva varjutamata" #: editor/plugins/spatial_editor_plugin.cpp msgid "View Environment" @@ -7205,7 +7211,7 @@ msgstr "Kuva informatsioon" #: editor/plugins/spatial_editor_plugin.cpp msgid "View FPS" -msgstr "" +msgstr "Kuva kaardisagedus" #: editor/plugins/spatial_editor_plugin.cpp msgid "Half Resolution" @@ -7213,7 +7219,7 @@ msgstr "Poolresolutioon" #: editor/plugins/spatial_editor_plugin.cpp msgid "Audio Listener" -msgstr "" +msgstr "Heli kuulaja" #: editor/plugins/spatial_editor_plugin.cpp msgid "Enable Doppler" @@ -7299,11 +7305,11 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Use Local Space" -msgstr "" +msgstr "Kasuta kohalikku ruumi" #: editor/plugins/spatial_editor_plugin.cpp msgid "Use Snap" -msgstr "" +msgstr "Kasuta naksamist" #: editor/plugins/spatial_editor_plugin.cpp msgid "Bottom View" @@ -9481,6 +9487,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -9990,7 +10000,7 @@ msgstr "" #: editor/property_editor.cpp msgid "File..." -msgstr "" +msgstr "Fail..." #: editor/property_editor.cpp msgid "Dir..." @@ -10281,7 +10291,7 @@ msgstr "" #: editor/scene_tree_dock.cpp msgid "Save New Scene As..." -msgstr "" +msgstr "Salvesta uus stseen kui..." #: editor/scene_tree_dock.cpp msgid "" @@ -10490,7 +10500,7 @@ msgstr "" #: editor/scene_tree_editor.cpp msgid "Open Script:" -msgstr "" +msgstr "Ava skript:" #: editor/scene_tree_editor.cpp msgid "" @@ -10506,7 +10516,7 @@ msgstr "" #: editor/scene_tree_editor.cpp msgid "Toggle Visibility" -msgstr "" +msgstr "Sea nähtavus sisse/välja" #: editor/scene_tree_editor.cpp msgid "" @@ -11896,6 +11906,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12156,6 +12186,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/eu.po b/editor/translations/eu.po index 8a0aab6f15..e27515849d 100644 --- a/editor/translations/eu.po +++ b/editor/translations/eu.po @@ -1061,7 +1061,7 @@ msgstr "Baliabide umezurtzen arakatzailea" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3543,6 +3543,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3590,23 +3600,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3629,10 +3627,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3668,7 +3671,10 @@ msgid "Move" msgstr "Mugitu" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9444,6 +9450,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11865,6 +11875,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12125,6 +12155,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/fa.po b/editor/translations/fa.po index bdbb10725c..f7bef53811 100644 --- a/editor/translations/fa.po +++ b/editor/translations/fa.po @@ -1100,7 +1100,7 @@ msgstr "پوینده‌ی منبع جدا Ø§ÙØªØ§Ø¯Ù‡" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3624,6 +3624,16 @@ msgid "Name contains invalid characters." msgstr "کاراکترهای معتبر:" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp #, fuzzy msgid "Renaming file:" msgstr "تغییر متغیر" @@ -3678,26 +3688,12 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "تغییر نام..." - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "انتخاب شده را به دو تا تکثیر Ú©Ù†" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "بارگیری خودکار را انجام دهید" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "صØÙ†Ù‡ جدید" @@ -3723,11 +3719,18 @@ msgid "Collapse All" msgstr "بستن" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "تغییر نام" +#, fuzzy +msgid "Duplicate..." +msgstr "انتخاب شده را به دو تا تکثیر Ú©Ù†" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "بارگیری خودکار را انجام دهید" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "تغییر نام..." #: editor/filesystem_dock.cpp #, fuzzy @@ -3764,8 +3767,11 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "" +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "تغییر نام" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9899,6 +9905,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12503,6 +12513,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp #, fuzzy msgid "" @@ -12797,6 +12827,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp #, fuzzy msgid "" diff --git a/editor/translations/fi.po b/editor/translations/fi.po index 2c5d6290f7..7a47df373d 100644 --- a/editor/translations/fi.po +++ b/editor/translations/fi.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-20 23:08+0000\n" +"PO-Revision-Date: 2020-11-29 08:29+0000\n" "Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n" "Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/" "godot/fi/>\n" @@ -1091,7 +1091,7 @@ msgstr "Irrallisten resurssien hallinta" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3700,6 +3700,16 @@ msgid "Name contains invalid characters." msgstr "Nimi sisältää virheellisiä kirjainmerkkejä." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Nimetään tiedosto uudelleen:" @@ -3747,23 +3757,11 @@ msgstr "Muokkaa riippuvuuksia..." msgid "View Owners..." msgstr "Tarkastele omistajia..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Nimeä uudelleen..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Kahdenna..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Siirrä..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "Siirrä roskakoriin" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Uusi skene..." @@ -3786,11 +3784,16 @@ msgid "Collapse All" msgstr "Tiivistä kaikki" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Nimeä uudelleen" +msgid "Duplicate..." +msgstr "Kahdenna..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Siirrä roskakoriin" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Nimeä uudelleen..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3825,8 +3828,11 @@ msgid "Move" msgstr "Siirrä" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Tästä sijainnista löytyy jo samanniminen tiedosto tai kansio." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Nimeä uudelleen" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8316,23 +8322,20 @@ msgid "Create a new rectangle." msgstr "Luo uusi suorakulmio." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Suorakaidetäyttö" +msgstr "Uusi suorakaide" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Luo uusi polygoni." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "Siirrä polygonia" +msgstr "Uusi polygoni" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Poista valitut" +msgstr "Poista valittu muoto" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9808,6 +9811,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12386,6 +12393,26 @@ msgstr "" "CPUParticles2D animaatio edellyttää CanvasItemMaterial käyttöä niin että " "\"Particles Animation\" on kytketty päälle." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12716,6 +12743,26 @@ msgstr "" "jäykkätilassa) ajon aikana.\n" "Muuta sen sijaan solmun alla olevia törmäysmuotoja." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12957,6 +13004,9 @@ msgstr "Varying tyypin voi sijoittaa vain vertex-funktiossa." msgid "Constants cannot be modified." msgstr "Vakioita ei voi muokata." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Tästä sijainnista löytyy jo samanniminen tiedosto tai kansio." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "'build-tools' hakemisto puuttuu!" diff --git a/editor/translations/fil.po b/editor/translations/fil.po index 542596ed45..c430475062 100644 --- a/editor/translations/fil.po +++ b/editor/translations/fil.po @@ -1064,7 +1064,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3543,6 +3543,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3590,23 +3600,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3629,10 +3627,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3666,7 +3669,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9447,6 +9453,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11866,6 +11876,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12126,6 +12156,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/fr.po b/editor/translations/fr.po index b5bb7cbdcd..3085e78d7b 100644 --- a/editor/translations/fr.po +++ b/editor/translations/fr.po @@ -81,7 +81,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-26 08:43+0000\n" +"PO-Revision-Date: 2020-12-10 14:11+0100\n" "Last-Translator: Rémi Verschelde <akien@godotengine.org>\n" "Language-Team: French <https://hosted.weblate.org/projects/godot-engine/" "godot/fr/>\n" @@ -90,7 +90,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.4-dev\n" +"X-Generator: Poedit 2.4.2\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1172,7 +1172,7 @@ msgstr "Explorateur de ressources orphelines" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3815,6 +3815,22 @@ msgid "Name contains invalid characters." msgstr "Le nom contient des caractères invalides." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" +"Les fichiers ou dossiers suivants entrent en conflit avec des éléments de la " +"destination '%s' :\n" +"\n" +"%s\n" +"\n" +"Souhaitez-vous les écraser ?" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Renommer le fichier :" @@ -3862,23 +3878,11 @@ msgstr "Modifier les dépendances…" msgid "View Owners..." msgstr "Voir les propriétaires…" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Renommer..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Dupliquer…" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Déplacer vers…" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "Déplacer vers la corbeille" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nouvelle scène..." @@ -3901,11 +3905,16 @@ msgid "Collapse All" msgstr "Réduire tout" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Renommer" +msgid "Duplicate..." +msgstr "Dupliquer…" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Déplacer vers la corbeille" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Renommer..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3940,9 +3949,11 @@ msgid "Move" msgstr "Déplacer" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "" -"Il existe déjà un fichier ou un dossier ayant le même nom à cet emplacement." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Renommer" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9959,6 +9970,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "Non supporté par les drivers de votre carte graphique." + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12569,6 +12584,26 @@ msgstr "" "L'animation de CPUParticles2D a besoin d'un CanvasItemMaterial avec " "« Particles Animation » activé." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "Node A et Node B doivent être des PhysicsBody2D" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "Node A doit être un PhysicsBody2D" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "Node B doit être un PhysicsBody2D" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12909,6 +12944,26 @@ msgstr "" "rigide) seront remplacées par le moteur physique lors de l'exécution.\n" "Modifiez la taille dans les formes de collision enfant à la place." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "Node A et Node B doivent être des PhysicsBody" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "Node A doit être un PhysicsBody" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "Node B doit être un PhysicsBody" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "Le joint n'est connecté à aucun PhysicsBody" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "Node A et Node B doivent être des PhysicsBody différents" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13156,6 +13211,11 @@ msgstr "Les variations ne peuvent être affectées que dans la fonction vertex." msgid "Constants cannot be modified." msgstr "Les constantes ne peuvent être modifiées." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "" +#~ "Il existe déjà un fichier ou un dossier ayant le même nom à cet " +#~ "emplacement." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "Dossier « build-tools » manquant !" diff --git a/editor/translations/ga.po b/editor/translations/ga.po index 025d5778f8..971c0b0bec 100644 --- a/editor/translations/ga.po +++ b/editor/translations/ga.po @@ -1057,7 +1057,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3536,6 +3536,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3583,23 +3593,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3622,10 +3620,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3659,7 +3662,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9442,6 +9448,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11862,6 +11872,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12122,6 +12152,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/he.po b/editor/translations/he.po index 5ac3e3f060..ebccec8d4b 100644 --- a/editor/translations/he.po +++ b/editor/translations/he.po @@ -22,7 +22,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-25 14:10+0000\n" +"PO-Revision-Date: 2020-12-03 19:28+0000\n" "Last-Translator: Ziv D <wizdavid@gmail.com>\n" "Language-Team: Hebrew <https://hosted.weblate.org/projects/godot-engine/" "godot/he/>\n" @@ -1098,7 +1098,7 @@ msgstr "דפדפן מש××‘×™× ×™×ª×•×ž×™×" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3683,6 +3683,16 @@ msgid "Name contains invalid characters." msgstr "×”×©× ×ž×›×™×œ ×ª×•×•×™× ×©×’×•×™×™×." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "×©×™× ×•×™ ×©× ×”×§×•×‘×¥:" @@ -3734,25 +3744,12 @@ msgstr "עריכת תלויות…" msgid "View Owners..." msgstr "צפייה בבעלי×…" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "×©×™× ×•×™ ש×…" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "שכפול…" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "העברה ×ל…" #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "הזזת ×˜×¢×™× ×” ×וטומטית" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "×¡×¦× ×” חדשה" @@ -3779,11 +3776,17 @@ msgid "Collapse All" msgstr "×œ×¦×ž×¦× ×”×›×•×œ" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "×©×™× ×•×™ ש×" +msgid "Duplicate..." +msgstr "שכפול…" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "הזזת ×˜×¢×™× ×” ×וטומטית" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "×©×™× ×•×™ ש×…" #: editor/filesystem_dock.cpp #, fuzzy @@ -3822,9 +3825,11 @@ msgid "Move" msgstr "העברה" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "There is already file or folder with the same name in this location." -msgstr "כבר ×§×™×™×ž×™× ×§×•×‘×¥ ×ו תיקייה ×‘×©× ×”×–×”." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "×©×™× ×•×™ ש×" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -5133,29 +5138,27 @@ msgstr "קטגוריה:" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Site:" -msgstr "" +msgstr "×תר:" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Support" -msgstr "ייבו×" +msgstr "תמיכה" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Official" -msgstr "" +msgstr "רשמי" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Testing" -msgstr "" +msgstr "בבדיקה" #: editor/plugins/asset_library_editor_plugin.cpp -#, fuzzy msgid "Loading..." -msgstr "×˜×¢×™× ×”" +msgstr "×‘×˜×¢×™× ×”â€¦" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Assets ZIP File" -msgstr "" +msgstr "קובץ ZIP של × ×›×¡×™×" #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "" @@ -5163,58 +5166,60 @@ msgid "" "Save your scene (for images to be saved in the same dir), or pick a save " "path from the BakedLightmap properties." msgstr "" +"×ין ×פשרות לקבוע × ×ª×™×‘ שמירה עבור ×ª×ž×•× ×•×ª lightmap.\n" +"שמור/×™ ×ת ×”×¡×¦×™× ×” שלך (כדי ×©×ª×ž×•× ×•×ª יישמרו ב×ותה תיקייה), ×ו בחר/×™ × ×ª×™×‘ שמירה " +"ממ××¤×™×™× ×™ BakedLightmap." #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "" "No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake " "Light' flag is on." -msgstr "" +msgstr "×ין רשתות ל×פייה. וד×/×™ ×©×”× ×ž×›×™×œ×™× ×¢×¨×•×¥ UV2 והדגל 'Bake Light' מ×ופשר." #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "Failed creating lightmap images, make sure path is writable." -msgstr "" +msgstr "יצירת ×ª×ž×•× ×•×ª lightmap × ×›×©×œ×”, וד×/×™ ×©×”× ×ª×™×‘ × ×™×ª×Ÿ לכתיבה." #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "Bake Lightmaps" -msgstr "" +msgstr "×פיית Lightmaps" #: editor/plugins/camera_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Preview" -msgstr "" +msgstr "תצוגה מקדימה" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Configure Snap" -msgstr "" +msgstr "הגדרת הצמדה" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Grid Offset:" -msgstr "" +msgstr "היסט רשת:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Grid Step:" -msgstr "" +msgstr "שלב רשת:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Primary Line Every:" -msgstr "" +msgstr "קו ר×שי כל:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "steps" -msgstr "" +msgstr "צעדי×" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Rotation Offset:" -msgstr "" +msgstr "היסט סיבוב:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Rotation Step:" -msgstr "" +msgstr "צעד סיבוב:" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Scale Step:" -msgstr "יחס מתיחה:" +msgstr "צעד ×§× ×” מידה:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Move Vertical Guide" @@ -9893,6 +9898,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12400,6 +12409,26 @@ msgstr "" "×”× ×¤×©×ª CPUParticles2D מחייבת שימוש ב-CanvasItemMaterial ×¢× \"×”× ×¤×©×ª חלקיקי×\" " "מ×ופשרת." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12703,6 +12732,26 @@ msgstr "" "הפיזיקה בזמן ריצה.\n" "×‘×ž×§×•× ×–×ת יש ×œ×©× ×•×ª ×ת גודל צורות ×”×”×ª× ×’×©×•×ª של הצ×צ××™×." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12934,6 +12983,10 @@ msgstr "× ×™×ª×Ÿ להקצות ×©×™× ×•×™×™× ×¨×§ ×‘×¤×•× ×§×¦×™×ª vertex." msgid "Constants cannot be modified." msgstr "××™ ×פשר ×œ×©× ×•×ª קבועי×." +#, fuzzy +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "כבר ×§×™×™×ž×™× ×§×•×‘×¥ ×ו תיקייה ×‘×©× ×”×–×”." + #~ msgid "Error trying to save layout!" #~ msgstr "שמירת הפריסה × ×›×©×œ×”!" diff --git a/editor/translations/hi.po b/editor/translations/hi.po index de3b8630ab..03fbdc1971 100644 --- a/editor/translations/hi.po +++ b/editor/translations/hi.po @@ -1089,7 +1089,7 @@ msgstr "अनाथ संसाधन à¤à¤•à¥à¤¸à¤ªà¥à¤²à¥‹à¤°à¤°" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3670,6 +3670,16 @@ msgid "Name contains invalid characters." msgstr "नाम मे अमानà¥à¤¯ अकà¥à¤·à¤° मौजूद." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "फ़ाइल का नाम बदल रहे है:" @@ -3717,24 +3727,11 @@ msgstr "निरà¥à¤à¤°à¤¿à¤¤ फ़ाइलें संपादित क msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "डà¥à¤ªà¥à¤²à¤¿à¤•ेट..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "औटोलोड हिलाइये" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "नया दृशà¥à¤¯..." @@ -3757,10 +3754,16 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "डà¥à¤ªà¥à¤²à¤¿à¤•ेट..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "औटोलोड हिलाइये" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3794,7 +3797,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9659,6 +9665,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12125,6 +12135,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12385,6 +12415,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/hr.po b/editor/translations/hr.po index 3b79d58af0..c762ff0562 100644 --- a/editor/translations/hr.po +++ b/editor/translations/hr.po @@ -1071,7 +1071,7 @@ msgstr "IstraživaÄ napuÅ¡tenih resursa" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3548,6 +3548,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3595,24 +3605,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Premjesti Autoload" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3635,10 +3632,16 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Premjesti Autoload" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3672,7 +3675,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9457,6 +9463,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11878,6 +11888,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12138,6 +12168,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/hu.po b/editor/translations/hu.po index dfa4c1255c..bd67e49dfd 100644 --- a/editor/translations/hu.po +++ b/editor/translations/hu.po @@ -12,12 +12,14 @@ # sztrovacsek <magadeve@gmail.com>, 2019. # Ãcs Zoltán <acszoltan111@gmail.com>, 2020. # cefrebevalo <szmarci711@gmail.com>, 2020. +# thekeymethod <csokan.andras87@protonmail.ch>, 2020. +# Czmorek Dávid <czmdav.soft@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-09-22 03:23+0000\n" -"Last-Translator: Ãcs Zoltán <acszoltan111@gmail.com>\n" +"PO-Revision-Date: 2020-12-07 08:11+0000\n" +"Last-Translator: Czmorek Dávid <czmdav.soft@gmail.com>\n" "Language-Team: Hungarian <https://hosted.weblate.org/projects/godot-engine/" "godot/hu/>\n" "Language: hu\n" @@ -25,7 +27,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.3-dev\n" +"X-Generator: Weblate 4.4-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -34,9 +36,8 @@ msgstr "" "Érvénytelen tÃpusargumentum a convert()-hez használjon TYPE_* konstansokat." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp -#, fuzzy msgid "Expected a string of length 1 (a character)." -msgstr "Egy hosszúságú karaktersorozat szükséges." +msgstr "Szöveg elvárt hossza 1 ( egy karakter)." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp @@ -58,7 +59,7 @@ msgstr "Érvénytelen operandusok az %s, %s és %s operátorhoz." #: core/math/expression.cpp msgid "Invalid index of type %s for base type %s" -msgstr "" +msgstr "Érvénytelen %s tÃpusú index %s tÃpusú alaphoz" #: core/math/expression.cpp msgid "Invalid named index '%s' for base type %s" @@ -66,7 +67,7 @@ msgstr "Érvénytelen nevezett index '%s' %s alaptÃpushoz" #: core/math/expression.cpp msgid "Invalid arguments to construct '%s'" -msgstr "" +msgstr "Érvénytelen argumentumok a(z) '%s' épÃtÅ‘ben" #: core/math/expression.cpp msgid "On call to '%s':" @@ -122,127 +123,120 @@ msgstr "Érték:" #: editor/animation_bezier_editor.cpp msgid "Insert Key Here" -msgstr "Kulcs beszúrása" +msgstr "Kulcs Beszúrása Ide" #: editor/animation_bezier_editor.cpp msgid "Duplicate Selected Key(s)" -msgstr "Kiválasztott kulcs(ok) megkettÅ‘zése" +msgstr "Kiválasztott Kulcs(ok) MegkettÅ‘zése" #: editor/animation_bezier_editor.cpp msgid "Delete Selected Key(s)" -msgstr "Kiválasztott kulcs(ok) törlése" +msgstr "Kiválasztott Kulcs(ok) Törlése" #: editor/animation_bezier_editor.cpp msgid "Add Bezier Point" -msgstr "Bézier pont hozzáadása" +msgstr "Bézier Pont Hozzáadása" #: editor/animation_bezier_editor.cpp msgid "Move Bezier Points" -msgstr "Bézier pontok áthelyezése" +msgstr "Bézier Pontok Mozgatása" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Duplicate Keys" -msgstr "Animáció kulcsok megkettÅ‘zése" +msgstr "Animáció - Kulcsok MegkettÅ‘zése" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Delete Keys" -msgstr "Animáció kulcsok törlése" +msgstr "Animáció - Kulcsok Törlése" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Change Keyframe Time" -msgstr "Animáció kulcsképkocka idÅ‘ változtatás" +msgstr "Animáció - Kulcskép IdÅ‘ Változtatása" #: editor/animation_track_editor.cpp msgid "Anim Change Transition" -msgstr "Animáció átmenet változtatása" +msgstr "Animáció - Ãtmenet Változtatása" #: editor/animation_track_editor.cpp msgid "Anim Change Transform" -msgstr "Animáció transzformáció változtatás" +msgstr "Animáció - Transzformáció Változtatása" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Value" -msgstr "Animáció kulcsképkocka érték változtatás" +msgstr "Animáció - Kulcskép Érték Változtatása" #: editor/animation_track_editor.cpp msgid "Anim Change Call" -msgstr "Animáció hÃvás változtatás" +msgstr "Animáció - HÃvás Változtatása" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Keyframe Time" -msgstr "Animáció kulcsképkocka idÅ‘ változtatás" +msgstr "Animáció - Több Kulcskép IdÅ‘ Változtatása" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Transition" -msgstr "Animáció átmenet változtatása" +msgstr "Animáció - Több Ãtmenet Változtatása" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Transform" -msgstr "Animáció transzformáció változtatás" +msgstr "Animáció - Több Transzformáció Változtatása" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Keyframe Value" -msgstr "Animáció kulcsképkocka érték változtatás" +msgstr "Animáció - Több Kulcskép Érték Változtatása" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Multi Change Call" -msgstr "Animáció hÃvás változtatás" +msgstr "Animáció - Több HÃvás Változtatása" #: editor/animation_track_editor.cpp msgid "Change Animation Length" -msgstr "Animáció hosszának változtatása" +msgstr "Animáció Hosszának Változtatása" #: editor/animation_track_editor.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Change Animation Loop" -msgstr "Animációs ciklus változtatása" +msgstr "Animáció Ismétlésének Változtatása" #: editor/animation_track_editor.cpp msgid "Property Track" -msgstr "Tulajdonságkövetés" +msgstr "Tulajdonság Sáv" #: editor/animation_track_editor.cpp msgid "3D Transform Track" -msgstr "" +msgstr "3D Transzform Sáv" #: editor/animation_track_editor.cpp msgid "Call Method Track" -msgstr "HÃvás módszer követése" +msgstr "Metódus HÃvás Sáv" #: editor/animation_track_editor.cpp msgid "Bezier Curve Track" -msgstr "Bézier görbe nyomvonal" +msgstr "Bézier Görbe Sáv" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Audio Playback Track" -msgstr "Hang lejátszás követése" +msgstr "Hang Lejátszás Sáv" #: editor/animation_track_editor.cpp msgid "Animation Playback Track" -msgstr "" +msgstr "Animáció Lejátszás Sáv" #: editor/animation_track_editor.cpp msgid "Animation length (frames)" -msgstr "Animáció hossza (képkockákban)" +msgstr "Animáció hossza (képkockák)" #: editor/animation_track_editor.cpp msgid "Animation length (seconds)" -msgstr "Animáció hossza (másodpercben)" +msgstr "Animáció hossza (másodpercek)" #: editor/animation_track_editor.cpp msgid "Add Track" -msgstr "Nyomvonal hozzáadása" +msgstr "Sáv Hozzáadása" #: editor/animation_track_editor.cpp msgid "Animation Looping" -msgstr "Animáció ismétlése" +msgstr "Animáció Ismétlése" #: editor/animation_track_editor.cpp #: modules/visual_script/visual_script_editor.cpp @@ -250,39 +244,36 @@ msgid "Functions:" msgstr "Függvények:" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Audio Clips:" -msgstr "Audió klipek:" +msgstr "Hang Klipek:" #: editor/animation_track_editor.cpp msgid "Anim Clips:" -msgstr "Animáció klipek:" +msgstr "Animáció Klipek:" #: editor/animation_track_editor.cpp msgid "Change Track Path" -msgstr "" +msgstr "Sáv Útvonal Változtatás" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Toggle this track on/off." -msgstr "A sáv ki/be kapcsolása." +msgstr "Jelen sáv ki/be kapcsolása." #: editor/animation_track_editor.cpp msgid "Update Mode (How this property is set)" -msgstr "" +msgstr "FrissÃtés Módja (Hogyan van ez a tulajdonság beállÃtva)" #: editor/animation_track_editor.cpp msgid "Interpolation Mode" -msgstr "Interpolációs mód" +msgstr "Interpolálás Módja" #: editor/animation_track_editor.cpp msgid "Loop Wrap Mode (Interpolate end with beginning on loop)" -msgstr "" +msgstr "Összefűzés Módja (Vége és kezdete interpolálása ismétlés esetén)" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Remove this track." -msgstr "Kiválasztott nyomvonal eltávolÃtása." +msgstr "Jelen sáv eltávolÃtása." #: editor/animation_track_editor.cpp msgid "Time (s): " @@ -290,7 +281,7 @@ msgstr "IdÅ‘ (mp): " #: editor/animation_track_editor.cpp msgid "Toggle Track Enabled" -msgstr "" +msgstr "Sáv Engedélyezés Kapcsolása" #: editor/animation_track_editor.cpp msgid "Continuous" @@ -298,7 +289,7 @@ msgstr "Folyamatos" #: editor/animation_track_editor.cpp msgid "Discrete" -msgstr "Diszkrét" +msgstr "Pontozott" #: editor/animation_track_editor.cpp msgid "Trigger" @@ -323,48 +314,48 @@ msgstr "Köbös" #: editor/animation_track_editor.cpp msgid "Clamp Loop Interp" -msgstr "" +msgstr "Ãtmenet Nélküli Interpoláció" #: editor/animation_track_editor.cpp msgid "Wrap Loop Interp" -msgstr "" +msgstr "Folytatólagos Interpoláció" #: editor/animation_track_editor.cpp #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert Key" -msgstr "Kulcs beszúrása" +msgstr "Kulcs Beszúrása" #: editor/animation_track_editor.cpp msgid "Duplicate Key(s)" -msgstr "Kulcs(ok) megkettÅ‘zése" +msgstr "Kulcs(ok) MegkettÅ‘zése" #: editor/animation_track_editor.cpp msgid "Delete Key(s)" -msgstr "Kulcs(ok) törlése" +msgstr "Kulcs(ok) Törlése" #: editor/animation_track_editor.cpp msgid "Change Animation Update Mode" -msgstr "Animáció frissÃtés módjának megváltoztatása" +msgstr "Animáció FrissÃtés Módjának Változtatása" #: editor/animation_track_editor.cpp msgid "Change Animation Interpolation Mode" -msgstr "" +msgstr "Animáció Interpolálás Módjának Változtatása" #: editor/animation_track_editor.cpp msgid "Change Animation Loop Mode" -msgstr "Animáció hurok mód változtatása" +msgstr "Animáció Összefűzés Módjának Változtatása" #: editor/animation_track_editor.cpp msgid "Remove Anim Track" -msgstr "Animáció nyomvonal eltávolÃtás" +msgstr "Animáció Sáv EltávolÃtása" #: editor/animation_track_editor.cpp msgid "Create NEW track for %s and insert key?" -msgstr "ÚJ nyomvonalat hoz létre a következÅ‘höz: %s, és beszúrja a kulcsot?" +msgstr "Létrehoz ÚJ sávot a következÅ‘höz: %s, és beszúrja a kulcsot?" #: editor/animation_track_editor.cpp msgid "Create %d NEW tracks and insert keys?" -msgstr "Létrehoz %d ÚJ nyomvonalat és beszúrja a kulcsokat?" +msgstr "Létrehoz %d ÚJ sávot és beszúrja a kulcsokat?" #: editor/animation_track_editor.cpp editor/create_dialog.cpp #: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp @@ -380,36 +371,39 @@ msgstr "Létrehozás" #: editor/animation_track_editor.cpp msgid "Anim Insert" -msgstr "Animáció beszúrása" +msgstr "Animáció - Beszúrás" #: editor/animation_track_editor.cpp -#, fuzzy msgid "AnimationPlayer can't animate itself, only other players." -msgstr "Az AnimationPlayer nem tudja animálni önmagát, csak más játékosokat." +msgstr "" +"AnimationPlayer nem tudja önmagát animálni, csak más AnimationPlayer " +"elemeket." #: editor/animation_track_editor.cpp msgid "Anim Create & Insert" -msgstr "Animáció létrehozása és beillesztése" +msgstr "Animáció - Létrehozás és Beillesztés" #: editor/animation_track_editor.cpp msgid "Anim Insert Track & Key" -msgstr "Animáció nyomvonal és kulcs beszúrása" +msgstr "Animáció - Sáv és Kulcs Beszúrása" #: editor/animation_track_editor.cpp msgid "Anim Insert Key" -msgstr "Animáció kulcs beillesztés" +msgstr "Animáció - Kulcs Beszúrása" #: editor/animation_track_editor.cpp msgid "Change Animation Step" -msgstr "Animáció léptékének megváltoztatása" +msgstr "Animáció Léptékének Változtatása" #: editor/animation_track_editor.cpp msgid "Rearrange Tracks" -msgstr "" +msgstr "Sávok Újrarendezése" #: editor/animation_track_editor.cpp msgid "Transform tracks only apply to Spatial-based nodes." msgstr "" +"A transzform sávok csak a Spatial tÃpusú vagy azt bÅ‘vÃtÅ‘ elemekre " +"vonatkoznak." #: editor/animation_track_editor.cpp msgid "" @@ -418,59 +412,64 @@ msgid "" "-AudioStreamPlayer2D\n" "-AudioStreamPlayer3D" msgstr "" +"Hang sávok csak a következÅ‘ tÃpusú node-ra mutathatnak:\n" +"-AudioStreamPlayer\n" +"-AudioStreamPlayer2D\n" +"-AudioStreamPlayer3D" #: editor/animation_track_editor.cpp msgid "Animation tracks can only point to AnimationPlayer nodes." -msgstr "" +msgstr "Animáció sávok csak AnimationPlayer node-ra mutathatnak." #: editor/animation_track_editor.cpp msgid "An animation player can't animate itself, only other players." msgstr "" +"Egy AnimationPlayer nem tudja önmagát animálni, csak más AnimationPlayer " +"node-okat." #: editor/animation_track_editor.cpp msgid "Not possible to add a new track without a root" -msgstr "" +msgstr "Új sáv hozzáadása nem lehetséges gyökér nélkül" #: editor/animation_track_editor.cpp msgid "Invalid track for Bezier (no suitable sub-properties)" -msgstr "" +msgstr "Érvénytelen sáv Bezier számára (nincs megfelelÅ‘ al-tulajdonság)" #: editor/animation_track_editor.cpp msgid "Add Bezier Track" -msgstr "" +msgstr "Beizer Sáv Hozzáadása" #: editor/animation_track_editor.cpp msgid "Track path is invalid, so can't add a key." -msgstr "" +msgstr "Sáv elérési útja helytelen, kulcs hozzáadása nem lehetséges." #: editor/animation_track_editor.cpp msgid "Track is not of type Spatial, can't insert key" -msgstr "" +msgstr "Sáv tÃpusa nem Spatial, kulcs hozzáadása nem lehetséges" #: editor/animation_track_editor.cpp msgid "Add Transform Track Key" -msgstr "" +msgstr "Transzform Sáv Kulcs hozzáadása" #: editor/animation_track_editor.cpp msgid "Add Track Key" -msgstr "Nyomvonal kulcs hozzáadása" +msgstr "Sáv Kulcs Hozzáadása" #: editor/animation_track_editor.cpp msgid "Track path is invalid, so can't add a method key." -msgstr "" +msgstr "Sáv elérési útja helytelen, kulcs hozzáadása nem lehetséges." #: editor/animation_track_editor.cpp msgid "Add Method Track Key" -msgstr "Metódus nyomvonal kulcs beillesztése" +msgstr "Metódus Sáv Kulcs Hozzáadása" #: editor/animation_track_editor.cpp msgid "Method not found in object: " msgstr "A metódus nem található az objektumban: " #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Move Keys" -msgstr "Animáció kulcsok mozgatása" +msgstr "Animáció - Kulcsok Mozgatása" #: editor/animation_track_editor.cpp msgid "Clipboard is empty" @@ -478,17 +477,17 @@ msgstr "A vágólap üres" #: editor/animation_track_editor.cpp msgid "Paste Tracks" -msgstr "Nyomvonalak beillesztése" +msgstr "Sávok beillesztése" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Anim Scale Keys" -msgstr "Animáció kulcsok nyújtás" +msgstr "Animáció - Kulcsok Nyújtása" #: editor/animation_track_editor.cpp msgid "" "This option does not work for Bezier editing, as it's only a single track." msgstr "" +"Ez az opció nem működik Bezier szerkesztésre, mert ez csak egyetlen sáv." #: editor/animation_track_editor.cpp msgid "" @@ -502,6 +501,15 @@ msgid "" "Alternatively, use an import preset that imports animations to separate " "files." msgstr "" +"Ez az animáció egy importált jelenethez tartozik, ezért az importált sávok " +"módosÃtásai nem lesznek mentve.\n" +"\n" +"Egyedi sávok hozzáadásának engedélyezéséhez navigáljon a jelenet importálás " +"beállÃtásaihoz, állÃtsa be\n" +"\"Animation > Storage\" értékét \"Files\"-ra, engedélyezze a(z) \"Animation " +"> Keep Custom Tracks\" opciót, majd importálja újra.\n" +"Egy másik megoldás, ha olyan import elÅ‘beállÃtást használ, ami az " +"animációkat külön fájlba importálja." #: editor/animation_track_editor.cpp msgid "Warning: Editing imported animation" @@ -515,11 +523,12 @@ msgstr "" #: editor/animation_track_editor.cpp msgid "Only show tracks from nodes selected in tree." -msgstr "" +msgstr "Csak a fában kiválosztott node-ok sávjainak megjelenÃtése." #: editor/animation_track_editor.cpp msgid "Group tracks by node or display them as plain list." msgstr "" +"Sávok csoportosÃtása node-ok szerint, vagy megjelenÃtés egyszerű listaként." #: editor/animation_track_editor.cpp msgid "Snap:" @@ -554,44 +563,43 @@ msgstr "Animáció tulajdonságok." #: editor/animation_track_editor.cpp msgid "Copy Tracks" -msgstr "Nyomvonalak másolása" +msgstr "Sávok Másolása" #: editor/animation_track_editor.cpp msgid "Scale Selection" -msgstr "Kijelölés átméretezése" +msgstr "Kijelölés Nyújtása" #: editor/animation_track_editor.cpp msgid "Scale From Cursor" -msgstr "Ãtméretezés a kurzortól" +msgstr "Nyújtás a Kurzortól" #: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp msgid "Duplicate Selection" -msgstr "Kijelölés megkettÅ‘zése" +msgstr "Kijelölés MegkettÅ‘zése" #: editor/animation_track_editor.cpp msgid "Duplicate Transposed" -msgstr "Ãthelyezettek megkettÅ‘zése" +msgstr "Ãthelyezettek MegkettÅ‘zése" #: editor/animation_track_editor.cpp msgid "Delete Selection" -msgstr "Kijelölés törlése" +msgstr "Kijelölés Törlése" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Go to Next Step" -msgstr "Ugrás a következÅ‘ lépésre" +msgstr "Ugrás a KövetkezÅ‘ Lépésre" #: editor/animation_track_editor.cpp msgid "Go to Previous Step" -msgstr "Ugrás az elÅ‘zÅ‘ lépésre" +msgstr "Ugrás az ElÅ‘zÅ‘ Lépésre" #: editor/animation_track_editor.cpp msgid "Optimize Animation" -msgstr "Animáció optimalizálása" +msgstr "Animáció Optimalizálása" #: editor/animation_track_editor.cpp msgid "Clean-Up Animation" -msgstr "Animáció tisztÃtása" +msgstr "Animáció TisztÃtása" #: editor/animation_track_editor.cpp msgid "Pick the node that will be animated:" @@ -1096,7 +1104,7 @@ msgstr "Ãrva Forrás KezelÅ‘" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3404,7 +3412,7 @@ msgstr "Nem sikerült a szkript futtatása:" #: editor/editor_run_script.cpp msgid "Did you forget the '_run' method?" -msgstr "Nem felejtette el a '_run' metódust?" +msgstr "Elfelejtette a '_run' metódust?" #: editor/editor_spin_slider.cpp msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes." @@ -3525,7 +3533,7 @@ msgstr "A kérés sikertelen." #: editor/export_template_manager.cpp msgid "Redirect Loop." -msgstr "ÃtirányÃtási Hurok." +msgstr "Ciklus átiránÃtása." #: editor/export_template_manager.cpp #: editor/plugins/asset_library_editor_plugin.cpp @@ -3687,6 +3695,16 @@ msgid "Name contains invalid characters." msgstr "A név érvénytelen karaktereket tartalmaz." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Fájl átnevezése:" @@ -3734,24 +3752,11 @@ msgstr "FüggÅ‘ségek Szerkesztése..." msgid "View Owners..." msgstr "Tulajdonosok Megtekintése..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Ãtnevezés..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "MegkettÅ‘zés..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Ãthelyezés..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "AutoLoad Ãthelyezése" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Új jelenet..." @@ -3774,11 +3779,17 @@ msgid "Collapse All" msgstr "Összes becsukása" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Ãtnevezés" +msgid "Duplicate..." +msgstr "MegkettÅ‘zés..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "AutoLoad Ãthelyezése" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Ãtnevezés..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3813,8 +3824,11 @@ msgid "Move" msgstr "Ãthelyezés" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Ezen a helyen már van azonos nevű fájl vagy mappa." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Ãtnevezés" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -3950,15 +3964,15 @@ msgstr "Importálás Külön Anyagokkal" #: editor/import/resource_importer_scene.cpp msgid "Import with Separate Objects" -msgstr "Importálás Külön Objektumokkal" +msgstr "Importálás külön objektumokkal" #: editor/import/resource_importer_scene.cpp msgid "Import with Separate Objects+Materials" -msgstr "Importálás Külön Objektumokkal És Anyagokkal" +msgstr "Importálás külön objektumokkal és anyagokkal" #: editor/import/resource_importer_scene.cpp msgid "Import with Separate Objects+Animations" -msgstr "Importálás Külön Objektumokkal És Animációkkal" +msgstr "Importálás külön objektumokkal és animációkkal" #: editor/import/resource_importer_scene.cpp msgid "Import with Separate Materials+Animations" @@ -3966,7 +3980,7 @@ msgstr "Importálás Külön Anyagokkal És Animációkkal" #: editor/import/resource_importer_scene.cpp msgid "Import with Separate Objects+Materials+Animations" -msgstr "Importálás Külön Objektumokkal, Anyagokkal És Animációkkal" +msgstr "Importálás külön objektumokkal, anyagokkal és animációkkal" #: editor/import/resource_importer_scene.cpp msgid "Import as Multiple Scenes" @@ -4114,15 +4128,15 @@ msgstr "A jelenleg szerkesztett erÅ‘forrás elmentése." #: editor/inspector_dock.cpp msgid "Go to the previous edited object in history." -msgstr "Ugrás az elÅ‘zÅ‘leg módosÃtott objektumra a történelemben." +msgstr "Ugrás az elÅ‘zÅ‘leg módosÃtott objektumra az elÅ‘zményekben." #: editor/inspector_dock.cpp msgid "Go to the next edited object in history." -msgstr "Ugrás a következÅ‘ módosÃtott objektumra a történelemben." +msgstr "Ugrás a következÅ‘ módosÃtott objektumra az elÅ‘zményekben." #: editor/inspector_dock.cpp msgid "History of recently edited objects." -msgstr "A nemrég módosÃtott objektumok történelme." +msgstr "A nemrég módosÃtott objektumok elÅ‘zményei." #: editor/inspector_dock.cpp msgid "Object properties." @@ -4951,7 +4965,7 @@ msgstr "Kérés sikertelen, túl sok átirányÃtás" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Redirect loop." -msgstr "Hurok átirányÃtása." +msgstr "Ciklus átirányÃtása." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Request failed, timeout" @@ -5461,8 +5475,8 @@ msgid "" "Show a list of all objects at the position clicked\n" "(same as Alt+RMB in select mode)." msgstr "" -"Lista mutatási minden objektumról a kattintás helye alatt\n" -"(ugyanaz, mint Alt + Jobb Egérgomb Kiválasztó Módban)." +"Lista megjelenÃtése minden objektumról a kattintás helyénél\n" +"(ugyanaz, mint Alt + jobb egérgomb kiválasztó módban)." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Click to change object's rotation pivot." @@ -5548,12 +5562,12 @@ msgstr "Illesztés segédvonalakhoz" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Lock the selected object in place (can't be moved)." -msgstr "A kiválasztott objektum zárolása (mozgathatatlanná tétele)." +msgstr "A kiválasztott objektum zárolása (nem lesz mozgatható)." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Unlock the selected object (can be moved)." -msgstr "A kiválasztott objektum feloldása (mozgathatóvá tétele)." +msgstr "A kiválasztott objektum feloldása (mozgatható lesz)." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -6773,12 +6787,13 @@ msgid "Filter scripts" msgstr "Szkriptek szűrése" #: editor/plugins/script_editor_plugin.cpp +#, fuzzy msgid "Toggle alphabetical sorting of the method list." -msgstr "" +msgstr "Ãbécészerinti rendezés változtatása a metóduslistában." #: editor/plugins/script_editor_plugin.cpp msgid "Filter methods" -msgstr "" +msgstr "Metódusok szűrése" #: editor/plugins/script_editor_plugin.cpp msgid "Sort" @@ -6942,7 +6957,7 @@ msgstr "Legutóbbi szkriptek törlése" #: editor/plugins/script_text_editor.cpp msgid "Connections to method:" -msgstr "" +msgstr "Kapcsolatok a metódushoz:" #: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp msgid "Source" @@ -7244,7 +7259,7 @@ msgstr "" #: editor/plugins/spatial_editor_plugin.cpp msgid "Objects Drawn" -msgstr "" +msgstr "Rajzolt objektumok" #: editor/plugins/spatial_editor_plugin.cpp msgid "Material Changes" @@ -7780,7 +7795,7 @@ msgstr "" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Loop" -msgstr "" +msgstr "Ciklus" #: editor/plugins/sprite_frames_editor_plugin.cpp #, fuzzy @@ -8485,7 +8500,6 @@ msgid "Version Control System" msgstr "" #: editor/plugins/version_control_editor_plugin.cpp -#, fuzzy msgid "Initialize" msgstr "Inicializálás" @@ -8503,7 +8517,7 @@ msgstr "Változások" #: editor/plugins/version_control_editor_plugin.cpp msgid "Modified" -msgstr "" +msgstr "MódosÃtott" #: editor/plugins/version_control_editor_plugin.cpp msgid "Renamed" @@ -9664,6 +9678,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -9805,9 +9823,8 @@ msgid "Scan" msgstr "Keresés" #: editor/project_manager.cpp -#, fuzzy msgid "Select a Folder to Scan" -msgstr "Válasszon egy beolvasandó mappát" +msgstr "Válassza ki a mappát a kereséshez" #: editor/project_manager.cpp msgid "New Project" @@ -9827,7 +9844,7 @@ msgstr "ÚjraindÃtás most" #: editor/project_manager.cpp msgid "Can't run project" -msgstr "Nem lehet futtatni a projektet" +msgstr "A projekt futtatása nem sikerült" #: editor/project_manager.cpp msgid "" @@ -9848,11 +9865,11 @@ msgstr "Kulcs " #: editor/project_settings_editor.cpp msgid "Joy Button" -msgstr "" +msgstr "Joy gomb" #: editor/project_settings_editor.cpp msgid "Joy Axis" -msgstr "" +msgstr "Joy tengely" #: editor/project_settings_editor.cpp msgid "Mouse Button" @@ -9890,7 +9907,7 @@ msgstr "Eszköz" #: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp msgid "Press a Key..." -msgstr "Nyomj meg egy gombot..." +msgstr "Nyomjon le egy billentyűt" #: editor/project_settings_editor.cpp #, fuzzy @@ -10000,7 +10017,7 @@ msgstr "" #: editor/project_settings_editor.cpp msgid "Delete Item" -msgstr "" +msgstr "Elem törlése" #: editor/project_settings_editor.cpp msgid "" @@ -10211,20 +10228,19 @@ msgstr "" #: editor/property_selector.cpp msgid "Select Virtual Method" -msgstr "" +msgstr "Virtuális metódus kiválasztása" #: editor/property_selector.cpp msgid "Select Method" -msgstr "" +msgstr "Metódus kiválasztása" #: editor/rename_dialog.cpp editor/scene_tree_dock.cpp msgid "Batch Rename" msgstr "Csoportos átnevezés" #: editor/rename_dialog.cpp -#, fuzzy msgid "Replace:" -msgstr "Csere: " +msgstr "Csere:" #: editor/rename_dialog.cpp msgid "Prefix:" @@ -10335,9 +10351,8 @@ msgid "Reset" msgstr "VisszaállÃtás" #: editor/rename_dialog.cpp -#, fuzzy msgid "Regular Expression Error:" -msgstr "Reguláris kifejezés használata" +msgstr "Reguláris Kifejezési Hiba:" #: editor/rename_dialog.cpp #, fuzzy @@ -11160,7 +11175,7 @@ msgstr "" #: modules/gdscript/gdscript_functions.cpp msgid "Not based on a script" -msgstr "" +msgstr "Nem alapul szkripten" #: modules/gdscript/gdscript_functions.cpp msgid "Not based on a resource file" @@ -11168,19 +11183,21 @@ msgstr "" #: modules/gdscript/gdscript_functions.cpp msgid "Invalid instance dictionary format (missing @path)" -msgstr "" +msgstr "Érvénytelen példány szótár formátum (hiányzó @path)" #: modules/gdscript/gdscript_functions.cpp msgid "Invalid instance dictionary format (can't load script at @path)" msgstr "" +"Érvénytelen példány szótár formátum (nem lehet kódot betölteni a @path " +"helyén)" #: modules/gdscript/gdscript_functions.cpp msgid "Invalid instance dictionary format (invalid script at @path)" -msgstr "" +msgstr "Érvénytelen példány szótár formátum (hibás kód a @path helyén)" #: modules/gdscript/gdscript_functions.cpp msgid "Invalid instance dictionary (invalid subclasses)" -msgstr "" +msgstr "Érvénytelen példány szótár (érvénytelen alosztályok)" #: modules/gdscript/gdscript_functions.cpp msgid "Object can't provide a length." @@ -11476,7 +11493,7 @@ msgstr "A név nem érvényes azonosÃtó:" #: modules/visual_script/visual_script_editor.cpp msgid "Name already in use by another func/var/signal:" -msgstr "" +msgstr "A nevet már használja egy függvény/változó/jelzés:" #: modules/visual_script/visual_script_editor.cpp msgid "Rename Function" @@ -11516,7 +11533,7 @@ msgstr "Kimeneti port eltávolÃtása" #: modules/visual_script/visual_script_editor.cpp msgid "Change Expression" -msgstr "Kifejezés módosÃtása" +msgstr "Kifejezés változtatása" #: modules/visual_script/visual_script_editor.cpp msgid "Remove VisualScript Nodes" @@ -11552,11 +11569,11 @@ msgstr "" #: modules/visual_script/visual_script_editor.cpp msgid "Add Preload Node" -msgstr "" +msgstr "ElÅ‘re betöltött node hozzáadása" #: modules/visual_script/visual_script_editor.cpp msgid "Add Node(s) From Tree" -msgstr "" +msgstr "Node(ok) hozzáadása a fáról" #: modules/visual_script/visual_script_editor.cpp msgid "" @@ -11694,11 +11711,11 @@ msgstr "" #: modules/visual_script/visual_script_editor.cpp msgid "Delete Selected" -msgstr "Kijelöltek törlése" +msgstr "Kiválasztottak törlése" #: modules/visual_script/visual_script_editor.cpp msgid "Find Node Type" -msgstr "" +msgstr "Node tÃpus keresése" #: modules/visual_script/visual_script_editor.cpp msgid "Copy Nodes" @@ -12099,6 +12116,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12359,6 +12396,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12566,6 +12623,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Ezen a helyen már van azonos nevű fájl vagy mappa." + #~ msgid "Error trying to save layout!" #~ msgstr "Hiba történt az elrendezés mentésekor!" diff --git a/editor/translations/id.po b/editor/translations/id.po index 153df872de..1e88404be4 100644 --- a/editor/translations/id.po +++ b/editor/translations/id.po @@ -1112,7 +1112,7 @@ msgstr "Penjelajah Resource Orphan" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3732,6 +3732,16 @@ msgid "Name contains invalid characters." msgstr "Nama mengandung karakter tidak valid." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Mengubah nama berkas dengan:" @@ -3779,24 +3789,11 @@ msgstr "Sunting Dependensi..." msgid "View Owners..." msgstr "Tampilkan Pemilik Berkas..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Ubah Nama..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Gandakan..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Pindahkan ke..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Pindahkan Autoload" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Skena Baru…" @@ -3819,11 +3816,17 @@ msgid "Collapse All" msgstr "Lipat Semua" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Ubah Nama" +msgid "Duplicate..." +msgstr "Gandakan..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Pindahkan Autoload" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Ubah Nama..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3858,8 +3861,11 @@ msgid "Move" msgstr "Pindahkan" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Sudah ada nama berkas atau folder seperti itu di lokasi ini." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Ubah Nama" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9853,6 +9859,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12429,6 +12439,26 @@ msgstr "" "Animasi CPUParticles2D membutuhkan penggunaan CanvasItemMaterial dengan " "\"Animasi Partikel\" diaktifkan." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12746,6 +12776,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp #, fuzzy msgid "" @@ -12988,6 +13038,9 @@ msgstr "Variasi hanya bisa ditetapkan dalam fungsi vertex." msgid "Constants cannot be modified." msgstr "Konstanta tidak dapat dimodifikasi." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Sudah ada nama berkas atau folder seperti itu di lokasi ini." + #~ msgid "Error trying to save layout!" #~ msgstr "Error mencoba untuk menyimpan layout!" diff --git a/editor/translations/is.po b/editor/translations/is.po index c478090e4d..e6f66312bc 100644 --- a/editor/translations/is.po +++ b/editor/translations/is.po @@ -1092,7 +1092,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3578,6 +3578,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3625,25 +3635,11 @@ msgstr "Breyta" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "Hreyfimynd Tvöfalda Lykla" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Hreyfa Viðbótar Lykil" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3666,10 +3662,17 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +#, fuzzy +msgid "Duplicate..." +msgstr "Hreyfimynd Tvöfalda Lykla" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Hreyfa Viðbótar Lykil" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3703,7 +3706,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9548,6 +9554,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11987,6 +11997,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12247,6 +12277,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/it.po b/editor/translations/it.po index 03396bfa1f..8eefe1b29d 100644 --- a/editor/translations/it.po +++ b/editor/translations/it.po @@ -59,8 +59,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-23 21:42+0000\n" -"Last-Translator: Lorenzo Cerqua <lorenzocerqua@tutanota.com>\n" +"PO-Revision-Date: 2020-12-07 08:11+0000\n" +"Last-Translator: Mirko <miknsop@gmail.com>\n" "Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/" "godot/it/>\n" "Language: it\n" @@ -72,9 +72,8 @@ msgstr "" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp -#, fuzzy msgid "Invalid type argument to convert(), use TYPE_* constants." -msgstr "Argomento tipo non valido per convert(), usare le costanti TYPE_*." +msgstr "Tipo argomento non valido per convert(), usa le costanti TYPE_*." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." @@ -83,11 +82,10 @@ msgstr "Prevista una stringa di lunghezza 1 (un singolo carattere)." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp -#, fuzzy msgid "Not enough bytes for decoding bytes, or invalid format." msgstr "" -"Non ci sono abbastanza byte per riuscire a decodificarli, oppure il formato " -"non è valido." +"Non ci sono abbastanza byte per decodificarli, oppure il formato non è " +"valido." #: core/math/expression.cpp msgid "Invalid input %i (not passed) in expression" @@ -178,14 +176,12 @@ msgid "Delete Selected Key(s)" msgstr "Elimina le chiavi selezionate" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Add Bezier Point" -msgstr "Aggiungi punto Bézier" +msgstr "Aggiungi Punto Bezier" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Move Bezier Points" -msgstr "Sposta punto Bézier" +msgstr "Sposta Punti Bezier" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Duplicate Keys" @@ -1092,16 +1088,16 @@ msgstr "" "Puoi trovare i file rimossi nel cestino di sistema per ripristinarli." #: editor/dependency_editor.cpp -#, fuzzy msgid "" "The files being removed are required by other resources in order for them to " "work.\n" "Remove them anyway? (no undo)\n" "You can find the removed files in the system trash to restore them." msgstr "" -"I file che stanno per essere rimossi sono richiesti da altre risorse perché " -"esse funzionino.\n" -"Rimuoverli comunque? (non annullabile)" +"I file che stanno per essere rimossi sono richiesti per il funzionamento di " +"altre risorse.\n" +"Rimuoverli comunque? (non annullabile)\n" +"Puoi trovare i file rimossi nel cestino di sistema per ripristinarli." #: editor/dependency_editor.cpp msgid "Cannot remove:" @@ -1145,7 +1141,7 @@ msgstr "Esplora risorse orfane" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -2178,6 +2174,7 @@ msgid "Property:" msgstr "Proprietà :" #: editor/editor_inspector.cpp +#, fuzzy msgid "Set" msgstr "Imposta" @@ -2370,6 +2367,9 @@ msgid "" "An error occurred while trying to save the editor layout.\n" "Make sure the editor's user data path is writable." msgstr "" +"Si è verificato un errore mentre si stava provando a salvare il layout " +"dell'editor.\n" +"Assicurati che il percorso dati dell'editor dell'utente sia scrivibile." #: editor/editor_node.cpp msgid "" @@ -2386,9 +2386,8 @@ msgid "Layout name not found!" msgstr "Nome della disposizione non trovato!" #: editor/editor_node.cpp -#, fuzzy msgid "Restored the Default layout to its base settings." -msgstr "Ripristinata la disposizione predefinita alle impostazioni originali." +msgstr "Ripristinato il layout default alle impostazioni base." #: editor/editor_node.cpp msgid "" @@ -3777,6 +3776,16 @@ msgid "Name contains invalid characters." msgstr "Il nome contiene caratteri non validi." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Rinomina file:" @@ -3824,23 +3833,11 @@ msgstr "Modifica Dipendenze..." msgid "View Owners..." msgstr "Vedi Proprietari..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Rinomina..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplica..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Sposta in..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "Sposta nel cestino" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nuova scena…" @@ -3863,11 +3860,16 @@ msgid "Collapse All" msgstr "Comprimi Tutto" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Rinomina" +msgid "Duplicate..." +msgstr "Duplica..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Sposta nel cestino" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Rinomina..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3902,8 +3904,11 @@ msgid "Move" msgstr "Sposta" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "C'è già un file o una cartella con lo stesso nome in questo percorso." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Rinomina" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -6608,14 +6613,12 @@ msgid "Paint Bone Weights" msgstr "Dipingi peso delle ossa" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Open Polygon 2D UV editor." -msgstr "Apri editor Poligono 2D UV." +msgstr "Apri l'editor UV di Polygon2D." #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Polygon 2D UV Editor" -msgstr "Polygon 2D UV Editor" +msgstr "Editor UV Polygon 2D" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "UV" @@ -6712,14 +6715,12 @@ msgid "Grid Settings" msgstr "Impostazioni griglia" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Snap" msgstr "Snap" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Enable Snap" -msgstr "Abilita snap" +msgstr "Abilita Snap" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Grid" @@ -6771,9 +6772,8 @@ msgid "Delete Resource" msgstr "Elimina risorsa" #: editor/plugins/resource_preloader_editor_plugin.cpp -#, fuzzy msgid "Resource clipboard is empty!" -msgstr "Gli appunti risorse sono vuoti!" +msgstr "La clipboard delle risorse è vuota!" #: editor/plugins/resource_preloader_editor_plugin.cpp msgid "Paste Resource" @@ -6915,9 +6915,8 @@ msgid "Filter scripts" msgstr "Filtra gli script" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Toggle alphabetical sorting of the method list." -msgstr "Attiva/Disattiva l'ordinazione alfabetica della lista dei metodi." +msgstr "Abilita/Disabilita l'ordinamento alfabetico della lista dei metodi." #: editor/plugins/script_editor_plugin.cpp msgid "Filter methods" @@ -7084,7 +7083,6 @@ msgid "Clear Recent Scripts" msgstr "Rimuovi Script Recenti" #: editor/plugins/script_text_editor.cpp -#, fuzzy msgid "Connections to method:" msgstr "Connessioni al metodo:" @@ -7097,7 +7095,6 @@ msgid "Target" msgstr "Target" #: editor/plugins/script_text_editor.cpp -#, fuzzy msgid "" "Missing connected method '%s' for signal '%s' from node '%s' to node '%s'." msgstr "" @@ -7135,9 +7132,8 @@ msgid "Pick Color" msgstr "Scegli un colore" #: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp -#, fuzzy msgid "Convert Case" -msgstr "Converti capitalizzazione" +msgstr "Converti Maiuscole/Minuscole" #: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp msgid "Uppercase" @@ -7192,9 +7188,8 @@ msgid "Indent Right" msgstr "Indenta a destra" #: editor/plugins/script_text_editor.cpp -#, fuzzy msgid "Toggle Comment" -msgstr "Attiva/Disattiva commento" +msgstr "Attiva/Disattiva Commento" #: editor/plugins/script_text_editor.cpp msgid "Fold/Unfold Line" @@ -7270,9 +7265,8 @@ msgstr "Vai alla linea..." #: editor/plugins/script_text_editor.cpp #: modules/visual_script/visual_script_editor.cpp -#, fuzzy msgid "Toggle Breakpoint" -msgstr "Attiva/Disattiva punti di interruzione" +msgstr "Attiva/Disattiva Punto D'Interruzione" #: editor/plugins/script_text_editor.cpp msgid "Remove All Breakpoints" @@ -7303,12 +7297,10 @@ msgid "This skeleton has no bones, create some children Bone2D nodes." msgstr "Questo scheletro non ha ossa, crea dei nodi figlio Bone2D." #: editor/plugins/skeleton_2d_editor_plugin.cpp -#, fuzzy msgid "Create Rest Pose from Bones" msgstr "Crea Posizione di Riposo dalle Ossa" #: editor/plugins/skeleton_2d_editor_plugin.cpp -#, fuzzy msgid "Set Rest Pose to Bones" msgstr "Imposta Ossa in Posizione di Riposo" @@ -7317,12 +7309,10 @@ msgid "Skeleton2D" msgstr "Skeleton2D" #: editor/plugins/skeleton_2d_editor_plugin.cpp -#, fuzzy msgid "Make Rest Pose (From Bones)" msgstr "Crea Posizione di Riposo (Dalle Ossa)" #: editor/plugins/skeleton_2d_editor_plugin.cpp -#, fuzzy msgid "Set Bones to Rest Pose" msgstr "Imposta Ossa in Posizione di Riposo" @@ -7331,6 +7321,7 @@ msgid "Create physical bones" msgstr "Crea ossa fisiche" #: editor/plugins/skeleton_editor_plugin.cpp +#, fuzzy msgid "Skeleton" msgstr "Scheletro" @@ -7678,6 +7669,7 @@ msgstr "Abilita/Disabilita Vista libera" #: editor/plugins/spatial_editor_plugin.cpp #: editor/plugins/visual_shader_editor_plugin.cpp +#, fuzzy msgid "Transform" msgstr "Trasforma" @@ -8425,23 +8417,20 @@ msgid "Create a new rectangle." msgstr "Crea un nuovo rettangolo." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Riempi Rettangolo" +msgstr "Nuovo Rettangolo" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Crea un nuovo poligono." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "Sposta poligono" +msgstr "Nuovo Poligono" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Elimina selezionati" +msgstr "Elimina Forma Selezionata" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -8752,8 +8741,9 @@ msgid "Scalar" msgstr "Scalare" #: editor/plugins/visual_shader_editor_plugin.cpp +#, fuzzy msgid "Vector" -msgstr "Vettore" +msgstr "Vector" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Boolean" @@ -9929,6 +9919,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11282,6 +11276,7 @@ msgid "Value" msgstr "Valore" #: editor/script_editor_debugger.cpp +#, fuzzy msgid "Monitors" msgstr "Monitor" @@ -12206,7 +12201,7 @@ msgstr "" #: platform/android/export/export.cpp msgid "Missing 'platform-tools' directory!" -msgstr "" +msgstr "Cartella 'platform-tools' inesistente!" #: platform/android/export/export.cpp msgid "" @@ -12523,6 +12518,26 @@ msgstr "" "L'animazione CPUParticles2D richiede l'utilizzo di un CanvasItemMaterial con " "\"Animazione Particelle\" abilitata." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12856,6 +12871,26 @@ msgstr "" "rigide) saranno sovrascritti dal motore fisico quando in esecuzione.\n" "Modifica invece la dimensione in sagome di collisione figlie." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13091,14 +13126,18 @@ msgid "Assignment to uniform." msgstr "Assegnazione all'uniforme." #: servers/visual/shader_language.cpp -#, fuzzy msgid "Varyings can only be assigned in vertex function." -msgstr "Varyings può essere assegnato soltanto nella funzione del vertice." +msgstr "" +"Le variabili possono essere assegnate soltanto in funzione del vertice." #: servers/visual/shader_language.cpp msgid "Constants cannot be modified." msgstr "Le constanti non possono essere modificate." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "" +#~ "C'è già un file o una cartella con lo stesso nome in questo percorso." + #~ msgid "Error trying to save layout!" #~ msgstr "Errore nel salvataggio della disposizione!" diff --git a/editor/translations/ja.po b/editor/translations/ja.po index 4b107d82e1..0ec6a58ed9 100644 --- a/editor/translations/ja.po +++ b/editor/translations/ja.po @@ -36,7 +36,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-24 16:44+0000\n" +"PO-Revision-Date: 2020-12-01 20:29+0000\n" "Last-Translator: Wataru Onuki <bettawat@yahoo.co.jp>\n" "Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/" "godot/ja/>\n" @@ -1116,7 +1116,7 @@ msgstr "å¤ç«‹ãƒªã‚½ãƒ¼ã‚¹ エクスプãƒãƒ¼ãƒ©ãƒ¼" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3728,6 +3728,16 @@ msgid "Name contains invalid characters." msgstr "åå‰ã«ä½¿ç”¨ã§ããªã„æ–‡å—ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "ファイルåを変更:" @@ -3775,23 +3785,11 @@ msgstr "ä¾å˜é–¢ä¿‚ã®ç·¨é›†..." msgid "View Owners..." msgstr "オーナーを見る..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "åå‰ã‚’変更..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "複製..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "移動..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "ã”ã¿ç®±ã¸ç§»å‹•" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "æ–°è¦ã‚·ãƒ¼ãƒ³..." @@ -3814,11 +3812,16 @@ msgid "Collapse All" msgstr "ã™ã¹ã¦æŠ˜ã‚ŠãŸãŸã‚€" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "åå‰ã®å¤‰æ›´" +msgid "Duplicate..." +msgstr "複製..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "ã”ã¿ç®±ã¸ç§»å‹•" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "åå‰ã‚’変更..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3853,8 +3856,11 @@ msgid "Move" msgstr "移動" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "ã“ã®ãƒ‘スã«ã¯ã€æ—¢ã«åŒåã®ãƒ•ァイルã‹ãƒ•ォルダãŒã‚りã¾ã™ã€‚" +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "åå‰ã®å¤‰æ›´" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8333,27 +8339,24 @@ msgid "Create a new rectangle." msgstr "æ–°ã—ã長方形を作æˆã€‚" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "長方形ペイント" +msgstr "æ–°è¦é•·æ–¹å½¢" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "æ–°è¦ãƒãƒªã‚´ãƒ³ã‚’生æˆã€‚" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "ãƒãƒªã‚´ãƒ³ã‚’移動" +msgstr "æ–°è¦ãƒãƒªã‚´ãƒ³" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "é¸æŠžå¯¾è±¡ã‚’å‰Šé™¤" +msgstr "é¸æŠžã—ãŸã‚·ã‚§ã‚¤ãƒ—を削除" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." -msgstr "é ˜åŸŸRect内ã®ãƒãƒªã‚´ãƒ³ã‚’ä¿æŒã—ã¾ã™ã€‚" +msgstr "é ˜åŸŸ Rect 内ã®ãƒãƒªã‚´ãƒ³ã‚’ä¿æŒã—ã¾ã™ã€‚" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Enable snap and show grid (configurable via the Inspector)." @@ -9821,6 +9824,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12370,8 +12377,8 @@ msgid "" "A shape must be provided for CollisionShape2D to function. Please create a " "shape resource for it!" msgstr "" -"関数ã«å¯¾ã—㦠CollisionShape2D ã®å½¢çж(シェイプ)を指定ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ãã®" -"ãŸã‚ã®ã‚·ã‚§ã‚¤ãƒ—リソースを作æˆã—ã¦ãã ã•ã„!" +"関数ã«å¯¾ã—㦠CollisionShape2D ã®å½¢çж (シェイプ) を指定ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ã" +"ã®ãŸã‚ã®ã‚·ã‚§ã‚¤ãƒ—リソースを作æˆã—ã¦ãã ã•ã„ï¼" #: scene/2d/collision_shape_2d.cpp msgid "" @@ -12389,6 +12396,26 @@ msgstr "" "CPUParticles2Dアニメーションã§ã¯ã€ \"Particles Animation\" を有効ã«ã—ãŸ" "CanvasItemMaterialを使用ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12412,8 +12439,8 @@ msgid "" "A NavigationPolygon resource must be set or created for this node to work. " "Please set a property or draw a polygon." msgstr "" -"NavigationPolygon リソースをè¨å®šã¾ãŸã¯å‹•作ã™ã‚‹ã‚ˆã†ã«ã“ã®ãƒŽãƒ¼ãƒ‰ç”¨ã«ä½œæˆã™ã‚‹å¿…" -"è¦ãŒã‚りã¾ã™ã€‚プãƒãƒ‘ティをè¨å®šã™ã‚‹ã‹ã€ãƒãƒªã‚´ãƒ³ã‚’æç”»ã—ã¦ãã ã•ã„。" +"ã“ã®ãƒŽãƒ¼ãƒ‰ç”¨ã« NavigationPolygon リソースをè¨å®šã¾ãŸã¯ä½œæˆã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚" +"プãƒãƒ‘ティをè¨å®šã™ã‚‹ã‹ã€ãƒãƒªã‚´ãƒ³ã‚’æç”»ã—ã¦ãã ã•ã„。" #: scene/2d/navigation_polygon.cpp msgid "" @@ -12717,6 +12744,26 @@ msgstr "" "物ç†ã‚¨ãƒ³ã‚¸ãƒ³ã«ã‚ˆã£ã¦ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰ã•れã¾ã™ã€‚\n" "代ã‚りã«ã€åã®è¡çªã‚·ã‚§ã‚¤ãƒ—ã®ã‚µã‚¤ã‚ºã‚’変更ã—ã¦ãã ã•ã„。" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12958,6 +13005,9 @@ msgstr "Varying変数ã¯é ‚点関数ã«ã®ã¿å‰²ã‚Šå½“ã¦ã‚‹ã“ã¨ãŒã§ãã¾ã msgid "Constants cannot be modified." msgstr "定数ã¯å¤‰æ›´ã§ãã¾ã›ã‚“。" +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "ã“ã®ãƒ‘スã«ã¯ã€æ—¢ã«åŒåã®ãƒ•ァイルã‹ãƒ•ォルダãŒã‚りã¾ã™ã€‚" + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "'build-tools' ディレクトリãŒã‚りã¾ã›ã‚“ï¼" diff --git a/editor/translations/ka.po b/editor/translations/ka.po index 55895c0e5e..ae770dc05a 100644 --- a/editor/translations/ka.po +++ b/editor/translations/ka.po @@ -1136,7 +1136,7 @@ msgstr "áƒáƒ‘áƒáƒšáƒ˜ რესურსების მáƒáƒ«áƒ˜áƒ”ბელá #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3669,6 +3669,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3719,23 +3729,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp #, fuzzy msgid "New Scene..." msgstr "რესურსი" @@ -3761,10 +3759,15 @@ msgid "Collapse All" msgstr "ყველáƒáƒ¡ ჩáƒáƒœáƒáƒªáƒ•ლებáƒ" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3799,7 +3802,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9751,6 +9757,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12226,6 +12236,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12486,6 +12516,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/ko.po b/editor/translations/ko.po index 9d1ccc2440..14f197d86e 100644 --- a/editor/translations/ko.po +++ b/editor/translations/ko.po @@ -1103,7 +1103,7 @@ msgstr "미사용 리소스 íƒìƒ‰ê¸°" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3693,6 +3693,16 @@ msgid "Name contains invalid characters." msgstr "ì´ë¦„ì— ìž˜ëª»ëœ ë¬¸ìžê°€ 있습니다." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "íŒŒì¼ ì´ë¦„ 바꾸기:" @@ -3740,24 +3750,11 @@ msgstr "ì¢…ì† ê´€ê³„ 편집..." msgid "View Owners..." msgstr "ì†Œìœ ìž ë³´ê¸°..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "ì´ë¦„ 바꾸기..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "ë³µì œ..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "여기로 ì´ë™..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "ì˜¤í† ë¡œë“œ ì´ë™" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "새 씬..." @@ -3780,11 +3777,17 @@ msgid "Collapse All" msgstr "ëª¨ë‘ ì ‘ê¸°" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "ì´ë¦„ 바꾸기" +msgid "Duplicate..." +msgstr "ë³µì œ..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "ì˜¤í† ë¡œë“œ ì´ë™" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "ì´ë¦„ 바꾸기..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3819,8 +3822,11 @@ msgid "Move" msgstr "ì´ë™" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "ì´ ìœ„ì¹˜ì—는 ê°™ì€ ì´ë¦„ì˜ íŒŒì¼ì´ë‚˜ í´ë”ê°€ 있습니다." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "ì´ë¦„ 바꾸기" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9763,6 +9769,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12302,6 +12312,26 @@ msgstr "" "CPUParticles2D ì• ë‹ˆë©”ì´ì…˜ì—는 \"Particles Animation\"ì´ ì¼œì§„ " "CanvasItemMaterialì„ ì‚¬ìš©í•´ì•¼ 합니다." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12619,6 +12649,26 @@ msgstr "" "í° ë¶€ë‹´ì´ ë©ë‹ˆë‹¤.\n" "ëŒ€ì‹ ìžì‹ ì¶©ëŒ ëª¨ì–‘ì˜ í¬ê¸°ë¥¼ 변경하세요." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12856,6 +12906,9 @@ msgstr "Varyingì€ ê¼ì§“ì 함수ì—ë§Œ ì§€ì •í• ìˆ˜ 있습니다." msgid "Constants cannot be modified." msgstr "ìƒìˆ˜ëŠ” ìˆ˜ì •í• ìˆ˜ 없습니다." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "ì´ ìœ„ì¹˜ì—는 ê°™ì€ ì´ë¦„ì˜ íŒŒì¼ì´ë‚˜ í´ë”ê°€ 있습니다." + #~ msgid "Error trying to save layout!" #~ msgstr "ë ˆì´ì•„웃 ì €ìž¥ 중 오류!" diff --git a/editor/translations/lt.po b/editor/translations/lt.po index 28cb35e017..6dafdd84e0 100644 --- a/editor/translations/lt.po +++ b/editor/translations/lt.po @@ -1097,7 +1097,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3629,6 +3629,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3681,26 +3691,12 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "Duplikuoti" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Mix Nodas" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "Atidaryti Skriptų Editorių" @@ -3723,10 +3719,17 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +#, fuzzy +msgid "Duplicate..." +msgstr "Duplikuoti" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Mix Nodas" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3762,7 +3765,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9728,6 +9734,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12197,6 +12207,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12459,6 +12489,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/lv.po b/editor/translations/lv.po index 2284a0fe02..64a29939e9 100644 --- a/editor/translations/lv.po +++ b/editor/translations/lv.po @@ -1093,7 +1093,7 @@ msgstr "BÄreņu Resursu PÄrlÅ«ks" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3578,6 +3578,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3625,23 +3635,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Jauna Aina..." @@ -3664,10 +3662,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3701,7 +3704,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9547,6 +9553,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11995,6 +12005,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12255,6 +12285,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/mi.po b/editor/translations/mi.po index adae136a19..df5a0dcf55 100644 --- a/editor/translations/mi.po +++ b/editor/translations/mi.po @@ -1048,7 +1048,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3524,6 +3524,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3571,23 +3581,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3610,10 +3608,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3647,7 +3650,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9419,6 +9425,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11832,6 +11842,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12092,6 +12122,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/ml.po b/editor/translations/ml.po index f09e381719..346d52b331 100644 --- a/editor/translations/ml.po +++ b/editor/translations/ml.po @@ -1058,7 +1058,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3536,6 +3536,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3583,23 +3593,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3622,10 +3620,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3659,7 +3662,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9436,6 +9442,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11850,6 +11860,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12110,6 +12140,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/mr.po b/editor/translations/mr.po index 8ea8dc7027..8f588050ab 100644 --- a/editor/translations/mr.po +++ b/editor/translations/mr.po @@ -1055,7 +1055,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3531,6 +3531,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3578,23 +3588,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3617,10 +3615,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3654,7 +3657,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9427,6 +9433,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11840,6 +11850,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12100,6 +12130,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/ms.po b/editor/translations/ms.po index 01affc2669..d00dfd659f 100644 --- a/editor/translations/ms.po +++ b/editor/translations/ms.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-09-15 07:17+0000\n" +"PO-Revision-Date: 2020-12-02 09:52+0000\n" "Last-Translator: Keviindran Ramachandran <keviinx@yahoo.com>\n" "Language-Team: Malay <https://hosted.weblate.org/projects/godot-engine/godot/" "ms/>\n" @@ -22,7 +22,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.3-dev\n" +"X-Generator: Weblate 4.4-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -904,9 +904,8 @@ msgid "Signals" msgstr "Isyarat" #: editor/connections_dialog.cpp -#, fuzzy msgid "Filter signals" -msgstr "Dari Isyarat:" +msgstr "Tapis isyarat" #: editor/connections_dialog.cpp msgid "Are you sure you want to remove all connections from this signal?" @@ -1035,14 +1034,15 @@ msgid "Owners Of:" msgstr "Pemilik:" #: editor/dependency_editor.cpp -#, fuzzy msgid "" "Remove selected files from the project? (no undo)\n" "You can find the removed files in the system trash to restore them." -msgstr "Alih keluar fail terpilih dari projek? (Tidak dapat dipulihkan)" +msgstr "" +"Alih keluar fail terpilih dari projek? (Tidak boleh buat asal)\n" +"Anda boleh mencari fail yang dikeluarkan dalam tong sampah untuk " +"memulihkannya." #: editor/dependency_editor.cpp -#, fuzzy msgid "" "The files being removed are required by other resources in order for them to " "work.\n" @@ -1051,7 +1051,9 @@ msgid "" msgstr "" "Fail yang akan dikeluarkan diperlukan oleh sumber lain agar dapat " "berfungsi.\n" -"Masih mahu keluarkan fail tersebut? (tidak boleh buat asal)" +"Masih mahu keluarkan fail tersebut? (tidak boleh buat asal)\n" +"Anda boleh mencari fail yang dikeluarkan dalam tong sampah untuk " +"memulihkannya." #: editor/dependency_editor.cpp msgid "Cannot remove:" @@ -1095,7 +1097,7 @@ msgstr "Penjelajah Sumber Yatim" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -1157,12 +1159,10 @@ msgid "Gold Sponsors" msgstr "Penaja Emas" #: editor/editor_about.cpp -#, fuzzy msgid "Silver Sponsors" msgstr "Penderma Perak" #: editor/editor_about.cpp -#, fuzzy msgid "Bronze Sponsors" msgstr "Penderma Gangsa" @@ -3637,6 +3637,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3684,24 +3694,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Pindah Autoload" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3724,10 +3721,16 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Pindah Autoload" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3761,7 +3764,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9562,6 +9568,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11986,6 +11996,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12246,6 +12276,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/nb.po b/editor/translations/nb.po index 4028e7b357..b1bb5ead4b 100644 --- a/editor/translations/nb.po +++ b/editor/translations/nb.po @@ -1148,7 +1148,7 @@ msgstr "Foreldreløs ressursutforsker" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3889,6 +3889,16 @@ msgid "Name contains invalid characters." msgstr "Navn inneholder ugyldige tegn." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Endrer filnavn:" @@ -3943,26 +3953,12 @@ msgstr "Endre Avhengigheter..." msgid "View Owners..." msgstr "Vis Eiere..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Endre Navn..." - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "Duplisér" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Flytt Til..." #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Flytt Autoload" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "Ny Scene" @@ -3989,11 +3985,18 @@ msgid "Collapse All" msgstr "Kollaps alle" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Endre navn" +#, fuzzy +msgid "Duplicate..." +msgstr "Duplisér" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Flytt Autoload" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Endre Navn..." #: editor/filesystem_dock.cpp #, fuzzy @@ -4032,9 +4035,11 @@ msgid "Move" msgstr "Flytt" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "There is already file or folder with the same name in this location." -msgstr "En fil eller mappe med dette navnet eksisterer allerede." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Endre navn" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -10271,6 +10276,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12860,6 +12869,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -13120,6 +13149,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13329,6 +13378,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Konstanter kan ikke endres." +#, fuzzy +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "En fil eller mappe med dette navnet eksisterer allerede." + #~ msgid "Error trying to save layout!" #~ msgstr "Error ved lagring av layout!" diff --git a/editor/translations/nl.po b/editor/translations/nl.po index 9311078bae..2b0d754edd 100644 --- a/editor/translations/nl.po +++ b/editor/translations/nl.po @@ -47,7 +47,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-10-30 10:21+0000\n" +"PO-Revision-Date: 2020-11-29 08:28+0000\n" "Last-Translator: Stijn Hinlopen <f.a.hinlopen@gmail.com>\n" "Language-Team: Dutch <https://hosted.weblate.org/projects/godot-engine/godot/" "nl/>\n" @@ -56,7 +56,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.3.2-dev\n" +"X-Generator: Weblate 4.4-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -940,9 +940,8 @@ msgid "Signals" msgstr "Signalen" #: editor/connections_dialog.cpp -#, fuzzy msgid "Filter signals" -msgstr "Filter tegels" +msgstr "Signalen filteren" #: editor/connections_dialog.cpp msgid "Are you sure you want to remove all connections from this signal?" @@ -1071,16 +1070,16 @@ msgid "Owners Of:" msgstr "Eigenaren van:" #: editor/dependency_editor.cpp -#, fuzzy msgid "" "Remove selected files from the project? (no undo)\n" "You can find the removed files in the system trash to restore them." msgstr "" "Geselecteerde bestanden uit het project verwijderen? (Kan niet ongedaan " -"gemaakt worden)" +"gemaakt worden)\n" +"De bestanden kunnen mogelijk vanuit de prullenbak van het systeem hersteld " +"worden." #: editor/dependency_editor.cpp -#, fuzzy msgid "" "The files being removed are required by other resources in order for them to " "work.\n" @@ -1089,7 +1088,9 @@ msgid "" msgstr "" "De bestanden die verwijderd worden zijn nodig om andere bronnen te laten " "werken.\n" -"Toch verwijderen? (Onomkeerbaar)" +"Toch verwijderen? (Onomkeerbaar)\n" +"De bestanden kunnen mogelijk vanuit de prullenbak van het systeem hersteld " +"worden." #: editor/dependency_editor.cpp msgid "Cannot remove:" @@ -1133,7 +1134,7 @@ msgstr "Weesbronnen bekijken" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -1195,14 +1196,12 @@ msgid "Gold Sponsors" msgstr "Gouden Sponsors" #: editor/editor_about.cpp -#, fuzzy msgid "Silver Sponsors" -msgstr "Zilveren Donors" +msgstr "Zilveren Sponsoren" #: editor/editor_about.cpp -#, fuzzy msgid "Bronze Sponsors" -msgstr "Bronzen Donors" +msgstr "Bronzen Sponsoren" #: editor/editor_about.cpp msgid "Mini Sponsors" @@ -1715,9 +1714,8 @@ msgid "Node Dock" msgstr "Knooptabblad" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "FileSystem Dock" -msgstr "Bestandssysteem" +msgstr "Bestandssysteempaneel" #: editor/editor_feature_profile.cpp msgid "Import Dock" @@ -2359,6 +2357,8 @@ msgid "" "An error occurred while trying to save the editor layout.\n" "Make sure the editor's user data path is writable." msgstr "" +"Fout tijdens het opslaan van de editorindeling.\n" +"Zorg dat er naar het pad voor editorgebruikgegevens beschrijfbaar is." #: editor/editor_node.cpp msgid "" @@ -2366,15 +2366,17 @@ msgid "" "To restore the Default layout to its base settings, use the Delete Layout " "option and delete the Default layout." msgstr "" +"Standaardindeling overschreven.\n" +"Om de oorspronkelijke instellingen van de standaardindeling te herstellen, " +"moet je de standaardindeling verwijderen met de optie 'Indeling verwijderen'." #: editor/editor_node.cpp msgid "Layout name not found!" msgstr "Indelingsnaam niet gevonden!" #: editor/editor_node.cpp -#, fuzzy msgid "Restored the Default layout to its base settings." -msgstr "Standaardindeling teruggezet naar basisinstellingen." +msgstr "Standaardindeling teruggezet naar oorspronkelijke instellingen." #: editor/editor_node.cpp msgid "" @@ -2867,7 +2869,7 @@ msgstr "Debuggen" #: editor/editor_node.cpp msgid "Deploy with Remote Debug" -msgstr "Opstarten met debugging op afstand" +msgstr "Uitrollen met debugging op afstand" #: editor/editor_node.cpp msgid "" @@ -2878,11 +2880,15 @@ msgid "" "mobile device).\n" "You don't need to enable it to use the GDScript debugger locally." msgstr "" +"Als deze optie geactiveerd is, zal één-klik uitrol het programma proberen " +"een verbinding te sarten met het IP-adres van deze computer.\n" +"Deze optie is bedoeld om op afstand fouten op te sporen (gewoonlijk met een " +"mobiel toestel).\n" +"Je hebt dit niet nodig om het draaiende programma lokaal te inspecteren." #: editor/editor_node.cpp -#, fuzzy msgid "Small Deploy with Network Filesystem" -msgstr "Klein uitvoerbaar bestand opstarten met netwerk bestandsserver" +msgstr "Kleine uitrol met netwerkbestandssysteem" #: editor/editor_node.cpp #, fuzzy @@ -2928,12 +2934,10 @@ msgstr "" "deze optie aanstaat." #: editor/editor_node.cpp -#, fuzzy msgid "Synchronize Scene Changes" -msgstr "Scèneveranderingen synchroniseren" +msgstr "Veranderingen in de scène synchroniseren" #: editor/editor_node.cpp -#, fuzzy msgid "" "When this option is enabled, any changes made to the scene in the editor " "will be replicated in the running project.\n" @@ -2941,14 +2945,13 @@ msgid "" "filesystem option is enabled." msgstr "" "Wanneer deze optie aanstaat, wordt elke verandering gemaakt in de editor " -"toegepast op het draaiend spel.\n" +"toegepast op het lopende spel.\n" "Wanneer dit op afstand wordt gebruikt op een andere machine, is dit " "efficiënter met het netwerk bestandssysteem." #: editor/editor_node.cpp -#, fuzzy msgid "Synchronize Script Changes" -msgstr "Scriptveranderingen synchroniseren" +msgstr "Veranderingen in scripts synchroniseren" #: editor/editor_node.cpp #, fuzzy @@ -3755,6 +3758,16 @@ msgid "Name contains invalid characters." msgstr "Naam bevat ongeldige tekens." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Bestand hernoemen:" @@ -3802,24 +3815,11 @@ msgstr "Afhankelijkheden aanpassen..." msgid "View Owners..." msgstr "Bekijk eigenaren..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Hernoemen..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Dupliceren..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Verplaats Naar..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Autoload verplaatsen" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nieuwe scène..." @@ -3842,11 +3842,16 @@ msgid "Collapse All" msgstr "Alles inklappen" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Naam wijzigen" +msgid "Duplicate..." +msgstr "Dupliceren..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Naar prullenbak verplaatsen" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Hernoemen..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3881,8 +3886,11 @@ msgid "Move" msgstr "Verplaatsen" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Er is al een bestand of map met dezelfde naam op dit pad." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Naam wijzigen" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -5285,27 +5293,24 @@ msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)" msgstr "" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Rotate %d CanvasItems" -msgstr "CanvasItem roteren" +msgstr "%d CanvasItems roteren" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Rotate CanvasItem \"%s\" to %d degrees" -msgstr "CanvasItem roteren" +msgstr "CanvasItem \"%s\" roteren tot %d graden" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Move CanvasItem \"%s\" Anchor" -msgstr "Verplaats CanvasItem" +msgstr "Verplaats Anker van CanvasItem \"%s\"" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Scale Node2D \"%s\" to (%s, %s)" -msgstr "" +msgstr "Node2D \"%s\" verschalen naar (%s, %s)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Resize Control \"%s\" to (%d, %d)" -msgstr "" +msgstr "Control \"%s\" vergrootten tot (%d, %d)" #: editor/plugins/canvas_item_editor_plugin.cpp #, fuzzy @@ -9892,6 +9897,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12468,6 +12477,26 @@ msgstr "" "CPUParticles2D vereist een CanvasItemMaterial met \"Particles Animation\" " "ingeschakeld." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12798,6 +12827,26 @@ msgstr "" "overschreven worden door de physics engine als het spel start.\n" "Verander in plaats daarvan de grootte van CollisionShapes in de kinderen." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13039,6 +13088,9 @@ msgstr "Varyings kunnen alleen worden toegewezenin vertex functies." msgid "Constants cannot be modified." msgstr "Constanten kunnen niet worden aangepast." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Er is al een bestand of map met dezelfde naam op dit pad." + #~ msgid "Error trying to save layout!" #~ msgstr "Fout bij het opslaan van indeling!" diff --git a/editor/translations/or.po b/editor/translations/or.po index e5c61be021..ba12c5c7eb 100644 --- a/editor/translations/or.po +++ b/editor/translations/or.po @@ -1054,7 +1054,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3530,6 +3530,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3577,23 +3587,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3616,10 +3614,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3653,7 +3656,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9425,6 +9431,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11838,6 +11848,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12098,6 +12128,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/pl.po b/editor/translations/pl.po index 580715c76d..3e67b723b5 100644 --- a/editor/translations/pl.po +++ b/editor/translations/pl.po @@ -44,12 +44,13 @@ # Roman Skiba <romanskiba0@gmail.com>, 2020. # Piotr Grodzki <ziemniakglados@gmail.com>, 2020. # Dzejkop <jakubtrad@gmail.com>, 2020. +# Mateusz Grzonka <alpinus4@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-20 23:08+0000\n" -"Last-Translator: Tomek <kobewi4e@gmail.com>\n" +"PO-Revision-Date: 2020-12-01 20:29+0000\n" +"Last-Translator: Mateusz Grzonka <alpinus4@gmail.com>\n" "Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/" "godot/pl/>\n" "Language: pl\n" @@ -1127,7 +1128,7 @@ msgstr "Eksplorator osieroconych zasobów" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3733,6 +3734,16 @@ msgid "Name contains invalid characters." msgstr "Nazwa zawiera niedozwolone znaki." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Zmiana nazwy pliku:" @@ -3780,23 +3791,11 @@ msgstr "Edytuj zależnoÅ›ci..." msgid "View Owners..." msgstr "Pokaż wÅ‚aÅ›cicieli..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "ZmieÅ„ nazwÄ™..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplikuj..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "PrzenieÅ› do..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "PrzenieÅ› do kosza" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nowa scena..." @@ -3819,11 +3818,16 @@ msgid "Collapse All" msgstr "ZwiÅ„ wszystko" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "ZmieÅ„ nazwÄ™" +msgid "Duplicate..." +msgstr "Duplikuj..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "PrzenieÅ› do kosza" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "ZmieÅ„ nazwÄ™..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3858,8 +3862,11 @@ msgid "Move" msgstr "PrzenieÅ›" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "W tej lokalizacji istnieje już plik lub folder o podanej nazwie." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "ZmieÅ„ nazwÄ™" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8348,23 +8355,20 @@ msgid "Create a new rectangle." msgstr "Utwórz nowy prostokÄ…t." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Malowanie prostokÄ…tne" +msgstr "Nowy prostokÄ…t" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Utwórz nowy wielokÄ…t." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "PrzesuÅ„ WielokÄ…t" +msgstr "Nowy WielokÄ…t" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "UsuÅ„ zaznaczone" +msgstr "UsuÅ„ Zaznaczony KsztaÅ‚t" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9840,6 +9844,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12420,6 +12428,26 @@ msgstr "" "Animacja CPUParticles2D wymaga użycia CanvasItemMaterial z włączonym " "\"Particles Animation\"." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12751,6 +12779,26 @@ msgstr "" "nadpisane przez silnik fizyki podczas dziaÅ‚ania.\n" "Zamiast tego, zmieÅ„ rozmiary ksztaÅ‚tów kolizji w wÄ™zÅ‚ach podrzÄ™dnych." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12990,6 +13038,9 @@ msgstr "Varying może być przypisane tylko w funkcji wierzchoÅ‚ków." msgid "Constants cannot be modified." msgstr "StaÅ‚e nie mogÄ… być modyfikowane." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "W tej lokalizacji istnieje już plik lub folder o podanej nazwie." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "Brakuje folderu \"build-tools\"!" diff --git a/editor/translations/pr.po b/editor/translations/pr.po index 740aaabb1e..ca0f2d5f7e 100644 --- a/editor/translations/pr.po +++ b/editor/translations/pr.po @@ -1098,7 +1098,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3647,6 +3647,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp #, fuzzy msgid "Renaming file:" msgstr "Rename Variable" @@ -3698,24 +3708,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Forge yer Node!" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3738,10 +3735,16 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Forge yer Node!" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3778,7 +3781,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9756,6 +9762,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12279,6 +12289,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12539,6 +12569,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/pt.po b/editor/translations/pt.po index c114c09299..b675b90e75 100644 --- a/editor/translations/pt.po +++ b/editor/translations/pt.po @@ -22,7 +22,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-24 16:44+0000\n" +"PO-Revision-Date: 2020-12-01 20:29+0000\n" "Last-Translator: João Lopes <linux-man@hotmail.com>\n" "Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/" "godot/pt/>\n" @@ -1104,7 +1104,7 @@ msgstr "Explorador de Recursos Órfãos" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3721,6 +3721,16 @@ msgid "Name contains invalid characters." msgstr "O nome contém caracteres inválidos." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Mudar nome do Ficheiro:" @@ -3768,23 +3778,11 @@ msgstr "Editar Dependências..." msgid "View Owners..." msgstr "Ver proprietários..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Renomear..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplicar..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Mover para..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "Mover para Reciclagem" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nova Cena..." @@ -3807,11 +3805,16 @@ msgid "Collapse All" msgstr "Colapsar Tudo" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Renomear" +msgid "Duplicate..." +msgstr "Duplicar..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Mover para Reciclagem" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Renomear..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3846,8 +3849,11 @@ msgid "Move" msgstr "Mover" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Já existe um ficheiro ou pasta com o mesmo nome nesta localização." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Renomear" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8321,23 +8327,20 @@ msgid "Create a new rectangle." msgstr "Criar novo retângulo." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Pintar retângulo" +msgstr "Novo Retângulo" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Criar um novo polÃgono." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "Mover PolÃgono" +msgstr "Novo PolÃgono" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Apagar Selecionado" +msgstr "Apagar Forma Selecionada" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9809,6 +9812,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12390,6 +12397,26 @@ msgstr "" "Animação CPUParticles2D requer o uso de um CanvasItemMaterial com " "\"Particles Animation\" ativada." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12714,6 +12741,26 @@ msgstr "" "reescritas pelo motor de fÃsica na execução.\n" "Mude antes o tamanho das formas de colisão filhas." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12954,6 +13001,9 @@ msgstr "Variações só podem ser atribuÃdas na função vértice." msgid "Constants cannot be modified." msgstr "Constantes não podem ser modificadas." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Já existe um ficheiro ou pasta com o mesmo nome nesta localização." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "Diretoria 'build-tools' em falta!" diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po index 8e2b759cec..90d332c743 100644 --- a/editor/translations/pt_BR.po +++ b/editor/translations/pt_BR.po @@ -101,12 +101,15 @@ # Jairo Tuboi <tuboi.jairo@gmail.com>, 2020. # Felipe Fetter <felipetfetter@gmail.com>, 2020. # Rafael Henrique Capati <rhcapati@gmail.com>, 2020. +# NogardRyuu <nogardryuu@gmail.com>, 2020. +# Elton <eltondeoliveira@outlook.com>, 2020. +# ThiagoCTN <thiagocampostn@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: 2016-05-30\n" -"PO-Revision-Date: 2020-10-05 01:02+0000\n" -"Last-Translator: Rafael Henrique Capati <rhcapati@gmail.com>\n" +"PO-Revision-Date: 2020-12-07 08:11+0000\n" +"Last-Translator: ThiagoCTN <thiagocampostn@gmail.com>\n" "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/" "godot-engine/godot/pt_BR/>\n" "Language: pt_BR\n" @@ -114,7 +117,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.3-dev\n" +"X-Generator: Weblate 4.4-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1123,14 +1126,15 @@ msgid "Owners Of:" msgstr "Donos De:" #: editor/dependency_editor.cpp -#, fuzzy msgid "" "Remove selected files from the project? (no undo)\n" "You can find the removed files in the system trash to restore them." -msgstr "Remover arquivos selecionados do projeto? (irreversÃvel)" +msgstr "" +"Remover arquivos selecionados do projeto? (irreversÃvel)\n" +"Você pode encontrar os arquivos removidos na lixeira e restaurá-los caso " +"seja necessário." #: editor/dependency_editor.cpp -#, fuzzy msgid "" "The files being removed are required by other resources in order for them to " "work.\n" @@ -1139,7 +1143,9 @@ msgid "" msgstr "" "Os arquivos sendo removidos são requeridos por outros recursos para que " "funcionem.\n" -"Removê-los mesmo assim? (irreversÃvel)" +"Removê-los mesmo assim? (irreversÃvel)\n" +"Você pode encontrar os arquivos removidos na lixeira e restaurá-los caso " +"necessário." #: editor/dependency_editor.cpp msgid "Cannot remove:" @@ -1167,7 +1173,7 @@ msgstr "Consertar Dependências" #: editor/dependency_editor.cpp msgid "Errors loading!" -msgstr "Erros ao carregar!" +msgstr "Erro ao carregar!" #: editor/dependency_editor.cpp msgid "Permanently delete %d item(s)? (No undo!)" @@ -1183,7 +1189,7 @@ msgstr "Explorador de Recursos Órfãos" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -1692,35 +1698,33 @@ msgstr "" "Fallback Enabled' (Recuperação de driver ativada)." #: editor/editor_export.cpp -#, fuzzy msgid "" "Target platform requires 'PVRTC' texture compression for GLES2. Enable " "'Import Pvrtc' in Project Settings." msgstr "" -"A plataforma alvo requer compressão de texturas 'ETC' para GLES2. Habilite " -"'Import Etc' nas Configurações de Projeto." +"A plataforma alvo requer compressão de texturas 'PVRTC' para GLES2. Habilite " +"'Importar Pvrtc' nas Configurações de Projeto." #: editor/editor_export.cpp -#, fuzzy msgid "" "Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. " "Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings." msgstr "" -"A plataforma de destino requer compactação de textura 'ETC2' para GLES3. " -"Ativar 'Importar Etc 2' nas Configurações do Projeto." +"A plataforma de destino requer compactação de textura 'ETC2' ou 'PVRTC' para " +"GLES3. Ativar 'Importar Etc 2' ou 'Importar Pvrtc' nas Configurações do " +"Projeto." #: editor/editor_export.cpp -#, fuzzy msgid "" "Target platform requires 'PVRTC' texture compression for the driver fallback " "to GLES2.\n" "Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback " "Enabled'." msgstr "" -"A plataforma de destino requer compactação de textura 'ETC' para o driver " +"A plataforma de destino requer compressão de textura 'PVRTC' para o driver " "retornar ao GLES2.\n" -"Ativar 'Importar Etc' em Configurações do Projeto ou desabilitar 'Driver " -"Fallback Enabled' (Recuperação de driver ativada)." +"Habilite 'Importar Pvrtc' em Configurações do Projeto ou desabilite 'Driver " +"Reserva Ativado'." #: editor/editor_export.cpp platform/android/export/export.cpp #: platform/iphone/export/export.cpp platform/javascript/export/export.cpp @@ -2405,6 +2409,8 @@ msgid "" "An error occurred while trying to save the editor layout.\n" "Make sure the editor's user data path is writable." msgstr "" +"Ocorreu um erro ao tentar salvar o layout do editor.\n" +"Certifique-se de que o caminho de dados do usuário do editor seja gravável." #: editor/editor_node.cpp msgid "" @@ -2412,15 +2418,17 @@ msgid "" "To restore the Default layout to its base settings, use the Delete Layout " "option and delete the Default layout." msgstr "" +"Layout do editor padrão substituÃdo.\n" +"Para restaurar o layout padrão para suas configurações básicas, use a opção " +"Excluir layout e exclua o layout padrão." #: editor/editor_node.cpp msgid "Layout name not found!" msgstr "Nome do layout não encontrado!" #: editor/editor_node.cpp -#, fuzzy msgid "Restored the Default layout to its base settings." -msgstr "Layout padrão restaurado à s configurações base." +msgstr "Layout padrão restaurado à s configurações básicas." #: editor/editor_node.cpp msgid "" @@ -3802,6 +3810,16 @@ msgid "Name contains invalid characters." msgstr "Nome contém caracteres inválidos." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Renomear arquivo:" @@ -3849,24 +3867,11 @@ msgstr "Editar Dependências..." msgid "View Owners..." msgstr "Visualizar Proprietários..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Renomear..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Duplicar..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Mover Para..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Mover Autoload" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nova Cena..." @@ -3889,11 +3894,16 @@ msgid "Collapse All" msgstr "Recolher Tudo" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Renomear" +msgid "Duplicate..." +msgstr "Duplicar..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Mover para o Lixo" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Renomear..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3928,8 +3938,11 @@ msgid "Move" msgstr "Mover" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Já há uma pasta ou arquivo neste caminho com o nome especificado." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Renomear" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -5333,50 +5346,43 @@ msgstr "Criar Guias Horizontais e Verticais" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)" -msgstr "" +msgstr "Definir Deslocamento do Pivô do CanvasItem \"%s\" para (%d, %d)" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Rotate %d CanvasItems" -msgstr "Rotacionar CanvasItem" +msgstr "Rotacionar %d CanvasItem" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Rotate CanvasItem \"%s\" to %d degrees" -msgstr "Rotacionar CanvasItem" +msgstr "Rotacionar CanvasItem \"%s\" para %d graus" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Move CanvasItem \"%s\" Anchor" -msgstr "Mover CanvaItem" +msgstr "Mover Âncora do CanvaItem \"%s\"" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Scale Node2D \"%s\" to (%s, %s)" -msgstr "" +msgstr "Dimensionar Node2D \"%s\" para (%s, %s)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Resize Control \"%s\" to (%d, %d)" -msgstr "" +msgstr "Redimensinar Controle \"%s\" para (%d, %d)" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Scale %d CanvasItems" -msgstr "Tamanho CanvasItem" +msgstr "Dimensionar %d CanvasItem" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Scale CanvasItem \"%s\" to (%s, %s)" -msgstr "Tamanho CanvasItem" +msgstr "Redimensionar CanvasItem \"%s\" para (%s, %s)" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Move %d CanvasItems" -msgstr "Mover CanvaItem" +msgstr "Mover %d CanvaItem" #: editor/plugins/canvas_item_editor_plugin.cpp -#, fuzzy msgid "Move CanvasItem \"%s\" to (%d, %d)" -msgstr "Mover CanvaItem" +msgstr "Mover CanvaItem \"%s\" para (%d, %d)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" @@ -6657,18 +6663,16 @@ msgid "Move Points" msgstr "Mover pontos" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Command: Rotate" -msgstr "Arrastar: Rotacionar" +msgstr "Command: Rotacionar" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Shift: Move All" msgstr "Shift: Mover Todos" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Shift+Command: Scale" -msgstr "Shift+Ctrl: Escala" +msgstr "Shift+Command: Redimensionar" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Ctrl: Rotate" @@ -6717,14 +6721,12 @@ msgid "Radius:" msgstr "Raio:" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Copy Polygon to UV" -msgstr "Criar PolÃgono & UV" +msgstr "Copiar PolÃgono para UV" #: editor/plugins/polygon_2d_editor_plugin.cpp -#, fuzzy msgid "Copy UV to Polygon" -msgstr "Converter para PolÃgono2D" +msgstr "Copiar UV para PolÃgono" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Clear UV" @@ -8269,13 +8271,12 @@ msgid "Paint Tile" msgstr "Pintar Tile" #: editor/plugins/tile_map_editor_plugin.cpp -#, fuzzy msgid "" "Shift+LMB: Line Draw\n" "Shift+Command+LMB: Rectangle Paint" msgstr "" "Shift+LMB: Desenhar Linha\n" -"Shift+Ctrl+LMB: Pintar Retângulo" +"Shift+Command+LMB: Pintar Retângulo" #: editor/plugins/tile_map_editor_plugin.cpp msgid "" @@ -8287,7 +8288,7 @@ msgstr "" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Pick Tile" -msgstr "Pegar Tile" +msgstr "Escolher Tile" #: editor/plugins/tile_map_editor_plugin.cpp msgid "Rotate Left" @@ -8430,23 +8431,20 @@ msgid "Create a new rectangle." msgstr "Criar um novo retângulo." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Pintura Retângular" +msgstr "Novo Retângulo" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Criar um novo polÃgono." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "Mover PolÃgono" +msgstr "Novo PolÃgono" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Excluir Selecionados" +msgstr "Excluir Formas Selecionados" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -8815,9 +8813,8 @@ msgid "Add Node to Visual Shader" msgstr "Adicionar Nó ao Visual Shader" #: editor/plugins/visual_shader_editor_plugin.cpp -#, fuzzy msgid "Node(s) Moved" -msgstr "Nó Movido" +msgstr "Node(s) Movidos" #: editor/plugins/visual_shader_editor_plugin.cpp msgid "Duplicate Nodes" @@ -9554,8 +9551,9 @@ msgstr "" "uniformes e constantes." #: editor/plugins/visual_shader_editor_plugin.cpp +#, fuzzy msgid "A reference to an existing uniform." -msgstr "" +msgstr "Uma referência a um uniforme existente." #: editor/plugins/visual_shader_editor_plugin.cpp msgid "(Fragment/Light mode only) Scalar derivative function." @@ -9922,6 +9920,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12497,6 +12499,26 @@ msgstr "" "A animação CPUParticles2D requer o uso de um CanvasItemMaterial com " "\"Animação de partÃculas\" ativada." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12825,6 +12847,26 @@ msgstr "" "sobrescritas pelo motor de fÃsica ao executar.\n" "Ao invés disso, altere o tamanho nas formas de colisão filhas." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13068,6 +13110,9 @@ msgstr "Variáveis só podem ser atribuÃdas na função de vértice." msgid "Constants cannot be modified." msgstr "Constantes não podem serem modificadas." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Já há uma pasta ou arquivo neste caminho com o nome especificado." + #~ msgid "Error trying to save layout!" #~ msgstr "Erro ao salvar o layout!" diff --git a/editor/translations/ro.po b/editor/translations/ro.po index a36099f15d..95bca8b085 100644 --- a/editor/translations/ro.po +++ b/editor/translations/ro.po @@ -1102,7 +1102,7 @@ msgstr "Explorator de Resurse Orfane" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3707,6 +3707,16 @@ msgid "Name contains invalid characters." msgstr "Numele furnizat conÈ›ine caractere nevalide." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Redenumind fiÈ™ierul:" @@ -3754,24 +3764,11 @@ msgstr "Editează DependinÈ›ele..." msgid "View Owners..." msgstr "Vizualizează Proprietarii..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "RedenumeÈ™te..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "DuplicaÈ›i..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Mută ÃŽn..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "MutaÈ›i Autoload" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Scenă nouă..." @@ -3794,11 +3791,17 @@ msgid "Collapse All" msgstr "ReduceÈ›i Toate" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "RedenumeÈ™te" +msgid "Duplicate..." +msgstr "DuplicaÈ›i..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "MutaÈ›i Autoload" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "RedenumeÈ™te..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3833,8 +3836,11 @@ msgid "Move" msgstr "Mută" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Există deja un fiÈ™ier sau un dosar cu acelaÈ™i nume în această locaÈ›ie." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "RedenumeÈ™te" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9899,6 +9905,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12401,6 +12411,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12661,6 +12691,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12866,6 +12916,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "" +#~ "Există deja un fiÈ™ier sau un dosar cu acelaÈ™i nume în această locaÈ›ie." + #~ msgid "Error trying to save layout!" #~ msgstr "Eroare la încercarea de a salva schema!" diff --git a/editor/translations/ru.po b/editor/translations/ru.po index 1ed11041e2..7a6d423212 100644 --- a/editor/translations/ru.po +++ b/editor/translations/ru.po @@ -88,11 +88,12 @@ # NeoLan Qu <it.bulla@mail.ru>, 2020. # Nikita Epifanov <nikgreens@protonmail.com>, 2020. # Cube Show <griiv.06@gmail.com>, 2020. +# Roman Tolkachyov <roman@tolkachyov.name>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-20 23:08+0000\n" +"PO-Revision-Date: 2020-12-01 20:29+0000\n" "Last-Translator: Danil Alexeev <danil@alexeev.xyz>\n" "Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/" "godot/ru/>\n" @@ -1172,7 +1173,7 @@ msgstr "Обзор подключённых реÑурÑов" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3786,6 +3787,16 @@ msgid "Name contains invalid characters." msgstr "Ð˜Ð¼Ñ Ñодержит недопуÑтимые Ñимволы." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Переименование файла:" @@ -3833,23 +3844,11 @@ msgstr "Редактировать завиÑимоÑти..." msgid "View Owners..." msgstr "ПроÑмотреть владельцев..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Переименовать..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Дублировать..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "ПеремеÑтить в..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "Удалить в Корзину" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "ÐÐ¾Ð²Ð°Ñ Ñцена..." @@ -3872,11 +3871,16 @@ msgid "Collapse All" msgstr "Свернуть вÑе" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Переименовать" +msgid "Duplicate..." +msgstr "Дублировать..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Удалить в Корзину" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Переименовать..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3911,8 +3915,11 @@ msgid "Move" msgstr "ПеремеÑтить" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "По Ñтому пути уже ÑущеÑтвует файл или папка Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ именем." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Переименовать" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8395,23 +8402,20 @@ msgid "Create a new rectangle." msgstr "Создать новый прÑмоугольник." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "ПрÑÐ¼Ð¾ÑƒÐ³Ð¾Ð»ÑŒÐ½Ð°Ñ Ð¿Ð¾ÐºÑ€Ð°Ñка" +msgstr "Ðовый прÑмоугольник" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Создать новый полигон." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "Передвинуть полигон" +msgstr "Ðовый полигон" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Удалить выделенное" +msgstr "Удалить выбранную форму" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9886,6 +9890,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12459,6 +12467,26 @@ msgstr "" "ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ CPUParticles2D требует иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ CanvasItemMaterial Ñ " "включённой опцией «Particles Animation»." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12785,6 +12813,26 @@ msgstr "" "переопределены движком при запуÑке.\n" "Измените размер дочерней формы коллизии." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13027,6 +13075,9 @@ msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ быть назначены только Ð msgid "Constants cannot be modified." msgstr "КонÑтанты не могут быть изменены." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "По Ñтому пути уже ÑущеÑтвует файл или папка Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ именем." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "Ð”Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Â«build-tools» отÑутÑтвует!" diff --git a/editor/translations/si.po b/editor/translations/si.po index 5afc820f33..e1675c412f 100644 --- a/editor/translations/si.po +++ b/editor/translations/si.po @@ -1077,7 +1077,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3556,6 +3556,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3603,23 +3613,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3642,10 +3640,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3679,7 +3682,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9503,6 +9509,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11933,6 +11943,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12193,6 +12223,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/sk.po b/editor/translations/sk.po index bfffcb5afc..db612cbd65 100644 --- a/editor/translations/sk.po +++ b/editor/translations/sk.po @@ -1086,7 +1086,7 @@ msgstr "Orphan Resource Explorer" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3691,6 +3691,16 @@ msgid "Name contains invalid characters." msgstr "Meno obsahuje neplatné pÃsmená." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Zostávajúce súbory:" @@ -3738,24 +3748,11 @@ msgstr "EditovaÅ¥ Závislosti..." msgid "View Owners..." msgstr "ZobraziÅ¥ Majiteľov..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "PremenovaÅ¥..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "DuplikovaÅ¥..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Presunúť Do..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "Presunúť AutoLoad-y" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Nová Scéna..." @@ -3778,11 +3775,17 @@ msgid "Collapse All" msgstr "Collapse All" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "PremenovaÅ¥" +msgid "Duplicate..." +msgstr "DuplikovaÅ¥..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Presunúť AutoLoad-y" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "PremenovaÅ¥..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3817,8 +3820,11 @@ msgid "Move" msgstr "Presunúť" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Už tu je súbor alebo prieÄinok pomenovaný rovnako." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "PremenovaÅ¥" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9801,6 +9807,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12302,6 +12312,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp #, fuzzy msgid "" @@ -12571,6 +12601,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12776,6 +12826,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Už tu je súbor alebo prieÄinok pomenovaný rovnako." + #~ msgid "Error trying to save layout!" #~ msgstr "Error pri ukladanà layout-i!" diff --git a/editor/translations/sl.po b/editor/translations/sl.po index 8e123095e3..0326de6a9f 100644 --- a/editor/translations/sl.po +++ b/editor/translations/sl.po @@ -1144,7 +1144,7 @@ msgstr "Raziskovalec Osamljenih Virov" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3829,6 +3829,16 @@ msgid "Name contains invalid characters." msgstr "Ime vsebuje neveljavne znake." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Preimenovanje Datoteke:" @@ -3881,25 +3891,12 @@ msgstr "Uredi Odvisnosti..." msgid "View Owners..." msgstr "Poglej Lastnike..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Preimenuj..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Podvoji..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Premakni V..." #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Premakni SamodejnoNalaganje" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "Nov Prizor" @@ -3926,11 +3923,17 @@ msgid "Collapse All" msgstr "SkrÄi vse" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Preimenuj" +msgid "Duplicate..." +msgstr "Podvoji..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Premakni SamodejnoNalaganje" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Preimenuj..." #: editor/filesystem_dock.cpp #, fuzzy @@ -3969,9 +3972,11 @@ msgid "Move" msgstr "Premakni" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "There is already file or folder with the same name in this location." -msgstr "Datoteka ali mapa s tem imenom že obstaja." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Preimenuj" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -10140,6 +10145,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12698,6 +12707,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12963,6 +12992,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13181,6 +13230,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Konstante ni možno spreminjati." +#, fuzzy +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Datoteka ali mapa s tem imenom že obstaja." + #~ msgid "Error trying to save layout!" #~ msgstr "Napaka pri shranjevanju postavitev!" diff --git a/editor/translations/sq.po b/editor/translations/sq.po index 4cd813a759..434fd72854 100644 --- a/editor/translations/sq.po +++ b/editor/translations/sq.po @@ -1086,7 +1086,7 @@ msgstr "Eksploruesi I Resurseve Pa Zotërues" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3769,6 +3769,16 @@ msgid "Name contains invalid characters." msgstr "Emri permban karaktere të pasakta." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Duke riemërtuar skedarin:" @@ -3821,25 +3831,12 @@ msgstr "Modifiko Varësitë..." msgid "View Owners..." msgstr "Shiko Pronarët..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Riemërto..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Dyfisho..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Lëviz në..." #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Lëviz Autoload-in" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "Skenë e Re" @@ -3862,11 +3859,17 @@ msgid "Collapse All" msgstr "Mbyll të Gjitha" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Riemërto" +msgid "Duplicate..." +msgstr "Dyfisho..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Lëviz Autoload-in" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Riemërto..." #: editor/filesystem_dock.cpp #, fuzzy @@ -3904,10 +3907,11 @@ msgid "Move" msgstr "Lëviz" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "" -"Ekziston që më parë një skedar ose folder me të njëjtin emër në këtë " -"vendndodhje." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Riemërto" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9798,6 +9802,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12279,6 +12287,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12539,6 +12567,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12741,6 +12789,11 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "" +#~ "Ekziston që më parë një skedar ose folder me të njëjtin emër në këtë " +#~ "vendndodhje." + #~ msgid "Error trying to save layout!" #~ msgstr "Gabim duke provuar të ruaj faqosjen!" diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po index b941a7097c..d5b4d28f95 100644 --- a/editor/translations/sr_Cyrl.po +++ b/editor/translations/sr_Cyrl.po @@ -1200,7 +1200,7 @@ msgstr "Преглед повезаних реÑурÑа" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -4021,6 +4021,16 @@ msgid "Name contains invalid characters." msgstr "Дато име Ñадржи неважећа Ñлова." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Преименовање датотеке:" @@ -4075,26 +4085,12 @@ msgstr "Измени завиÑноÑти..." msgid "View Owners..." msgstr "Погледај влаÑнике..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Преименуј..." - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "Дуплирај" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Помери у..." #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Помери аутоматÑко учитавање" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "Ðова Ñцена" @@ -4121,11 +4117,18 @@ msgid "Collapse All" msgstr "Умањи Ñве" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Преименуј" +#, fuzzy +msgid "Duplicate..." +msgstr "Дуплирај" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Помери аутоматÑко учитавање" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Преименуј..." #: editor/filesystem_dock.cpp #, fuzzy @@ -4164,9 +4167,11 @@ msgid "Move" msgstr "Помери" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "There is already file or folder with the same name in this location." -msgstr "Датотека или директоријум Ñа овим именом већ поÑтоји." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Преименуј" #: editor/filesystem_dock.cpp #, fuzzy @@ -10925,6 +10930,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp #, fuzzy msgid "" "Higher visual quality\n" @@ -13947,6 +13956,26 @@ msgstr "" "ПроцеÑорЧеÑтице2Д анимација захтева коришћење ПлатноПредметМатеријала Ñа " "омогућеном \"Ðнимациом ЧеÑтица\"." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp #, fuzzy msgid "" @@ -14315,6 +14344,26 @@ msgstr "" "Промена величине у ТврдомТелу (у карактеру или трвдом моду) ће бити " "препиÑана од Ñтране физичког мотора у раду." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp #, fuzzy msgid "" @@ -14593,6 +14642,10 @@ msgstr "Варијације могу Ñамо бити одређене у фу msgid "Constants cannot be modified." msgstr "КонÑтанте није могуће мењати." +#, fuzzy +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Датотека или директоријум Ñа овим именом већ поÑтоји." + #~ msgid "Error trying to save layout!" #~ msgstr "Грешка при чувању раÑпореда!" diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po index db169729e3..3343da96fc 100644 --- a/editor/translations/sr_Latn.po +++ b/editor/translations/sr_Latn.po @@ -1086,7 +1086,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3573,6 +3573,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3620,23 +3630,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3659,10 +3657,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3696,7 +3699,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9581,6 +9587,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12024,6 +12034,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12284,6 +12314,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/sv.po b/editor/translations/sv.po index 3d2eea1ceb..faab1ec8ed 100644 --- a/editor/translations/sv.po +++ b/editor/translations/sv.po @@ -1104,7 +1104,7 @@ msgstr "Föräldralös Resursutforskare" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3768,6 +3768,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Byter namn pÃ¥ filen:" @@ -3823,16 +3833,6 @@ msgstr "" msgid "View Owners..." msgstr "Visa Ägare..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -#, fuzzy -msgid "Rename..." -msgstr "Byt namn..." - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "Duplicera" - #: editor/filesystem_dock.cpp #, fuzzy msgid "Move To..." @@ -3840,11 +3840,6 @@ msgstr "Flytta Till..." #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Flytta Autoload" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "Ny Scen" @@ -3871,11 +3866,19 @@ msgid "Collapse All" msgstr "Stäng Alla" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Byt namn" +#, fuzzy +msgid "Duplicate..." +msgstr "Duplicera" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Flytta Autoload" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +#, fuzzy +msgid "Rename..." +msgstr "Byt namn..." #: editor/filesystem_dock.cpp #, fuzzy @@ -3912,9 +3915,11 @@ msgid "Move" msgstr "Flytta" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "There is already file or folder with the same name in this location." -msgstr "En fil eller mapp med detta namn finns redan." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Byt namn" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -10021,6 +10026,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12577,6 +12586,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12856,6 +12885,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp #, fuzzy msgid "" @@ -13067,6 +13116,10 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#, fuzzy +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "En fil eller mapp med detta namn finns redan." + #~ msgid "Error trying to save layout!" #~ msgstr "Fel vid försök att spara layout!" diff --git a/editor/translations/ta.po b/editor/translations/ta.po index 4a056fc781..c89be893b8 100644 --- a/editor/translations/ta.po +++ b/editor/translations/ta.po @@ -1082,7 +1082,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3563,6 +3563,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3610,25 +3620,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -#, fuzzy -msgid "Duplicate..." -msgstr "அசைவூடà¯à®Ÿà¯ போலிபசà¯à®šà®¾à®µà®¿à®•ளà¯" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "சேர௠மà¯à®•à¯à®•ியபà¯à®ªà¯à®³à¯à®³à®¿à®¯à¯ˆ நகரà¯à®¤à¯à®¤à¯" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3651,10 +3647,17 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +#, fuzzy +msgid "Duplicate..." +msgstr "அசைவூடà¯à®Ÿà¯ போலிபசà¯à®šà®¾à®µà®¿à®•ளà¯" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "சேர௠மà¯à®•à¯à®•ியபà¯à®ªà¯à®³à¯à®³à®¿à®¯à¯ˆ நகரà¯à®¤à¯à®¤à¯" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3688,7 +3691,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9503,6 +9509,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11933,6 +11943,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12193,6 +12223,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/te.po b/editor/translations/te.po index 8d186752d1..806a6bb133 100644 --- a/editor/translations/te.po +++ b/editor/translations/te.po @@ -1057,7 +1057,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3533,6 +3533,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3580,23 +3590,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3619,10 +3617,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3656,7 +3659,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9429,6 +9435,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11842,6 +11852,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12102,6 +12132,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/th.po b/editor/translations/th.po index 60db227d35..1a36ecf42b 100644 --- a/editor/translations/th.po +++ b/editor/translations/th.po @@ -7,12 +7,13 @@ # Thanachart Monpassorn <nunf_2539@hotmail.com>, 2020. # Anonymous <noreply@weblate.org>, 2020. # Lon3r <mptube.p@gmail.com>, 2020. +# Kongfa Warorot <gongpha@hotmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-20 23:08+0000\n" -"Last-Translator: Thanachart Monpassorn <nunf_2539@hotmail.com>\n" +"PO-Revision-Date: 2020-12-01 20:29+0000\n" +"Last-Translator: Kongfa Warorot <gongpha@hotmail.com>\n" "Language-Team: Thai <https://hosted.weblate.org/projects/godot-engine/godot/" "th/>\n" "Language: th\n" @@ -1080,7 +1081,7 @@ msgstr "ทรัพยาà¸à¸£à¸—ี่ไม่ได้ใช้" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -1171,7 +1172,7 @@ msgstr "ผู้บริจาค" #: editor/editor_about.cpp msgid "License" -msgstr "สัà¸à¸à¸²à¸à¸™à¸¸à¸à¸²à¸•" +msgstr "ลิขสิทธิ์" #: editor/editor_about.cpp msgid "Third-party Licenses" @@ -3634,6 +3635,16 @@ msgid "Name contains invalid characters." msgstr "à¸à¸±à¸à¸©à¸£à¸šà¸²à¸‡à¸•ัวใช้ไม่ได้" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "เปลี่ยนชื่à¸à¹„ฟล์:" @@ -3681,23 +3692,11 @@ msgstr "à¹à¸à¹‰à¹„ขà¸à¸²à¸£à¸à¹‰à¸²à¸‡à¸à¸´à¸‡..." msgid "View Owners..." msgstr "ดูเจ้าขà¸à¸‡..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "เปลี่ยนชื่à¸..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "ทำซ้ำ..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "ย้ายไป..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "ย้ายไปถังขยะ" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "ฉาà¸à¹ƒà¸«à¸¡à¹ˆ..." @@ -3720,11 +3719,16 @@ msgid "Collapse All" msgstr "ยุบเข้า" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "เปลี่ยนชื่à¸" +msgid "Duplicate..." +msgstr "ทำซ้ำ..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "ย้ายไปถังขยะ" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "เปลี่ยนชื่à¸..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3759,8 +3763,11 @@ msgid "Move" msgstr "ย้าย" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "มีไฟล์หรืà¸à¹‚ฟลเดà¸à¸£à¹Œà¸Šà¸·à¹ˆà¸à¹€à¸”ียวà¸à¸±à¸™à¸à¸¢à¸¹à¹ˆà¹à¸¥à¹‰à¸§" +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "เปลี่ยนชื่à¸" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -7173,7 +7180,7 @@ msgstr "à¹à¸—รà¸à¸„ีย์à¹à¸à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™" #: editor/plugins/spatial_editor_plugin.cpp msgid "Pitch" -msgstr "เสียงสูงต่ำ" +msgstr "Pitch" #: editor/plugins/spatial_editor_plugin.cpp msgid "Yaw" @@ -8201,23 +8208,20 @@ msgid "Create a new rectangle." msgstr "สร้างสี่เหลี่ยมใหม่" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "วาดสี่เหลี่ยม" +msgstr "สี่เหลี่ยมใหม่" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "สร้างรูปหลายเหลี่ยมใหม่" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "ย้ายรูปหลายเหลี่ยม" +msgstr "รูปหลายเหลี่ยมใหม่" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "ลบสิ่งที่เลืà¸à¸" +msgstr "ลบรูปร่างที่เลืà¸à¸" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9654,6 +9658,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12161,6 +12169,26 @@ msgstr "" "à¹à¸à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™ CPUParticles2D จำเป็นต้à¸à¸‡à¹ƒà¸Šà¹‰ CanvasItemMaterial โดยเปิดà¸à¸²à¸£à¸—ำงาน " "\"Particles Animation\"" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12455,6 +12483,26 @@ msgstr "" "จะถูà¸à¹à¸—นที่โดยเà¸à¹‡à¸™à¸ˆà¸´à¹‰à¸™à¸Ÿà¸´à¸ªà¸´à¸à¸ªà¹Œà¹€à¸¡à¸·à¹ˆà¸à¸—ำงาน\n" "เปลี่ยนขนาดในขà¸à¸šà¹€à¸‚ตà¸à¸²à¸£à¸Šà¸™à¸¥à¸¹à¸à¹à¸—น" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12681,6 +12729,9 @@ msgstr "Varyings สามารถà¸à¸³à¸«à¸™à¸”ในังà¸à¹Œà¸Šà¸±à¸™à¹€ msgid "Constants cannot be modified." msgstr "ค่าคงที่ไม่สามารถà¹à¸à¹‰à¹„ขได้" +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "มีไฟล์หรืà¸à¹‚ฟลเดà¸à¸£à¹Œà¸Šà¸·à¹ˆà¸à¹€à¸”ียวà¸à¸±à¸™à¸à¸¢à¸¹à¹ˆà¹à¸¥à¹‰à¸§" + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "ไดเร็à¸à¸—à¸à¸£à¸µ 'build-tools' หายไป!" diff --git a/editor/translations/tr.po b/editor/translations/tr.po index 61eb8819f9..0d0c2ff2ee 100644 --- a/editor/translations/tr.po +++ b/editor/translations/tr.po @@ -59,7 +59,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-25 14:10+0000\n" +"PO-Revision-Date: 2020-11-29 08:29+0000\n" "Last-Translator: Zsosu Ktosu <zktosu@gmail.com>\n" "Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/" "godot/tr/>\n" @@ -1140,7 +1140,7 @@ msgstr "Orphan Kaynak AraÅŸtırıcı" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -2150,7 +2150,7 @@ msgstr "Metot" #: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp msgid "Signal" -msgstr "Sinyaller" +msgstr "Sinyal" #: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp msgid "Constant" @@ -3753,6 +3753,16 @@ msgid "Name contains invalid characters." msgstr "İsim geçersiz karkterler içeriyor." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Dosya yeniden-adlandırma:" @@ -3800,23 +3810,11 @@ msgstr "Bağımlılıkları Düzenle..." msgid "View Owners..." msgstr "Sahipleri Görüntüle..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Yeniden Adlandır..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "ÇoÄŸalt..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Åžuraya Taşı..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "Çöpe At" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Yeni Sahne..." @@ -3839,11 +3837,16 @@ msgid "Collapse All" msgstr "Hepsini Daralt" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Yeniden Adlandır" +msgid "Duplicate..." +msgstr "ÇoÄŸalt..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "Çöpe At" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Yeniden Adlandır..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3878,8 +3881,11 @@ msgid "Move" msgstr "Taşı" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Bu konumda zaten aynı ada sahip bir dosya veya klasör var." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Yeniden Adlandır" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8361,23 +8367,20 @@ msgid "Create a new rectangle." msgstr "Yeni dikdörtgen oluÅŸtur." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Dikdörtgen Boya" +msgstr "Dolu Dikdörtgen" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Yeni bir çokgen oluÅŸturun." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "Çokgeni Taşı" +msgstr "Yeni Çokgen" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Seçilenleri Sil" +msgstr "Seçilen Åžekli Sil" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9849,6 +9852,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12415,6 +12422,26 @@ msgstr "" "CPUParçacık2B animasyonu \"Parçacık Animasyonu\" seçimi etkin olarak " "CanvasÖgesiMalzemesi kullanımı gerektirir." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12746,6 +12773,26 @@ msgstr "" "çalıştığında geçersiz kılınacak.\n" "Boyu deÄŸiÅŸikliÄŸini bunun yerine çocuk çarpışma ÅŸekilleri içinden yapın." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12988,6 +13035,9 @@ msgstr "varyings yalnızca vertex iÅŸlevinde atanabilir." msgid "Constants cannot be modified." msgstr "Sabit deÄŸerler deÄŸiÅŸtirilemez." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Bu konumda zaten aynı ada sahip bir dosya veya klasör var." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "Eksik 'inÅŸa-araçları' dizini!" diff --git a/editor/translations/tzm.po b/editor/translations/tzm.po index 6d0b1ff421..b9c48c5b34 100644 --- a/editor/translations/tzm.po +++ b/editor/translations/tzm.po @@ -1055,7 +1055,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3531,6 +3531,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3578,23 +3588,11 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "" @@ -3617,10 +3615,15 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3654,7 +3657,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9426,6 +9432,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -11839,6 +11849,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12099,6 +12129,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/uk.po b/editor/translations/uk.po index 19d0cee9a7..dd03dac3cf 100644 --- a/editor/translations/uk.po +++ b/editor/translations/uk.po @@ -20,8 +20,8 @@ msgid "" msgstr "" "Project-Id-Version: Ukrainian (Godot Engine)\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-23 21:42+0000\n" -"Last-Translator: Miroslav <zinmirx@gmail.com>\n" +"PO-Revision-Date: 2020-11-29 08:29+0000\n" +"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n" "Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/" "godot/uk/>\n" "Language: uk\n" @@ -1109,7 +1109,7 @@ msgstr "ОглÑд підключених реÑурÑів" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3730,6 +3730,16 @@ msgid "Name contains invalid characters." msgstr "Ðазва міÑтить некоректні Ñимволи." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "ÐŸÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ:" @@ -3777,23 +3787,11 @@ msgstr "Редагувати залежноÑті..." msgid "View Owners..." msgstr "ПереглÑнути влаÑників..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Перейменувати..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Дублювати..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "ПереміÑтити до..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "ПереÑунути до Ñмітника" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "Створити Ñцену…" @@ -3816,11 +3814,16 @@ msgid "Collapse All" msgstr "Згорнути вÑе" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Перейменувати" +msgid "Duplicate..." +msgstr "Дублювати..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "ПереÑунути до Ñмітника" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Перейменувати..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3855,8 +3858,11 @@ msgid "Move" msgstr "ПереміÑтити" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "У вказаному каталозі вже міÑтитьÑÑ Ñ‚ÐµÐºÐ° або файл із вказано назвою." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Перейменувати" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8349,23 +8355,20 @@ msgid "Create a new rectangle." msgstr "Створити прÑмокутник." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "Ðамалювати прÑмокутник" +msgstr "Ðовий прÑмокутник" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "Створити новий полігон." #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "ПереміÑтити полігон" +msgstr "Ðовий полігон" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "Вилучити вибране" +msgstr "Вилучити позначену форму" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9846,6 +9849,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12441,6 +12448,26 @@ msgstr "" "ÐÐ½Ñ–Ð¼Ð°Ñ†Ñ–Ñ CPUParticles2D потребує викориÑÑ‚Ð°Ð½Ð½Ñ CanvasItemMaterial із " "увімкненим параметром «ÐÐ½Ñ–Ð¼Ð°Ñ†Ñ–Ñ Ñ‡Ð°Ñток»." +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12774,6 +12801,26 @@ msgstr "" "фізичним рушієм під Ñ‡Ð°Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸.\n" "ЗаміÑть цієї зміни, вам варто змінити розміри дочірніх форм зіткненнÑ." +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13018,6 +13065,9 @@ msgstr "Змінні величини можна пов'Ñзувати лише msgid "Constants cannot be modified." msgstr "Сталі не можна змінювати." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "У вказаному каталозі вже міÑтитьÑÑ Ñ‚ÐµÐºÐ° або файл із вказано назвою." + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "Ðе знайдено каталогу «build-tools»!" diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po index 33902a4398..a87c4865c2 100644 --- a/editor/translations/ur_PK.po +++ b/editor/translations/ur_PK.po @@ -1075,7 +1075,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3597,6 +3597,16 @@ msgid "Name contains invalid characters." msgstr "" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "" @@ -3649,25 +3659,12 @@ msgstr "" msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "" - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "" - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "" #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "ایکشن منتقل کریں" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "سب سکریپشن بنائیں" @@ -3691,10 +3688,16 @@ msgid "Collapse All" msgstr "" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "ایکشن منتقل کریں" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." msgstr "" #: editor/filesystem_dock.cpp @@ -3728,7 +3731,10 @@ msgid "Move" msgstr "" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" msgstr "" #: editor/filesystem_dock.cpp @@ -9667,6 +9673,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12141,6 +12151,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12401,6 +12431,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" diff --git a/editor/translations/vi.po b/editor/translations/vi.po index 500ad127b4..f08207bd30 100644 --- a/editor/translations/vi.po +++ b/editor/translations/vi.po @@ -1100,7 +1100,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3702,6 +3702,16 @@ msgid "Name contains invalid characters." msgstr "Tên có chứa kà tá»± không hợp lệ." #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "Äổi tên tệp tin:" @@ -3750,25 +3760,12 @@ msgstr "Chỉnh sá»a các phần phụ thuá»™c..." msgid "View Owners..." msgstr "Xem các scene sở hữu..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "Äổi tên..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "Nhân đôi..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "Di chuyển đến..." #: editor/filesystem_dock.cpp #, fuzzy -msgid "Move to Trash" -msgstr "Di chuyển Nút" - -#: editor/filesystem_dock.cpp -#, fuzzy msgid "New Scene..." msgstr "Tạo Cảnh Má»›i" @@ -3791,11 +3788,17 @@ msgid "Collapse All" msgstr "Thu gá»n Tất cả" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "Äổi tên" +msgid "Duplicate..." +msgstr "Nhân đôi..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "Di chuyển Nút" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "Äổi tên..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3830,8 +3833,11 @@ msgid "Move" msgstr "Di chuyển" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "Äã có tệp tin hoặc thư mục cùng tên tại vị trà nà y." +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "Äổi tên" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -9839,6 +9845,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12390,6 +12400,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12650,6 +12680,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12861,6 +12911,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "Không thể chỉnh sá»a hằng số." +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "Äã có tệp tin hoặc thư mục cùng tên tại vị trà nà y." + #~ msgid "Error trying to save layout!" #~ msgstr "Lá»—i khi cố gắng lưu bố cục!" diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po index 3bf38ece6c..bd6c730382 100644 --- a/editor/translations/zh_CN.po +++ b/editor/translations/zh_CN.po @@ -72,11 +72,12 @@ # Gardner Belgrade <hapenia@sina.com>, 2020. # godhidden <z2zz2zz@yahoo.com>, 2020. # BinotaLIU <me@binota.org>, 2020. +# TakWolf <takwolf@foxmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: Chinese (Simplified) (Godot Engine)\n" "POT-Creation-Date: 2018-01-20 12:15+0200\n" -"PO-Revision-Date: 2020-11-20 23:08+0000\n" +"PO-Revision-Date: 2020-11-29 08:29+0000\n" "Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n" "Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/" "godot-engine/godot/zh_Hans/>\n" @@ -1144,7 +1145,7 @@ msgstr "å¤ç«‹èµ„æºæµè§ˆå™¨" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3689,6 +3690,16 @@ msgid "Name contains invalid characters." msgstr "åç§°åŒ…å«æ— 效å—符。" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "é‡å‘½å文件:" @@ -3736,23 +3747,11 @@ msgstr "编辑ä¾èµ–..." msgid "View Owners..." msgstr "查看所有者..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "é‡å‘½å为..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "é‡å¤..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "移动..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "移动至回收站" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "新建场景..." @@ -3775,11 +3774,16 @@ msgid "Collapse All" msgstr "全部折å " #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "é‡å‘½å" +msgid "Duplicate..." +msgstr "é‡å¤..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "移动至回收站" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "é‡å‘½å为..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3814,8 +3818,11 @@ msgid "Move" msgstr "移动" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "当å‰ä½ç½®å·²å˜åœ¨åŒå文件或文件夹。" +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "é‡å‘½å" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -7326,7 +7333,7 @@ msgstr "é”定视角旋转" #: editor/plugins/spatial_editor_plugin.cpp msgid "Display Normal" -msgstr "显示法线" +msgstr "æ˜¾ç¤ºæ ‡å‡†" #: editor/plugins/spatial_editor_plugin.cpp msgid "Display Wireframe" @@ -8254,23 +8261,20 @@ msgid "Create a new rectangle." msgstr "创建新矩形。" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "绘制矩形" +msgstr "新建矩形" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "创建新多边形。" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "移动多边形" +msgstr "新建多边形" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "åˆ é™¤é€‰ä¸é¡¹" +msgstr "åˆ é™¤æ‰€é€‰å½¢çŠ¶" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9700,6 +9704,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12201,6 +12209,26 @@ msgstr "" "CPUParticles2D 动画需è¦ä½¿ç”¨å¯ç”¨äº† “Particles Animation†的 " "CanvasItemMaterial。" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12497,6 +12525,26 @@ msgstr "" "的覆盖。\n" "建议您修改å节点的碰撞形状。" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12727,6 +12775,9 @@ msgstr "å˜é‡åªèƒ½åœ¨é¡¶ç‚¹å‡½æ•°ä¸æŒ‡å®šã€‚" msgid "Constants cannot be modified." msgstr "ä¸å…许修改常é‡ã€‚" +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "当å‰ä½ç½®å·²å˜åœ¨åŒå文件或文件夹。" + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "缺失“build-toolsâ€ç›®å½•ï¼" diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po index 5ed91fb436..b3faa76c3c 100644 --- a/editor/translations/zh_HK.po +++ b/editor/translations/zh_HK.po @@ -1128,7 +1128,7 @@ msgstr "" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3801,6 +3801,16 @@ msgid "Name contains invalid characters." msgstr "åå—嫿œ‰ç„¡æ•ˆå—符。" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "釿–°å‘½å檔案:" @@ -3853,26 +3863,12 @@ msgstr "編輯Dependencies..." msgid "View Owners..." msgstr "" -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -#, fuzzy -msgid "Rename..." -msgstr "釿–°å‘½å..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "å†è£½..." - #: editor/filesystem_dock.cpp #, fuzzy msgid "Move To..." msgstr "æ¬åˆ°..." #: editor/filesystem_dock.cpp -#, fuzzy -msgid "Move to Trash" -msgstr "移動Autoload" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "æ–°å¢žå ´æ™¯..." @@ -3895,11 +3891,18 @@ msgid "Collapse All" msgstr "全部折疊" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "釿–°å‘½å" +msgid "Duplicate..." +msgstr "å†è£½..." + +#: editor/filesystem_dock.cpp +#, fuzzy +msgid "Move to Trash" +msgstr "移動Autoload" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +#, fuzzy +msgid "Rename..." +msgstr "釿–°å‘½å..." #: editor/filesystem_dock.cpp #, fuzzy @@ -3937,8 +3940,11 @@ msgid "Move" msgstr "移動" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "æ¤ä½ç½®å·²å˜åœ¨åŒå的檔案或資料夾。" +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "釿–°å‘½å" #: editor/filesystem_dock.cpp #, fuzzy @@ -10089,6 +10095,10 @@ msgid "OpenGL ES 3.0" msgstr "" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12663,6 +12673,26 @@ msgid "" "\"Particles Animation\" enabled." msgstr "" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12923,6 +12953,26 @@ msgid "" "Change the size in children collision shapes instead." msgstr "" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -13131,6 +13181,9 @@ msgstr "" msgid "Constants cannot be modified." msgstr "" +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "æ¤ä½ç½®å·²å˜åœ¨åŒå的檔案或資料夾。" + #, fuzzy #~ msgid "Error trying to save layout!" #~ msgstr "儲å˜ä½ˆå±€æ™‚出ç¾éŒ¯èª¤ï¼" diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po index 1c9d2b77c1..dc3c1f49f7 100644 --- a/editor/translations/zh_TW.po +++ b/editor/translations/zh_TW.po @@ -29,7 +29,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-11-20 23:08+0000\n" +"PO-Revision-Date: 2020-12-07 08:11+0000\n" "Last-Translator: BinotaLIU <me@binota.org>\n" "Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/" "godot-engine/godot/zh_Hant/>\n" @@ -1097,7 +1097,7 @@ msgstr "å¤ç«‹è³‡æºç€è¦½å™¨" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp -#: editor/filesystem_dock.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp #: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp msgid "Delete" @@ -3644,6 +3644,16 @@ msgid "Name contains invalid characters." msgstr "å稱包å«ç„¡æ•ˆå—元。" #: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp msgid "Renaming file:" msgstr "釿–°å‘½å檔案:" @@ -3691,23 +3701,11 @@ msgstr "ç·¨è¼¯ç›¸ä¾æ€§..." msgid "View Owners..." msgstr "æª¢è¦–æ“æœ‰è€…..." -#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp -msgid "Rename..." -msgstr "釿–°å‘½å..." - -#: editor/filesystem_dock.cpp -msgid "Duplicate..." -msgstr "é‡è¤‡..." - #: editor/filesystem_dock.cpp msgid "Move To..." msgstr "移動至..." #: editor/filesystem_dock.cpp -msgid "Move to Trash" -msgstr "移動至資æºå›žæ”¶æ¡¶" - -#: editor/filesystem_dock.cpp msgid "New Scene..." msgstr "æ–°å¢žå ´æ™¯..." @@ -3730,11 +3728,16 @@ msgid "Collapse All" msgstr "æ”¶åˆå…¨éƒ¨" #: editor/filesystem_dock.cpp -#: editor/plugins/animation_tree_player_editor_plugin.cpp -#: editor/project_manager.cpp editor/rename_dialog.cpp -#: editor/scene_tree_dock.cpp -msgid "Rename" -msgstr "釿–°å‘½å" +msgid "Duplicate..." +msgstr "é‡è¤‡..." + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "移動至資æºå›žæ”¶æ¡¶" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "釿–°å‘½å..." #: editor/filesystem_dock.cpp msgid "Previous Folder/File" @@ -3769,8 +3772,11 @@ msgid "Move" msgstr "移動" #: editor/filesystem_dock.cpp -msgid "There is already file or folder with the same name in this location." -msgstr "該ä½ç½®å·²æœ‰ç›¸åŒå稱的檔案或資料夾。" +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "釿–°å‘½å" #: editor/filesystem_dock.cpp msgid "Overwrite" @@ -8210,23 +8216,20 @@ msgid "Create a new rectangle." msgstr "建立新矩形。" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Rectangle" -msgstr "矩形繪製" +msgstr "新增矩形" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Create a new polygon." msgstr "建立新多邊形。" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "New Polygon" -msgstr "移動多邊形" +msgstr "新增多邊形" #: editor/plugins/tile_set_editor_plugin.cpp -#, fuzzy msgid "Delete Selected Shape" -msgstr "刪除所é¸" +msgstr "刪除所é¸å½¢ç‹€" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Keep polygon inside region Rect." @@ -9656,6 +9659,10 @@ msgid "OpenGL ES 3.0" msgstr "OpenGL ES 3.0" #: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp msgid "" "Higher visual quality\n" "All features available\n" @@ -12162,6 +12169,26 @@ msgstr "" "CPUParticles2D 動畫需è¦ä½¿ç”¨æœ‰å•Ÿç”¨ã€ŒParticles Animation(粒å動畫)ã€çš„ " "CanvasItemMaterial。" +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + #: scene/2d/light_2d.cpp msgid "" "A texture with the shape of the light must be supplied to the \"Texture\" " @@ -12456,6 +12483,26 @@ msgstr "" "複寫。\n" "請改為修改其å節點的碰撞形狀之大å°ã€‚" +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + #: scene/3d/remote_transform.cpp msgid "" "The \"Remote Path\" property must point to a valid Spatial or Spatial-" @@ -12687,6 +12734,9 @@ msgstr "Varying 變數åªå¯åœ¨é ‚點函å¼ä¸æŒ‡æ´¾ã€‚" msgid "Constants cannot be modified." msgstr "ä¸å¯ä¿®æ”¹å¸¸æ•¸ã€‚" +#~ msgid "There is already file or folder with the same name in this location." +#~ msgstr "該ä½ç½®å·²æœ‰ç›¸åŒå稱的檔案或資料夾。" + #~ msgid "Missing 'build-tools' directory!" #~ msgstr "缺少「build-toolsã€è³‡æ–™å¤¾ï¼" @@ -1,6 +1,4 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" @@ -13,7 +11,7 @@ height="1024" id="svg3030" version="1.1" - inkscape:version="0.92.1 r15371" + inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" sodipodi:docname="icon.svg" inkscape:export-filename="/home/akien/Projects/godot/godot.git/icon.png" inkscape:export-xdpi="24" @@ -27,17 +25,18 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.35" - inkscape:cx="707.24666" - inkscape:cy="14.063809" + inkscape:zoom="0.8359375" + inkscape:cx="512" + inkscape:cy="512" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" - inkscape:window-width="1920" - inkscape:window-height="1011" - inkscape:window-x="0" - inkscape:window-y="0" - inkscape:window-maximized="1" /> + inkscape:window-width="1916" + inkscape:window-height="1025" + inkscape:window-x="1360" + inkscape:window-y="53" + inkscape:window-maximized="1" + inkscape:document-rotation="0" /> <metadata id="metadata3035"> <rdf:RDF> @@ -46,7 +45,7 @@ <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> + <dc:title></dc:title> </cc:Work> </rdf:RDF> </metadata> @@ -70,10 +69,11 @@ transform="matrix(4.162611,0,0,-4.162611,104.69892,525.90697)" style="stroke-width:0.32031175"> <path - d="m 0,0 v -47.514 -6.035 -5.492 c 0.108,-0.001 0.216,-0.005 0.323,-0.015 l 36.196,-3.49 c 1.896,-0.183 3.382,-1.709 3.514,-3.609 l 1.116,-15.978 31.574,-2.253 2.175,14.747 c 0.282,1.912 1.922,3.329 3.856,3.329 h 38.188 c 1.933,0 3.573,-1.417 3.855,-3.329 l 2.175,-14.747 31.575,2.253 1.115,15.978 c 0.133,1.9 1.618,3.425 3.514,3.609 l 36.182,3.49 c 0.107,0.01 0.214,0.014 0.322,0.015 v 4.711 l 0.015,0.005 V 0 h 0.134 c 4.795,6.12 9.232,12.569 13.487,19.449 -5.651,9.62 -12.575,18.217 -19.976,26.182 -6.864,-3.455 -13.531,-7.369 -19.828,-11.534 -3.151,3.132 -6.7,5.694 -10.186,8.372 -3.425,2.751 -7.285,4.768 -10.946,7.118 1.09,8.117 1.629,16.108 1.846,24.448 -9.446,4.754 -19.519,7.906 -29.708,10.17 -4.068,-6.837 -7.788,-14.241 -11.028,-21.479 -3.842,0.642 -7.702,0.88 -11.567,0.926 v 0.006 c -0.027,0 -0.052,-0.006 -0.075,-0.006 -0.024,0 -0.049,0.006 -0.073,0.006 V 63.652 C 93.903,63.606 90.046,63.368 86.203,62.726 82.965,69.964 79.247,77.368 75.173,84.205 64.989,81.941 54.915,78.789 45.47,74.035 45.686,65.695 46.225,57.704 47.318,49.587 43.65,47.237 39.795,45.22 36.369,42.469 32.888,39.791 29.333,37.229 26.181,34.097 19.884,38.262 13.219,42.176 6.353,45.631 -1.048,37.666 -7.968,29.069 -13.621,19.449 -9.368,12.569 -4.928,6.12 -0.134,0 Z" - style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32031175" + d="m 0,0 v -47.514 -6.035 -5.492 c 0.108,-0.001 0.216,-0.005 0.323,-0.015 l 36.196,-3.49 c 1.896,-0.183 3.382,-1.709 3.514,-3.609 l 1.116,-15.978 31.574,-2.253 2.175,14.747 c 0.282,1.912 1.922,3.329 3.856,3.329 h 38.188 c 1.933,0 3.573,-1.417 3.855,-3.329 l 2.175,-14.747 31.575,2.253 1.115,15.978 c 0.133,1.9 1.618,3.425 3.514,3.609 l 36.182,3.49 c 0.107,0.01 0.214,0.014 0.322,0.015 v 4.711 l 0.015,0.005 V 0 c 5.09692,6.4164715 9.92323,13.494208 13.621,19.449 -5.651,9.62 -12.575,18.217 -19.976,26.182 -6.864,-3.455 -13.531,-7.369 -19.828,-11.534 -3.151,3.132 -6.7,5.694 -10.186,8.372 -3.425,2.751 -7.285,4.768 -10.946,7.118 1.09,8.117 1.629,16.108 1.846,24.448 -9.446,4.754 -19.519,7.906 -29.708,10.17 -4.068,-6.837 -7.788,-14.241 -11.028,-21.479 -3.842,0.642 -7.702,0.88 -11.567,0.926 v 0.006 c -0.027,0 -0.052,-0.006 -0.075,-0.006 -0.024,0 -0.049,0.006 -0.073,0.006 V 63.652 C 93.903,63.606 90.046,63.368 86.203,62.726 82.965,69.964 79.247,77.368 75.173,84.205 64.989,81.941 54.915,78.789 45.47,74.035 45.686,65.695 46.225,57.704 47.318,49.587 43.65,47.237 39.795,45.22 36.369,42.469 32.888,39.791 29.333,37.229 26.181,34.097 19.884,38.262 13.219,42.176 6.353,45.631 -1.048,37.666 -7.968,29.069 -13.621,19.449 -9.1783421,12.475308 -4.4130298,5.4661124 0,0 Z" + style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312" id="path84-6" - inkscape:connector-curvature="0" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccccsssscccccccccccccccccccsccccccccccc" /> </g> <g id="g86-7" Binary files differ@@ -1,6 +1,4 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" @@ -11,7 +9,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg2" version="1.1" - inkscape:version="0.92.1 r15371" + inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" xml:space="preserve" width="1024" height="414" @@ -22,7 +20,7 @@ inkscape:export-ydpi="48"><metadata id="metadata8"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs id="defs6"><clipPath clipPathUnits="userSpaceOnUse" id="clipPath16"><path @@ -37,21 +35,22 @@ guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1011" + inkscape:window-width="1916" + inkscape:window-height="1025" id="namedview4" showgrid="false" - inkscape:zoom="0.63432763" - inkscape:cx="166.44059" - inkscape:cy="101.14582" - inkscape:window-x="0" - inkscape:window-y="0" + inkscape:zoom="1.2041016" + inkscape:cx="512" + inkscape:cy="207" + inkscape:window-x="1360" + inkscape:window-y="53" inkscape:window-maximized="1" inkscape:current-layer="g14" fit-margin-top="48" fit-margin-left="48" fit-margin-right="48" - fit-margin-bottom="48" /><g + fit-margin-bottom="48" + inkscape:document-rotation="0" /><g id="g10" inkscape:groupmode="layer" inkscape:label="godot_engine_logo_2017_curves-01" @@ -171,10 +170,11 @@ id="g82" transform="matrix(1.1310535,0,0,1.1310535,126.80608,346.04533)" style="stroke-width:0.88413143"><path - d="m 0,0 v -47.514 -6.035 -5.492 c 0.108,-0.001 0.216,-0.005 0.323,-0.015 l 36.196,-3.49 c 1.896,-0.183 3.382,-1.709 3.514,-3.609 l 1.116,-15.978 31.574,-2.253 2.175,14.747 c 0.282,1.912 1.922,3.329 3.856,3.329 h 38.188 c 1.933,0 3.573,-1.417 3.855,-3.329 l 2.175,-14.747 31.575,2.253 1.115,15.978 c 0.133,1.9 1.618,3.425 3.514,3.609 l 36.182,3.49 c 0.107,0.01 0.214,0.014 0.322,0.015 v 4.711 l 0.015,0.005 V 0 h 0.134 c 4.795,6.12 9.232,12.569 13.487,19.449 -5.651,9.62 -12.575,18.217 -19.976,26.182 -6.864,-3.455 -13.531,-7.369 -19.828,-11.534 -3.151,3.132 -6.7,5.694 -10.186,8.372 -3.425,2.751 -7.285,4.768 -10.946,7.118 1.09,8.117 1.629,16.108 1.846,24.448 -9.446,4.754 -19.519,7.906 -29.708,10.17 -4.068,-6.837 -7.788,-14.241 -11.028,-21.479 -3.842,0.642 -7.702,0.88 -11.567,0.926 v 0.006 c -0.027,0 -0.052,-0.006 -0.075,-0.006 -0.024,0 -0.049,0.006 -0.073,0.006 V 63.652 C 93.903,63.606 90.046,63.368 86.203,62.726 82.965,69.964 79.247,77.368 75.173,84.205 64.989,81.941 54.915,78.789 45.47,74.035 45.686,65.695 46.225,57.704 47.318,49.587 43.65,47.237 39.795,45.22 36.369,42.469 32.888,39.791 29.333,37.229 26.181,34.097 19.884,38.262 13.219,42.176 6.353,45.631 -1.048,37.666 -7.968,29.069 -13.621,19.449 -9.368,12.569 -4.928,6.12 -0.134,0 Z" - style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + d="m 0,0 v -47.514 -6.035 -5.492 c 0.108,-0.001 0.216,-0.005 0.323,-0.015 l 36.196,-3.49 c 1.896,-0.183 3.382,-1.709 3.514,-3.609 l 1.116,-15.978 31.574,-2.253 2.175,14.747 c 0.282,1.912 1.922,3.329 3.856,3.329 h 38.188 c 1.933,0 3.573,-1.417 3.855,-3.329 l 2.175,-14.747 31.575,2.253 1.115,15.978 c 0.133,1.9 1.618,3.425 3.514,3.609 l 36.182,3.49 c 0.107,0.01 0.214,0.014 0.322,0.015 v 4.711 l 0.015,0.005 V 0 c 5.09692,6.4164715 9.92323,13.494208 13.621,19.449 -5.651,9.62 -12.575,18.217 -19.976,26.182 -6.864,-3.455 -13.531,-7.369 -19.828,-11.534 -3.151,3.132 -6.7,5.694 -10.186,8.372 -3.425,2.751 -7.285,4.768 -10.946,7.118 1.09,8.117 1.629,16.108 1.846,24.448 -9.446,4.754 -19.519,7.906 -29.708,10.17 -4.068,-6.837 -7.788,-14.241 -11.028,-21.479 -3.842,0.642 -7.702,0.88 -11.567,0.926 v 0.006 c -0.027,0 -0.052,-0.006 -0.075,-0.006 -0.024,0 -0.049,0.006 -0.073,0.006 V 63.652 C 93.903,63.606 90.046,63.368 86.203,62.726 82.965,69.964 79.247,77.368 75.173,84.205 64.989,81.941 54.915,78.789 45.47,74.035 45.686,65.695 46.225,57.704 47.318,49.587 43.65,47.237 39.795,45.22 36.369,42.469 32.888,39.791 29.333,37.229 26.181,34.097 19.884,38.262 13.219,42.176 6.353,45.631 -1.048,37.666 -7.968,29.069 -13.621,19.449 -9.1783421,12.475308 -4.4130298,5.4661124 0,0 Z" + style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131" id="path84" - inkscape:connector-curvature="0" /></g><g + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccccsssscccccccccccccccccccsccccccccccc" /></g><g id="g86" transform="matrix(1.1310535,0,0,1.1310535,311.40329,266.88437)" style="stroke-width:0.88413143"><path diff --git a/methods.py b/methods.py index f7134b472b..15eb82ae74 100644 --- a/methods.py +++ b/methods.py @@ -843,7 +843,7 @@ def show_progress(env): try: with open(node_count_fname) as f: node_count_max = int(f.readline()) - except: + except Exception: pass cache_directory = os.environ.get("SCONS_CACHE") diff --git a/misc/dist/document_icons/project.svg b/misc/dist/document_icons/project.svg index 3feed413dd..9b2644186a 100644 --- a/misc/dist/document_icons/project.svg +++ b/misc/dist/document_icons/project.svg @@ -1 +1 @@ -<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><path d="m812.681 293.783c-23.575-32.542-141.93-39.864-197.505-34.983 2.17-68.048 31.457-117.655-37.966-177.025m-415.32-32.625h302.11c77.128-2.02 126.554 37.836 178.444 84.882l123.665 109.83c63.819 56.94 89.13 110.624 96 188.174v542.885h-700.219z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round" stroke-width="19.603"/><g stroke-width=".32"><path d="m712.572 590.17s-.666-4.089-1.056-4.052l-74.179 7.157a12.056 12.056 0 0 0 -10.9 11.191l-2.038 29.21-57.387 4.094-3.905-26.472c-.868-5.888-6.01-10.327-11.961-10.327h-78.292c-5.95 0-11.09 4.439-11.96 10.327l-3.906 26.472-57.387-4.095-2.038-29.208a12.057 12.057 0 0 0 -10.901-11.194l-74.214-7.155c-.384-.037-.665 4.056-1.049 4.056l-.1 16.052 62.853 10.136 2.059 29.47c.416 5.965 5.23 10.788 11.2 11.217l79.035 5.638c.299.021.594.033.89.033 5.94 0 11.072-4.44 11.941-10.329l4.017-27.237h57.414l4.017 27.237c.867 5.886 6.006 10.326 11.953 10.326.292 0 .583-.009.868-.03l79.046-5.638c5.967-.428 10.783-5.252 11.2-11.218l2.056-29.469 62.826-10.18z" fill="#fff"/><path d="m311.398 469.127v121.042c.221.003.443.01.662.031l74.207 7.155a7.99 7.99 0 0 1 7.204 7.4l2.289 32.756 64.731 4.619 4.46-30.234a7.99 7.99 0 0 1 7.904-6.824h78.292a7.99 7.99 0 0 1 7.904 6.824l4.458 30.234 64.733-4.619 2.287-32.757a7.993 7.993 0 0 1 7.203-7.4l74.178-7.154c.22-.02.44-.028.66-.031v-9.658l.032-.01v-111.373h.275c9.83-12.547 18.926-25.768 27.65-39.874-11.586-19.722-25.78-37.347-40.954-53.677-14.073 7.083-27.74 15.108-40.65 23.647-6.46-6.421-13.736-11.674-20.883-17.164-7.022-5.64-14.936-9.775-22.44-14.593 2.234-16.641 3.339-33.024 3.783-50.122-19.366-9.747-40.017-16.209-60.905-20.85-8.34 14.017-15.967 29.196-22.61 44.035-7.876-1.316-15.79-1.804-23.713-1.898v-.013c-.055 0-.107.013-.154.013-.05 0-.1-.013-.15-.013v.013c-7.937.095-15.845.582-23.724 1.898-6.638-14.84-14.261-30.018-22.613-44.035-20.879 4.641-41.532 11.104-60.895 20.85.442 17.098 1.548 33.48 3.788 50.122-7.52 4.818-15.423 8.953-22.447 14.592-7.137 5.491-14.425 10.745-20.887 17.165-12.91-8.539-26.573-16.564-40.65-23.646-15.173 16.329-29.36 33.953-40.95 53.676 8.72 14.106 17.823 27.327 27.65 39.874z" fill="#478cbf"/><path d="m646 612.615-2.3 32.93a7.992 7.992 0 0 1 -7.402 7.413l-79.044 5.64a7.991 7.991 0 0 1 -8.474-6.806l-4.531-30.74h-64.496l-4.533 30.74c-.608 4.137-4.308 7.112-8.474 6.806l-79.043-5.64a7.992 7.992 0 0 1 -7.402-7.413l-2.3-32.931-66.726-6.434c.032 7.173.124 15.028.124 16.592 0 70.472 89.397 104.344 200.465 104.734h.273c111.07-.39 200.435-34.262 200.435-104.734 0-1.592.096-9.416.129-16.592z" fill="#478cbf"/><path d="m451.527 518.261c0 24.71-20.02 44.725-44.72 44.725-24.688 0-44.714-20.016-44.714-44.725 0-24.691 20.026-44.697 44.713-44.697 24.7 0 44.72 20.006 44.72 44.697" fill="#fff"/><path d="m440.766 520.915c0 16.388-13.283 29.671-29.684 29.671-16.393 0-29.684-13.283-29.684-29.671 0-16.39 13.29-29.685 29.684-29.685 16.401 0 29.684 13.295 29.684 29.685" fill="#414042"/><path d="m511.997 567.054c-7.951 0-14.394-5.86-14.394-13.081v-41.17c0-7.216 6.444-13.08 14.394-13.08s14.408 5.864 14.408 13.08v41.17c0 7.222-6.458 13.081-14.408 13.081m60.477-48.793c0 24.71 20.02 44.725 44.724 44.725 24.686 0 44.71-20.016 44.71-44.725 0-24.691-20.024-44.697-44.71-44.697-24.704 0-44.724 20.006-44.724 44.697" fill="#fff"/><path d="m583.238 520.915c0 16.388 13.279 29.671 29.668 29.671 16.405 0 29.683-13.283 29.683-29.671 0-16.39-13.278-29.685-29.684-29.685-16.388 0-29.668 13.295-29.668 29.685" fill="#414042"/></g><text style="font-weight:800;font-size:16;font-family:Montserrat;letter-spacing:0;word-spacing:0;fill:#333f67" x="234.416" y="878.644"><tspan font-size="112" x="234.416" y="878.644">PROJECT</tspan></text></svg> +<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><path d="m812.681 293.783c-23.575-32.542-141.93-39.864-197.505-34.983 2.17-68.048 31.457-117.655-37.966-177.025m-415.32-32.625h302.11c77.128-2.02 126.554 37.836 178.444 84.882l123.665 109.83c63.819 56.94 89.13 110.624 96 188.174v542.885h-700.219z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round" stroke-width="19.603"/><g stroke-width=".32"><path d="m712.572 590.17s-.666-4.089-1.056-4.052l-74.179 7.157a12.056 12.056 0 0 0 -10.9 11.191l-2.038 29.21-57.387 4.094-3.905-26.472c-.868-5.888-6.01-10.327-11.961-10.327h-78.292c-5.95 0-11.09 4.439-11.96 10.327l-3.906 26.472-57.387-4.095-2.038-29.208a12.057 12.057 0 0 0 -10.901-11.194l-74.214-7.155c-.384-.037-.665 4.056-1.049 4.056l-.1 16.052 62.853 10.136 2.059 29.47c.416 5.965 5.23 10.788 11.2 11.217l79.035 5.638c.299.021.594.033.89.033 5.94 0 11.072-4.44 11.941-10.329l4.017-27.237h57.414l4.017 27.237c.867 5.886 6.006 10.326 11.953 10.326.292 0 .583-.009.868-.03l79.046-5.638c5.967-.428 10.783-5.252 11.2-11.218l2.056-29.469 62.826-10.18z" fill="#fff"/><path d="m311.398 469.127v121.042c.221.003.443.01.662.031l74.207 7.155c3.88703.37478 6.93367 3.50431 7.204 7.4l2.289 32.756 64.731 4.619 4.46-30.234c.57822-3.91981 3.94178-6.82377 7.904-6.824h78.292c3.96222.00023 7.32578 2.90419 7.904 6.824l4.458 30.234 64.733-4.619 2.287-32.757c.27147-3.89481 3.31693-7.02357 7.203-7.4l74.178-7.154c.22-.02.44-.028.66-.031v-9.658l.032-.01v-111.373c10.4496-13.15476 20.3441-27.66594 27.925-39.874-11.586-19.722-25.78-37.347-40.954-53.677-14.073 7.083-27.74 15.108-40.65 23.647-6.46-6.421-13.736-11.674-20.883-17.164-7.022-5.64-14.936-9.775-22.44-14.593 2.234-16.641 3.339-33.024 3.783-50.122-19.366-9.747-40.017-16.209-60.905-20.85-8.34 14.017-15.967 29.196-22.61 44.035-7.876-1.316-15.79-1.804-23.713-1.898v-.013c-.055 0-.107.013-.154.013-.05 0-.1-.013-.15-.013v.013c-7.937.095-15.845.582-23.724 1.898-6.638-14.84-14.261-30.018-22.613-44.035-20.879 4.641-41.532 11.104-60.895 20.85.442 17.098 1.548 33.48 3.788 50.122-7.52 4.818-15.423 8.953-22.447 14.592-7.137 5.491-14.425 10.745-20.887 17.165-12.91-8.539-26.573-16.564-40.65-23.646-15.173 16.329-29.36 33.953-40.95 53.676 9.10746 14.29708 18.8786 28.66782 27.925 39.873z" fill="#478cbf"/><path d="m646 612.615-2.3 32.93a7.992 7.992 0 0 1 -7.402 7.413l-79.044 5.64a7.991 7.991 0 0 1 -8.474-6.806l-4.531-30.74h-64.496l-4.533 30.74c-.608 4.137-4.308 7.112-8.474 6.806l-79.043-5.64a7.992 7.992 0 0 1 -7.402-7.413l-2.3-32.931-66.726-6.434c.032 7.173.124 15.028.124 16.592 0 70.472 89.397 104.344 200.465 104.734h.273c111.07-.39 200.435-34.262 200.435-104.734 0-1.592.096-9.416.129-16.592z" fill="#478cbf"/><path d="m451.527 518.261c0 24.71-20.02 44.725-44.72 44.725-24.688 0-44.714-20.016-44.714-44.725 0-24.691 20.026-44.697 44.713-44.697 24.7 0 44.72 20.006 44.72 44.697" fill="#fff"/><path d="m440.766 520.915c0 16.388-13.283 29.671-29.684 29.671-16.393 0-29.684-13.283-29.684-29.671 0-16.39 13.29-29.685 29.684-29.685 16.401 0 29.684 13.295 29.684 29.685" fill="#414042"/><path d="m511.997 567.054c-7.951 0-14.394-5.86-14.394-13.081v-41.17c0-7.216 6.444-13.08 14.394-13.08s14.408 5.864 14.408 13.08v41.17c0 7.222-6.458 13.081-14.408 13.081m60.477-48.793c0 24.71 20.02 44.725 44.724 44.725 24.686 0 44.71-20.016 44.71-44.725 0-24.691-20.024-44.697-44.71-44.697-24.704 0-44.724 20.006-44.724 44.697" fill="#fff"/><path d="m583.238 520.915c0 16.388 13.279 29.671 29.668 29.671 16.405 0 29.683-13.283 29.683-29.671 0-16.39-13.278-29.685-29.684-29.685-16.388 0-29.668 13.295-29.668 29.685" fill="#414042"/></g><text style="font-weight:800;font-size:16;font-family:Montserrat;letter-spacing:0;word-spacing:0;fill:#333f67" x="234.416" y="878.644"><tspan font-size="112" x="234.416" y="878.644">PROJECT</tspan></text></svg> diff --git a/misc/dist/document_icons/project_extra_small.svg b/misc/dist/document_icons/project_extra_small.svg index f17789b69a..1fa1e728e9 100644 --- a/misc/dist/document_icons/project_extra_small.svg +++ b/misc/dist/document_icons/project_extra_small.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M12.698 4.59c-.368-.508-2.218-.623-3.086-.546.034-1.064.492-1.839-.593-2.766m-6.49-.51H7.25c1.205-.032 1.977.591 2.788 1.326L11.97 3.81c.998.89 1.393 1.729 1.5 2.94v8.483H2.53z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round"/><g stroke-width=".32"><path d="M12.062 10.583s-.014-.083-.022-.082l-1.502.145a.244.244 0 0 0-.22.226l-.042.592-1.162.083-.079-.536a.246.246 0 0 0-.242-.21H7.208c-.12 0-.225.09-.243.21l-.079.536-1.162-.083-.041-.592a.244.244 0 0 0-.22-.226L3.958 10.5c-.007-.001-.013.082-.02.082l-.003.325 1.273.205.042.597c.008.12.105.218.226.227l1.6.114h.019c.12 0 .224-.089.242-.208l.081-.552h1.163l.08.552a.246.246 0 0 0 .26.208l1.601-.114a.246.246 0 0 0 .227-.227l.042-.597 1.272-.206z" fill="#fff"/><path d="M3.938 8.132v2.45l.013.001 1.503.145a.162.162 0 0 1 .146.15l.046.663 1.311.094.09-.612a.162.162 0 0 1 .16-.138h1.586a.162.162 0 0 1 .16.138l.09.612 1.311-.094.046-.663a.162.162 0 0 1 .146-.15l1.502-.145h.014V8.132h.006c.2-.254.383-.522.56-.808a6.285 6.285 0 0 0-.83-1.087 8.105 8.105 0 0 0-.823.48c-.13-.13-.278-.237-.422-.348-.143-.115-.303-.198-.455-.296a9.38 9.38 0 0 0 .077-1.015 5.275 5.275 0 0 0-1.234-.422 8.781 8.781 0 0 0-.457.892 3.13 3.13 0 0 0-.48-.039H8h-.003c-.16.002-.32.012-.48.039a8.71 8.71 0 0 0-.458-.892 5.276 5.276 0 0 0-1.233.422c.009.346.031.678.076 1.015-.152.098-.312.181-.454.296-.145.11-.292.217-.423.347a8.093 8.093 0 0 0-.823-.479c-.307.331-.595.688-.83 1.087.177.286.361.554.56.808z" fill="#478cbf"/><path d="M10.714 11.037l-.047.667a.162.162 0 0 1-.15.15l-1.6.114a.162.162 0 0 1-.172-.137l-.092-.623H7.347l-.092.623a.162.162 0 0 1-.171.137l-1.6-.114a.162.162 0 0 1-.15-.15l-.047-.667-1.351-.13.002.336c0 1.427 1.81 2.113 4.06 2.12h.005c2.25-.007 4.059-.693 4.059-2.12l.002-.336z" fill="#478cbf"/><path d="M6.776 9.127a.905.905 0 1 1-1.811 0 .905.905 0 0 1 1.81 0" fill="#fff"/><path d="M6.558 9.18a.6.6 0 1 1-1.202 0 .6.6 0 0 1 1.202 0" fill="#414042"/><path d="M8 10.115c-.16 0-.291-.119-.291-.265v-.834c0-.146.13-.265.291-.265.161 0 .292.119.292.265v.834c0 .146-.13.265-.292.265m1.225-.988a.906.906 0 1 0 1.81 0 .906.906 0 0 0-1.81 0" fill="#fff"/><path d="M9.443 9.18a.6.6 0 1 0 1.201 0 .6.6 0 0 0-1.201 0" fill="#414042"/></g></svg> +<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12.698 4.59c-.368-.508-2.218-.623-3.086-.546.034-1.064.492-1.839-.593-2.766m-6.49-.51h4.721c1.205-.032 1.977.591 2.788 1.326l1.932 1.716c.998.89 1.393 1.729 1.5 2.94v8.483h-10.94z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round"/><g stroke-width=".32"><path d="m12.062 10.583s-.014-.083-.022-.082l-1.502.145a.244.244 0 0 0 -.22.226l-.042.592-1.162.083-.079-.536a.246.246 0 0 0 -.242-.21h-1.585c-.12 0-.225.09-.243.21l-.079.536-1.162-.083-.041-.592a.244.244 0 0 0 -.22-.226l-1.505-.146c-.007-.001-.013.082-.02.082l-.003.325 1.273.205.042.597c.008.12.105.218.226.227l1.6.114h.019c.12 0 .224-.089.242-.208l.081-.552h1.163l.08.552a.246.246 0 0 0 .26.208l1.601-.114a.246.246 0 0 0 .227-.227l.042-.597 1.272-.206z" fill="#fff"/><path d="m3.938 8.132v2.45l.013.001 1.503.145c.078773.0076.1405059.07105.146.15l.046.663 1.311.094.09-.612c.01187-.07924.079879-.137895.16-.138h1.586c.080121.000105.1481303.05876.16.138l.09.612 1.311-.094.046-.663c.0055-.07895.06723-.142375.146-.15l1.502-.145h.014v-2.451c.22118-.2597567.402804-.5673567.566-.808-.236303-.3914463-.514617-.7559371-.83-1.087-.283508.1437236-.558316.3040004-.823.48-.13-.13-.278-.237-.422-.348-.143-.115-.303-.198-.455-.296.044019-.3366902.069724-.6755224.077-1.015-.392294-.1911688-.8067944-.3329185-1.234-.422-.1691916.2883902-.3217734.5862085-.457.892-.158761-.0253078-.3192359-.0383464-.48-.039h-.004-.003c-.16.002-.32.012-.48.039-.135411-.3058816-.288331-.6037083-.458-.892-.4268603.0891708-.841019.2309186-1.233.422.009.346.031.678.076 1.015-.152.098-.312.181-.454.296-.145.11-.292.217-.423.347-.264694-.1756817-.5395029-.3356251-.823-.479-.307.331-.595.688-.83 1.087.1718588.2982703.3967405.5717122.566.808z" fill="#478cbf"/><path d="m10.714 11.037-.047.667a.162.162 0 0 1 -.15.15l-1.6.114a.162.162 0 0 1 -.172-.137l-.092-.623h-1.306l-.092.623a.162.162 0 0 1 -.171.137l-1.6-.114a.162.162 0 0 1 -.15-.15l-.047-.667-1.351-.13.002.336c0 1.427 1.81 2.113 4.06 2.12h.005c2.25-.007 4.059-.693 4.059-2.12l.002-.336z" fill="#478cbf"/><path d="m6.776 9.127a.905.905 0 1 1 -1.811 0 .905.905 0 0 1 1.81 0" fill="#fff"/><path d="m6.558 9.18a.6.6 0 1 1 -1.202 0 .6.6 0 0 1 1.202 0" fill="#414042"/><path d="m8 10.115c-.16 0-.291-.119-.291-.265v-.834c0-.146.13-.265.291-.265s.292.119.292.265v.834c0 .146-.13.265-.292.265m1.225-.988a.906.906 0 1 0 1.81 0 .906.906 0 0 0 -1.81 0" fill="#fff"/><path d="m9.443 9.18a.6.6 0 1 0 1.201 0 .6.6 0 0 0 -1.201 0" fill="#414042"/></g></svg> diff --git a/misc/dist/document_icons/project_small.svg b/misc/dist/document_icons/project_small.svg index d9473b1da3..058eded3ee 100644 --- a/misc/dist/document_icons/project_small.svg +++ b/misc/dist/document_icons/project_small.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M25.396 9.18c-.736-1.016-4.435-1.245-6.172-1.093.068-2.126.983-3.676-1.186-5.532M5.059 1.536H14.5c2.41-.063 3.955 1.182 5.576 2.652l3.865 3.433c1.994 1.779 2.785 3.457 3 5.88v16.965H5.059z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round"/><g stroke-width=".32"><path d="M22.268 20.443s-.02-.128-.033-.127l-2.318.224a.377.377 0 0 0-.34.35l-.064.912-1.793.128-.122-.827a.38.38 0 0 0-.374-.323h-2.447a.38.38 0 0 0-.374.323l-.122.827-1.793-.128-.064-.913a.377.377 0 0 0-.34-.35l-2.32-.223c-.011-.001-.02.127-.032.127l-.003.501 1.964.317.064.921a.38.38 0 0 0 .35.35l2.47.177h.028a.38.38 0 0 0 .373-.322l.125-.851h1.795l.125.851a.38.38 0 0 0 .4.322l2.471-.176a.38.38 0 0 0 .35-.351l.064-.92 1.964-.32z" fill="#fff"/><path d="M9.732 16.66v3.783h.02l2.32.224a.25.25 0 0 1 .224.231l.072 1.024 2.023.144.14-.945a.25.25 0 0 1 .246-.213h2.447a.25.25 0 0 1 .247.213l.14.945 2.022-.144.072-1.024a.25.25 0 0 1 .225-.23l2.318-.225h.02v-.302h.001V16.66h.009c.307-.392.591-.805.864-1.246a9.7 9.7 0 0 0-1.28-1.677c-.44.22-.867.472-1.27.738-.202-.2-.43-.364-.653-.536-.22-.176-.466-.305-.701-.456.07-.52.104-1.032.118-1.566a8.14 8.14 0 0 0-1.903-.652c-.26.438-.499.913-.707 1.376a4.832 4.832 0 0 0-.74-.059h-.01a4.837 4.837 0 0 0-.742.06 13.44 13.44 0 0 0-.706-1.377 8.142 8.142 0 0 0-1.903.652c.014.534.048 1.046.118 1.566-.235.15-.482.28-.701.456-.223.172-.451.336-.653.536-.403-.266-.83-.517-1.27-.738a9.704 9.704 0 0 0-1.28 1.677c.273.44.557.854.864 1.246z" fill="#478cbf"/><path d="M20.188 21.144l-.072 1.029a.25.25 0 0 1-.231.232l-2.47.176a.25.25 0 0 1-.265-.213l-.142-.96h-2.015l-.142.96a.25.25 0 0 1-.265.213l-2.47-.176a.25.25 0 0 1-.231-.232l-.072-1.03-2.085-.2c0 .224.004.47.004.518 0 2.203 2.793 3.261 6.264 3.273h.009c3.47-.012 6.263-1.07 6.263-3.273l.004-.518z" fill="#478cbf"/><path d="M14.11 18.195a1.397 1.397 0 1 1-2.794.001 1.397 1.397 0 0 1 2.795 0" fill="#fff"/><path d="M13.774 18.278a.927.927 0 1 1-1.854 0 .927.927 0 0 1 1.854 0" fill="#414042"/><path d="M16 19.72c-.248 0-.45-.183-.45-.409v-1.286c0-.226.202-.409.45-.409.249 0 .45.183.45.409v1.286c0 .226-.201.41-.45.41m1.89-1.526a1.397 1.397 0 1 0 2.795 0 1.397 1.397 0 0 0-2.795 0" fill="#fff"/><path d="M18.227 18.278a.927.927 0 1 0 1.854 0 .927.927 0 0 0-1.854 0" fill="#414042"/></g></svg> +<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="m25.396 9.18c-.736-1.016-4.435-1.245-6.172-1.093.068-2.126.983-3.676-1.186-5.532m-12.979-1.019h9.441c2.41-.063 3.955 1.182 5.576 2.652l3.865 3.433c1.994 1.779 2.785 3.457 3 5.88v16.965h-21.882z" fill="#eff1f5" stroke="#9f9fa1" stroke-linecap="round" stroke-linejoin="round"/><g stroke-width=".32"><path d="m22.268 20.443s-.02-.128-.033-.127l-2.318.224a.377.377 0 0 0 -.34.35l-.064.912-1.793.128-.122-.827a.38.38 0 0 0 -.374-.323h-2.447a.38.38 0 0 0 -.374.323l-.122.827-1.793-.128-.064-.913a.377.377 0 0 0 -.34-.35l-2.32-.223c-.011-.001-.02.127-.032.127l-.003.501 1.964.317.064.921a.38.38 0 0 0 .35.35l2.47.177h.028a.38.38 0 0 0 .373-.322l.125-.851h1.795l.125.851a.38.38 0 0 0 .4.322l2.471-.176a.38.38 0 0 0 .35-.351l.064-.92 1.964-.32z" fill="#fff"/><path d="m9.732 16.66v3.783h.02l2.32.224c.120882.01233.215393.109796.224.231l.072 1.024 2.023.144.14-.945c.01825-.121952.122691-.212385.246-.213h2.447c.123688.000122.228694.09067.247.213l.14.945 2.022-.144.072-1.024c.0091-.121156.104074-.218195.225-.23l2.318-.225h.02v-.302h.001v-3.481c.337369-.403598.623887-.872775.873-1.246-.364428-.603874-.793632-1.166199-1.28-1.677-.44.22-.867.472-1.27.738-.202-.2-.43-.364-.653-.536-.22-.176-.466-.305-.701-.456.07-.52.104-1.032.118-1.566-.604936-.295179-1.244149-.514184-1.903-.652-.26.438-.499.913-.707 1.376-.244789-.03861-.492185-.05834-.74-.059h-.01c-.248507.00091-.496575.02097-.742.06-.208692-.472178-.444416-.93194-.706-1.377-.658846.137836-1.298056.35684-1.903.652.014.534.048 1.046.118 1.566-.235.15-.482.28-.701.456-.223.172-.451.336-.653.536-.403-.266-.83-.517-1.27-.738-.4863434.510822-.9155458 1.073144-1.28 1.677.2695251.457258.6077461.88389.873 1.246z" fill="#478cbf"/><path d="m20.188 21.144-.072 1.029a.25.25 0 0 1 -.231.232l-2.47.176a.25.25 0 0 1 -.265-.213l-.142-.96h-2.015l-.142.96a.25.25 0 0 1 -.265.213l-2.47-.176a.25.25 0 0 1 -.231-.232l-.072-1.03-2.085-.2c0 .224.004.47.004.518 0 2.203 2.793 3.261 6.264 3.273h.009c3.47-.012 6.263-1.07 6.263-3.273l.004-.518z" fill="#478cbf"/><path d="m14.11 18.195a1.397 1.397 0 1 1 -2.794.001 1.397 1.397 0 0 1 2.795 0" fill="#fff"/><path d="m13.774 18.278a.927.927 0 1 1 -1.854 0 .927.927 0 0 1 1.854 0" fill="#414042"/><path d="m16 19.72c-.248 0-.45-.183-.45-.409v-1.286c0-.226.202-.409.45-.409.249 0 .45.183.45.409v1.286c0 .226-.201.41-.45.41m1.89-1.526a1.397 1.397 0 1 0 2.795 0 1.397 1.397 0 0 0 -2.795 0" fill="#fff"/><path d="m18.227 18.278a.927.927 0 1 0 1.854 0 .927.927 0 0 0 -1.854 0" fill="#414042"/></g></svg> diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html index d4234d08ac..bf608dfa49 100644 --- a/misc/dist/html/editor.html +++ b/misc/dist/html/editor.html @@ -9,11 +9,12 @@ body { touch-action: none; + font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; margin: 0; border: 0 none; padding: 0; text-align: center; - background-color: black; + background-color: #333b4f; overflow: hidden; } @@ -28,7 +29,6 @@ } .godot { - font-family: 'Noto Sans', 'Droid Sans', Arial, sans-serif; color: #e0e0e0; background-color: #3b3943; background-image: linear-gradient(to bottom, #403e48, #35333c); @@ -36,6 +36,44 @@ box-shadow: 0 0 1px 1px #2f2d35; } + .btn { + appearance: none; + color: #e0e0e0; + background-color: #262c3b; + border: 1px solid #202531; + padding: 0.5rem 1rem; + margin: 0 0.5rem; + } + + .btn:focus { + outline: 1px solid #699ce8; + } + + .btn:not(:disabled):hover { + color: #e0e1e5; + border-color: #666c7b; + } + + .btn:active { + border-color: #699ce8; + color: #699ce8; + } + + .btn:disabled { + color: #aaa; + border-color: #242937; + } + + .btn.tab-btn { + padding: 0.3rem 1rem; + } + + .btn.close-btn { + padding: 0.3rem 1rem; + margin-left: -0.75rem; + font-weight: 700; + } + /* Status display * ============== */ @@ -116,27 +154,28 @@ </head> <body> <div id="tabs-buttons"> - <button id="btn-tab-loader" class="tab-btn" onclick="showTab('loader')">Loader</button> - <button id="btn-tab-editor" class="tab-btn" disabled="disabled" onclick="showTab('editor')">Editor</button> - <button id="btn-close-editor" class="close-btn" disabled="disabled" onclick="closeEditor()">X</button> - <button id="btn-tab-game" class="tab-btn" disabled="disabled" onclick="showTab('game')">Game</button> - <button id="btn-close-game" class="close-btn" disabled="disabled" onclick="closeGame()">X</button> + <button id="btn-tab-loader" class="btn tab-btn" onclick="showTab('loader')">Loader</button> + <button id="btn-tab-editor" class="btn tab-btn" disabled="disabled" onclick="showTab('editor')">Editor</button> + <button id="btn-close-editor" class="btn close-btn" disabled="disabled" onclick="closeEditor()">×</button> + <button id="btn-tab-game" class="btn tab-btn" disabled="disabled" onclick="showTab('game')">Game</button> + <button id="btn-close-game" class="btn close-btn" disabled="disabled" onclick="closeGame()">×</button> </div> <div id='tabs'> <div id='tab-loader'> - <div style="color: white;" id="persistence"> + <div style="color: #e0e0e0;" id="persistence"> <label for="videoMode" style="display: none;">Select video driver:</label><br /> <select id="videoMode" style="display: none;"> <option value="GLES2" selected="selected">WebGL</option> <option value="GLES3">WebGL 2</option> </select> <br /> - <label for="zip-file">Preload project zip: </label><input id="zip-file" type="file" id="files" name="files"/> + <img src="logo.svg"> <br /> - <button id="startButton">Start Godot Editor</button> + <label for="zip-file" style="margin-right: 1rem">Preload project ZIP:</label> <input id="zip-file" type="file" id="files" name="files" style="margin-bottom: 1rem"/> <br /> + <button id="startButton" class="btn" style="margin-bottom: 4rem">Start Godot editor</button> <br /> - <button onclick="clearPersistence()">Clear persistent data</button> + <button class="btn" onclick="clearPersistence()">Clear persistent data</button> </div> </div> <div id='tab-editor' style="display: none;"> @@ -197,7 +236,8 @@ } Promise.all([ deleteDB("/home/web_user/projects"), - deleteDB("/home/web_user/.config") + deleteDB("/home/web_user/.config"), + deleteDB("/home/web_user/.cache"), ]).then(function(results) { alert("Done."); }).catch(function (err) { @@ -259,7 +299,7 @@ function startEditor(zip) { const INDETERMINATE_STATUS_STEP_MS = 100; - const persistentPaths = ['/home/web_user/.config', '/home/web_user/projects']; + const persistentPaths = ['/home/web_user/.config', '/home/web_user/.cache', '/home/web_user/projects']; var editorCanvas = document.getElementById('editor-canvas'); var gameCanvas = document.getElementById('game-canvas'); diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html index 7d29b35f61..85c5305b85 100644 --- a/misc/dist/html/full-size.html +++ b/misc/dist/html/full-size.html @@ -145,6 +145,7 @@ $GODOT_HEAD_INCLUDE const EXECUTABLE_NAME = '$GODOT_BASENAME'; const MAIN_PACK = '$GODOT_BASENAME.pck'; const EXTRA_ARGS = JSON.parse('$GODOT_ARGS'); + const GDNATIVE_LIBS = [$GODOT_GDNATIVE_LIBS]; const INDETERMINATE_STATUS_STEP_MS = 100; const FULL_WINDOW = $GODOT_FULL_WINDOW; @@ -263,6 +264,7 @@ $GODOT_HEAD_INCLUDE } else { setStatusMode('indeterminate'); engine.setCanvas(canvas); + engine.setGDNativeLibraries(GDNATIVE_LIBS); engine.startGame(EXECUTABLE_NAME, MAIN_PACK, EXTRA_ARGS).then(() => { setStatusMode('hidden'); initializing = false; diff --git a/misc/dist/html/logo.svg b/misc/dist/html/logo.svg new file mode 100644 index 0000000000..afca8a36da --- /dev/null +++ b/misc/dist/html/logo.svg @@ -0,0 +1,219 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + id="svg2" + version="1.1" + inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" + xml:space="preserve" + width="1024" + height="414" + viewBox="0 0 959.99998 388.125" + sodipodi:docname="logo.svg" + inkscape:export-filename="/home/akien/Projects/godot/godot.git/logo.png" + inkscape:export-xdpi="48" + inkscape:export-ydpi="48"><metadata + id="metadata8"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs + id="defs6"><clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath16"><path + d="M 0,595.276 H 841.89 V 0 H 0 Z" + id="path18" + inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1916" + inkscape:window-height="1025" + id="namedview4" + showgrid="false" + inkscape:zoom="1.2041016" + inkscape:cx="512" + inkscape:cy="207" + inkscape:window-x="1360" + inkscape:window-y="53" + inkscape:window-maximized="1" + inkscape:current-layer="g14" + fit-margin-top="48" + fit-margin-left="48" + fit-margin-right="48" + fit-margin-bottom="48" + inkscape:document-rotation="0" /><g + id="g10" + inkscape:groupmode="layer" + inkscape:label="godot_engine_logo_2017_curves-01" + transform="matrix(1.25,0,0,-1.25,-94.249997,597.49874)"><g + id="g12"><g + id="g14" + clip-path="url(#clipPath16)"><g + id="g20" + transform="matrix(1.1310535,0,0,1.1310535,531.44953,355.31567)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 c -3.611,0 -6.636,-1.659 -9.09,-4.967 -2.441,-3.311 -3.668,-7.958 -3.668,-13.938 0,-5.993 1.166,-10.581 3.503,-13.778 2.333,-3.207 5.398,-4.804 9.2,-4.804 3.8,0 6.887,1.617 9.258,4.862 2.371,3.233 3.559,7.861 3.559,13.886 0,6.02 -1.227,10.654 -3.673,13.89 C 6.646,-1.617 3.616,0 0,0 m -0.055,-59.493 c -10.573,0 -19.195,3.46 -25.859,10.379 -6.655,6.925 -9.984,17.03 -9.984,30.314 0,13.292 3.367,23.356 10.101,30.209 6.736,6.844 15.431,10.269 26.082,10.269 10.649,0 19.251,-3.363 25.794,-10.109 6.555,-6.733 9.827,-16.94 9.827,-30.591 0,-13.661 -3.348,-23.822 -10.05,-30.49 -6.702,-6.654 -15.333,-9.981 -25.911,-9.981" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path22" + inkscape:connector-curvature="0" /></g><g + id="g24" + transform="matrix(1.1310535,0,0,1.1310535,607.8515,354.43097)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 v -33.768 c 0,-1.577 0.116,-2.571 0.342,-2.988 0.224,-0.415 0.903,-0.623 2.029,-0.623 4.144,0 7.283,1.548 9.429,4.634 2.151,3.083 3.215,8.216 3.215,15.405 0,7.192 -1.113,11.878 -3.325,14.055 C 9.467,-1.102 5.946,0 1.129,0 Z m -21.675,-52.392 v 67.735 c 0,1.883 0.468,3.369 1.413,4.471 0.939,1.085 2.161,1.636 3.671,1.636 H 2.263 c 11.965,0 21.053,-3.018 27.257,-9.04 6.215,-6.02 9.322,-15.499 9.322,-28.447 0,-27.7 -11.821,-41.547 -35.456,-41.547 h -19.302 c -3.836,0 -5.759,1.727 -5.759,5.192" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path26" + inkscape:connector-curvature="0" /></g><g + id="g28" + transform="matrix(1.1310535,0,0,1.1310535,700.81066,355.31567)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 c -3.612,0 -6.645,-1.659 -9.095,-4.967 -2.44,-3.311 -3.662,-7.958 -3.662,-13.938 0,-5.993 1.169,-10.581 3.499,-13.778 2.33,-3.207 5.398,-4.804 9.2,-4.804 3.801,0 6.89,1.617 9.258,4.862 2.372,3.233 3.56,7.861 3.56,13.886 0,6.02 -1.225,10.654 -3.671,13.89 C 6.642,-1.617 3.616,0 0,0 m -0.058,-59.493 c -10.577,0 -19.193,3.46 -25.851,10.379 -6.663,6.925 -9.993,17.03 -9.993,30.314 0,13.292 3.367,23.356 10.1,30.209 6.741,6.844 15.431,10.269 26.086,10.269 10.651,0 19.246,-3.363 25.797,-10.109 6.55,-6.733 9.822,-16.94 9.822,-30.591 0,-13.661 -3.349,-23.822 -10.05,-30.49 -6.699,-6.654 -15.338,-9.981 -25.911,-9.981" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path30" + inkscape:connector-curvature="0" /></g><g + id="g32" + transform="matrix(1.1310535,0,0,1.1310535,789.01132,291.33514)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 c 0,-1.496 -3.721,-2.255 -11.176,-2.255 -7.448,0 -11.18,0.759 -11.18,2.255 v 56.681 h -13.545 c -1.281,0 -2.185,1.727 -2.71,5.198 -0.226,1.652 -0.334,3.343 -0.334,5.077 0,1.724 0.108,3.422 0.334,5.077 0.525,3.462 1.429,5.202 2.71,5.202 h 49.112 c 1.279,0 2.179,-1.74 2.712,-5.202 0.221,-1.655 0.335,-3.353 0.335,-5.077 0,-1.734 -0.114,-3.425 -0.335,-5.077 C 15.39,58.408 14.49,56.681 13.211,56.681 H 0 Z" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path34" + inkscape:connector-curvature="0" /></g><g + id="g36" + transform="matrix(1.1310535,0,0,1.1310535,468.26549,336.71278)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 c -6.078,0.094 -13.034,-1.173 -13.034,-1.173 v -11.863 h 6.995 l -0.078,-5.288 c 0,-1.959 -1.942,-2.943 -5.815,-2.943 -3.878,0 -7.303,1.642 -10.274,4.917 -2.978,3.279 -4.459,8.072 -4.459,14.388 0,6.329 1.447,10.995 4.345,14.006 2.892,3.008 6.683,4.517 11.346,4.517 1.959,0 3.987,-0.316 6.096,-0.961 2.11,-0.639 3.519,-1.238 4.238,-1.799 0.713,-0.577 1.391,-0.85 2.032,-0.85 0.638,0 1.671,0.746 3.1,2.255 1.431,1.505 2.713,3.786 3.844,6.827 1.126,3.057 1.69,5.4 1.69,7.062 0,1.649 -0.036,2.786 -0.109,3.386 -1.581,1.73 -4.499,3.102 -8.755,4.122 -4.248,1.017 -9.011,1.522 -14.28,1.522 -11.594,0 -20.66,-3.65 -27.207,-10.95 -6.552,-7.303 -9.822,-16.783 -9.822,-28.452 0,-13.701 3.347,-24.087 10.041,-31.162 6.706,-7.074 15.51,-10.607 26.425,-10.607 5.87,0 11.08,0.505 15.632,1.522 4.557,1.013 7.586,2.053 9.093,3.105 l 0.452,35.33 C 11.496,-1.036 6.078,-0.104 0,0" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path38" + inkscape:connector-curvature="0" /></g><g + id="g40" + transform="matrix(1.1310535,0,0,1.1310535,441.34721,235.75121)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 c -0.624,-1.28 -1.771,-2.454 -3.449,-3.516 -1.676,-1.069 -3.805,-1.6 -6.391,-1.6 -3.412,0 -6.156,1.075 -8.24,3.249 -2.076,2.157 -3.116,5.266 -3.116,9.323 v 10.116 c 0,3.969 0.98,7.013 2.946,9.138 1.962,2.108 4.59,3.177 7.872,3.177 3.208,0 5.695,-0.844 7.455,-2.513 1.755,-1.675 2.677,-4.015 2.757,-7.003 L -0.21,20.238 h -2.619 c -0.094,2.29 -0.759,4.057 -2.01,5.305 -1.244,1.238 -3.095,1.864 -5.539,1.864 -2.473,0 -4.432,-0.837 -5.866,-2.516 -1.43,-1.675 -2.143,-4.103 -2.143,-7.293 V 7.424 c 0,-3.308 0.771,-5.83 2.311,-7.567 1.54,-1.724 3.616,-2.588 6.236,-2.588 1.913,0 3.451,0.339 4.602,1.033 1.155,0.684 1.956,1.519 2.409,2.51 v 8.861 h -7.06 v 2.463 H 0 Z" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path42" + inkscape:connector-curvature="0" /></g><g + id="g44" + transform="matrix(1.1310535,0,0,1.1310535,456.01527,232.82495)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 c 1.553,0 2.936,0.44 4.144,1.336 1.21,0.9 2.058,2.037 2.561,3.422 v 5.468 H 2.213 c -1.91,0 -3.44,-0.541 -4.585,-1.623 C -3.52,7.528 -4.088,6.185 -4.088,4.588 -4.088,3.239 -3.733,2.131 -3.014,1.277 -2.296,0.42 -1.292,0 0,0 M 7.124,-2.04 C 6.984,-1.164 6.875,-0.453 6.806,0.104 6.739,0.671 6.705,1.235 6.705,1.808 5.938,0.554 4.948,-0.486 3.725,-1.301 2.504,-2.122 1.146,-2.529 -0.35,-2.529 c -2.092,0 -3.701,0.648 -4.84,1.946 -1.132,1.303 -1.704,3.059 -1.704,5.276 0,2.343 0.823,4.223 2.473,5.618 1.649,1.395 3.89,2.092 6.709,2.092 h 4.417 v 3.106 c 0,1.786 -0.456,3.193 -1.351,4.21 -0.914,1.004 -2.17,1.512 -3.791,1.512 -1.508,0 -2.752,-0.479 -3.728,-1.45 -0.973,-0.965 -1.456,-2.144 -1.456,-3.549 l -2.623,0.023 -0.046,0.137 c -0.074,1.906 0.647,3.591 2.168,5.084 1.515,1.489 3.459,2.229 5.825,2.229 2.338,0 4.22,-0.711 5.657,-2.128 1.429,-1.431 2.146,-3.471 2.146,-6.124 V 3.057 c 0,-0.903 0.042,-1.78 0.121,-2.617 0.081,-0.848 0.212,-1.665 0.417,-2.48 z" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path46" + inkscape:connector-curvature="0" /></g><g + id="g48" + transform="matrix(1.1310535,0,0,1.1310535,476.7303,259.10521)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 0.24,-3.923 c 0.664,1.404 1.554,2.486 2.657,3.255 1.107,0.759 2.41,1.138 3.906,1.138 1.527,0 2.814,-0.444 3.852,-1.343 1.039,-0.896 1.805,-2.252 2.292,-4.074 0.623,1.682 1.505,3.011 2.65,3.973 1.145,0.964 2.534,1.444 4.143,1.444 2.217,0 3.937,-0.897 5.156,-2.692 1.224,-1.799 1.834,-4.559 1.834,-8.288 v -14.765 h -2.823 v 14.814 c 0,3.1 -0.429,5.283 -1.263,6.538 -0.839,1.257 -2.042,1.89 -3.598,1.89 -1.637,0 -2.915,-0.691 -3.834,-2.096 -0.914,-1.405 -1.478,-3.161 -1.683,-5.282 v -0.655 -15.209 H 10.72 v 14.798 c 0,3.027 -0.424,5.194 -1.292,6.488 -0.864,1.294 -2.066,1.936 -3.609,1.936 -1.475,0 -2.668,-0.45 -3.562,-1.342 -0.9,-0.897 -1.54,-2.125 -1.928,-3.683 V -25.275 H -2.477 V 0 Z" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path50" + inkscape:connector-curvature="0" /></g><g + id="g52" + transform="matrix(1.1310535,0,0,1.1310535,522.82277,256.83868)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 c -1.758,0 -3.202,-0.802 -4.334,-2.402 -1.133,-1.606 -1.718,-3.585 -1.765,-5.944 h 11.66 v 1.082 c 0,2.086 -0.489,3.823 -1.469,5.201 C 3.106,-0.684 1.745,0 0,0 m 0.397,-23.76 c -2.725,0 -4.954,1.026 -6.685,3.073 -1.726,2.043 -2.591,4.657 -2.591,7.841 v 4.197 c 0,3.19 0.867,5.85 2.602,7.965 1.739,2.105 3.828,3.158 6.277,3.158 2.648,0 4.699,-0.939 6.164,-2.823 1.468,-1.887 2.201,-4.422 2.201,-7.603 v -2.773 H -6.099 v -2.102 c 0,-2.447 0.586,-4.484 1.752,-6.11 1.168,-1.63 2.755,-2.438 4.744,-2.438 1.382,0 2.585,0.244 3.588,0.724 1.003,0.491 1.863,1.179 2.578,2.082 l 1.149,-1.988 C 6.949,-21.525 5.96,-22.307 4.753,-22.887 3.549,-23.464 2.094,-23.76 0.397,-23.76" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path54" + inkscape:connector-curvature="0" /></g><g + id="g56" + transform="matrix(1.1310535,0,0,1.1310535,558.0805,256.83868)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="M 0,0 C -1.763,0 -3.21,-0.802 -4.341,-2.402 -5.467,-4.008 -6.053,-5.987 -6.104,-8.346 H 5.559 v 1.082 c 0,2.086 -0.488,3.823 -1.474,5.201 C 3.104,-0.684 1.744,0 0,0 m 0.394,-23.76 c -2.726,0 -4.951,1.026 -6.679,3.073 -1.733,2.043 -2.6,4.657 -2.6,7.841 v 4.197 c 0,3.19 0.871,5.85 2.602,7.965 1.744,2.105 3.834,3.158 6.283,3.158 2.643,0 4.703,-0.939 6.164,-2.823 1.463,-1.887 2.197,-4.422 2.197,-7.603 v -2.773 H -6.104 v -2.102 c 0,-2.447 0.587,-4.484 1.76,-6.11 1.162,-1.63 2.742,-2.438 4.738,-2.438 1.387,0 2.585,0.244 3.585,0.724 1.007,0.491 1.866,1.179 2.589,2.082 l 1.141,-1.988 c -0.764,-0.968 -1.75,-1.75 -2.959,-2.33 -1.204,-0.577 -2.658,-0.873 -4.356,-0.873" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path58" + inkscape:connector-curvature="0" /></g><g + id="g60" + transform="matrix(1.1310535,0,0,1.1310535,575.91679,259.10521)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 0.23,-4.178 c 0.674,1.483 1.564,2.634 2.682,3.435 1.108,0.805 2.413,1.213 3.914,1.213 2.258,0 3.988,-0.835 5.189,-2.513 1.214,-1.675 1.815,-4.279 1.815,-7.812 v -15.42 h -2.825 v 15.394 c 0,2.888 -0.423,4.905 -1.264,6.075 -0.836,1.17 -2.065,1.753 -3.665,1.753 -1.435,0 -2.638,-0.466 -3.603,-1.414 C 1.504,-4.406 0.782,-5.657 0.301,-7.234 V -25.275 H -2.504 V 0 Z" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path62" + inkscape:connector-curvature="0" /></g><g + id="g64" + transform="matrix(1.1310535,0,0,1.1310535,600.8685,242.30884)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 c 0,-2.565 0.486,-4.605 1.472,-6.123 0.974,-1.532 2.457,-2.288 4.436,-2.288 1.356,0 2.498,0.361 3.435,1.101 0.934,0.74 1.672,1.77 2.218,3.077 v 12.52 c -0.525,1.346 -1.246,2.434 -2.157,3.272 -0.91,0.824 -2.062,1.238 -3.448,1.238 -1.975,0 -3.468,-0.86 -4.46,-2.587 C 0.497,8.48 0,6.224 0,3.454 Z m -2.833,3.454 c 0,3.582 0.723,6.459 2.177,8.627 1.442,2.157 3.448,3.239 6.004,3.239 1.419,0 2.664,-0.346 3.728,-1.04 1.066,-0.681 1.947,-1.678 2.654,-2.946 l 0.274,3.516 h 2.381 v -25.298 c 0,-3.239 -0.751,-5.749 -2.26,-7.525 -1.511,-1.769 -3.657,-2.665 -6.428,-2.665 -0.996,0 -2.067,0.156 -3.212,0.459 -1.147,0.303 -2.162,0.701 -3.052,1.2 l 0.776,2.463 c 0.759,-0.492 1.608,-0.873 2.548,-1.141 0.932,-0.277 1.895,-0.41 2.894,-0.41 2.009,0 3.498,0.645 4.46,1.932 0.966,1.304 1.45,3.19 1.45,5.687 v 3.057 c -0.717,-1.138 -1.597,-2.011 -2.64,-2.614 -1.039,-0.606 -2.253,-0.909 -3.622,-0.909 -2.539,0 -4.53,0.994 -5.968,2.982 C -2.11,-5.948 -2.833,-3.301 -2.833,0 Z" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path66" + inkscape:connector-curvature="0" /></g><path + d="m 627.82321,230.5176 h -3.20089 v 28.58738 h 3.20089 z m 0,36.72644 h -3.20089 v 4.50385 h 3.20089 z" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994" + id="path68" + inkscape:connector-curvature="0" /><g + id="g70" + transform="matrix(1.1310535,0,0,1.1310535,638.15379,259.10521)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="m 0,0 0.23,-4.178 c 0.676,1.483 1.562,2.634 2.678,3.435 1.115,0.805 2.422,1.213 3.916,1.213 2.258,0 3.995,-0.835 5.199,-2.513 1.211,-1.675 1.807,-4.279 1.807,-7.812 v -15.42 h -2.825 v 15.394 c 0,2.888 -0.422,4.905 -1.261,6.075 -0.843,1.17 -2.063,1.753 -3.668,1.753 -1.434,0 -2.635,-0.466 -3.599,-1.414 C 1.51,-4.406 0.785,-5.657 0.306,-7.234 V -25.275 H -2.503 V 0 Z" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path72" + inkscape:connector-curvature="0" /></g><g + id="g74" + transform="matrix(1.1310535,0,0,1.1310535,669.70883,256.83868)" + style="stroke-width:0.88413143;fill:#e0e0e0;fill-opacity:1"><path + d="M 0,0 C -1.763,0 -3.208,-0.802 -4.334,-2.402 -5.463,-4.008 -6.052,-5.987 -6.102,-8.346 H 5.56 v 1.082 c 0,2.086 -0.486,3.823 -1.47,5.201 C 3.109,-0.684 1.747,0 0,0 m 0.401,-23.76 c -2.733,0 -4.958,1.026 -6.681,3.073 -1.73,2.043 -2.595,4.657 -2.595,7.841 v 4.197 c 0,3.19 0.865,5.85 2.6,7.965 1.739,2.105 3.831,3.158 6.275,3.158 2.646,0 4.706,-0.939 6.172,-2.823 1.462,-1.887 2.195,-4.422 2.195,-7.603 v -2.773 H -6.102 v -2.102 c 0,-2.447 0.59,-4.484 1.757,-6.11 1.166,-1.63 2.748,-2.438 4.746,-2.438 1.382,0 2.579,0.244 3.578,0.724 1.012,0.491 1.869,1.179 2.591,2.082 l 1.147,-1.988 c -0.769,-0.968 -1.755,-1.75 -2.962,-2.33 -1.203,-0.577 -2.658,-0.873 -4.354,-0.873" + style="fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path76" + inkscape:connector-curvature="0" /></g><g + id="g78" + transform="matrix(1.1310535,0,0,1.1310535,348.13109,279.2668)" + style="stroke-width:0.88413143"><path + d="m 0,0 c 0,0 -0.325,1.994 -0.515,1.976 l -36.182,-3.491 c -2.879,-0.278 -5.115,-2.574 -5.317,-5.459 l -0.994,-14.247 -27.992,-1.997 -1.904,12.912 c -0.424,2.872 -2.932,5.037 -5.835,5.037 h -38.188 c -2.902,0 -5.41,-2.165 -5.834,-5.037 l -1.905,-12.912 -27.992,1.997 -0.994,14.247 c -0.202,2.886 -2.438,5.182 -5.317,5.46 l -36.2,3.49 c -0.187,0.018 -0.324,-1.978 -0.511,-1.978 l -0.049,-7.83 30.658,-4.944 1.004,-14.374 c 0.203,-2.91 2.551,-5.263 5.463,-5.472 l 38.551,-2.75 c 0.146,-0.01 0.29,-0.016 0.434,-0.016 2.897,0 5.401,2.166 5.825,5.038 l 1.959,13.286 h 28.005 l 1.959,-13.286 c 0.423,-2.871 2.93,-5.037 5.831,-5.037 0.142,0 0.284,0.005 0.423,0.015 l 38.556,2.75 c 2.911,0.209 5.26,2.562 5.463,5.472 l 1.003,14.374 30.645,4.966 z" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path80" + inkscape:connector-curvature="0" /></g><g + id="g82" + transform="matrix(1.1310535,0,0,1.1310535,126.80608,346.04533)" + style="stroke-width:0.88413143"><path + d="m 0,0 v -47.514 -6.035 -5.492 c 0.108,-0.001 0.216,-0.005 0.323,-0.015 l 36.196,-3.49 c 1.896,-0.183 3.382,-1.709 3.514,-3.609 l 1.116,-15.978 31.574,-2.253 2.175,14.747 c 0.282,1.912 1.922,3.329 3.856,3.329 h 38.188 c 1.933,0 3.573,-1.417 3.855,-3.329 l 2.175,-14.747 31.575,2.253 1.115,15.978 c 0.133,1.9 1.618,3.425 3.514,3.609 l 36.182,3.49 c 0.107,0.01 0.214,0.014 0.322,0.015 v 4.711 l 0.015,0.005 V 0 c 5.09692,6.4164715 9.92323,13.494208 13.621,19.449 -5.651,9.62 -12.575,18.217 -19.976,26.182 -6.864,-3.455 -13.531,-7.369 -19.828,-11.534 -3.151,3.132 -6.7,5.694 -10.186,8.372 -3.425,2.751 -7.285,4.768 -10.946,7.118 1.09,8.117 1.629,16.108 1.846,24.448 -9.446,4.754 -19.519,7.906 -29.708,10.17 -4.068,-6.837 -7.788,-14.241 -11.028,-21.479 -3.842,0.642 -7.702,0.88 -11.567,0.926 v 0.006 c -0.027,0 -0.052,-0.006 -0.075,-0.006 -0.024,0 -0.049,0.006 -0.073,0.006 V 63.652 C 93.903,63.606 90.046,63.368 86.203,62.726 82.965,69.964 79.247,77.368 75.173,84.205 64.989,81.941 54.915,78.789 45.47,74.035 45.686,65.695 46.225,57.704 47.318,49.587 43.65,47.237 39.795,45.22 36.369,42.469 32.888,39.791 29.333,37.229 26.181,34.097 19.884,38.262 13.219,42.176 6.353,45.631 -1.048,37.666 -7.968,29.069 -13.621,19.449 -9.1783421,12.475308 -4.4130298,5.4661124 0,0 Z" + style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131" + id="path84" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccccsssscccccccccccccccccccsccccccccccc" /></g><g + id="g86" + transform="matrix(1.1310535,0,0,1.1310535,311.40329,266.88437)" + style="stroke-width:0.88413143"><path + d="m 0,0 -1.121,-16.063 c -0.135,-1.936 -1.675,-3.477 -3.611,-3.616 l -38.555,-2.751 c -0.094,-0.007 -0.188,-0.01 -0.281,-0.01 -1.916,0 -3.569,1.406 -3.852,3.33 l -2.211,14.994 H -81.09 l -2.211,-14.994 c -0.297,-2.018 -2.101,-3.469 -4.133,-3.32 l -38.555,2.751 c -1.936,0.139 -3.476,1.68 -3.611,3.616 L -130.721,0 -163.268,3.138 c 0.015,-3.498 0.06,-7.33 0.06,-8.093 0,-34.374 43.605,-50.896 97.781,-51.086 h 0.066 0.067 c 54.176,0.19 97.766,16.712 97.766,51.086 0,0.777 0.047,4.593 0.063,8.093 z" + style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path88" + inkscape:connector-curvature="0" /></g><g + id="g90" + transform="matrix(1.1310535,0,0,1.1310535,204.11393,318.93771)" + style="stroke-width:0.88413143"><path + d="m 0,0 c 0,-12.052 -9.765,-21.815 -21.813,-21.815 -12.042,0 -21.81,9.763 -21.81,21.815 0,12.044 9.768,21.802 21.81,21.802 C -9.765,21.802 0,12.044 0,0" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path92" + inkscape:connector-curvature="0" /></g><g + id="g94" + transform="matrix(1.1310535,0,0,1.1310535,198.17748,317.47435)" + style="stroke-width:0.88413143"><path + d="m 0,0 c 0,-7.994 -6.479,-14.473 -14.479,-14.473 -7.996,0 -14.479,6.479 -14.479,14.473 0,7.994 6.483,14.479 14.479,14.479 C -6.479,14.479 0,7.994 0,0" + style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path96" + inkscape:connector-curvature="0" /></g><g + id="g98" + transform="matrix(1.1310535,0,0,1.1310535,237.47503,292.01909)" + style="stroke-width:0.88413143"><path + d="m 0,0 c -3.878,0 -7.021,2.858 -7.021,6.381 v 20.081 c 0,3.52 3.143,6.381 7.021,6.381 3.878,0 7.028,-2.861 7.028,-6.381 V 6.381 C 7.028,2.858 3.878,0 0,0" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path100" + inkscape:connector-curvature="0" /></g><g + id="g102" + transform="matrix(1.1310535,0,0,1.1310535,270.84021,318.93771)" + style="stroke-width:0.88413143"><path + d="m 0,0 c 0,-12.052 9.765,-21.815 21.815,-21.815 12.041,0 21.808,9.763 21.808,21.815 0,12.044 -9.767,21.802 -21.808,21.802 C 9.765,21.802 0,12.044 0,0" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path104" + inkscape:connector-curvature="0" /></g><g + id="g106" + transform="matrix(1.1310535,0,0,1.1310535,276.77813,317.47435)" + style="stroke-width:0.88413143"><path + d="m 0,0 c 0,-7.994 6.477,-14.473 14.471,-14.473 8.002,0 14.479,6.479 14.479,14.473 0,7.994 -6.477,14.479 -14.479,14.479 C 6.477,14.479 0,7.994 0,0" + style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.88413143" + id="path108" + inkscape:connector-curvature="0" /></g></g></g></g></svg> diff --git a/misc/dist/project_icon.svg b/misc/dist/project_icon.svg index 1a355131ba..cece381340 100644 --- a/misc/dist/project_icon.svg +++ b/misc/dist/project_icon.svg @@ -1 +1 @@ -<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -98.519719)"><rect fill="#1e1a21" height="1008" rx="176.28572" stroke="#2e2832" stroke-width="16" width="1008" x="8" y="106.51972"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325h.134c4.795 6.12 9.232 12.569 13.487 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.253-6.88 8.693-13.329 13.487-19.449z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 97.676491 522.86238)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 788.7623 819.22103)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 387.09785 624.34645)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 364.87318 629.82505)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 511.99324 725.12292)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 636.90407 624.34645)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 659.13434 629.82505)"/></g></svg> +<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -98.519719)"><rect fill="#1e1a21" height="1008" rx="176.28572" stroke="#2e2832" stroke-width="16" width="1008" x="8" y="106.51972"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325c5.09692 6.4164712 9.92323 13.494208 13.621 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.4426581-6.973693 9.2079704-13.9828879 13.621-19.449z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 97.676491 522.86238)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 788.7623 819.22103)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 387.09785 624.34645)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 364.87318 629.82505)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 511.99324 725.12292)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 636.90407 624.34645)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 659.13434 629.82505)"/></g></svg> diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp index 21ba67ecd3..796ee27a7d 100644 --- a/modules/assimp/editor_scene_importer_assimp.cpp +++ b/modules/assimp/editor_scene_importer_assimp.cpp @@ -838,7 +838,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat String ai_anim_mesh_name = AssimpUtils::get_assimp_string(ai_mesh->mAnimMeshes[j]->mName); if (!morph_mesh_string_lookup.has(ai_anim_mesh_name)) { morph_mesh_string_lookup.insert(ai_anim_mesh_name, j); - mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); + mesh->set_blend_shape_mode(ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED); if (ai_anim_mesh_name.empty()) { ai_anim_mesh_name = String("morph_") + itos(j); } diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index cce72770f5..f8c05761bb 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -319,7 +319,7 @@ bool CSGShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<CSGSphere3D>(p_spatial) || Object::cast_to<CSGBox3D>(p_spatial) || Object::cast_to<CSGCylinder3D>(p_spatial) || Object::cast_to<CSGTorus3D>(p_spatial) || Object::cast_to<CSGMesh3D>(p_spatial) || Object::cast_to<CSGPolygon3D>(p_spatial); } -String CSGShape3DGizmoPlugin::get_name() const { +String CSGShape3DGizmoPlugin::get_gizmo_name() const { return "CSGShape3D"; } diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index 83ee847caf..cf44f76f37 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -40,7 +40,7 @@ class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; bool is_selectable_when_hidden() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_compress_etc.cpp index 4e9e64c6a7..bcdea41b43 100644 --- a/modules/etc/image_etc.cpp +++ b/modules/etc/image_compress_etc.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* image_etc.cpp */ +/* image_compress_etc.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "image_etc.h" -#include "Etc.h" -#include "EtcFilter.h" +#include "image_compress_etc.h" + #include "core/io/image.h" #include "core/os/copymem.h" #include "core/os/os.h" #include "core/string/print_string.h" +#include <Etc.h> +#include <EtcFilter.h> + static Image::Format _get_etc2_mode(Image::UsedChannels format) { switch (format) { case Image::USED_CHANNELS_R: diff --git a/modules/etc/image_etc.h b/modules/etc/image_compress_etc.h index 7b4f26e127..016e64e4fc 100644 --- a/modules/etc/image_etc.h +++ b/modules/etc/image_compress_etc.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* image_etc.h */ +/* image_compress_etc.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IMAGE_ETC1_H -#define IMAGE_ETC1_H +#ifndef IMAGE_COMPRESS_ETC_H +#define IMAGE_COMPRESS_ETC_H void _register_etc_compress_func(); -#endif // IMAGE_ETC_H +#endif // IMAGE_COMPRESS_ETC_H diff --git a/modules/etc/register_types.cpp b/modules/etc/register_types.cpp index 0972857808..225ba6b954 100644 --- a/modules/etc/register_types.cpp +++ b/modules/etc/register_types.cpp @@ -30,7 +30,7 @@ #include "register_types.h" -#include "image_etc.h" +#include "image_compress_etc.h" #include "texture_loader_pkm.h" static Ref<ResourceFormatPKM> resource_loader_pkm; diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp index f0f095ddf5..719fcbc927 100644 --- a/modules/gdnative/gdnative_library_editor_plugin.cpp +++ b/modules/gdnative/gdnative_library_editor_plugin.cpp @@ -308,11 +308,11 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() { platform_android.library_extension = "*.so"; platforms["Android"] = platform_android; - // TODO: Javascript platform is not supported yet - // NativePlatformConfig platform_html5; - // platform_html5.name = "HTML5"; - // platform_html5.library_extension = "*.wasm"; - // platforms["Javascript"] = platform_html5; + NativePlatformConfig platform_html5; + platform_html5.name = "HTML5"; + platform_html5.entries.push_back("wasm32"); + platform_html5.library_extension = "*.wasm"; + platforms["HTML5"] = platform_html5; NativePlatformConfig platform_ios; platform_ios.name = "iOS"; diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h index 406c3ba663..e4b1fd5eb0 100644 --- a/modules/gdnative/include/pluginscript/godot_pluginscript.h +++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h @@ -72,6 +72,7 @@ typedef struct { godot_string_name name; godot_bool is_tool; godot_string_name base; + godot_string icon_path; // Member lines format: {<string>: <int>} godot_dictionary member_lines; @@ -127,6 +128,7 @@ typedef struct { const char **string_delimiters; // nullptr terminated array godot_bool has_named_classes; godot_bool supports_builtin_mode; + godot_bool can_inherit_from_file; godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name); godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_packed_string_array *r_functions); diff --git a/modules/gdnative/include/text/godot_text.h b/modules/gdnative/include/text/godot_text.h index 2eac6adfb5..6885f2463d 100644 --- a/modules/gdnative/include/text/godot_text.h +++ b/modules/gdnative/include/text/godot_text.h @@ -82,6 +82,9 @@ typedef struct { void (*font_set_antialiased)(void *, godot_rid *, bool); bool (*font_get_antialiased)(void *, godot_rid *); godot_dictionary (*font_get_feature_list)(void *, godot_rid *); + godot_dictionary (*font_get_variation_list)(void *, godot_rid *); + void (*font_set_variation)(void *, godot_rid *, const godot_string *, double); + double (*font_get_variation)(void *, godot_rid *, const godot_string *); void (*font_set_distance_field_hint)(void *, godot_rid *, bool); bool (*font_get_distance_field_hint)(void *, godot_rid *); void (*font_set_hinting)(void *, godot_rid *, godot_int); diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp index fc9c4ebd77..df685e716f 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -142,6 +142,10 @@ bool PluginScriptLanguage::supports_builtin_mode() const { return _desc.supports_builtin_mode; } +bool PluginScriptLanguage::can_inherit_from_file() const { + return _desc.can_inherit_from_file; +} + int PluginScriptLanguage::find_function(const String &p_function, const String &p_code) const { if (_desc.find_function) { return _desc.find_function(_data, (godot_string *)&p_function, (godot_string *)&p_code); @@ -398,6 +402,32 @@ void PluginScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool #endif } +bool PluginScriptLanguage::handles_global_class_type(const String &p_type) const { + return p_type == "PluginScript"; +} + +String PluginScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { + if (!p_path.empty()) { + Ref<PluginScript> script = ResourceLoader::load(p_path, "PluginScript"); + if (script.is_valid()) { + if (r_base_type) { + *r_base_type = script->get_instance_base_type(); + } + if (r_icon_path) { + *r_icon_path = script->get_script_class_icon_path(); + } + return script->get_script_class_name(); + } + if (r_base_type) { + *r_base_type = String(); + } + if (r_icon_path) { + *r_icon_path = String(); + } + } + return String(); +} + void PluginScriptLanguage::lock() { _lock.lock(); } diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h index 53e1e3ae9b..7548eba4a0 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.h +++ b/modules/gdnative/pluginscript/pluginscript_language.h @@ -78,7 +78,7 @@ public: virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; - virtual bool can_inherit_from_file() { return true; } + virtual bool can_inherit_from_file() const; virtual int find_function(const String &p_function, const String &p_code) const; virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const; virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint); @@ -122,6 +122,11 @@ public: virtual void frame(); + /* GLOBAL CLASSES */ + + virtual bool handles_global_class_type(const String &p_type) const; + virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const; + void lock(); void unlock(); diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp index 87c6288806..d69ab2fcb7 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.cpp +++ b/modules/gdnative/pluginscript/pluginscript_script.cpp @@ -302,6 +302,7 @@ Error PluginScript::reload(bool p_keep_state) { _data = manifest.data; _name = *(StringName *)&manifest.name; _tool = manifest.is_tool; + _icon_path = *(String *)&manifest.icon_path; Dictionary *members = (Dictionary *)&manifest.member_lines; for (const Variant *key = members->next(); key != nullptr; key = members->next(key)) { diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h index dc1ed6d576..12d93cc407 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.h +++ b/modules/gdnative/pluginscript/pluginscript_script.h @@ -69,6 +69,7 @@ private: String _source; String _path; StringName _name; + String _icon_path; protected: static void _bind_methods(); @@ -84,6 +85,14 @@ protected: virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override; #endif public: + String get_script_class_name() const { + return _name; + } + + String get_script_class_icon_path() const { + return _icon_path; + } + virtual bool can_instance() const override; virtual Ref<Script> get_base_script() const override; //for script inheritance diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp index 68624260a6..cb87adafe8 100644 --- a/modules/gdnative/text/text_server_gdnative.cpp +++ b/modules/gdnative/text/text_server_gdnative.cpp @@ -148,6 +148,24 @@ bool TextServerGDNative::font_get_antialiased(RID p_font) const { return interface->font_get_antialiased(data, (godot_rid *)&p_font); } +Dictionary TextServerGDNative::font_get_variation_list(RID p_font) const { + ERR_FAIL_COND_V(interface == nullptr, Dictionary()); + godot_dictionary result = interface->font_get_variation_list(data, (godot_rid *)&p_font); + Dictionary info = *(Dictionary *)&result; + godot_dictionary_destroy(&result); + + return info; +} + +void TextServerGDNative::font_set_variation(RID p_font, const String &p_name, double p_value) { + ERR_FAIL_COND(interface == nullptr); + interface->font_set_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name, p_value); +} + +double TextServerGDNative::font_get_variation(RID p_font, const String &p_name) const { + return interface->font_get_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name); +} + void TextServerGDNative::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) { ERR_FAIL_COND(interface == nullptr); interface->font_set_hinting(data, (godot_rid *)&p_font, (godot_int)p_hinting); diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h index 0196120c00..959302aaf4 100644 --- a/modules/gdnative/text/text_server_gdnative.h +++ b/modules/gdnative/text/text_server_gdnative.h @@ -76,6 +76,10 @@ public: virtual bool font_get_antialiased(RID p_font) const override; virtual Dictionary font_get_feature_list(RID p_font) const override; + virtual Dictionary font_get_variation_list(RID p_font) const override; + + virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override; + virtual double font_get_variation(RID p_font, const String &p_name) const override; virtual void font_set_hinting(RID p_font, Hinting p_hinting) override; virtual Hinting font_get_hinting(RID p_font) const override; diff --git a/modules/gdnavigation/nav_map.cpp b/modules/gdnavigation/nav_map.cpp index 7919e6a01f..c8c1b422e8 100644 --- a/modules/gdnavigation/nav_map.cpp +++ b/modules/gdnavigation/nav_map.cpp @@ -707,7 +707,7 @@ void NavMap::sync() { } if (regenerate_links) { - map_update_id = map_update_id + 1 % 9999999; + map_update_id = (map_update_id + 1) % 9999999; } if (agents_dirty) { diff --git a/modules/gdnavigation/navigation_mesh_generator.cpp b/modules/gdnavigation/navigation_mesh_generator.cpp index 5329600e39..3310123ca9 100644 --- a/modules/gdnavigation/navigation_mesh_generator.cpp +++ b/modules/gdnavigation/navigation_mesh_generator.cpp @@ -176,10 +176,10 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, BoxShape3D *box = Object::cast_to<BoxShape3D>(*s); if (box) { - Ref<CubeMesh> cube_mesh; - cube_mesh.instance(); - cube_mesh->set_size(box->get_extents() * 2.0); - mesh = cube_mesh; + Ref<BoxMesh> box_mesh; + box_mesh.instance(); + box_mesh->set_size(box->get_extents() * 2.0); + mesh = box_mesh; } CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s); diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index eeb66ebfc0..4ed129b3ff 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -763,7 +763,7 @@ <argument index="1" name="exp" type="float"> </argument> <description> - Returns the result of [code]x[/code] raised to the power of [code]y[/code]. + Returns the result of [code]base[/code] raised to the power of [code]exp[/code]. [codeblock] pow(2, 5) # Returns 32.0 [/codeblock] diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 49357f3d2e..e38647eaab 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -42,7 +42,7 @@ private: Color color; String start_key; String end_key; - bool line_only; + bool line_only = false; }; Vector<ColorRegion> color_regions; Map<int, int> color_region_cache; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 3eb260f95f..f949d26664 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -471,7 +471,7 @@ public: virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; virtual bool supports_documentation() const; - virtual bool can_inherit_from_file() { return true; } + virtual bool can_inherit_from_file() const { return true; } virtual int find_function(const String &p_function, const String &p_code) const; virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const; virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index f2d3b1fb18..e3f058886f 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -98,7 +98,8 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D } break; case GDScriptParser::DataType::SCRIPT: { result.kind = GDScriptDataType::SCRIPT; - result.script_type = Ref<Script>(p_datatype.script_type).ptr(); + result.script_type_ref = Ref<Script>(p_datatype.script_type); + result.script_type = result.script_type_ref.ptr(); result.native_type = result.script_type->get_instance_base_type(); } break; case GDScriptParser::DataType::CLASS: { @@ -124,11 +125,13 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D names.pop_back(); } result.kind = GDScriptDataType::GDSCRIPT; - result.script_type = script.ptr(); + result.script_type_ref = script; + result.script_type = result.script_type_ref.ptr(); result.native_type = script->get_instance_base_type(); } else { result.kind = GDScriptDataType::GDSCRIPT; - result.script_type = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path).ptr(); + result.script_type_ref = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path); + result.script_type = result.script_type_ref.ptr(); result.native_type = p_datatype.native_type; } } @@ -151,8 +154,8 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D // Only hold strong reference to the script if it's not the owner of the // element qualified with this type, to avoid cyclic references (leaks). - if (result.script_type && result.script_type != p_owner) { - result.script_type_ref = Ref<Script>(result.script_type); + if (result.script_type && result.script_type == p_owner) { + result.script_type_ref = Ref<Script>(); } return result; diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 668dfd4835..bd2d170e52 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -723,8 +723,8 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode } break; case ClassNode::Member::ENUM: { Dictionary enum_dict; - for (int j = 0; j < m.m_enum->values.size(); i++) { - enum_dict[m.m_enum->values[i].identifier->name] = m.m_enum->values[i].value; + for (int j = 0; j < m.m_enum->values.size(); j++) { + enum_dict[m.m_enum->values[j].identifier->name] = m.m_enum->values[j].value; } Dictionary api; diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 1ef991841b..66995382e7 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -447,7 +447,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i if (cell != last_cell) { //cell changed, update pointer to indices giw[cell * 2 + 1] = i; - last_cell = cell; solidw[cell] = true; } tiw[i] = triangle_sort[i].triangle_index; @@ -543,7 +542,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i tf.width = grid_size; tf.height = grid_size; tf.depth = grid_size; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; Vector<Vector<uint8_t>> texdata; @@ -695,7 +694,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d tf.width = atlas_size.width; tf.height = atlas_size.height; tf.array_layers = atlas_slices; - tf.type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; @@ -826,84 +825,84 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(vertex_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(triangle_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; u.ids.push_back(box_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 4; u.ids.push_back(triangle_cell_indices_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 5; u.ids.push_back(lights_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 6; u.ids.push_back(seams_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 7; u.ids.push_back(probe_positions_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 8; u.ids.push_back(grid_texture); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(grid_texture_sdf); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 10; u.ids.push_back(albedo_array_tex); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 11; u.ids.push_back(emission_array_tex); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 12; u.ids.push_back(sampler); base_uniforms.push_back(u); @@ -917,7 +916,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d tf.width = atlas_size.width; tf.height = atlas_size.height; tf.depth = 1; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; tf.format = RD::DATA_FORMAT_D32_SFLOAT; @@ -1049,14 +1048,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(position_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(unocclude_tex); //will be unused uniforms.push_back(u); @@ -1089,42 +1088,42 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(light_source_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(light_dest_tex); //will be unused uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(position_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; u.ids.push_back(normal_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(light_accum_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(light_primary_dynamic_tex); uniforms.push_back(u); @@ -1169,49 +1168,49 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(light_dest_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(light_source_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(position_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; u.ids.push_back(normal_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(light_accum_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(unocclude_tex); //reuse unocclude tex uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 6; u.ids.push_back(light_environment_tex); //reuse unocclude tex uniforms.push_back(u); @@ -1317,28 +1316,28 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(light_probe_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(light_dest_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(light_primary_dynamic_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; u.ids.push_back(light_environment_tex); uniforms.push_back(u); @@ -1463,14 +1462,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(light_accum_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(light_accum_tex2); uniforms.push_back(u); @@ -1554,7 +1553,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; u.ids.push_back(light_accum_tex2); uniforms.push_back(u); diff --git a/modules/meshoptimizer/SCsub b/modules/meshoptimizer/SCsub new file mode 100644 index 0000000000..3b1a5f917e --- /dev/null +++ b/modules/meshoptimizer/SCsub @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_meshoptimizer = env_modules.Clone() + +# Thirdparty source files +thirdparty_dir = "#thirdparty/meshoptimizer/" +thirdparty_sources = [ + "allocator.cpp", + "clusterizer.cpp", + "indexcodec.cpp", + "indexgenerator.cpp", + "overdrawanalyzer.cpp", + "overdrawoptimizer.cpp", + "simplifier.cpp", + "spatialorder.cpp", + "stripifier.cpp", + "vcacheanalyzer.cpp", + "vcacheoptimizer.cpp", + "vertexcodec.cpp", + "vertexfilter.cpp", + "vfetchanalyzer.cpp", + "vfetchoptimizer.cpp", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + +env_thirdparty = env_meshoptimizer.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources) + +env_modules.add_source_files(env.modules_sources, ["register_types.cpp"]) diff --git a/modules/meshoptimizer/config.py b/modules/meshoptimizer/config.py new file mode 100644 index 0000000000..82e4e43397 --- /dev/null +++ b/modules/meshoptimizer/config.py @@ -0,0 +1,7 @@ +def can_build(env, platform): + # Having this on release by default, it's small and a lot of users like to do procedural stuff + return True + + +def configure(env): + pass diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp new file mode 100644 index 0000000000..26c8c6ab72 --- /dev/null +++ b/modules/meshoptimizer/register_types.cpp @@ -0,0 +1,43 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "scene/resources/surface_tool.h" +#include "thirdparty/meshoptimizer/meshoptimizer.h" + +void register_meshoptimizer_types() { + SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache; + SurfaceTool::simplify_func = meshopt_simplify; +} + +void unregister_meshoptimizer_types() { + SurfaceTool::optimize_vertex_cache_func = nullptr; + SurfaceTool::simplify_func = nullptr; +} diff --git a/modules/meshoptimizer/register_types.h b/modules/meshoptimizer/register_types.h new file mode 100644 index 0000000000..42b3a76a85 --- /dev/null +++ b/modules/meshoptimizer/register_types.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 MESHOPTIMIZER_REGISTER_TYPES_H +#define MESHOPTIMIZER_REGISTER_TYPES_H + +void register_meshoptimizer_types(); +void unregister_meshoptimizer_types(); + +#endif // PVR_REGISTER_TYPES_H diff --git a/modules/minimp3/SCsub b/modules/minimp3/SCsub new file mode 100644 index 0000000000..f4d1605d55 --- /dev/null +++ b/modules/minimp3/SCsub @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_minimp3 = env_modules.Clone() + +thirdparty_dir = "#thirdparty/minimp3/" + +# Treat minimp3 headers as system headers to avoid raising warnings. Not supported on MSVC. +if not env.msvc: + env_minimp3.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path]) +else: + env_minimp3.Prepend(CPPPATH=[thirdparty_dir]) + +# Godot's own source files +env_minimp3.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp new file mode 100644 index 0000000000..b20c043e0c --- /dev/null +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -0,0 +1,228 @@ +/*************************************************************************/ +/* audio_stream_mp3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#define MINIMP3_ONLY_MP3 +#define MINIMP3_FLOAT_OUTPUT +#define MINIMP3_IMPLEMENTATION +#define MINIMP3_NO_STDIO + +#include "audio_stream_mp3.h" + +#include "core/os/file_access.h" + +void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) { + ERR_FAIL_COND(!active); + + int todo = p_frames; + + while (todo && active) { + mp3dec_frame_info_t frame_info; + mp3d_sample_t *buf_frame = nullptr; + + int samples_mixed = mp3dec_ex_read_frame(mp3d, &buf_frame, &frame_info, mp3_stream->channels); + + if (samples_mixed) { + p_buffer[p_frames - todo] = AudioFrame(buf_frame[0], buf_frame[samples_mixed - 1]); + --todo; + ++frames_mixed; + } + + else { + //EOF + if (mp3_stream->loop) { + seek(mp3_stream->loop_offset); + loops++; + } else { + //fill remainder with silence + for (int i = p_frames - todo; i < p_frames; i++) { + p_buffer[i] = AudioFrame(0, 0); + } + active = false; + todo = 0; + } + } + } +} + +float AudioStreamPlaybackMP3::get_stream_sampling_rate() { + return mp3_stream->sample_rate; +} + +void AudioStreamPlaybackMP3::start(float p_from_pos) { + active = true; + seek(p_from_pos); + loops = 0; + _begin_resample(); +} + +void AudioStreamPlaybackMP3::stop() { + active = false; +} + +bool AudioStreamPlaybackMP3::is_playing() const { + return active; +} + +int AudioStreamPlaybackMP3::get_loop_count() const { + return loops; +} + +float AudioStreamPlaybackMP3::get_playback_position() const { + return float(frames_mixed) / mp3_stream->sample_rate; +} + +void AudioStreamPlaybackMP3::seek(float p_time) { + if (!active) + return; + + if (p_time >= mp3_stream->get_length()) { + p_time = 0; + } + + frames_mixed = uint32_t(mp3_stream->sample_rate * p_time); + mp3dec_ex_seek(mp3d, frames_mixed * mp3_stream->channels); +} + +AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() { + if (mp3d) { + mp3dec_ex_close(mp3d); + memfree(mp3d); + } +} + +Ref<AudioStreamPlayback> AudioStreamMP3::instance_playback() { + Ref<AudioStreamPlaybackMP3> mp3s; + + ERR_FAIL_COND_V(data == nullptr, mp3s); + + mp3s.instance(); + mp3s->mp3_stream = Ref<AudioStreamMP3>(this); + mp3s->mp3d = (mp3dec_ex_t *)memalloc(sizeof(mp3dec_ex_t)); + + int errorcode = mp3dec_ex_open_buf(mp3s->mp3d, (const uint8_t *)data, data_len, MP3D_SEEK_TO_SAMPLE); + + mp3s->frames_mixed = 0; + mp3s->active = false; + mp3s->loops = 0; + + if (errorcode) { + ERR_FAIL_COND_V(errorcode, Ref<AudioStreamPlaybackMP3>()); + } + + return mp3s; +} + +String AudioStreamMP3::get_stream_name() const { + return ""; //return stream_name; +} + +void AudioStreamMP3::clear_data() { + if (data) { + memfree(data); + data = nullptr; + data_len = 0; + } +} + +void AudioStreamMP3::set_data(const Vector<uint8_t> &p_data) { + int src_data_len = p_data.size(); + const uint8_t *src_datar = p_data.ptr(); + + mp3dec_ex_t mp3d; + mp3dec_ex_open_buf(&mp3d, src_datar, src_data_len, MP3D_SEEK_TO_SAMPLE); + + channels = mp3d.info.channels; + sample_rate = mp3d.info.hz; + length = float(mp3d.samples) / (sample_rate * float(channels)); + + mp3dec_ex_close(&mp3d); + + clear_data(); + + data = memalloc(src_data_len); + copymem(data, src_datar, src_data_len); + data_len = src_data_len; +} + +Vector<uint8_t> AudioStreamMP3::get_data() const { + Vector<uint8_t> vdata; + + if (data_len && data) { + vdata.resize(data_len); + { + uint8_t *w = vdata.ptrw(); + copymem(w, data, data_len); + } + } + + return vdata; +} + +void AudioStreamMP3::set_loop(bool p_enable) { + loop = p_enable; +} + +bool AudioStreamMP3::has_loop() const { + return loop; +} + +void AudioStreamMP3::set_loop_offset(float p_seconds) { + loop_offset = p_seconds; +} + +float AudioStreamMP3::get_loop_offset() const { + return loop_offset; +} + +float AudioStreamMP3::get_length() const { + return length; +} + +void AudioStreamMP3::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamMP3::set_data); + ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamMP3::get_data); + + ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamMP3::set_loop); + ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamMP3::has_loop); + + ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamMP3::set_loop_offset); + ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamMP3::get_loop_offset); + + ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop", "has_loop"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop_offset", "get_loop_offset"); +} + +AudioStreamMP3::AudioStreamMP3() { +} + +AudioStreamMP3::~AudioStreamMP3() { + clear_data(); +} diff --git a/platform/android/file_access_jandroid.h b/modules/minimp3/audio_stream_mp3.h index e252a4d3ac..8d67190ac5 100644 --- a/platform/android/file_access_jandroid.h +++ b/modules/minimp3/audio_stream_mp3.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* file_access_jandroid.h */ +/* audio_stream_mp3.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,56 +28,83 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef FILE_ACCESS_JANDROID_H -#define FILE_ACCESS_JANDROID_H +#ifndef AUDIO_STREAM_MP3_H +#define AUDIO_STREAM_MP3_H -#include "core/os/file_access.h" -#include "java_godot_lib_jni.h" -class FileAccessJAndroid : public FileAccess { - static jobject io; - static jclass cls; +#include "core/io/resource_loader.h" +#include "servers/audio/audio_stream.h" - static jmethodID _file_open; - static jmethodID _file_get_size; - static jmethodID _file_seek; - static jmethodID _file_tell; - static jmethodID _file_eof; - static jmethodID _file_read; - static jmethodID _file_close; +#include "minimp3_ex.h" - int id; - static FileAccess *create_jandroid(); +class AudioStreamMP3; + +class AudioStreamPlaybackMP3 : public AudioStreamPlaybackResampled { + GDCLASS(AudioStreamPlaybackMP3, AudioStreamPlaybackResampled); + + mp3dec_ex_t *mp3d = nullptr; + uint32_t frames_mixed = 0; + bool active = false; + int loops = 0; + + friend class AudioStreamMP3; + + Ref<AudioStreamMP3> mp3_stream; + +protected: + virtual void _mix_internal(AudioFrame *p_buffer, int p_frames) override; + virtual float get_stream_sampling_rate() override; public: - virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file - virtual void close(); ///< close a file - virtual bool is_open() const; ///< true when file is open + virtual void start(float p_from_pos = 0.0) override; + virtual void stop() override; + virtual bool is_playing() const override; + + virtual int get_loop_count() const override; //times it looped - virtual void seek(size_t p_position); ///< seek to a given position - virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file - virtual size_t get_position() const; ///< get position in the file - virtual size_t get_len() const; ///< get size of the file + virtual float get_playback_position() const override; + virtual void seek(float p_time) override; - virtual bool eof_reached() const; ///< reading passed EOF + AudioStreamPlaybackMP3() {} + ~AudioStreamPlaybackMP3(); +}; + +class AudioStreamMP3 : public AudioStream { + GDCLASS(AudioStreamMP3, AudioStream); + OBJ_SAVE_TYPE(AudioStream) //children are all saved as AudioStream, so they can be exchanged + RES_BASE_EXTENSION("mp3str"); + + friend class AudioStreamPlaybackMP3; - virtual uint8_t get_8() const; ///< get a byte - virtual int get_buffer(uint8_t *p_dst, int p_length) const; + void *data = nullptr; + uint32_t data_len = 0; - virtual Error get_error() const; ///< get last error + float sample_rate = 1; + int channels = 1; + float length = 0; + bool loop = false; + float loop_offset = 0; + void clear_data(); + +protected: + static void _bind_methods(); + +public: + void set_loop(bool p_enable); + bool has_loop() const; - virtual void flush(); - virtual void store_8(uint8_t p_dest); ///< store a byte + void set_loop_offset(float p_seconds); + float get_loop_offset() const; - virtual bool file_exists(const String &p_path); ///< return true if a file exists + virtual Ref<AudioStreamPlayback> instance_playback() override; + virtual String get_stream_name() const override; - static void setup(jobject p_io); + void set_data(const Vector<uint8_t> &p_data); + Vector<uint8_t> get_data() const; - virtual uint64_t _get_modified_time(const String &p_file) { return 0; } - virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } - virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } + virtual float get_length() const override; - FileAccessJAndroid(); - ~FileAccessJAndroid(); + AudioStreamMP3(); + virtual ~AudioStreamMP3(); }; -#endif // FILE_ACCESS_JANDROID_H +#endif // AUDIO_STREAM_MP3_H diff --git a/modules/minimp3/config.py b/modules/minimp3/config.py new file mode 100644 index 0000000000..bd35d099b9 --- /dev/null +++ b/modules/minimp3/config.py @@ -0,0 +1,16 @@ +def can_build(env, platform): + return True + + +def configure(env): + pass + + +def get_doc_classes(): + return [ + "AudioStreamMP3", + ] + + +def get_doc_path(): + return "doc_classes" diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml new file mode 100644 index 0000000000..92e777ca0f --- /dev/null +++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioStreamMP3" inherits="AudioStream" version="4.0"> + <brief_description> + MP3 audio stream driver. + </brief_description> + <description> + MP3 audio stream driver. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray( )"> + Contains the audio data in bytes. + </member> + <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false"> + If [code]true[/code], the stream will automatically loop when it reaches the end. + </member> + <member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset" default="0.0"> + Time in seconds at which the stream starts after being looped. + </member> + </members> + <constants> + </constants> +</class> diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp new file mode 100644 index 0000000000..2c648b8efe --- /dev/null +++ b/modules/minimp3/register_types.cpp @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "audio_stream_mp3.h" + +#ifdef TOOLS_ENABLED +#include "core/config/engine.h" +#include "resource_importer_mp3.h" +#endif + +void register_minimp3_types() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + Ref<ResourceImporterMP3> mp3_import; + mp3_import.instance(); + ResourceFormatImporter::get_singleton()->add_importer(mp3_import); + } +#endif + ClassDB::register_class<AudioStreamMP3>(); +} + +void unregister_minimp3_types() { +} diff --git a/modules/minimp3/register_types.h b/modules/minimp3/register_types.h new file mode 100644 index 0000000000..0d841e4987 --- /dev/null +++ b/modules/minimp3/register_types.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 MINIMP3_REGISTER_TYPES_H +#define MINIMP3_REGISTER_TYPES_H + +void register_minimp3_types(); +void unregister_minimp3_types(); + +#endif // MINIMP3_REGISTER_TYPES_H diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp new file mode 100644 index 0000000000..82e536a755 --- /dev/null +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -0,0 +1,104 @@ +/*************************************************************************/ +/* resource_importer_mp3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "resource_importer_mp3.h" + +#include "core/io/resource_saver.h" +#include "core/os/file_access.h" +#include "scene/resources/texture.h" + +String ResourceImporterMP3::get_importer_name() const { + return "mp3"; +} + +String ResourceImporterMP3::get_visible_name() const { + return "MP3"; +} + +void ResourceImporterMP3::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("mp3"); +} + +String ResourceImporterMP3::get_save_extension() const { + return "mp3str"; +} + +String ResourceImporterMP3::get_resource_type() const { + return "AudioStreamMP3"; +} + +bool ResourceImporterMP3::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { + return true; +} + +int ResourceImporterMP3::get_preset_count() const { + return 0; +} + +String ResourceImporterMP3::get_preset_name(int p_idx) const { + return String(); +} + +void ResourceImporterMP3::get_import_options(List<ImportOption> *r_options, int p_preset) const { + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0)); +} + +Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { + bool loop = p_options["loop"]; + float loop_offset = p_options["loop_offset"]; + + FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); + + ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + + size_t len = f->get_len(); + + Vector<uint8_t> data; + data.resize(len); + uint8_t *w = data.ptrw(); + + f->get_buffer(w, len); + + memdelete(f); + + Ref<AudioStreamMP3> mp3_stream; + mp3_stream.instance(); + + mp3_stream->set_data(data); + ERR_FAIL_COND_V(!mp3_stream->get_data().size(), ERR_FILE_CORRUPT); + mp3_stream->set_loop(loop); + mp3_stream->set_loop_offset(loop_offset); + + return ResourceSaver::save(p_save_path + ".mp3str", mp3_stream); +} + +ResourceImporterMP3::ResourceImporterMP3() { +} diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h new file mode 100644 index 0000000000..c1e8315e21 --- /dev/null +++ b/modules/minimp3/resource_importer_mp3.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* resource_importer_mp3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 RESOURCE_IMPORTER_MP3_H +#define RESOURCE_IMPORTER_MP3_H + +#include "audio_stream_mp3.h" +#include "core/io/resource_importer.h" + +class ResourceImporterMP3 : public ResourceImporter { + GDCLASS(ResourceImporterMP3, ResourceImporter); + +public: + virtual String get_importer_name() const override; + virtual String get_visible_name() const override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual String get_save_extension() const override; + virtual String get_resource_type() const override; + + virtual int get_preset_count() const override; + virtual String get_preset_name(int p_idx) const override; + + virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override; + virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override; + + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; + + ResourceImporterMP3(); +}; + +#endif // RESOURCE_IMPORTER_MP3_H diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index 6057004166..9b10bac2f0 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -97,6 +97,7 @@ def configure(env, env_mono): copy_mono_root = env["copy_mono_root"] mono_prefix = env["mono_prefix"] + mono_bcl = env["mono_bcl"] mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"] @@ -397,7 +398,7 @@ def configure(env, env_mono): if tools_enabled: # Only supported for editor builds. - copy_mono_root_files(env, mono_root) + copy_mono_root_files(env, mono_root, mono_bcl) def make_template_dir(env, mono_root): @@ -430,7 +431,7 @@ def make_template_dir(env, mono_root): copy_mono_shared_libs(env, mono_root, template_mono_root_dir) -def copy_mono_root_files(env, mono_root): +def copy_mono_root_files(env, mono_root, mono_bcl): from glob import glob from shutil import copy from shutil import rmtree @@ -455,7 +456,7 @@ def copy_mono_root_files(env, mono_root): # Copy framework assemblies - mono_framework_dir = os.path.join(mono_root, "lib", "mono", "4.5") + mono_framework_dir = mono_bcl or os.path.join(mono_root, "lib", "mono", "4.5") mono_framework_facades_dir = os.path.join(mono_framework_dir, "Facades") editor_mono_framework_dir = os.path.join(editor_mono_root_dir, "lib", "mono", "4.5") diff --git a/modules/mono/config.py b/modules/mono/config.py index c4a6b408e6..4c851a2989 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -27,6 +27,14 @@ def configure(env): PathVariable.PathAccept, ) ) + envvars.Add( + PathVariable( + "mono_bcl", + "Path to a custom Mono BCL (Base Class Library) directory for the target platform", + "", + PathVariable.PathAccept, + ) + ) envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static)) envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True)) envvars.Add(BoolVariable("build_cil", "Build C# solutions", True)) diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs index 9514cc9622..1a1639aac7 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs @@ -2,6 +2,7 @@ using Godot; using System; using Godot.Collections; using GodotTools.Internals; +using JetBrains.Annotations; using File = GodotTools.Utils.File; using Path = System.IO.Path; @@ -26,6 +27,9 @@ namespace GodotTools.Build private TextEdit buildLog; private PopupMenu issuesListContextMenu; + private readonly object pendingBuildLogTextLock = new object(); + [NotNull] private string pendingBuildLogText = string.Empty; + [Signal] public event Action BuildStateChanged; public bool HasBuildExited { get; private set; } = false; @@ -240,16 +244,34 @@ namespace GodotTools.Build EmitSignal(nameof(BuildStateChanged)); } + private void UpdateBuildLogText() + { + lock (pendingBuildLogTextLock) + { + buildLog.Text += pendingBuildLogText; + pendingBuildLogText = string.Empty; + ScrollToLastNonEmptyLogLine(); + } + } + private void StdOutputReceived(string text) { - buildLog.Text += text + "\n"; - ScrollToLastNonEmptyLogLine(); + lock (pendingBuildLogTextLock) + { + if (pendingBuildLogText.Length == 0) + CallDeferred(nameof(UpdateBuildLogText)); + pendingBuildLogText += text + "\n"; + } } private void StdErrorReceived(string text) { - buildLog.Text += text + "\n"; - ScrollToLastNonEmptyLogLine(); + lock (pendingBuildLogTextLock) + { + if (pendingBuildLogText.Length == 0) + CallDeferred(nameof(UpdateBuildLogText)); + pendingBuildLogText += text + "\n"; + } } private void ScrollToLastNonEmptyLogLine() @@ -377,12 +399,14 @@ namespace GodotTools.Build BuildManager.BuildStarted += BuildStarted; BuildManager.BuildFinished += BuildFinished; // StdOutput/Error can be received from different threads, so we need to use CallDeferred - BuildManager.StdOutputReceived += line => CallDeferred(nameof(StdOutputReceived), line); - BuildManager.StdErrorReceived += line => CallDeferred(nameof(StdErrorReceived), line); + BuildManager.StdOutputReceived += StdOutputReceived; + BuildManager.StdErrorReceived += StdErrorReceived; } public void OnBeforeSerialize() { + // In case it didn't update yet. We don't want to have to serialize any pending output. + UpdateBuildLogText(); } public void OnAfterDeserialize() diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 6fefcd48a4..0cc1bb5f46 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -45,7 +45,7 @@ class BindingsGenerator { struct ConstantInterface { String name; String proxy_name; - int value; + int value = 0; const DocData::ConstantDoc *const_doc; ConstantInterface() {} @@ -75,7 +75,7 @@ class BindingsGenerator { struct PropertyInterface { StringName cname; String proxy_name; - int index; + int index = 0; StringName setter; StringName getter; @@ -480,7 +480,7 @@ class BindingsGenerator { String im_type_out; // Return type for the C# method declaration. Also used as companion of [unique_siq] String im_sig; // Signature for the C# method declaration String unique_sig; // Unique signature to avoid duplicates in containers - bool editor_only; + bool editor_only = false; InternalCall() {} diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index 1a0d5743ae..b006eed69f 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -55,10 +55,10 @@ MonoAssemblyName *new_mono_assembly_name() { struct AssemblyRefInfo { String name; - uint16_t major; - uint16_t minor; - uint16_t build; - uint16_t revision; + uint16_t major = 0; + uint16_t minor = 0; + uint16_t build = 0; + uint16_t revision = 0; }; AssemblyRefInfo get_assemblyref_name(MonoImage *p_image, int index) { diff --git a/modules/mono/editor/script_class_parser.h b/modules/mono/editor/script_class_parser.h index 3c55fa07a7..deb6061191 100644 --- a/modules/mono/editor/script_class_parser.h +++ b/modules/mono/editor/script_class_parser.h @@ -45,22 +45,22 @@ public: }; String name; - Type type; + Type type = NAMESPACE_DECL; }; struct ClassDecl { String name; String namespace_; Vector<String> base; - bool nested; + bool nested = false; }; private: String code; - int idx; - int line; + int idx = 0; + int line = 0; String error_str; - bool error; + bool error = false; Variant value; Vector<ClassDecl> classes; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs index b33490f9cb..bd3bcb0c58 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs @@ -120,13 +120,13 @@ namespace Godot /// <param name="b">The destination quaternion.</param> /// <param name="preA">A quaternion before this quaternion.</param> /// <param name="postB">A quaternion after `b`.</param> - /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated quaternion.</returns> - public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t t) + public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t weight) { - real_t t2 = (1.0f - t) * t * 2f; - Quat sp = Slerp(b, t); - Quat sq = preA.Slerpni(postB, t); + real_t t2 = (1.0f - weight) * weight * 2f; + Quat sp = Slerp(b, weight); + Quat sq = preA.Slerpni(postB, weight); return sp.Slerpni(sq, t2); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index d536b14eac..b74dd6f4f4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -194,15 +194,16 @@ namespace Godot /// <param name="b">The destination vector.</param> /// <param name="preA">A vector before this vector.</param> /// <param name="postB">A vector after `b`.</param> - /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> - public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t) + public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight) { Vector2 p0 = preA; Vector2 p1 = this; Vector2 p2 = b; Vector2 p3 = postB; + real_t t = weight; real_t t2 = t * t; real_t t3 = t2 * t; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 4a4a2a43cd..07f5b3c38e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -161,15 +161,16 @@ namespace Godot /// <param name="b">The destination vector.</param> /// <param name="preA">A vector before this vector.</param> /// <param name="postB">A vector after `b`.</param> - /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> - public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t t) + public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight) { Vector3 p0 = preA; Vector3 p1 = this; Vector3 p2 = b; Vector3 p3 = postB; + real_t t = weight; real_t t2 = t * t; real_t t3 = t2 * t; diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index 6575cbc1c8..b734f52e4e 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -290,7 +290,7 @@ bool GDMonoClass::has_public_parameterless_ctor() { return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC; } -GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) { +GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_params_count) { MethodKey key = MethodKey(p_name, p_params_count); GDMonoMethod **match = methods.getptr(key); @@ -330,7 +330,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName return get_method(p_raw_method, p_name, params_count); } -GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count) { +GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count) { ERR_FAIL_NULL_V(p_raw_method, nullptr); MethodKey key = MethodKey(p_name, p_params_count); diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index 87db2fa033..b93dfec30a 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -59,13 +59,12 @@ class GDMonoClass { MethodKey() {} - MethodKey(const StringName &p_name, int p_params_count) { - name = p_name; - params_count = p_params_count; + MethodKey(const StringName &p_name, uint16_t p_params_count) : + name(p_name), params_count(p_params_count) { } StringName name; - int params_count; + uint16_t params_count = 0; }; StringName namespace_name; @@ -139,10 +138,10 @@ public: bool implements_interface(GDMonoClass *p_interface); bool has_public_parameterless_ctor(); - GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0); + GDMonoMethod *get_method(const StringName &p_name, uint16_t p_params_count = 0); GDMonoMethod *get_method(MonoMethod *p_raw_method); GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name); - GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count); + GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count); GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace); GDMonoField *get_field(const StringName &p_name); diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 00a1e1e507..61d7f64a2a 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -46,29 +46,15 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) { } void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) { -#define SET_FROM_STRUCT(m_type) \ - { \ - GDMonoMarshal::M_##m_type from = MARSHALLED_OUT(m_type, p_value.operator ::m_type()); \ - mono_field_set_value(p_object, mono_field, &from); \ - } - -#define SET_FROM_ARRAY(m_type) \ - { \ - MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \ - mono_field_set_value(p_object, mono_field, managed); \ - } - switch (type.type_encoding) { case MONO_TYPE_BOOLEAN: { MonoBoolean val = p_value.operator bool(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_CHAR: { int16_t val = p_value.operator unsigned short(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_I1: { int8_t val = p_value.operator signed char(); mono_field_set_value(p_object, mono_field, &val); @@ -85,7 +71,6 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ int64_t val = p_value.operator int64_t(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_U1: { uint8_t val = p_value.operator unsigned char(); mono_field_set_value(p_object, mono_field, &val); @@ -102,93 +87,92 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ uint64_t val = p_value.operator uint64_t(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_R4: { float val = p_value.operator float(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_R8: { double val = p_value.operator double(); mono_field_set_value(p_object, mono_field, &val); } break; - - case MONO_TYPE_STRING: { - if (p_value.get_type() == Variant::NIL) { - // Otherwise, Variant -> String would return the string "Null" - MonoString *mono_string = nullptr; - mono_field_set_value(p_object, mono_field, mono_string); - } else { - MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value); - mono_field_set_value(p_object, mono_field, mono_string); - } - } break; - case MONO_TYPE_VALUETYPE: { GDMonoClass *tclass = type.type_class; if (tclass == CACHED_CLASS(Vector2)) { - SET_FROM_STRUCT(Vector2); + GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Vector2i)) { - SET_FROM_STRUCT(Vector2i); + GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Rect2)) { - SET_FROM_STRUCT(Rect2); + GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Rect2i)) { - SET_FROM_STRUCT(Rect2i); + GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Transform2D)) { - SET_FROM_STRUCT(Transform2D); + GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Vector3)) { - SET_FROM_STRUCT(Vector3); + GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Vector3i)) { - SET_FROM_STRUCT(Vector3i); + GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Basis)) { - SET_FROM_STRUCT(Basis); + GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Quat)) { - SET_FROM_STRUCT(Quat); + GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Transform)) { - SET_FROM_STRUCT(Transform); + GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(AABB)) { - SET_FROM_STRUCT(AABB); + GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Color)) { - SET_FROM_STRUCT(Color); + GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Plane)) { - SET_FROM_STRUCT(Plane); + GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); + mono_field_set_value(p_object, mono_field, &from); break; } @@ -267,118 +251,35 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + tclass->get_name() + "'."); } break; - + case MONO_TYPE_STRING: { + if (p_value.get_type() == Variant::NIL) { + // Otherwise, Variant -> String would return the string "Null" + MonoString *mono_string = nullptr; + mono_field_set_value(p_object, mono_field, mono_string); + } else { + MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value); + mono_field_set_value(p_object, mono_field, mono_string); + } + } break; case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type()); - - if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { - SET_FROM_ARRAY(Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { - SET_FROM_ARRAY(PackedByteArray); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { - SET_FROM_ARRAY(PackedInt32Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) { - SET_FROM_ARRAY(PackedInt64Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(float)) { - SET_FROM_ARRAY(PackedFloat32Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(double)) { - SET_FROM_ARRAY(PackedFloat64Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(String)) { - SET_FROM_ARRAY(PackedStringArray); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { - SET_FROM_ARRAY(PackedVector2Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { - SET_FROM_ARRAY(PackedVector3Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(Color)) { - SET_FROM_ARRAY(PackedColorArray); - break; - } - - GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); - if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) { - MonoArray *managed = GDMonoMarshal::Array_to_mono_array(p_value.operator ::Array(), array_type_class); + MonoArray *managed = GDMonoMarshal::variant_to_mono_array(p_value, type.type_class); + if (likely(managed != nullptr)) { mono_field_set_value(p_object, mono_field, managed); - break; } - - ERR_FAIL_MSG("Attempted to convert Variant to a managed array of unmarshallable element type."); } break; - case MONO_TYPE_CLASS: { - GDMonoClass *type_class = type.type_class; - - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *()); + MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_class(p_value, type.type_class); + if (likely(managed != nullptr)) { mono_field_set_value(p_object, mono_field, managed); - break; } - - if (CACHED_CLASS(StringName) == type_class) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName()); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - if (CACHED_CLASS(NodePath) == type_class) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath()); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - if (CACHED_CLASS(RID) == type_class) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator ::RID()); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // Godot.Collections.Dictionary or IDictionary - if (CACHED_CLASS(Dictionary) == type_class || type_class == CACHED_CLASS(System_Collections_IDictionary)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary)); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // Godot.Collections.Array or ICollection or IEnumerable - if (CACHED_CLASS(Array) == type_class || - type_class == CACHED_CLASS(System_Collections_ICollection) || - type_class == CACHED_CLASS(System_Collections_IEnumerable)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); + } break; + case MONO_TYPE_GENERICINST: { + MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_genericinst(p_value, type.type_class); + if (likely(managed != nullptr)) { mono_field_set_value(p_object, mono_field, managed); - break; } - - ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + type_class->get_name() + "'."); } break; - case MONO_TYPE_OBJECT: { // Variant switch (p_value.get_type()) { @@ -404,43 +305,56 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ mono_field_set_value(p_object, mono_field, mono_string); } break; case Variant::VECTOR2: { - SET_FROM_STRUCT(Vector2); + GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::VECTOR2I: { - SET_FROM_STRUCT(Vector2i); + GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::RECT2: { - SET_FROM_STRUCT(Rect2); + GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::RECT2I: { - SET_FROM_STRUCT(Rect2i); + GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::VECTOR3: { - SET_FROM_STRUCT(Vector3); + GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::VECTOR3I: { - SET_FROM_STRUCT(Vector3i); + GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::TRANSFORM2D: { - SET_FROM_STRUCT(Transform2D); + GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::PLANE: { - SET_FROM_STRUCT(Plane); + GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::QUAT: { - SET_FROM_STRUCT(Quat); + GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::AABB: { - SET_FROM_STRUCT(AABB); + GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::BASIS: { - SET_FROM_STRUCT(Basis); + GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::TRANSFORM: { - SET_FROM_STRUCT(Transform); + GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::COLOR: { - SET_FROM_STRUCT(Color); + GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::STRING_NAME: { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName()); @@ -475,106 +389,49 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_BYTE_ARRAY: { - SET_FROM_ARRAY(PackedByteArray); + MonoArray *managed = GDMonoMarshal::PackedByteArray_to_mono_array(p_value.operator ::PackedByteArray()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_INT32_ARRAY: { - SET_FROM_ARRAY(PackedInt32Array); + MonoArray *managed = GDMonoMarshal::PackedInt32Array_to_mono_array(p_value.operator ::PackedInt32Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_INT64_ARRAY: { - SET_FROM_ARRAY(PackedInt64Array); + MonoArray *managed = GDMonoMarshal::PackedInt64Array_to_mono_array(p_value.operator ::PackedInt64Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_FLOAT32_ARRAY: { - SET_FROM_ARRAY(PackedFloat32Array); + MonoArray *managed = GDMonoMarshal::PackedFloat32Array_to_mono_array(p_value.operator ::PackedFloat32Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_FLOAT64_ARRAY: { - SET_FROM_ARRAY(PackedFloat64Array); + MonoArray *managed = GDMonoMarshal::PackedFloat64Array_to_mono_array(p_value.operator ::PackedFloat64Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_STRING_ARRAY: { - SET_FROM_ARRAY(PackedStringArray); + MonoArray *managed = GDMonoMarshal::PackedStringArray_to_mono_array(p_value.operator ::PackedStringArray()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_VECTOR2_ARRAY: { - SET_FROM_ARRAY(PackedVector2Array); + MonoArray *managed = GDMonoMarshal::PackedVector2Array_to_mono_array(p_value.operator ::PackedVector2Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_VECTOR3_ARRAY: { - SET_FROM_ARRAY(PackedVector3Array); + MonoArray *managed = GDMonoMarshal::PackedVector3Array_to_mono_array(p_value.operator ::PackedVector3Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_COLOR_ARRAY: { - SET_FROM_ARRAY(PackedColorArray); + MonoArray *managed = GDMonoMarshal::PackedColorArray_to_mono_array(p_value.operator ::PackedColorArray()); + mono_field_set_value(p_object, mono_field, managed); } break; default: break; } } break; - - case MONO_TYPE_GENERICINST: { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type()); - - // Godot.Collections.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // Godot.Collections.Array<T> - if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // System.Collections.Generic.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { - MonoReflectionType *key_reftype = nullptr; - MonoReflectionType *value_reftype = nullptr; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - MonoObject *managed = GDMonoMarshal::Dictionary_to_system_generic_dict(p_value.operator Dictionary(), - type.type_class, key_reftype, value_reftype); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // System.Collections.Generic.List<T> - if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { - MonoReflectionType *elem_reftype = nullptr; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - MonoObject *managed = GDMonoMarshal::Array_to_system_generic_list(p_value.operator Array(), - type.type_class, elem_reftype); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // IDictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { - MonoReflectionType *key_reftype; - MonoReflectionType *value_reftype; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); - - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), godot_dict_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // ICollection<T> or IEnumerable<T> - if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { - MonoReflectionType *elem_reftype; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); - - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), godot_array_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - } break; - default: { ERR_PRINT("Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding) + "."); } break; } - -#undef SET_FROM_ARRAY_AND_BREAK -#undef SET_FROM_STRUCT_AND_BREAK } MonoObject *GDMonoField::get_value(MonoObject *p_object) { diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index b8ee0204c4..7584e7ff0d 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -160,13 +160,13 @@ void GDMonoLog::initialize() { OS::Date date_now = OS::get_singleton()->get_date(); OS::Time time_now = OS::get_singleton()->get_time(); - String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d", + String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d", date_now.year, date_now.month, date_now.day, time_now.hour, time_now.min, time_now.sec); - log_file_name += str_format(" (%d)", OS::get_singleton()->get_process_id()); + log_file_name += str_format("_%d", OS::get_singleton()->get_process_id()); - log_file_name += ".txt"; + log_file_name += ".log"; log_file_path = logs_dir.plus_file(log_file_name); diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index eee880ba60..64b350f270 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -311,152 +311,590 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_ return false; } -MonoObject *variant_to_mono_object(const Variant *p_var) { - ManagedType type; +MonoString *variant_to_mono_string(const Variant &p_var) { + if (p_var.get_type() == Variant::NIL) { + return nullptr; // Otherwise, Variant -> String would return the string "Null" + } + return mono_string_from_godot(p_var.operator String()); +} + +MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class) { + MonoArrayType *array_type = mono_type_get_array_type(p_type_class->get_mono_type()); + + if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { + return Array_to_mono_array(p_var.operator Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { + return PackedByteArray_to_mono_array(p_var.operator PackedByteArray()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { + return PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) { + return PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(float)) { + return PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(double)) { + return PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(String)) { + return PackedStringArray_to_mono_array(p_var.operator PackedStringArray()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { + return PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { + return PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(Color)) { + return PackedColorArray_to_mono_array(p_var.operator PackedColorArray()); + } + + if (mono_class_is_assignable_from(CACHED_CLASS(GodotObject)->get_mono_ptr(), array_type->eklass)) { + return Array_to_mono_array(p_var.operator ::Array(), array_type->eklass); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to array of unsupported element type:" + + GDMonoClass::get_full_name(array_type->eklass) + "'."); +} + +MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class) { + // GodotObject + if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) { + return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); + } + + if (CACHED_CLASS(StringName) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator StringName()); + } + + if (CACHED_CLASS(NodePath) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator NodePath()); + } - type.type_encoding = MONO_TYPE_OBJECT; - // type.type_class is not needed when we specify the MONO_TYPE_OBJECT encoding + if (CACHED_CLASS(RID) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator ::RID()); + } + + // Godot.Collections.Dictionary or IDictionary + if (CACHED_CLASS(Dictionary) == p_type_class || CACHED_CLASS(System_Collections_IDictionary) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary)); + } - return variant_to_mono_object(p_var, type); + // Godot.Collections.Array or ICollection or IEnumerable + if (CACHED_CLASS(Array) == p_type_class || + CACHED_CLASS(System_Collections_ICollection) == p_type_class || + CACHED_CLASS(System_Collections_IEnumerable) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array)); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type: '" + + p_type_class->get_full_name() + "'."); } -MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) { +MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class) { + MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type_class->get_mono_type()); + + // Godot.Collections.Dictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), p_type_class); + } + + // Godot.Collections.Array<T> + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { + return GDMonoUtils::create_managed_from(p_var.operator Array(), p_type_class); + } + + // System.Collections.Generic.Dictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { + MonoReflectionType *key_reftype = nullptr; + MonoReflectionType *value_reftype = nullptr; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + return Dictionary_to_system_generic_dict(p_var.operator Dictionary(), p_type_class, key_reftype, value_reftype); + } + + // System.Collections.Generic.List<T> + if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { + MonoReflectionType *elem_reftype = nullptr; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + return Array_to_system_generic_list(p_var.operator Array(), p_type_class, elem_reftype); + } + + // IDictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { + MonoReflectionType *key_reftype; + MonoReflectionType *value_reftype; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); + + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), godot_dict_class); + } + + // ICollection<T> or IEnumerable<T> + if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { + MonoReflectionType *elem_reftype; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); + + return GDMonoUtils::create_managed_from(p_var.operator Array(), godot_array_class); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported generic type: '" + + p_type_class->get_full_name() + "'."); +} + +MonoObject *variant_to_mono_object(const Variant &p_var) { + // Variant + switch (p_var.get_type()) { + case Variant::BOOL: { + MonoBoolean val = p_var.operator bool(); + return BOX_BOOLEAN(val); + } + case Variant::INT: { + int64_t val = p_var.operator int64_t(); + return BOX_INT64(val); + } + case Variant::FLOAT: { +#ifdef REAL_T_IS_DOUBLE + double val = p_var.operator double(); + return BOX_DOUBLE(val); +#else + float val = p_var.operator float(); + return BOX_FLOAT(val); +#endif + } + case Variant::STRING: + return (MonoObject *)mono_string_from_godot(p_var.operator String()); + case Variant::VECTOR2: { + GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var.operator ::Vector2()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); + } + case Variant::VECTOR2I: { + GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var.operator ::Vector2i()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from); + } + case Variant::RECT2: { + GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var.operator ::Rect2()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); + } + case Variant::RECT2I: { + GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var.operator ::Rect2i()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from); + } + case Variant::VECTOR3: { + GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var.operator ::Vector3()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); + } + case Variant::VECTOR3I: { + GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var.operator ::Vector3i()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from); + } + case Variant::TRANSFORM2D: { + GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var.operator ::Transform2D()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); + } + case Variant::PLANE: { + GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); + } + case Variant::QUAT: { + GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var.operator ::Quat()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); + } + case Variant::AABB: { + GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); + } + case Variant::BASIS: { + GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); + } + case Variant::TRANSFORM: { + GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var.operator ::Transform()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); + } + case Variant::COLOR: { + GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); + } + case Variant::STRING_NAME: + return GDMonoUtils::create_managed_from(p_var.operator StringName()); + case Variant::NODE_PATH: + return GDMonoUtils::create_managed_from(p_var.operator NodePath()); + case Variant::RID: + return GDMonoUtils::create_managed_from(p_var.operator ::RID()); + case Variant::OBJECT: + return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); + case Variant::CALLABLE: { + GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from); + } + case Variant::SIGNAL: { + GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from); + } + case Variant::DICTIONARY: + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary)); + case Variant::ARRAY: + return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array)); + case Variant::PACKED_BYTE_ARRAY: + return (MonoObject *)PackedByteArray_to_mono_array(p_var.operator PackedByteArray()); + case Variant::PACKED_INT32_ARRAY: + return (MonoObject *)PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array()); + case Variant::PACKED_INT64_ARRAY: + return (MonoObject *)PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array()); + case Variant::PACKED_FLOAT32_ARRAY: + return (MonoObject *)PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array()); + case Variant::PACKED_FLOAT64_ARRAY: + return (MonoObject *)PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array()); + case Variant::PACKED_STRING_ARRAY: + return (MonoObject *)PackedStringArray_to_mono_array(p_var.operator PackedStringArray()); + case Variant::PACKED_VECTOR2_ARRAY: + return (MonoObject *)PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array()); + case Variant::PACKED_VECTOR3_ARRAY: + return (MonoObject *)PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array()); + case Variant::PACKED_COLOR_ARRAY: + return (MonoObject *)PackedColorArray_to_mono_array(p_var.operator PackedColorArray()); + default: + return nullptr; + } +} + +size_t variant_get_managed_unboxed_size(const ManagedType &p_type) { + // This method prints no errors for unsupported types. It's called on all methods, not only + // those that end up being invoked with Variant parameters. + + // For MonoObject* we return 0, as it doesn't need to be stored. + constexpr size_t zero_for_mono_object = 0; + + switch (p_type.type_encoding) { + case MONO_TYPE_BOOLEAN: + return sizeof(MonoBoolean); + case MONO_TYPE_CHAR: + return sizeof(uint16_t); + case MONO_TYPE_I1: + return sizeof(int8_t); + case MONO_TYPE_I2: + return sizeof(int16_t); + case MONO_TYPE_I4: + return sizeof(int32_t); + case MONO_TYPE_I8: + return sizeof(int64_t); + case MONO_TYPE_U1: + return sizeof(uint8_t); + case MONO_TYPE_U2: + return sizeof(uint16_t); + case MONO_TYPE_U4: + return sizeof(uint32_t); + case MONO_TYPE_U8: + return sizeof(uint64_t); + case MONO_TYPE_R4: + return sizeof(float); + case MONO_TYPE_R8: + return sizeof(double); + case MONO_TYPE_VALUETYPE: { + GDMonoClass *vtclass = p_type.type_class; + +#define RETURN_CHECK_FOR_STRUCT(m_struct) \ + if (vtclass == CACHED_CLASS(m_struct)) { \ + return sizeof(M_##m_struct); \ + } + + RETURN_CHECK_FOR_STRUCT(Vector2); + RETURN_CHECK_FOR_STRUCT(Vector2i); + RETURN_CHECK_FOR_STRUCT(Rect2); + RETURN_CHECK_FOR_STRUCT(Rect2i); + RETURN_CHECK_FOR_STRUCT(Transform2D); + RETURN_CHECK_FOR_STRUCT(Vector3); + RETURN_CHECK_FOR_STRUCT(Vector3i); + RETURN_CHECK_FOR_STRUCT(Basis); + RETURN_CHECK_FOR_STRUCT(Quat); + RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(AABB); + RETURN_CHECK_FOR_STRUCT(Color); + RETURN_CHECK_FOR_STRUCT(Plane); + RETURN_CHECK_FOR_STRUCT(Callable); + RETURN_CHECK_FOR_STRUCT(SignalInfo); + +#undef RETURN_CHECK_FOR_STRUCT + + if (mono_class_is_enum(vtclass->get_mono_ptr())) { + MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); + switch (mono_type_get_type(enum_basetype)) { + case MONO_TYPE_BOOLEAN: + return sizeof(MonoBoolean); + case MONO_TYPE_CHAR: + return sizeof(uint16_t); + case MONO_TYPE_I1: + return sizeof(int8_t); + case MONO_TYPE_I2: + return sizeof(int16_t); + case MONO_TYPE_I4: + return sizeof(int32_t); + case MONO_TYPE_I8: + return sizeof(int64_t); + case MONO_TYPE_U1: + return sizeof(uint8_t); + case MONO_TYPE_U2: + return sizeof(uint16_t); + case MONO_TYPE_U4: + return sizeof(uint32_t); + case MONO_TYPE_U8: + return sizeof(uint64_t); + default: { + // Enum with unsupported base type. We return nullptr MonoObject* on error. + return zero_for_mono_object; + } + } + } + + // Enum with unsupported value type. We return nullptr MonoObject* on error. + } break; + case MONO_TYPE_STRING: + return zero_for_mono_object; + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_GENERICINST: + return zero_for_mono_object; + case MONO_TYPE_OBJECT: + return zero_for_mono_object; + } + + // Unsupported type encoding. We return nullptr MonoObject* on error. + return zero_for_mono_object; +} + +void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) { +#define RETURN_TYPE_VAL(m_type, m_val) \ + *reinterpret_cast<m_type *>(r_buffer) = m_val; \ + r_offset += sizeof(m_type); \ + return r_buffer; + + switch (p_type.type_encoding) { + case MONO_TYPE_BOOLEAN: + RETURN_TYPE_VAL(MonoBoolean, (MonoBoolean)p_var.operator bool()); + case MONO_TYPE_CHAR: + RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short()); + case MONO_TYPE_I1: + RETURN_TYPE_VAL(int8_t, p_var.operator signed char()); + case MONO_TYPE_I2: + RETURN_TYPE_VAL(int16_t, p_var.operator signed short()); + case MONO_TYPE_I4: + RETURN_TYPE_VAL(int32_t, p_var.operator signed int()); + case MONO_TYPE_I8: + RETURN_TYPE_VAL(int64_t, p_var.operator int64_t()); + case MONO_TYPE_U1: + RETURN_TYPE_VAL(uint8_t, p_var.operator unsigned char()); + case MONO_TYPE_U2: + RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short()); + case MONO_TYPE_U4: + RETURN_TYPE_VAL(uint32_t, p_var.operator unsigned int()); + case MONO_TYPE_U8: + RETURN_TYPE_VAL(uint64_t, p_var.operator uint64_t()); + case MONO_TYPE_R4: + RETURN_TYPE_VAL(float, p_var.operator float()); + case MONO_TYPE_R8: + RETURN_TYPE_VAL(double, p_var.operator double()); + case MONO_TYPE_VALUETYPE: { + GDMonoClass *vtclass = p_type.type_class; + +#define RETURN_CHECK_FOR_STRUCT(m_struct) \ + if (vtclass == CACHED_CLASS(m_struct)) { \ + GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \ + RETURN_TYPE_VAL(M_##m_struct, from); \ + } + + RETURN_CHECK_FOR_STRUCT(Vector2); + RETURN_CHECK_FOR_STRUCT(Vector2i); + RETURN_CHECK_FOR_STRUCT(Rect2); + RETURN_CHECK_FOR_STRUCT(Rect2i); + RETURN_CHECK_FOR_STRUCT(Transform2D); + RETURN_CHECK_FOR_STRUCT(Vector3); + RETURN_CHECK_FOR_STRUCT(Vector3i); + RETURN_CHECK_FOR_STRUCT(Basis); + RETURN_CHECK_FOR_STRUCT(Quat); + RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(AABB); + RETURN_CHECK_FOR_STRUCT(Color); + RETURN_CHECK_FOR_STRUCT(Plane); + +#undef RETURN_CHECK_FOR_STRUCT + + if (vtclass == CACHED_CLASS(Callable)) { + GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable()); + RETURN_TYPE_VAL(M_Callable, from); + } + + if (vtclass == CACHED_CLASS(SignalInfo)) { + GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal()); + RETURN_TYPE_VAL(M_SignalInfo, from); + } + + if (mono_class_is_enum(vtclass->get_mono_ptr())) { + MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); + switch (mono_type_get_type(enum_basetype)) { + case MONO_TYPE_BOOLEAN: { + MonoBoolean val = p_var.operator bool(); + RETURN_TYPE_VAL(MonoBoolean, val); + } + case MONO_TYPE_CHAR: { + uint16_t val = p_var.operator unsigned short(); + RETURN_TYPE_VAL(uint16_t, val); + } + case MONO_TYPE_I1: { + int8_t val = p_var.operator signed char(); + RETURN_TYPE_VAL(int8_t, val); + } + case MONO_TYPE_I2: { + int16_t val = p_var.operator signed short(); + RETURN_TYPE_VAL(int16_t, val); + } + case MONO_TYPE_I4: { + int32_t val = p_var.operator signed int(); + RETURN_TYPE_VAL(int32_t, val); + } + case MONO_TYPE_I8: { + int64_t val = p_var.operator int64_t(); + RETURN_TYPE_VAL(int64_t, val); + } + case MONO_TYPE_U1: { + uint8_t val = p_var.operator unsigned char(); + RETURN_TYPE_VAL(uint8_t, val); + } + case MONO_TYPE_U2: { + uint16_t val = p_var.operator unsigned short(); + RETURN_TYPE_VAL(uint16_t, val); + } + case MONO_TYPE_U4: { + uint32_t val = p_var.operator unsigned int(); + RETURN_TYPE_VAL(uint32_t, val); + } + case MONO_TYPE_U8: { + uint64_t val = p_var.operator uint64_t(); + RETURN_TYPE_VAL(uint64_t, val); + } + default: { + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + + GDMonoClass::get_full_name(mono_class_from_mono_type(enum_basetype)) + "'."); + } + } + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + + p_type.type_class->get_full_name() + "'."); + } break; +#undef RETURN_TYPE_VAL + case MONO_TYPE_STRING: + return variant_to_mono_string(p_var); + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + return variant_to_mono_array(p_var, p_type.type_class); + case MONO_TYPE_CLASS: + return variant_to_mono_object_of_class(p_var, p_type.type_class); + case MONO_TYPE_GENERICINST: + return variant_to_mono_object_of_genericinst(p_var, p_type.type_class); + case MONO_TYPE_OBJECT: + return variant_to_mono_object(p_var); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + + itos(p_type.type_encoding) + "."); +} + +MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) { switch (p_type.type_encoding) { case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_var->operator bool(); + MonoBoolean val = p_var.operator bool(); return BOX_BOOLEAN(val); } - case MONO_TYPE_CHAR: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_UINT16(val); } - case MONO_TYPE_I1: { - int8_t val = p_var->operator signed char(); + int8_t val = p_var.operator signed char(); return BOX_INT8(val); } case MONO_TYPE_I2: { - int16_t val = p_var->operator signed short(); + int16_t val = p_var.operator signed short(); return BOX_INT16(val); } case MONO_TYPE_I4: { - int32_t val = p_var->operator signed int(); + int32_t val = p_var.operator signed int(); return BOX_INT32(val); } case MONO_TYPE_I8: { - int64_t val = p_var->operator int64_t(); + int64_t val = p_var.operator int64_t(); return BOX_INT64(val); } - case MONO_TYPE_U1: { - uint8_t val = p_var->operator unsigned char(); + uint8_t val = p_var.operator unsigned char(); return BOX_UINT8(val); } case MONO_TYPE_U2: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_UINT16(val); } case MONO_TYPE_U4: { - uint32_t val = p_var->operator unsigned int(); + uint32_t val = p_var.operator unsigned int(); return BOX_UINT32(val); } case MONO_TYPE_U8: { - uint64_t val = p_var->operator uint64_t(); + uint64_t val = p_var.operator uint64_t(); return BOX_UINT64(val); } - case MONO_TYPE_R4: { - float val = p_var->operator float(); + float val = p_var.operator float(); return BOX_FLOAT(val); } case MONO_TYPE_R8: { - double val = p_var->operator double(); + double val = p_var.operator double(); return BOX_DOUBLE(val); } - - case MONO_TYPE_STRING: { - if (p_var->get_type() == Variant::NIL) { - return nullptr; // Otherwise, Variant -> String would return the string "Null" - } - return (MonoObject *)mono_string_from_godot(p_var->operator String()); - } break; - case MONO_TYPE_VALUETYPE: { GDMonoClass *vtclass = p_type.type_class; - if (vtclass == CACHED_CLASS(Vector2)) { - GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); - } - - if (vtclass == CACHED_CLASS(Vector2i)) { - GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from); - } - - if (vtclass == CACHED_CLASS(Rect2)) { - GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); - } - - if (vtclass == CACHED_CLASS(Rect2i)) { - GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from); - } - - if (vtclass == CACHED_CLASS(Transform2D)) { - GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); - } - - if (vtclass == CACHED_CLASS(Vector3)) { - GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); - } - - if (vtclass == CACHED_CLASS(Vector3i)) { - GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from); - } - - if (vtclass == CACHED_CLASS(Basis)) { - GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); - } - - if (vtclass == CACHED_CLASS(Quat)) { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); - } - - if (vtclass == CACHED_CLASS(Transform)) { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); - } - - if (vtclass == CACHED_CLASS(AABB)) { - GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); - } - - if (vtclass == CACHED_CLASS(Color)) { - GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); - } +#define RETURN_CHECK_FOR_STRUCT(m_struct) \ + if (vtclass == CACHED_CLASS(m_struct)) { \ + GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \ + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_struct), &from); \ + } - if (vtclass == CACHED_CLASS(Plane)) { - GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); - } + RETURN_CHECK_FOR_STRUCT(Vector2); + RETURN_CHECK_FOR_STRUCT(Vector2i); + RETURN_CHECK_FOR_STRUCT(Rect2); + RETURN_CHECK_FOR_STRUCT(Rect2i); + RETURN_CHECK_FOR_STRUCT(Transform2D); + RETURN_CHECK_FOR_STRUCT(Vector3); + RETURN_CHECK_FOR_STRUCT(Vector3i); + RETURN_CHECK_FOR_STRUCT(Basis); + RETURN_CHECK_FOR_STRUCT(Quat); + RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(AABB); + RETURN_CHECK_FOR_STRUCT(Color); + RETURN_CHECK_FOR_STRUCT(Plane); + +#undef RETURN_CHECK_FOR_STRUCT if (vtclass == CACHED_CLASS(Callable)) { - GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable()); + GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable()); return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from); } if (vtclass == CACHED_CLASS(SignalInfo)) { - GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal()); + GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal()); return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from); } @@ -465,316 +903,84 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype); switch (mono_type_get_type(enum_basetype)) { case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_var->operator bool(); + MonoBoolean val = p_var.operator bool(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_CHAR: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I1: { - int8_t val = p_var->operator signed char(); + int8_t val = p_var.operator signed char(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I2: { - int16_t val = p_var->operator signed short(); + int16_t val = p_var.operator signed short(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I4: { - int32_t val = p_var->operator signed int(); + int32_t val = p_var.operator signed int(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I8: { - int64_t val = p_var->operator int64_t(); + int64_t val = p_var.operator int64_t(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U1: { - uint8_t val = p_var->operator unsigned char(); + uint8_t val = p_var.operator unsigned char(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U2: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U4: { - uint32_t val = p_var->operator unsigned int(); + uint32_t val = p_var.operator unsigned int(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U8: { - uint64_t val = p_var->operator uint64_t(); + uint64_t val = p_var.operator uint64_t(); return BOX_ENUM(enum_baseclass, val); } default: { - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed enum value of unmarshallable base type."); + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + + GDMonoClass::get_full_name(enum_baseclass) + "'."); } } } - } break; - - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type()); - - if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { - return (MonoObject *)Array_to_mono_array(p_var->operator Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { - return (MonoObject *)PackedByteArray_to_mono_array(p_var->operator PackedByteArray()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { - return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) { - return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(float)) { - return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(double)) { - return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(String)) { - return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { - return (MonoObject *)PackedVector2Array_to_mono_array(p_var->operator PackedVector2Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { - return (MonoObject *)PackedVector3Array_to_mono_array(p_var->operator PackedVector3Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Color)) { - return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray()); - } - - GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); - if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) { - return (MonoObject *)Array_to_mono_array(p_var->operator Array(), array_type_class); - } - - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed array of unmarshallable element type."); - } break; - - case MONO_TYPE_CLASS: { - GDMonoClass *type_class = p_type.type_class; - - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); - } - - if (CACHED_CLASS(StringName) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator StringName()); - } - - if (CACHED_CLASS(NodePath) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator NodePath()); - } - - if (CACHED_CLASS(RID) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator ::RID()); - } - - // Godot.Collections.Dictionary or IDictionary - if (CACHED_CLASS(Dictionary) == type_class || CACHED_CLASS(System_Collections_IDictionary) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); - } - - // Godot.Collections.Array or ICollection or IEnumerable - if (CACHED_CLASS(Array) == type_class || - CACHED_CLASS(System_Collections_ICollection) == type_class || - CACHED_CLASS(System_Collections_IEnumerable) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); - } - } break; - case MONO_TYPE_OBJECT: { - // Variant - switch (p_var->get_type()) { - case Variant::BOOL: { - MonoBoolean val = p_var->operator bool(); - return BOX_BOOLEAN(val); - } - case Variant::INT: { - int64_t val = p_var->operator int64_t(); - return BOX_INT64(val); - } - case Variant::FLOAT: { -#ifdef REAL_T_IS_DOUBLE - double val = p_var->operator double(); - return BOX_DOUBLE(val); -#else - float val = p_var->operator float(); - return BOX_FLOAT(val); -#endif - } - case Variant::STRING: - return (MonoObject *)mono_string_from_godot(p_var->operator String()); - case Variant::VECTOR2: { - GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); - } - case Variant::VECTOR2I: { - GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from); - } - case Variant::RECT2: { - GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); - } - case Variant::RECT2I: { - GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from); - } - case Variant::VECTOR3: { - GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); - } - case Variant::VECTOR3I: { - GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from); - } - case Variant::TRANSFORM2D: { - GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); - } - case Variant::PLANE: { - GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); - } - case Variant::QUAT: { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); - } - case Variant::AABB: { - GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); - } - case Variant::BASIS: { - GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); - } - case Variant::TRANSFORM: { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); - } - case Variant::COLOR: { - GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); - } - case Variant::STRING_NAME: - return GDMonoUtils::create_managed_from(p_var->operator StringName()); - case Variant::NODE_PATH: - return GDMonoUtils::create_managed_from(p_var->operator NodePath()); - case Variant::RID: - return GDMonoUtils::create_managed_from(p_var->operator ::RID()); - case Variant::OBJECT: - return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); - case Variant::CALLABLE: { - GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from); - } - case Variant::SIGNAL: { - GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from); - } - case Variant::DICTIONARY: - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); - case Variant::ARRAY: - return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); - case Variant::PACKED_BYTE_ARRAY: - return (MonoObject *)PackedByteArray_to_mono_array(p_var->operator PackedByteArray()); - case Variant::PACKED_INT32_ARRAY: - return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array()); - case Variant::PACKED_INT64_ARRAY: - return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array()); - case Variant::PACKED_FLOAT32_ARRAY: - return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array()); - case Variant::PACKED_FLOAT64_ARRAY: - return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array()); - case Variant::PACKED_STRING_ARRAY: - return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray()); - case Variant::PACKED_VECTOR2_ARRAY: - return (MonoObject *)PackedVector2Array_to_mono_array(p_var->operator PackedVector2Array()); - case Variant::PACKED_VECTOR3_ARRAY: - return (MonoObject *)PackedVector3Array_to_mono_array(p_var->operator PackedVector3Array()); - case Variant::PACKED_COLOR_ARRAY: - return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray()); - default: - return nullptr; - } - break; - case MONO_TYPE_GENERICINST: { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); - - // Godot.Collections.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class); - } - - // Godot.Collections.Array<T> - if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class); - } - - // System.Collections.Generic.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { - MonoReflectionType *key_reftype = nullptr; - MonoReflectionType *value_reftype = nullptr; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - return Dictionary_to_system_generic_dict(p_var->operator Dictionary(), p_type.type_class, key_reftype, value_reftype); - } - - // System.Collections.Generic.List<T> - if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { - MonoReflectionType *elem_reftype = nullptr; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - return Array_to_system_generic_list(p_var->operator Array(), p_type.type_class, elem_reftype); - } - - // IDictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { - MonoReflectionType *key_reftype; - MonoReflectionType *value_reftype; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); - - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), godot_dict_class); - } - // ICollection<T> or IEnumerable<T> - if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { - MonoReflectionType *elem_reftype; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); - - return GDMonoUtils::create_managed_from(p_var->operator Array(), godot_array_class); - } - } break; + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + + p_type.type_class->get_full_name() + "'."); } break; + case MONO_TYPE_STRING: + return (MonoObject *)variant_to_mono_string(p_var); + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + return (MonoObject *)variant_to_mono_array(p_var, p_type.type_class); + case MONO_TYPE_CLASS: + return variant_to_mono_object_of_class(p_var, p_type.type_class); + case MONO_TYPE_GENERICINST: + return variant_to_mono_object_of_genericinst(p_var, p_type.type_class); + case MONO_TYPE_OBJECT: + return variant_to_mono_object(p_var); } - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to an unmarshallable managed type. Name: '" + - p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + "."); + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + + itos(p_type.type_encoding) + "."); } Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) { ERR_FAIL_COND_V(!p_type.type_class, Variant()); +#ifdef DEBUG_ENABLED + CRASH_COND_MSG(p_type.type_encoding == MONO_TYPE_OBJECT, "Type of object should be known."); +#endif + switch (p_type.type_encoding) { case MONO_TYPE_BOOLEAN: return (bool)unbox<MonoBoolean>(p_obj); - case MONO_TYPE_CHAR: return unbox<uint16_t>(p_obj); - case MONO_TYPE_I1: return unbox<int8_t>(p_obj); case MONO_TYPE_I2: @@ -783,7 +989,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return unbox<int32_t>(p_obj); case MONO_TYPE_I8: return unbox<int64_t>(p_obj); - case MONO_TYPE_U1: return unbox<uint8_t>(p_obj); case MONO_TYPE_U2: @@ -792,19 +997,10 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return unbox<uint32_t>(p_obj); case MONO_TYPE_U8: return unbox<uint64_t>(p_obj); - case MONO_TYPE_R4: return unbox<float>(p_obj); case MONO_TYPE_R8: return unbox<double>(p_obj); - - case MONO_TYPE_STRING: { - if (p_obj == nullptr) { - return Variant(); // NIL - } - return mono_string_to_godot_not_null((MonoString *)p_obj); - } break; - case MONO_TYPE_VALUETYPE: { GDMonoClass *vtclass = p_type.type_class; @@ -872,7 +1068,12 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return unbox<int32_t>(p_obj); } } break; - + case MONO_TYPE_STRING: { + if (p_obj == nullptr) { + return Variant(); // NIL + } + return mono_string_to_godot_not_null((MonoString *)p_obj); + } break; case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type()); @@ -928,7 +1129,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return Variant(); } } break; - case MONO_TYPE_CLASS: { GDMonoClass *type_class = p_type.type_class; @@ -973,7 +1173,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return ptr ? Variant(*ptr) : Variant(); } } break; - case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); @@ -1052,7 +1251,7 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) { ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj)); Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type); - if (var.get_type() == Variant::NIL && p_obj != nullptr) { + if (var.get_type() == Variant::NIL) { // `&& p_obj != nullptr` but omitted because always true // Cannot convert MonoObject* to Variant; fallback to 'ToString()'. MonoException *exc = nullptr; MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc); @@ -1115,9 +1314,10 @@ Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]] } MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) { - GDMonoClass *elem_class = ManagedType::from_reftype(p_elem_reftype).type_class; + MonoType *elem_type = mono_reflection_type_get_type(p_elem_reftype); + MonoClass *elem_class = mono_class_from_mono_type(elem_type); - String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + elem_class->get_type_desc() + ">)"; + String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + GDMonoUtils::get_type_desc(elem_type) + ">)"; GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true); CRASH_COND(ctor == nullptr); @@ -1156,9 +1356,9 @@ MonoArray *Array_to_mono_array(const Array &p_array) { return ret; } -MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class) { +MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class) { int length = p_array.size(); - MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class->get_mono_ptr(), length); + MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class, length); for (int i = 0; i < length; i++) { MonoObject *boxed = variant_to_mono_object(p_array[i]); diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index d1d5f1f202..6d8227f8b4 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -90,15 +90,40 @@ _FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) { // Variant -MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type); -MonoObject *variant_to_mono_object(const Variant *p_var); - -_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var) { - return variant_to_mono_object(&p_var); +size_t variant_get_managed_unboxed_size(const ManagedType &p_type); +void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset); +MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type); + +MonoObject *variant_to_mono_object(const Variant &p_var); +MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class); +MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class); +MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class); +MonoString *variant_to_mono_string(const Variant &p_var); + +// These overloads were added to avoid passing a `const Variant *` to the `const Variant &` +// parameter. That would result in the `Variant(bool)` copy constructor being called as +// pointers are implicitly converted to bool. Implicit conversions are f-ing evil. + +_FORCE_INLINE_ void *variant_to_managed_unboxed(const Variant *p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) { + return variant_to_managed_unboxed(*p_var, p_type, r_buffer, r_offset); } - -_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) { - return variant_to_mono_object(&p_var, p_type); +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) { + return variant_to_mono_object(*p_var, p_type); +} +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) { + return variant_to_mono_object(*p_var); +} +_FORCE_INLINE_ MonoArray *variant_to_mono_array(const Variant *p_var, GDMonoClass *p_type_class) { + return variant_to_mono_array(*p_var, p_type_class); +} +_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_class(const Variant *p_var, GDMonoClass *p_type_class) { + return variant_to_mono_object_of_class(*p_var, p_type_class); +} +_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_genericinst(const Variant *p_var, GDMonoClass *p_type_class) { + return variant_to_mono_object_of_genericinst(*p_var, p_type_class); +} +_FORCE_INLINE_ MonoString *variant_to_mono_string(const Variant *p_var) { + return variant_to_mono_string(*p_var); } Variant mono_object_to_variant(MonoObject *p_obj); @@ -120,7 +145,7 @@ Array system_generic_list_to_Array(MonoObject *p_obj, GDMonoClass *p_class, Mono // Array MonoArray *Array_to_mono_array(const Array &p_array); -MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class); +MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class); Array mono_array_to_Array(MonoArray *p_array); // PackedInt32Array diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 04f3b25a70..1d87726234 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -75,6 +75,10 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) { // clear the cache method_info_fetched = false; method_info = MethodInfo(); + + for (int i = 0; i < params_count; i++) { + params_buffer_size += GDMonoMarshal::variant_get_managed_unboxed_size(param_types[i]); + } } GDMonoClass *GDMonoMethod::get_enclosing_class() const { @@ -107,14 +111,15 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoObject *ret; if (params_count > 0) { - MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), params_count); + void **params = (void **)alloca(params_count * sizeof(void *)); + uint8_t *buffer = (uint8_t *)alloca(params_buffer_size); + unsigned int offset = 0; for (int i = 0; i < params_count; i++) { - MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]); - mono_array_setref(params, i, boxed_param); + params[i] = GDMonoMarshal::variant_to_managed_unboxed(p_params[i], param_types[i], buffer + offset, offset); } - ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc); + ret = GDMonoUtils::runtime_invoke(mono_method, p_object, params, &exc); } else { ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc); } @@ -279,16 +284,8 @@ const MethodInfo &GDMonoMethod::get_method_info() { return method_info; } -GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) { - name = p_name; - - mono_method = p_method; - - method_info_fetched = false; - - attrs_fetched = false; - attributes = nullptr; - +GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) : + name(p_name), mono_method(p_method) { _update_signature(); } diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index f78f57dca0..115bd998fa 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -38,15 +38,16 @@ class GDMonoMethod : public IMonoClassMember { StringName name; - int params_count; + uint16_t params_count; + unsigned int params_buffer_size = 0; ManagedType return_type; Vector<ManagedType> param_types; - bool method_info_fetched; + bool method_info_fetched = false; MethodInfo method_info; - bool attrs_fetched; - MonoCustomAttrInfo *attributes; + bool attrs_fetched = false; + MonoCustomAttrInfo *attributes = nullptr; void _update_signature(); void _update_signature(MonoMethodSignature *p_method_sig); @@ -72,7 +73,7 @@ public: _FORCE_INLINE_ MonoMethod *get_mono_ptr() const { return mono_method; } - _FORCE_INLINE_ int get_parameters_count() const { return params_count; } + _FORCE_INLINE_ uint16_t get_parameters_count() const { return params_count; } _FORCE_INLINE_ ManagedType get_return_type() const { return return_type; } MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = nullptr) const; diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index bc3be97102..1027c08a4a 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -149,10 +149,9 @@ bool GDMonoProperty::has_setter() { void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) { MonoMethod *prop_method = mono_property_get_set_method(mono_property); - MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1); - mono_array_setref(params, 0, p_value); + void *params[1] = { p_value }; MonoException *exc = nullptr; - GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc); + GDMonoUtils::runtime_invoke(prop_method, p_object, params, &exc); if (exc) { if (r_exc) { *r_exc = exc; diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 97fc4c57f9..05fd57255c 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -480,6 +480,7 @@ void set_pending_exception(MonoException *p_exc) { #else if (get_runtime_invoke_count() == 0) { debug_unhandled_exception(p_exc); + return; } if (!mono_runtime_set_pending_exception(p_exc, false)) { @@ -498,13 +499,6 @@ MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, M return ret; } -MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)r_exc); - GD_MONO_END_RUNTIME_INVOKE; - return ret; -} - MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) { GD_MONO_BEGIN_RUNTIME_INVOKE; MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 71c131f77c..faa3d24eeb 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -135,7 +135,6 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() { } MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc); -MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc); MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc); diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp index bd67b03c8e..f220abfb4c 100644 --- a/modules/mono/signal_awaiter_utils.cpp +++ b/modules/mono/signal_awaiter_utils.cpp @@ -48,18 +48,10 @@ Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signa } bool SignalAwaiterCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { + // Only called if both instances are of type SignalAwaiterCallable. Static cast is safe. const SignalAwaiterCallable *a = static_cast<const SignalAwaiterCallable *>(p_a); const SignalAwaiterCallable *b = static_cast<const SignalAwaiterCallable *>(p_b); - - if (a->target_id != b->target_id) { - return false; - } - - if (a->signal != b->signal) { - return false; - } - - return true; + return a->awaiter_handle.handle == b->awaiter_handle.handle; } bool SignalAwaiterCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { @@ -109,11 +101,15 @@ void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Va "Resumed after await, but class instance is gone."); #endif - MonoArray *signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount); + MonoArray *signal_args = nullptr; - for (int i = 0; i < p_argcount; i++) { - MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]); - mono_array_setref(signal_args, i, boxed); + if (p_argcount > 0) { + signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount); + + for (int i = 0; i < p_argcount; i++) { + MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]); + mono_array_setref(signal_args, i, boxed); + } } MonoObject *awaiter = awaiter_handle.get_target(); diff --git a/editor/run_settings_dialog.cpp b/modules/pvr/image_compress_pvrtc.cpp index b6dda4c5bb..6695a539d0 100644 --- a/editor/run_settings_dialog.cpp +++ b/modules/pvr/image_compress_pvrtc.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* run_settings_dialog.cpp */ +/* image_compress_pvrtc.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,58 +28,57 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "run_settings_dialog.h" +#include "image_compress_pvrtc.h" -void RunSettingsDialog::popup_run_settings() { - popup_centered(Size2(300, 150)); -} - -void RunSettingsDialog::set_custom_arguments(const String &p_arguments) { - arguments->set_text(p_arguments); -} +#include "core/io/image.h" +#include "core/object/reference.h" -String RunSettingsDialog::get_custom_arguments() const { - return arguments->get_text(); -} +#include <PvrTcEncoder.h> +#include <RgbaBitmap.h> -void RunSettingsDialog::_bind_methods() { - //ClassDB::bind_method("_browse_selected_file",&RunSettingsDialog::_browse_selected_file); -} +static void _compress_pvrtc1_4bpp(Image *p_img) { + Ref<Image> img = p_img->duplicate(); -void RunSettingsDialog::_run_mode_changed(int idx) { - if (idx == 0) { - arguments->set_editable(false); - } else { - arguments->set_editable(true); + bool make_mipmaps = false; + if (!img->is_size_po2() || img->get_width() != img->get_height()) { + make_mipmaps = img->has_mipmaps(); + img->resize_to_po2(true); + } + img->convert(Image::FORMAT_RGBA8); + if (!img->has_mipmaps() && make_mipmaps) { + img->generate_mipmaps(); } -} - -int RunSettingsDialog::get_run_mode() const { - return run_mode->get_selected(); -} -void RunSettingsDialog::set_run_mode(int p_run_mode) { - run_mode->select(p_run_mode); - arguments->set_editable(p_run_mode); -} + bool use_alpha = img->detect_alpha(); -RunSettingsDialog::RunSettingsDialog() { - /* SNAP DIALOG */ + Ref<Image> new_img; + new_img.instance(); + new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4); - VBoxContainer *vbc = memnew(VBoxContainer); - add_child(vbc); - //set_child_rect(vbc); + Vector<uint8_t> data = new_img->get_data(); + { + uint8_t *wr = data.ptrw(); + const uint8_t *r = img->get_data().ptr(); - run_mode = memnew(OptionButton); - vbc->add_margin_child(TTR("Run Mode:"), run_mode); - run_mode->add_item(TTR("Current Scene")); - run_mode->add_item(TTR("Main Scene")); - run_mode->connect("item_selected", callable_mp(this, &RunSettingsDialog::_run_mode_changed)); - arguments = memnew(LineEdit); - vbc->add_margin_child(TTR("Main Scene Arguments:"), arguments); - arguments->set_editable(false); + for (int i = 0; i <= new_img->get_mipmap_count(); i++) { + int ofs, size, w, h; + img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); + Javelin::RgbaBitmap bm(w, h); + void *dst = (void *)bm.GetData(); + copymem(dst, &r[ofs], size); + Javelin::ColorRgba<unsigned char> *dp = bm.GetData(); + for (int j = 0; j < size / 4; j++) { + // Red and blue colors are swapped. + SWAP(dp[j].r, dp[j].b); + } + new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); + Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm); + } + } - get_ok()->set_text(TTR("Close")); + p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data); +} - set_title(TTR("Scene Run Settings")); +void _register_pvrtc_compress_func() { + Image::_image_compress_pvrtc1_4bpp_func = _compress_pvrtc1_4bpp; } diff --git a/editor/pvrtc_compress.h b/modules/pvr/image_compress_pvrtc.h index 7b6c17d3c4..fde65f4bbe 100644 --- a/editor/pvrtc_compress.h +++ b/modules/pvr/image_compress_pvrtc.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* pvrtc_compress.h */ +/* image_compress_pvrtc.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PVRTC_COMPRESS_H -#define PVRTC_COMPRESS_H +#ifndef IMAGE_COMPRESS_PVRTC_H +#define IMAGE_COMPRESS_PVRTC_H -#include "core/io/image.h" +void _register_pvrtc_compress_func(); -void _pvrtc_register_compressors(); - -#endif // PVRTC_COMPRESS_H +#endif // IMAGE_COMPRESS_PVRTC_H diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp index 1eb697bba3..9bfc334d76 100644 --- a/modules/pvr/register_types.cpp +++ b/modules/pvr/register_types.cpp @@ -30,6 +30,7 @@ #include "register_types.h" +#include "image_compress_pvrtc.h" #include "texture_loader_pvr.h" static Ref<ResourceFormatPVR> resource_loader_pvr; @@ -37,6 +38,8 @@ static Ref<ResourceFormatPVR> resource_loader_pvr; void register_pvr_types() { resource_loader_pvr.instance(); ResourceLoader::add_resource_format_loader(resource_loader_pvr); + + _register_pvrtc_compress_func(); } void unregister_pvr_types() { diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp index 0923714387..c9cbb1935a 100644 --- a/modules/pvr/texture_loader_pvr.cpp +++ b/modules/pvr/texture_loader_pvr.cpp @@ -29,11 +29,8 @@ /*************************************************************************/ #include "texture_loader_pvr.h" -#include "PvrTcEncoder.h" -#include "RgbaBitmap.h" + #include "core/os/file_access.h" -#include <string.h> -#include <new> static void _pvrtc_decompress(Image *p_img); @@ -111,11 +108,11 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path, switch (flags & 0xFF) { case 0x18: case 0xC: - format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC2A : Image::FORMAT_PVRTC2; + format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_2A : Image::FORMAT_PVRTC1_2; break; case 0x19: case 0xD: - format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4; + format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4; break; case 0x16: format = Image::FORMAT_L8; @@ -183,53 +180,8 @@ String ResourceFormatPVR::get_resource_type(const String &p_path) const { return ""; } -static void _compress_pvrtc4(Image *p_img) { - Ref<Image> img = p_img->duplicate(); - - bool make_mipmaps = false; - if (!img->is_size_po2() || img->get_width() != img->get_height()) { - make_mipmaps = img->has_mipmaps(); - img->resize_to_po2(true); - } - img->convert(Image::FORMAT_RGBA8); - if (!img->has_mipmaps() && make_mipmaps) { - img->generate_mipmaps(); - } - - bool use_alpha = img->detect_alpha(); - - Ref<Image> new_img; - new_img.instance(); - new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4); - - Vector<uint8_t> data = new_img->get_data(); - { - uint8_t *wr = data.ptrw(); - const uint8_t *r = img->get_data().ptr(); - - for (int i = 0; i <= new_img->get_mipmap_count(); i++) { - int ofs, size, w, h; - img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); - Javelin::RgbaBitmap bm(w, h); - void *dst = (void *)bm.GetData(); - copymem(dst, &r[ofs], size); - Javelin::ColorRgba<unsigned char> *dp = bm.GetData(); - for (int j = 0; j < size / 4; j++) { - /* red and blue colors are swapped. */ - SWAP(dp[j].r, dp[j].b); - } - new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); - Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm); - } - } - - p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data); -} - ResourceFormatPVR::ResourceFormatPVR() { Image::_image_decompress_pvrtc = _pvrtc_decompress; - Image::_image_compress_pvrtc4_func = _compress_pvrtc4; - Image::_image_compress_pvrtc2_func = _compress_pvrtc4; } ///////////////////////////////////////////////////////// @@ -635,9 +587,9 @@ static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int } static void _pvrtc_decompress(Image *p_img) { - ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC2 && p_img->get_format() != Image::FORMAT_PVRTC2A && p_img->get_format() != Image::FORMAT_PVRTC4 && p_img->get_format() != Image::FORMAT_PVRTC4A); + ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC1_2 && p_img->get_format() != Image::FORMAT_PVRTC1_2A && p_img->get_format() != Image::FORMAT_PVRTC1_4 && p_img->get_format() != Image::FORMAT_PVRTC1_4A); - bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC2 || p_img->get_format() == Image::FORMAT_PVRTC2A); + bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC1_2 || p_img->get_format() == Image::FORMAT_PVRTC1_2A); Vector<uint8_t> data = p_img->get_data(); const uint8_t *r = data.ptr(); diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp index 10c3732fd7..b905b7dabb 100644 --- a/modules/text_server_adv/bitmap_font_adv.cpp +++ b/modules/text_server_adv/bitmap_font_adv.cpp @@ -175,8 +175,9 @@ static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *font, void *font_data, hb_ return true; } -static hb_font_funcs_t *_hb_bmp_get_font_funcs() { - hb_font_funcs_t *funcs = hb_font_funcs_create(); +static hb_font_funcs_t *funcs = nullptr; +void hb_bmp_create_font_funcs() { + funcs = hb_font_funcs_create(); hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr); //hb_font_funcs_set_font_v_extents_func (funcs, hb_bmp_get_font_v_extents, nullptr, nullptr); @@ -194,12 +195,17 @@ static hb_font_funcs_t *_hb_bmp_get_font_funcs() { //hb_font_funcs_set_glyph_from_name_func (funcs, hb_bmp_get_glyph_from_name, nullptr, nullptr); hb_font_funcs_make_immutable(funcs); +} - return funcs; +void hb_bmp_free_font_funcs() { + if (funcs != nullptr) { + hb_font_funcs_destroy(funcs); + funcs = nullptr; + } } static void _hb_bmp_font_set_funcs(hb_font_t *p_font, BitmapFontDataAdvanced *p_face, int p_size, bool p_unref) { - hb_font_set_funcs(p_font, _hb_bmp_get_font_funcs(), _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy); + hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy); } hb_font_t *hb_bmp_font_create(BitmapFontDataAdvanced *p_face, int p_size, hb_destroy_func_t p_destroy) { @@ -384,7 +390,6 @@ Error BitmapFontDataAdvanced::load_from_memory(const uint8_t *p_data, size_t p_s chr.rect.position.y = c[2]; chr.rect.size.x = c[3]; chr.rect.size.y = c[4]; - chr.texture_idx = 0; if (c[7] < 0) { chr.advance.x = c[3]; } else { diff --git a/modules/text_server_adv/bitmap_font_adv.h b/modules/text_server_adv/bitmap_font_adv.h index b2fe7f43af..cb1a726f76 100644 --- a/modules/text_server_adv/bitmap_font_adv.h +++ b/modules/text_server_adv/bitmap_font_adv.h @@ -33,6 +33,9 @@ #include "font_adv.h" +void hb_bmp_create_font_funcs(); +void hb_bmp_free_font_funcs(); + struct BitmapFontDataAdvanced : public FontDataAdvanced { _THREAD_SAFE_CLASS_ diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp index 90e5cc8831..08c4ad2727 100644 --- a/modules/text_server_adv/dynamic_font_adv.cpp +++ b/modules/text_server_adv/dynamic_font_adv.cpp @@ -32,8 +32,7 @@ #include FT_STROKER_H #include FT_ADVANCES_H - -HashMap<String, Vector<uint8_t>> DynamicFontDataAdvanced::font_mem_cache; +#include FT_MULTIPLE_MASTERS_H DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(int p_size, int p_outline_size) { ERR_FAIL_COND_V(!valid, nullptr); @@ -55,11 +54,10 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size( if (E != nullptr) { fds = E->get(); } else { - // FT_OPEN_STREAM is extremely slow only on Android. - if (OS::get_singleton()->get_name() == "Android" && font_mem == nullptr && font_path != String()) { - if (font_mem_cache.has(font_path)) { - font_mem = font_mem_cache[font_path].ptr(); - font_mem_size = font_mem_cache[font_path].size(); + if (font_mem == nullptr && font_path != String()) { + if (!font_mem_cache.empty()) { + font_mem = font_mem_cache.ptr(); + font_mem_size = font_mem_cache.size(); } else { FileAccess *f = FileAccess::open(font_path, FileAccess::READ); if (!f) { @@ -67,11 +65,9 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size( } size_t len = f->get_len(); - font_mem_cache[font_path] = Vector<uint8_t>(); - Vector<uint8_t> &fontdata = font_mem_cache[font_path]; - fontdata.resize(len); - f->get_buffer(fontdata.ptrw(), len); - font_mem = fontdata.ptr(); + font_mem_cache.resize(len); + f->get_buffer(font_mem_cache.ptrw(), len); + font_mem = font_mem_cache.ptr(); font_mem_size = len; f->close(); } @@ -79,27 +75,7 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size( int error = 0; fds = memnew(DataAtSize); - if (font_mem == nullptr && font_path != String()) { - FileAccess *f = FileAccess::open(font_path, FileAccess::READ); - if (!f) { - memdelete(fds); - ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'."); - } - - memset(&fds->stream, 0, sizeof(FT_StreamRec)); - fds->stream.base = nullptr; - fds->stream.size = f->get_len(); - fds->stream.pos = 0; - fds->stream.descriptor.pointer = f; - fds->stream.read = _ft_stream_io; - fds->stream.close = _ft_stream_close; - - FT_Open_Args fargs; - memset(&fargs, 0, sizeof(FT_Open_Args)); - fargs.flags = FT_OPEN_STREAM; - fargs.stream = &fds->stream; - error = FT_Open_Face(library, &fargs, 0, &fds->face); - } else if (font_mem) { + if (font_mem) { memset(&fds->stream, 0, sizeof(FT_StreamRec)); fds->stream.base = (unsigned char *)font_mem; fds->stream.size = font_mem_size; @@ -159,33 +135,89 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size( memdelete(fds); ERR_FAIL_V_MSG(nullptr, "Error loading HB font."); } + if (p_outline_size != 0) { size_cache_outline[id] = fds; } else { size_cache[id] = fds; } - } + // Write variations. + if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { + FT_MM_Var *amaster; + + FT_Get_MM_Var(fds->face, &amaster); + + Vector<hb_variation_t> hb_vars; + Vector<FT_Fixed> coords; + coords.resize(amaster->num_axis); + + FT_Get_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw()); + + for (FT_UInt i = 0; i < amaster->num_axis; i++) { + hb_variation_t var; + + // Reset to default. + var.tag = amaster->axis[i].tag; + var.value = (double)amaster->axis[i].def / 65536.f; + coords.write[i] = amaster->axis[i].def; + + if (variations.has(var.tag)) { + var.value = variations[var.tag]; + coords.write[i] = CLAMP(variations[var.tag] * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum); + } + + hb_vars.push_back(var); + } + + FT_Set_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw()); + hb_font_set_variations(fds->hb_handle, hb_vars.empty() ? nullptr : &hb_vars[0], hb_vars.size()); + + FT_Done_MM_Var(library, amaster); + } + } return fds; } -unsigned long DynamicFontDataAdvanced::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - - if (f->get_position() != offset) { - f->seek(offset); +Dictionary DynamicFontDataAdvanced::get_variation_list() const { + _THREAD_SAFE_METHOD_ + DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size); + if (fds == nullptr) { + return Dictionary(); } - if (count == 0) { - return 0; + + Dictionary ret; + // Read variations. + if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { + FT_MM_Var *amaster; + + FT_Get_MM_Var(fds->face, &amaster); + + for (FT_UInt i = 0; i < amaster->num_axis; i++) { + ret[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536); + } + + FT_Done_MM_Var(library, amaster); } + return ret; +} - return f->get_buffer(buffer, count); +void DynamicFontDataAdvanced::set_variation(const String &p_name, double p_value) { + _THREAD_SAFE_METHOD_ + int32_t tag = TS->name_to_tag(p_name); + if (!variations.has(tag) || (variations[tag] != p_value)) { + variations[tag] = p_value; + clear_cache(); + } } -void DynamicFontDataAdvanced::_ft_stream_close(FT_Stream stream) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - f->close(); - memdelete(f); +double DynamicFontDataAdvanced::get_variation(const String &p_name) const { + _THREAD_SAFE_METHOD_ + int32_t tag = TS->name_to_tag(p_name); + if (!variations.has(tag)) { + return 0.f; + } + return variations[tag]; } Dictionary DynamicFontDataAdvanced::get_feature_list() const { @@ -222,8 +254,6 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const { DynamicFontDataAdvanced::TexturePosition DynamicFontDataAdvanced::find_texture_pos_for_glyph(DynamicFontDataAdvanced::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) { TexturePosition ret; ret.index = -1; - ret.x = 0; - ret.y = 0; int mw = p_width; int mh = p_height; diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h index 61cff3cde9..f9d6735c32 100644 --- a/modules/text_server_adv/dynamic_font_adv.h +++ b/modules/text_server_adv/dynamic_font_adv.h @@ -116,7 +116,9 @@ private: const uint8_t *font_mem = nullptr; int font_mem_size = 0; String font_path; - static HashMap<String, Vector<uint8_t>> font_mem_cache; + Vector<uint8_t> font_mem_cache; + + Map<int32_t, double> variations; float rect_margin = 1.f; int base_size = 16; @@ -128,9 +130,6 @@ private: Map<CacheID, DataAtSize *> size_cache; Map<CacheID, DataAtSize *> size_cache_outline; - static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count); - static void _ft_stream_close(FT_Stream stream); - DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0); TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height); @@ -149,6 +148,10 @@ public: virtual float get_descent(int p_size) const override; virtual Dictionary get_feature_list() const override; + virtual Dictionary get_variation_list() const override; + + virtual void set_variation(const String &p_name, double p_value) override; + virtual double get_variation(const String &p_name) const override; virtual float get_underline_position(int p_size) const override; virtual float get_underline_thickness(int p_size) const override; diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h index 232d6d7d08..88b327f57b 100644 --- a/modules/text_server_adv/font_adv.h +++ b/modules/text_server_adv/font_adv.h @@ -50,6 +50,10 @@ struct FontDataAdvanced { virtual float get_descent(int p_size) const = 0; virtual Dictionary get_feature_list() const { return Dictionary(); }; + virtual Dictionary get_variation_list() const { return Dictionary(); }; + + virtual void set_variation(const String &p_name, double p_value){}; + virtual double get_variation(const String &p_name) const { return 0; }; virtual float get_underline_position(int p_size) const = 0; virtual float get_underline_thickness(int p_size) const = 0; diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp index 8a2b2cced0..60a617c3a7 100644 --- a/modules/text_server_adv/script_iterator.cpp +++ b/modules/text_server_adv/script_iterator.cpp @@ -56,11 +56,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length int paren_sp = -1; int start_sp = paren_sp; UErrorCode err = U_ZERO_ERROR; + const char32_t *str = p_string.ptr(); do { script_code = USCRIPT_COMMON; for (script_start = script_end; script_end < p_length; script_end++) { - UChar32 ch = p_string[script_end]; + UChar32 ch = str[script_end]; UScriptCode sc = uscript_getScript(ch, &err); if (U_FAILURE(err)) { ERR_FAIL_MSG(u_errorName(err)); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index e391777eea..803004f93f 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -132,7 +132,7 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) { /*************************************************************************/ String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite"; -uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA; +uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE; bool TextServerAdvanced::has_feature(Feature p_feature) { return (interface_features & p_feature) == p_feature; @@ -622,6 +622,27 @@ bool TextServerAdvanced::font_get_antialiased(RID p_font) const { return fd->get_antialiased(); } +Dictionary TextServerAdvanced::font_get_variation_list(RID p_font) const { + _THREAD_SAFE_METHOD_ + const FontDataAdvanced *fd = font_owner.getornull(p_font); + ERR_FAIL_COND_V(!fd, Dictionary()); + return fd->get_variation_list(); +} + +void TextServerAdvanced::font_set_variation(RID p_font, const String &p_name, double p_value) { + _THREAD_SAFE_METHOD_ + FontDataAdvanced *fd = font_owner.getornull(p_font); + ERR_FAIL_COND(!fd); + fd->set_variation(p_name, p_value); +} + +double TextServerAdvanced::font_get_variation(RID p_font, const String &p_name) const { + _THREAD_SAFE_METHOD_ + const FontDataAdvanced *fd = font_owner.getornull(p_font); + ERR_FAIL_COND_V(!fd, 0); + return fd->get_variation(p_name); +} + void TextServerAdvanced::font_set_distance_field_hint(RID p_font, bool p_distance_field) { _THREAD_SAFE_METHOD_ FontDataAdvanced *fd = font_owner.getornull(p_font); @@ -1108,7 +1129,9 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->width = 0; sd->upos = 0; sd->uthk = 0; - for (int i = 0; i < sd->glyphs.size(); i++) { + int sd_size = sd->glyphs.size(); + + for (int i = 0; i < sd_size; i++) { Glyph gl = sd->glyphs[i]; Variant key; if (gl.count == 1) { @@ -1128,8 +1151,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y); @@ -1144,8 +1167,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x); @@ -1160,19 +1183,19 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off)); sd->descent = MAX(sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off)); } else { - sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } sd->width += gl.advance * gl.repeat; @@ -1248,6 +1271,11 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->utf16 = new_sd->text.utf16(); new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length())); + int sd_size = sd->glyphs.size(); + const Glyph *sd_glyphs = sd->glyphs.ptr(); + const FontDataAdvanced *fd = nullptr; + RID prev_rid = RID(); + for (int ov = 0; ov < sd->bidi_override.size(); ov++) { UErrorCode err = U_ZERO_ERROR; @@ -1280,21 +1308,23 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start); int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length); - for (int j = 0; j < sd->glyphs.size(); j++) { - if ((sd->glyphs[j].start >= bidi_run_start) && (sd->glyphs[j].end <= bidi_run_end)) { + for (int j = 0; j < sd_size; j++) { + if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) { // Copy glyphs. - Glyph gl = sd->glyphs[j]; + Glyph gl = sd_glyphs[j]; Variant key; + bool find_embedded = false; if (gl.count == 1) { for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { if (E->get().pos == gl.start) { + find_embedded = true; key = E->key(); new_sd->objects[key] = E->get(); break; } } } - if (key != Variant()) { + if (find_embedded) { if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->objects[key].rect.position.x = new_sd->width; new_sd->width += new_sd->objects[key].rect.size.x; @@ -1303,8 +1333,8 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y); @@ -1318,8 +1348,8 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x); @@ -1327,23 +1357,26 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng } } } else { - const FontDataAdvanced *fd = font_owner.getornull(gl.font_rid); + if (prev_rid != gl.font_rid) { + fd = font_owner.getornull(gl.font_rid); + prev_rid = gl.font_rid; + } if (fd != nullptr) { if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->ascent = MAX(new_sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off)); new_sd->descent = MAX(new_sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off)); } else { - new_sd->ascent = MAX(new_sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - new_sd->descent = MAX(new_sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (new_sd->orientation == ORIENTATION_HORIZONTAL) { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } new_sd->width += gl.advance * gl.repeat; @@ -1491,9 +1524,9 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { float old_adv = gl.advance; if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { - gl.advance = MAX(gl.advance + delta_width_per_space, 0.f); + gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.f)); } else { - gl.advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size); + gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size)); } sd->width += (gl.advance - old_adv); } @@ -1529,8 +1562,10 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float delta = -1; } + Glyph *gl = sd->glyphs.ptrw(); + for (int i = start; i != end; i += delta) { - if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { + if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { float tab_off = 0.f; while (tab_off <= off) { tab_off += p_tab_stops[tab_index]; @@ -1539,13 +1574,13 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float tab_index = 0; } } - float old_adv = sd->glyphs.write[i].advance; - sd->glyphs.write[i].advance = (tab_off - off); - sd->width += sd->glyphs.write[i].advance - old_adv; + float old_adv = gl[i].advance; + gl[i].advance = tab_off - off; + sd->width += gl[i].advance - old_adv; off = 0; continue; } - off += sd->glyphs[i].advance * sd->glyphs[i].repeat; + off += gl[i].advance * gl[i].repeat; } return 0.f; @@ -1565,8 +1600,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { const UChar *data = sd->utf16.ptr(); - Map<int, bool> breaks; - + HashMap<int, bool> breaks; UErrorCode err = U_ZERO_ERROR; for (int i = 0; i < sd->spans.size(); i++) { UBreakIterator *bi = ubrk_open(UBRK_LINE, sd->spans[i].language.ascii().get_data(), data + _convert_pos_inv(sd, sd->spans[i].start), _convert_pos_inv(sd, sd->spans[i].end - sd->spans[i].start), &err); @@ -1598,40 +1632,47 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { sd->sort_valid = false; sd->glyphs_logical.clear(); + int sd_size = sd->glyphs.size(); + const char32_t *ch = sd->text.ptr(); + Glyph *sd_glyphs = sd->glyphs.ptrw(); - for (int i = 0; i < sd->glyphs.size(); i++) { - if (sd->glyphs[i].count > 0) { - char32_t c = sd->text[sd->glyphs[i].start - sd->start]; + for (int i = 0; i < sd_size; i++) { + if (sd_glyphs[i].count > 0) { + char32_t c = ch[sd_glyphs[i].start - sd->start]; if (c == 0xfffc) { continue; } if (c == 0x0009 || c == 0x000b) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_TAB; + sd_glyphs[i].flags |= GRAPHEME_IS_TAB; } if (breaks.has(sd->glyphs[i].start)) { if (breaks[sd->glyphs[i].start]) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_HARD; + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; } else { if (is_whitespace(c)) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT; - sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE; + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; + sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; } else { TextServer::Glyph gl; - gl.start = sd->glyphs[i].start; - gl.end = sd->glyphs[i].end; + gl.start = sd_glyphs[i].start; + gl.end = sd_glyphs[i].end; gl.count = 1; - gl.repeat = 1; - gl.font_rid = sd->glyphs[i].font_rid; - gl.font_size = sd->glyphs[i].font_size; + gl.font_rid = sd_glyphs[i].font_rid; + gl.font_size = sd_glyphs[i].font_size; gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL; - sd->glyphs.insert(i + sd->glyphs[i].count, gl); // insert after - i += sd->glyphs[i].count; + sd->glyphs.insert(i + sd_glyphs[i].count, gl); // insert after + + // Update write pointer and size. + sd_size = sd->glyphs.size(); + sd_glyphs = sd->glyphs.ptrw(); + + i += sd_glyphs[i].count; continue; } } } - i += (sd->glyphs[i].count - 1); + i += (sd_glyphs[i].count - 1); } } @@ -1767,9 +1808,10 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { sd->sort_valid = false; sd->glyphs_logical.clear(); + int sd_size = sd->glyphs.size(); if (jstops.size() > 0) { - for (int i = 0; i < sd->glyphs.size(); i++) { + for (int i = 0; i < sd_size; i++) { if (sd->glyphs[i].count > 0) { if (jstops.has(sd->glyphs[i].start)) { char32_t c = sd->text[sd->glyphs[i].start - sd->start]; @@ -1803,7 +1845,6 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { gl.start = sd->glyphs[i].start; gl.end = sd->glyphs[i].end; gl.count = 1; - gl.repeat = 1; gl.font_rid = sd->glyphs[i].font_rid; gl.font_size = sd->glyphs[i].font_size; gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL; @@ -1838,8 +1879,6 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced // Process glyphs. TextServer::Glyph gl; - gl.start = -1; - gl.end = -1; if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) { gl.flags |= TextServer::GRAPHEME_IS_RTL; @@ -1850,15 +1889,15 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced if (glyph_count > 0) { if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size)); + gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size))); } else { - gl.advance = -glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size)); + gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size))); } gl.count = 1; gl.index = glyph_info[0].codepoint; - gl.x_off = glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size)); - gl.y_off = -glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size)); + gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size))); + gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size))); if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) { gl.flags |= GRAPHEME_IS_VALID; @@ -1873,8 +1912,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star fd = font_owner.getornull(p_fonts[p_fb_index]); } + int fs = p_sd->spans[p_span].font_size; if (fd == nullptr) { - // Add fallback glyohs + // Add fallback glyphs for (int i = p_start; i < p_end; i++) { if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) { TextServer::Glyph gl; @@ -1882,20 +1922,19 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star gl.end = i + 1; gl.count = 1; gl.index = p_sd->text[i]; - gl.font_size = p_sd->spans[p_span].font_size; + gl.font_size = fs; gl.font_rid = RID(); - gl.flags = 0; if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) { gl.flags |= TextServer::GRAPHEME_IS_RTL; } if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x; - p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + gl.advance = get_hex_code_box_size(fs, gl.index).x; + p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.75f)); + p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.25f)); } else { - gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y; - p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + gl.advance = get_hex_code_box_size(fs, gl.index).y; + p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f)); + p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f)); } p_sd->width += gl.advance; @@ -1905,7 +1944,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star return; } - hb_font_t *hb_font = fd->get_hb_handle(p_sd->spans[p_span].font_size); + hb_font_t *hb_font = fd->get_hb_handle(fs); ERR_FAIL_COND(hb_font == nullptr); hb_buffer_clear_contents(p_sd->hb_buffer); @@ -1981,17 +2020,17 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star gl.count = 0; gl.font_rid = p_fonts[p_fb_index]; - gl.font_size = p_sd->spans[p_span].font_size; + gl.font_size = fs; gl.index = glyph_info[i].codepoint; if (gl.index != 0) { if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(gl.font_size)); + gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(fs))); } else { - gl.advance = -glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(gl.font_size)); + gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(fs))); } - gl.x_off = glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(gl.font_size)); - gl.y_off = -glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(gl.font_size)); + gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(fs))); + gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(fs))); } if (p_sd->preserve_control) { @@ -2026,14 +2065,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star } for (int j = 0; j < w[i].count; j++) { if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - p_sd->ascent = MAX(p_sd->ascent, MAX(fd->get_ascent(w[i + j].font_size), w[i + j].y_off)); - p_sd->descent = MAX(p_sd->descent, MAX(fd->get_descent(w[i + j].font_size), w[i + j].y_off)); + p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off); + p_sd->descent = MAX(p_sd->descent, w[i + j].y_off); } else { - p_sd->ascent = MAX(p_sd->ascent, fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5); - p_sd->descent = MAX(p_sd->descent, fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5); + p_sd->ascent = MAX(p_sd->ascent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5)); + p_sd->descent = MAX(p_sd->descent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5)); } - p_sd->upos = MAX(p_sd->upos, font_get_underline_position(w[i + j].font_rid, w[i + j].font_size)); - p_sd->uthk = MAX(p_sd->uthk, font_get_underline_thickness(w[i + j].font_rid, w[i + j].font_size)); p_sd->width += w[i + j].advance; p_sd->glyphs.push_back(w[i + j]); } @@ -2051,6 +2088,10 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star if (failed_subrun_start != p_end + 1) { _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1); } + p_sd->ascent = MAX(p_sd->ascent, fd->get_ascent(fs)); + p_sd->descent = MAX(p_sd->descent, fd->get_descent(fs)); + p_sd->upos = MAX(p_sd->upos, fd->get_underline_position(fs)); + p_sd->uthk = MAX(p_sd->uthk, fd->get_underline_thickness(fs)); } } @@ -2180,8 +2221,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y); @@ -2195,8 +2236,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x); @@ -2207,7 +2248,6 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { gl.start = span.start; gl.end = span.end; gl.count = 1; - gl.index = 0; gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_VIRTUAL; if (sd->orientation == ORIENTATION_HORIZONTAL) { gl.advance = sd->objects[span.embedded_key].rect.size.x; @@ -2507,9 +2547,11 @@ void TextServerAdvanced::register_server() { } TextServerAdvanced::TextServerAdvanced() { + hb_bmp_create_font_funcs(); } TextServerAdvanced::~TextServerAdvanced() { + hb_bmp_free_font_funcs(); u_cleanup(); #ifndef ICU_STATIC_DATA if (icu_data != nullptr) { diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index f26b87f67e..8c26554158 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -138,6 +138,10 @@ public: virtual bool font_get_antialiased(RID p_font) const override; virtual Dictionary font_get_feature_list(RID p_font) const override; + virtual Dictionary font_get_variation_list(RID p_font) const override; + + virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override; + virtual double font_get_variation(RID p_font, const String &p_name) const override; virtual void font_set_hinting(RID p_font, Hinting p_hinting) override; virtual Hinting font_get_hinting(RID p_font) const override; diff --git a/modules/text_server_fb/bitmap_font_fb.cpp b/modules/text_server_fb/bitmap_font_fb.cpp index 5ab8edbd71..99cbccb69a 100644 --- a/modules/text_server_fb/bitmap_font_fb.cpp +++ b/modules/text_server_fb/bitmap_font_fb.cpp @@ -198,7 +198,6 @@ Error BitmapFontDataFallback::load_from_memory(const uint8_t *p_data, size_t p_s chr.rect.position.y = c[2]; chr.rect.size.x = c[3]; chr.rect.size.y = c[4]; - chr.texture_idx = 0; if (c[7] < 0) { chr.advance.x = c[3]; } else { diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp index 6feeaec102..6731870e8f 100644 --- a/modules/text_server_fb/dynamic_font_fb.cpp +++ b/modules/text_server_fb/dynamic_font_fb.cpp @@ -33,8 +33,6 @@ #include FT_STROKER_H #include FT_ADVANCES_H -HashMap<String, Vector<uint8_t>> DynamicFontDataFallback::font_mem_cache; - DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(int p_size, int p_outline_size) { ERR_FAIL_COND_V(!valid, nullptr); ERR_FAIL_COND_V(p_size < 0 || p_size > UINT16_MAX, nullptr); @@ -55,11 +53,10 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( if (E != nullptr) { fds = E->get(); } else { - // FT_OPEN_STREAM is extremely slow only on Android. - if (OS::get_singleton()->get_name() == "Android" && font_mem == nullptr && font_path != String()) { - if (font_mem_cache.has(font_path)) { - font_mem = font_mem_cache[font_path].ptr(); - font_mem_size = font_mem_cache[font_path].size(); + if (font_mem == nullptr && font_path != String()) { + if (!font_mem_cache.empty()) { + font_mem = font_mem_cache.ptr(); + font_mem_size = font_mem_cache.size(); } else { FileAccess *f = FileAccess::open(font_path, FileAccess::READ); if (!f) { @@ -67,11 +64,9 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( } size_t len = f->get_len(); - font_mem_cache[font_path] = Vector<uint8_t>(); - Vector<uint8_t> &fontdata = font_mem_cache[font_path]; - fontdata.resize(len); - f->get_buffer(fontdata.ptrw(), len); - font_mem = fontdata.ptr(); + font_mem_cache.resize(len); + f->get_buffer(font_mem_cache.ptrw(), len); + font_mem = font_mem_cache.ptr(); font_mem_size = len; f->close(); } @@ -79,27 +74,7 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( int error = 0; fds = memnew(DataAtSize); - if (font_mem == nullptr && font_path != String()) { - FileAccess *f = FileAccess::open(font_path, FileAccess::READ); - if (!f) { - memdelete(fds); - ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'."); - } - - memset(&fds->stream, 0, sizeof(FT_StreamRec)); - fds->stream.base = nullptr; - fds->stream.size = f->get_len(); - fds->stream.pos = 0; - fds->stream.descriptor.pointer = f; - fds->stream.read = _ft_stream_io; - fds->stream.close = _ft_stream_close; - - FT_Open_Args fargs; - memset(&fargs, 0, sizeof(FT_Open_Args)); - fargs.flags = FT_OPEN_STREAM; - fargs.stream = &fds->stream; - error = FT_Open_Face(library, &fargs, 0, &fds->face); - } else if (font_mem) { + if (font_mem) { memset(&fds->stream, 0, sizeof(FT_StreamRec)); fds->stream.base = (unsigned char *)font_mem; fds->stream.size = font_mem_size; @@ -161,30 +136,9 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( return fds; } -unsigned long DynamicFontDataFallback::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - - if (f->get_position() != offset) { - f->seek(offset); - } - if (count == 0) { - return 0; - } - - return f->get_buffer(buffer, count); -} - -void DynamicFontDataFallback::_ft_stream_close(FT_Stream stream) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - f->close(); - memdelete(f); -} - DynamicFontDataFallback::TexturePosition DynamicFontDataFallback::find_texture_pos_for_glyph(DynamicFontDataFallback::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) { TexturePosition ret; ret.index = -1; - ret.x = 0; - ret.y = 0; int mw = p_width; int mh = p_height; diff --git a/modules/text_server_fb/dynamic_font_fb.h b/modules/text_server_fb/dynamic_font_fb.h index 060b8cfbf9..6ac8cb52a8 100644 --- a/modules/text_server_fb/dynamic_font_fb.h +++ b/modules/text_server_fb/dynamic_font_fb.h @@ -107,7 +107,7 @@ private: const uint8_t *font_mem = nullptr; int font_mem_size = 0; String font_path; - static HashMap<String, Vector<uint8_t>> font_mem_cache; + Vector<uint8_t> font_mem_cache; float rect_margin = 1.f; int base_size = 16; @@ -119,9 +119,6 @@ private: Map<CacheID, DataAtSize *> size_cache; Map<CacheID, DataAtSize *> size_cache_outline; - static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count); - static void _ft_stream_close(FT_Stream stream); - DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0); TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height); diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index e74a1d9ef9..383250996d 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -625,7 +625,11 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->width = 0; sd->upos = 0; sd->uthk = 0; - for (int i = 0; i < sd->glyphs.size(); i++) { + int sd_size = sd->glyphs.size(); + const FontDataFallback *fd = nullptr; + RID prev_rid = RID(); + + for (int i = 0; i < sd_size; i++) { Glyph gl = sd->glyphs[i]; Variant key; if (gl.count == 1) { @@ -645,8 +649,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y); @@ -661,8 +665,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x); @@ -671,25 +675,28 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->glyphs.write[i].advance = sd->objects[key].rect.size.y; } } else { - const FontDataFallback *fd = font_owner.getornull(gl.font_rid); + if (prev_rid != gl.font_rid) { + fd = font_owner.getornull(gl.font_rid); + prev_rid = gl.font_rid; + } if (fd != nullptr) { if (sd->orientation == ORIENTATION_HORIZONTAL) { sd->ascent = MAX(sd->ascent, fd->get_ascent(gl.font_size)); sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size)); } else { - sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } sd->width += gl.advance * gl.repeat; @@ -760,21 +767,25 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng if (p_length > 0) { new_sd->text = sd->text.substr(p_start, p_length); + int sd_size = sd->glyphs.size(); + const Glyph *sd_glyphs = sd->glyphs.ptr(); - for (int i = 0; i < sd->glyphs.size(); i++) { - if ((sd->glyphs[i].start >= new_sd->start) && (sd->glyphs[i].end <= new_sd->end)) { - Glyph gl = sd->glyphs[i]; + for (int i = 0; i < sd_size; i++) { + if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) { + Glyph gl = sd_glyphs[i]; Variant key; + bool find_embedded = false; if (gl.count == 1) { for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { if (E->get().pos == gl.start) { + find_embedded = true; key = E->key(); new_sd->objects[key] = E->get(); break; } } } - if (key != Variant()) { + if (find_embedded) { if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->objects[key].rect.position.x = new_sd->width; new_sd->width += new_sd->objects[key].rect.size.x; @@ -783,8 +794,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y); @@ -798,8 +809,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x); @@ -813,17 +824,17 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, fd->get_ascent(gl.font_size)); new_sd->descent = MAX(new_sd->descent, fd->get_descent(gl.font_size)); } else { - new_sd->ascent = MAX(new_sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - new_sd->descent = MAX(new_sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (new_sd->orientation == ORIENTATION_HORIZONTAL) { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } new_sd->width += gl.advance * gl.repeat; @@ -943,7 +954,7 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, if (gl.count > 0) { if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { float old_adv = gl.advance; - gl.advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size); + gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size)); sd->width += (gl.advance - old_adv); } } @@ -978,8 +989,10 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float delta = -1; } + Glyph *gl = sd->glyphs.ptrw(); + for (int i = start; i != end; i += delta) { - if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { + if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { float tab_off = 0.f; while (tab_off <= off) { tab_off += p_tab_stops[tab_index]; @@ -988,13 +1001,13 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float tab_index = 0; } } - float old_adv = sd->glyphs.write[i].advance; - sd->glyphs.write[i].advance = (tab_off - off); - sd->width += sd->glyphs.write[i].advance - old_adv; + float old_adv = gl[i].advance; + gl[i].advance = tab_off - off; + sd->width += gl[i].advance - old_adv; off = 0; continue; } - off += sd->glyphs[i].advance * sd->glyphs[i].repeat; + off += gl[i].advance * gl[i].repeat; } return 0.f; @@ -1012,7 +1025,8 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { return true; // Noting to do. } - for (int i = 0; i < sd->glyphs.size(); i++) { + int sd_size = sd->glyphs.size(); + for (int i = 0; i < sd_size; i++) { if (sd->glyphs[i].count > 0) { char32_t c = sd->text[sd->glyphs[i].start]; if (is_whitespace(c) && !is_linebreak(c)) { @@ -1086,8 +1100,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y); @@ -1101,8 +1115,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x); @@ -1157,14 +1171,14 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size)); } else { gl.advance = fd->get_advance(gl.index, gl.font_size).y; - gl.x_off = -fd->get_advance(gl.index, gl.font_size).x * 0.5; + gl.x_off = -Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5); gl.y_off = fd->get_ascent(gl.font_size); - sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } } - sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); - sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); + sd->upos = MAX(sd->upos, fd->get_underline_position(gl.font_size)); + sd->uthk = MAX(sd->uthk, fd->get_underline_thickness(gl.font_size)); // Add kerning to previous glyph. if (sd->glyphs.size() > 0) { @@ -1181,12 +1195,12 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x; - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y; - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } sd->width += gl.advance; diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index b10d4523f2..f9ef184579 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -2367,7 +2367,7 @@ void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p binds.push_back(p_binds[i]); } binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing - p_obj->connect_compat(p_signal, this, "_signal_callback", binds, CONNECT_ONESHOT); + p_obj->connect(p_signal, Callable(this, "_signal_callback"), binds, CONNECT_ONESHOT); } bool VisualScriptFunctionState::is_valid() const { diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub index d0744fa313..67d3f1bebd 100644 --- a/modules/webm/libvpx/SCsub +++ b/modules/webm/libvpx/SCsub @@ -278,7 +278,7 @@ if webm_cpu_x86: try: yasm_found = True subprocess.Popen([yasm_path, "--version"], stdout=devnull, stderr=devnull).communicate() - except: + except Exception: yasm_found = False if yasm_found: break diff --git a/modules/webrtc/library_godot_webrtc.js b/modules/webrtc/library_godot_webrtc.js index f725a10a6f..9f029407d2 100644 --- a/modules/webrtc/library_godot_webrtc.js +++ b/modules/webrtc/library_godot_webrtc.js @@ -90,6 +90,7 @@ const GodotRTCDataChannel = { }, }, + godot_js_rtc_datachannel_ready_state_get__sig: 'ii', godot_js_rtc_datachannel_ready_state_get: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -109,6 +110,7 @@ const GodotRTCDataChannel = { } }, + godot_js_rtc_datachannel_send__sig: 'iiiii', godot_js_rtc_datachannel_send: function (p_id, p_buffer, p_length, p_raw) { const ref = IDHandler.get(p_id); if (!ref) { @@ -129,14 +131,17 @@ const GodotRTCDataChannel = { return 0; }, + godot_js_rtc_datachannel_is_ordered__sig: 'ii', godot_js_rtc_datachannel_is_ordered: function (p_id) { return IDHandler.get_prop(p_id, 'ordered', true); }, + godot_js_rtc_datachannel_id_get__sig: 'ii', godot_js_rtc_datachannel_id_get: function (p_id) { return IDHandler.get_prop(p_id, 'id', 65535); }, + godot_js_rtc_datachannel_max_packet_lifetime_get__sig: 'ii', godot_js_rtc_datachannel_max_packet_lifetime_get: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -151,14 +156,17 @@ const GodotRTCDataChannel = { return 65535; }, + godot_js_rtc_datachannel_max_retransmits_get__sig: 'ii', godot_js_rtc_datachannel_max_retransmits_get: function (p_id) { return IDHandler.get_prop(p_id, 'maxRetransmits', 65535); }, - godot_js_rtc_datachannel_is_negotiated: function (p_id, p_def) { + godot_js_rtc_datachannel_is_negotiated__sig: 'ii', + godot_js_rtc_datachannel_is_negotiated: function (p_id) { return IDHandler.get_prop(p_id, 'negotiated', 65535); }, + godot_js_rtc_datachannel_label_get__sig: 'ii', godot_js_rtc_datachannel_label_get: function (p_id) { const ref = IDHandler.get(p_id); if (!ref || !ref.label) { @@ -167,6 +175,7 @@ const GodotRTCDataChannel = { return GodotRuntime.allocString(ref.label); }, + godot_js_rtc_datachannel_protocol_get__sig: 'ii', godot_js_rtc_datachannel_protocol_get: function (p_id) { const ref = IDHandler.get(p_id); if (!ref || !ref.protocol) { @@ -175,11 +184,13 @@ const GodotRTCDataChannel = { return GodotRuntime.allocString(ref.protocol); }, + godot_js_rtc_datachannel_destroy__sig: 'vi', godot_js_rtc_datachannel_destroy: function (p_id) { GodotRTCDataChannel.close(p_id); IDHandler.remove(p_id); }, + godot_js_rtc_datachannel_connect__sig: 'viiiiii', godot_js_rtc_datachannel_connect: function (p_id, p_ref, p_on_open, p_on_message, p_on_error, p_on_close) { const onopen = GodotRuntime.get_func(p_on_open).bind(null, p_ref); const onmessage = GodotRuntime.get_func(p_on_message).bind(null, p_ref); @@ -188,6 +199,7 @@ const GodotRTCDataChannel = { GodotRTCDataChannel.connect(p_id, onopen, onmessage, onerror, onclose); }, + godot_js_rtc_datachannel_close__sig: 'vi', godot_js_rtc_datachannel_close: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -280,6 +292,7 @@ const GodotRTCPeerConnection = { }, }, + godot_js_rtc_pc_create__sig: 'iiiiii', godot_js_rtc_pc_create: function (p_config, p_ref, p_on_state_change, p_on_candidate, p_on_datachannel) { const onstatechange = GodotRuntime.get_func(p_on_state_change).bind(null, p_ref); const oncandidate = GodotRuntime.get_func(p_on_candidate).bind(null, p_ref); @@ -302,6 +315,7 @@ const GodotRTCPeerConnection = { return id; }, + godot_js_rtc_pc_close__sig: 'vi', godot_js_rtc_pc_close: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -310,6 +324,7 @@ const GodotRTCPeerConnection = { ref.close(); }, + godot_js_rtc_pc_destroy__sig: 'vi', godot_js_rtc_pc_destroy: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -321,6 +336,7 @@ const GodotRTCPeerConnection = { IDHandler.remove(p_id); }, + godot_js_rtc_pc_offer_create__sig: 'viiii', godot_js_rtc_pc_offer_create: function (p_id, p_obj, p_on_session, p_on_error) { const ref = IDHandler.get(p_id); if (!ref) { @@ -335,6 +351,7 @@ const GodotRTCPeerConnection = { }); }, + godot_js_rtc_pc_local_description_set__sig: 'viiiii', godot_js_rtc_pc_local_description_set: function (p_id, p_type, p_sdp, p_obj, p_on_error) { const ref = IDHandler.get(p_id); if (!ref) { @@ -351,6 +368,7 @@ const GodotRTCPeerConnection = { }); }, + godot_js_rtc_pc_remote_description_set__sig: 'viiiiii', godot_js_rtc_pc_remote_description_set: function (p_id, p_type, p_sdp, p_obj, p_session_created, p_on_error) { const ref = IDHandler.get(p_id); if (!ref) { @@ -375,6 +393,7 @@ const GodotRTCPeerConnection = { }); }, + godot_js_rtc_pc_ice_candidate_add__sig: 'viiii', godot_js_rtc_pc_ice_candidate_add: function (p_id, p_mid_name, p_mline_idx, p_sdp) { const ref = IDHandler.get(p_id); if (!ref) { @@ -390,6 +409,7 @@ const GodotRTCPeerConnection = { }, godot_js_rtc_pc_datachannel_create__deps: ['$GodotRTCDataChannel'], + godot_js_rtc_pc_datachannel_create__sig: 'iiii', godot_js_rtc_pc_datachannel_create: function (p_id, p_label, p_config) { try { const ref = IDHandler.get(p_id); diff --git a/modules/websocket/library_godot_websocket.js b/modules/websocket/library_godot_websocket.js index 6ada4e7335..cf2c00a6a6 100644 --- a/modules/websocket/library_godot_websocket.js +++ b/modules/websocket/library_godot_websocket.js @@ -135,6 +135,7 @@ const GodotWebSocket = { }, }, + godot_js_websocket_create__sig: 'iiiiiiii', godot_js_websocket_create: function (p_ref, p_url, p_proto, p_on_open, p_on_message, p_on_error, p_on_close) { const on_open = GodotRuntime.get_func(p_on_open).bind(null, p_ref); const on_message = GodotRuntime.get_func(p_on_message).bind(null, p_ref); @@ -156,6 +157,7 @@ const GodotWebSocket = { return GodotWebSocket.create(socket, on_open, on_message, on_error, on_close); }, + godot_js_websocket_send__sig: 'iiiii', godot_js_websocket_send: function (p_id, p_buf, p_buf_len, p_raw) { const bytes_array = new Uint8Array(p_buf_len); let i = 0; @@ -169,12 +171,14 @@ const GodotWebSocket = { return GodotWebSocket.send(p_id, out); }, + godot_js_websocket_close__sig: 'viii', godot_js_websocket_close: function (p_id, p_code, p_reason) { const code = p_code; const reason = GodotRuntime.parseString(p_reason); GodotWebSocket.close(p_id, code, reason); }, + godot_js_websocket_destroy__sig: 'vi', godot_js_websocket_destroy: function (p_id) { GodotWebSocket.destroy(p_id); }, diff --git a/platform/android/SCsub b/platform/android/SCsub index ec42bc42b5..d8013b0baf 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -6,7 +6,6 @@ android_files = [ "os_android.cpp", "file_access_android.cpp", "audio_driver_opensl.cpp", - "file_access_jandroid.cpp", "dir_access_jandroid.cpp", "thread_jandroid.cpp", "net_socket_android.cpp", @@ -14,6 +13,7 @@ android_files = [ "java_godot_lib_jni.cpp", "java_class_wrapper.cpp", "java_godot_wrapper.cpp", + "java_godot_view_wrapper.cpp", "java_godot_io_wrapper.cpp", "jni_utils.cpp", "android_keys_utils.cpp", diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h index a10afa1df8..4a34e77324 100644 --- a/platform/android/android_keys_utils.h +++ b/platform/android/android_keys_utils.h @@ -35,8 +35,8 @@ #include <core/os/keyboard.h> struct _WinTranslatePair { - unsigned int keysym; - unsigned int keycode; + unsigned int keysym = 0; + unsigned int keycode = 0; }; static _WinTranslatePair _ak_to_keycode[] = { diff --git a/platform/android/api/java_class_wrapper.h b/platform/android/api/java_class_wrapper.h index 64da049407..63d71f5cf1 100644 --- a/platform/android/api/java_class_wrapper.h +++ b/platform/android/api/java_class_wrapper.h @@ -66,10 +66,10 @@ class JavaClass : public Reference { Map<StringName, Variant> constant_map; struct MethodInfo { - bool _static; + bool _static = false; Vector<uint32_t> param_types; Vector<StringName> param_sigs; - uint32_t return_type; + uint32_t return_type = 0; jmethodID method; }; diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp index 740e9a3132..e96e80e967 100644 --- a/platform/android/audio_driver_opensl.cpp +++ b/platform/android/audio_driver_opensl.cpp @@ -339,6 +339,4 @@ void AudioDriverOpenSL::set_pause(bool p_pause) { AudioDriverOpenSL::AudioDriverOpenSL() { s_ad = this; - pause = false; - active = false; } diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h index b30711705b..999cbe4657 100644 --- a/platform/android/audio_driver_opensl.h +++ b/platform/android/audio_driver_opensl.h @@ -38,19 +38,19 @@ #include <SLES/OpenSLES_Android.h> class AudioDriverOpenSL : public AudioDriver { - bool active; + bool active = false; Mutex mutex; enum { BUFFER_COUNT = 2 }; - bool pause; + bool pause = false; - uint32_t buffer_size; - int16_t *buffers[BUFFER_COUNT]; - int32_t *mixdown_buffer; - int last_free; + uint32_t buffer_size = 0; + int16_t *buffers[BUFFER_COUNT] = {}; + int32_t *mixdown_buffer = nullptr; + int last_free = 0; Vector<int16_t> rec_buffer; diff --git a/platform/android/detect.py b/platform/android/detect.py index 60d4146712..650606ff8b 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -334,6 +334,6 @@ def get_ndk_version(path): key_value = list(map(lambda x: x.strip(), line.split("="))) if key_value[0] == "Pkg.Revision": return key_value[1] - except: + except Exception: print("Could not read source prop file '%s'" % prop_file_path) return None diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index ba75a4b10c..ac619973d2 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -30,7 +30,7 @@ #include "dir_access_jandroid.h" #include "core/string/print_string.h" -#include "file_access_jandroid.h" +#include "file_access_android.h" #include "string_android.h" #include "thread_jandroid.h" @@ -146,7 +146,7 @@ bool DirAccessJAndroid::file_exists(String p_file) { else sd = current_dir.plus_file(p_file); - FileAccessJAndroid *f = memnew(FileAccessJAndroid); + FileAccessAndroid *f = memnew(FileAccessAndroid); bool exists = f->file_exists(sd); memdelete(f); diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index c8ed44d699..8711a4333c 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -686,7 +686,7 @@ void DisplayServerAndroid::process_hover(int p_type, Point2 p_pos) { } } -void DisplayServerAndroid::process_mouse_event(int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) { +void DisplayServerAndroid::process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) { int event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask); switch (event_action) { case AMOTION_EVENT_ACTION_BUTTON_PRESS: @@ -694,8 +694,13 @@ void DisplayServerAndroid::process_mouse_event(int event_action, int event_andro Ref<InputEventMouseButton> ev; ev.instance(); _set_key_modifier_state(ev); - ev->set_position(event_pos); - ev->set_global_position(event_pos); + if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { + ev->set_position(event_pos); + ev->set_global_position(event_pos); + } else { + ev->set_position(hover_prev_pos); + ev->set_global_position(hover_prev_pos); + } ev->set_pressed(event_action == AMOTION_EVENT_ACTION_BUTTON_PRESS); int changed_button_mask = buttons_state ^ event_buttons_mask; @@ -710,18 +715,29 @@ void DisplayServerAndroid::process_mouse_event(int event_action, int event_andro Ref<InputEventMouseMotion> ev; ev.instance(); _set_key_modifier_state(ev); - ev->set_position(event_pos); - ev->set_global_position(event_pos); - ev->set_relative(event_pos - hover_prev_pos); + if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { + ev->set_position(event_pos); + ev->set_global_position(event_pos); + ev->set_relative(event_pos - hover_prev_pos); + hover_prev_pos = event_pos; + } else { + ev->set_position(hover_prev_pos); + ev->set_global_position(hover_prev_pos); + ev->set_relative(event_pos); + } ev->set_button_mask(event_buttons_mask); Input::get_singleton()->accumulate_input_event(ev); - hover_prev_pos = event_pos; } break; case AMOTION_EVENT_ACTION_SCROLL: { Ref<InputEventMouseButton> ev; ev.instance(); - ev->set_position(event_pos); - ev->set_global_position(event_pos); + if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { + ev->set_position(event_pos); + ev->set_global_position(event_pos); + } else { + ev->set_position(hover_prev_pos); + ev->set_global_position(hover_prev_pos); + } ev->set_pressed(true); buttons_state = event_buttons_mask; if (event_vertical_factor > 0) { @@ -809,6 +825,24 @@ void DisplayServerAndroid::process_gyroscope(const Vector3 &p_gyroscope) { Input::get_singleton()->set_gyroscope(p_gyroscope); } +void DisplayServerAndroid::mouse_set_mode(MouseMode p_mode) { + if (mouse_mode == p_mode) { + return; + } + + if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) { + OS_Android::get_singleton()->get_godot_java()->get_godot_view()->request_pointer_capture(); + } else { + OS_Android::get_singleton()->get_godot_java()->get_godot_view()->release_pointer_capture(); + } + + mouse_mode = p_mode; +} + +DisplayServer::MouseMode DisplayServerAndroid::mouse_get_mode() const { + return mouse_mode; +} + Point2i DisplayServerAndroid::mouse_get_position() const { return hover_prev_pos; } diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index aa5a2c1185..f1f1a6a278 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -41,7 +41,7 @@ class RenderingDeviceVulkan; class DisplayServerAndroid : public DisplayServer { public: struct TouchPos { - int id; + int id = 0; Point2 pos; }; @@ -52,12 +52,12 @@ public: }; struct JoypadEvent { - int device; - int type; - int index; - bool pressed; - float value; - int hat; + int device = 0; + int type = 0; + int index = 0; + bool pressed = false; + float value = 0; + int hat = 0; }; private: @@ -70,6 +70,8 @@ private: int buttons_state; + MouseMode mouse_mode; + bool keep_screen_on; Vector<TouchPos> touch; @@ -172,12 +174,15 @@ public: void process_gyroscope(const Vector3 &p_gyroscope); void process_touch(int p_event, int p_pointer, const Vector<TouchPos> &p_points); void process_hover(int p_type, Point2 p_pos); - void process_mouse_event(int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0); + void process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0); void process_double_tap(int event_android_button_mask, Point2 p_pos); void process_scroll(Point2 p_pos); void process_joy_event(JoypadEvent p_event); void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); + void mouse_set_mode(MouseMode p_mode); + MouseMode mouse_get_mode() const; + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); static void register_android_driver(); diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index d24c96f87a..eed3b226c8 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -205,7 +205,7 @@ static const char *SPLASH_BG_COLOR_PATH = "res/drawable/splash_bg_color.png"; struct LauncherIcon { const char *export_path; - int dimensions; + int dimensions = 0; }; static const int icon_densities_count = 6; @@ -250,12 +250,12 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { String id; String name; String description; - int api_level; + int api_level = 0; }; struct APKExportData { zipFile apk; - EditorProgress *ep; + EditorProgress *ep = nullptr; }; Vector<PluginConfig> plugins; diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index 2446ca2829..0d933fb858 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -157,11 +157,6 @@ bool FileAccessAndroid::file_exists(const String &p_path) { return true; } -FileAccessAndroid::FileAccessAndroid() { - a = nullptr; - eof = false; -} - FileAccessAndroid::~FileAccessAndroid() { close(); } diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index a347c63ffb..7fc7d8c83d 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -39,10 +39,10 @@ class FileAccessAndroid : public FileAccess { static FileAccess *create_android(); - mutable AAsset *a; - mutable size_t len; - mutable size_t pos; - mutable bool eof; + mutable AAsset *a = nullptr; + mutable size_t len = 0; + mutable size_t pos = 0; + mutable bool eof = false; public: static AAssetManager *asset_manager; @@ -74,7 +74,6 @@ public: //static void make_default(); - FileAccessAndroid(); ~FileAccessAndroid(); }; diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp deleted file mode 100644 index df8b57fd3a..0000000000 --- a/platform/android/file_access_jandroid.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/*************************************************************************/ -/* file_access_jandroid.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "file_access_jandroid.h" -#include "core/os/os.h" -#include "thread_jandroid.h" -#include <unistd.h> - -jobject FileAccessJAndroid::io = nullptr; -jclass FileAccessJAndroid::cls; -jmethodID FileAccessJAndroid::_file_open = 0; -jmethodID FileAccessJAndroid::_file_get_size = 0; -jmethodID FileAccessJAndroid::_file_seek = 0; -jmethodID FileAccessJAndroid::_file_read = 0; -jmethodID FileAccessJAndroid::_file_tell = 0; -jmethodID FileAccessJAndroid::_file_eof = 0; -jmethodID FileAccessJAndroid::_file_close = 0; - -FileAccess *FileAccessJAndroid::create_jandroid() { - return memnew(FileAccessJAndroid); -} - -Error FileAccessJAndroid::_open(const String &p_path, int p_mode_flags) { - if (is_open()) - close(); - - String path = fix_path(p_path).simplify_path(); - if (path.begins_with("/")) - path = path.substr(1, path.length()); - else if (path.begins_with("res://")) - path = path.substr(6, path.length()); - - JNIEnv *env = ThreadAndroid::get_env(); - - jstring js = env->NewStringUTF(path.utf8().get_data()); - int res = env->CallIntMethod(io, _file_open, js, (p_mode_flags & WRITE) ? true : false); - env->DeleteLocalRef(js); - - OS::get_singleton()->print("fopen: '%s' ret %i\n", path.utf8().get_data(), res); - - if (res <= 0) - return ERR_FILE_CANT_OPEN; - id = res; - - return OK; -} - -void FileAccessJAndroid::close() { - if (!is_open()) - return; - - JNIEnv *env = ThreadAndroid::get_env(); - - env->CallVoidMethod(io, _file_close, id); - id = 0; -} - -bool FileAccessJAndroid::is_open() const { - return id != 0; -} - -void FileAccessJAndroid::seek(size_t p_position) { - JNIEnv *env = ThreadAndroid::get_env(); - - ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); - env->CallVoidMethod(io, _file_seek, id, p_position); -} - -void FileAccessJAndroid::seek_end(int64_t p_position) { - ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); - - seek(get_len()); -} - -size_t FileAccessJAndroid::get_position() const { - JNIEnv *env = ThreadAndroid::get_env(); - ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); - return env->CallIntMethod(io, _file_tell, id); -} - -size_t FileAccessJAndroid::get_len() const { - JNIEnv *env = ThreadAndroid::get_env(); - ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); - return env->CallIntMethod(io, _file_get_size, id); -} - -bool FileAccessJAndroid::eof_reached() const { - JNIEnv *env = ThreadAndroid::get_env(); - ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); - return env->CallIntMethod(io, _file_eof, id); -} - -uint8_t FileAccessJAndroid::get_8() const { - ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); - uint8_t byte; - get_buffer(&byte, 1); - return byte; -} - -int FileAccessJAndroid::get_buffer(uint8_t *p_dst, int p_length) const { - ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); - if (p_length == 0) - return 0; - JNIEnv *env = ThreadAndroid::get_env(); - - jbyteArray jca = (jbyteArray)env->CallObjectMethod(io, _file_read, id, p_length); - - int len = env->GetArrayLength(jca); - env->GetByteArrayRegion(jca, 0, len, (jbyte *)p_dst); - env->DeleteLocalRef((jobject)jca); - - return len; -} - -Error FileAccessJAndroid::get_error() const { - if (eof_reached()) - return ERR_FILE_EOF; - return OK; -} - -void FileAccessJAndroid::flush() { -} - -void FileAccessJAndroid::store_8(uint8_t p_dest) { -} - -bool FileAccessJAndroid::file_exists(const String &p_path) { - JNIEnv *env = ThreadAndroid::get_env(); - - String path = fix_path(p_path).simplify_path(); - if (path.begins_with("/")) - path = path.substr(1, path.length()); - else if (path.begins_with("res://")) - path = path.substr(6, path.length()); - - jstring js = env->NewStringUTF(path.utf8().get_data()); - int res = env->CallIntMethod(io, _file_open, js, false); - if (res <= 0) { - env->DeleteLocalRef(js); - return false; - } - env->CallVoidMethod(io, _file_close, res); - env->DeleteLocalRef(js); - return true; -} - -void FileAccessJAndroid::setup(jobject p_io) { - io = p_io; - JNIEnv *env = ThreadAndroid::get_env(); - - jclass c = env->GetObjectClass(io); - cls = (jclass)env->NewGlobalRef(c); - - _file_open = env->GetMethodID(cls, "file_open", "(Ljava/lang/String;Z)I"); - _file_get_size = env->GetMethodID(cls, "file_get_size", "(I)I"); - _file_tell = env->GetMethodID(cls, "file_tell", "(I)I"); - _file_eof = env->GetMethodID(cls, "file_eof", "(I)Z"); - _file_seek = env->GetMethodID(cls, "file_seek", "(II)V"); - _file_read = env->GetMethodID(cls, "file_read", "(II)[B"); - _file_close = env->GetMethodID(cls, "file_close", "(I)V"); -} - -FileAccessJAndroid::FileAccessJAndroid() { - id = 0; -} - -FileAccessJAndroid::~FileAccessJAndroid() { - if (is_open()) - close(); -} diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 3bbe35091c..ad1dc53bc0 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -988,4 +988,9 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC public void initInputDevices() { mRenderView.initInputDevices(); } + + @Keep + private GodotRenderView getRenderView() { // used by native side to get renderView + return mRenderView; + } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java index d731e080c4..2cd67933ee 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java @@ -144,6 +144,11 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView return inputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event); } + @Override + public boolean onCapturedPointerEvent(MotionEvent event) { + return inputHandler.onGenericMotionEvent(event); + } + private void init(XRMode xrMode, boolean translucent, int depth, int stencil) { setPreserveEGLContextOnPause(true); setFocusableInTouchMode(true); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java index 6cd5ca7b4e..d5e0345a9c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java @@ -120,6 +120,11 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV } @Override + public boolean onCapturedPointerEvent(MotionEvent event) { + return mInputHandler.onGenericMotionEvent(event); + } + + @Override public void onResume() { super.onResume(); diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java index 6d5be312f1..b052cd9d92 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java @@ -245,7 +245,7 @@ public class GodotInputHandler implements InputDeviceListener { } }); return true; - } else if ((event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) { + } else if (event.isFromSource(InputDevice.SOURCE_MOUSE) || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return handleMouseEvent(event); } @@ -462,6 +462,11 @@ public class GodotInputHandler implements InputDeviceListener { } }); } + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_UP: { + // we can safely ignore these cases because they are always come beside ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE + return true; + } } return false; } diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 5dc773fae2..48b8171222 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -43,7 +43,6 @@ #include "dir_access_jandroid.h" #include "display_server_android.h" #include "file_access_android.h" -#include "file_access_jandroid.h" #include "jni_utils.h" #include "main/main.h" #include "net_socket_android.h" @@ -89,14 +88,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en godot_io_java = new GodotIOJavaWrapper(env, godot_java->get_member_object("io", "Lorg/godotengine/godot/GodotIO;", env)); ThreadAndroid::make_default(jvm); -#ifdef USE_JAVA_FILE_ACCESS - FileAccessJAndroid::setup(godot_io_java->get_instance()); -#else jobject amgr = env->NewGlobalRef(p_asset_manager); FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr); -#endif DirAccessJAndroid::setup(godot_io_java->get_instance()); AudioDriverAndroid::setup(godot_io_java->get_instance()); @@ -251,9 +246,8 @@ void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, tp.id = (int)p[0]; points.push_back(tp); } - - if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { - DisplayServerAndroid::get_singleton()->process_mouse_event(ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor); + if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE || (input_device & AINPUT_SOURCE_MOUSE_RELATIVE) == AINPUT_SOURCE_MOUSE_RELATIVE) { + DisplayServerAndroid::get_singleton()->process_mouse_event(input_device, ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor); } else { DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points); } diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp new file mode 100644 index 0000000000..6655dd9895 --- /dev/null +++ b/platform/android/java_godot_view_wrapper.cpp @@ -0,0 +1,66 @@ +/*************************************************************************/ +/* java_godot_view_wrapper.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "java_godot_view_wrapper.h" + +#include "thread_jandroid.h" + +GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) { + JNIEnv *env = ThreadAndroid::get_env(); + + _godot_view = env->NewGlobalRef(godot_view); + + _cls = (jclass)env->NewGlobalRef(env->GetObjectClass(godot_view)); + + if (android_get_device_api_level() >= __ANDROID_API_O__) { + _request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V"); + _release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V"); + } +} + +void GodotJavaViewWrapper::request_pointer_capture() { + if (_request_pointer_capture != 0) { + JNIEnv *env = ThreadAndroid::get_env(); + env->CallVoidMethod(_godot_view, _request_pointer_capture); + } +} + +void GodotJavaViewWrapper::release_pointer_capture() { + if (_request_pointer_capture != 0) { + JNIEnv *env = ThreadAndroid::get_env(); + env->CallVoidMethod(_godot_view, _release_pointer_capture); + } +} + +GodotJavaViewWrapper::~GodotJavaViewWrapper() { + JNIEnv *env = ThreadAndroid::get_env(); + env->DeleteGlobalRef(_godot_view); + env->DeleteGlobalRef(_cls); +} diff --git a/editor/run_settings_dialog.h b/platform/android/java_godot_view_wrapper.h index 4d6d842de0..4c8f6edad0 100644 --- a/editor/run_settings_dialog.h +++ b/platform/android/java_godot_view_wrapper.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* run_settings_dialog.h */ +/* java_godot_view_wrapper.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,42 +28,29 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RUN_SETTINGS_DIALOG_H -#define RUN_SETTINGS_DIALOG_H +#ifndef GODOT_JAVA_GODOT_VIEW_WRAPPER_H +#define GODOT_JAVA_GODOT_VIEW_WRAPPER_H -#include "scene/gui/check_button.h" -#include "scene/gui/dialogs.h" -#include "scene/gui/file_dialog.h" -#include "scene/gui/line_edit.h" - -class RunSettingsDialog : public AcceptDialog { - GDCLASS(RunSettingsDialog, AcceptDialog); - -public: - enum RunMode { - RUN_LOCAL_SCENE, - RUN_MAIN_SCENE, - }; +#include <android/log.h> +#include <jni.h> +// Class that makes functions in java/src/org/godotengine/godot/GodotView.java callable from C++ +class GodotJavaViewWrapper { private: - OptionButton *run_mode; - LineEdit *arguments; + jclass _cls; - void _run_mode_changed(int idx); + jobject _godot_view; -protected: - static void _bind_methods(); + jmethodID _request_pointer_capture = 0; + jmethodID _release_pointer_capture = 0; public: - int get_run_mode() const; - void set_run_mode(int p_run_mode); - - void set_custom_arguments(const String &p_arguments); - String get_custom_arguments() const; + GodotJavaViewWrapper(jobject godot_view); - void popup_run_settings(); + void request_pointer_capture(); + void release_pointer_capture(); - RunSettingsDialog(); + ~GodotJavaViewWrapper(); }; -#endif // RUN_SETTINGS_DIALOG_H +#endif //GODOT_JAVA_GODOT_VIEW_WRAPPER_H diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp index cff591d903..7919e47b5c 100644 --- a/platform/android/java_godot_wrapper.cpp +++ b/platform/android/java_godot_wrapper.cpp @@ -109,6 +109,16 @@ jobject GodotJavaWrapper::get_class_loader() { } } +GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() { + if (_godot_view != nullptr) { + return _godot_view; + } + JNIEnv *env = ThreadAndroid::get_env(); + jmethodID godot_view_getter = env->GetMethodID(godot_class, "getRenderView", "()Lorg/godotengine/godot/GodotRenderView;"); + _godot_view = new GodotJavaViewWrapper(env->CallObjectMethod(godot_instance, godot_view_getter)); + return _godot_view; +} + void GodotJavaWrapper::on_video_init(JNIEnv *p_env) { if (_on_video_init) if (p_env == nullptr) diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h index e0c3809a64..c212e107cb 100644 --- a/platform/android/java_godot_wrapper.h +++ b/platform/android/java_godot_wrapper.h @@ -37,6 +37,7 @@ #include <android/log.h> #include <jni.h> +#include "java_godot_view_wrapper.h" #include "string_android.h" // Class that makes functions in java/src/org/godotengine/godot/Godot.java callable from C++ @@ -47,6 +48,8 @@ private: jclass godot_class; jclass activity_class; + GodotJavaViewWrapper *_godot_view = nullptr; + jmethodID _on_video_init = 0; jmethodID _restart = 0; jmethodID _finish = 0; @@ -74,6 +77,7 @@ public: jobject get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env = nullptr); jobject get_class_loader(); + GodotJavaViewWrapper *get_godot_view(); void on_video_init(JNIEnv *p_env = nullptr); void on_godot_main_loop_started(JNIEnv *p_env = nullptr); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 00733f6dbb..b90fb3ce6e 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -31,15 +31,13 @@ #include "os_android.h" #include "core/config/project_settings.h" -#include "core/io/file_access_buffered_fa.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" -#include "file_access_android.h" #include "main/main.h" #include "platform/android/display_server_android.h" #include "dir_access_jandroid.h" -#include "file_access_jandroid.h" +#include "file_access_android.h" #include "net_socket_android.h" #include <dlfcn.h> @@ -62,16 +60,10 @@ void OS_Android::initialize_core() { if (use_apk_expansion) FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES); else { -#ifdef USE_JAVA_FILE_ACCESS - FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid>>(FileAccess::ACCESS_RESOURCES); -#else - //FileAccess::make_default<FileAccessBufferedFA<FileAccessAndroid> >(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES); -#endif } FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM); - //FileAccessBufferedFA<FileAccessUnix>::make_default(); if (use_apk_expansion) DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES); else @@ -314,6 +306,7 @@ OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_god #if defined(OPENGL_ENABLED) gl_extensions = nullptr; use_gl2 = false; + use_16bits_fbo = false; #endif #if defined(VULKAN_ENABLED) diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index fff82c9467..3406c75c35 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -94,8 +94,8 @@ class EditorExportPlatformIOS : public EditorExportPlatform { struct IOSExportAsset { String exported_path; - bool is_framework; // framework is anything linked to the binary, otherwise it's a resource - bool should_embed; + bool is_framework = false; // framework is anything linked to the binary, otherwise it's a resource + bool should_embed = false; }; String _get_additional_plist_content(); @@ -314,9 +314,9 @@ Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_ge struct LoadingScreenInfo { const char *preset_key; const char *export_name; - int width; - int height; - bool rotate; + int width = 0; + int height = 0; + bool rotate = false; }; static const LoadingScreenInfo loading_screen_infos[] = { @@ -667,7 +667,7 @@ struct IconInfo { const char *actual_size_side; const char *scale; const char *unscaled_size; - bool is_required; + bool is_required = false; }; static const IconInfo icon_infos[] = { @@ -962,7 +962,7 @@ Error EditorExportPlatformIOS::_walk_dir_recursive(DirAccess *p_da, FileHandler struct CodesignData { const Ref<EditorExportPreset> &preset; - bool debug; + bool debug = false; CodesignData(const Ref<EditorExportPreset> &p_preset, bool p_debug) : preset(p_preset), diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub index 627ae778b1..7a8005fe30 100644 --- a/platform/javascript/SCsub +++ b/platform/javascript/SCsub @@ -12,13 +12,8 @@ javascript_files = [ "api/javascript_tools_editor_plugin.cpp", ] -build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"] -if env["threads_enabled"]: - build_targets.append("#bin/godot${PROGSUFFIX}.worker.js") - -build = env.add_program(build_targets, javascript_files) - -env.AddJSLibraries( +sys_env = env.Clone() +sys_env.AddJSLibraries( [ "js/libs/library_godot_audio.js", "js/libs/library_godot_display.js", @@ -29,12 +24,48 @@ env.AddJSLibraries( ) if env["tools"]: - env.AddJSLibraries(["js/libs/library_godot_editor_tools.js"]) + sys_env.AddJSLibraries(["js/libs/library_godot_editor_tools.js"]) if env["javascript_eval"]: - env.AddJSLibraries(["js/libs/library_godot_eval.js"]) -for lib in env["JS_LIBS"]: - env.Append(LINKFLAGS=["--js-library", lib]) -env.Depends(build, env["JS_LIBS"]) + sys_env.AddJSLibraries(["js/libs/library_godot_eval.js"]) +for lib in sys_env["JS_LIBS"]: + sys_env.Append(LINKFLAGS=["--js-library", lib]) + +build = [] +if env["gdnative_enabled"]: + build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"] + # Reset libraries. The main runtime will only link emscripten libraries, not godot ones. + sys_env["LIBS"] = [] + # We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly. + sys_env.Append(LIBS=["idbfs.js"]) + # JS prepended to the module code loading the side library. + sys_env.Append(LINKFLAGS=["--pre-js", sys_env.File("js/dynlink.pre.js")]) + # Configure it as a main module (dynamic linking support). + sys_env.Append(CCFLAGS=["-s", "MAIN_MODULE=1"]) + sys_env.Append(LINKFLAGS=["-s", "MAIN_MODULE=1"]) + sys_env.Append(CCFLAGS=["-s", "EXPORT_ALL=1"]) + sys_env.Append(LINKFLAGS=["-s", "EXPORT_ALL=1"]) + # Force exporting the standard library (printf, malloc, etc.) + sys_env["ENV"]["EMCC_FORCE_STDLIBS"] = "libc,libc++,libc++abi" + # The main emscripten runtime, with exported standard libraries. + sys = sys_env.Program(build_targets, ["javascript_runtime.cpp"]) + sys_env.Depends(sys, "js/dynlink.pre.js") + + # The side library, containing all Godot code. + wasm_env = env.Clone() + wasm_env.Append(CPPDEFINES=["WASM_GDNATIVE"]) # So that OS knows it can run GDNative libraries. + wasm_env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"]) + wasm_env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"]) + wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", javascript_files) + build = [sys[0], sys[1], wasm[0]] +else: + build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"] + if env["threads_enabled"]: + build_targets.append("#bin/godot${PROGSUFFIX}.worker.js") + # We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly. + sys_env.Append(LIBS=["idbfs.js"]) + build = sys_env.Program(build_targets, javascript_files + ["javascript_runtime.cpp"]) + +sys_env.Depends(build[0], sys_env["JS_LIBS"]) engine = [ "js/engine/preloader.js", @@ -61,10 +92,19 @@ out_files = [ ] html_file = "#misc/dist/html/editor.html" if env["tools"] else "#misc/dist/html/full-size.html" in_files = [js_wrapped, build[1], html_file, "#platform/javascript/js/libs/audio.worklet.js"] -if env["threads_enabled"]: - in_files.append(build[2]) +if env["gdnative_enabled"]: + in_files.append(build[2]) # Runtime + out_files.append(zip_dir.File(binary_name + ".side.wasm")) +elif env["threads_enabled"]: + in_files.append(build[2]) # Worker out_files.append(zip_dir.File(binary_name + ".worker.js")) +if env["tools"]: + in_files.append("#misc/dist/html/logo.svg") + out_files.append(zip_dir.File("logo.svg")) + in_files.append("#icon.png") + out_files.append(zip_dir.File("favicon.png")) + zip_files = env.InstallAs(out_files, in_files) env.Zip( "#bin/godot", diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index dd982bc3a8..78fbed6d0f 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -189,7 +189,9 @@ Error AudioDriverJavaScript::capture_start() { lock(); input_buffer_init(buffer_length); unlock(); - godot_audio_capture_start(); + if (godot_audio_capture_start()) { + return FAILED; + } return OK; } diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 9f584d0899..d53c774e77 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -1,6 +1,8 @@ import os +import sys from emscripten_helpers import run_closure_compiler, create_engine_file, add_js_libraries +from methods import get_compiler_version from SCons.Util import WhereIs @@ -20,9 +22,17 @@ def get_opts(): from SCons.Variables import BoolVariable return [ + ("initial_memory", "Initial WASM memory (in MiB)", 16), + BoolVariable("use_assertions", "Use Emscripten runtime assertions", False), + BoolVariable("use_thinlto", "Use ThinLTO", False), + BoolVariable("use_ubsan", "Use Emscripten undefined behavior sanitizer (UBSAN)", False), + BoolVariable("use_asan", "Use Emscripten address sanitizer (ASAN)", False), + BoolVariable("use_lsan", "Use Emscripten leak sanitizer (LSAN)", False), + BoolVariable("use_safe_heap", "Use Emscripten SAFE_HEAP sanitizer", False), # eval() can be a security concern, so it can be disabled. BoolVariable("javascript_eval", "Enable JavaScript eval interface", True), BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", False), + BoolVariable("gdnative_enabled", "Enable WebAssembly GDNative support (produces bigger binaries)", False), BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False), ] @@ -40,6 +50,9 @@ def get_flags(): def configure(env): + if not isinstance(env["initial_memory"], int): + print("Initial memory must be a valid integer") + sys.exit(255) ## Build type @@ -62,15 +75,18 @@ def configure(env): env.Append(CPPDEFINES=["DEBUG_ENABLED"]) env.Append(CCFLAGS=["-O1", "-g"]) env.Append(LINKFLAGS=["-O1", "-g"]) + env["use_assertions"] = True + + if env["use_assertions"]: env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"]) if env["tools"]: if not env["threads_enabled"]: - raise RuntimeError( - "Threads must be enabled to build the editor. Please add the 'threads_enabled=yes' option" - ) - # Tools need more memory. Initial stack memory in bytes. See `src/settings.js` in emscripten repository (will be renamed to INITIAL_MEMORY). - env.Append(LINKFLAGS=["-s", "TOTAL_MEMORY=33554432"]) + print("Threads must be enabled to build the editor. Please add the 'threads_enabled=yes' option") + sys.exit(255) + if env["initial_memory"] < 32: + print("Editor build requires at least 32MiB of initial memory. Forcing it.") + env["initial_memory"] = 32 elif env["builtin_icu"]: env.Append(CCFLAGS=["-frtti"]) else: @@ -80,15 +96,32 @@ def configure(env): # Don't use dynamic_cast, necessary with no-rtti. env.Append(CPPDEFINES=["NO_SAFE_CAST"]) + env.Append(LINKFLAGS=["-s", "INITIAL_MEMORY=%sMB" % env["initial_memory"]]) + ## Copy env variables. env["ENV"] = os.environ # LTO - if env["use_lto"]: - env.Append(CCFLAGS=["-s", "WASM_OBJECT_FILES=0"]) - env.Append(LINKFLAGS=["-s", "WASM_OBJECT_FILES=0"]) - env.Append(CCFLAGS=["-flto"]) - env.Append(LINKFLAGS=["-flto"]) + if env["use_thinlto"]: + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + elif env["use_lto"]: + env.Append(CCFLAGS=["-flto=full"]) + env.Append(LINKFLAGS=["-flto=full"]) + + # Sanitizers + if env["use_ubsan"]: + env.Append(CCFLAGS=["-fsanitize=undefined"]) + env.Append(LINKFLAGS=["-fsanitize=undefined"]) + if env["use_asan"]: + env.Append(CCFLAGS=["-fsanitize=address"]) + env.Append(LINKFLAGS=["-fsanitize=address"]) + if env["use_lsan"]: + env.Append(CCFLAGS=["-fsanitize=leak"]) + env.Append(LINKFLAGS=["-fsanitize=leak"]) + if env["use_safe_heap"]: + env.Append(CCFLAGS=["-s", "SAFE_HEAP=1"]) + env.Append(LINKFLAGS=["-s", "SAFE_HEAP=1"]) # Closure compiler if env["use_closure_compiler"]: @@ -135,6 +168,10 @@ def configure(env): if env["javascript_eval"]: env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"]) + if env["threads_enabled"] and env["gdnative_enabled"]: + print("Threads and GDNative support can't be both enabled due to WebAssembly limitations") + sys.exit(255) + # Thread support (via SharedArrayBuffer). if env["threads_enabled"]: env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"]) @@ -146,14 +183,19 @@ def configure(env): else: env.Append(CPPDEFINES=["NO_THREADS"]) + if env["gdnative_enabled"]: + major, minor, patch = get_compiler_version(env) + if major < 2 or (major == 2 and minor == 0 and patch < 10): + print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % (major, minor, patch)) + sys.exit(255) + env.Append(CCFLAGS=["-s", "RELOCATABLE=1"]) + env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"]) + env.extra_suffix = ".gdnative" + env.extra_suffix + # Reduce code size by generating less support code (e.g. skip NodeJS support). env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"]) - # We use IDBFS in javascript_main.cpp. Since Emscripten 1.39.1 it needs to - # be linked explicitly. - env.Append(LIBS=["idbfs.js"]) - - env.Append(LINKFLAGS=["-s", "BINARYEN=1"]) + # Wrap the JavaScript support code around a closure named Godot. env.Append(LINKFLAGS=["-s", "MODULARIZE=1", "-s", "EXPORT_NAME='Godot'"]) # Allow increasing memory buffer size during runtime. This is efficient @@ -164,12 +206,14 @@ def configure(env): # This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 1. env.Append(LINKFLAGS=["-s", "USE_WEBGL2=1"]) + # Do not call main immediately when the support code is ready. env.Append(LINKFLAGS=["-s", "INVOKE_RUN=0"]) # Allow use to take control of swapping WebGL buffers. env.Append(LINKFLAGS=["-s", "OFFSCREEN_FRAMEBUFFER=1"]) - # callMain for manual start, FS for preloading, PATH and ERRNO_CODES for BrowserFS. + # callMain for manual start. env.Append(LINKFLAGS=["-s", "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain']"]) + # Add code that allow exiting runtime. env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"]) diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index c3b7e0304e..37681b2484 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -37,16 +37,13 @@ #include "platform/javascript/logo.gen.h" #include "platform/javascript/run_icon.gen.h" -#define EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE "webassembly_release.zip" -#define EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG "webassembly_debug.zip" - class EditorHTTPServer : public Reference { private: Ref<TCP_Server> server; Ref<StreamPeerTCP> connection; - uint64_t time; + uint64_t time = 0; uint8_t req_buf[4096]; - int req_pos; + int req_pos = 0; void _clear_client() { connection = Ref<StreamPeerTCP>(); @@ -85,36 +82,44 @@ public: // Wrong protocol ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version."); - String filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export"); + const String cache_path = EditorSettings::get_singleton()->get_cache_dir(); const String basereq = "/tmp_js_export"; - String ctype = ""; + String filepath; + String ctype; if (req[1] == basereq + ".html") { - filepath += ".html"; + filepath = cache_path.plus_file(req[1].get_file()); ctype = "text/html"; } else if (req[1] == basereq + ".js") { - filepath += ".js"; + filepath = cache_path.plus_file(req[1].get_file()); ctype = "application/javascript"; } else if (req[1] == basereq + ".audio.worklet.js") { - filepath += ".audio.worklet.js"; + filepath = cache_path.plus_file(req[1].get_file()); ctype = "application/javascript"; } else if (req[1] == basereq + ".worker.js") { - filepath += ".worker.js"; + filepath = cache_path.plus_file(req[1].get_file()); ctype = "application/javascript"; } else if (req[1] == basereq + ".pck") { - filepath += ".pck"; + filepath = cache_path.plus_file(req[1].get_file()); ctype = "application/octet-stream"; } else if (req[1] == basereq + ".png" || req[1] == "/favicon.png") { // Also allow serving the generated favicon for a smoother loading experience. if (req[1] == "/favicon.png") { filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png"); } else { - filepath += ".png"; + filepath = basereq + ".png"; } ctype = "image/png"; + } else if (req[1] == basereq + ".side.wasm") { + filepath = cache_path.plus_file(req[1].get_file()); + ctype = "application/wasm"; } else if (req[1] == basereq + ".wasm") { - filepath += ".wasm"; + filepath = cache_path.plus_file(req[1].get_file()); ctype = "application/wasm"; - } else { + } else if (req[1].ends_with(".wasm")) { + filepath = cache_path.plus_file(req[1].get_file()); // TODO dangerous? + ctype = "application/wasm"; + } + if (filepath.empty() || !FileAccess::exists(filepath)) { String s = "HTTP/1.1 404 Not Found\r\n"; s += "Connection: Close\r\n"; s += "\r\n"; @@ -203,15 +208,40 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform { Ref<ImageTexture> logo; Ref<ImageTexture> run_icon; Ref<ImageTexture> stop_icon; - int menu_options; - - void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags); + int menu_options = 0; -private: Ref<EditorHTTPServer> server; - bool server_quit; + bool server_quit = false; Mutex server_lock; - Thread *server_thread; + Thread *server_thread = nullptr; + + enum ExportMode { + EXPORT_MODE_NORMAL = 0, + EXPORT_MODE_THREADS = 1, + EXPORT_MODE_GDNATIVE = 2, + }; + + String _get_template_name(ExportMode p_mode, bool p_debug) const { + String name = "webassembly"; + switch (p_mode) { + case EXPORT_MODE_THREADS: + name += "_threads"; + break; + case EXPORT_MODE_GDNATIVE: + name += "_gdnative"; + break; + default: + break; + } + if (p_debug) { + name += "_debug.zip"; + } else { + name += "_release.zip"; + } + return name; + } + + void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects); static void _server_thread_poll(void *data); @@ -250,7 +280,7 @@ public: ~EditorExportPlatformJavaScript(); }; -void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags) { +void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects) { String str_template = String::utf8(reinterpret_cast<const char *>(p_html.ptr()), p_html.size()); String str_export; Vector<String> lines = str_template.split("\n"); @@ -258,6 +288,10 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re String flags_json; gen_export_flags(flags, p_flags); flags_json = JSON::print(flags); + String libs; + for (int i = 0; i < p_shared_objects.size(); i++) { + libs += "\"" + p_shared_objects[i].path.get_file() + "\","; + } for (int i = 0; i < lines.size(); i++) { String current_line = lines[i]; @@ -265,6 +299,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re current_line = current_line.replace("$GODOT_PROJECT_NAME", ProjectSettings::get_singleton()->get_setting("application/config/name")); current_line = current_line.replace("$GODOT_HEAD_INCLUDE", p_preset->get("html/head_include")); current_line = current_line.replace("$GODOT_FULL_WINDOW", p_preset->get("html/full_window_size") ? "true" : "false"); + current_line = current_line.replace("$GODOT_GDNATIVE_LIBS", libs); current_line = current_line.replace("$GODOT_DEBUG_ENABLED", p_debug ? "true" : "false"); current_line = current_line.replace("$GODOT_ARGS", flags_json); str_export += current_line + "\n"; @@ -291,12 +326,19 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP r_features->push_back("etc2"); } } + ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); + if (mode == EXPORT_MODE_THREADS) { + r_features->push_back("threads"); + } else if (mode == EXPORT_MODE_GDNATIVE) { + r_features->push_back("wasm32"); + } } void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_options) { r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type. r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer @@ -320,11 +362,11 @@ Ref<Texture2D> EditorExportPlatformJavaScript::get_logo() const { bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; + ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); // Look for export templates (first official, and if defined custom templates). - - bool dvalid = exists_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG, &err); - bool rvalid = exists_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE, &err); + bool dvalid = exists_export_template(_get_template_name(mode, true), &err); + bool rvalid = exists_export_template(_get_template_name(mode, false), &err); if (p_preset->get("custom_template/debug") != "") { dvalid = FileAccess::exists(p_preset->get("custom_template/debug")); @@ -377,11 +419,8 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese template_path = template_path.strip_edges(); if (template_path == String()) { - if (p_debug) { - template_path = find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG); - } else { - template_path = find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE); - } + ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); + template_path = find_export_template(_get_template_name(mode, p_debug)); } if (!DirAccess::exists(p_path.get_base_dir())) { @@ -393,12 +432,24 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese return ERR_FILE_NOT_FOUND; } + Vector<SharedObject> shared_objects; String pck_path = p_path.get_basename() + ".pck"; - Error error = save_pack(p_preset, pck_path); + Error error = save_pack(p_preset, pck_path, &shared_objects); if (error != OK) { EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path); return error; } + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + for (int i = 0; i < shared_objects.size(); i++) { + String dst = p_path.get_base_dir().plus_file(shared_objects[i].path.get_file()); + error = da->copy(shared_objects[i].path, dst); + if (error != OK) { + EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + shared_objects[i].path.get_file()); + memdelete(da); + return error; + } + } + memdelete(da); FileAccess *src_f = nullptr; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); @@ -437,14 +488,18 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese if (!custom_html.empty()) { continue; } - _fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug, p_flags); + _fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects); file = p_path.get_file(); } else if (file == "godot.js") { file = p_path.get_file().get_basename() + ".js"; + } else if (file == "godot.worker.js") { file = p_path.get_file().get_basename() + ".worker.js"; + } else if (file == "godot.side.wasm") { + file = p_path.get_file().get_basename() + ".side.wasm"; + } else if (file == "godot.audio.worklet.js") { file = p_path.get_file().get_basename() + ".audio.worklet.js"; @@ -475,7 +530,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese buf.resize(f->get_len()); f->get_buffer(buf.ptrw(), buf.size()); memdelete(f); - _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug, p_flags); + _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects); f = FileAccess::open(p_path, FileAccess::WRITE); if (!f) { @@ -577,6 +632,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese DirAccess::remove_file_or_error(basepath + ".audio.worklet.js"); DirAccess::remove_file_or_error(basepath + ".pck"); DirAccess::remove_file_or_error(basepath + ".png"); + DirAccess::remove_file_or_error(basepath + ".side.wasm"); DirAccess::remove_file_or_error(basepath + ".wasm"); DirAccess::remove_file_or_error(EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png")); return err; @@ -625,7 +681,6 @@ void EditorExportPlatformJavaScript::_server_thread_poll(void *data) { EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { server.instance(); - server_quit = false; server_thread = Thread::create(_server_thread_poll, this); Ref<Image> img = memnew(Image(_javascript_logo)); @@ -642,8 +697,6 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { } else { stop_icon.instance(); } - - menu_options = 0; } EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() { diff --git a/platform/javascript/godot_audio.h b/platform/javascript/godot_audio.h index 7ebda3ad39..aeb234269e 100644 --- a/platform/javascript/godot_audio.h +++ b/platform/javascript/godot_audio.h @@ -41,14 +41,14 @@ extern int godot_audio_is_available(); extern int godot_audio_init(int p_mix_rate, int p_latency, void (*_state_cb)(int), void (*_latency_cb)(float)); extern void godot_audio_resume(); -extern void godot_audio_capture_start(); +extern int godot_audio_capture_start(); extern void godot_audio_capture_stop(); // Worklet typedef int32_t GodotAudioState[4]; extern void godot_audio_worklet_create(int p_channels); extern void godot_audio_worklet_start(float *p_in_buf, int p_in_size, float *p_out_buf, int p_out_size, GodotAudioState p_state); -extern void godot_audio_worklet_state_add(GodotAudioState p_state, int p_idx, int p_value); +extern int godot_audio_worklet_state_add(GodotAudioState p_state, int p_idx, int p_value); extern int godot_audio_worklet_state_get(GodotAudioState p_state, int p_idx); extern int godot_audio_worklet_state_wait(int32_t *p_state, int p_idx, int32_t p_expected, int p_timeout); diff --git a/platform/javascript/http_request.h b/platform/javascript/http_request.h index 54e98c1927..41e4749216 100644 --- a/platform/javascript/http_request.h +++ b/platform/javascript/http_request.h @@ -47,7 +47,7 @@ typedef enum { extern int godot_xhr_new(); extern void godot_xhr_reset(int p_xhr_id); -extern bool godot_xhr_free(int p_xhr_id); +extern void godot_xhr_free(int p_xhr_id); extern int godot_xhr_open(int p_xhr_id, const char *p_method, const char *p_url, const char *p_user = nullptr, const char *p_password = nullptr); diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp index 2d28a63566..b4985a4f36 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/javascript/javascript_main.cpp @@ -75,7 +75,7 @@ void main_loop_callback() { } /// When calling main, it is assumed FS is setup and synced. -int main(int argc, char *argv[]) { +extern EMSCRIPTEN_KEEPALIVE int godot_js_main(int argc, char *argv[]) { os = new OS_JavaScript(); // We must override main when testing is enabled diff --git a/platform/javascript/javascript_runtime.cpp b/platform/javascript/javascript_runtime.cpp new file mode 100644 index 0000000000..bfe9fbd1bc --- /dev/null +++ b/platform/javascript/javascript_runtime.cpp @@ -0,0 +1,35 @@ +/*************************************************************************/ +/* javascript_runtime.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +extern int godot_js_main(int argc, char *argv[]); + +int main(int argc, char *argv[]) { + return godot_js_main(argc, argv); +} diff --git a/platform/javascript/js/dynlink.pre.js b/platform/javascript/js/dynlink.pre.js new file mode 100644 index 0000000000..34bc371ea9 --- /dev/null +++ b/platform/javascript/js/dynlink.pre.js @@ -0,0 +1 @@ +Module['dynamicLibraries'] = [Module['thisProgram'] + '.side.wasm'].concat(Module['dynamicLibraries'] ? Module['dynamicLibraries'] : []); diff --git a/platform/javascript/js/engine/engine.js b/platform/javascript/js/engine/engine.js index 74153b672a..4b8a7dde69 100644 --- a/platform/javascript/js/engine/engine.js +++ b/platform/javascript/js/engine/engine.js @@ -34,6 +34,7 @@ const Engine = (function () { this.onExecute = null; this.onExit = null; this.persistentPaths = ['/userfs']; + this.gdnativeLibs = []; } Engine.prototype.init = /** @param {string=} basePath */ function (basePath) { @@ -58,6 +59,10 @@ const Engine = (function () { initPromise = new Promise(function (resolve, reject) { config['locateFile'] = Utils.createLocateRewrite(loadPath); config['instantiateWasm'] = Utils.createInstantiatePromise(loadPromise); + // Emscripten configuration. + config['thisProgram'] = me.executableName; + config['noExitRuntime'] = true; + config['dynamicLibraries'] = me.gdnativeLibs; Godot(config).then(function (module) { module['initFS'](me.persistentPaths).then(function (fs_err) { me.rtenv = module; @@ -119,9 +124,6 @@ const Engine = (function () { locale = navigator.languages ? navigator.languages[0] : navigator.language; locale = locale.split('.')[0]; } - // Emscripten configuration. - me.rtenv['thisProgram'] = me.executableName; - me.rtenv['noExitRuntime'] = true; // Godot configuration. me.rtenv['initConfig']({ 'resizeCanvasOnStart': me.resizeCanvasOnStart, @@ -249,6 +251,10 @@ const Engine = (function () { this.persistentPaths = persistentPaths; }; + Engine.prototype.setGDNativeLibraries = function (gdnativeLibs) { + this.gdnativeLibs = gdnativeLibs; + }; + Engine.prototype.requestQuit = function () { if (this.rtenv) { this.rtenv['request_quit'](); @@ -277,6 +283,7 @@ const Engine = (function () { Engine.prototype['setOnExit'] = Engine.prototype.setOnExit; Engine.prototype['copyToFS'] = Engine.prototype.copyToFS; Engine.prototype['setPersistentPaths'] = Engine.prototype.setPersistentPaths; + Engine.prototype['setGDNativeLibraries'] = Engine.prototype.setGDNativeLibraries; Engine.prototype['requestQuit'] = Engine.prototype.requestQuit; return Engine; }()); diff --git a/platform/javascript/js/engine/utils.js b/platform/javascript/js/engine/utils.js index d0fca4e1cb..9273bbad42 100644 --- a/platform/javascript/js/engine/utils.js +++ b/platform/javascript/js/engine/utils.js @@ -8,6 +8,8 @@ const Utils = { // eslint-disable-line no-unused-vars return `${execName}.audio.worklet.js`; } else if (path.endsWith('.js')) { return `${execName}.js`; + } else if (path.endsWith('.side.wasm')) { + return `${execName}.side.wasm`; } else if (path.endsWith('.wasm')) { return `${execName}.wasm`; } diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/javascript/js/libs/library_godot_audio.js index 0c1f477f34..d01b8d887b 100644 --- a/platform/javascript/js/libs/library_godot_audio.js +++ b/platform/javascript/js/libs/library_godot_audio.js @@ -77,28 +77,37 @@ const GodotAudio = { create_input: function (callback) { if (GodotAudio.input) { - return; // Already started. + return 0; // Already started. } function gotMediaInput(stream) { - GodotAudio.input = GodotAudio.ctx.createMediaStreamSource(stream); - callback(GodotAudio.input); + try { + GodotAudio.input = GodotAudio.ctx.createMediaStreamSource(stream); + callback(GodotAudio.input); + } catch (e) { + GodotRuntime.error('Failed creaating input.', e); + } } - if (navigator.mediaDevices.getUserMedia) { + if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { navigator.mediaDevices.getUserMedia({ 'audio': true, }).then(gotMediaInput, function (e) { - GodotRuntime.print(e); + GodotRuntime.error('Error getting user media.', e); }); } else { if (!navigator.getUserMedia) { navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; } + if (!navigator.getUserMedia) { + GodotRuntime.error('getUserMedia not available.'); + return 1; + } navigator.getUserMedia({ 'audio': true, }, gotMediaInput, function (e) { GodotRuntime.print(e); }); } + return 0; }, close_async: function (resolve, reject) { @@ -137,6 +146,7 @@ const GodotAudio = { }, }, + godot_audio_is_available__sig: 'i', godot_audio_is_available__proxy: 'sync', godot_audio_is_available: function () { if (!(window.AudioContext || window.webkitAudioContext)) { @@ -145,12 +155,14 @@ const GodotAudio = { return 1; }, + godot_audio_init__sig: 'iiiii', godot_audio_init: function (p_mix_rate, p_latency, p_state_change, p_latency_update) { const statechange = GodotRuntime.get_func(p_state_change); const latencyupdate = GodotRuntime.get_func(p_latency_update); return GodotAudio.init(p_mix_rate, p_latency, statechange, latencyupdate); }, + godot_audio_resume__sig: 'v', godot_audio_resume: function () { if (GodotAudio.ctx && GodotAudio.ctx.state !== 'running') { GodotAudio.ctx.resume(); @@ -158,16 +170,15 @@ const GodotAudio = { }, godot_audio_capture_start__proxy: 'sync', + godot_audio_capture_start__sig: 'i', godot_audio_capture_start: function () { - if (GodotAudio.input) { - return; // Already started. - } - GodotAudio.create_input(function (input) { + return GodotAudio.create_input(function (input) { input.connect(GodotAudio.driver.get_node()); }); }, godot_audio_capture_stop__proxy: 'sync', + godot_audio_capture_stop__sig: 'v', godot_audio_capture_stop: function () { if (GodotAudio.input) { const tracks = GodotAudio.input['mediaStream']['getTracks'](); @@ -241,10 +252,12 @@ const GodotAudioWorklet = { }, }, + godot_audio_worklet_create__sig: 'vi', godot_audio_worklet_create: function (channels) { GodotAudioWorklet.create(channels); }, + godot_audio_worklet_start__sig: 'viiiii', godot_audio_worklet_start: function (p_in_buf, p_in_size, p_out_buf, p_out_size, p_state) { const out_buffer = GodotRuntime.heapSub(HEAPF32, p_out_buf, p_out_size); const in_buffer = GodotRuntime.heapSub(HEAPF32, p_in_buf, p_in_size); @@ -252,15 +265,18 @@ const GodotAudioWorklet = { GodotAudioWorklet.start(in_buffer, out_buffer, state); }, + godot_audio_worklet_state_wait__sig: 'iiii', godot_audio_worklet_state_wait: function (p_state, p_idx, p_expected, p_timeout) { Atomics.wait(HEAP32, (p_state >> 2) + p_idx, p_expected, p_timeout); return Atomics.load(HEAP32, (p_state >> 2) + p_idx); }, + godot_audio_worklet_state_add__sig: 'iiii', godot_audio_worklet_state_add: function (p_state, p_idx, p_value) { return Atomics.add(HEAP32, (p_state >> 2) + p_idx, p_value); }, + godot_audio_worklet_state_get__sig: 'iii', godot_audio_worklet_state_get: function (p_state, p_idx) { return Atomics.load(HEAP32, (p_state >> 2) + p_idx); }, @@ -330,10 +346,12 @@ const GodotAudioScript = { }, }, + godot_audio_script_create__sig: 'iii', godot_audio_script_create: function (buffer_length, channel_count) { return GodotAudioScript.create(buffer_length, channel_count); }, + godot_audio_script_start__sig: 'viiiii', godot_audio_script_start: function (p_in_buf, p_in_size, p_out_buf, p_out_size, p_cb) { const onprocess = GodotRuntime.get_func(p_cb); GodotAudioScript.start(p_in_buf, p_in_size, p_out_buf, p_out_size, onprocess); diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js index 9651b48952..800d6f414f 100644 --- a/platform/javascript/js/libs/library_godot_display.js +++ b/platform/javascript/js/libs/library_godot_display.js @@ -280,6 +280,7 @@ const GodotDisplay = { window_icon: '', }, + godot_js_display_is_swap_ok_cancel__sig: 'i', godot_js_display_is_swap_ok_cancel: function () { const win = (['Windows', 'Win64', 'Win32', 'WinCE']); const plat = navigator.platform || ''; @@ -289,10 +290,12 @@ const GodotDisplay = { return 0; }, + godot_js_display_alert__sig: 'vi', godot_js_display_alert: function (p_text) { window.alert(GodotRuntime.parseString(p_text)); // eslint-disable-line no-alert }, + godot_js_display_pixel_ratio_get__sig: 'f', godot_js_display_pixel_ratio_get: function () { return window.devicePixelRatio || 1; }, @@ -300,14 +303,17 @@ const GodotDisplay = { /* * Canvas */ + godot_js_display_canvas_focus__sig: 'v', godot_js_display_canvas_focus: function () { GodotConfig.canvas.focus(); }, + godot_js_display_canvas_is_focused__sig: 'i', godot_js_display_canvas_is_focused: function () { return document.activeElement === GodotConfig.canvas; }, + godot_js_display_canvas_bounding_rect_position_get__sig: 'vii', godot_js_display_canvas_bounding_rect_position_get: function (r_x, r_y) { const brect = GodotConfig.canvas.getBoundingClientRect(); GodotRuntime.setHeapValue(r_x, brect.x, 'i32'); @@ -317,6 +323,7 @@ const GodotDisplay = { /* * Touchscreen */ + godot_js_display_touchscreen_is_available__sig: 'i', godot_js_display_touchscreen_is_available: function () { return 'ontouchstart' in window; }, @@ -324,6 +331,7 @@ const GodotDisplay = { /* * Clipboard */ + godot_js_display_clipboard_set__sig: 'ii', godot_js_display_clipboard_set: function (p_text) { const text = GodotRuntime.parseString(p_text); if (!navigator.clipboard || !navigator.clipboard.writeText) { @@ -336,6 +344,7 @@ const GodotDisplay = { return 0; }, + godot_js_display_clipboard_get__sig: 'ii', godot_js_display_clipboard_get: function (callback) { const func = GodotRuntime.get_func(callback); try { @@ -354,6 +363,7 @@ const GodotDisplay = { /* * Window */ + godot_js_display_window_request_fullscreen__sig: 'v', godot_js_display_window_request_fullscreen: function () { const canvas = GodotConfig.canvas; (canvas.requestFullscreen || canvas.msRequestFullscreen @@ -362,10 +372,12 @@ const GodotDisplay = { ).call(canvas); }, + godot_js_display_window_title_set__sig: 'vi', godot_js_display_window_title_set: function (p_data) { document.title = GodotRuntime.parseString(p_data); }, + godot_js_display_window_icon_set__sig: 'vii', godot_js_display_window_icon_set: function (p_ptr, p_len) { let link = document.getElementById('-gd-engine-icon'); if (link === null) { @@ -386,6 +398,7 @@ const GodotDisplay = { /* * Cursor */ + godot_js_display_cursor_set_visible__sig: 'vi', godot_js_display_cursor_set_visible: function (p_visible) { const visible = p_visible !== 0; if (visible === GodotDisplayCursor.visible) { @@ -399,14 +412,17 @@ const GodotDisplay = { } }, + godot_js_display_cursor_is_hidden__sig: 'i', godot_js_display_cursor_is_hidden: function () { return !GodotDisplayCursor.visible; }, + godot_js_display_cursor_set_shape__sig: 'vi', godot_js_display_cursor_set_shape: function (p_string) { GodotDisplayCursor.set_shape(GodotRuntime.parseString(p_string)); }, + godot_js_display_cursor_set_custom_shape__sig: 'viiiii', godot_js_display_cursor_set_custom_shape: function (p_shape, p_ptr, p_len, p_hotspot_x, p_hotspot_y) { const shape = GodotRuntime.parseString(p_shape); const old_shape = GodotDisplayCursor.cursors[shape]; @@ -432,6 +448,7 @@ const GodotDisplay = { /* * Listeners */ + godot_js_display_notification_cb__sig: 'viiiii', godot_js_display_notification_cb: function (callback, p_enter, p_exit, p_in, p_out) { const canvas = GodotConfig.canvas; const func = GodotRuntime.get_func(callback); @@ -443,6 +460,7 @@ const GodotDisplay = { }); }, + godot_js_display_paste_cb__sig: 'vi', godot_js_display_paste_cb: function (callback) { const func = GodotRuntime.get_func(callback); GodotDisplayListeners.add(window, 'paste', function (evt) { @@ -453,6 +471,7 @@ const GodotDisplay = { }, false); }, + godot_js_display_drop_files_cb__sig: 'vi', godot_js_display_drop_files_cb: function (callback) { const func = GodotRuntime.get_func(callback); const dropFiles = function (files) { diff --git a/platform/javascript/js/libs/library_godot_editor_tools.js b/platform/javascript/js/libs/library_godot_editor_tools.js index f39fed04a8..12edc8e733 100644 --- a/platform/javascript/js/libs/library_godot_editor_tools.js +++ b/platform/javascript/js/libs/library_godot_editor_tools.js @@ -30,6 +30,7 @@ const GodotEditorTools = { godot_js_editor_download_file__deps: ['$FS'], + godot_js_editor_download_file__sig: 'viii', godot_js_editor_download_file: function (p_path, p_name, p_mime) { const path = GodotRuntime.parseString(p_path); const name = GodotRuntime.parseString(p_name); diff --git a/platform/javascript/js/libs/library_godot_eval.js b/platform/javascript/js/libs/library_godot_eval.js index 33ff231726..1a2440dd24 100644 --- a/platform/javascript/js/libs/library_godot_eval.js +++ b/platform/javascript/js/libs/library_godot_eval.js @@ -30,6 +30,7 @@ const GodotEval = { godot_js_eval__deps: ['$GodotRuntime'], + godot_js_eval__sig: 'iiiiiii', godot_js_eval: function (p_js, p_use_global_ctx, p_union_ptr, p_byte_arr, p_byte_arr_write, p_callback) { const js_code = GodotRuntime.parseString(p_js); let eval_ret = null; diff --git a/platform/javascript/js/libs/library_godot_http_request.js b/platform/javascript/js/libs/library_godot_http_request.js index 2b9aa88208..d4468bd5aa 100644 --- a/platform/javascript/js/libs/library_godot_http_request.js +++ b/platform/javascript/js/libs/library_godot_http_request.js @@ -50,6 +50,7 @@ const GodotHTTPRequest = { }, }, + godot_xhr_new__sig: 'i', godot_xhr_new: function () { const newId = GodotHTTPRequest.getUnusedRequestId(); GodotHTTPRequest.requests[newId] = new XMLHttpRequest(); @@ -57,30 +58,36 @@ const GodotHTTPRequest = { return newId; }, + godot_xhr_reset__sig: 'vi', godot_xhr_reset: function (xhrId) { GodotHTTPRequest.requests[xhrId] = new XMLHttpRequest(); GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[xhrId]); }, + godot_xhr_free__sig: 'vi', godot_xhr_free: function (xhrId) { GodotHTTPRequest.requests[xhrId].abort(); GodotHTTPRequest.requests[xhrId] = null; }, + godot_xhr_open__sig: 'viiiii', godot_xhr_open: function (xhrId, method, url, p_user, p_password) { const user = p_user > 0 ? GodotRuntime.parseString(p_user) : null; const password = p_password > 0 ? GodotRuntime.parseString(p_password) : null; GodotHTTPRequest.requests[xhrId].open(GodotRuntime.parseString(method), GodotRuntime.parseString(url), true, user, password); }, + godot_xhr_set_request_header__sig: 'viii', godot_xhr_set_request_header: function (xhrId, header, value) { GodotHTTPRequest.requests[xhrId].setRequestHeader(GodotRuntime.parseString(header), GodotRuntime.parseString(value)); }, + godot_xhr_send_null__sig: 'vi', godot_xhr_send_null: function (xhrId) { GodotHTTPRequest.requests[xhrId].send(); }, + godot_xhr_send_string__sig: 'vii', godot_xhr_send_string: function (xhrId, strPtr) { if (!strPtr) { GodotRuntime.error('Failed to send string per XHR: null pointer'); @@ -89,6 +96,7 @@ const GodotHTTPRequest = { GodotHTTPRequest.requests[xhrId].send(GodotRuntime.parseString(strPtr)); }, + godot_xhr_send_data__sig: 'viii', godot_xhr_send_data: function (xhrId, ptr, len) { if (!ptr) { GodotRuntime.error('Failed to send data per XHR: null pointer'); @@ -101,23 +109,28 @@ const GodotHTTPRequest = { GodotHTTPRequest.requests[xhrId].send(HEAPU8.subarray(ptr, ptr + len)); }, + godot_xhr_abort__sig: 'vi', godot_xhr_abort: function (xhrId) { GodotHTTPRequest.requests[xhrId].abort(); }, + godot_xhr_get_status__sig: 'ii', godot_xhr_get_status: function (xhrId) { return GodotHTTPRequest.requests[xhrId].status; }, + godot_xhr_get_ready_state__sig: 'ii', godot_xhr_get_ready_state: function (xhrId) { return GodotHTTPRequest.requests[xhrId].readyState; }, + godot_xhr_get_response_headers_length__sig: 'ii', godot_xhr_get_response_headers_length: function (xhrId) { const headers = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders(); return headers === null ? 0 : GodotRuntime.strlen(headers); }, + godot_xhr_get_response_headers__sig: 'viii', godot_xhr_get_response_headers: function (xhrId, dst, len) { const str = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders(); if (str === null) { @@ -126,11 +139,13 @@ const GodotHTTPRequest = { GodotRuntime.stringToHeap(str, dst, len); }, + godot_xhr_get_response_length__sig: 'ii', godot_xhr_get_response_length: function (xhrId) { const body = GodotHTTPRequest.requests[xhrId].response; return body === null ? 0 : body.byteLength; }, + godot_xhr_get_response__sig: 'viii', godot_xhr_get_response: function (xhrId, dst, len) { let buf = GodotHTTPRequest.requests[xhrId].response; if (buf === null) { diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js index 44b104922e..260cfbf97f 100644 --- a/platform/javascript/js/libs/library_godot_os.js +++ b/platform/javascript/js/libs/library_godot_os.js @@ -75,14 +75,17 @@ const GodotConfig = { }, }, + godot_js_config_canvas_id_get__sig: 'vii', godot_js_config_canvas_id_get: function (p_ptr, p_ptr_max) { GodotRuntime.stringToHeap(`#${GodotConfig.canvas.id}`, p_ptr, p_ptr_max); }, + godot_js_config_locale_get__sig: 'vii', godot_js_config_locale_get: function (p_ptr, p_ptr_max) { GodotRuntime.stringToHeap(GodotConfig.locale, p_ptr, p_ptr_max); }, + godot_js_config_is_resize_on_start__sig: 'i', godot_js_config_is_resize_on_start: function () { return GodotConfig.resize_on_start ? 1 : 0; }, @@ -239,19 +242,23 @@ const GodotOS = { }, }, + godot_js_os_finish_async__sig: 'vi', godot_js_os_finish_async: function (p_callback) { const func = GodotRuntime.get_func(p_callback); GodotOS.finish_async(func); }, + godot_js_os_request_quit_cb__sig: 'vi', godot_js_os_request_quit_cb: function (p_callback) { GodotOS.request_quit = GodotRuntime.get_func(p_callback); }, + godot_js_os_fs_is_persistent__sig: 'i', godot_js_os_fs_is_persistent: function () { return GodotFS.is_persistent(); }, + godot_js_os_fs_sync__sig: 'vi', godot_js_os_fs_sync: function (callback) { const func = GodotRuntime.get_func(callback); GodotOS._fs_sync_promise = GodotFS.sync(); @@ -260,6 +267,7 @@ const GodotOS = { }); }, + godot_js_os_execute__sig: 'ii', godot_js_os_execute: function (p_json) { const json_args = GodotRuntime.parseString(p_json); const args = JSON.parse(json_args); @@ -270,6 +278,7 @@ const GodotOS = { return 1; }, + godot_js_os_shell_open__sig: 'vi', godot_js_os_shell_open: function (p_uri) { window.open(GodotRuntime.parseString(p_uri), '_blank'); }, diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 80723d54fc..8c976da58e 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -31,7 +31,6 @@ #include "os_javascript.h" #include "core/debugger/engine_debugger.h" -#include "core/io/file_access_buffered_fa.h" #include "core/io/json.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" @@ -43,6 +42,7 @@ #include "modules/websocket/remote_debugger_peer_websocket.h" #endif +#include <dlfcn.h> #include <emscripten.h> #include <stdlib.h> @@ -51,7 +51,6 @@ // Lifecycle void OS_JavaScript::initialize() { OS_Unix::initialize_core(); - FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix>>(FileAccess::ACCESS_RESOURCES); DisplayServerJavaScript::register_javascript_driver(); #ifdef MODULE_WEBSOCKET_ENABLED @@ -127,12 +126,24 @@ int OS_JavaScript::get_process_id() const { } bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) { - if (p_feature == "HTML5" || p_feature == "web") + if (p_feature == "HTML5" || p_feature == "web") { return true; + } #ifdef JAVASCRIPT_EVAL_ENABLED - if (p_feature == "JavaScript") + if (p_feature == "JavaScript") { + return true; + } +#endif +#ifndef NO_THREADS + if (p_feature == "threads") { return true; + } +#endif +#if WASM_GDNATIVE + if (p_feature == "wasm32") { + return true; + } #endif return false; @@ -187,6 +198,13 @@ bool OS_JavaScript::is_userfs_persistent() const { return idb_available; } +Error OS_JavaScript::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { + String path = p_path.get_file(); + p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); + ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ". Error: " + dlerror()); + return OK; +} + OS_JavaScript *OS_JavaScript::get_singleton() { return static_cast<OS_JavaScript *>(OS::get_singleton()); } diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 03a3053367..6682f8fd85 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -87,6 +87,7 @@ public: String get_user_data_dir() const override; bool is_userfs_persistent() const override; + Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) override; void resume_audio(); diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp index e5a9bb4737..709523e836 100644 --- a/platform/linuxbsd/detect_prime_x11.cpp +++ b/platform/linuxbsd/detect_prime_x11.cpp @@ -56,7 +56,7 @@ typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLX struct vendor { const char *glxvendor; - int priority; + int priority = 0; }; vendor vendormap[] = { diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 3c6f462e92..0507ef3fff 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -63,25 +63,25 @@ // Hints for X11 fullscreen typedef struct { - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long inputMode; - unsigned long status; + unsigned long flags = 0; + unsigned long functions = 0; + unsigned long decorations = 0; + long inputMode = 0; + unsigned long status = 0; } Hints; typedef struct _xrr_monitor_info { Atom name; - Bool primary; - Bool automatic; - int noutput; - int x; - int y; - int width; - int height; - int mwidth; - int mheight; - RROutput *outputs; + Bool primary = false; + Bool automatic = false; + int noutput = 0; + int x = 0; + int y = 0; + int width = 0; + int height = 0; + int mwidth = 0; + int mheight = 0; + RROutput *outputs = nullptr; } xrr_monitor_info; #undef CursorShape diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 4a9d0a8181..0676587f7a 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -49,15 +49,6 @@ static const char *ignore_str = "/dev/input/js"; #endif -JoypadLinux::Joypad::Joypad() { - fd = -1; - dpad = 0; - devpath = ""; - for (int i = 0; i < MAX_ABS; i++) { - abs_info[i] = nullptr; - } -} - JoypadLinux::Joypad::~Joypad() { for (int i = 0; i < MAX_ABS; i++) { if (abs_info[i]) { diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h index 0d175193a5..71eab78f99 100644 --- a/platform/linuxbsd/joypad_linux.h +++ b/platform/linuxbsd/joypad_linux.h @@ -56,17 +56,16 @@ private: Input::JoyAxis curr_axis[MAX_ABS]; int key_map[MAX_KEY]; int abs_map[MAX_ABS]; - int dpad; - int fd; + int dpad = 0; + int fd = -1; String devpath; - input_absinfo *abs_info[MAX_ABS]; + input_absinfo *abs_info[MAX_ABS] = {}; - bool force_feedback; - int ff_effect_id; - uint64_t ff_effect_timestamp; + bool force_feedback = false; + int ff_effect_id = 0; + uint64_t ff_effect_timestamp = 0; - Joypad(); ~Joypad(); void reset(); }; diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index e569aa03d7..ac88d457a7 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -303,65 +303,147 @@ static String get_mountpoint(const String &p_path) { } Error OS_LinuxBSD::move_to_trash(const String &p_path) { - String trash_can = ""; + int err_code; + List<String> args; + args.push_back(p_path); + args.push_front("trash"); // The command is `gio trash <file_name>` so we need to add it to args. + Error result = execute("gio", args, true, nullptr, nullptr, &err_code); // For GNOME based machines. + if (result == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + + args.pop_front(); + args.push_front("move"); + args.push_back("trash:/"); // The command is `kioclient5 move <file_name> trash:/`. + result = execute("kioclient5", args, true, nullptr, nullptr, &err_code); // For KDE based machines. + if (result == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + + args.pop_front(); + args.pop_back(); + result = execute("gvfs-trash", args, true, nullptr, nullptr, &err_code); // For older Linux machines. + if (result == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + + // If the commands `kioclient5`, `gio` or `gvfs-trash` don't exist on the system we do it manually. + String trash_path = ""; String mnt = get_mountpoint(p_path); - // If there is a directory "[Mountpoint]/.Trash-[UID]/files", use it as the trash can. + // If there is a directory "[Mountpoint]/.Trash-[UID], use it as the trash can. if (mnt != "") { - String path(mnt + "/.Trash-" + itos(getuid()) + "/files"); + String path(mnt + "/.Trash-" + itos(getuid())); struct stat s; if (!stat(path.utf8().get_data(), &s)) { - trash_can = path; + trash_path = path; } } - // Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash/files" as the trash can. - if (trash_can == "") { + // Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash" as the trash can. + if (trash_path == "") { char *dhome = getenv("XDG_DATA_HOME"); if (dhome) { - trash_can = String(dhome) + "/Trash/files"; + trash_path = String(dhome) + "/Trash"; } } - // Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash/files" as the trash can. - if (trash_can == "") { + // Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash" as the trash can. + if (trash_path == "") { char *home = getenv("HOME"); if (home) { - trash_can = String(home) + "/.local/share/Trash/files"; + trash_path = String(home) + "/.local/share/Trash"; } } // Issue an error if none of the previous locations is appropriate for the trash can. - if (trash_can == "") { - ERR_PRINT("move_to_trash: Could not determine the trash can location"); - return FAILED; - } + ERR_FAIL_COND_V_MSG(trash_path == "", FAILED, "Could not determine the trash can location"); // Create needed directories for decided trash can location. - DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - Error err = dir_access->make_dir_recursive(trash_can); - memdelete(dir_access); + { + DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Error err = dir_access->make_dir_recursive(trash_path); + + // Issue an error if trash can is not created proprely. + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\""); + err = dir_access->make_dir_recursive(trash_path + "/files"); + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/files"); + err = dir_access->make_dir_recursive(trash_path + "/info"); + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/info"); + memdelete(dir_access); + } - // Issue an error if trash can is not created proprely. - if (err != OK) { - ERR_PRINT("move_to_trash: Could not create the trash can \"" + trash_can + "\""); - return err; + // The trash can is successfully created, now we check that we don't exceed our file name length limit. + // If the file name is too long trim it so we can add the identifying number and ".trashinfo". + // Assumes that the file name length limit is 255 characters. + String file_name = basename(p_path.utf8().get_data()); + if (file_name.length() > 240) { + file_name = file_name.substr(0, file_name.length() - 15); + } + + String dest_path = trash_path + "/files/" + file_name; + struct stat buff; + int id_number = 0; + String fn = file_name; + + // Checks if a resource with the same name already exist in the trash can, + // if there is, add an identifying number to our resource's name. + while (stat(dest_path.utf8().get_data(), &buff) == 0) { + id_number++; + + // Added a limit to check for identically named files already on the trash can + // if there are too many it could make the editor unresponsive. + ERR_FAIL_COND_V_MSG(id_number > 99, FAILED, "Too many identically named resources already in the trash can."); + fn = file_name + "." + itos(id_number); + dest_path = trash_path + "/files/" + fn; + } + file_name = fn; + + // Generates the .trashinfo file + OS::Date date = OS::get_singleton()->get_date(false); + OS::Time time = OS::get_singleton()->get_time(false); + String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, date.month, date.day, time.hour, time.min); + timestamp = vformat("%s%02d", timestamp, time.sec); // vformat only supports up to 6 arguments. + String trash_info = "[Trash Info]\nPath=" + p_path.http_escape() + "\nDeletionDate=" + timestamp + "\n"; + { + Error err; + FileAccess *file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err); + ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file:" + trash_path + "/info/" + file_name + ".trashinfo"); + file->store_string(trash_info); + file->close(); + + // Rename our resource before moving it to the trash can. + DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + err = dir_access->rename(p_path, p_path.get_base_dir() + "/" + file_name); + ERR_FAIL_COND_V_MSG(err != OK, err, "Can't rename file \"" + p_path + "\""); + memdelete(dir_access); } - // The trash can is successfully created, now move the given resource to it. + // Move the given resource to the trash can. // Do not use DirAccess:rename() because it can't move files across multiple mountpoints. List<String> mv_args; - mv_args.push_back(p_path); - mv_args.push_back(trash_can); - int retval; - err = execute("mv", mv_args, true, nullptr, nullptr, &retval); - - // Issue an error if "mv" failed to move the given resource to the trash can. - if (err != OK || retval != 0) { - ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_can + "\""); - return FAILED; + mv_args.push_back(p_path.get_base_dir() + "/" + file_name); + mv_args.push_back(trash_path + "/files"); + { + int retval; + Error err = execute("mv", mv_args, true, nullptr, nullptr, &retval); + + // Issue an error if "mv" failed to move the given resource to the trash can. + if (err != OK || retval != 0) { + ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_path + "/files\""); + DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + err = dir_access->rename(p_path.get_base_dir() + "/" + file_name, p_path); + memdelete(dir_access); + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not rename " + p_path.get_base_dir() + "/" + file_name + " back to its original name:" + p_path); + return FAILED; + } } - return OK; } diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index 073d35008b..ea55a3ff28 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -77,13 +77,13 @@ public: struct KeyEvent { WindowID window_id; - unsigned int osx_state; - bool pressed; - bool echo; - bool raw; - uint32_t keycode; - uint32_t physical_keycode; - uint32_t unicode; + unsigned int osx_state = false; + bool pressed = false; + bool echo = false; + bool raw = false; + uint32_t keycode = 0; + uint32_t physical_keycode = 0; + uint32_t unicode = 0; }; struct WarpEvent { diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index f5aad91946..eecd2ed641 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -48,7 +48,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform { GDCLASS(EditorExportPlatformOSX, EditorExportPlatform); - int version_code; + int version_code = 0; Ref<ImageTexture> logo; diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp index cfc371710b..b2871b261e 100644 --- a/platform/osx/joypad_osx.cpp +++ b/platform/osx/joypad_osx.cpp @@ -37,14 +37,6 @@ static JoypadOSX *self = nullptr; joypad::joypad() { - device_ref = nullptr; - ff_device = nullptr; - ff_axes = nullptr; - ff_directions = nullptr; - ffservice = 0; - ff_timestamp = 0; - id = 0; - ff_constant_force.lMagnitude = 10000; ff_effect.dwDuration = 0; ff_effect.dwSamplePeriod = 0; diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h index dc238e68e4..6c2a1ea70b 100644 --- a/platform/osx/joypad_osx.h +++ b/platform/osx/joypad_osx.h @@ -46,10 +46,10 @@ struct rec_element { IOHIDElementRef ref; IOHIDElementCookie cookie; - uint32_t usage; + uint32_t usage = 0; - int min; - int max; + int min = 0; + int max = 0; struct Comparator { bool operator()(const rec_element p_a, const rec_element p_b) const { return p_a.usage < p_b.usage; } @@ -57,22 +57,22 @@ struct rec_element { }; struct joypad { - IOHIDDeviceRef device_ref; + IOHIDDeviceRef device_ref = nullptr; Vector<rec_element> axis_elements; Vector<rec_element> button_elements; Vector<rec_element> hat_elements; - int id; + int id = 0; - io_service_t ffservice; /* Interface for force feedback, 0 = no ff */ + io_service_t ffservice = 0; /* Interface for force feedback, 0 = no ff */ FFCONSTANTFORCE ff_constant_force; FFDeviceObjectReference ff_device; FFEffectObjectReference ff_object; - uint64_t ff_timestamp; - LONG *ff_directions; + uint64_t ff_timestamp = 0; + LONG *ff_directions = nullptr; FFEFFECT ff_effect; - DWORD *ff_axes; + DWORD *ff_axes = nullptr; void add_hid_elements(CFArrayRef p_array); void add_hid_element(IOHIDElementRef p_element); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 399a29cbe0..ed03e953a5 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -286,7 +286,7 @@ Error OS_OSX::shell_open(String p_uri) { String OS_OSX::get_locale() const { NSString *locale_code = [[NSLocale preferredLanguages] objectAtIndex:0]; - return [locale_code UTF8String]; + return String([locale_code UTF8String]).replace("-", "_"); } String OS_OSX::get_executable_path() const { diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp index 22af8ba985..f8b420b1c8 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -49,14 +49,6 @@ const char *OS_Server::get_video_driver_name(int p_driver) const { return "Dummy"; } -int OS_Server::get_audio_driver_count() const { - return 1; -} - -const char *OS_Server::get_audio_driver_name(int p_driver) const { - return "Dummy"; -} - int OS_Server::get_current_video_driver() const { return video_driver_index; } diff --git a/platform/server/os_server.h b/platform/server/os_server.h index a4ae6a0bf6..95b6b5143b 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -47,22 +47,22 @@ #undef CursorShape class OS_Server : public OS_Unix { - RenderingServer *rendering_server; + RenderingServer *rendering_server = nullptr; VideoMode current_videomode; List<String> args; - MainLoop *main_loop; + MainLoop *main_loop = nullptr; - bool grab; + bool grab = false; virtual void delete_main_loop(); - bool force_quit; + bool force_quit = false; - InputDefault *input; + InputDefault *input = nullptr; CrashHandler crash_handler; - int video_driver_index; + int video_driver_index = 0; Ref<ResourceFormatDummyTexture> resource_loader_dummy; @@ -70,8 +70,6 @@ protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; virtual int get_current_video_driver() const; - virtual int get_audio_driver_count() const; - virtual const char *get_audio_driver_name(int p_driver) const; virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/uwp/context_egl_uwp.cpp b/platform/uwp/context_egl_uwp.cpp index 2da6c5897a..a6607ed42c 100644 --- a/platform/uwp/context_egl_uwp.cpp +++ b/platform/uwp/context_egl_uwp.cpp @@ -204,7 +204,8 @@ ContextEGL_UWP::ContextEGL_UWP(CoreWindow ^ p_window, Driver p_driver) : mEglContext(EGL_NO_CONTEXT), mEglSurface(EGL_NO_SURFACE), driver(p_driver), - window(p_window) {} + window(p_window), + vsync(false) {} ContextEGL_UWP::~ContextEGL_UWP() { cleanup(); diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index 30568241a9..00b57c48f3 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -108,7 +108,7 @@ class AppxPackager { struct BlockHash { String base64_hash; - size_t compressed_size; + size_t compressed_size = 0; }; struct FileMeta { @@ -120,12 +120,10 @@ class AppxPackager { Vector<BlockHash> hashes; uLong file_crc32 = 0; ZPOS64_T zip_offset = 0; - - FileMeta() {} }; String progress_task; - FileAccess *package; + FileAccess *package = nullptr; Set<String> mime_types; diff --git a/platform/uwp/joypad_uwp.h b/platform/uwp/joypad_uwp.h index 13f246a438..2df87d6fd5 100644 --- a/platform/uwp/joypad_uwp.h +++ b/platform/uwp/joypad_uwp.h @@ -58,21 +58,12 @@ private: struct ControllerDevice { Windows::Gaming::Input::IGameController ^ controller_reference; - int id; - bool connected; - ControllerType type; - float ff_timestamp; - float ff_end_timestamp; - bool vibrating; - - ControllerDevice() { - id = -1; - connected = false; - type = ControllerType::GAMEPAD_CONTROLLER; - ff_timestamp = 0.0f; - ff_end_timestamp = 0.0f; - vibrating = false; - } + int id = -1; + bool connected = false; + ControllerType type = ControllerType::GAMEPAD_CONTROLLER; + float ff_timestamp = 0; + float ff_end_timestamp = 0; + bool vibrating = false; }; ControllerDevice controllers[MAX_CONTROLLERS]; diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index c2d1acf8a0..fd25cefe2b 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -55,13 +55,13 @@ public: CHAR_EVENT_MESSAGE }; - bool alt, shift, control; - MessageType type; - bool pressed; - unsigned int keycode; - unsigned int physical_keycode; - unsigned int unicode; - bool echo; + bool alt = false, shift = false, control = false; + MessageType type = KEY_EVENT_MESSAGE; + bool pressed = false; + unsigned int keycode = 0; + unsigned int physical_keycode = 0; + unsigned int unicode = 0; + bool echo = false; CorePhysicalKeyStatus status; }; diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp index 1c32639a38..54251fc66c 100644 --- a/platform/windows/context_gl_windows.cpp +++ b/platform/windows/context_gl_windows.cpp @@ -211,6 +211,7 @@ ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) { hWnd = hwnd; use_vsync = false; vsync_via_compositor = false; + pixel_format = 0; } ContextGL_Windows::~ContextGL_Windows() { diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index 7abf451062..0f2f49c5ce 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -57,7 +57,7 @@ struct module_data { std::string image_name; std::string module_name; - void *base_address; + void *base_address = nullptr; DWORD load_size; }; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index ee13e3c774..859051ede9 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -95,7 +95,7 @@ def build_res_file(target, source, env): out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate() if len(out[1]): return 1 - except: + except Exception: return 1 return 0 diff --git a/platform/windows/joypad_windows.h b/platform/windows/joypad_windows.h index 223b44fcd6..08adc6b663 100644 --- a/platform/windows/joypad_windows.h +++ b/platform/windows/joypad_windows.h @@ -92,21 +92,13 @@ private: }; struct xinput_gamepad { - int id; - bool attached; - bool vibrating; - DWORD last_packet; + int id = 0; + bool attached = false; + bool vibrating = false; + DWORD last_packet = 0; XINPUT_STATE state; - uint64_t ff_timestamp; - uint64_t ff_end_timestamp; - - xinput_gamepad() { - attached = false; - vibrating = false; - ff_timestamp = 0; - ff_end_timestamp = 0; - last_packet = 0; - } + uint64_t ff_timestamp = 0; + uint64_t ff_end_timestamp = 0; }; typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index ae6b54513d..451f3bf18c 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -183,7 +183,6 @@ void OS_Windows::initialize() { FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM); - //FileAccessBufferedFA<FileAccessWindows>::make_default(); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM); @@ -562,21 +561,21 @@ String OS_Windows::get_locale() const { LANGID langid = GetUserDefaultUILanguage(); String neutral; - int lang = langid & ((1 << 9) - 1); - int sublang = langid & ~((1 << 9) - 1); + int lang = PRIMARYLANGID(langid); + int sublang = SUBLANGID(langid); while (wl->locale) { if (wl->main_lang == lang && wl->sublang == SUBLANG_NEUTRAL) neutral = wl->locale; if (lang == wl->main_lang && sublang == wl->sublang) - return wl->locale; + return String(wl->locale).replace("-", "_"); wl++; } if (neutral != "") - return neutral; + return String(neutral).replace("-", "_"); return "en"; } @@ -802,6 +801,11 @@ void OS_Windows::set_current_tablet_driver(const String &p_driver) { } OS_Windows::OS_Windows(HINSTANCE _hInstance) { + ticks_per_second = 0; + ticks_start = 0; + main_loop = nullptr; + process_map = nullptr; + //Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink. HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll"); if (wintab_lib) { diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index ef2a9a4911..3649746c40 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -397,14 +397,14 @@ Ref<Gradient> CPUParticles2D::get_color_ramp() const { return color_ramp; } -void CPUParticles2D::set_particle_flag(Flags p_flag, bool p_enable) { - ERR_FAIL_INDEX(p_flag, FLAG_MAX); - flags[p_flag] = p_enable; +void CPUParticles2D::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { + ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); + particle_flags[p_particle_flag] = p_enable; } -bool CPUParticles2D::get_particle_flag(Flags p_flag) const { - ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); - return flags[p_flag]; +bool CPUParticles2D::get_particle_flag(ParticleFlags p_particle_flag) const { + ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false); + return particle_flags[p_particle_flag]; } void CPUParticles2D::set_emission_shape(EmissionShape p_shape) { @@ -905,7 +905,7 @@ void CPUParticles2D::_particles_process(float p_delta) { p.color *= p.base_color; - if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { if (p.velocity.length() > 0.0) { p.transform.elements[1] = p.velocity.normalized(); p.transform.elements[0] = p.transform.elements[1].tangent(); @@ -1130,7 +1130,7 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { set_color_ramp(gt->get_gradient()); } - set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY)); + set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); set_emission_shape(EmissionShape(material->get_emission_shape())); set_emission_sphere_radius(material->get_emission_sphere_radius()); @@ -1246,8 +1246,8 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles2D::set_color_ramp); ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles2D::get_color_ramp); - ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles2D::set_particle_flag); - ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles2D::get_particle_flag); + ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &CPUParticles2D::set_particle_flag); + ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &CPUParticles2D::get_particle_flag); ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles2D::set_emission_shape); ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles2D::get_emission_shape); @@ -1279,8 +1279,8 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors"); - ADD_GROUP("Flags", "flag_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY); + ADD_GROUP("Particle Flags", "particle_flag_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); ADD_GROUP("Direction", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "direction"), "set_direction", "get_direction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); @@ -1351,10 +1351,10 @@ void CPUParticles2D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET); BIND_ENUM_CONSTANT(PARAM_MAX); - BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); - BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); // Unused, but exposed for consistency with 3D. - BIND_ENUM_CONSTANT(FLAG_DISABLE_Z); // Unused, but exposed for consistency with 3D. - BIND_ENUM_CONSTANT(FLAG_MAX); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y); // Unused, but exposed for consistency with 3D. + BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z); // Unused, but exposed for consistency with 3D. + BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); @@ -1415,8 +1415,8 @@ CPUParticles2D::CPUParticles2D() { set_param_randomness(Parameter(i), 0); } - for (int i = 0; i < FLAG_MAX; i++) { - flags[i] = false; + for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { + particle_flags[i] = false; } set_color(Color(1, 1, 1, 1)); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 0f2a3e4920..857f19b20f 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -61,11 +61,11 @@ public: PARAM_MAX }; - enum Flags { - FLAG_ALIGN_Y_TO_VELOCITY, - FLAG_ROTATE_Y, // Unused, but exposed for consistency with 3D. - FLAG_DISABLE_Z, // Unused, but exposed for consistency with 3D. - FLAG_MAX + enum ParticleFlags { + PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, + PARTICLE_FLAG_ROTATE_Y, // Unused, but exposed for consistency with 3D. + PARTICLE_FLAG_DISABLE_Z, // Unused, but exposed for consistency with 3D. + PARTICLE_FLAG_MAX }; enum EmissionShape { @@ -159,7 +159,7 @@ private: Color color; Ref<Gradient> color_ramp; - bool flags[FLAG_MAX]; + bool particle_flags[PARTICLE_FLAG_MAX]; EmissionShape emission_shape; float emission_sphere_radius; @@ -253,8 +253,8 @@ public: void set_color_ramp(const Ref<Gradient> &p_ramp); Ref<Gradient> get_color_ramp() const; - void set_particle_flag(Flags p_flag, bool p_enable); - bool get_particle_flag(Flags p_flag) const; + void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable); + bool get_particle_flag(ParticleFlags p_particle_flag) const; void set_emission_shape(EmissionShape p_shape); void set_emission_sphere_radius(float p_radius); @@ -287,7 +287,7 @@ public: VARIANT_ENUM_CAST(CPUParticles2D::DrawOrder) VARIANT_ENUM_CAST(CPUParticles2D::Parameter) -VARIANT_ENUM_CAST(CPUParticles2D::Flags) +VARIANT_ENUM_CAST(CPUParticles2D::ParticleFlags) VARIANT_ENUM_CAST(CPUParticles2D::EmissionShape) #endif // CPU_PARTICLES_2D_H diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index a4a930455b..46096d7460 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -127,9 +127,9 @@ void GPUParticles2D::_update_particle_emission_transform() { void GPUParticles2D::set_process_material(const Ref<Material> &p_material) { process_material = p_material; Ref<ParticlesMaterial> pm = p_material; - if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) { + if (pm.is_valid() && !pm->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) { // Likely a new (3D) material, modify it to match 2D space - pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true); + pm->set_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z, true); pm->set_gravity(Vector3(0, 98, 0)); } RID material_rid; diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 6908fbeada..b5b39ccc8f 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -238,7 +238,7 @@ Ref<OccluderPolygon2D> LightOccluder2D::get_occluder_polygon() const { void LightOccluder2D::set_occluder_light_mask(int p_mask) { mask = p_mask; - RS::get_singleton()->canvas_light_occluder_set_light_mask(occluder, mask); + RS::get_singleton()->canvas_light_occluder_set_light_mask(occluder, p_mask); } int LightOccluder2D::get_occluder_light_mask() const { @@ -285,7 +285,7 @@ void LightOccluder2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D"), "set_occluder_polygon", "get_occluder_polygon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdf_collision"), "set_as_sdf_collision", "is_set_as_sdf_collision"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "occluder_light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask"); } LightOccluder2D::LightOccluder2D() { diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index f1522dbaeb..e0116d9bad 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -459,39 +459,6 @@ void LineBuilder::strip_begin(Vector2 up, Vector2 down, Color color, float uvx) _last_index[DOWN] = vi + 1; } -void LineBuilder::strip_new_quad(Vector2 up, Vector2 down, Color color, float uvx) { - int vi = vertices.size(); - - vertices.push_back(vertices[_last_index[UP]]); - vertices.push_back(vertices[_last_index[DOWN]]); - vertices.push_back(up); - vertices.push_back(down); - - if (_interpolate_color) { - colors.push_back(color); - colors.push_back(color); - colors.push_back(color); - colors.push_back(color); - } - - if (texture_mode != Line2D::LINE_TEXTURE_NONE) { - uvs.push_back(uvs[_last_index[UP]]); - uvs.push_back(uvs[_last_index[DOWN]]); - uvs.push_back(Vector2(uvx, UP)); - uvs.push_back(Vector2(uvx, DOWN)); - } - - indices.push_back(vi); - indices.push_back(vi + 3); - indices.push_back(vi + 1); - indices.push_back(vi); - indices.push_back(vi + 2); - indices.push_back(vi + 3); - - _last_index[UP] = vi + 2; - _last_index[DOWN] = vi + 3; -} - void LineBuilder::strip_add_quad(Vector2 up, Vector2 down, Color color, float uvx) { int vi = vertices.size(); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index d305f2805e..f40a993423 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -170,7 +170,7 @@ void PathFollow2D::_update_transform() { } Vector2 pos = c->interpolate_baked(offset, cubic); - if (rotate) { + if (rotates) { float ahead = offset + lookahead; if (loop && ahead >= path_length) { @@ -279,7 +279,7 @@ void PathFollow2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &PathFollow2D::set_unit_offset); ClassDB::bind_method(D_METHOD("get_unit_offset"), &PathFollow2D::get_unit_offset); - ClassDB::bind_method(D_METHOD("set_rotate", "enable"), &PathFollow2D::set_rotate); + ClassDB::bind_method(D_METHOD("set_rotates", "enable"), &PathFollow2D::set_rotates); ClassDB::bind_method(D_METHOD("is_rotating"), &PathFollow2D::is_rotating); ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enable"), &PathFollow2D::set_cubic_interpolation); @@ -295,7 +295,7 @@ void PathFollow2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotate"), "set_rotate", "is_rotating"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotates"), "set_rotates", "is_rotating"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead"); @@ -371,13 +371,13 @@ float PathFollow2D::get_lookahead() const { return lookahead; } -void PathFollow2D::set_rotate(bool p_rotate) { - rotate = p_rotate; +void PathFollow2D::set_rotates(bool p_rotates) { + rotates = p_rotates; _update_transform(); } bool PathFollow2D::is_rotating() const { - return rotate; + return rotates; } void PathFollow2D::set_loop(bool p_loop) { @@ -393,7 +393,7 @@ PathFollow2D::PathFollow2D() { h_offset = 0; v_offset = 0; path = nullptr; - rotate = true; + rotates = true; cubic = true; loop = true; lookahead = 4; diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index 7fea75cd7c..fcb8b40125 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -70,7 +70,7 @@ private: real_t lookahead; bool cubic; bool loop; - bool rotate; + bool rotates; void _update_transform(); @@ -99,7 +99,7 @@ public: void set_loop(bool p_loop); bool has_loop() const; - void set_rotate(bool p_rotate); + void set_rotates(bool p_rotates); bool is_rotating() const; void set_cubic_interpolation(bool p_enable); diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index b1ffe76662..b1adb0e88e 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -505,11 +505,11 @@ bool Area3D::is_overriding_audio_bus() const { return audio_bus_override; } -void Area3D::set_audio_bus(const StringName &p_audio_bus) { +void Area3D::set_audio_bus_name(const StringName &p_audio_bus) { audio_bus = p_audio_bus; } -StringName Area3D::get_audio_bus() const { +StringName Area3D::get_audio_bus_name() 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; @@ -625,8 +625,8 @@ void Area3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_audio_bus_override", "enable"), &Area3D::set_audio_bus_override); ClassDB::bind_method(D_METHOD("is_overriding_audio_bus"), &Area3D::is_overriding_audio_bus); - ClassDB::bind_method(D_METHOD("set_audio_bus", "name"), &Area3D::set_audio_bus); - ClassDB::bind_method(D_METHOD("get_audio_bus"), &Area3D::get_audio_bus); + ClassDB::bind_method(D_METHOD("set_audio_bus_name", "name"), &Area3D::set_audio_bus_name); + ClassDB::bind_method(D_METHOD("get_audio_bus_name"), &Area3D::get_audio_bus_name); ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area3D::set_use_reverb_bus); ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area3D::is_using_reverb_bus); @@ -665,7 +665,7 @@ void Area3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_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_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus", "get_audio_bus"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name"); ADD_GROUP("Reverb Bus", "reverb_bus_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus"); diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h index 7d1f030baf..51f6317517 100644 --- a/scene/3d/area_3d.h +++ b/scene/3d/area_3d.h @@ -190,8 +190,8 @@ public: 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; + void set_audio_bus_name(const StringName &p_audio_bus); + StringName get_audio_bus_name() const; void set_use_reverb_bus(bool p_enable); bool is_using_reverb_bus() const; diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index b093788d75..2907eb3c7e 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -327,9 +327,6 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const { return att; } -void _update_sound() { -} - void AudioStreamPlayer3D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { velocity_tracker->reset(get_global_transform().origin); @@ -487,7 +484,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { if (area) { if (area->is_overriding_audio_bus()) { //override audio bus - StringName bus_name = area->get_audio_bus(); + StringName bus_name = area->get_audio_bus_name(); output.bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name); } diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index c977e0d4aa..215d9e062c 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -39,7 +39,7 @@ AABB CPUParticles3D::get_aabb() const { return AABB(); } -Vector<Face3> CPUParticles3D::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> CPUParticles3D::get_faces(uint32_t p_usage_particle_flags) const { return Vector<Face3>(); } @@ -368,17 +368,17 @@ Ref<Gradient> CPUParticles3D::get_color_ramp() const { return color_ramp; } -void CPUParticles3D::set_particle_flag(Flags p_flag, bool p_enable) { - ERR_FAIL_INDEX(p_flag, FLAG_MAX); - flags[p_flag] = p_enable; - if (p_flag == FLAG_DISABLE_Z) { +void CPUParticles3D::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { + ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); + particle_flags[p_particle_flag] = p_enable; + if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) { _change_notify(); } } -bool CPUParticles3D::get_particle_flag(Flags p_flag) const { - ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); - return flags[p_flag]; +bool CPUParticles3D::get_particle_flag(ParticleFlags p_particle_flag) const { + ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false); + return particle_flags[p_particle_flag]; } void CPUParticles3D::set_emission_shape(EmissionShape p_shape) { @@ -459,7 +459,7 @@ void CPUParticles3D::_validate_property(PropertyInfo &property) const { property.usage = 0; } - if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { + if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { property.usage = 0; } } @@ -675,7 +675,7 @@ void CPUParticles3D::_particles_process(float p_delta) { p.hue_rot_rand = Math::randf(); p.anim_offset_rand = Math::randf(); - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { float angle1_rad = Math::atan2(direction.y, direction.x) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0); p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); @@ -725,7 +725,7 @@ void CPUParticles3D::_particles_process(float p_delta) { p.transform.origin = emission_points.get(random_idx); if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) { - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { Vector3 normal = emission_normals.get(random_idx); Vector2 normal_2d(normal.x, normal.y); Transform2D m2; @@ -762,7 +762,7 @@ void CPUParticles3D::_particles_process(float p_delta) { p.transform = emission_xform * p.transform; } - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { p.velocity.z = 0.0; p.transform.origin.z = 0.0; } @@ -783,7 +783,7 @@ void CPUParticles3D::_particles_process(float p_delta) { } float tex_orbit_velocity = 0.0; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]); } @@ -830,7 +830,7 @@ void CPUParticles3D::_particles_process(float p_delta) { Vector3 force = gravity; Vector3 position = p.transform.origin; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { position.z = 0.0; } //apply linear acceleration @@ -840,7 +840,7 @@ void CPUParticles3D::_particles_process(float p_delta) { Vector3 diff = position - org; force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3(); //apply tangential acceleration; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { Vector2 yx = Vector2(diff.y, diff.x); Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized(); force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); @@ -852,7 +852,7 @@ void CPUParticles3D::_particles_process(float p_delta) { //apply attractor forces p.velocity += force * local_delta; //orbit velocity - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]); if (orbit_amount != 0.0) { float ang = orbit_amount * local_delta * Math_PI * 2.0; @@ -923,8 +923,8 @@ void CPUParticles3D::_particles_process(float p_delta) { p.color *= p.base_color; - if (flags[FLAG_DISABLE_Z]) { - if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { if (p.velocity.length() > 0.0) { p.transform.basis.set_axis(1, p.velocity.normalized()); } else { @@ -941,7 +941,7 @@ void CPUParticles3D::_particles_process(float p_delta) { } else { //orient particle Y towards velocity - if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { if (p.velocity.length() > 0.0) { p.transform.basis.set_axis(1, p.velocity.normalized()); } else { @@ -959,7 +959,7 @@ void CPUParticles3D::_particles_process(float p_delta) { } //turn particle by rotation in Y - if (flags[FLAG_ROTATE_Y]) { + if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) { Basis rot_y(Vector3(0, 1, 0), p.custom[0]); p.transform.basis = p.transform.basis * rot_y; } @@ -973,7 +973,7 @@ void CPUParticles3D::_particles_process(float p_delta) { p.transform.basis.scale(Vector3(1, 1, 1) * base_scale); - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { p.velocity.z = 0.0; p.transform.origin.z = 0.0; } @@ -1199,9 +1199,9 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) { set_color_ramp(gt->get_gradient()); } - set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY)); - set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y)); - set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z)); + set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); + set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ROTATE_Y)); + set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z)); set_emission_shape(EmissionShape(material->get_emission_shape())); set_emission_sphere_radius(material->get_emission_sphere_radius()); @@ -1318,8 +1318,8 @@ void CPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles3D::set_color_ramp); ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles3D::get_color_ramp); - ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles3D::set_particle_flag); - ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles3D::get_particle_flag); + ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &CPUParticles3D::set_particle_flag); + ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &CPUParticles3D::get_particle_flag); ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles3D::set_emission_shape); ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles3D::get_emission_shape); @@ -1351,10 +1351,10 @@ void CPUParticles3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors"); - ADD_GROUP("Flags", "flag_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_particle_flag", "get_particle_flag", FLAG_ROTATE_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_particle_flag", "get_particle_flag", FLAG_DISABLE_Z); + ADD_GROUP("Particle Flags", "particle_flag_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z); ADD_GROUP("Direction", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); @@ -1426,10 +1426,10 @@ void CPUParticles3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET); BIND_ENUM_CONSTANT(PARAM_MAX); - BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); - BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); - BIND_ENUM_CONSTANT(FLAG_DISABLE_Z); - BIND_ENUM_CONSTANT(FLAG_MAX); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); @@ -1493,8 +1493,8 @@ CPUParticles3D::CPUParticles3D() { set_param_randomness(Parameter(i), 0); } - for (int i = 0; i < FLAG_MAX; i++) { - flags[i] = false; + for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { + particle_flags[i] = false; } can_update = false; diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index da4811b60e..8c1b8a684c 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -61,11 +61,11 @@ public: PARAM_MAX }; - enum Flags { - FLAG_ALIGN_Y_TO_VELOCITY, - FLAG_ROTATE_Y, - FLAG_DISABLE_Z, - FLAG_MAX + enum ParticleFlags { + PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, + PARTICLE_FLAG_ROTATE_Y, + PARTICLE_FLAG_DISABLE_Z, + PARTICLE_FLAG_MAX }; enum EmissionShape { @@ -160,7 +160,7 @@ private: Color color; Ref<Gradient> color_ramp; - bool flags[FLAG_MAX]; + bool particle_flags[PARTICLE_FLAG_MAX]; EmissionShape emission_shape; float emission_sphere_radius; @@ -256,8 +256,8 @@ public: void set_color_ramp(const Ref<Gradient> &p_ramp); Ref<Gradient> get_color_ramp() const; - void set_particle_flag(Flags p_flag, bool p_enable); - bool get_particle_flag(Flags p_flag) const; + void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable); + bool get_particle_flag(ParticleFlags p_particle_flag) const; void set_emission_shape(EmissionShape p_shape); void set_emission_sphere_radius(float p_radius); @@ -290,7 +290,7 @@ public: VARIANT_ENUM_CAST(CPUParticles3D::DrawOrder) VARIANT_ENUM_CAST(CPUParticles3D::Parameter) -VARIANT_ENUM_CAST(CPUParticles3D::Flags) +VARIANT_ENUM_CAST(CPUParticles3D::ParticleFlags) VARIANT_ENUM_CAST(CPUParticles3D::EmissionShape) #endif // CPU_PARTICLES_H diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 3d3467583d..2ae01c7ab8 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -182,6 +182,7 @@ void NavigationRegion3D::bake_navigation_mesh() { void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) { set_navigation_mesh(p_nav_mesh); bake_thread = nullptr; + emit_signal("bake_finished"); } String NavigationRegion3D::get_configuration_warning() const { diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index f25a64c567..ae6bbad8bf 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -94,10 +94,6 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { return; } - if (delta_offset == 0) { - return; - } - float bl = c->get_baked_length(); if (bl == 0.0) { return; @@ -156,7 +152,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { t.origin = pos; - if (p_update_xyz_rot) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree + if (p_update_xyz_rot && delta_offset != 0) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree. Vector3 t_prev = (pos - c->interpolate_baked(offset - delta_offset, cubic)).normalized(); Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized(); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 0ae1c0e3b6..4425af26f9 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -848,7 +848,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { skin_bindings.insert(skin_ref.operator->()); - skin->connect_compat("changed", skin_ref.operator->(), "_skin_changed"); + skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed")); _make_dirty(); //skin needs to be updated, so update skeleton diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h index 80acc3e937..6c1db6dd33 100644 --- a/scene/3d/skeleton_ik_3d.h +++ b/scene/3d/skeleton_ik_3d.h @@ -76,10 +76,6 @@ class FabrikInverseKinematic { ChainTip(ChainItem *p_chain_item, const EndEffector *p_end_effector) : chain_item(p_chain_item), end_effector(p_end_effector) {} - - ChainTip(const ChainTip &p_other_ct) : - chain_item(p_other_ct.chain_item), - end_effector(p_other_ct.end_effector) {} }; struct Chain { diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index b6999beff4..1d20a9cd3b 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -486,7 +486,7 @@ void Sprite3D::_draw() { RS::get_singleton()->immediate_normal(immediate, normal); RS::get_singleton()->immediate_tangent(immediate, tangent); RS::get_singleton()->immediate_color(immediate, color); - RS::get_singleton()->immediate_uv(immediate, uvs[i]); + RS::get_singleton()->immediate_uv(immediate, uvs[index[i]]); Vector3 vtx; vtx[x_axis] = vertices[index[i]][0]; @@ -815,7 +815,7 @@ void AnimatedSprite3D::_draw() { RS::get_singleton()->immediate_normal(immediate, normal); RS::get_singleton()->immediate_tangent(immediate, tangent); RS::get_singleton()->immediate_color(immediate, color); - RS::get_singleton()->immediate_uv(immediate, uvs[i]); + RS::get_singleton()->immediate_uv(immediate, uvs[indices[i]]); Vector3 vtx; vtx[x_axis] = vertices[indices[i]][0]; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index c0015aa338..763461880f 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -211,7 +211,7 @@ void XRController3D::_notification(int p_what) { emit_signal("button_pressed", i); button_states += mask; } else if (was_pressed && !is_pressed) { - emit_signal("button_release", i); + emit_signal("button_released", i); button_states -= mask; }; @@ -257,7 +257,7 @@ void XRController3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_mesh"), &XRController3D::get_mesh); ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button"))); - ADD_SIGNAL(MethodInfo("button_release", PropertyInfo(Variant::INT, "button"))); + ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::INT, "button"))); ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"))); }; @@ -282,7 +282,7 @@ String XRController3D::get_controller_name() const { return String("Not connected"); }; - return tracker->get_name(); + return tracker->get_tracker_name(); }; int XRController3D::get_joystick_id() const { @@ -480,7 +480,7 @@ String XRAnchor3D::get_anchor_name() const { return String("Not connected"); }; - return tracker->get_name(); + return tracker->get_tracker_name(); }; bool XRAnchor3D::get_is_active() const { diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 17ce05f130..36552c966d 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -565,7 +565,7 @@ void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<Anima { Ref<AnimationNode> node = states[p_name].node; if (node.is_valid()) { - node->disconnect_compat("tree_changed", this, "_tree_changed"); + node->disconnect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed)); } } @@ -574,7 +574,7 @@ void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<Anima emit_changed(); emit_signal("tree_changed"); - p_node->connect_compat("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED); + p_node->connect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed), varray(), CONNECT_REFERENCE_COUNTED); } Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name) const { diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index f8a67d154b..6ebd1011e9 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -615,7 +615,7 @@ void ColorPicker::_screen_pick_pressed() { screen->set_default_cursor_shape(CURSOR_POINTING_HAND); screen->connect("gui_input", callable_mp(this, &ColorPicker::_screen_input)); // It immediately toggles off in the first press otherwise. - screen->call_deferred("connect", "hide", Callable(btn_pick, "set_pressed"), varray(false)); + screen->call_deferred("connect", "hidden", Callable(btn_pick, "set_pressed"), varray(false)); } screen->raise(); #ifndef _MSC_VER diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index f9b7d828f4..b471bb9d4e 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -223,13 +223,6 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) { } data.icon_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - } else if (name.begins_with("custom_shaders/")) { - String dname = name.get_slicec('/', 1); - if (data.shader_override.has(dname)) { - data.shader_override[dname]->disconnect("changed", callable_mp(this, &Control::_override_changed)); - } - data.shader_override.erase(dname); - notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_styles/")) { String dname = name.get_slicec('/', 1); if (data.style_override.has(dname)) { @@ -264,9 +257,6 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) { if (name.begins_with("custom_icons/")) { String dname = name.get_slicec('/', 1); add_theme_icon_override(dname, p_value); - } else if (name.begins_with("custom_shaders/")) { - String dname = name.get_slicec('/', 1); - add_theme_shader_override(dname, p_value); } else if (name.begins_with("custom_styles/")) { String dname = name.get_slicec('/', 1); add_theme_style_override(dname, p_value); @@ -318,9 +308,6 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const { if (sname.begins_with("custom_icons/")) { String name = sname.get_slicec('/', 1); r_ret = data.icon_override.has(name) ? Variant(data.icon_override[name]) : Variant(); - } else if (sname.begins_with("custom_shaders/")) { - String name = sname.get_slicec('/', 1); - r_ret = data.shader_override.has(name) ? Variant(data.shader_override[name]) : Variant(); } else if (sname.begins_with("custom_styles/")) { String name = sname.get_slicec('/', 1); r_ret = data.style_override.has(name) ? Variant(data.style_override[name]) : Variant(); @@ -368,18 +355,6 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const { } { List<StringName> names; - theme->get_shader_list(get_class_name(), &names); - for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; - if (data.shader_override.has(E->get())) { - hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; - } - - p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_shaders/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "Shader,VisualShader", hint)); - } - } - { - List<StringName> names; theme->get_stylebox_list(get_class_name(), &names); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; @@ -481,10 +456,6 @@ bool Control::is_layout_rtl() const { } } -void Control::_resize(const Size2 &p_size) { - _size_changed(); -} - //moved theme configuration here, so controls can set up even if still not inside active scene void Control::add_child_notify(Node *p_child) { @@ -901,35 +872,6 @@ Ref<Texture2D> Control::get_icons(Control *p_theme_owner, Window *p_theme_owner_ return Theme::get_default()->get_icon(p_name, p_node_type); } -Ref<Shader> Control::get_theme_shader(const StringName &p_name, const StringName &p_node_type) const { - if (p_node_type == StringName() || p_node_type == get_class_name()) { - const Ref<Shader> *sdr = data.shader_override.getptr(p_name); - if (sdr) { - return *sdr; - } - } - - StringName type = p_node_type ? p_node_type : get_class_name(); - - return get_shaders(data.theme_owner, data.theme_owner_window, p_name, type); -} - -Ref<Shader> Control::get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { - Ref<Shader> shader; - - if (_find_theme_item(p_theme_owner, p_theme_owner_window, shader, &Theme::get_shader, &Theme::has_shader, p_name, p_node_type)) { - return shader; - } - - if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_shader(p_name, p_node_type)) { - return Theme::get_project_default()->get_shader(p_name, p_node_type); - } - } - - return Theme::get_default()->get_shader(p_name, p_node_type); -} - Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_node_type) const { if (p_node_type == StringName() || p_node_type == get_class_name()) { const Ref<StyleBox> *style = data.style_override.getptr(p_name); @@ -1078,11 +1020,6 @@ bool Control::has_theme_icon_override(const StringName &p_name) const { return tex != nullptr; } -bool Control::has_theme_shader_override(const StringName &p_name) const { - const Ref<Shader> *sdr = data.shader_override.getptr(p_name); - return sdr != nullptr; -} - bool Control::has_theme_stylebox_override(const StringName &p_name) const { const Ref<StyleBox> *style = data.style_override.getptr(p_name); return style != nullptr; @@ -1133,31 +1070,6 @@ bool Control::has_icons(Control *p_theme_owner, Window *p_theme_owner_window, co return Theme::get_default()->has_icon(p_name, p_node_type); } -bool Control::has_theme_shader(const StringName &p_name, const StringName &p_node_type) const { - if (p_node_type == StringName() || p_node_type == get_class_name()) { - if (has_theme_shader_override(p_name)) { - return true; - } - } - - StringName type = p_node_type ? p_node_type : get_class_name(); - - return has_shaders(data.theme_owner, data.theme_owner_window, p_name, type); -} - -bool Control::has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) { - if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_shader, p_name, p_node_type)) { - return true; - } - - if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_shader(p_name, p_node_type)) { - return true; - } - } - return Theme::get_default()->has_shader(p_name, p_node_type); -} - bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_node_type) const { if (p_node_type == StringName() || p_node_type == get_class_name()) { if (has_theme_stylebox_override(p_name)) { @@ -1891,23 +1803,6 @@ void Control::add_theme_icon_override(const StringName &p_name, const Ref<Textur notification(NOTIFICATION_THEME_CHANGED); } -void Control::add_theme_shader_override(const StringName &p_name, const Ref<Shader> &p_shader) { - if (data.shader_override.has(p_name)) { - data.shader_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed)); - } - - // clear if "null" is passed instead of a shader - if (p_shader.is_null()) { - data.shader_override.erase(p_name); - } else { - data.shader_override[p_name] = p_shader; - if (data.shader_override[p_name].is_valid()) { - data.shader_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED); - } - } - notification(NOTIFICATION_THEME_CHANGED); -} - void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) { if (data.style_override.has(p_name)) { data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed)); @@ -2905,7 +2800,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("get_theme"), &Control::get_theme); ClassDB::bind_method(D_METHOD("add_theme_icon_override", "name", "texture"), &Control::add_theme_icon_override); - ClassDB::bind_method(D_METHOD("add_theme_shader_override", "name", "shader"), &Control::add_theme_shader_override); ClassDB::bind_method(D_METHOD("add_theme_stylebox_override", "name", "stylebox"), &Control::add_theme_style_override); ClassDB::bind_method(D_METHOD("add_theme_font_override", "name", "font"), &Control::add_theme_font_override); ClassDB::bind_method(D_METHOD("add_theme_font_size_override", "name", "font_size"), &Control::add_theme_font_size_override); @@ -2920,7 +2814,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "node_type"), &Control::get_theme_constant, DEFVAL("")); ClassDB::bind_method(D_METHOD("has_theme_icon_override", "name"), &Control::has_theme_icon_override); - ClassDB::bind_method(D_METHOD("has_theme_shader_override", "name"), &Control::has_theme_shader_override); ClassDB::bind_method(D_METHOD("has_theme_stylebox_override", "name"), &Control::has_theme_stylebox_override); ClassDB::bind_method(D_METHOD("has_theme_font_override", "name"), &Control::has_theme_font_override); ClassDB::bind_method(D_METHOD("has_theme_font_size_override", "name"), &Control::has_theme_font_size_override); diff --git a/scene/gui/control.h b/scene/gui/control.h index e1f05dfe64..8496729f05 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -212,7 +212,6 @@ private: NodePath focus_prev; HashMap<StringName, Ref<Texture2D>> icon_override; - HashMap<StringName, Ref<Shader>> shader_override; HashMap<StringName, Ref<StyleBox>> style_override; HashMap<StringName, Ref<Font>> font_override; HashMap<StringName, int> font_size_override; @@ -238,7 +237,6 @@ private: void _update_minimum_size(); void _update_scroll(); - void _resize(const Size2 &p_size); void _compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]); void _compute_anchors(Rect2 p_rect, const float p_margins[4], float (&r_anchors)[4]); @@ -264,7 +262,6 @@ private: _FORCE_INLINE_ static bool _has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_node_type); static Ref<Texture2D> get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); - static Ref<Shader> get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); static Ref<StyleBox> get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); static Ref<Font> get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); static int get_font_sizes(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); @@ -272,7 +269,6 @@ private: static int get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); static bool has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); - static bool has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); static bool has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); static bool has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); static bool has_font_sizes(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName()); @@ -456,7 +452,6 @@ public: /* SKINNING */ void add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon); - void add_theme_shader_override(const StringName &p_name, const Ref<Shader> &p_shader); void add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style); void add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font); void add_theme_font_size_override(const StringName &p_name, int p_font_size); @@ -464,7 +459,6 @@ public: void add_theme_constant_override(const StringName &p_name, int p_constant); Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_node_type = StringName()) const; - Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_node_type = StringName()) const; Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const; Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const; int get_theme_font_size(const StringName &p_name, const StringName &p_node_type = StringName()) const; @@ -472,7 +466,6 @@ public: int get_theme_constant(const StringName &p_name, const StringName &p_node_type = StringName()) const; bool has_theme_icon_override(const StringName &p_name) const; - bool has_theme_shader_override(const StringName &p_name) const; bool has_theme_stylebox_override(const StringName &p_name) const; bool has_theme_font_override(const StringName &p_name) const; bool has_theme_font_size_override(const StringName &p_name) const; @@ -480,7 +473,6 @@ public: bool has_theme_constant_override(const StringName &p_name) const; bool has_theme_icon(const StringName &p_name, const StringName &p_node_type = StringName()) const; - bool has_theme_shader(const StringName &p_name, const StringName &p_node_type = StringName()) const; bool has_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const; bool has_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const; bool has_theme_font_size(const StringName &p_name, const StringName &p_node_type = StringName()) const; diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 53fe5712c7..5be7804ac1 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -78,6 +78,7 @@ void ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) { item.icon_region = Rect2i(); item.icon_modulate = Color(1, 1, 1, 1); //item.text=p_item; + item.text_buf.instance(); item.selectable = p_selectable; item.selected = false; item.disabled = false; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index e83c062e8a..566d77e3fd 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -64,16 +64,17 @@ bool Label::is_uppercase() const { } int Label::get_line_height(int p_line) const { + Ref<Font> font = get_theme_font("font"); if (p_line >= 0 && p_line < lines_rid.size()) { - return TS->shaped_text_get_size(lines_rid[p_line]).y; + return TS->shaped_text_get_size(lines_rid[p_line]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM); } else if (lines_rid.size() > 0) { int h = 0; for (int i = 0; i < lines_rid.size(); i++) { - h = MAX(h, TS->shaped_text_get_size(lines_rid[i]).y); + h = MAX(h, TS->shaped_text_get_size(lines_rid[i]).y) + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM); } return h; } else { - return get_theme_font("font")->get_height(get_theme_font_size("font_size")); + return font->get_height(get_theme_font_size("font_size")); } } @@ -138,6 +139,7 @@ void Label::_shape() { void Label::_update_visible() { int line_spacing = get_theme_constant("line_spacing", "Label"); Ref<StyleBox> style = get_theme_stylebox("normal", "Label"); + Ref<Font> font = get_theme_font("font"); int lines_visible = lines_rid.size(); if (max_lines_visible >= 0 && lines_visible > max_lines_visible) { @@ -147,7 +149,7 @@ void Label::_update_visible() { minsize.height = 0; int last_line = MIN(lines_rid.size(), lines_visible + lines_skipped); for (int64_t i = lines_skipped; i < last_line; i++) { - minsize.height += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing; + minsize.height += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; if (minsize.height > (get_size().height - style->get_minimum_size().height + line_spacing)) { break; } @@ -197,7 +199,7 @@ void Label::_notification(int p_what) { // Get number of lines to fit to the height. for (int64_t i = lines_skipped; i < lines_rid.size(); i++) { - total_h += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing; + total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) { break; } @@ -213,7 +215,7 @@ void Label::_notification(int p_what) { // Get real total height. total_h = 0; for (int64_t i = lines_skipped; i < last_line; i++) { - total_h += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing; + total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; } int vbegin = 0, vsep = 0; @@ -249,8 +251,10 @@ void Label::_notification(int p_what) { if (percent_visible < 1) { int total_glyphs = 0; for (int i = lines_skipped; i < last_line; i++) { - const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(lines_rid[i]); - for (int j = 0; j < glyphs.size(); j++) { + const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]); + const TextServer::Glyph *glyphs = visual.ptr(); + int gl_size = visual.size(); + for (int j = 0; j < gl_size; j++) { if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { total_glyphs++; } @@ -263,7 +267,7 @@ void Label::_notification(int p_what) { ofs.y = style->get_offset().y + vbegin; for (int i = lines_skipped; i < last_line; i++) { ofs.x = 0; - ofs.y += TS->shaped_text_get_ascent(lines_rid[i]); + ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + font->get_spacing(Font::SPACING_TOP); switch (align) { case ALIGN_FILL: case ALIGN_LEFT: { @@ -285,11 +289,13 @@ void Label::_notification(int p_what) { } break; } - const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(lines_rid[i]); + const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]); + const TextServer::Glyph *glyphs = visual.ptr(); + int gl_size = visual.size(); float x = ofs.x; int outlines_drawn = glyhps_drawn; - for (int j = 0; j < glyphs.size(); j++) { + for (int j = 0; j < gl_size; j++) { for (int k = 0; k < glyphs[j].repeat; k++) { if (glyphs[j].font_rid != RID()) { if (font_color_shadow.a > 0) { @@ -318,7 +324,7 @@ void Label::_notification(int p_what) { } ofs.x = x; - for (int j = 0; j < glyphs.size(); j++) { + for (int j = 0; j < gl_size; j++) { for (int k = 0; k < glyphs[j].repeat; k++) { if (glyphs[j].font_rid != RID()) { TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off), glyphs[j].index, font_color); @@ -337,7 +343,7 @@ void Label::_notification(int p_what) { } } - ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing; + ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing + font->get_spacing(Font::SPACING_BOTTOM); } } @@ -381,12 +387,13 @@ int Label::get_line_count() const { } int Label::get_visible_line_count() const { + Ref<Font> font = get_theme_font("font"); Ref<StyleBox> style = get_theme_stylebox("normal"); int line_spacing = get_theme_constant("line_spacing"); int lines_visible = 0; float total_h = 0; for (int64_t i = lines_skipped; i < lines_rid.size(); i++) { - total_h += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing; + total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) { break; } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 2eaa814419..9f8b944f4c 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -228,6 +228,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } break; + case (KEY_Y): // PASTE (Yank for unix users). case (KEY_V): { // PASTE. if (editable) { @@ -258,13 +259,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } break; - case (KEY_Y): { // PASTE (Yank for unix users). - - if (editable) { - paste_text(); - } - - } break; case (KEY_K): { // Delete from cursor_pos to end. if (editable) { @@ -732,6 +726,7 @@ void LineEdit::_notification(int p_what) { style = get_theme_stylebox("read_only"); draw_caret = false; } + Ref<Font> font = get_theme_font("font"); style->draw(ci, Rect2(Point2(), size)); @@ -742,7 +737,7 @@ void LineEdit::_notification(int p_what) { int x_ofs = 0; bool using_placeholder = text.empty() && ime_text.empty(); float text_width = TS->shaped_text_get_size(text_rid).x; - float text_height = TS->shaped_text_get_size(text_rid).y; + float text_height = TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM); switch (align) { case ALIGN_FILL: @@ -833,14 +828,16 @@ void LineEdit::_notification(int p_what) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_color); } } - const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(text_rid); + const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(text_rid); + const TextServer::Glyph *glyphs = visual.ptr(); + int gl_size = visual.size(); // Draw text. ofs.y += TS->shaped_text_get_ascent(text_rid); - for (int i = 0; i < glyphs.size(); i++) { + for (int i = 0; i < gl_size; i++) { bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end; for (int j = 0; j < glyphs[i].repeat; j++) { - if (ceil(ofs.x) >= x_ofs && floor(ofs.x + glyphs[i].advance) <= ofs_max) { + if (ceil(ofs.x) >= x_ofs && (ofs.x + glyphs[i].advance) <= ofs_max) { if (glyphs[i].font_rid != RID()) { TS->font_draw_glyph(glyphs[i].font_rid, ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_color_selected : font_color); } else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { @@ -1570,7 +1567,7 @@ Size2 LineEdit::get_minimum_size() const { min_size.width = MAX(min_size.width, full_width + space_size); } - min_size.height = MAX(TS->shaped_text_get_size(text_rid).y, font->get_height(font_size)); + min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM), font->get_height(font_size)); // Take icons into account. bool using_placeholder = text.empty() && ime_text.empty(); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 6dbf005f73..07f03ad40e 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -232,12 +232,13 @@ void PopupMenu::_submenu_timeout() { } void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { - if (p_event->is_action("ui_down") && p_event->is_pressed() && mouse_over != items.size() - 1) { + if (p_event->is_action("ui_down") && p_event->is_pressed()) { int search_from = mouse_over + 1; if (search_from >= items.size()) { search_from = 0; } + bool match_found = false; for (int i = search_from; i < items.size(); i++) { if (!items[i].separator && !items[i].disabled) { mouse_over = i; @@ -245,15 +246,31 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { _scroll_to_item(i); control->update(); set_input_as_handled(); + match_found = true; break; } } - } else if (p_event->is_action("ui_up") && p_event->is_pressed() && mouse_over != 0) { + + if (!match_found) { + // If the last item is not selectable, try re-searching from the start. + for (int i = 0; i < search_from; i++) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal("id_focused", i); + _scroll_to_item(i); + control->update(); + set_input_as_handled(); + break; + } + } + } + } else if (p_event->is_action("ui_up") && p_event->is_pressed()) { int search_from = mouse_over - 1; if (search_from < 0) { search_from = items.size() - 1; } + bool match_found = false; for (int i = search_from; i >= 0; i--) { if (!items[i].separator && !items[i].disabled) { mouse_over = i; @@ -261,9 +278,24 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { _scroll_to_item(i); control->update(); set_input_as_handled(); + match_found = true; break; } } + + if (!match_found) { + // If the first item is not selectable, try re-searching from the end. + for (int i = items.size() - 1; i >= search_from; i--) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal("id_focused", i); + _scroll_to_item(i); + control->update(); + set_input_as_handled(); + break; + } + } + } } else if (p_event->is_action("ui_left") && p_event->is_pressed()) { Node *n = get_parent(); if (n && Object::cast_to<PopupMenu>(n)) { @@ -446,6 +478,7 @@ void PopupMenu::_draw_items() { Color font_color_disabled = get_theme_color("font_color_disabled"); Color font_color_accel = get_theme_color("font_color_accel"); Color font_color_hover = get_theme_color("font_color_hover"); + Color font_color_separator = get_theme_color("font_color_separator"); float scroll_width = scroll_container->get_v_scrollbar()->is_visible_in_tree() ? scroll_container->get_v_scrollbar()->get_size().width : 0; float display_width = control->get_size().width - scroll_width; @@ -548,7 +581,7 @@ void PopupMenu::_draw_items() { if (items[i].separator) { if (text != String()) { int center = (display_width - items[i].text_buf->get_size().width) / 2; - items[i].text_buf->draw(ci, Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), font_color_disabled); + items[i].text_buf->draw(ci, Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), font_color_separator); } } else { item_ofs.x += icon_ofs + check_ofs; diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp index 76ca8abcc7..5b201f45d3 100644 --- a/scene/gui/rich_text_effect.cpp +++ b/scene/gui/rich_text_effect.cpp @@ -64,11 +64,8 @@ RichTextEffect::RichTextEffect() { } void CharFXTransform::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_relative_index"), &CharFXTransform::get_relative_index); - ClassDB::bind_method(D_METHOD("set_relative_index", "index"), &CharFXTransform::set_relative_index); - - ClassDB::bind_method(D_METHOD("get_absolute_index"), &CharFXTransform::get_absolute_index); - ClassDB::bind_method(D_METHOD("set_absolute_index", "index"), &CharFXTransform::set_absolute_index); + ClassDB::bind_method(D_METHOD("get_range"), &CharFXTransform::get_range); + ClassDB::bind_method(D_METHOD("set_range", "range"), &CharFXTransform::set_range); ClassDB::bind_method(D_METHOD("get_elapsed_time"), &CharFXTransform::get_elapsed_time); ClassDB::bind_method(D_METHOD("set_elapsed_time", "time"), &CharFXTransform::set_elapsed_time); @@ -76,6 +73,9 @@ void CharFXTransform::_bind_methods() { ClassDB::bind_method(D_METHOD("is_visible"), &CharFXTransform::is_visible); ClassDB::bind_method(D_METHOD("set_visibility", "visibility"), &CharFXTransform::set_visibility); + ClassDB::bind_method(D_METHOD("is_outline"), &CharFXTransform::is_outline); + ClassDB::bind_method(D_METHOD("set_outline", "outline"), &CharFXTransform::set_outline); + ClassDB::bind_method(D_METHOD("get_offset"), &CharFXTransform::get_offset); ClassDB::bind_method(D_METHOD("set_offset", "offset"), &CharFXTransform::set_offset); @@ -85,27 +85,24 @@ void CharFXTransform::_bind_methods() { ClassDB::bind_method(D_METHOD("get_environment"), &CharFXTransform::get_environment); ClassDB::bind_method(D_METHOD("set_environment", "environment"), &CharFXTransform::set_environment); - ClassDB::bind_method(D_METHOD("get_character"), &CharFXTransform::get_character); - ClassDB::bind_method(D_METHOD("set_character", "character"), &CharFXTransform::set_character); + ClassDB::bind_method(D_METHOD("get_glyph_index"), &CharFXTransform::get_glyph_index); + ClassDB::bind_method(D_METHOD("set_glyph_index", "glyph_index"), &CharFXTransform::set_glyph_index); + + ClassDB::bind_method(D_METHOD("get_font"), &CharFXTransform::get_font); + ClassDB::bind_method(D_METHOD("set_font", "font"), &CharFXTransform::set_font); - ADD_PROPERTY(PropertyInfo(Variant::INT, "relative_index"), "set_relative_index", "get_relative_index"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "absolute_index"), "set_absolute_index", "get_absolute_index"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "range"), "set_range", "get_range"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time"), "set_elapsed_time", "get_elapsed_time"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visibility", "is_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "outline"), "set_outline", "is_outline"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "env"), "set_environment", "get_environment"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "character"), "set_character", "get_character"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_index"), "set_glyph_index", "get_glyph_index"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "font"), "set_font", "get_font"); } CharFXTransform::CharFXTransform() { - relative_index = 0; - absolute_index = 0; - visibility = true; - offset = Point2(); - color = Color(); - character = 0; - elapsed_time = 0.0f; } CharFXTransform::~CharFXTransform() { diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h index e6b9f09e4d..1aa62c1c83 100644 --- a/scene/gui/rich_text_effect.h +++ b/scene/gui/rich_text_effect.h @@ -54,32 +54,37 @@ protected: static void _bind_methods(); public: - uint64_t relative_index; - uint64_t absolute_index; - bool visibility; + Vector2i range; + bool visibility = true; + bool outline = false; Point2 offset; Color color; - char32_t character; - float elapsed_time; + float elapsed_time = 0.0f; Dictionary environment; + uint32_t glpyh_index = 0; + RID font; CharFXTransform(); ~CharFXTransform(); - uint64_t get_relative_index() { return relative_index; } - void set_relative_index(uint64_t p_index) { relative_index = p_index; } - uint64_t get_absolute_index() { return absolute_index; } - void set_absolute_index(uint64_t p_index) { absolute_index = p_index; } + Vector2i get_range() { return range; } + void set_range(const Vector2i &p_range) { range = p_range; } float get_elapsed_time() { return elapsed_time; } void set_elapsed_time(float p_elapsed_time) { elapsed_time = p_elapsed_time; } bool is_visible() { return visibility; } - void set_visibility(bool p_vis) { visibility = p_vis; } + void set_visibility(bool p_visibility) { visibility = p_visibility; } + bool is_outline() { return outline; } + void set_outline(bool p_outline) { outline = p_outline; } Point2 get_offset() { return offset; } void set_offset(Point2 p_offset) { offset = p_offset; } Color get_color() { return color; } void set_color(Color p_color) { color = p_color; } - int get_character() { return (int)character; } - void set_character(int p_char) { character = (char32_t)p_char; } + + uint32_t get_glyph_index() const { return glpyh_index; }; + void set_glyph_index(uint32_t p_glpyh_index) { glpyh_index = p_glpyh_index; }; + RID get_font() const { return font; }; + void set_font(RID p_font) { font = p_font; }; + Dictionary get_environment() { return environment; } void set_environment(Dictionary p_environment) { environment = p_environment; } }; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 08214b958e..244d90ca6b 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -140,741 +140,1088 @@ Rect2 RichTextLabel::_get_text_rect() { return Rect2(style->get_offset(), get_size() - style->get_minimum_size()); } -int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) { - ERR_FAIL_INDEX_V((int)p_mode, 3, 0); - - RID ci; - if (r_outside) { - *r_outside = false; +RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item_from, RichTextLabel::Item *p_item_to, int p_position) { + int offset = 0; + for (Item *it = p_item_from; it && it != p_item_to; it = _get_next_item(it)) { + switch (it->type) { + case ITEM_TEXT: { + ItemText *t = (ItemText *)it; + offset += t->text.length(); + if (offset > p_position) { + return it; + } + } break; + case ITEM_NEWLINE: + case ITEM_IMAGE: + case ITEM_TABLE: { + offset += 1; + } break; + default: + break; + } } - if (p_mode == PROCESS_DRAW) { - ci = get_canvas_item(); + return p_item_from; +} - if (r_click_item) { - *r_click_item = nullptr; - } +String RichTextLabel::_roman(int p_num, bool p_capitalize) const { + if (p_num > 3999) { + return "ERR"; + }; + String s; + if (p_capitalize) { + String M[] = { "", "M", "MM", "MMM" }; + String C[] = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" }; + String X[] = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" }; + String I[] = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" }; + s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10]; + } else { + String M[] = { "", "m", "mm", "mmm" }; + String C[] = { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" }; + String X[] = { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" }; + String I[] = { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" }; + s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10]; } - Line &l = p_frame->lines.write[p_line]; - Item *it = l.from; + return s; +} - int line_ofs = 0; - int margin = _find_margin(it, p_base_font); - Align align = _find_align(it); - int line = 0; - int spaces = 0; +String RichTextLabel::_letters(int p_num, bool p_capitalize) const { + int64_t n = p_num; - int height = get_size().y; + int chars = 0; + do { + n /= 24; + chars++; + } while (n); - if (p_mode != PROCESS_CACHE) { - ERR_FAIL_INDEX_V(line, l.offset_caches.size(), 0); - line_ofs = l.offset_caches[line]; - } + String s; + s.resize(chars + 1); + char32_t *c = s.ptrw(); + c[chars] = 0; + n = p_num; + do { + int mod = ABS(n % 24); + char a = (p_capitalize ? 'A' : 'a'); + c[--chars] = a + mod - 1; - if (p_mode == PROCESS_CACHE) { - l.offset_caches.clear(); - l.height_caches.clear(); - l.ascent_caches.clear(); - l.descent_caches.clear(); - l.char_count = 0; - l.minimum_width = 0; - l.maximum_width = 0; - } + n /= 24; + } while (n); - int wofs = margin; - int spaces_size = 0; - int align_ofs = 0; + return s; +} - if (p_mode != PROCESS_CACHE && align != ALIGN_FILL) { - wofs += line_ofs; - } +void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width) { + ERR_FAIL_COND(p_frame == nullptr); + ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size()); + + Line &l = p_frame->lines.write[p_line]; - int begin = margin; + l.offset.x = _find_margin(l.from, p_base_font, p_base_font_size); + l.text_buf->set_width(p_width - l.offset.x); - Ref<Font> cfont = _find_font(it); - if (cfont.is_null()) { - cfont = p_base_font; + if (tab_size > 0) { // Align inline tabs. + Vector<float> tabs; + tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width); + l.text_buf->tab_align(tabs); } - //line height should be the font height for the first time, this ensures that an empty line will never have zero height and successive newlines are displayed - int line_height = cfont->get_height(); - int line_ascent = cfont->get_ascent(); - int line_descent = cfont->get_descent(); + Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr; + for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) { + switch (it->type) { + case ITEM_TABLE: { + ItemTable *table = static_cast<ItemTable *>(it); + int hseparation = get_theme_constant("table_hseparation"); + int vseparation = get_theme_constant("table_vseparation"); + int col_count = table->columns.size(); - int backtrack = 0; // for dynamic hidden content. + for (int i = 0; i < col_count; i++) { + table->columns.write[i].width = 0; + } - int nonblank_line_count = 0; //number of nonblank lines as counted during PROCESS_DRAW + int idx = 0; + for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { + ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. + ItemFrame *frame = static_cast<ItemFrame *>(E->get()); + for (int i = 0; i < frame->lines.size(); i++) { + _resize_line(frame, i, p_base_font, p_base_font_size, 1); + } + idx++; + } - Variant meta; + // Compute minimum width for each cell. + const int available_width = p_width - hseparation * (col_count - 1); -#define RETURN return nonblank_line_count - -#define NEW_LINE \ - { \ - if (p_mode != PROCESS_CACHE) { \ - line++; \ - backtrack = 0; \ - if (!line_is_blank) { \ - nonblank_line_count++; \ - } \ - line_is_blank = true; \ - if (line < l.offset_caches.size()) \ - line_ofs = l.offset_caches[line]; \ - wofs = margin; \ - if (align != ALIGN_FILL) \ - wofs += line_ofs; \ - } else { \ - int used = wofs - margin; \ - switch (align) { \ - case ALIGN_LEFT: \ - l.offset_caches.push_back(0); \ - break; \ - case ALIGN_CENTER: \ - l.offset_caches.push_back(((p_width - margin) - used) / 2); \ - break; \ - case ALIGN_RIGHT: \ - l.offset_caches.push_back(((p_width - margin) - used)); \ - break; \ - case ALIGN_FILL: \ - l.offset_caches.push_back(line_wrapped ? ((p_width - margin) - used) : 0); \ - break; \ - } \ - l.height_caches.push_back(line_height); \ - l.ascent_caches.push_back(line_ascent); \ - l.descent_caches.push_back(line_descent); \ - l.space_caches.push_back(spaces); \ - } \ - line_wrapped = false; \ - y += line_height + get_theme_constant(SceneStringNames::get_singleton()->line_separation); \ - line_height = 0; \ - line_ascent = 0; \ - line_descent = 0; \ - spaces = 0; \ - spaces_size = 0; \ - wofs = begin; \ - align_ofs = 0; \ - if (p_mode != PROCESS_CACHE) { \ - lh = line < l.height_caches.size() ? l.height_caches[line] : 1; \ - line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; \ - line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1; \ - if (align != ALIGN_FILL) { \ - if (line < l.offset_caches.size()) { \ - wofs = l.offset_caches[line]; \ - } \ - } \ - } \ - if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && p_click_pos.x < p_ofs.x + wofs) { \ - if (r_outside) \ - *r_outside = true; \ - *r_click_item = it; \ - *r_click_char = rchar; \ - RETURN; \ - } \ - } - -#define ENSURE_WIDTH(m_width) \ - if (p_mode == PROCESS_CACHE) { \ - l.maximum_width = MAX(l.maximum_width, MIN(p_width, wofs + m_width)); \ - l.minimum_width = MAX(l.minimum_width, m_width); \ - } \ - if (wofs - backtrack + m_width > p_width) { \ - line_wrapped = true; \ - if (p_mode == PROCESS_CACHE) { \ - if (spaces > 0) \ - spaces -= 1; \ - } \ - const bool x_in_range = (p_click_pos.x > p_ofs.x + wofs) && (!p_frame->cell || p_click_pos.x < p_ofs.x + p_width); \ - if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && x_in_range) { \ - if (r_outside) \ - *r_outside = true; \ - *r_click_item = it; \ - *r_click_char = rchar; \ - RETURN; \ - } \ - NEW_LINE \ - } - -#define ADVANCE(m_width) \ - { \ - if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && p_click_pos.x >= p_ofs.x + wofs && p_click_pos.x < p_ofs.x + wofs + m_width) { \ - if (r_outside) \ - *r_outside = false; \ - *r_click_item = it; \ - *r_click_char = rchar; \ - RETURN; \ - } \ - wofs += m_width; \ - } - -#define CHECK_HEIGHT(m_height) \ - if (m_height > line_height) { \ - line_height = m_height; \ - } - -#define YRANGE_VISIBLE(m_top, m_height) \ - (m_height > 0 && ((m_top >= 0 && m_top < height) || ((m_top + m_height - 1) >= 0 && (m_top + m_height - 1) < height))) - - Color selection_fg; - Color selection_bg; - - if (p_mode == PROCESS_DRAW) { - selection_fg = get_theme_color("font_color_selected"); - selection_bg = get_theme_color("selection_color"); - } - - int rchar = 0; - int lh = 0; - bool line_is_blank = true; - bool line_wrapped = false; - int fh = 0; + // Compute available width and total ratio (for expanders). + int total_ratio = 0; + int remaining_width = available_width; + table->total_width = hseparation; - while (it) { - switch (it->type) { - case ITEM_ALIGN: { - ItemAlign *align_it = static_cast<ItemAlign *>(it); + for (int i = 0; i < col_count; i++) { + remaining_width -= table->columns[i].min_width; + if (table->columns[i].max_width > table->columns[i].min_width) { + table->columns.write[i].expand = true; + } + if (table->columns[i].expand) { + total_ratio += table->columns[i].expand_ratio; + } + } - align = align_it->align; + // Assign actual widths. + for (int i = 0; i < col_count; i++) { + table->columns.write[i].width = table->columns[i].min_width; + if (table->columns[i].expand && total_ratio > 0) { + table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; + } + table->total_width += table->columns[i].width + hseparation; + } - } break; - case ITEM_INDENT: { - if (it != l.from) { - ItemIndent *indent_it = static_cast<ItemIndent *>(it); - - int indent = indent_it->level * tab_size * cfont->get_char_size(' ').width; - margin += indent; - begin += indent; - wofs += indent; + // Resize to max_width if needed and distribute the remaining space. + bool table_need_fit = true; + while (table_need_fit) { + table_need_fit = false; + // Fit slim. + for (int i = 0; i < col_count; i++) { + if (!table->columns[i].expand) { + continue; + } + int dif = table->columns[i].width - table->columns[i].max_width; + if (dif > 0) { + table_need_fit = true; + table->columns.write[i].width = table->columns[i].max_width; + table->total_width -= dif; + total_ratio -= table->columns[i].expand_ratio; + } + } + // Grow. + remaining_width = available_width - table->total_width; + if (remaining_width > 0 && total_ratio > 0) { + for (int i = 0; i < col_count; i++) { + if (table->columns[i].expand) { + int dif = table->columns[i].max_width - table->columns[i].width; + if (dif > 0) { + int slice = table->columns[i].expand_ratio * remaining_width / total_ratio; + int incr = MIN(dif, slice); + table->columns.write[i].width += incr; + table->total_width += incr; + } + } + } + } } + // Update line width and get total height. + idx = 0; + table->total_height = 0; + table->rows.clear(); + + Vector2 offset; + float row_height = 0; + + for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { + ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. + ItemFrame *frame = static_cast<ItemFrame *>(E->get()); + + int column = idx % col_count; + + offset.x += frame->padding.position.x; + float yofs = frame->padding.position.y; + for (int i = 0; i < frame->lines.size(); i++) { + frame->lines.write[i].text_buf->set_width(table->columns[column].width); + table->columns.write[column].width = MAX(table->columns.write[column].width, ceil(frame->lines[i].text_buf->get_size().x)); + + if (i > 0) { + frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y; + } else { + frame->lines.write[i].offset.y = 0; + } + frame->lines.write[i].offset += Vector2(offset.x, offset.y); + + float h = frame->lines[i].text_buf->get_size().y; + if (frame->min_size_over.y > 0) { + h = MAX(h, frame->min_size_over.y); + } + if (frame->max_size_over.y > 0) { + h = MIN(h, frame->max_size_over.y); + } + yofs += h; + } + yofs += frame->padding.size.y; + offset.x += table->columns[column].width + hseparation + frame->padding.size.x; + + row_height = MAX(yofs, row_height); + if (column == col_count - 1) { + offset.x = 0; + row_height += vseparation; + table->total_height += row_height; + offset.y += row_height; + table->rows.push_back(row_height); + row_height = 0; + } + idx++; + } + l.text_buf->resize_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align); } break; - case ITEM_TEXT: { - ItemText *text = static_cast<ItemText *>(it); + default: + break; + } + } + if (p_line > 0) { + l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y; + } else { + l.offset.y = 0; + } +} + +void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset) { + ERR_FAIL_COND(p_frame == nullptr); + ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size()); + + Line &l = p_frame->lines.write[p_line]; + + // Clear cache. + l.text_buf->clear(); + l.text_buf->set_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_TRIM_EDGE_SPACES); + l.char_offset = *r_char_offset; + l.char_count = 0; + + // Add indent. + l.offset.x = _find_margin(l.from, p_base_font, p_base_font_size); + l.text_buf->set_width(p_width - l.offset.x); + l.text_buf->set_align((HAlign)_find_align(l.from)); + l.text_buf->set_direction(_find_direction(l.from)); + + if (tab_size > 0) { // Align inline tabs. + Vector<float> tabs; + tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width); + l.text_buf->tab_align(tabs); + } + + // Shape current paragraph. + String text; + Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr; + for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) { + if (visible_characters >= 0 && l.char_offset + l.char_count > visible_characters) { + break; + } + switch (it->type) { + case ITEM_NEWLINE: { Ref<Font> font = _find_font(it); if (font.is_null()) { font = p_base_font; } + int font_size = _find_font_size(it); + if (font_size == -1) { + font_size = p_base_font_size; + } + l.text_buf->add_string("\n", font, font_size, Dictionary(), ""); + text += "\n"; + l.char_count += 1; + } break; + case ITEM_TEXT: { + ItemText *t = (ItemText *)it; + Ref<Font> font = _find_font(it); + if (font.is_null()) { + font = p_base_font; + } + int font_size = _find_font_size(it); + if (font_size == -1) { + font_size = p_base_font_size; + } + Dictionary font_ftr = _find_font_features(it); + String lang = _find_language(it); + String tx = t->text; + if (visible_characters >= 0 && l.char_offset + l.char_count + tx.length() > visible_characters) { + tx = tx.substr(0, l.char_offset + l.char_count + tx.length() - visible_characters); + } - const char32_t *c = text->text.get_data(); - const char32_t *cf = c; - int ascent = font->get_ascent(); - int descent = font->get_descent(); - - Color color; - Color font_color_shadow; - bool underline = false; - bool strikethrough = false; - ItemFade *fade = nullptr; - int it_char_start = p_char_count; - - Vector<ItemFX *> fx_stack = Vector<ItemFX *>(); - _fetch_item_fx_stack(text, fx_stack); - bool custom_fx_ok = true; - - if (p_mode == PROCESS_DRAW) { - color = _find_color(text, p_base_color); - font_color_shadow = _find_color(text, p_font_color_shadow); - if (_find_underline(text) || (_find_meta(text, &meta) && underline_meta)) { - underline = true; - } else if (_find_strikethrough(text)) { - strikethrough = true; - } + l.text_buf->add_string(tx, font, font_size, font_ftr, lang); + text += tx; + l.char_count += tx.length(); + } break; + case ITEM_IMAGE: { + ItemImage *img = (ItemImage *)it; + l.text_buf->add_object((uint64_t)it, img->image->get_size(), img->inline_align, 1); + text += String::chr(0xfffc); + } break; + case ITEM_TABLE: { + ItemTable *table = static_cast<ItemTable *>(it); + int hseparation = get_theme_constant("table_hseparation"); + int vseparation = get_theme_constant("table_vseparation"); + int col_count = table->columns.size(); + int t_char_count = 0; + // Set minimums to zero. + for (int i = 0; i < col_count; i++) { + table->columns.write[i].min_width = 0; + table->columns.write[i].max_width = 0; + table->columns.write[i].width = 0; + } + // Compute minimum width for each cell. + const int available_width = p_width - hseparation * (col_count - 1); - Item *fade_item = it; - while (fade_item) { - if (fade_item->type == ITEM_FADE) { - fade = static_cast<ItemFade *>(fade_item); - break; - } - fade_item = fade_item->parent; - } + int idx = 0; + for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { + ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. + ItemFrame *frame = static_cast<ItemFrame *>(E->get()); - } else if (p_mode == PROCESS_CACHE) { - l.char_count += text->text.length(); + int column = idx % col_count; + for (int i = 0; i < frame->lines.size(); i++) { + int char_offset = l.char_offset + l.char_count; + _shape_line(frame, i, p_base_font, p_base_font_size, 1, &char_offset); + int cell_ch = (char_offset - (l.char_offset + l.char_count)); + l.char_count += cell_ch; + t_char_count += cell_ch; + + table->columns.write[column].min_width = MAX(table->columns[column].min_width, ceil(frame->lines[i].text_buf->get_size().x)); + table->columns.write[column].max_width = MAX(table->columns[column].max_width, ceil(frame->lines[i].text_buf->get_non_wraped_size().x)); + } + idx++; } - rchar = 0; - //FontDrawer drawer(font, Color(1, 1, 1)); - while (*c) { - int end = 0; - int w = 0; - int fw = 0; + // Compute available width and total ratio (for expanders). + int total_ratio = 0; + int remaining_width = available_width; + table->total_width = hseparation; - lh = 0; + for (int i = 0; i < col_count; i++) { + remaining_width -= table->columns[i].min_width; + if (table->columns[i].max_width > table->columns[i].min_width) { + table->columns.write[i].expand = true; + } + if (table->columns[i].expand) { + total_ratio += table->columns[i].expand_ratio; + } + } - if (p_mode != PROCESS_CACHE) { - lh = line < l.height_caches.size() ? l.height_caches[line] : 1; - line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; - line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1; + // Assign actual widths. + for (int i = 0; i < col_count; i++) { + table->columns.write[i].width = table->columns[i].min_width; + if (table->columns[i].expand && total_ratio > 0) { + table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; } - while (c[end] != 0 && !(end && c[end - 1] == ' ' && c[end] != ' ')) { - int cw = font->get_char_size(c[end], c[end + 1]).width; - if (c[end] == '\t') { - cw = tab_size * font->get_char_size(' ').width; - } + table->total_width += table->columns[i].width + hseparation; + } - if (end > 0 && fw + cw + begin > p_width) { - break; //don't allow lines longer than assigned width + // Resize to max_width if needed and distribute the remaining space. + bool table_need_fit = true; + while (table_need_fit) { + table_need_fit = false; + // Fit slim. + for (int i = 0; i < col_count; i++) { + if (!table->columns[i].expand) { + continue; + } + int dif = table->columns[i].width - table->columns[i].max_width; + if (dif > 0) { + table_need_fit = true; + table->columns.write[i].width = table->columns[i].max_width; + table->total_width -= dif; + total_ratio -= table->columns[i].expand_ratio; } - - fw += cw; - - end++; } - CHECK_HEIGHT(fh); - ENSURE_WIDTH(fw); - - line_ascent = MAX(line_ascent, ascent); - line_descent = MAX(line_descent, descent); - fh = line_ascent + line_descent; - - if (end && c[end - 1] == ' ') { - if (p_mode == PROCESS_CACHE) { - spaces_size += font->get_char_size(' ').width; - } else if (align == ALIGN_FILL) { - int ln = MIN(l.offset_caches.size() - 1, line); - if (l.space_caches[ln]) { - align_ofs = spaces * l.offset_caches[ln] / l.space_caches[ln]; + // Grow. + remaining_width = available_width - table->total_width; + if (remaining_width > 0 && total_ratio > 0) { + for (int i = 0; i < col_count; i++) { + if (table->columns[i].expand) { + int dif = table->columns[i].max_width - table->columns[i].width; + if (dif > 0) { + int slice = table->columns[i].expand_ratio * remaining_width / total_ratio; + int incr = MIN(dif, slice); + table->columns.write[i].width += incr; + table->total_width += incr; + } } } - spaces++; } + } - { - int ofs = 0 - backtrack; + // Update line width and get total height. + idx = 0; + table->total_height = 0; + table->rows.clear(); - for (int i = 0; i < end; i++) { - int pofs = wofs + ofs; + Vector2 offset; + float row_height = 0; - if (p_mode == PROCESS_POINTER && r_click_char && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh) { - int cw = font->get_char_size(c[i], c[i + 1]).x; + for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { + ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. + ItemFrame *frame = static_cast<ItemFrame *>(E->get()); - if (c[i] == '\t') { - cw = tab_size * font->get_char_size(' ').width; - } + int column = idx % col_count; - if (p_click_pos.x - cw / 2 > p_ofs.x + align_ofs + pofs) { - rchar = int((&c[i]) - cf); - } + offset.x += frame->padding.position.x; + float yofs = frame->padding.position.y; + for (int i = 0; i < frame->lines.size(); i++) { + frame->lines.write[i].text_buf->set_width(table->columns[column].width); + table->columns.write[column].width = MAX(table->columns.write[column].width, ceil(frame->lines[i].text_buf->get_size().x)); - ofs += cw; - } else if (p_mode == PROCESS_DRAW) { - bool selected = false; - Color fx_color = Color(color); - Point2 fx_offset; - char32_t fx_char = c[i]; - - if (selection.active) { - int cofs = (&c[i]) - cf; - if ((text->index > selection.from->index || (text->index == selection.from->index && cofs >= selection.from_char)) && (text->index < selection.to->index || (text->index == selection.to->index && cofs <= selection.to_char))) { - selected = true; - } - } + if (i > 0) { + frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y; + } else { + frame->lines.write[i].offset.y = 0; + } + frame->lines.write[i].offset += Vector2(offset.x, offset.y); - int cw = 0; - int c_item_offset = p_char_count - it_char_start; + float h = frame->lines[i].text_buf->get_size().y; + if (frame->min_size_over.y > 0) { + h = MAX(h, frame->min_size_over.y); + } + if (frame->max_size_over.y > 0) { + h = MIN(h, frame->max_size_over.y); + } + yofs += h; + } + yofs += frame->padding.size.y; + offset.x += table->columns[column].width + hseparation + frame->padding.size.x; - float faded_visibility = 1.0f; - if (fade) { - if (c_item_offset >= fade->starting_index) { - faded_visibility -= (float)(c_item_offset - fade->starting_index) / (float)fade->length; - faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility; - } - fx_color.a = faded_visibility; - } + row_height = MAX(yofs, row_height); + if (column == col_count - 1) { + offset.x = 0; + row_height += vseparation; + table->total_height += row_height; + offset.y += row_height; + table->rows.push_back(row_height); + row_height = 0; + } + idx++; + } + + l.text_buf->add_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align, t_char_count); + text += String::chr(0xfffc).repeat(t_char_count); + } break; + default: + break; + } + } - bool visible = visible_characters < 0 || ((p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - line_descent - line_ascent, line_ascent + line_descent)) && - faded_visibility > 0.0f); + //Apply BiDi override. + l.text_buf->set_bidi_override(structured_text_parser(_find_stt(l.from), st_args, text)); - const bool previously_visible = visible; + *r_char_offset = l.char_offset + l.char_count; - for (int j = 0; j < fx_stack.size(); j++) { - ItemFX *item_fx = fx_stack[j]; + if (p_line > 0) { + l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y; + } else { + l.offset.y = 0; + } +} - if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) { - ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx); +float RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &p_shadow_ofs) { + Vector2 off; - Ref<CharFXTransform> charfx = item_custom->char_fx_transform; - Ref<RichTextEffect> custom_effect = item_custom->custom_effect; + ERR_FAIL_COND_V(p_frame == nullptr, off.y); + ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), off.y); - if (!custom_effect.is_null()) { - charfx->elapsed_time = item_custom->elapsed_time; - charfx->relative_index = c_item_offset; - charfx->absolute_index = p_char_count; - charfx->visibility = visible; - charfx->offset = fx_offset; - charfx->color = fx_color; - charfx->character = fx_char; + Line &l = p_frame->lines.write[p_line]; - bool effect_status = custom_effect->_process_effect_impl(charfx); - custom_fx_ok = effect_status; + Item *it_from = l.from; + Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr; + Variant meta; - fx_offset += charfx->offset; - fx_color = charfx->color; - visible &= charfx->visibility; - fx_char = charfx->character; - } - } else if (item_fx->type == ITEM_SHAKE) { - ItemShake *item_shake = static_cast<ItemShake *>(item_fx); - - uint64_t char_current_rand = item_shake->offset_random(c_item_offset); - uint64_t char_previous_rand = item_shake->offset_previous_random(c_item_offset); - uint64_t max_rand = 2147483647; - double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); - double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); - double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate)); - n_time = (n_time > 1.0) ? 1.0 : n_time; - fx_offset += Point2(Math::lerp(Math::sin(previous_offset), - Math::sin(current_offset), - n_time), - Math::lerp(Math::cos(previous_offset), - Math::cos(current_offset), - n_time)) * - (float)item_shake->strength / 10.0f; - } else if (item_fx->type == ITEM_WAVE) { - ItemWave *item_wave = static_cast<ItemWave *>(item_fx); - - double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_wave->amplitude / 10.0f); - fx_offset += Point2(0, 1) * value; - } else if (item_fx->type == ITEM_TORNADO) { - ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx); - - double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius); - double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius); - fx_offset += Point2(torn_x, torn_y); - } else if (item_fx->type == ITEM_RAINBOW) { - ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx); - - fx_color = fx_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + pofs) / 50)), - item_rainbow->saturation, - item_rainbow->value, - fx_color.a); - } - } + if (it_from == nullptr) { + return off.y; + } - if (visible) { - line_is_blank = false; - w += font->get_char_size(c[i], c[i + 1]).x; - } + RID ci = get_canvas_item(); + bool rtl = (l.text_buf->get_direction() == TextServer::DIRECTION_RTL); + bool lrtl = is_layout_rtl(); - if (c[i] == '\t') { - visible = false; - } + Vector<int> list_index; + Vector<ItemList *> list_items; + _find_list(l.from, list_index, list_items); - if (visible) { - if (selected) { - cw = font->get_char_size(fx_char, c[i + 1]).x; - draw_rect(Rect2(p_ofs.x + pofs, p_ofs.y + y, cw, lh), selection_bg); - } + String prefix; + for (int i = 0; i < list_index.size(); i++) { + if (rtl) { + prefix = prefix + "."; + } else { + prefix = "." + prefix; + } + String segment; + if (list_items[i]->list_type == LIST_DOTS) { + static const char32_t _prefix[2] = { 0x25CF, 0 }; + prefix = _prefix; + break; + } else if (list_items[i]->list_type == LIST_NUMBERS) { + segment = TS->format_number(itos(list_index[i]), _find_language(l.from)); + } else if (list_items[i]->list_type == LIST_LETTERS) { + segment = _letters(list_index[i], list_items[i]->capitalize); + } else if (list_items[i]->list_type == LIST_ROMAN) { + segment = _roman(list_index[i], list_items[i]->capitalize); + } + if (rtl) { + prefix = prefix + segment; + } else { + prefix = segment + prefix; + } + } + if (prefix != "") { + Ref<Font> font = _find_font(l.from); + if (font.is_null()) { + font = get_theme_font("normal_font"); + } + int font_size = _find_font_size(l.from); + if (font_size == -1) { + font_size = get_theme_font_size("normal_font_size"); + } + if (rtl) { + float offx = 0.0f; + if (!lrtl && p_frame == main) { // Skip Scrollbar. + offx -= scroll_w; + } + font->draw_string(ci, p_ofs + Vector2(p_width - l.offset.x + offx, l.text_buf->get_line_ascent(0)), " " + prefix, HALIGN_LEFT, l.offset.x, font_size, _find_color(l.from, p_base_color)); + } else { + float offx = 0.0f; + if (lrtl && p_frame == main) { // Skip Scrollbar. + offx += scroll_w; + } + font->draw_string(ci, p_ofs + Vector2(offx, l.text_buf->get_line_ascent(0)), prefix + " ", HALIGN_RIGHT, l.offset.x, font_size, _find_color(l.from, p_base_color)); + } + } - if (p_font_color_shadow.a > 0) { - float x_ofs_shadow = align_ofs + pofs; - float y_ofs_shadow = y + lh - line_descent; - font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow); + // Draw text. + for (int line = 0; line < l.text_buf->get_line_count(); line++) { + RID rid = l.text_buf->get_line_rid(line); - if (p_shadow_as_outline) { - font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y) + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow); - font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow); - font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow); - } - } + float width = l.text_buf->get_width(); + float length = TS->shaped_text_get_width(rid); - if (selected) { - font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), fx_char, c[i + 1], -1, override_selected_font_color ? selection_fg : fx_color); - } else { - cw = font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent) + fx_offset, fx_char, c[i + 1], -1, fx_color); - } - } else if (previously_visible && c[i] != '\t') { - backtrack += font->get_char_size(fx_char, c[i + 1]).x; - } + // Draw line. - p_char_count++; - if (c[i] == '\t') { - cw = tab_size * font->get_char_size(' ').width; - backtrack = MAX(0, backtrack - cw); + if (rtl) { + off.x = p_width - l.offset.x - width; + if (!lrtl && p_frame == main) { // Skip Scrollbar. + off.x -= scroll_w; + } + } else { + off.x = l.offset.x; + if (lrtl && p_frame == main) { // Skip Scrollbar. + off.x += scroll_w; + } + } + + // Draw text. + switch (l.text_buf->get_align()) { + case HALIGN_FILL: + case HALIGN_LEFT: { + if (rtl) { + off.x += width - length; + } + } break; + case HALIGN_CENTER: { + off.x += Math::floor((width - length) / 2.0); + } break; + case HALIGN_RIGHT: { + if (!rtl) { + off.x += width - length; + } + } break; + } + + //draw_rect(Rect2(p_ofs + off, TS->shaped_text_get_size(rid)), Color(1,0,0), false, 2); //DEBUG_RECTS + + off.y += TS->shaped_text_get_ascent(rid); + // Draw inlined objects. + Array objects = TS->shaped_text_get_objects(rid); + for (int i = 0; i < objects.size(); i++) { + Item *it = (Item *)(uint64_t)objects[i]; + if (it != nullptr) { + Rect2 rect = TS->shaped_text_get_object_rect(rid, objects[i]); + //draw_rect(rect, Color(1,0,0), false, 2); //DEBUG_RECTS + switch (it->type) { + case ITEM_IMAGE: { + ItemImage *img = static_cast<ItemImage *>(it); + img->image->draw_rect(ci, Rect2(p_ofs + rect.position + off, rect.size), false, img->color); + } break; + case ITEM_TABLE: { + ItemTable *table = static_cast<ItemTable *>(it); + Color odd_row_bg = get_theme_color("table_odd_row_bg"); + Color even_row_bg = get_theme_color("table_even_row_bg"); + Color border = get_theme_color("table_border"); + int col_count = table->columns.size(); + int row_count = table->rows.size(); + + int idx = 0; + for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { + ItemFrame *frame = static_cast<ItemFrame *>(E->get()); + + int col = idx % col_count; + int row = idx / col_count; + + if (frame->lines.size() != 0 && row < row_count) { + Vector2 coff = frame->lines[0].offset; + if (rtl) { + coff.x = rect.size.width - table->columns[col].width - coff.x; + } + if (row % 2 == 0) { + draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg), true); + } else { + draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg), true); } + draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->border != Color(0, 0, 0, 0) ? frame->border : border), false); + } - ofs += cw; + for (int j = 0; j < frame->lines.size(); j++) { + _draw_line(frame, j, p_ofs + rect.position + off + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_base_color, p_outline_size, p_outline_color, p_font_color_shadow, p_shadow_as_outline, p_shadow_ofs); } + idx++; } + } break; + default: + break; + } + } + } - if (underline) { - Color uc = color; - uc.a *= 0.5; - int uy = y + lh - line_descent + font->get_underline_position(); - float underline_width = font->get_underline_thickness(); -#ifdef TOOLS_ENABLED - underline_width *= EDSCALE; -#endif - RS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, underline_width); - } else if (strikethrough) { - Color uc = color; - uc.a *= 0.5; - int uy = y + lh - (line_ascent + line_descent) / 2; - float strikethrough_width = font->get_underline_thickness(); -#ifdef TOOLS_ENABLED - strikethrough_width *= EDSCALE; -#endif - RS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, strikethrough_width); - } - } + const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid); + const TextServer::Glyph *glyphs = visual.ptr(); + int gl_size = visual.size(); - ADVANCE(fw); - CHECK_HEIGHT(fh); //must be done somewhere - c = &c[end]; - } + Vector2 gloff = off; + // Draw oulines and shadow. + for (int i = 0; i < gl_size; i++) { + Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start); + int size = _find_outline_size(it); + Color font_color = _find_outline_color(it, Color(0, 0, 0, 0)); + if (size <= 0) { + gloff.x += glyphs[i].advance; + continue; + } - } break; - case ITEM_IMAGE: { - lh = 0; - if (p_mode != PROCESS_CACHE) { - lh = line < l.height_caches.size() ? l.height_caches[line] : 1; - } else { - l.char_count += 1; //images count as chars too + // Get FX. + ItemFade *fade = nullptr; + Item *fade_item = it; + while (fade_item) { + if (fade_item->type == ITEM_FADE) { + fade = static_cast<ItemFade *>(fade_item); + break; } + fade_item = fade_item->parent; + } - ItemImage *img = static_cast<ItemImage *>(it); + Vector<ItemFX *> fx_stack; + _fetch_item_fx_stack(it, fx_stack); + bool custom_fx_ok = true; - Ref<Font> font = _find_font(it); - if (font.is_null()) { - font = p_base_font; + Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off); + RID frid = glyphs[i].font_rid; + uint32_t gl = glyphs[i].index; + + //Apply fx. + float faded_visibility = 1.0f; + if (fade) { + if (glyphs[i].start >= fade->starting_index) { + faded_visibility -= (float)(glyphs[i].start - fade->starting_index) / (float)fade->length; + faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility; } + font_color.a = faded_visibility; + } - if (p_mode == PROCESS_POINTER && r_click_char) { - *r_click_char = 0; + bool visible = (font_color.a != 0); + + for (int j = 0; j < fx_stack.size(); j++) { + ItemFX *item_fx = fx_stack[j]; + if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) { + ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx); + + Ref<CharFXTransform> charfx = item_custom->char_fx_transform; + Ref<RichTextEffect> custom_effect = item_custom->custom_effect; + + if (!custom_effect.is_null()) { + charfx->elapsed_time = item_custom->elapsed_time; + charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end); + charfx->visibility = visible; + charfx->outline = true; + charfx->font = frid; + charfx->glpyh_index = gl; + charfx->offset = fx_offset; + charfx->color = font_color; + + bool effect_status = custom_effect->_process_effect_impl(charfx); + custom_fx_ok = effect_status; + + fx_offset += charfx->offset; + font_color = charfx->color; + frid = charfx->font; + gl = charfx->glpyh_index; + visible &= charfx->visibility; + } + } else if (item_fx->type == ITEM_SHAKE) { + ItemShake *item_shake = static_cast<ItemShake *>(item_fx); + + uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start); + uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start); + uint64_t max_rand = 2147483647; + double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); + double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); + double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate)); + n_time = (n_time > 1.0) ? 1.0 : n_time; + fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f; + } else if (item_fx->type == ITEM_WAVE) { + ItemWave *item_wave = static_cast<ItemWave *>(item_fx); + + double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f); + fx_offset += Point2(0, 1) * value; + } else if (item_fx->type == ITEM_TORNADO) { + ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx); + + double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius); + double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius); + fx_offset += Point2(torn_x, torn_y); + } else if (item_fx->type == ITEM_RAINBOW) { + ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx); + + font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + gloff.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a); } + } - ENSURE_WIDTH(img->size.width); + Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); - bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->size.height, img->size.height)); + // Draw glyph outlines. + for (int j = 0; j < glyphs[i].repeat; j++) { if (visible) { - line_is_blank = false; - } - - if (p_mode == PROCESS_DRAW && visible) { - img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->size.height), img->size), false, img->color); + if (frid != RID()) { + if (p_shadow_as_outline) { + TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, shadow_ofs.y), gl, p_font_color_shadow); + TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(shadow_ofs.x, -shadow_ofs.y), gl, p_font_color_shadow); + TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, -shadow_ofs.y), gl, p_font_color_shadow); + } + TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff, gl, font_color); + } } - p_char_count++; - - ADVANCE(img->size.width); - CHECK_HEIGHT((img->size.height + font->get_descent())); + gloff.x += glyphs[i].advance; + } + } - } break; - case ITEM_NEWLINE: { - lh = 0; + // Draw main text. + Color selection_fg = get_theme_color("font_color_selected"); + Color selection_bg = get_theme_color("selection_color"); - if (p_mode != PROCESS_CACHE) { - lh = line < l.height_caches.size() ? l.height_caches[line] : 1; - line_is_blank = true; - } + int sel_start = -1; + int sel_end = -1; - } break; - case ITEM_TABLE: { - lh = 0; - ItemTable *table = static_cast<ItemTable *>(it); - int hseparation = get_theme_constant("table_hseparation"); - int vseparation = get_theme_constant("table_vseparation"); - Color ccolor = _find_color(table, p_base_color); - Vector2 draw_ofs = Point2(wofs, y); - Color font_color_shadow = get_theme_color("font_color_shadow"); - bool use_outline = get_theme_constant("shadow_as_outline"); - Point2 shadow_ofs2(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); - - if (p_mode == PROCESS_CACHE) { - int idx = 0; - //set minimums to zero - for (int i = 0; i < table->columns.size(); i++) { - table->columns.write[i].min_width = 0; - table->columns.write[i].max_width = 0; - table->columns.write[i].width = 0; - } - //compute minimum width for each cell - const int available_width = p_width - hseparation * (table->columns.size() - 1) - wofs; + if (selection.active && (selection.from_frame->lines[selection.from_line].char_offset + selection.from_char) <= (l.char_offset + TS->shaped_text_get_range(rid).y) && (selection.to_frame->lines[selection.to_line].char_offset + selection.to_char) >= (l.char_offset + TS->shaped_text_get_range(rid).x)) { + sel_start = MAX(TS->shaped_text_get_range(rid).x, (selection.from_frame->lines[selection.from_line].char_offset + selection.from_char) - l.char_offset); + sel_end = MIN(TS->shaped_text_get_range(rid).y, (selection.to_frame->lines[selection.to_line].char_offset + selection.to_char) - l.char_offset); - for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { - ERR_CONTINUE(E->get()->type != ITEM_FRAME); //children should all be frames - ItemFrame *frame = static_cast<ItemFrame *>(E->get()); + Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_start, sel_end); + for (int i = 0; i < sel.size(); i++) { + Rect2 rect = Rect2(sel[i].x + p_ofs.x + off.x, p_ofs.y + off.y - TS->shaped_text_get_ascent(rid), sel[i].y - sel[i].x, TS->shaped_text_get_size(rid).y); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_bg); + } + } - int column = idx % table->columns.size(); + for (int i = 0; i < gl_size; i++) { + bool selected = selection.active && (sel_start != -1) && (glyphs[i].start >= sel_start) && (glyphs[i].end <= sel_end); + Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start); + Color font_color = _find_color(it, p_base_color); + if (_find_underline(it) || (_find_meta(it, &meta) && underline_meta)) { + Color uc = font_color; + uc.a *= 0.5; + float y_off = TS->shaped_text_get_underline_position(rid); + float underline_width = TS->shaped_text_get_underline_thickness(rid); +#ifdef TOOLS_ENABLED + underline_width *= EDSCALE; +#endif + draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width); + } else if (_find_strikethrough(it)) { + Color uc = font_color; + uc.a *= 0.5; + float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2; + float underline_width = TS->shaped_text_get_underline_thickness(rid); +#ifdef TOOLS_ENABLED + underline_width *= EDSCALE; +#endif + draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width); + } - int ly = 0; + // Get FX. + ItemFade *fade = nullptr; + Item *fade_item = it; + while (fade_item) { + if (fade_item->type == ITEM_FADE) { + fade = static_cast<ItemFade *>(fade_item); + break; + } + fade_item = fade_item->parent; + } - for (int i = 0; i < frame->lines.size(); i++) { - _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs2); - table->columns.write[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width); - table->columns.write[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].maximum_width); - } - idx++; - } + Vector<ItemFX *> fx_stack; + _fetch_item_fx_stack(it, fx_stack); + bool custom_fx_ok = true; - //compute available width and total ratio (for expanders) + Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off); + RID frid = glyphs[i].font_rid; + uint32_t gl = glyphs[i].index; - int total_ratio = 0; - int remaining_width = available_width; - table->total_width = hseparation; + //Apply fx. + float faded_visibility = 1.0f; + if (fade) { + if (glyphs[i].start >= fade->starting_index) { + faded_visibility -= (float)(glyphs[i].start - fade->starting_index) / (float)fade->length; + faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility; + } + font_color.a = faded_visibility; + } - for (int i = 0; i < table->columns.size(); i++) { - remaining_width -= table->columns[i].min_width; - if (table->columns[i].max_width > table->columns[i].min_width) { - table->columns.write[i].expand = true; - } - if (table->columns[i].expand) { - total_ratio += table->columns[i].expand_ratio; - } + bool visible = (font_color.a != 0); + + for (int j = 0; j < fx_stack.size(); j++) { + ItemFX *item_fx = fx_stack[j]; + if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) { + ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx); + + Ref<CharFXTransform> charfx = item_custom->char_fx_transform; + Ref<RichTextEffect> custom_effect = item_custom->custom_effect; + + if (!custom_effect.is_null()) { + charfx->elapsed_time = item_custom->elapsed_time; + charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end); + charfx->visibility = visible; + charfx->outline = false; + charfx->font = frid; + charfx->glpyh_index = gl; + charfx->offset = fx_offset; + charfx->color = font_color; + + bool effect_status = custom_effect->_process_effect_impl(charfx); + custom_fx_ok = effect_status; + + fx_offset += charfx->offset; + font_color = charfx->color; + frid = charfx->font; + gl = charfx->glpyh_index; + visible &= charfx->visibility; } + } else if (item_fx->type == ITEM_SHAKE) { + ItemShake *item_shake = static_cast<ItemShake *>(item_fx); + + uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start); + uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start); + uint64_t max_rand = 2147483647; + double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); + double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); + double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate)); + n_time = (n_time > 1.0) ? 1.0 : n_time; + fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f; + } else if (item_fx->type == ITEM_WAVE) { + ItemWave *item_wave = static_cast<ItemWave *>(item_fx); + + double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f); + fx_offset += Point2(0, 1) * value; + } else if (item_fx->type == ITEM_TORNADO) { + ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx); + + double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius); + double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius); + fx_offset += Point2(torn_x, torn_y); + } else if (item_fx->type == ITEM_RAINBOW) { + ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx); + + font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + off.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a); + } + } - //assign actual widths - for (int i = 0; i < table->columns.size(); i++) { - table->columns.write[i].width = table->columns[i].min_width; - if (table->columns[i].expand && total_ratio > 0) { - table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; - } - table->total_width += table->columns[i].width + hseparation; - } + if (selected) { + font_color = override_selected_font_color ? selection_fg : font_color; + } - //resize to max_width if needed and distribute the remaining space - bool table_need_fit = true; - while (table_need_fit) { - table_need_fit = false; - //fit slim - for (int i = 0; i < table->columns.size(); i++) { - if (!table->columns[i].expand) { - continue; - } - int dif = table->columns[i].width - table->columns[i].max_width; - if (dif > 0) { - table_need_fit = true; - table->columns.write[i].width = table->columns[i].max_width; - table->total_width -= dif; - total_ratio -= table->columns[i].expand_ratio; - } - } - //grow - remaining_width = available_width - table->total_width; - if (remaining_width > 0 && total_ratio > 0) { - for (int i = 0; i < table->columns.size(); i++) { - if (table->columns[i].expand) { - int dif = table->columns[i].max_width - table->columns[i].width; - if (dif > 0) { - int slice = table->columns[i].expand_ratio * remaining_width / total_ratio; - int incr = MIN(dif, slice); - table->columns.write[i].width += incr; - table->total_width += incr; - } - } - } - } + // Draw glyphs. + for (int j = 0; j < glyphs[i].repeat; j++) { + if (visible) { + if (frid != RID()) { + TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color); + } else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { + TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color); } + } + off.x += glyphs[i].advance; + } + } + off.y += TS->shaped_text_get_descent(rid); + } - //compute caches properly again with the right width - idx = 0; - for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { - ERR_CONTINUE(E->get()->type != ITEM_FRAME); //children should all be frames - ItemFrame *frame = static_cast<ItemFrame *>(E->get()); + return off.y; +} - int column = idx % table->columns.size(); +void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool *r_outside) { + if (r_click_item) { + *r_click_item = nullptr; + } + if (r_click_char != nullptr) { + *r_click_char = 0; + } + if (r_outside != nullptr) { + *r_outside = true; + } - for (int i = 0; i < frame->lines.size(); i++) { - int ly = 0; - _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs2); - frame->lines.write[i].height_cache = ly; //actual height - frame->lines.write[i].height_accum_cache = ly; //actual height - } - idx++; - } - } + Size2 size = get_size(); + Rect2 text_rect = _get_text_rect(); - Point2 offset(align_ofs + hseparation, vseparation); + int vofs = vscroll->get_value(); - int row_height = 0; - //draw using computed caches - int idx = 0; - for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { - ERR_CONTINUE(E->get()->type != ITEM_FRAME); //children should all be frames - ItemFrame *frame = static_cast<ItemFrame *>(E->get()); + // Search for the first line. + int from_line = 0; - int column = idx % table->columns.size(); + //TODO, change to binary search ? + while (from_line < main->lines.size()) { + if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y + _get_text_rect().get_position().y >= vofs) { + break; + } + from_line++; + } - int ly = 0; - int yofs = 0; + if (from_line >= main->lines.size()) { + return; + } - int lines_h = frame->lines[frame->lines.size() - 1].height_accum_cache - (frame->lines[0].height_accum_cache - frame->lines[0].height_cache); - int lines_ofs = p_ofs.y + offset.y + draw_ofs.y; + Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs); + while (ofs.y < size.height && from_line < main->lines.size()) { + ofs.y += _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char); + if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) { + if (r_outside != nullptr) { + *r_outside = false; + } + return; + } + from_line++; + } +} - bool visible = lines_ofs < get_size().height && lines_ofs + lines_h >= 0; - if (visible) { - line_is_blank = false; - } +float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char) { + Vector2 off; - for (int i = 0; i < frame->lines.size(); i++) { - if (visible) { - if (p_mode == PROCESS_DRAW) { - nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs2); - } else if (p_mode == PROCESS_POINTER) { - _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs2, p_click_pos, r_click_item, r_click_char, r_outside); - if (r_click_item && *r_click_item) { - RETURN; // exit early - } - } - } + int char_pos = -1; + Line &l = p_frame->lines.write[p_line]; + bool rtl = (l.text_buf->get_direction() == TextServer::DIRECTION_RTL); + bool lrtl = is_layout_rtl(); + bool table_hit = false; - yofs += frame->lines[i].height_cache; - if (p_mode == PROCESS_CACHE) { - frame->lines.write[i].height_accum_cache = offset.y + draw_ofs.y + frame->lines[i].height_cache; - } - } + for (int line = 0; line < l.text_buf->get_line_count(); line++) { + RID rid = l.text_buf->get_line_rid(line); - row_height = MAX(yofs, row_height); - offset.x += table->columns[column].width + hseparation; + float width = l.text_buf->get_width(); + float length = TS->shaped_text_get_width(rid); - if (column == table->columns.size() - 1) { - offset.y += row_height + vseparation; - offset.x = hseparation; - row_height = 0; - } - idx++; - } + if (rtl) { + off.x = p_width - l.offset.x - width; + if (!lrtl && p_frame == main) { // Skip Scrollbar. + off.x -= scroll_w; + } + } else { + off.x = l.offset.x; + if (lrtl && p_frame == main) { // Skip Scrollbar. + off.x += scroll_w; + } + } - int total_height = offset.y; - if (row_height) { - total_height = row_height + vseparation; + switch (l.text_buf->get_align()) { + case HALIGN_FILL: + case HALIGN_LEFT: { + if (rtl) { + off.x += width - length; } + } break; + case HALIGN_CENTER: { + off.x += Math::floor((width - length) / 2.0); + } break; + case HALIGN_RIGHT: { + if (!rtl) { + off.x += width - length; + } + } break; + } - ADVANCE(table->total_width); - CHECK_HEIGHT(total_height); + off.y += TS->shaped_text_get_ascent(rid); - } break; + Array objects = TS->shaped_text_get_objects(rid); + for (int i = 0; i < objects.size(); i++) { + Item *it = (Item *)(uint64_t)objects[i]; + if (it != nullptr) { + Rect2 rect = TS->shaped_text_get_object_rect(rid, objects[i]); + if (rect.has_point(p_click - p_ofs - off)) { + switch (it->type) { + case ITEM_TABLE: { + int hseparation = get_theme_constant("table_hseparation"); + int vseparation = get_theme_constant("table_vseparation"); - default: { - } - } + ItemTable *table = static_cast<ItemTable *>(it); - Item *itp = it; + table_hit = true; - it = _get_next_item(it); + int idx = 0; + int col_count = table->columns.size(); + int row_count = table->rows.size(); - if (it && (p_line + 1 < p_frame->lines.size()) && p_frame->lines[p_line + 1].from == it) { - if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh) { - //went to next line, but pointer was on the previous one - if (r_outside) { - *r_outside = true; + for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { + ItemFrame *frame = static_cast<ItemFrame *>(E->get()); + + int col = idx % col_count; + int row = idx / col_count; + + if (frame->lines.size() != 0 && row < row_count) { + Vector2 coff = frame->lines[0].offset; + if (rtl) { + coff.x = rect.size.width - table->columns[col].width - coff.x; + } + Rect2 crect = Rect2(p_ofs + off + rect.position + coff - frame->padding.position, Size2(table->columns[col].width + hseparation, table->rows[row] + vseparation) + frame->padding.position + frame->padding.size); + if (col == col_count - 1) { + if (rtl) { + crect.size.x = crect.position.x + crect.size.x; + crect.position.x = 0; + } else { + crect.size.x = get_size().x; + } + } + if (crect.has_point(p_click)) { + for (int j = 0; j < frame->lines.size(); j++) { + _find_click_in_line(frame, j, p_ofs + off + rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char); + if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) { + return off.y; + } + } + } + } + idx++; + } + } break; + default: + break; + } } - *r_click_item = itp; - *r_click_char = rchar; - RETURN; } + } + Rect2 rect = Rect2(p_ofs + off - Vector2(0, TS->shaped_text_get_ascent(rid)), Size2(get_size().x, TS->shaped_text_get_size(rid).y)); - break; + if (rect.has_point(p_click) && !table_hit) { + char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x); } + off.y += TS->shaped_text_get_descent(rid); } - NEW_LINE; - RETURN; + if (char_pos >= 0) { + // Find item. + if (r_click_item != nullptr) { + Item *it = p_frame->lines[p_line].from; + Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr; + it = _get_item_at_pos(it, it_to, char_pos); + *r_click_item = it; + } + + if (r_click_frame != nullptr) { + *r_click_frame = p_frame; + } + + if (r_click_line != nullptr) { + *r_click_line = p_line; + } + + if (r_click_char != nullptr) { + *r_click_char = char_pos; + } + } -#undef RETURN -#undef NEW_LINE -#undef ENSURE_WIDTH -#undef ADVANCE -#undef CHECK_HEIGHT + return off.y; } void RichTextLabel::_scroll_changed(double) { @@ -910,7 +1257,7 @@ void RichTextLabel::_update_scroll() { vscroll->hide(); } - main->first_invalid_line = 0; //invalidate ALL + main->first_resized_line = 0; //invalidate ALL _validate_line_caches(main); } } @@ -960,10 +1307,11 @@ void RichTextLabel::_notification(int p_what) { } } break; case NOTIFICATION_RESIZED: { - main->first_invalid_line = 0; //invalidate ALL + main->first_resized_line = 0; //invalidate ALL update(); } break; + case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_ENTER_TREE: { if (bbcode != "") { set_bbcode(bbcode); @@ -971,11 +1319,11 @@ void RichTextLabel::_notification(int p_what) { main->first_invalid_line = 0; //invalidate ALL update(); - } break; - case NOTIFICATION_THEME_CHANGED: { + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: + case NOTIFICATION_TRANSLATION_CHANGED: { + main->first_invalid_line = 0; //invalidate ALL update(); - } break; case NOTIFICATION_DRAW: { _validate_line_caches(main); @@ -994,36 +1342,37 @@ void RichTextLabel::_notification(int p_what) { RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false); } - int ofs = vscroll->get_value(); - - //todo, change to binary search + float vofs = vscroll->get_value(); + // Search for the first line. int from_line = 0; - int total_chars = 0; + + //TODO, change to binary search ? while (from_line < main->lines.size()) { - if (main->lines[from_line].height_accum_cache + _get_text_rect().get_position().y >= ofs) { + if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y + _get_text_rect().get_position().y >= vofs) { break; } - total_chars += main->lines[from_line].char_count; from_line++; } if (from_line >= main->lines.size()) { break; //nothing to draw } - int y = (main->lines[from_line].height_accum_cache - main->lines[from_line].height_cache) - ofs; Ref<Font> base_font = get_theme_font("normal_font"); Color base_color = get_theme_color("default_color"); + Color outline_color = get_theme_color("outline_color"); + int outline_size = get_theme_constant("outline_size"); Color font_color_shadow = get_theme_color("font_color_shadow"); bool use_outline = get_theme_constant("shadow_as_outline"); Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); visible_line_count = 0; - while (y < size.height && from_line < main->lines.size()) { - visible_line_count++; - _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, Point2i(), nullptr, nullptr, nullptr, total_chars); - total_chars += main->lines[from_line].char_count; + // New cache draw. + Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs); + while (ofs.y < size.height && from_line < main->lines.size()) { + visible_line_count++; + ofs.y += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_color_shadow, use_outline, shadow_ofs); from_line++; } } break; @@ -1036,50 +1385,12 @@ void RichTextLabel::_notification(int p_what) { } } -void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item, int *r_click_char, bool *r_outside) { - if (r_click_item) { - *r_click_item = nullptr; - } - - Rect2 text_rect = _get_text_rect(); - int ofs = vscroll->get_value(); - Color font_color_shadow = get_theme_color("font_color_shadow"); - bool use_outline = get_theme_constant("shadow_as_outline"); - Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); - - //todo, change to binary search - int from_line = 0; - - while (from_line < p_frame->lines.size()) { - if (p_frame->lines[from_line].height_accum_cache >= ofs) { - break; - } - from_line++; - } - - if (from_line >= p_frame->lines.size()) { - return; - } - - int y = (p_frame->lines[from_line].height_accum_cache - p_frame->lines[from_line].height_cache) - ofs; - Ref<Font> base_font = get_theme_font("normal_font"); - Color base_color = get_theme_color("default_color"); - - while (y < text_rect.get_size().height && from_line < p_frame->lines.size()) { - _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_POINTER, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, p_click, r_click_item, r_click_char, r_outside); - if (r_click_item && *r_click_item) { - return; - } - from_line++; - } -} - Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const { if (!underline_meta) { return CURSOR_ARROW; } - if (selection.click) { + if (selection.click_item) { return CURSOR_IBEAM; } @@ -1087,10 +1398,13 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const return CURSOR_ARROW; //invalid } - int line = 0; + if (main->first_resized_line < main->lines.size()) { + return CURSOR_ARROW; //invalid + } + Item *item = nullptr; - bool outside; - ((RichTextLabel *)(this))->_find_click(main, p_pos, &item, &line, &outside); + bool outside = true; + ((RichTextLabel *)(this))->_find_click(main, p_pos, nullptr, nullptr, &item, nullptr, &outside); if (item && !outside && ((RichTextLabel *)(this))->_find_meta(item, nullptr)) { return CURSOR_POINTING_HAND; @@ -1106,27 +1420,37 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { if (main->first_invalid_line < main->lines.size()) { return; } + if (main->first_resized_line < main->lines.size()) { + return; + } if (b->get_button_index() == BUTTON_LEFT) { if (b->is_pressed() && !b->is_doubleclick()) { scroll_updated = false; - int line = 0; - Item *item = nullptr; - + ItemFrame *c_frame = nullptr; + int c_line = 0; + Item *c_item = nullptr; + int c_index = 0; bool outside; - _find_click(main, b->get_position(), &item, &line, &outside); - if (item) { + _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside); + if (c_item != nullptr) { if (selection.enabled) { - selection.click = item; - selection.click_char = line; + selection.click_frame = c_frame; + selection.click_item = c_item; + selection.click_line = c_line; + selection.click_char = c_index; // Erase previous selection. if (selection.active) { - selection.from = nullptr; - selection.from_char = '\0'; - selection.to = nullptr; - selection.to_char = '\0'; + selection.from_frame = nullptr; + selection.from_line = 0; + selection.from_item = nullptr; + selection.from_char = 0; + selection.to_frame = nullptr; + selection.to_line = 0; + selection.to_item = nullptr; + selection.to_char = 0; selection.active = false; update(); @@ -1135,44 +1459,49 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { } } else if (b->is_pressed() && b->is_doubleclick() && selection.enabled) { //doubleclick: select word - int line = 0; - Item *item = nullptr; + + ItemFrame *c_frame = nullptr; + int c_line = 0; + Item *c_item = nullptr; + int c_index = 0; bool outside; - _find_click(main, b->get_position(), &item, &line, &outside); + _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside); - while (item && item->type != ITEM_TEXT) { - item = _get_next_item(item, true); - } + if (c_frame) { + const Line &l = c_frame->lines[c_line]; + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(l.text_buf->get_rid()); + for (int i = 0; i < words.size(); i++) { + if (c_index >= words[i].x && c_index < words[i].y) { + selection.from_frame = c_frame; + selection.from_line = c_line; + selection.from_item = c_item; + selection.from_char = words[i].x; + + selection.to_frame = c_frame; + selection.to_line = c_line; + selection.to_item = c_item; + selection.to_char = words[i].y; - if (item && item->type == ITEM_TEXT) { - String itext = static_cast<ItemText *>(item)->text; - - int beg, end; - if (select_word(itext, line, beg, end)) { - selection.from = item; - selection.to = item; - selection.from_char = beg; - selection.to_char = end - 1; - selection.active = true; - update(); + selection.active = true; + update(); + break; + } } } } else if (!b->is_pressed()) { - selection.click = nullptr; + selection.click_item = nullptr; if (!b->is_doubleclick() && !scroll_updated) { - int line = 0; - Item *item = nullptr; + Item *c_item = nullptr; - bool outside; - _find_click(main, b->get_position(), &item, &line, &outside); + bool outside = true; + _find_click(main, b->get_position(), nullptr, nullptr, &c_item, nullptr, &outside); - if (item) { + if (c_item) { Variant meta; - if (!outside && _find_meta(item, &meta)) { + if (!outside && _find_meta(c_item, &meta)) { //meta clicked - emit_signal("meta_clicked", meta); } } @@ -1221,13 +1550,13 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { } break; case KEY_UP: { if (vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height()); + vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size"))); handled = true; } } break; case KEY_DOWN: { if (vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height()); + vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size"))); handled = true; } } break; @@ -1265,27 +1594,32 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { if (main->first_invalid_line < main->lines.size()) { return; } + if (main->first_resized_line < main->lines.size()) { + return; + } - int line = 0; - Item *item = nullptr; + ItemFrame *c_frame = nullptr; + int c_line = 0; + Item *c_item = nullptr; + int c_index = 0; bool outside; - _find_click(main, m->get_position(), &item, &line, &outside); - if (selection.click) { - if (!item) { - return; // do not update - } - - selection.from = selection.click; + _find_click(main, m->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside); + if (selection.click_item && c_item) { + selection.from_frame = selection.click_frame; + selection.from_line = selection.click_line; + selection.from_item = selection.click_item; selection.from_char = selection.click_char; - selection.to = item; - selection.to_char = line; + selection.to_frame = c_frame; + selection.to_line = c_line; + selection.to_item = c_item; + selection.to_char = c_index; bool swap = false; - if (selection.from->index > selection.to->index) { + if (selection.from_item->index > selection.to_item->index) { swap = true; - } else if (selection.from->index == selection.to->index) { + } else if (selection.from_item->index == selection.to_item->index) { if (selection.from_char > selection.to_char) { swap = true; } else if (selection.from_char == selection.to_char) { @@ -1295,7 +1629,9 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { } if (swap) { - SWAP(selection.from, selection.to); + SWAP(selection.from_frame, selection.to_frame); + SWAP(selection.from_line, selection.to_line); + SWAP(selection.from_item, selection.to_item); SWAP(selection.from_char, selection.to_char); } @@ -1305,7 +1641,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { Variant meta; ItemMeta *item_meta; - if (item && !outside && _find_meta(item, &meta, &item_meta)) { + if (c_item && !outside && _find_meta(c_item, &meta, &item_meta)) { if (meta_hovering != item_meta) { if (meta_hovering) { emit_signal("meta_hover_ended", current_meta); @@ -1322,6 +1658,31 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { } } +void RichTextLabel::_find_frame(Item *p_item, ItemFrame **r_frame, int *r_line) { + if (r_frame != nullptr) { + *r_frame = nullptr; + } + if (r_line != nullptr) { + *r_line = 0; + } + + Item *item = p_item; + + while (item) { + if (item->parent != nullptr && item->parent->type == ITEM_FRAME) { + if (r_frame != nullptr) { + *r_frame = (ItemFrame *)item->parent; + } + if (r_line != nullptr) { + *r_line = item->line; + } + return; + } + + item = item->parent; + } +} + Ref<Font> RichTextLabel::_find_font(Item *p_item) { Item *fontitem = p_item; @@ -1337,10 +1698,103 @@ Ref<Font> RichTextLabel::_find_font(Item *p_item) { return Ref<Font>(); } -int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font) { +int RichTextLabel::_find_font_size(Item *p_item) { + Item *sizeitem = p_item; + + while (sizeitem) { + if (sizeitem->type == ITEM_FONT_SIZE) { + ItemFontSize *fi = static_cast<ItemFontSize *>(sizeitem); + return fi->font_size; + } + + sizeitem = sizeitem->parent; + } + + return -1; +} + +int RichTextLabel::_find_outline_size(Item *p_item) { + Item *sizeitem = p_item; + + while (sizeitem) { + if (sizeitem->type == ITEM_OUTLINE_SIZE) { + ItemOutlineSize *fi = static_cast<ItemOutlineSize *>(sizeitem); + return fi->outline_size; + } + + sizeitem = sizeitem->parent; + } + + return 0; +} + +Dictionary RichTextLabel::_find_font_features(Item *p_item) { + Item *ffitem = p_item; + + while (ffitem) { + if (ffitem->type == ITEM_FONT_FEATURES) { + ItemFontFeatures *fi = static_cast<ItemFontFeatures *>(ffitem); + return fi->opentype_features; + } + + ffitem = ffitem->parent; + } + + return Dictionary(); +} + +RichTextLabel::ItemList *RichTextLabel::_find_list_item(Item *p_item) { Item *item = p_item; - int margin = 0; + while (item) { + if (item->type == ITEM_LIST) { + return static_cast<ItemList *>(item); + } + item = item->parent; + } + + return nullptr; +} + +int RichTextLabel::_find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list) { + Item *item = p_item; + Item *prev_item = p_item; + + int level = 0; + + while (item) { + if (item->type == ITEM_LIST) { + ItemList *list = static_cast<ItemList *>(item); + + ItemFrame *frame = nullptr; + int line = -1; + _find_frame(list, &frame, &line); + + int index = 1; + if (frame != nullptr) { + for (int i = list->line + 1; i <= prev_item->line; i++) { + if (_find_list_item(frame->lines[i].from) == list) { + index++; + } + } + } + + r_index.push_back(index); + r_list.push_back(list); + + prev_item = item; + } + level++; + item = item->parent; + } + + return level; +} + +int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size) { + Item *item = p_item; + + float margin = 0; while (item) { if (item->type == ITEM_INDENT) { @@ -1348,16 +1802,22 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font) { if (font.is_null()) { font = p_base_font; } - - ItemIndent *indent = static_cast<ItemIndent *>(item); - - margin += indent->level * tab_size * font->get_char_size(' ').width; + int font_size = _find_font_size(item); + if (font_size == -1) { + font_size = p_base_font_size; + } + margin += tab_size * font->get_char_size('m', 0, font_size).width; } else if (item->type == ITEM_LIST) { Ref<Font> font = _find_font(item); if (font.is_null()) { font = p_base_font; } + int font_size = _find_font_size(item); + if (font_size == -1) { + font_size = p_base_font_size; + } + margin += tab_size * font->get_char_size('m', 0, font_size).width; } item = item->parent; @@ -1370,9 +1830,9 @@ RichTextLabel::Align RichTextLabel::_find_align(Item *p_item) { Item *item = p_item; while (item) { - if (item->type == ITEM_ALIGN) { - ItemAlign *align = static_cast<ItemAlign *>(item); - return align->align; + if (item->type == ITEM_PARAGRAPH) { + ItemParagraph *p = static_cast<ItemParagraph *>(item); + return p->align; } item = item->parent; @@ -1381,6 +1841,57 @@ RichTextLabel::Align RichTextLabel::_find_align(Item *p_item) { return default_align; } +TextServer::Direction RichTextLabel::_find_direction(Item *p_item) { + Item *item = p_item; + + while (item) { + if (item->type == ITEM_PARAGRAPH) { + ItemParagraph *p = static_cast<ItemParagraph *>(item); + if (p->direction != Control::TEXT_DIRECTION_INHERITED) { + return (TextServer::Direction)p->direction; + } + } + + item = item->parent; + } + + if (text_direction == Control::TEXT_DIRECTION_INHERITED) { + return is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR; + } else { + return (TextServer::Direction)text_direction; + } +} + +Control::StructuredTextParser RichTextLabel::_find_stt(Item *p_item) { + Item *item = p_item; + + while (item) { + if (item->type == ITEM_PARAGRAPH) { + ItemParagraph *p = static_cast<ItemParagraph *>(item); + return p->st_parser; + } + + item = item->parent; + } + + return st_parser; +} + +String RichTextLabel::_find_language(Item *p_item) { + Item *item = p_item; + + while (item) { + if (item->type == ITEM_PARAGRAPH) { + ItemParagraph *p = static_cast<ItemParagraph *>(item); + return p->language; + } + + item = item->parent; + } + + return language; +} + Color RichTextLabel::_find_color(Item *p_item, const Color &p_default_color) { Item *item = p_item; @@ -1396,25 +1907,26 @@ Color RichTextLabel::_find_color(Item *p_item, const Color &p_default_color) { return p_default_color; } -bool RichTextLabel::_find_underline(Item *p_item) { +Color RichTextLabel::_find_outline_color(Item *p_item, const Color &p_default_color) { Item *item = p_item; while (item) { - if (item->type == ITEM_UNDERLINE) { - return true; + if (item->type == ITEM_OUTLINE_COLOR) { + ItemOutlineColor *color = static_cast<ItemOutlineColor *>(item); + return color->color; } item = item->parent; } - return false; + return p_default_color; } -bool RichTextLabel::_find_strikethrough(Item *p_item) { +bool RichTextLabel::_find_underline(Item *p_item) { Item *item = p_item; while (item) { - if (item->type == ITEM_STRIKETHROUGH) { + if (item->type == ITEM_UNDERLINE) { return true; } @@ -1424,17 +1936,17 @@ bool RichTextLabel::_find_strikethrough(Item *p_item) { return false; } -bool RichTextLabel::_find_by_type(Item *p_item, ItemType p_type) { - ERR_FAIL_INDEX_V((int)p_type, 19, false); - +bool RichTextLabel::_find_strikethrough(Item *p_item) { Item *item = p_item; while (item) { - if (item->type == p_type) { + if (item->type == ITEM_STRIKETHROUGH) { return true; } + item = item->parent; } + return false; } @@ -1530,38 +2042,67 @@ bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) { void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { if (p_frame->first_invalid_line == p_frame->lines.size()) { + if (p_frame->first_resized_line == p_frame->lines.size()) { + return; + } + + // Resize lines without reshaping. + Size2 size = get_size(); + if (fixed_width != -1) { + size.width = fixed_width; + } + Rect2 text_rect = _get_text_rect(); + + Ref<Font> base_font = get_theme_font("normal_font"); + int base_font_size = get_theme_font_size("normal_font_size"); + + for (int i = p_frame->first_resized_line; i < p_frame->lines.size(); i++) { + _resize_line(p_frame, i, base_font, base_font_size, text_rect.get_size().width - scroll_w); + } + + int total_height = 0; + if (p_frame->lines.size()) { + total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y + get_theme_stylebox("normal")->get_minimum_size().height; + } + + p_frame->first_resized_line = p_frame->lines.size(); + + updating_scroll = true; + vscroll->set_max(total_height); + vscroll->set_page(size.height); + if (scroll_follow && scroll_following) { + vscroll->set_value(total_height - size.height); + } + updating_scroll = false; + + if (fit_content_height) { + minimum_size_changed(); + } return; } - //validate invalid lines + // Shape invalid lines. Size2 size = get_size(); if (fixed_width != -1) { size.width = fixed_width; } Rect2 text_rect = _get_text_rect(); - Color font_color_shadow = get_theme_color("font_color_shadow"); - bool use_outline = get_theme_constant("shadow_as_outline"); - Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); Ref<Font> base_font = get_theme_font("normal_font"); + int base_font_size = get_theme_font_size("normal_font_size"); + int total_chars = (p_frame->first_invalid_line == 0) ? 0 : (p_frame->lines[p_frame->first_invalid_line].char_offset + p_frame->lines[p_frame->first_invalid_line].char_count); for (int i = p_frame->first_invalid_line; i < p_frame->lines.size(); i++) { - int y = 0; - _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, i, PROCESS_CACHE, base_font, Color(), font_color_shadow, use_outline, shadow_ofs); - p_frame->lines.write[i].height_cache = y; - p_frame->lines.write[i].height_accum_cache = y; - - if (i > 0) { - p_frame->lines.write[i].height_accum_cache += p_frame->lines[i - 1].height_accum_cache; - } + _shape_line(p_frame, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, &total_chars); } int total_height = 0; if (p_frame->lines.size()) { - total_height = p_frame->lines[p_frame->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height; + total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y + get_theme_stylebox("normal")->get_minimum_size().height; } - main->first_invalid_line = p_frame->lines.size(); + p_frame->first_invalid_line = p_frame->lines.size(); + p_frame->first_resized_line = p_frame->lines.size(); updating_scroll = true; vscroll->set_max(total_height); @@ -1569,7 +2110,6 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { if (scroll_follow && scroll_following) { vscroll->set_value(total_height - size.height); } - updating_scroll = false; if (fit_content_height) { @@ -1641,6 +2181,13 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) p_item->parent = current; p_item->E = current->subitems.push_back(p_item); p_item->index = current_idx++; + p_item->char_ofs = current_char_ofs; + if (p_item->type == ITEM_TEXT) { + ItemText *t = (ItemText *)p_item; + current_char_ofs += t->text.length(); + } else if (p_item->type == ITEM_IMAGE) { + current_char_ofs++; + } if (p_enter) { current = p_item; @@ -1686,7 +2233,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub } } -void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color) { +void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, VAlign p_align) { if (current->type == ITEM_TABLE) { return; } @@ -1696,6 +2243,7 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, item->image = p_image; item->color = p_color; + item->inline_align = p_align; if (p_width > 0) { // custom width @@ -1764,7 +2312,7 @@ bool RichTextLabel::remove_line(const int p_line) { main->lines.write[0].from = main; } - main->first_invalid_line = 0; + main->first_invalid_line = 0; // p_line ??? return true; } @@ -1813,6 +2361,30 @@ void RichTextLabel::push_mono() { push_font(mono_font); } +void RichTextLabel::push_font_size(int p_font_size) { + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemFontSize *item = memnew(ItemFontSize); + + item->font_size = p_font_size; + _add_item(item, true); +} + +void RichTextLabel::push_font_features(const Dictionary &p_features) { + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemFontFeatures *item = memnew(ItemFontFeatures); + + item->opentype_features = p_features; + _add_item(item, true); +} + +void RichTextLabel::push_outline_size(int p_font_size) { + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemOutlineSize *item = memnew(ItemOutlineSize); + + item->outline_size = p_font_size; + _add_item(item, true); +} + void RichTextLabel::push_color(const Color &p_color) { ERR_FAIL_COND(current->type == ITEM_TABLE); ItemColor *item = memnew(ItemColor); @@ -1821,6 +2393,14 @@ void RichTextLabel::push_color(const Color &p_color) { _add_item(item, true); } +void RichTextLabel::push_outline_color(const Color &p_color) { + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemOutlineColor *item = memnew(ItemOutlineColor); + + item->color = p_color; + _add_item(item, true); +} + void RichTextLabel::push_underline() { ERR_FAIL_COND(current->type == ITEM_TABLE); ItemUnderline *item = memnew(ItemUnderline); @@ -1835,11 +2415,14 @@ void RichTextLabel::push_strikethrough() { _add_item(item, true); } -void RichTextLabel::push_align(Align p_align) { +void RichTextLabel::push_paragraph(Align p_align, Control::TextDirection p_direction, const String &p_language, Control::StructuredTextParser p_st_parser) { ERR_FAIL_COND(current->type == ITEM_TABLE); - ItemAlign *item = memnew(ItemAlign); + ItemParagraph *item = memnew(ItemParagraph); item->align = p_align; + item->direction = p_direction; + item->language = p_language; + item->st_parser = p_st_parser; _add_item(item, true, true); } @@ -1852,13 +2435,15 @@ void RichTextLabel::push_indent(int p_level) { _add_item(item, true, true); } -void RichTextLabel::push_list(ListType p_list) { +void RichTextLabel::push_list(int p_level, ListType p_list, bool p_capitalize) { ERR_FAIL_COND(current->type == ITEM_TABLE); - ERR_FAIL_INDEX(p_list, 3); + ERR_FAIL_COND(p_level < 0); ItemList *item = memnew(ItemList); item->list_type = p_list; + item->level = p_level; + item->capitalize = p_capitalize; _add_item(item, true, true); } @@ -1870,17 +2455,18 @@ void RichTextLabel::push_meta(const Variant &p_meta) { _add_item(item, true); } -void RichTextLabel::push_table(int p_columns) { +void RichTextLabel::push_table(int p_columns, VAlign p_align) { ERR_FAIL_COND(p_columns < 1); ItemTable *item = memnew(ItemTable); item->columns.resize(p_columns); item->total_width = 0; + item->inline_align = p_align; for (int i = 0; i < item->columns.size(); i++) { item->columns.write[i].expand = false; item->columns.write[i].expand_ratio = 1; } - _add_item(item, true, true); + _add_item(item, true, false); } void RichTextLabel::push_fade(int p_start_index, int p_length) { @@ -1934,6 +2520,36 @@ void RichTextLabel::set_table_column_expand(int p_column, bool p_expand, int p_r table->columns.write[p_column].expand_ratio = p_ratio; } +void RichTextLabel::set_cell_row_background_color(const Color &p_odd_row_bg, const Color &p_even_row_bg) { + ERR_FAIL_COND(current->type != ITEM_FRAME); + ItemFrame *cell = static_cast<ItemFrame *>(current); + ERR_FAIL_COND(!cell->cell); + cell->odd_row_bg = p_odd_row_bg; + cell->even_row_bg = p_even_row_bg; +} + +void RichTextLabel::set_cell_border_color(const Color &p_color) { + ERR_FAIL_COND(current->type != ITEM_FRAME); + ItemFrame *cell = static_cast<ItemFrame *>(current); + ERR_FAIL_COND(!cell->cell); + cell->border = p_color; +} + +void RichTextLabel::set_cell_size_override(const Size2 &p_min_size, const Size2 &p_max_size) { + ERR_FAIL_COND(current->type != ITEM_FRAME); + ItemFrame *cell = static_cast<ItemFrame *>(current); + ERR_FAIL_COND(!cell->cell); + cell->min_size_over = p_min_size; + cell->max_size_over = p_max_size; +} + +void RichTextLabel::set_cell_padding(const Rect2 &p_padding) { + ERR_FAIL_COND(current->type != ITEM_FRAME); + ItemFrame *cell = static_cast<ItemFrame *>(current); + ERR_FAIL_COND(!cell->cell); + cell->padding = p_padding; +} + void RichTextLabel::push_cell() { ERR_FAIL_COND(current->type != ITEM_TABLE); @@ -1942,10 +2558,9 @@ void RichTextLabel::push_cell() { _add_item(item, true); current_frame = item; item->cell = true; - item->parent_line = item->parent_frame->lines.size() - 1; item->lines.resize(1); item->lines.write[0].from = nullptr; - item->first_invalid_line = 0; + item->first_invalid_line = 0; // parent frame last line ??? } int RichTextLabel::get_current_table_column() const { @@ -1972,9 +2587,13 @@ void RichTextLabel::clear() { main->lines.resize(1); main->first_invalid_line = 0; update(); - selection.click = nullptr; + + selection.click_frame = nullptr; + selection.click_item = nullptr; selection.active = false; + current_idx = 1; + current_char_ofs = 0; if (scroll_follow) { scroll_following = true; } @@ -1986,7 +2605,7 @@ void RichTextLabel::clear() { void RichTextLabel::set_tab_size(int p_spaces) { tab_size = p_spaces; - main->first_invalid_line = 0; + main->first_resized_line = 0; update(); } @@ -2135,7 +2754,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { if (tag_stack.front()->get() == "i") { in_italics = false; } - if (tag_stack.front()->get() == "indent") { + if ((tag_stack.front()->get() == "indent") || (tag_stack.front()->get() == "ol") || (tag_stack.front()->get() == "ul")) { indent_level--; } @@ -2177,12 +2796,24 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag.begins_with("table=")) { - int columns = tag.substr(6, tag.length()).to_int(); + Vector<String> subtag = tag.substr(6, tag.length()).split(","); + int columns = subtag[0].to_int(); if (columns < 1) { columns = 1; } - push_table(columns); + VAlign align = VALIGN_TOP; + if (subtag.size() > 1) { + if (subtag[1] == "top" || subtag[1] == "t") { + align = VALIGN_TOP; + } else if (subtag[1] == "center" || subtag[1] == "c") { + align = VALIGN_CENTER; + } else if (subtag[1] == "bottom" || subtag[1] == "b") { + align = VALIGN_BOTTOM; + } + } + + push_table(columns, align); pos = brk_end + 1; tag_stack.push_front("table"); } else if (tag == "cell") { @@ -2197,6 +2828,42 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { set_table_column_expand(get_current_table_column(), true, ratio); push_cell(); + + pos = brk_end + 1; + tag_stack.push_front("cell"); + } else if (tag.begins_with("cell ")) { + Vector<String> subtag = tag.substr(5, tag.length()).split(" "); + + for (int i = 0; i < subtag.size(); i++) { + Vector<String> subtag_a = subtag[i].split("="); + if (subtag_a.size() == 2) { + if (subtag_a[0] == "expand") { + int ratio = subtag_a[1].to_int(); + if (ratio < 1) { + ratio = 1; + } + set_table_column_expand(get_current_table_column(), true, ratio); + } + } + } + push_cell(); + for (int i = 0; i < subtag.size(); i++) { + Vector<String> subtag_a = subtag[i].split("="); + if (subtag_a.size() == 2) { + if (subtag_a[0] == "border") { + Color color = _get_color_from_string(subtag_a[1], Color(0, 0, 0, 0)); + set_cell_border_color(color); + } else if (subtag_a[0] == "bg") { + Vector<String> subtag_b = subtag_a[1].split(","); + if (subtag_b.size() == 2) { + Color color1 = _get_color_from_string(subtag_b[0], Color(0, 0, 0, 0)); + Color color2 = _get_color_from_string(subtag_b[1], Color(0, 0, 0, 0)); + set_cell_row_background_color(color1, color2); + } + } + } + } + pos = brk_end + 1; tag_stack.push_front("cell"); } else if (tag == "u") { @@ -2209,32 +2876,156 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { push_strikethrough(); pos = brk_end + 1; tag_stack.push_front(tag); + } else if (tag == "lrm") { + add_text(String::chr(0x200E)); + pos = brk_end + 1; + } else if (tag == "rlm") { + add_text(String::chr(0x200F)); + pos = brk_end + 1; + } else if (tag == "lre") { + add_text(String::chr(0x202A)); + pos = brk_end + 1; + } else if (tag == "rle") { + add_text(String::chr(0x202B)); + pos = brk_end + 1; + } else if (tag == "lro") { + add_text(String::chr(0x202D)); + pos = brk_end + 1; + } else if (tag == "rlo") { + add_text(String::chr(0x202E)); + pos = brk_end + 1; + } else if (tag == "pdf") { + add_text(String::chr(0x202C)); + pos = brk_end + 1; + } else if (tag == "alm") { + add_text(String::chr(0x061c)); + pos = brk_end + 1; + } else if (tag == "lri") { + add_text(String::chr(0x2066)); + pos = brk_end + 1; + } else if (tag == "rli") { + add_text(String::chr(0x2027)); + pos = brk_end + 1; + } else if (tag == "fsi") { + add_text(String::chr(0x2068)); + pos = brk_end + 1; + } else if (tag == "pdi") { + add_text(String::chr(0x2069)); + pos = brk_end + 1; + } else if (tag == "zwj") { + add_text(String::chr(0x200D)); + pos = brk_end + 1; + } else if (tag == "zwnj") { + add_text(String::chr(0x200C)); + pos = brk_end + 1; + } else if (tag == "wj") { + add_text(String::chr(0x2060)); + pos = brk_end + 1; + } else if (tag == "shy") { + add_text(String::chr(0x00AD)); + pos = brk_end + 1; } else if (tag == "center") { - push_align(ALIGN_CENTER); + push_paragraph(ALIGN_CENTER); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "fill") { - push_align(ALIGN_FILL); + push_paragraph(ALIGN_FILL); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "right") { - push_align(ALIGN_RIGHT); + push_paragraph(ALIGN_RIGHT); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "ul") { - push_list(LIST_DOTS); + indent_level++; + push_list(indent_level, LIST_DOTS, false); pos = brk_end + 1; tag_stack.push_front(tag); - } else if (tag == "ol") { - push_list(LIST_NUMBERS); + } else if ((tag == "ol") || (tag == "ol type=1")) { + indent_level++; + push_list(indent_level, LIST_NUMBERS, false); pos = brk_end + 1; tag_stack.push_front(tag); + } else if (tag == "ol type=a") { + indent_level++; + push_list(indent_level, LIST_LETTERS, false); + pos = brk_end + 1; + tag_stack.push_front("ol"); + } else if (tag == "ol type=A") { + indent_level++; + push_list(indent_level, LIST_LETTERS, true); + pos = brk_end + 1; + tag_stack.push_front("ol"); + } else if (tag == "ol type=i") { + indent_level++; + push_list(indent_level, LIST_ROMAN, false); + pos = brk_end + 1; + tag_stack.push_front("ol"); + } else if (tag == "ol type=I") { + indent_level++; + push_list(indent_level, LIST_ROMAN, true); + pos = brk_end + 1; + tag_stack.push_front("ol"); } else if (tag == "indent") { indent_level++; push_indent(indent_level); pos = brk_end + 1; tag_stack.push_front(tag); - + } else if (tag == "p") { + push_paragraph(ALIGN_LEFT); + pos = brk_end + 1; + tag_stack.push_front("p"); + } else if (tag.begins_with("p ")) { + Vector<String> subtag = tag.substr(2, tag.length()).split(" "); + Align align = ALIGN_LEFT; + Control::TextDirection dir = Control::TEXT_DIRECTION_INHERITED; + String lang; + Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT; + for (int i = 0; i < subtag.size(); i++) { + Vector<String> subtag_a = subtag[i].split("="); + if (subtag_a.size() == 2) { + if (subtag_a[0] == "align") { + if (subtag_a[1] == "l" || subtag_a[1] == "left") { + align = ALIGN_LEFT; + } else if (subtag_a[1] == "c" || subtag_a[1] == "center") { + align = ALIGN_CENTER; + } else if (subtag_a[1] == "r" || subtag_a[1] == "right") { + align = ALIGN_RIGHT; + } else if (subtag_a[1] == "f" || subtag_a[1] == "fill") { + align = ALIGN_FILL; + } + } else if (subtag_a[0] == "dir" || subtag_a[0] == "direction") { + if (subtag_a[1] == "a" || subtag_a[1] == "auto") { + dir = Control::TEXT_DIRECTION_AUTO; + } else if (subtag_a[1] == "l" || subtag_a[1] == "ltr") { + dir = Control::TEXT_DIRECTION_LTR; + } else if (subtag_a[1] == "r" || subtag_a[1] == "rtl") { + dir = Control::TEXT_DIRECTION_RTL; + } + } else if (subtag_a[0] == "lang" || subtag_a[0] == "language") { + lang = subtag_a[1]; + } else if (subtag_a[0] == "st" || subtag_a[0] == "bidi_override") { + if (subtag_a[1] == "d" || subtag_a[1] == "default") { + st_parser = STRUCTURED_TEXT_DEFAULT; + } else if (subtag_a[1] == "u" || subtag_a[1] == "uri") { + st_parser = STRUCTURED_TEXT_URI; + } else if (subtag_a[1] == "f" || subtag_a[1] == "file") { + st_parser = STRUCTURED_TEXT_FILE; + } else if (subtag_a[1] == "e" || subtag_a[1] == "email") { + st_parser = STRUCTURED_TEXT_EMAIL; + } else if (subtag_a[1] == "l" || subtag_a[1] == "list") { + st_parser = STRUCTURED_TEXT_LIST; + } else if (subtag_a[1] == "n" || subtag_a[1] == "none") { + st_parser = STRUCTURED_TEXT_NONE; + } else if (subtag_a[1] == "c" || subtag_a[1] == "custom") { + st_parser = STRUCTURED_TEXT_CUSTOM; + } + } + } + } + push_paragraph(align, dir, lang, st_parser); + pos = brk_end + 1; + tag_stack.push_front("p"); } else if (tag == "url") { int end = p_bbcode.find("[", brk_end); if (end == -1) { @@ -2251,7 +3042,19 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { push_meta(url); pos = brk_end + 1; tag_stack.push_front("url"); - } else if (bbcode_name == "img") { + } else if (tag.begins_with("img")) { + VAlign align = VALIGN_TOP; + if (tag.begins_with("img=")) { + String al = tag.substr(4, tag.length()); + if (al == "top" || al == "t") { + align = VALIGN_TOP; + } else if (al == "center" || al == "c") { + align = VALIGN_CENTER; + } else if (al == "bottom" || al == "b") { + align = VALIGN_BOTTOM; + } + } + int end = p_bbcode.find("[", brk_end); if (end == -1) { end = p_bbcode.length(); @@ -2289,7 +3092,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { } } - add_image(texture, width, height, color); + add_image(texture, width, height, color, align); } pos = end; @@ -2301,6 +3104,13 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { pos = brk_end + 1; tag_stack.push_front("color"); + } else if (tag.begins_with("outline_color=")) { + String color_str = tag.substr(14, tag.length()); + Color color = _get_color_from_string(color_str, base_color); + push_outline_color(color); + pos = brk_end + 1; + tag_stack.push_front("outline_color"); + } else if (tag.begins_with("font=")) { String fnt = tag.substr(5, tag.length()); @@ -2313,6 +3123,54 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { pos = brk_end + 1; tag_stack.push_front("font"); + } else if (tag.begins_with("font_size=")) { + int fnt_size = tag.substr(10, tag.length()).to_int(); + push_font_size(fnt_size); + pos = brk_end + 1; + tag_stack.push_front("font_size"); + } else if (tag.begins_with("opentype_features=")) { + String fnt_ftr = tag.substr(18, tag.length()); + Vector<String> subtag = fnt_ftr.split(","); + Dictionary ftrs; + for (int i = 0; i < subtag.size(); i++) { + Vector<String> subtag_a = subtag[i].split("="); + if (subtag_a.size() == 2) { + ftrs[TS->name_to_tag(subtag_a[0])] = subtag_a[1].to_int(); + } else if (subtag_a.size() == 1) { + ftrs[TS->name_to_tag(subtag_a[0])] = 1; + } + } + push_font_features(ftrs); + pos = brk_end + 1; + tag_stack.push_front("opentype_features"); + } else if (tag.begins_with("font ")) { + Vector<String> subtag = tag.substr(2, tag.length()).split(" "); + + for (int i = 1; i < subtag.size(); i++) { + Vector<String> subtag_a = subtag[i].split("=", true, 2); + if (subtag_a.size() == 2) { + if (subtag_a[0] == "name" || subtag_a[0] == "n") { + String fnt = subtag_a[1]; + Ref<Font> font = ResourceLoader::load(fnt, "Font"); + if (font.is_valid()) { + push_font(font); + } else { + push_font(normal_font); + } + } else if (subtag_a[0] == "size" || subtag_a[0] == "s") { + int fnt_size = subtag_a[1].to_int(); + push_font_size(fnt_size); + } + } + } + + pos = brk_end + 1; + tag_stack.push_front("font"); + } else if (tag.begins_with("outline_size=")) { + int fnt_size = tag.substr(13, tag.length()).to_int(); + push_outline_size(fnt_size); + pos = brk_end + 1; + tag_stack.push_front("outline_size"); } else if (bbcode_name == "fade") { int start_index = 0; @@ -2445,7 +3303,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { void RichTextLabel::scroll_to_line(int p_line) { ERR_FAIL_INDEX(p_line, main->lines.size()); _validate_line_caches(main); - vscroll->set_value(main->lines[p_line].height_accum_cache - main->lines[p_line].height_cache); + vscroll->set_value(main->lines[p_line].offset.y); } int RichTextLabel::get_line_count() const { @@ -2472,95 +3330,160 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) { } } -bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) { - ERR_FAIL_COND_V(!selection.enabled, false); - Item *it = main; - int charidx = 0; - - if (p_from_selection && selection.active) { - it = selection.to; - charidx = selection.to_char + 1; - } - - while (it) { - if (it->type == ITEM_TEXT) { - ItemText *t = static_cast<ItemText *>(it); - int sp = t->text.findn(p_string, charidx); - if (sp != -1) { - selection.from = it; - selection.from_char = sp; - selection.to = it; - selection.to_char = sp + p_string.length() - 1; - selection.active = true; - update(); - - _validate_line_caches(main); +bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to) { + ERR_FAIL_COND_V(p_frame == nullptr, false); + ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), false); - int fh = _find_font(t).is_valid() ? _find_font(t)->get_height() : get_theme_font("normal_font")->get_height(); + Line &l = p_frame->lines.write[p_line]; - float offset = 0; + String text; + Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr; + for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) { + switch (it->type) { + case ITEM_NEWLINE: { + text += "\n"; + } break; + case ITEM_TEXT: { + ItemText *t = (ItemText *)it; + text += t->text; + } break; + case ITEM_IMAGE: { + text += " "; + } break; + case ITEM_TABLE: { + ItemTable *table = static_cast<ItemTable *>(it); + int idx = 0; + for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { + ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. + ItemFrame *frame = static_cast<ItemFrame *>(E->get()); - int line = t->line; - Item *item = t; - while (item) { - if (item->type == ITEM_FRAME) { - ItemFrame *frame = static_cast<ItemFrame *>(item); - if (line >= 0 && line < frame->lines.size()) { - offset += frame->lines[line].height_accum_cache - frame->lines[line].height_cache; - line = frame->line; + for (int i = 0; i < frame->lines.size(); i++) { + if (_search_line(frame, i, p_string, p_from, p_to)) { + return true; } } - item = item->parent; + idx++; } - vscroll->set_value(offset - fh); + } break; + default: + break; + } + } + int sp = text.findn(p_string, 0); + if (sp != -1) { + selection.from_frame = p_frame; + selection.from_line = p_line; + selection.from_item = _get_item_at_pos(l.from, it_to, sp); + selection.from_char = sp; + selection.to_frame = p_frame; + selection.to_line = p_line; + selection.to_item = _get_item_at_pos(l.from, it_to, sp + p_string.length() - 1); + selection.to_char = sp + p_string.length() - 1; + selection.active = true; + return true; + } + + return false; +} +bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) { + ERR_FAIL_COND_V(!selection.enabled, false); + + if (p_from_selection && selection.active) { + for (int i = 0; i < main->lines.size(); i++) { + if (_search_line(main, i, p_string, selection.from_item, selection.to_item)) { + update(); return true; } } - - if (p_search_previous) { - it = _get_prev_item(it, true); - } else { - it = _get_next_item(it, true); + } else { + for (int i = 0; i < main->lines.size(); i++) { + if (_search_line(main, i, p_string, nullptr, nullptr)) { + update(); + return true; + } } - charidx = 0; } return false; } -String RichTextLabel::get_selected_text() { - if (!selection.active || !selection.enabled) { - return ""; - } - +String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) { String text; + ERR_FAIL_COND_V(p_frame == nullptr, text); + ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), text); - RichTextLabel::Item *item = selection.from; - - while (item) { - if (item->type == ITEM_TEXT) { - String itext = static_cast<ItemText *>(item)->text; - if (item == selection.from && item == selection.to) { - text += itext.substr(selection.from_char, selection.to_char - selection.from_char + 1); - } else if (item == selection.from) { - text += itext.substr(selection.from_char, itext.size()); - } else if (item == selection.to) { - text += itext.substr(0, selection.to_char + 1); - } else { - text += itext; - } + Line &l = p_frame->lines.write[p_line]; - } else if (item->type == ITEM_NEWLINE) { - text += "\n"; + Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr; + int end_idx = 0; + if (it_to != nullptr) { + end_idx = it_to->index; + } else { + for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) { + end_idx = it->index + 1; + } + } + for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) { + if ((p_selection.to_item != nullptr) && (p_selection.to_item->index < l.from->index)) { + break; } - if (item == selection.to) { + if ((p_selection.from_item != nullptr) && (p_selection.from_item->index >= end_idx)) { break; } + switch (it->type) { + case ITEM_NEWLINE: { + text += "\n"; + } break; + case ITEM_TEXT: { + ItemText *t = (ItemText *)it; + text += t->text; + } break; + case ITEM_IMAGE: { + text += " "; + } break; + case ITEM_TABLE: { + ItemTable *table = static_cast<ItemTable *>(it); + int idx = 0; + int col_count = table->columns.size(); + for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { + ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. + ItemFrame *frame = static_cast<ItemFrame *>(E->get()); + int column = idx % col_count; + + for (int i = 0; i < frame->lines.size(); i++) { + text += _get_line_text(frame, i, p_selection); + } + if (column == col_count - 1) { + text += "\n"; + } else { + text += " "; + } + idx++; + } + } break; + default: + break; + } + } + if ((l.from != nullptr) && (p_frame == p_selection.to_frame) && (p_selection.to_item != nullptr) && (p_selection.to_item->index >= l.from->index) && (p_selection.to_item->index < end_idx)) { + text = text.substr(0, p_selection.to_char); + } + if ((l.from != nullptr) && (p_frame == p_selection.from_frame) && (p_selection.from_item != nullptr) && (p_selection.from_item->index >= l.from->index) && (p_selection.from_item->index < end_idx)) { + text = text.substr(p_selection.from_char, -1); + } + return text; +} - item = _get_next_item(item, true); +String RichTextLabel::get_selected_text() { + if (!selection.active || !selection.enabled) { + return ""; } + String text; + for (int i = 0; i < main->lines.size(); i++) { + text += _get_line_text(main, i, selection); + } return text; } @@ -2611,7 +3534,7 @@ String RichTextLabel::get_text() { text += t->text; } else if (it->type == ITEM_NEWLINE) { text += "\n"; - } else if (it->type == ITEM_INDENT) { + } else if (it->type == ITEM_INDENT || it->type == ITEM_LIST) { text += "\t"; } it = _get_next_item(it, true); @@ -2624,18 +3547,73 @@ void RichTextLabel::set_text(const String &p_string) { add_text(p_string); } -void RichTextLabel::set_percent_visible(float p_percent) { - if (p_percent < 0 || p_percent >= 1) { - visible_characters = -1; - percent_visible = 1; +void RichTextLabel::set_text_direction(Control::TextDirection p_text_direction) { + ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); + if (text_direction != p_text_direction) { + text_direction = p_text_direction; + main->first_invalid_line = 0; //invalidate ALL + _validate_line_caches(main); + update(); + } +} - } else { - visible_characters = get_total_character_count() * p_percent; - percent_visible = p_percent; +void RichTextLabel::set_structured_text_bidi_override(Control::StructuredTextParser p_parser) { + if (st_parser != p_parser) { + st_parser = p_parser; + main->first_invalid_line = 0; //invalidate ALL + _validate_line_caches(main); + update(); } +} + +Control::StructuredTextParser RichTextLabel::get_structured_text_bidi_override() const { + return st_parser; +} + +void RichTextLabel::set_structured_text_bidi_override_options(Array p_args) { + st_args = p_args; + main->first_invalid_line = 0; //invalidate ALL + _validate_line_caches(main); update(); } +Array RichTextLabel::get_structured_text_bidi_override_options() const { + return st_args; +} + +Control::TextDirection RichTextLabel::get_text_direction() const { + return text_direction; +} + +void RichTextLabel::set_language(const String &p_language) { + if (language != p_language) { + language = p_language; + main->first_invalid_line = 0; //invalidate ALL + _validate_line_caches(main); + update(); + } +} + +String RichTextLabel::get_language() const { + return language; +} + +void RichTextLabel::set_percent_visible(float p_percent) { + if (percent_visible != p_percent) { + if (p_percent < 0 || p_percent >= 1) { + visible_characters = -1; + percent_visible = 1; + + } else { + visible_characters = get_total_character_count() * p_percent; + percent_visible = p_percent; + } + main->first_invalid_line = 0; //invalidate ALL + _validate_line_caches(main); + update(); + } +} + float RichTextLabel::get_percent_visible() const { return percent_visible; } @@ -2671,7 +3649,7 @@ void RichTextLabel::install_effect(const Variant effect) { int RichTextLabel::get_content_height() const { int total_height = 0; if (main->lines.size()) { - total_height = main->lines[main->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height; + total_height = main->lines[main->lines.size() - 1].offset.y + main->lines[main->lines.size() - 1].text_buf->get_size().y + get_theme_stylebox("normal")->get_minimum_size().height; } return total_height; } @@ -2681,29 +3659,46 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text); ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text); ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text); - ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0))); + ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(VALIGN_TOP)); ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline); ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line); ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font); + ClassDB::bind_method(D_METHOD("push_font_size", "font_size"), &RichTextLabel::push_font_size); + ClassDB::bind_method(D_METHOD("push_font_features", "opentype_features"), &RichTextLabel::push_font_features); ClassDB::bind_method(D_METHOD("push_normal"), &RichTextLabel::push_normal); ClassDB::bind_method(D_METHOD("push_bold"), &RichTextLabel::push_bold); ClassDB::bind_method(D_METHOD("push_bold_italics"), &RichTextLabel::push_bold_italics); ClassDB::bind_method(D_METHOD("push_italics"), &RichTextLabel::push_italics); ClassDB::bind_method(D_METHOD("push_mono"), &RichTextLabel::push_mono); ClassDB::bind_method(D_METHOD("push_color", "color"), &RichTextLabel::push_color); - ClassDB::bind_method(D_METHOD("push_align", "align"), &RichTextLabel::push_align); + ClassDB::bind_method(D_METHOD("push_outline_size", "outline_size"), &RichTextLabel::push_outline_size); + ClassDB::bind_method(D_METHOD("push_outline_color", "color"), &RichTextLabel::push_outline_color); + ClassDB::bind_method(D_METHOD("push_paragraph", "align", "base_direction", "language", "st_parser"), &RichTextLabel::push_paragraph, DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(""), DEFVAL(STRUCTURED_TEXT_DEFAULT)); ClassDB::bind_method(D_METHOD("push_indent", "level"), &RichTextLabel::push_indent); - ClassDB::bind_method(D_METHOD("push_list", "type"), &RichTextLabel::push_list); + ClassDB::bind_method(D_METHOD("push_list", "level", "type", "capitalize"), &RichTextLabel::push_list); ClassDB::bind_method(D_METHOD("push_meta", "data"), &RichTextLabel::push_meta); ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline); ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough); - ClassDB::bind_method(D_METHOD("push_table", "columns"), &RichTextLabel::push_table); + ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(VALIGN_TOP)); ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand); + ClassDB::bind_method(D_METHOD("set_cell_row_background_color", "odd_row_bg", "even_row_bg"), &RichTextLabel::set_cell_row_background_color); + ClassDB::bind_method(D_METHOD("set_cell_border_color", "color"), &RichTextLabel::set_cell_border_color); + ClassDB::bind_method(D_METHOD("set_cell_size_override", "min_size", "max_size"), &RichTextLabel::set_cell_size_override); + ClassDB::bind_method(D_METHOD("set_cell_padding", "padding"), &RichTextLabel::set_cell_padding); ClassDB::bind_method(D_METHOD("push_cell"), &RichTextLabel::push_cell); ClassDB::bind_method(D_METHOD("pop"), &RichTextLabel::pop); ClassDB::bind_method(D_METHOD("clear"), &RichTextLabel::clear); + ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override", "parser"), &RichTextLabel::set_structured_text_bidi_override); + ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override"), &RichTextLabel::get_structured_text_bidi_override); + ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override_options", "args"), &RichTextLabel::set_structured_text_bidi_override_options); + ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override_options"), &RichTextLabel::get_structured_text_bidi_override_options); + ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &RichTextLabel::set_text_direction); + ClassDB::bind_method(D_METHOD("get_text_direction"), &RichTextLabel::get_text_direction); + ClassDB::bind_method(D_METHOD("set_language", "language"), &RichTextLabel::set_language); + ClassDB::bind_method(D_METHOD("get_language"), &RichTextLabel::get_language); + ClassDB::bind_method(D_METHOD("set_meta_underline", "enable"), &RichTextLabel::set_meta_underline); ClassDB::bind_method(D_METHOD("is_meta_underlined"), &RichTextLabel::is_meta_underlined); @@ -2778,6 +3773,13 @@ void RichTextLabel::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, "RichTextEffect", (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); + + ADD_GROUP("Structured Text", "structured_text_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options"); + ADD_SIGNAL(MethodInfo("meta_clicked", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); ADD_SIGNAL(MethodInfo("meta_hover_started", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); ADD_SIGNAL(MethodInfo("meta_hover_ended", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); @@ -2789,6 +3791,7 @@ void RichTextLabel::_bind_methods() { BIND_ENUM_CONSTANT(LIST_NUMBERS); BIND_ENUM_CONSTANT(LIST_LETTERS); + BIND_ENUM_CONSTANT(LIST_ROMAN); BIND_ENUM_CONSTANT(LIST_DOTS); BIND_ENUM_CONSTANT(ITEM_FRAME); @@ -2796,10 +3799,14 @@ void RichTextLabel::_bind_methods() { BIND_ENUM_CONSTANT(ITEM_IMAGE); BIND_ENUM_CONSTANT(ITEM_NEWLINE); BIND_ENUM_CONSTANT(ITEM_FONT); + BIND_ENUM_CONSTANT(ITEM_FONT_SIZE); + BIND_ENUM_CONSTANT(ITEM_FONT_FEATURES); BIND_ENUM_CONSTANT(ITEM_COLOR); + BIND_ENUM_CONSTANT(ITEM_OUTLINE_SIZE); + BIND_ENUM_CONSTANT(ITEM_OUTLINE_COLOR); BIND_ENUM_CONSTANT(ITEM_UNDERLINE); BIND_ENUM_CONSTANT(ITEM_STRIKETHROUGH); - BIND_ENUM_CONSTANT(ITEM_ALIGN); + BIND_ENUM_CONSTANT(ITEM_PARAGRAPH); BIND_ENUM_CONSTANT(ITEM_INDENT); BIND_ENUM_CONSTANT(ITEM_LIST); BIND_ENUM_CONSTANT(ITEM_TABLE); @@ -2929,6 +3936,7 @@ RichTextLabel::RichTextLabel() { main->lines.resize(1); main->lines.write[0].from = main; main->first_invalid_line = 0; + main->first_resized_line = 0; current_frame = main; tab_size = 4; default_align = ALIGN_LEFT; @@ -2954,10 +3962,10 @@ RichTextLabel::RichTextLabel() { vscroll->connect("value_changed", callable_mp(this, &RichTextLabel::_scroll_changed)); vscroll->set_step(1); vscroll->hide(); - current_idx = 1; use_bbcode = false; - selection.click = nullptr; + selection.click_frame = nullptr; + selection.click_item = nullptr; selection.active = false; selection.enabled = false; diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 67a3f466a6..93e48dd449 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -33,6 +33,7 @@ #include "rich_text_effect.h" #include "scene/gui/scroll_bar.h" +#include "scene/resources/text_paragraph.h" class RichTextLabel : public Control { GDCLASS(RichTextLabel, Control); @@ -48,6 +49,7 @@ public: enum ListType { LIST_NUMBERS, LIST_LETTERS, + LIST_ROMAN, LIST_DOTS }; @@ -57,10 +59,14 @@ public: ITEM_IMAGE, ITEM_NEWLINE, ITEM_FONT, + ITEM_FONT_SIZE, + ITEM_FONT_FEATURES, ITEM_COLOR, + ITEM_OUTLINE_SIZE, + ITEM_OUTLINE_COLOR, ITEM_UNDERLINE, ITEM_STRIKETHROUGH, - ITEM_ALIGN, + ITEM_PARAGRAPH, ITEM_INDENT, ITEM_LIST, ITEM_TABLE, @@ -80,31 +86,25 @@ private: struct Item; struct Line { - Item *from; - Vector<int> offset_caches; - Vector<int> height_caches; - Vector<int> ascent_caches; - Vector<int> descent_caches; - Vector<int> space_caches; - int height_cache; - int height_accum_cache; - int char_count; - int minimum_width; - int maximum_width; - - Line() { - from = nullptr; - char_count = 0; - } + Item *from = nullptr; + + Ref<TextParagraph> text_buf; + + Vector2 offset; + int char_offset = 0; + int char_count = 0; + + Line() { text_buf.instance(); } }; struct Item { - int index; - Item *parent; - ItemType type; + int index = 0; + int char_ofs = 0; + Item *parent = nullptr; + ItemType type = ITEM_FRAME; List<Item *> subitems; - List<Item *>::Element *E; - int line; + List<Item *>::Element *E = nullptr; + int line = 0; void _clear_children() { while (subitems.size()) { @@ -113,29 +113,26 @@ private: } } - Item() { - parent = nullptr; - E = nullptr; - line = 0; - index = 0; - type = ITEM_FRAME; - } virtual ~Item() { _clear_children(); } }; struct ItemFrame : public Item { - int parent_line; - bool cell; + bool cell = false; + Vector<Line> lines; - int first_invalid_line; - ItemFrame *parent_frame; - - ItemFrame() { - type = ITEM_FRAME; - parent_frame = nullptr; - cell = false; - parent_line = 0; - } + int first_invalid_line = 0; + int first_resized_line = 0; + + ItemFrame *parent_frame = nullptr; + + Color odd_row_bg = Color(0, 0, 0, 0); + Color even_row_bg = Color(0, 0, 0, 0); + Color border = Color(0, 0, 0, 0); + Size2 min_size_over = Size2(-1, -1); + Size2 max_size_over = Size2(-1, -1); + Rect2 padding; + + ItemFrame() { type = ITEM_FRAME; } }; struct ItemText : public Item { @@ -145,6 +142,7 @@ private: struct ItemImage : public Item { Ref<Texture2D> image; + VAlign inline_align = VALIGN_TOP; Size2 size; Color color; ItemImage() { type = ITEM_IMAGE; } @@ -155,11 +153,31 @@ private: ItemFont() { type = ITEM_FONT; } }; + struct ItemFontSize : public Item { + int font_size = 16; + ItemFontSize() { type = ITEM_FONT_SIZE; } + }; + + struct ItemFontFeatures : public Item { + Dictionary opentype_features; + ItemFontFeatures() { type = ITEM_FONT_FEATURES; } + }; + struct ItemColor : public Item { Color color; ItemColor() { type = ITEM_COLOR; } }; + struct ItemOutlineSize : public Item { + int outline_size = 0; + ItemOutlineSize() { type = ITEM_OUTLINE_SIZE; } + }; + + struct ItemOutlineColor : public Item { + Color color; + ItemOutlineColor() { type = ITEM_OUTLINE_COLOR; } + }; + struct ItemUnderline : public Item { ItemUnderline() { type = ITEM_UNDERLINE; } }; @@ -173,18 +191,23 @@ private: ItemMeta() { type = ITEM_META; } }; - struct ItemAlign : public Item { - Align align; - ItemAlign() { type = ITEM_ALIGN; } + struct ItemParagraph : public Item { + Align align = ALIGN_LEFT; + String language; + Control::TextDirection direction = Control::TEXT_DIRECTION_AUTO; + Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT; + ItemParagraph() { type = ITEM_PARAGRAPH; } }; struct ItemIndent : public Item { - int level; + int level = 0; ItemIndent() { type = ITEM_INDENT; } }; struct ItemList : public Item { - ListType list_type; + ListType list_type = LIST_DOTS; + bool capitalize = false; + int level = 0; ItemList() { type = ITEM_LIST; } }; @@ -202,37 +225,32 @@ private: }; Vector<Column> columns; - int total_width; + Vector<float> rows; + + int total_width = 0; + int total_height = 0; + VAlign inline_align = VALIGN_TOP; ItemTable() { type = ITEM_TABLE; } }; struct ItemFade : public Item { - int starting_index; - int length; + int starting_index = 0; + int length = 0; ItemFade() { type = ITEM_FADE; } }; struct ItemFX : public Item { - float elapsed_time; - - ItemFX() { - elapsed_time = 0.0f; - } + float elapsed_time = 0.f; }; struct ItemShake : public ItemFX { - int strength; - float rate; - uint64_t _current_rng; - uint64_t _previous_rng; - - ItemShake() { - strength = 0; - rate = 0.0f; - _current_rng = 0; - type = ITEM_SHAKE; - } + int strength = 0; + float rate = 0.0f; + uint64_t _current_rng = 0; + uint64_t _previous_rng = 0; + + ItemShake() { type = ITEM_SHAKE; } void reroll_random() { _previous_rng = _current_rng; @@ -251,38 +269,25 @@ private: }; struct ItemWave : public ItemFX { - float frequency; - float amplitude; + float frequency = 1.0f; + float amplitude = 1.0f; - ItemWave() { - frequency = 1.0f; - amplitude = 1.0f; - type = ITEM_WAVE; - } + ItemWave() { type = ITEM_WAVE; } }; struct ItemTornado : public ItemFX { - float radius; - float frequency; + float radius = 1.0f; + float frequency = 1.0f; - ItemTornado() { - radius = 1.0f; - frequency = 1.0f; - type = ITEM_TORNADO; - } + ItemTornado() { type = ITEM_TORNADO; } }; struct ItemRainbow : public ItemFX { - float saturation; - float value; - float frequency; - - ItemRainbow() { - saturation = 0.8f; - value = 0.8f; - frequency = 1.0f; - type = ITEM_RAINBOW; - } + float saturation = 0.8f; + float value = 0.8f; + float frequency = 1.0f; + + ItemRainbow() { type = ITEM_RAINBOW; } }; struct ItemCustomFX : public ItemFX { @@ -291,7 +296,6 @@ private: ItemCustomFX() { type = ITEM_CUSTOMFX; - char_fx_transform.instance(); } @@ -316,7 +320,8 @@ private: int scroll_w; bool scroll_updated; bool updating_scroll; - int current_idx; + int current_idx = 1; + int current_char_ofs = 0; int visible_line_count; int tab_size; @@ -336,23 +341,25 @@ private: void _add_item(Item *p_item, bool p_enter = false, bool p_ensure_newline = false); void _remove_item(Item *p_item, const int p_line, const int p_subitem_line); - struct ProcessState { - int line_width; - }; - - enum ProcessMode { - PROCESS_CACHE, - PROCESS_DRAW, - PROCESS_POINTER - }; + String language; + TextDirection text_direction = TEXT_DIRECTION_AUTO; + Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT; + Array st_args; struct Selection { - Item *click; + ItemFrame *click_frame; + int click_line; + Item *click_item; int click_char; - Item *from; + ItemFrame *from_frame; + int from_line; + Item *from_item; int from_char; - Item *to; + + ItemFrame *to_frame; + int to_line; + Item *to_item; int to_char; bool active; // anything selected? i.e. from, to, etc. valid? @@ -364,18 +371,38 @@ private: int visible_characters; float percent_visible; - int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos = Point2i(), Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr, int p_char_count = 0); - void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr); + void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr); + + String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel); + bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to); + + void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset); + void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width); + float _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs); + float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr); + + String _roman(int p_num, bool p_capitalize) const; + String _letters(int p_num, bool p_capitalize) const; + Item *_get_item_at_pos(Item *p_item_from, Item *p_item_to, int p_position); + void _find_frame(Item *p_item, ItemFrame **r_frame, int *r_line); Ref<Font> _find_font(Item *p_item); - int _find_margin(Item *p_item, const Ref<Font> &p_base_font); + int _find_font_size(Item *p_item); + Dictionary _find_font_features(Item *p_item); + int _find_outline_size(Item *p_item); + ItemList *_find_list_item(Item *p_item); + int _find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list); + int _find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size); Align _find_align(Item *p_item); + TextServer::Direction _find_direction(Item *p_item); + Control::StructuredTextParser _find_stt(Item *p_item); + String _find_language(Item *p_item); Color _find_color(Item *p_item, const Color &p_default_color); + Color _find_outline_color(Item *p_item, const Color &p_default_color); bool _find_underline(Item *p_item); bool _find_strikethrough(Item *p_item); bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = nullptr); bool _find_layout_subitem(Item *from, Item *to); - bool _find_by_type(Item *p_item, ItemType p_type); void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack); static Color _get_color_from_string(const String &p_color_str, const Color &p_default_color); @@ -395,8 +422,6 @@ private: bool use_bbcode; String bbcode; - void _update_all_lines(); - int fixed_width; bool fit_content_height; @@ -407,23 +432,27 @@ protected: public: String get_text(); void add_text(const String &p_text); - void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0)); + void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), VAlign p_align = VALIGN_TOP); void add_newline(); bool remove_line(const int p_line); void push_font(const Ref<Font> &p_font); + void push_font_size(int p_font_size); + void push_font_features(const Dictionary &p_features); + void push_outline_size(int p_font_size); void push_normal(); void push_bold(); void push_bold_italics(); void push_italics(); void push_mono(); void push_color(const Color &p_color); + void push_outline_color(const Color &p_color); void push_underline(); void push_strikethrough(); - void push_align(Align p_align); + void push_paragraph(Align p_align, Control::TextDirection p_direction = Control::TEXT_DIRECTION_INHERITED, const String &p_language = "", Control::StructuredTextParser p_st_parser = STRUCTURED_TEXT_DEFAULT); void push_indent(int p_level); - void push_list(ListType p_list); + void push_list(int p_level, ListType p_list, bool p_capitalize); void push_meta(const Variant &p_meta); - void push_table(int p_columns); + void push_table(int p_columns, VAlign p_align = VALIGN_TOP); void push_fade(int p_start_index, int p_length); void push_shake(int p_strength, float p_rate); void push_wave(float p_frequency, float p_amplitude); @@ -431,6 +460,10 @@ public: void push_rainbow(float p_saturation, float p_value, float p_frequency); void push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment); void set_table_column_expand(int p_column, bool p_expand, int p_ratio = 1); + void set_cell_row_background_color(const Color &p_odd_row_bg, const Color &p_even_row_bg); + void set_cell_border_color(const Color &p_color); + void set_cell_size_override(const Size2 &p_min_size, const Size2 &p_max_size); + void set_cell_padding(const Rect2 &p_padding); int get_current_table_column() const; void push_cell(); void pop(); @@ -485,6 +518,18 @@ public: void set_text(const String &p_string); + void set_text_direction(TextDirection p_text_direction); + TextDirection get_text_direction() const; + + void set_language(const String &p_language); + String get_language() const; + + void set_structured_text_bidi_override(Control::StructuredTextParser p_parser); + Control::StructuredTextParser get_structured_text_bidi_override() const; + + void set_structured_text_bidi_override_options(Array p_args); + Array get_structured_text_bidi_override_options() const; + void set_visible_characters(int p_visible); int get_visible_characters() const; int get_total_character_count() const; diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 9340d98ede..70de63fd40 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -449,18 +449,6 @@ double ScrollBar::get_area_offset() const { return ofs; } -double ScrollBar::get_click_pos(const Point2 &p_pos) const { - float pos = (orientation == VERTICAL) ? p_pos.y : p_pos.x; - pos -= get_area_offset(); - - float area = get_area_size(); - if (area == 0) { - return 0; - } else { - return pos / area; - } -} - double ScrollBar::get_grabber_offset() const { return (get_area_size()) * get_as_ratio(); } diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h index 75f5ad1647..358ed74965 100644 --- a/scene/gui/scroll_bar.h +++ b/scene/gui/scroll_bar.h @@ -61,7 +61,6 @@ class ScrollBar : public Range { double get_grabber_min_size() const; double get_area_size() const; double get_area_offset() const; - double get_click_pos(const Point2 &p_pos) const; double get_grabber_offset() const; static void set_can_focus_by_default(bool p_can_focus); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index d7ca2f66ea..01c1a15b79 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -415,6 +415,11 @@ void TabContainer::_notification(int p_what) { break; } + if (all_tabs_in_front) { + // Draw the tab area. + panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); + } + // Draw unselected tabs in back int x = 0; int x_current = 0; @@ -446,8 +451,10 @@ void TabContainer::_notification(int p_what) { last_tab_cache = index; } - // Draw the tab area. - panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); + if (!all_tabs_in_front) { + // Draw the tab area. + panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); + } // Draw selected tab in front. only draw selected tab when it's in visible range. if (tabs.size() > 0 && current - first_tab_cache < tab_widths.size() && current >= first_tab_cache) { @@ -1017,6 +1024,20 @@ bool TabContainer::are_tabs_visible() const { return tabs_visible; } +void TabContainer::set_all_tabs_in_front(bool p_in_front) { + if (p_in_front == all_tabs_in_front) { + return; + } + + all_tabs_in_front = p_in_front; + + update(); +} + +bool TabContainer::is_all_tabs_in_front() const { + return all_tabs_in_front; +} + Control *TabContainer::_get_tab(int p_idx) const { return get_tab_control(p_idx); } @@ -1208,6 +1229,8 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tab_align"), &TabContainer::get_tab_align); ClassDB::bind_method(D_METHOD("set_tabs_visible", "visible"), &TabContainer::set_tabs_visible); ClassDB::bind_method(D_METHOD("are_tabs_visible"), &TabContainer::are_tabs_visible); + ClassDB::bind_method(D_METHOD("set_all_tabs_in_front", "is_front"), &TabContainer::set_all_tabs_in_front); + ClassDB::bind_method(D_METHOD("is_all_tabs_in_front"), &TabContainer::is_all_tabs_in_front); ClassDB::bind_method(D_METHOD("set_tab_title", "tab_idx", "title"), &TabContainer::set_tab_title); ClassDB::bind_method(D_METHOD("get_tab_title", "tab_idx"), &TabContainer::get_tab_title); ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &TabContainer::set_tab_icon); @@ -1234,6 +1257,7 @@ void TabContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_align", "get_tab_align"); ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "all_tabs_in_front"), "set_all_tabs_in_front", "is_all_tabs_in_front"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size"); @@ -1253,6 +1277,7 @@ TabContainer::TabContainer() { previous = 0; align = ALIGN_CENTER; tabs_visible = true; + all_tabs_in_front = false; drag_to_rearrange_enabled = false; tabs_rearrange_group = -1; use_hidden_tabs_for_min_size = false; diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 2fef606551..91153e5fc3 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -52,6 +52,7 @@ private: int current; int previous; bool tabs_visible; + bool all_tabs_in_front; bool buttons_visible_cache; bool menu_hovered; int highlight_arrow; @@ -94,6 +95,9 @@ public: void set_tabs_visible(bool p_visible); bool are_tabs_visible() const; + void set_all_tabs_in_front(bool p_is_front); + bool is_all_tabs_in_front() const; + void set_tab_title(int p_tab, const String &p_title); String get_tab_title(int p_tab) const; diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 06e55deacb..5b26428e45 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -153,7 +153,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { if (cb_hover != -1) { //pressed - emit_signal("tab_close", cb_hover); + emit_signal("tab_closed", cb_hover); } cb_pressing = false; @@ -641,7 +641,7 @@ void Tabs::_update_hover() { } if (hover != hover_now) { hover = hover_now; - emit_signal("tab_hover", hover); + emit_signal("tab_hovered", hover); } if (hover_buttons == -1) { // no hover @@ -1114,8 +1114,8 @@ void Tabs::_bind_methods() { ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("right_button_pressed", PropertyInfo(Variant::INT, "tab"))); - ADD_SIGNAL(MethodInfo("tab_close", PropertyInfo(Variant::INT, "tab"))); - ADD_SIGNAL(MethodInfo("tab_hover", PropertyInfo(Variant::INT, "tab"))); + ADD_SIGNAL(MethodInfo("tab_closed", PropertyInfo(Variant::INT, "tab"))); + ADD_SIGNAL(MethodInfo("tab_hovered", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("reposition_active_tab_request", PropertyInfo(Variant::INT, "idx_to"))); ADD_SIGNAL(MethodInfo("tab_clicked", PropertyInfo(Variant::INT, "tab"))); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index b9818e139f..1d65abc95f 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1141,7 +1141,7 @@ void TextEdit::_notification(int p_what) { // Draw line. RID rid = ldata->get_line_rid(line_wrap_index); - float text_height = TS->shaped_text_get_size(rid).y; + float text_height = TS->shaped_text_get_size(rid).y + cache.font->get_spacing(Font::SPACING_TOP) + cache.font->get_spacing(Font::SPACING_BOTTOM); if (rtl) { char_margin = size.width - char_margin - TS->shaped_text_get_size(rid).x; @@ -1240,10 +1240,13 @@ void TextEdit::_notification(int p_what) { ofs_y += (row_height - text_height) / 2; - const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(rid); + const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid); + const TextServer::Glyph *glyphs = visual.ptr(); + int gl_size = visual.size(); + ofs_y += ldata->get_line_ascent(line_wrap_index); float char_ofs = 0.f; - for (int j = 0; j < glyphs.size(); j++) { + for (int j = 0; j < gl_size; j++) { if (color_map.has(glyphs[j].start)) { current_color = color_map[glyphs[j].start].get("color"); if (readonly && current_color.a > cache.font_color_readonly.a) { @@ -1647,7 +1650,7 @@ void TextEdit::_notification(int p_what) { if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); - DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + _get_cursor_pixel_pos(), get_viewport()->get_window_id()); + DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + _get_cursor_pixel_pos(false), get_viewport()->get_window_id()); } if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { @@ -2069,8 +2072,10 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co r_col = col; } -Vector2i TextEdit::_get_cursor_pixel_pos() { - adjust_viewport_to_cursor(); +Vector2i TextEdit::_get_cursor_pixel_pos(bool p_adjust_viewport) { + if (p_adjust_viewport) { + adjust_viewport_to_cursor(); + } int row = 1; for (int i = get_first_visible_line(); i < cursor.line; i++) { if (!is_line_hidden(i)) { @@ -6616,8 +6621,8 @@ void TextEdit::set_line_length_guideline_hard_column(int p_column) { } void TextEdit::set_draw_minimap(bool p_draw) { - draw_minimap = p_draw; if (draw_minimap != p_draw) { + draw_minimap = p_draw; _update_wrap_at(); } update(); @@ -6628,8 +6633,8 @@ bool TextEdit::is_drawing_minimap() const { } void TextEdit::set_minimap_width(int p_minimap_width) { - minimap_width = p_minimap_width; if (minimap_width != p_minimap_width) { + minimap_width = p_minimap_width; _update_wrap_at(); } update(); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index c2fe4afec5..3f16ed1366 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -700,7 +700,7 @@ public: int cursor_get_column() const; int cursor_get_line() const; - Vector2i _get_cursor_pixel_pos(); + Vector2i _get_cursor_pixel_pos(bool p_adjust_viewport = true); bool cursor_get_blink_enabled() const; void cursor_set_blink_enabled(const bool p_enabled); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 6bd8003ef0..063a5e7ac1 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -597,12 +597,6 @@ String TreeItem::get_button_tooltip(int p_column, int p_idx) const { return cells[p_column].buttons[p_idx].tooltip; } -int TreeItem::get_button_id(int p_column, int p_idx) const { - ERR_FAIL_INDEX_V(p_column, cells.size(), -1); - ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), -1); - return cells[p_column].buttons[p_idx].id; -} - void TreeItem::erase_button(int p_column, int p_idx) { ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); @@ -4081,10 +4075,6 @@ void Tree::set_cursor_can_exit_tree(bool p_enable) { cursor_can_exit_tree = p_enable; } -bool Tree::can_cursor_exit_tree() const { - return cursor_can_exit_tree; -} - void Tree::set_hide_folding(bool p_hide) { hide_folding = p_hide; update(); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 4c3d03c91a..82422b8be3 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -227,7 +227,6 @@ public: int get_button_count(int p_column) const; String get_button_tooltip(int p_column, int p_idx) const; Ref<Texture2D> get_button(int p_column, int p_idx) const; - int get_button_id(int p_column, int p_idx) const; void erase_button(int p_column, int p_idx); int get_button_by_id(int p_column, int p_id) const; void set_button(int p_column, int p_idx, const Ref<Texture2D> &p_button); @@ -633,7 +632,6 @@ public: void scroll_to_item(TreeItem *p_item); void set_cursor_can_exit_tree(bool p_enable); - bool can_cursor_exit_tree() const; VScrollBar *get_vscroll_bar() { return v_scroll; } diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 6806a55151..43350fae37 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -364,7 +364,7 @@ void CanvasItem::_propagate_visibility_changed(bool p_visible) { if (p_visible) { update(); //todo optimize } else { - emit_signal(SceneStringNames::get_singleton()->hide); + emit_signal(SceneStringNames::get_singleton()->hidden); } _block(); @@ -1227,7 +1227,7 @@ void CanvasItem::_bind_methods() { ADD_SIGNAL(MethodInfo("draw")); ADD_SIGNAL(MethodInfo("visibility_changed")); - ADD_SIGNAL(MethodInfo("hide")); + ADD_SIGNAL(MethodInfo("hidden")); ADD_SIGNAL(MethodInfo("item_rect_changed")); BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED); diff --git a/scene/main/node.h b/scene/main/node.h index 873c27bc13..024d036fd3 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -74,9 +74,8 @@ public: private: struct GroupData { - bool persistent; - SceneTree::Group *group; - GroupData() { persistent = false; } + bool persistent = false; + SceneTree::Group *group = nullptr; }; struct NetData { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 6350777a3d..e496748b2d 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3824,7 +3824,7 @@ void SubViewport::_bind_methods() { BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS); BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER); - BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME); + BIND_ENUM_CONSTANT(CLEAR_MODE_ONCE); BIND_ENUM_CONSTANT(UPDATE_DISABLED); BIND_ENUM_CONSTANT(UPDATE_ONCE); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 7ce202d27c..f08f255dde 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -624,7 +624,7 @@ public: enum ClearMode { CLEAR_MODE_ALWAYS, CLEAR_MODE_NEVER, - CLEAR_MODE_ONLY_NEXT_FRAME + CLEAR_MODE_ONCE }; enum UpdateMode { diff --git a/scene/main/window.cpp b/scene/main/window.cpp index d88c8fb3af..ad87139332 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1167,11 +1167,6 @@ Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName return Control::get_icons(theme_owner, theme_owner_window, p_name, type); } -Ref<Shader> Window::get_theme_shader(const StringName &p_name, const StringName &p_type) const { - StringName type = p_type ? p_type : get_class_name(); - return Control::get_shaders(theme_owner, theme_owner_window, p_name, type); -} - Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const { StringName type = p_type ? p_type : get_class_name(); return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, type); @@ -1202,11 +1197,6 @@ bool Window::has_theme_icon(const StringName &p_name, const StringName &p_type) return Control::has_icons(theme_owner, theme_owner_window, p_name, type); } -bool Window::has_theme_shader(const StringName &p_name, const StringName &p_type) const { - StringName type = p_type ? p_type : get_class_name(); - return Control::has_shaders(theme_owner, theme_owner_window, p_name, type); -} - bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const { StringName type = p_type ? p_type : get_class_name(); return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, type); diff --git a/scene/main/window.h b/scene/main/window.h index a9a17ab9ba..20f8309952 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -253,7 +253,6 @@ public: Rect2i get_usable_parent_rect() const; Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const; - Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const; Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const; int get_theme_font_size(const StringName &p_name, const StringName &p_type = StringName()) const; @@ -261,7 +260,6 @@ public: int get_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const; bool has_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const; - bool has_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const; bool has_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const; bool has_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const; bool has_theme_font_size(const StringName &p_name, const StringName &p_type = StringName()) const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 7082d70ae9..73507d36fc 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -234,6 +234,10 @@ static Ref<ResourceFormatLoaderText> resource_loader_text; static Ref<ResourceFormatLoaderFont> resource_loader_font; +#ifndef DISABLE_DEPRECATED +static Ref<ResourceFormatLoaderCompatFont> resource_loader_compat_font; +#endif /* DISABLE_DEPRECATED */ + static Ref<ResourceFormatLoaderStreamTexture2D> resource_loader_stream_texture; static Ref<ResourceFormatLoaderStreamTextureLayered> resource_loader_texture_layered; static Ref<ResourceFormatLoaderStreamTexture3D> resource_loader_texture_3d; @@ -251,6 +255,11 @@ void register_scene_types() { resource_loader_font.instance(); ResourceLoader::add_resource_format_loader(resource_loader_font); +#ifndef DISABLE_DEPRECATED + resource_loader_compat_font.instance(); + ResourceLoader::add_resource_format_loader(resource_loader_compat_font); +#endif /* DISABLE_DEPRECATED */ + resource_loader_stream_texture.instance(); ResourceLoader::add_resource_format_loader(resource_loader_stream_texture); @@ -670,8 +679,8 @@ void register_scene_types() { #ifndef _3D_DISABLED ClassDB::register_virtual_class<PrimitiveMesh>(); + ClassDB::register_class<BoxMesh>(); ClassDB::register_class<CapsuleMesh>(); - ClassDB::register_class<CubeMesh>(); ClassDB::register_class<CylinderMesh>(); ClassDB::register_class<PlaneMesh>(); ClassDB::register_class<PrismMesh>(); @@ -799,6 +808,9 @@ void register_scene_types() { #ifndef DISABLE_DEPRECATED // Dropped in 4.0, near approximation. ClassDB::add_compatibility_class("AnimationTreePlayer", "AnimationTree"); + ClassDB::add_compatibility_class("BitmapFont", "Font"); + ClassDB::add_compatibility_class("DynamicFont", "Font"); + ClassDB::add_compatibility_class("DynamicFontData", "FontData"); ClassDB::add_compatibility_class("ToolButton", "Button"); // Renamed in 4.0. @@ -835,6 +847,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("CSGShape", "CSGShape3D"); ClassDB::add_compatibility_class("CSGSphere", "CSGSphere3D"); ClassDB::add_compatibility_class("CSGTorus", "CSGTorus3D"); + ClassDB::add_compatibility_class("CubeMesh", "BoxMesh"); ClassDB::add_compatibility_class("CylinderShape", "CylinderShape3D"); ClassDB::add_compatibility_class("DirectionalLight", "DirectionalLight3D"); ClassDB::add_compatibility_class("EditorSpatialGizmo", "EditorNode3DGizmo"); @@ -917,7 +930,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("StreamTexture", "StreamTexture2D"); ClassDB::add_compatibility_class("Light2D", "PointLight2D"); -#endif +#endif /* DISABLE_DEPRECATED */ OS::get_singleton()->yield(); //may take time to init @@ -969,6 +982,11 @@ void unregister_scene_types() { ResourceLoader::remove_resource_format_loader(resource_loader_font); resource_loader_font.unref(); +#ifndef DISABLE_DEPRECATED + ResourceLoader::remove_resource_format_loader(resource_loader_compat_font); + resource_loader_compat_font.unref(); +#endif /* DISABLE_DEPRECATED */ + ResourceLoader::remove_resource_format_loader(resource_loader_texture_layered); resource_loader_texture_layered.unref(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 1d92ed4830..82f6a8ef57 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -571,6 +571,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color_accel", "PopupMenu", Color(0.7, 0.7, 0.7, 0.8)); theme->set_color("font_color_disabled", "PopupMenu", Color(0.4, 0.4, 0.4, 0.8)); theme->set_color("font_color_hover", "PopupMenu", control_font_color); + theme->set_color("font_color_separator", "PopupMenu", control_font_color); theme->set_constant("hseparation", "PopupMenu", 4 * scale); theme->set_constant("vseparation", "PopupMenu", 4 * scale); @@ -802,6 +803,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font("bold_italics_font", "RichTextLabel", Ref<Font>()); theme->set_font("mono_font", "RichTextLabel", Ref<Font>()); + theme->set_font_size("normal_font_size", "RichTextLabel", -1); + theme->set_font_size("bold_font_size", "RichTextLabel", -1); + theme->set_font_size("italics_font_size", "RichTextLabel", -1); + theme->set_font_size("bold_italics_font_size", "RichTextLabel", -1); + theme->set_font_size("mono_font_size", "RichTextLabel", -1); + theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1)); theme->set_color("font_color_selected", "RichTextLabel", font_color_selection); theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8)); @@ -816,6 +823,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale); theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale); + theme->set_color("table_odd_row_bg", "RichTextLabel", Color(0, 0, 0, 0)); + theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0)); + theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0)); // Containers theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1)); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 2ed5953b8f..1eb78a3679 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -591,7 +591,7 @@ void Environment::set_glow_level(int p_level, float p_intensity) { } float Environment::get_glow_level(int p_level) const { - ERR_FAIL_INDEX_V(p_level, RS::MAX_GLOW_LEVELS, false); + ERR_FAIL_INDEX_V(p_level, RS::MAX_GLOW_LEVELS, 0.0); return glow_levels[p_level]; } diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index da35137a09..fab8642c20 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -53,6 +53,11 @@ void FontData::_bind_methods() { ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased); ClassDB::bind_method(D_METHOD("get_antialiased"), &FontData::get_antialiased); + ClassDB::bind_method(D_METHOD("get_variation_list"), &FontData::get_variation_list); + + ClassDB::bind_method(D_METHOD("set_variation", "tag", "value"), &FontData::set_variation); + ClassDB::bind_method(D_METHOD("get_variation", "tag"), &FontData::get_variation); + ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontData::set_hinting); ClassDB::bind_method(D_METHOD("get_hinting"), &FontData::get_hinting); @@ -115,6 +120,11 @@ bool FontData::_set(const StringName &p_name, const Variant &p_value) { set_script_support_override(scr, p_value); return true; } + if (str.begins_with("variation/")) { + String name = str.get_slicec('/', 1); + set_variation(name, p_value); + return true; + } return false; } @@ -137,6 +147,12 @@ bool FontData::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_script_support_override(scr); return true; } + if (str.begins_with("variation/")) { + String name = str.get_slicec('/', 1); + + r_ret = get_variation(name); + return true; + } return false; } @@ -153,6 +169,12 @@ void FontData::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::BOOL, "script_support_override/" + scr_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE)); } p_list->push_back(PropertyInfo(Variant::NIL, "script_support_override/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + + Dictionary variations = get_variation_list(); + for (const Variant *ftr = variations.next(nullptr); ftr != nullptr; ftr = variations.next(ftr)) { + Vector3i v = variations[*ftr]; + p_list->push_back(PropertyInfo(Variant::FLOAT, "variation/" + TS->tag_to_name(*ftr), PROPERTY_HINT_RANGE, itos(v.x) + "," + itos(v.y), PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE)); + } } RID FontData::get_rid() const { @@ -239,6 +261,26 @@ float FontData::get_underline_thickness(int p_size) const { return TS->font_get_underline_thickness(rid, (p_size < 0) ? base_size : p_size); } +Dictionary FontData::get_variation_list() const { + if (rid == RID()) { + return Dictionary(); + } + return TS->font_get_variation_list(rid); +} + +void FontData::set_variation(const String &p_name, double p_value) { + ERR_FAIL_COND(rid == RID()); + TS->font_set_variation(rid, p_name, p_value); + emit_changed(); +} + +double FontData::get_variation(const String &p_name) const { + if (rid == RID()) { + return 0; + } + return TS->font_get_variation(rid, p_name); +} + void FontData::set_antialiased(bool p_antialiased) { ERR_FAIL_COND(rid == RID()); TS->font_set_antialiased(rid, p_antialiased); @@ -472,6 +514,32 @@ void Font::_data_changed() { bool Font::_set(const StringName &p_name, const Variant &p_value) { String str = p_name; +#ifndef DISABLE_DEPRECATED + if (str == "font_data") { // Compatibility, DynamicFont main data + Ref<FontData> fd = p_value; + if (fd.is_valid()) { + add_data(fd); + return true; + } + return false; + } else if (str.begins_with("fallback/")) { // Compatibility, DynamicFont fallback data + Ref<FontData> fd = p_value; + if (fd.is_valid()) { + add_data(fd); + return true; + } + return false; + } else if (str == "fallback") { // Compatibility, BitmapFont fallback + Ref<Font> f = p_value; + if (f.is_valid()) { + for (int i = 0; i < f->get_data_count(); i++) { + add_data(f->get_data(i)); + } + return true; + } + return false; + } +#endif /* DISABLE_DEPRECATED */ if (str.begins_with("data/")) { int idx = str.get_slicec('/', 1).to_int(); Ref<FontData> fd = p_value; @@ -595,41 +663,41 @@ Dictionary Font::get_feature_list() const { float Font::get_height(int p_size) const { float ret = 0.f; for (int i = 0; i < data.size(); i++) { - ret += data[i]->get_height(p_size); + ret = MAX(ret, data[i]->get_height(p_size)); } - return (ret / data.size()) + spacing_top + spacing_bottom; + return ret + spacing_top + spacing_bottom; } float Font::get_ascent(int p_size) const { float ret = 0.f; for (int i = 0; i < data.size(); i++) { - ret += data[i]->get_ascent(p_size); + ret = MAX(ret, data[i]->get_ascent(p_size)); } - return (ret / data.size()) + spacing_top; + return ret + spacing_top; } float Font::get_descent(int p_size) const { float ret = 0.f; for (int i = 0; i < data.size(); i++) { - ret += data[i]->get_descent(p_size); + ret = MAX(ret, data[i]->get_descent(p_size)); } - return (ret / data.size()) + spacing_bottom; + return ret + spacing_bottom; } float Font::get_underline_position(int p_size) const { float ret = 0.f; for (int i = 0; i < data.size(); i++) { - ret += data[i]->get_underline_position(p_size); + ret = MAX(ret, data[i]->get_underline_position(p_size)); } - return (ret / data.size()); + return ret; } float Font::get_underline_thickness(int p_size) const { float ret = 0.f; for (int i = 0; i < data.size(); i++) { - ret += data[i]->get_underline_thickness(p_size); + ret = MAX(ret, data[i]->get_underline_thickness(p_size)); } - return (ret / data.size()); + return ret; } int Font::get_spacing(int p_type) const { @@ -899,6 +967,23 @@ RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_origina return dfont; } +void ResourceFormatLoaderFont::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const { +#ifndef DISABLE_DEPRECATED + if (p_type == "DynacmicFontData") { + p_extensions->push_back("ttf"); + p_extensions->push_back("otf"); + p_extensions->push_back("woff"); + return; + } + if (p_type == "BitmapFont") { // BitmapFont (*.font, *fnt) is handled by ResourceFormatLoaderCompatFont + return; + } +#endif /* DISABLE_DEPRECATED */ + if (p_type == "" || handles_type(p_type)) { + get_recognized_extensions(p_extensions); + } +} + void ResourceFormatLoaderFont::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("ttf"); p_extensions->push_back("otf"); @@ -918,3 +1003,45 @@ String ResourceFormatLoaderFont::get_resource_type(const String &p_path) const { } return ""; } + +#ifndef DISABLE_DEPRECATED + +RES ResourceFormatLoaderCompatFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { + if (r_error) { + *r_error = ERR_FILE_CANT_OPEN; + } + + Ref<FontData> dfont; + dfont.instance(); + dfont->load_resource(p_path); + + Ref<Font> font; + font.instance(); + font->add_data(dfont); + + if (r_error) { + *r_error = OK; + } + + return font; +} + +void ResourceFormatLoaderCompatFont::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const { + if (p_type == "BitmapFont") { + p_extensions->push_back("font"); + p_extensions->push_back("fnt"); + } +} + +void ResourceFormatLoaderCompatFont::get_recognized_extensions(List<String> *p_extensions) const { +} + +bool ResourceFormatLoaderCompatFont::handles_type(const String &p_type) const { + return (p_type == "Font"); +} + +String ResourceFormatLoaderCompatFont::get_resource_type(const String &p_path) const { + return ""; +} + +#endif /* DISABLE_DEPRECATED */ diff --git a/scene/resources/font.h b/scene/resources/font.h index 226979c4a0..fe28e1aea5 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -68,6 +68,10 @@ public: float get_descent(int p_size) const; Dictionary get_feature_list() const; + Dictionary get_variation_list() const; + + void set_variation(const String &p_name, double p_value); + double get_variation(const String &p_name) const; float get_underline_position(int p_size) const; float get_underline_thickness(int p_size) const; @@ -198,9 +202,23 @@ VARIANT_ENUM_CAST(Font::SpacingType); class ResourceFormatLoaderFont : public ResourceFormatLoader { public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); + virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + +#ifndef DISABLE_DEPRECATED + +class ResourceFormatLoaderCompatFont : public ResourceFormatLoader { +public: + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); + virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; }; -#endif +#endif /* DISABLE_DEPRECATED */ + +#endif /* FONT_H */ diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 35c967ce27..6e08af23f5 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -2417,10 +2417,10 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Height", "heightmap_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "heightmap_enabled"), "set_feature", "get_feature", FEATURE_HEIGHT_MAPPING); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "heightmap_scale", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_heightmap_scale", "get_heightmap_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "heightmap_scale", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_heightmap_scale", "get_heightmap_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "heightmap_deep_parallax"), "set_heightmap_deep_parallax", "is_heightmap_deep_parallax_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_min_layers", PROPERTY_HINT_RANGE, "1,32,1"), "set_heightmap_deep_parallax_min_layers", "get_heightmap_deep_parallax_min_layers"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_max_layers", PROPERTY_HINT_RANGE, "1,32,1"), "set_heightmap_deep_parallax_max_layers", "get_heightmap_deep_parallax_max_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_min_layers", PROPERTY_HINT_RANGE, "1,64,1"), "set_heightmap_deep_parallax_min_layers", "get_heightmap_deep_parallax_min_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_max_layers", PROPERTY_HINT_RANGE, "1,64,1"), "set_heightmap_deep_parallax_max_layers", "get_heightmap_deep_parallax_max_layers"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "heightmap_flip_tangent"), "set_heightmap_deep_parallax_flip_tangent", "get_heightmap_deep_parallax_flip_tangent"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "heightmap_flip_binormal"), "set_heightmap_deep_parallax_flip_binormal", "get_heightmap_deep_parallax_flip_binormal"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "heightmap_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_HEIGHTMAP); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index d12f92f8f7..287ec55560 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -480,9 +480,6 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES); BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP); - BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); - BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE); - BIND_ENUM_CONSTANT(ARRAY_VERTEX); BIND_ENUM_CONSTANT(ARRAY_NORMAL); BIND_ENUM_CONSTANT(ARRAY_TANGENT); @@ -536,6 +533,9 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES); BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE); BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS); + + BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); + BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE); } void Mesh::clear_cache() const { @@ -1387,7 +1387,7 @@ bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_v struct ArrayMeshLightmapSurface { Ref<Material> material; - Vector<SurfaceTool::Vertex> vertices; + LocalVector<SurfaceTool::Vertex> vertices; Mesh::PrimitiveType primitive; uint32_t format; }; @@ -1428,7 +1428,7 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach Array arrays = surface_get_arrays(i); s.material = surface_get_material(i); - s.vertices = SurfaceTool::create_vertex_array_from_triangle_arrays(arrays); + SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices); Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX]; int vc = rvertices.size(); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 659574c2c4..586bb2f802 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -53,7 +53,10 @@ public: NO_INDEX_ARRAY = RenderingServer::NO_INDEX_ARRAY, ARRAY_WEIGHTS_SIZE = RenderingServer::ARRAY_WEIGHTS_SIZE }; - + enum BlendShapeMode { + BLEND_SHAPE_MODE_NORMALIZED = RS::BLEND_SHAPE_MODE_NORMALIZED, + BLEND_SHAPE_MODE_RELATIVE = RS::BLEND_SHAPE_MODE_RELATIVE, + }; enum ArrayType { ARRAY_VERTEX = RenderingServer::ARRAY_VERTEX, ARRAY_NORMAL = RenderingServer::ARRAY_NORMAL, @@ -125,11 +128,6 @@ public: PRIMITIVE_MAX = RenderingServer::PRIMITIVE_MAX, }; - enum BlendShapeMode { - BLEND_SHAPE_MODE_NORMALIZED = RS::BLEND_SHAPE_MODE_NORMALIZED, - BLEND_SHAPE_MODE_RELATIVE = RS::BLEND_SHAPE_MODE_RELATIVE, - }; - virtual int get_surface_count() const = 0; virtual int surface_get_array_len(int p_idx) const = 0; virtual int surface_get_array_index_len(int p_idx) const = 0; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 5ce253f970..09674f3465 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -1481,16 +1481,6 @@ int SceneState::add_name(const StringName &p_name) { return names.size() - 1; } -int SceneState::find_name(const StringName &p_name) const { - for (int i = 0; i < names.size(); i++) { - if (names[i] == p_name) { - return i; - } - } - - return -1; -} - int SceneState::add_value(const Variant &p_value) { variants.push_back(p_value); return variants.size() - 1; diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index b8b3f84ecc..fce3891507 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -172,7 +172,6 @@ public: //build API int add_name(const StringName &p_name); - int find_name(const StringName &p_name) const; int add_value(const Variant &p_value); int add_node_path(const NodePath &p_path); int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index); diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index a286184aee..e2f96c54cb 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -329,7 +329,7 @@ void ParticlesMaterial::_update_shader() { code += " float tex_linear_velocity = 0.0;\n"; } - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n"; code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n"; code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n"; @@ -377,7 +377,7 @@ void ParticlesMaterial::_update_shader() { code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n"; if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " mat2 rotm;"; code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n"; code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n"; @@ -398,7 +398,7 @@ void ParticlesMaterial::_update_shader() { code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " VELOCITY.z = 0.0;\n"; code += " TRANSFORM[3].z = 0.0;\n"; } @@ -413,7 +413,7 @@ void ParticlesMaterial::_update_shader() { code += " float tex_linear_velocity = 0.0;\n"; } - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; } else { @@ -471,7 +471,7 @@ void ParticlesMaterial::_update_shader() { code += " vec3 force = gravity;\n"; code += " vec3 pos = TRANSFORM[3].xyz;\n"; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " pos.z = 0.0;\n"; } code += " // apply linear acceleration\n"; @@ -481,7 +481,7 @@ void ParticlesMaterial::_update_shader() { code += " vec3 diff = pos - org;\n"; code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);\n"; code += " // apply tangential acceleration;\n"; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n"; } else { @@ -495,7 +495,7 @@ void ParticlesMaterial::_update_shader() { code += " // apply attractor forces\n"; code += " VELOCITY += force * DELTA;\n"; code += " // orbit velocity\n"; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);\n"; code += " if (orbit_amount != 0.0) {\n"; code += " float ang = orbit_amount * DELTA * pi * 2.0;\n"; @@ -562,8 +562,8 @@ void ParticlesMaterial::_update_shader() { } code += "\n"; - if (flags[FLAG_DISABLE_Z]) { - if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { code += " if (length(VELOCITY) > 0.0) {\n"; code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n"; code += " } else {\n"; @@ -579,7 +579,7 @@ void ParticlesMaterial::_update_shader() { } else { // orient particle Y towards velocity - if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { code += " if (length(VELOCITY) > 0.0) {\n"; code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n"; code += " } else {\n"; @@ -598,7 +598,7 @@ void ParticlesMaterial::_update_shader() { code += " TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n"; } // turn particle by rotation in Y - if (flags[FLAG_ROTATE_Y]) { + if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) { code += " TRANSFORM = TRANSFORM * mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } } @@ -611,7 +611,7 @@ void ParticlesMaterial::_update_shader() { code += " TRANSFORM[0].xyz *= base_scale;\n"; code += " TRANSFORM[1].xyz *= base_scale;\n"; code += " TRANSFORM[2].xyz *= base_scale;\n"; - if (flags[FLAG_DISABLE_Z]) { + if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " VELOCITY.z = 0.0;\n"; code += " TRANSFORM[3].z = 0.0;\n"; } @@ -916,18 +916,18 @@ Ref<Texture2D> ParticlesMaterial::get_color_ramp() const { return color_ramp; } -void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) { - ERR_FAIL_INDEX(p_flag, FLAG_MAX); - flags[p_flag] = p_enable; +void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { + ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); + particle_flags[p_particle_flag] = p_enable; _queue_shader_change(); - if (p_flag == FLAG_DISABLE_Z) { + if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) { _change_notify(); } } -bool ParticlesMaterial::get_flag(Flags p_flag) const { - ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); - return flags[p_flag]; +bool ParticlesMaterial::get_particle_flag(ParticleFlags p_particle_flag) const { + ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false); + return particle_flags[p_particle_flag]; } void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) { @@ -1056,7 +1056,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const { property.usage = 0; } - if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { + if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { property.usage = 0; } } @@ -1170,8 +1170,8 @@ void ParticlesMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp); ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp); - ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &ParticlesMaterial::set_flag); - ClassDB::bind_method(D_METHOD("get_flag", "flag"), &ParticlesMaterial::get_flag); + ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticlesMaterial::set_particle_flag); + ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticlesMaterial::get_particle_flag); ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape); ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape); @@ -1238,10 +1238,10 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_normal_texture", "get_emission_normal_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_color_texture", "get_emission_color_texture"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count"); - ADD_GROUP("Flags", "flag_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_flag", "get_flag", FLAG_DISABLE_Z); + ADD_GROUP("ParticleFlags", "particle_flag_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z); ADD_GROUP("Direction", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); @@ -1327,10 +1327,10 @@ void ParticlesMaterial::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET); BIND_ENUM_CONSTANT(PARAM_MAX); - BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); - BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); - BIND_ENUM_CONSTANT(FLAG_DISABLE_Z); - BIND_ENUM_CONSTANT(FLAG_MAX); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z); + BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); @@ -1385,8 +1385,8 @@ ParticlesMaterial::ParticlesMaterial() : set_param_randomness(Parameter(i), 0); } - for (int i = 0; i < FLAG_MAX; i++) { - flags[i] = false; + for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { + particle_flags[i] = false; } set_color(Color(1, 1, 1, 1)); diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index 12fa53ef29..7e8f05b706 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -61,11 +61,11 @@ public: PARAM_MAX }; - enum Flags { - FLAG_ALIGN_Y_TO_VELOCITY, - FLAG_ROTATE_Y, - FLAG_DISABLE_Z, - FLAG_MAX + enum ParticleFlags { + PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, + PARTICLE_FLAG_ROTATE_Y, + PARTICLE_FLAG_DISABLE_Z, + PARTICLE_FLAG_MAX }; enum EmissionShape { @@ -90,7 +90,7 @@ private: struct { uint32_t texture_mask : 16; uint32_t texture_color : 1; - uint32_t flags : 4; + uint32_t particle_flags : 4; uint32_t emission_shape : 2; uint32_t invalid_key : 1; uint32_t has_emission_color : 1; @@ -124,9 +124,9 @@ private: mk.texture_mask |= (1 << i); } } - for (int i = 0; i < FLAG_MAX; i++) { - if (flags[i]) { - mk.flags |= (1 << i); + for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { + if (particle_flags[i]) { + mk.particle_flags |= (1 << i); } } @@ -227,7 +227,7 @@ private: Color color; Ref<Texture2D> color_ramp; - bool flags[FLAG_MAX]; + bool particle_flags[PARTICLE_FLAG_MAX]; EmissionShape emission_shape; float emission_sphere_radius; @@ -284,8 +284,8 @@ public: void set_color_ramp(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_color_ramp() const; - void set_flag(Flags p_flag, bool p_enable); - bool get_flag(Flags p_flag) const; + void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable); + bool get_particle_flag(ParticleFlags p_particle_flag) const; void set_emission_shape(EmissionShape p_shape); void set_emission_sphere_radius(float p_radius); @@ -349,7 +349,7 @@ public: }; VARIANT_ENUM_CAST(ParticlesMaterial::Parameter) -VARIANT_ENUM_CAST(ParticlesMaterial::Flags) +VARIANT_ENUM_CAST(ParticlesMaterial::ParticleFlags) VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape) VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode) diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 64322f333c..06e181cb99 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -477,10 +477,10 @@ CapsuleMesh::CapsuleMesh() { } /** - CubeMesh + BoxMesh */ -void CubeMesh::_create_mesh_array(Array &p_arr) const { +void BoxMesh::_create_mesh_array(Array &p_arr) const { int i, j, prevrow, thisrow, point; float x, y, z; float onethird = 1.0 / 3.0; @@ -672,16 +672,16 @@ void CubeMesh::_create_mesh_array(Array &p_arr) const { p_arr[RS::ARRAY_INDEX] = indices; } -void CubeMesh::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_size", "size"), &CubeMesh::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &CubeMesh::get_size); +void BoxMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_size", "size"), &BoxMesh::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &BoxMesh::get_size); - ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &CubeMesh::set_subdivide_width); - ClassDB::bind_method(D_METHOD("get_subdivide_width"), &CubeMesh::get_subdivide_width); - ClassDB::bind_method(D_METHOD("set_subdivide_height", "divisions"), &CubeMesh::set_subdivide_height); - ClassDB::bind_method(D_METHOD("get_subdivide_height"), &CubeMesh::get_subdivide_height); - ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &CubeMesh::set_subdivide_depth); - ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth); + ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &BoxMesh::set_subdivide_width); + ClassDB::bind_method(D_METHOD("get_subdivide_width"), &BoxMesh::get_subdivide_width); + ClassDB::bind_method(D_METHOD("set_subdivide_height", "divisions"), &BoxMesh::set_subdivide_height); + ClassDB::bind_method(D_METHOD("get_subdivide_height"), &BoxMesh::get_subdivide_height); + ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &BoxMesh::set_subdivide_depth); + ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &BoxMesh::get_subdivide_depth); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); @@ -689,43 +689,43 @@ void CubeMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); } -void CubeMesh::set_size(const Vector3 &p_size) { +void BoxMesh::set_size(const Vector3 &p_size) { size = p_size; _request_update(); } -Vector3 CubeMesh::get_size() const { +Vector3 BoxMesh::get_size() const { return size; } -void CubeMesh::set_subdivide_width(const int p_divisions) { +void BoxMesh::set_subdivide_width(const int p_divisions) { subdivide_w = p_divisions > 0 ? p_divisions : 0; _request_update(); } -int CubeMesh::get_subdivide_width() const { +int BoxMesh::get_subdivide_width() const { return subdivide_w; } -void CubeMesh::set_subdivide_height(const int p_divisions) { +void BoxMesh::set_subdivide_height(const int p_divisions) { subdivide_h = p_divisions > 0 ? p_divisions : 0; _request_update(); } -int CubeMesh::get_subdivide_height() const { +int BoxMesh::get_subdivide_height() const { return subdivide_h; } -void CubeMesh::set_subdivide_depth(const int p_divisions) { +void BoxMesh::set_subdivide_depth(const int p_divisions) { subdivide_d = p_divisions > 0 ? p_divisions : 0; _request_update(); } -int CubeMesh::get_subdivide_depth() const { +int BoxMesh::get_subdivide_depth() const { return subdivide_d; } -CubeMesh::CubeMesh() { +BoxMesh::BoxMesh() { // defaults size = Vector3(2.0, 2.0, 2.0); subdivide_w = 0; diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index f0ae611b5e..02aea9c5c8 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -130,10 +130,10 @@ public: }; /** - Similar to test cube but with subdivision support and different texture coordinates + A box */ -class CubeMesh : public PrimitiveMesh { - GDCLASS(CubeMesh, PrimitiveMesh); +class BoxMesh : public PrimitiveMesh { + GDCLASS(BoxMesh, PrimitiveMesh); private: Vector3 size; @@ -158,7 +158,7 @@ public: void set_subdivide_depth(const int p_divisions); int get_subdivide_depth() const; - CubeMesh(); + BoxMesh(); }; /** diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index cf8be8fe15..58645dbe65 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -704,7 +704,6 @@ ResourceLoaderText::ResourceLoaderText() { resources_total = 0; resource_current = 0; - use_sub_threads = false; progress = nullptr; lines = false; diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 69e8e0b5bd..05bb13a1e0 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -568,7 +568,7 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() { code += "\tCOLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));\n"; code += "\tCOLOR *= exposure;\n"; code += "\t// Make optional, eliminates banding\n"; - code += "\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.008 * dither_strength;\n"; + code += "\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength;\n"; code += "}\n"; shader = RS::get_singleton()->shader_create(); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index a8bf44c5c0..14197c6c68 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -404,16 +404,6 @@ void StyleBoxFlat::set_corner_radius_individual(const int radius_top_left, const emit_changed(); } -int StyleBoxFlat::get_corner_radius_min() const { - int smallest = corner_radius[0]; - for (int i = 1; i < 4; i++) { - if (smallest > corner_radius[i]) { - smallest = corner_radius[i]; - } - } - return smallest; -} - void StyleBoxFlat::set_corner_radius(const Corner p_corner, const int radius) { ERR_FAIL_INDEX((int)p_corner, 4); corner_radius[p_corner] = radius; diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index a1237776c6..7dd806e840 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -184,7 +184,6 @@ public: //CORNER void set_corner_radius_all(int radius); void set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_botton_right, const int radius_bottom_left); - int get_corner_radius_min() const; void set_corner_radius(Corner p_corner, const int radius); int get_corner_radius(Corner p_corner) const; diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 3166067573..129f8a48ce 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -33,6 +33,9 @@ #define _VERTEX_SNAP 0.0001 #define EQ_VERTEX_DIST 0.00001 +SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr; +SurfaceTool::SimplifyFunc SurfaceTool::simplify_func = nullptr; + bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const { if (vertex != p_vertex.vertex) { return false; @@ -74,12 +77,16 @@ bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const { } } - for (int i = 0; i < RS::ARRAY_CUSTOM_MAX; i++) { + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { if (custom[i] != p_vertex.custom[i]) { return false; } } + if (smooth_group != p_vertex.smooth_group) { + return false; + } + return true; } @@ -94,6 +101,7 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) { h = hash_djb2_buffer((const uint8_t *)p_vtx.bones.ptr(), p_vtx.bones.size() * sizeof(int), h); h = hash_djb2_buffer((const uint8_t *)p_vtx.weights.ptr(), p_vtx.weights.size() * sizeof(float), h); h = hash_djb2_buffer((const uint8_t *)&p_vtx.custom[0], sizeof(Color) * RS::ARRAY_CUSTOM_COUNT, h); + h = hash_djb2_one_32(p_vtx.smooth_group, h); return h; } @@ -118,6 +126,8 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) { vtx.bones = last_bones; vtx.tangent = last_tangent.normal; vtx.binormal = last_normal.cross(last_tangent.normal).normalized() * last_tangent.d; + vtx.smooth_group = last_smooth_group; + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { vtx.custom[i] = last_custom[i]; } @@ -252,13 +262,8 @@ void SurfaceTool::set_weights(const Vector<float> &p_weights) { last_weights = p_weights; } -void SurfaceTool::add_smooth_group(bool p_smooth) { - ERR_FAIL_COND(!begun); - if (index_array.size()) { - smooth_groups[index_array.size()] = p_smooth; - } else { - smooth_groups[vertex_array.size()] = p_smooth; - } +void SurfaceTool::set_smooth_group(uint32_t p_group) { + last_smooth_group = p_group; } void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<Color> &p_colors, const Vector<Vector2> &p_uv2s, const Vector<Vector3> &p_normals, const Vector<Plane> &p_tangents) { @@ -315,9 +320,8 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len); Vector3 *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; switch (i) { case Mesh::ARRAY_VERTEX: { @@ -339,9 +343,8 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len); Vector2 *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; switch (i) { case Mesh::ARRAY_TEX_UV: { @@ -360,9 +363,8 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * 4); float *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; w[idx + 0] = v.tangent.x; w[idx + 1] = v.tangent.y; @@ -381,9 +383,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len); Color *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + w[idx] = v.color; } @@ -400,9 +402,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * 4); uint8_t *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + const Color &c = v.custom[idx]; w[idx * 4 + 0] = CLAMP(int32_t(c.r * 255.0), 0, 255); w[idx * 4 + 1] = CLAMP(int32_t(c.g * 255.0), 0, 255); @@ -417,9 +419,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * 4); uint8_t *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + const Color &c = v.custom[idx]; w[idx * 4 + 0] = uint8_t(int8_t(CLAMP(int32_t(c.r * 127.0), -128, 127))); w[idx * 4 + 1] = uint8_t(int8_t(CLAMP(int32_t(c.g * 127.0), -128, 127))); @@ -434,9 +436,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * 4); uint16_t *w = (uint16_t *)array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + const Color &c = v.custom[idx]; w[idx * 2 + 0] = Math::make_half_float(c.r); w[idx * 2 + 1] = Math::make_half_float(c.g); @@ -449,9 +451,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * 8); uint16_t *w = (uint16_t *)array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + const Color &c = v.custom[idx]; w[idx * 4 + 0] = Math::make_half_float(c.r); w[idx * 4 + 1] = Math::make_half_float(c.g); @@ -466,9 +468,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len); float *w = (float *)array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + const Color &c = v.custom[idx]; w[idx] = c.r; } @@ -480,9 +482,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * 2); float *w = (float *)array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + const Color &c = v.custom[idx]; w[idx * 2 + 0] = c.r; w[idx * 2 + 1] = c.g; @@ -495,9 +497,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * 3); float *w = (float *)array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + const Color &c = v.custom[idx]; w[idx * 3 + 0] = c.r; w[idx * 3 + 1] = c.g; @@ -511,9 +513,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * 4); float *w = (float *)array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + const Color &c = v.custom[idx]; w[idx * 4 + 0] = c.r; w[idx * 4 + 1] = c.g; @@ -533,9 +535,8 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * count); int *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += count) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; ERR_CONTINUE(v.bones.size() != count); @@ -554,9 +555,9 @@ Array SurfaceTool::commit_to_arrays() { array.resize(varr_len * count); float *w = array.ptrw(); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += count) { - const Vertex &v = E->get(); + for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { + const Vertex &v = vertex_array[idx]; + ERR_CONTINUE(v.weights.size() != count); for (int j = 0; j < count; j++) { @@ -574,9 +575,8 @@ Array SurfaceTool::commit_to_arrays() { array.resize(index_array.size()); int *w = array.ptrw(); - int idx = 0; - for (List<int>::Element *E = index_array.front(); E; E = E->next(), idx++) { - w[idx] = E->get(); + for (uint32_t idx = 0; idx < index_array.size(); idx++) { + w[idx] = index_array[idx]; } a[i] = array; @@ -623,15 +623,16 @@ void SurfaceTool::index() { } HashMap<Vertex, int, VertexHasher> indices; - List<Vertex> new_vertices; + LocalVector<Vertex> old_vertex_array = vertex_array; + vertex_array.clear(); - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) { - int *idxptr = indices.getptr(E->get()); + for (uint32_t i = 0; i < old_vertex_array.size(); i++) { + int *idxptr = indices.getptr(old_vertex_array[i]); int idx; if (!idxptr) { idx = indices.size(); - new_vertices.push_back(E->get()); - indices[E->get()] = idx; + vertex_array.push_back(old_vertex_array[i]); + indices[old_vertex_array[i]] = idx; } else { idx = *idxptr; } @@ -639,9 +640,6 @@ void SurfaceTool::index() { index_array.push_back(idx); } - vertex_array.clear(); - vertex_array = new_vertices; - format |= Mesh::ARRAY_FORMAT_INDEX; } @@ -649,29 +647,26 @@ void SurfaceTool::deindex() { if (index_array.size() == 0) { return; //nothing to deindex } - Vector<Vertex> varr; - varr.resize(vertex_array.size()); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) { - varr.write[idx++] = E->get(); - } + + LocalVector<Vertex> old_vertex_array = vertex_array; vertex_array.clear(); - for (List<int>::Element *E = index_array.front(); E; E = E->next()) { - ERR_FAIL_INDEX(E->get(), varr.size()); - vertex_array.push_back(varr[E->get()]); + for (uint32_t i = 0; i < index_array.size(); i++) { + uint32_t index = index_array[i]; + ERR_FAIL_COND(index >= old_vertex_array.size()); + vertex_array.push_back(old_vertex_array[index]); } format &= ~Mesh::ARRAY_FORMAT_INDEX; index_array.clear(); } -void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat) { +void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) { Array arr = p_existing->surface_get_arrays(p_surface); ERR_FAIL_COND(arr.size() != RS::ARRAY_MAX); _create_list_from_arrays(arr, r_vertex, r_index, lformat); } -Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays, uint32_t *r_format) { - Vector<SurfaceTool::Vertex> ret; +void SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector<SurfaceTool::Vertex> &ret, uint32_t *r_format) { + ret.clear(); Vector<Vector3> varr = p_arrays[RS::ARRAY_VERTEX]; Vector<Vector3> narr = p_arrays[RS::ARRAY_NORMAL]; @@ -688,7 +683,7 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array if (r_format) { *r_format = 0; } - return ret; + return; } int lformat = 0; @@ -799,19 +794,14 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array if (r_format) { *r_format = lformat; } - - return ret; } -void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat) { - Vector<Vertex> arrays = create_vertex_array_from_triangle_arrays(arr, &lformat); - ERR_FAIL_COND(arrays.size() == 0); - - for (int i = 0; i < arrays.size(); i++) { - r_vertex->push_back(arrays[i]); - } +void SurfaceTool::_create_list_from_arrays(Array arr, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) { + create_vertex_array_from_triangle_arrays(arr, *r_vertex, &lformat); + ERR_FAIL_COND(r_vertex->size() == 0); //indices + r_index->clear(); Vector<int> idx = arr[RS::ARRAY_INDEX]; int is = idx.size(); @@ -864,14 +854,14 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const } uint32_t nformat; - List<Vertex> nvertices; - List<int> nindices; + LocalVector<Vertex> nvertices; + LocalVector<int> nindices; _create_list(p_existing, p_surface, &nvertices, &nindices, nformat); format |= nformat; int vfrom = vertex_array.size(); - for (List<Vertex>::Element *E = nvertices.front(); E; E = E->next()) { - Vertex v = E->get(); + for (uint32_t vi = 0; vi < nvertices.size(); vi++) { + Vertex v = nvertices[vi]; v.vertex = p_xform.xform(v.vertex); if (nformat & RS::ARRAY_FORMAT_NORMAL) { v.normal = p_xform.basis.xform(v.normal); @@ -884,8 +874,8 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const vertex_array.push_back(v); } - for (List<int>::Element *E = nindices.front(); E; E = E->next()) { - int dst_index = E->get() + vfrom; + for (uint32_t i = 0; i < nindices.size(); i++) { + int dst_index = nindices[i] + vfrom; index_array.push_back(dst_index); } if (index_array.size() % 3) { @@ -896,18 +886,18 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const //mikktspace callbacks namespace { struct TangentGenerationContextUserData { - Vector<List<SurfaceTool::Vertex>::Element *> vertices; - Vector<List<int>::Element *> indices; + LocalVector<SurfaceTool::Vertex> *vertices; + LocalVector<int> *indices; }; } // namespace int SurfaceTool::mikktGetNumFaces(const SMikkTSpaceContext *pContext) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); - if (triangle_data.indices.size() > 0) { - return triangle_data.indices.size() / 3; + if (triangle_data.indices->size() > 0) { + return triangle_data.indices->size() / 3; } else { - return triangle_data.vertices.size() / 3; + return triangle_data.vertices->size() / 3; } } @@ -918,13 +908,13 @@ int SurfaceTool::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, c void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); Vector3 v; - if (triangle_data.indices.size() > 0) { - int index = triangle_data.indices[iFace * 3 + iVert]->get(); - if (index < triangle_data.vertices.size()) { - v = triangle_data.vertices[index]->get().vertex; + if (triangle_data.indices->size() > 0) { + uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert); + if (index < triangle_data.vertices->size()) { + v = triangle_data.vertices->operator[](index).vertex; } } else { - v = triangle_data.vertices[iFace * 3 + iVert]->get().vertex; + v = triangle_data.vertices->operator[](iFace * 3 + iVert).vertex; } fvPosOut[0] = v.x; @@ -935,13 +925,13 @@ void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvP void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); Vector3 v; - if (triangle_data.indices.size() > 0) { - int index = triangle_data.indices[iFace * 3 + iVert]->get(); - if (index < triangle_data.vertices.size()) { - v = triangle_data.vertices[index]->get().normal; + if (triangle_data.indices->size() > 0) { + uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert); + if (index < triangle_data.vertices->size()) { + v = triangle_data.vertices->operator[](index).normal; } } else { - v = triangle_data.vertices[iFace * 3 + iVert]->get().normal; + v = triangle_data.vertices->operator[](iFace * 3 + iVert).normal; } fvNormOut[0] = v.x; @@ -952,13 +942,13 @@ void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNor void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); Vector2 v; - if (triangle_data.indices.size() > 0) { - int index = triangle_data.indices[iFace * 3 + iVert]->get(); - if (index < triangle_data.vertices.size()) { - v = triangle_data.vertices[index]->get().uv; + if (triangle_data.indices->size() > 0) { + uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert); + if (index < triangle_data.vertices->size()) { + v = triangle_data.vertices->operator[](index).uv; } } else { - v = triangle_data.vertices[iFace * 3 + iVert]->get().uv; + v = triangle_data.vertices->operator[](iFace * 3 + iVert).uv; } fvTexcOut[0] = v.x; @@ -969,13 +959,13 @@ void SurfaceTool::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, cons const tbool bIsOrientationPreserving, const int iFace, const int iVert) { TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData); Vertex *vtx = nullptr; - if (triangle_data.indices.size() > 0) { - int index = triangle_data.indices[iFace * 3 + iVert]->get(); - if (index < triangle_data.vertices.size()) { - vtx = &triangle_data.vertices[index]->get(); + if (triangle_data.indices->size() > 0) { + uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert); + if (index < triangle_data.vertices->size()) { + vtx = &triangle_data.vertices->operator[](index); } } else { - vtx = &triangle_data.vertices[iFace * 3 + iVert]->get(); + vtx = &triangle_data.vertices->operator[](iFace * 3 + iVert); } if (vtx != nullptr) { @@ -1001,18 +991,12 @@ void SurfaceTool::generate_tangents() { msc.m_pInterface = &mkif; TangentGenerationContextUserData triangle_data; - triangle_data.vertices.resize(vertex_array.size()); - int idx = 0; - for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) { - triangle_data.vertices.write[idx++] = E; - E->get().binormal = Vector3(); - E->get().tangent = Vector3(); - } - triangle_data.indices.resize(index_array.size()); - idx = 0; - for (List<int>::Element *E = index_array.front(); E; E = E->next()) { - triangle_data.indices.write[idx++] = E; + triangle_data.vertices = &vertex_array; + for (uint32_t i = 0; i < vertex_array.size(); i++) { + vertex_array[i].binormal = Vector3(); + vertex_array[i].tangent = Vector3(); } + triangle_data.indices = &index_array; msc.m_pUserData = &triangle_data; bool res = genTangSpaceDefault(&msc); @@ -1028,66 +1012,36 @@ void SurfaceTool::generate_normals(bool p_flip) { deindex(); - HashMap<Vertex, Vector3, VertexHasher> vertex_hash; + ERR_FAIL_COND((vertex_array.size() % 3) != 0); - int count = 0; - bool smooth = false; - if (smooth_groups.has(0)) { - smooth = smooth_groups[0]; - } + HashMap<Vertex, Vector3, VertexHasher> vertex_hash; - List<Vertex>::Element *B = vertex_array.front(); - for (List<Vertex>::Element *E = B; E;) { - List<Vertex>::Element *v[3]; - v[0] = E; - v[1] = v[0]->next(); - ERR_FAIL_COND(!v[1]); - v[2] = v[1]->next(); - ERR_FAIL_COND(!v[2]); - E = v[2]->next(); + for (uint32_t vi = 0; vi < vertex_array.size(); vi += 3) { + Vertex *v = &vertex_array[vi]; Vector3 normal; if (!p_flip) { - normal = Plane(v[0]->get().vertex, v[1]->get().vertex, v[2]->get().vertex).normal; + normal = Plane(v[0].vertex, v[1].vertex, v[2].vertex).normal; } else { - normal = Plane(v[2]->get().vertex, v[1]->get().vertex, v[0]->get().vertex).normal; + normal = Plane(v[2].vertex, v[1].vertex, v[0].vertex).normal; } - if (smooth) { - for (int i = 0; i < 3; i++) { - Vector3 *lv = vertex_hash.getptr(v[i]->get()); - if (!lv) { - vertex_hash.set(v[i]->get(), normal); - } else { - (*lv) += normal; - } - } - } else { - for (int i = 0; i < 3; i++) { - v[i]->get().normal = normal; - } - } - count += 3; - - if (smooth_groups.has(count) || !E) { - if (vertex_hash.size()) { - while (B != E) { - Vector3 *lv = vertex_hash.getptr(B->get()); - if (lv) { - B->get().normal = lv->normalized(); - } - - B = B->next(); - } - + for (int i = 0; i < 3; i++) { + Vector3 *lv = vertex_hash.getptr(v[i]); + if (!lv) { + vertex_hash.set(v[i], normal); } else { - B = E; + (*lv) += normal; } + } + } - vertex_hash.clear(); - if (E) { - smooth = smooth_groups[count]; - } + for (uint32_t vi = 0; vi < vertex_array.size(); vi++) { + Vector3 *lv = vertex_hash.getptr(vertex_array[vi]); + if (!lv) { + vertex_array[vi].normal = Vector3(); + } else { + vertex_array[vi].normal = lv->normalized(); } } @@ -1095,7 +1049,6 @@ void SurfaceTool::generate_normals(bool p_flip) { if (was_indexed) { index(); - smooth_groups.clear(); } } @@ -1111,8 +1064,8 @@ void SurfaceTool::clear() { last_weights.clear(); index_array.clear(); vertex_array.clear(); - smooth_groups.clear(); material.unref(); + last_smooth_group = 0; for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { last_custom_format[i] = CUSTOM_MAX; } @@ -1136,6 +1089,51 @@ SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const { ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX); return last_custom_format[p_index]; } +void SurfaceTool::optimize_indices_for_cache() { + ERR_FAIL_COND(optimize_vertex_cache_func == nullptr); + ERR_FAIL_COND(index_array.size() == 0); + + LocalVector old_index_array = index_array; + zeromem(index_array.ptr(), index_array.size() * sizeof(int)); + optimize_vertex_cache_func((unsigned int *)index_array.ptr(), (unsigned int *)old_index_array.ptr(), old_index_array.size(), vertex_array.size()); +} + +float SurfaceTool::get_max_axis_length() const { + ERR_FAIL_COND_V(vertex_array.size() == 0, 0); + + AABB aabb; + for (uint32_t i = 0; i < vertex_array.size(); i++) { + if (i == 0) { + aabb.position = vertex_array[i].vertex; + } else { + aabb.expand_to(vertex_array[i].vertex); + } + } + + return aabb.get_longest_axis_size(); +} +Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_count) { + Vector<int> lod; + + ERR_FAIL_COND_V(simplify_func == nullptr, lod); + ERR_FAIL_COND_V(vertex_array.size() == 0, lod); + ERR_FAIL_COND_V(index_array.size() == 0, lod); + + lod.resize(index_array.size()); + LocalVector<float> vertices; //uses floats + vertices.resize(vertex_array.size() * 3); + for (uint32_t i = 0; i < vertex_array.size(); i++) { + vertices[i * 3 + 0] = vertex_array[i].vertex.x; + vertices[i * 3 + 1] = vertex_array[i].vertex.y; + vertices[i * 3 + 2] = vertex_array[i].vertex.z; + } + + uint32_t index_count = simplify_func((unsigned int *)lod.ptrw(), (unsigned int *)index_array.ptr(), index_array.size(), vertices.ptr(), vertex_array.size(), sizeof(float) * 3, p_target_index_count, p_threshold); + ERR_FAIL_COND_V(index_count == 0, lod); + lod.resize(index_count); + + return lod; +} void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("set_skin_weight_count", "count"), &SurfaceTool::set_skin_weight_count); @@ -1155,7 +1153,7 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bones", "bones"), &SurfaceTool::set_bones); ClassDB::bind_method(D_METHOD("set_weights", "weights"), &SurfaceTool::set_weights); ClassDB::bind_method(D_METHOD("set_custom", "index", "custom"), &SurfaceTool::set_custom); - ClassDB::bind_method(D_METHOD("add_smooth_group", "smooth"), &SurfaceTool::add_smooth_group); + ClassDB::bind_method(D_METHOD("set_smooth_group", "index"), &SurfaceTool::set_smooth_group); ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>())); @@ -1166,6 +1164,11 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("generate_normals", "flip"), &SurfaceTool::generate_normals, DEFVAL(false)); ClassDB::bind_method(D_METHOD("generate_tangents"), &SurfaceTool::generate_tangents); + ClassDB::bind_method(D_METHOD("optimize_indices_for_cache"), &SurfaceTool::optimize_indices_for_cache); + + ClassDB::bind_method(D_METHOD("get_max_axis_length"), &SurfaceTool::get_max_axis_length); + ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3)); + ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material); ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear); diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index 4a5c7d990c..e80a5339a9 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -31,8 +31,8 @@ #ifndef SURFACE_TOOL_H #define SURFACE_TOOL_H +#include "core/templates/local_vector.h" #include "scene/resources/mesh.h" - #include "thirdparty/misc/mikktspace.h" class SurfaceTool : public Reference { @@ -50,6 +50,7 @@ public: Vector<int> bones; Vector<float> weights; Color custom[RS::ARRAY_CUSTOM_COUNT]; + uint32_t smooth_group = 0; bool operator==(const Vertex &p_vertex) const; @@ -73,6 +74,11 @@ public: SKIN_8_WEIGHTS }; + typedef void (*OptimizeVertexCacheFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, size_t vertex_count); + static OptimizeVertexCacheFunc optimize_vertex_cache_func; + typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error); + static SimplifyFunc simplify_func; + private: struct VertexHasher { static _FORCE_INLINE_ uint32_t hash(const Vertex &p_vtx); @@ -92,9 +98,8 @@ private: uint32_t format; Ref<Material> material; //arrays - List<Vertex> vertex_array; - List<int> index_array; - Map<int, bool> smooth_groups; + LocalVector<Vertex> vertex_array; + LocalVector<int> index_array; //memory Color last_color; @@ -104,6 +109,7 @@ private: Vector<int> last_bones; Vector<float> last_weights; Plane last_tangent; + uint32_t last_smooth_group = 0; SkinWeightCount skin_weights; @@ -111,8 +117,8 @@ private: CustomFormat last_custom_format[RS::ARRAY_CUSTOM_COUNT]; - void _create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat); - void _create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, uint32_t &lformat); + void _create_list_from_arrays(Array arr, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat); + void _create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat); //mikktspace callbacks static int mikktGetNumFaces(const SMikkTSpaceContext *pContext); @@ -143,10 +149,10 @@ public: void set_custom(int p_index, const Color &p_custom); void set_bones(const Vector<int> &p_bones); void set_weights(const Vector<float> &p_weights); + void set_smooth_group(uint32_t p_group); void add_vertex(const Vector3 &p_vertex); - void add_smooth_group(bool p_smooth); void add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs = Vector<Vector2>(), const Vector<Color> &p_colors = Vector<Color>(), const Vector<Vector2> &p_uv2s = Vector<Vector2>(), const Vector<Vector3> &p_normals = Vector<Vector3>(), const Vector<Plane> &p_tangents = Vector<Plane>()); void add_index(int p_index); @@ -156,14 +162,18 @@ public: void generate_normals(bool p_flip = false); void generate_tangents(); + void optimize_indices_for_cache(); + float get_max_axis_length() const; + Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3); + void set_material(const Ref<Material> &p_material); void clear(); - List<Vertex> &get_vertex_array() { return vertex_array; } + LocalVector<Vertex> &get_vertex_array() { return vertex_array; } void create_from_triangle_arrays(const Array &p_arrays); - static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays, uint32_t *r_format = nullptr); + static void create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector<Vertex> &ret, uint32_t *r_format = nullptr); Array commit_to_arrays(); void create_from(const Ref<Mesh> &p_existing, int p_surface); void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String &p_blend_shape_name); diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp index 5a419bb232..cc9b6758b6 100644 --- a/scene/resources/text_line.cpp +++ b/scene/resources/text_line.cpp @@ -113,6 +113,8 @@ RID TextLine::get_rid() const { void TextLine::clear() { TS->shaped_text_clear(rid); + spacing_top = 0; + spacing_bottom = 0; } void TextLine::set_preserve_invalid(bool p_enabled) { @@ -166,6 +168,8 @@ void TextLine::set_bidi_override(const Vector<Vector2i> &p_override) { bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); + spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); dirty = true; return res; } @@ -233,17 +237,21 @@ float TextLine::get_width() const { Size2 TextLine::get_size() const { const_cast<TextLine *>(this)->_shape(); - return TS->shaped_text_get_size(rid); + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom); + } else { + return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y); + } } float TextLine::get_line_ascent() const { const_cast<TextLine *>(this)->_shape(); - return TS->shaped_text_get_ascent(rid); + return TS->shaped_text_get_ascent(rid) + spacing_top; } float TextLine::get_line_descent() const { const_cast<TextLine *>(this)->_shape(); - return TS->shaped_text_get_descent(rid); + return TS->shaped_text_get_descent(rid) + spacing_bottom; } float TextLine::get_line_width() const { @@ -291,10 +299,10 @@ void TextLine::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color) co float clip_l; if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { - ofs.y += TS->shaped_text_get_ascent(rid); + ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top; clip_l = MAX(0, p_pos.x - ofs.x); } else { - ofs.x += TS->shaped_text_get_ascent(rid); + ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top; clip_l = MAX(0, p_pos.y - ofs.y); } return TS->shaped_text_draw(rid, p_canvas, ofs, clip_l, clip_l + width, p_color); @@ -330,10 +338,10 @@ void TextLine::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_si float clip_l; if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { - ofs.y += TS->shaped_text_get_ascent(rid); + ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top; clip_l = MAX(0, p_pos.x - ofs.x); } else { - ofs.x += TS->shaped_text_get_ascent(rid); + ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top; clip_l = MAX(0, p_pos.y - ofs.y); } return TS->shaped_text_draw_outline(rid, p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color); @@ -347,6 +355,8 @@ int TextLine::hit_test(float p_coords) const { TextLine::TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, TextServer::Direction p_direction, TextServer::Orientation p_orientation) { rid = TS->create_shaped_text(p_direction, p_orientation); + spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); + spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); } diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h index ffa06cc5c1..6ed3558bd9 100644 --- a/scene/resources/text_line.h +++ b/scene/resources/text_line.h @@ -40,6 +40,8 @@ class TextLine : public Reference { GDCLASS(TextLine, Reference); RID rid; + int spacing_top = 0; + int spacing_bottom = 0; bool dirty = true; diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp index d4f96ff9e8..fd6dd071eb 100644 --- a/scene/resources/text_paragraph.cpp +++ b/scene/resources/text_paragraph.cpp @@ -140,6 +140,8 @@ RID TextParagraph::get_line_rid(int p_line) const { } void TextParagraph::clear() { + spacing_top = 0; + spacing_bottom = 0; for (int i = 0; i < lines.size(); i++) { TS->free(lines[i]); } @@ -187,6 +189,8 @@ TextServer::Orientation TextParagraph::get_orientation() const { bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); + spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); dirty_lines = true; return res; } @@ -260,7 +264,11 @@ float TextParagraph::get_width() const { Size2 TextParagraph::get_non_wraped_size() const { const_cast<TextParagraph *>(this)->_shape_lines(); - return TS->shaped_text_get_size(rid); + if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { + return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom); + } else { + return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y); + } } Size2 TextParagraph::get_size() const { @@ -270,9 +278,9 @@ Size2 TextParagraph::get_size() const { Size2 lsize = TS->shaped_text_get_size(lines[i]); if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { size.x = MAX(size.x, lsize.x); - size.y += lsize.y; + size.y += lsize.y + spacing_top + spacing_bottom; } else { - size.x += lsize.x; + size.x += lsize.x + spacing_top + spacing_bottom; size.y = MAX(size.y, lsize.y); } } @@ -297,9 +305,9 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const { for (int i = 0; i < p_line; i++) { Size2 lsize = TS->shaped_text_get_size(lines[i]); if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { - xrect.position.y += lsize.y; + xrect.position.y += lsize.y + spacing_top + spacing_bottom; } else { - xrect.position.x += lsize.x; + xrect.position.x += lsize.x + spacing_top + spacing_bottom; } } return xrect; @@ -308,7 +316,11 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const { Size2 TextParagraph::get_line_size(int p_line) const { const_cast<TextParagraph *>(this)->_shape_lines(); ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Size2()); - return TS->shaped_text_get_size(lines[p_line]); + if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) { + return Size2(TS->shaped_text_get_size(lines[p_line]).x, TS->shaped_text_get_size(lines[p_line]).y + spacing_top + spacing_bottom); + } else { + return Size2(TS->shaped_text_get_size(lines[p_line]).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(lines[p_line]).y); + } } Vector2i TextParagraph::get_line_range(int p_line) const { @@ -320,13 +332,13 @@ Vector2i TextParagraph::get_line_range(int p_line) const { float TextParagraph::get_line_ascent(int p_line) const { const_cast<TextParagraph *>(this)->_shape_lines(); ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f); - return TS->shaped_text_get_ascent(lines[p_line]); + return TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; } float TextParagraph::get_line_descent(int p_line) const { const_cast<TextParagraph *>(this)->_shape_lines(); ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f); - return TS->shaped_text_get_descent(lines[p_line]); + return TS->shaped_text_get_descent(lines[p_line]) + spacing_bottom; } float TextParagraph::get_line_width(int p_line) const { @@ -353,10 +365,10 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo for (int i = 0; i < lines.size(); i++) { if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { ofs.x = p_pos.x; - ofs.y += TS->shaped_text_get_ascent(lines[i]); + ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top; } else { ofs.y = p_pos.y; - ofs.x += TS->shaped_text_get_ascent(lines[i]); + ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top; } float length = TS->shaped_text_get_width(lines[i]); if (width > 0) { @@ -389,10 +401,10 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo TS->shaped_text_draw(lines[i], p_canvas, ofs, clip_l, clip_l + width, p_color); if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { ofs.x = p_pos.x; - ofs.y += TS->shaped_text_get_descent(lines[i]); + ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; } else { ofs.y = p_pos.y; - ofs.x += TS->shaped_text_get_descent(lines[i]); + ofs.x += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; } } } @@ -403,10 +415,10 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli for (int i = 0; i < lines.size(); i++) { if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { ofs.x = p_pos.x; - ofs.y += TS->shaped_text_get_ascent(lines[i]); + ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top; } else { ofs.y = p_pos.y; - ofs.x += TS->shaped_text_get_ascent(lines[i]); + ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top; } float length = TS->shaped_text_get_width(lines[i]); if (width > 0) { @@ -439,10 +451,10 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli TS->shaped_text_draw_outline(lines[i], p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color); if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { ofs.x = p_pos.x; - ofs.y += TS->shaped_text_get_descent(lines[i]); + ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; } else { ofs.y = p_pos.y; - ofs.x += TS->shaped_text_get_descent(lines[i]); + ofs.x += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; } } } @@ -462,10 +474,12 @@ int TextParagraph::hit_test(const Point2 &p_coords) const { if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines[i]).y)) { return TS->shaped_text_hit_test_position(lines[i], p_coords.x); } + ofs.y += TS->shaped_text_get_size(lines[i]).y + spacing_bottom + spacing_top; } else { if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(lines[i]).x)) { return TS->shaped_text_hit_test_position(lines[i], p_coords.y); } + ofs.y += TS->shaped_text_get_size(lines[i]).x + spacing_bottom + spacing_top; } } return TS->shaped_text_get_range(rid).y; @@ -477,9 +491,9 @@ void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, co Vector2 ofs = p_pos; if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) { - ofs.y += TS->shaped_text_get_ascent(lines[p_line]); + ofs.y += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; } else { - ofs.x += TS->shaped_text_get_ascent(lines[p_line]); + ofs.x += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; } return TS->shaped_text_draw(lines[p_line], p_canvas, ofs, -1, -1, p_color); } @@ -490,9 +504,9 @@ void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_ Vector2 ofs = p_pos; if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) { - ofs.y += TS->shaped_text_get_ascent(lines[p_line]); + ofs.y += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; } else { - ofs.x += TS->shaped_text_get_ascent(lines[p_line]); + ofs.x += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; } return TS->shaped_text_draw_outline(lines[p_line], p_canvas, ofs, -1, -1, p_outline_size, p_color); } @@ -500,8 +514,9 @@ void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_ TextParagraph::TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, float p_width, TextServer::Direction p_direction, TextServer::Orientation p_orientation) { rid = TS->create_shaped_text(p_direction, p_orientation); TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); + spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); width = p_width; - dirty_lines = true; } TextParagraph::TextParagraph() { diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h index 587bb6bfc1..f7f49e9058 100644 --- a/scene/resources/text_paragraph.h +++ b/scene/resources/text_paragraph.h @@ -41,6 +41,8 @@ class TextParagraph : public Reference { RID rid; Vector<RID> lines; + int spacing_top = 0; + int spacing_bottom = 0; bool dirty_lines = true; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index d130470275..6a752d32e7 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -421,52 +421,6 @@ void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) cons } } -void Theme::set_shader(const StringName &p_name, const StringName &p_node_type, const Ref<Shader> &p_shader) { - bool new_value = !shader_map.has(p_node_type) || !shader_map[p_node_type].has(p_name); - - shader_map[p_node_type][p_name] = p_shader; - - if (new_value) { - _change_notify(); - emit_changed(); - } -} - -Ref<Shader> Theme::get_shader(const StringName &p_name, const StringName &p_node_type) const { - if (shader_map.has(p_node_type) && shader_map[p_node_type].has(p_name) && shader_map[p_node_type][p_name].is_valid()) { - return shader_map[p_node_type][p_name]; - } else { - return nullptr; - } -} - -bool Theme::has_shader(const StringName &p_name, const StringName &p_node_type) const { - return (shader_map.has(p_node_type) && shader_map[p_node_type].has(p_name) && shader_map[p_node_type][p_name].is_valid()); -} - -void Theme::clear_shader(const StringName &p_name, const StringName &p_node_type) { - ERR_FAIL_COND(!shader_map.has(p_node_type)); - ERR_FAIL_COND(!shader_map[p_node_type].has(p_name)); - - shader_map[p_node_type].erase(p_name); - _change_notify(); - emit_changed(); -} - -void Theme::get_shader_list(const StringName &p_node_type, List<StringName> *p_list) const { - ERR_FAIL_NULL(p_list); - - if (!shader_map.has(p_node_type)) { - return; - } - - const StringName *key = nullptr; - - while ((key = shader_map[p_node_type].next(key))) { - p_list->push_back(*key); - } -} - void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style) { //ERR_FAIL_COND(p_style.is_null()); @@ -782,7 +736,6 @@ void Theme::clear() { icon_map.clear(); style_map.clear(); font_map.clear(); - shader_map.clear(); color_map.clear(); constant_map.clear(); @@ -837,7 +790,6 @@ void Theme::copy_theme(const Ref<Theme> &p_other) { color_map = p_other->color_map; constant_map = p_other->constant_map; - shader_map = p_other->shader_map; _change_notify(); emit_changed(); diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 4175e19112..6ac47e8931 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -34,7 +34,6 @@ #include "core/io/resource.h" #include "core/io/resource_loader.h" #include "scene/resources/font.h" -#include "scene/resources/shader.h" #include "scene/resources/style_box.h" #include "scene/resources/texture.h" @@ -48,7 +47,6 @@ class Theme : public Resource { HashMap<StringName, HashMap<StringName, Ref<StyleBox>>> style_map; HashMap<StringName, HashMap<StringName, Ref<Font>>> font_map; HashMap<StringName, HashMap<StringName, int>> font_size_map; - HashMap<StringName, HashMap<StringName, Ref<Shader>>> shader_map; HashMap<StringName, HashMap<StringName, Color>> color_map; HashMap<StringName, HashMap<StringName, int>> constant_map; @@ -102,12 +100,6 @@ public: void clear_icon(const StringName &p_name, const StringName &p_node_type); void get_icon_list(StringName p_node_type, List<StringName> *p_list) const; - void set_shader(const StringName &p_name, const StringName &p_node_type, const Ref<Shader> &p_shader); - Ref<Shader> get_shader(const StringName &p_name, const StringName &p_node_type) const; - bool has_shader(const StringName &p_name, const StringName &p_node_type) const; - void clear_shader(const StringName &p_name, const StringName &p_node_type); - void get_shader_list(const StringName &p_node_type, List<StringName> *p_list) const; - void set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style); Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_node_type) const; bool has_stylebox(const StringName &p_name, const StringName &p_node_type) const; diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index c1dd59533d..a72066e7a8 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -41,7 +41,7 @@ SceneStringNames::SceneStringNames() { doubledot = StaticCString::create(".."); draw = StaticCString::create("draw"); _draw = StaticCString::create("_draw"); - hide = StaticCString::create("hide"); + hidden = StaticCString::create("hidden"); visibility_changed = StaticCString::create("visibility_changed"); input_event = StaticCString::create("input_event"); shader = StaticCString::create("shader"); diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 80ead560be..b4d2429d7f 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -58,7 +58,7 @@ public: StringName dot; StringName doubledot; StringName draw; - StringName hide; + StringName hidden; StringName visibility_changed; StringName input_event; StringName _input_event; diff --git a/servers/camera_server.h b/servers/camera_server.h index 54acce006a..e09b883eee 100644 --- a/servers/camera_server.h +++ b/servers/camera_server.h @@ -95,15 +95,16 @@ public: int get_feed_index(int p_id); Ref<CameraFeed> get_feed_by_id(int p_id); - // add and remove feeds + // Add and remove feeds. void add_feed(const Ref<CameraFeed> &p_feed); void remove_feed(const Ref<CameraFeed> &p_feed); - // get our feeds + // Get our feeds. Ref<CameraFeed> get_feed(int p_index); int get_feed_count(); Array get_feeds(); + // Intended for use with custom CameraServer implementation. RID feed_texture(int p_id, FeedImage p_texture); CameraServer(); diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h index cc1423a1cb..7b98177066 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h @@ -103,19 +103,6 @@ public: m_enableLimit = false; } - G6DOFRotationalLimitMotor3DSW(const G6DOFRotationalLimitMotor3DSW &limot) { - m_targetVelocity = limot.m_targetVelocity; - m_maxMotorForce = limot.m_maxMotorForce; - m_limitSoftness = limot.m_limitSoftness; - m_loLimit = limot.m_loLimit; - m_hiLimit = limot.m_hiLimit; - m_ERP = limot.m_ERP; - m_bounce = limot.m_bounce; - m_currentLimit = limot.m_currentLimit; - m_currentLimitError = limot.m_currentLimitError; - m_enableMotor = limot.m_enableMotor; - } - //! Is limited bool isLimited() { return (m_loLimit < m_hiLimit); @@ -163,16 +150,6 @@ public: enable_limit[2] = true; } - G6DOFTranslationalLimitMotor3DSW(const G6DOFTranslationalLimitMotor3DSW &other) { - m_lowerLimit = other.m_lowerLimit; - m_upperLimit = other.m_upperLimit; - m_accumulatedImpulse = other.m_accumulatedImpulse; - - m_limitSoftness = other.m_limitSoftness; - m_damping = other.m_damping; - m_restitution = other.m_restitution; - } - //! Test limit /*! - free means upper < lower, @@ -242,11 +219,8 @@ protected: //!@} - Generic6DOFJoint3DSW &operator=(Generic6DOFJoint3DSW &other) { - ERR_PRINT("pito"); - (void)other; - return *this; - } + Generic6DOFJoint3DSW(Generic6DOFJoint3DSW const &) = delete; + void operator=(Generic6DOFJoint3DSW const &) = delete; void buildLinearJacobian( JacobianEntry3DSW &jacLinear, const Vector3 &normalWorld, diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 506310b04a..cbb000cb8c 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -67,7 +67,7 @@ RID EffectsRD::_get_uniform_set_from_image(RID p_image) { } Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(p_image); uniforms.push_back(u); @@ -89,7 +89,7 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture); @@ -112,7 +112,7 @@ RID EffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_m Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture); @@ -140,7 +140,7 @@ RID EffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_texture1, RID p_ Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture1); @@ -148,7 +148,7 @@ RID EffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_texture1, RID p_ } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 1; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture2); @@ -177,14 +177,14 @@ RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_te Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(p_texture1); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(p_texture2); uniforms.push_back(u); @@ -1171,7 +1171,7 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, Vector<RD::Uniform> uniforms; for (int i = 0; i < p_dest_cubemap.size(); i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = i; u.ids.push_back(p_dest_cubemap[i]); uniforms.push_back(u); @@ -1591,7 +1591,7 @@ EffectsRD::EffectsRD() { Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(filter.coefficient_buffer); uniforms.push_back(u); diff --git a/servers/rendering/renderer_rd/light_cluster_builder.cpp b/servers/rendering/renderer_rd/light_cluster_builder.cpp index efb48e6df7..b76b41ba26 100644 --- a/servers/rendering/renderer_rd/light_cluster_builder.cpp +++ b/servers/rendering/renderer_rd/light_cluster_builder.cpp @@ -190,7 +190,7 @@ void LightClusterBuilder::setup(uint32_t p_width, uint32_t p_height, uint32_t p_ { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R32G32B32A32_UINT; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.width = width; tf.height = height; tf.depth = depth; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 5e74835fd8..8fa56b182c 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1022,7 +1022,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 1; u.ids.push_back(state.canvas_state_buffer); uniforms.push_back(u); @@ -1030,7 +1030,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 2; u.ids.push_back(state.lights_uniform_buffer); uniforms.push_back(u); @@ -1038,7 +1038,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; u.ids.push_back(storage->decal_atlas_get_texture()); uniforms.push_back(u); @@ -1046,7 +1046,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 4; u.ids.push_back(state.shadow_texture); uniforms.push_back(u); @@ -1054,7 +1054,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 5; u.ids.push_back(state.shadow_sampler); uniforms.push_back(u); @@ -1062,7 +1062,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 6; RID screen; if (p_backbuffer) { @@ -1079,7 +1079,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 7; RID sdf = storage->render_target_get_sdf_texture(p_to_render_target); u.ids.push_back(sdf); @@ -1089,7 +1089,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo { //needs samplers for the material (uses custom textures) create them RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 8; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -1110,7 +1110,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 9; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); @@ -1564,7 +1564,7 @@ void RendererCanvasRenderRD::_update_shadow_atlas() { { //texture RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = state.shadow_texture_size; tf.height = state.max_lights_per_render * 2; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -1575,7 +1575,7 @@ void RendererCanvasRenderRD::_update_shadow_atlas() { } { RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = state.shadow_texture_size; tf.height = state.max_lights_per_render * 2; tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; @@ -2320,7 +2320,7 @@ void RendererCanvasRenderRD::MaterialData::update_parameters(const Map<StringNam { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -2329,7 +2329,7 @@ void RendererCanvasRenderRD::MaterialData::update_parameters(const Map<StringNam const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -2667,7 +2667,7 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) { { //default shadow texture to keep uniform set happy RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = 4; tf.height = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -2681,7 +2681,7 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(storage->get_default_rd_storage_buffer()); uniforms.push_back(u); @@ -2740,7 +2740,7 @@ void RendererCanvasRenderRD::set_shadow_texture_size(int p_size) { { //create a default shadow texture to keep uniform set happy (and that it gets erased when a new one is created) RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = 4; tf.height = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 433396d0ff..4ae7e68219 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -47,7 +47,7 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) { Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(copy_viewports_sampler); u.ids.push_back(rd_texture); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp index 304382bbf6..5412688e3f 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp @@ -257,6 +257,9 @@ void RendererSceneRenderForward::ShaderData::set_code(const String &p_code) { RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; for (int k = 0; k < SHADER_VERSION_MAX; k++) { + if (!static_cast<RendererSceneRenderForward *>(singleton)->shader.scene_shader.is_variant_enabled(k)) { + continue; + } RD::PipelineRasterizationState raster_state; raster_state.cull_mode = cull_mode_rd; raster_state.wireframe = wireframe; @@ -479,7 +482,7 @@ void RendererSceneRenderForward::MaterialData::update_parameters(const Map<Strin { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -488,7 +491,7 @@ void RendererSceneRenderForward::MaterialData::update_parameters(const Map<Strin const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -516,11 +519,11 @@ RendererStorageRD::MaterialData *RendererSceneRenderForward::_create_material_fu return material_data; } -RendererSceneRenderForward::RenderBufferDataHighEnd::~RenderBufferDataHighEnd() { +RendererSceneRenderForward::RenderBufferDataForward::~RenderBufferDataForward() { clear(); } -void RendererSceneRenderForward::RenderBufferDataHighEnd::ensure_specular() { +void RendererSceneRenderForward::RenderBufferDataForward::ensure_specular() { if (!specular.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; @@ -574,7 +577,7 @@ void RendererSceneRenderForward::RenderBufferDataHighEnd::ensure_specular() { } } -void RendererSceneRenderForward::RenderBufferDataHighEnd::ensure_gi() { +void RendererSceneRenderForward::RenderBufferDataForward::ensure_gi() { if (!reflection_buffer.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; @@ -587,7 +590,7 @@ void RendererSceneRenderForward::RenderBufferDataHighEnd::ensure_gi() { } } -void RendererSceneRenderForward::RenderBufferDataHighEnd::ensure_giprobe() { +void RendererSceneRenderForward::RenderBufferDataForward::ensure_giprobe() { if (!giprobe_buffer.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8_UINT; @@ -623,7 +626,7 @@ void RendererSceneRenderForward::RenderBufferDataHighEnd::ensure_giprobe() { } } -void RendererSceneRenderForward::RenderBufferDataHighEnd::clear() { +void RendererSceneRenderForward::RenderBufferDataForward::clear() { if (ambient_buffer != RID() && ambient_buffer != color) { RD::get_singleton()->free(ambient_buffer); ambient_buffer = RID(); @@ -687,7 +690,7 @@ void RendererSceneRenderForward::RenderBufferDataHighEnd::clear() { } } -void RendererSceneRenderForward::RenderBufferDataHighEnd::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { +void RendererSceneRenderForward::RenderBufferDataForward::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { clear(); msaa = p_msaa; @@ -717,7 +720,7 @@ void RendererSceneRenderForward::RenderBufferDataHighEnd::configure(RID p_color_ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = p_width; tf.height = p_height; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = { @@ -754,7 +757,7 @@ void RendererSceneRenderForward::RenderBufferDataHighEnd::configure(RID p_color_ } } -void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBufferDataHighEnd *rb) { +void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) { if (rb->normal_roughness_buffer.is_valid()) { return; } @@ -793,7 +796,7 @@ void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBuffer } RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForward::_create_render_buffer_data() { - return memnew(RenderBufferDataHighEnd); + return memnew(RenderBufferDataForward); } bool RendererSceneRenderForward::free(RID p_rid) { @@ -911,7 +914,7 @@ void RendererSceneRenderForward::_fill_instances(RenderList::Element **p_element id.flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; } - if (!e->instance->gi_probe_instances.empty()) { + if (!low_end && !e->instance->gi_probe_instances.empty()) { uint32_t written = 0; for (int j = 0; j < e->instance->gi_probe_instances.size(); j++) { RID probe = e->instance->gi_probe_instances[j]; @@ -950,23 +953,13 @@ void RendererSceneRenderForward::_fill_instances(RenderList::Element **p_element /// RENDERING /// -void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set, bool p_force_wireframe, const Vector2 &p_uv_offset) { +void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe, const Vector2 &p_uv_offset) { RD::DrawListID draw_list = p_draw_list; RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; //global scope bindings RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET); - if (p_radiance_uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_radiance_uniform_set, RADIANCE_UNIFORM_SET); - } else { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_radiance_uniform_set, RADIANCE_UNIFORM_SET); - } - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, view_dependant_uniform_set, VIEW_DEPENDANT_UNIFORM_SET); - if (p_render_buffers_uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET); - } else { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET); - } + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_render_pass_uniform_set, RENDER_PASS_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET); MaterialData *prev_material = nullptr; @@ -1214,7 +1207,7 @@ void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_ren scene_state.ubo.fog_enabled = false; if (p_render_buffers.is_valid()) { - RenderBufferDataHighEnd *render_buffers = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); + RenderBufferDataForward *render_buffers = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) { scene_state.ubo.gi_upscale_for_msaa = true; } @@ -1639,9 +1632,9 @@ void RendererSceneRenderForward::_setup_lightmaps(InstanceBase **p_lightmap_cull } void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color) { - RenderBufferDataHighEnd *render_buffer = nullptr; + RenderBufferDataForward *render_buffer = nullptr; if (p_render_buffer.is_valid()) { - render_buffer = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffer); + render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer); } //first of all, make a new render pass @@ -1686,7 +1679,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf opaque_framebuffer = render_buffer->color_fb; - if (p_gi_probe_cull_count > 0) { + if (!low_end && p_gi_probe_cull_count > 0) { using_giprobe = true; render_buffer->ensure_gi(); } @@ -1761,7 +1754,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf render_list.clear(); _fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, using_sdfgi); - bool using_sss = render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; + bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; if (using_sss) { using_separate_specular = true; @@ -1769,7 +1762,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf using_separate_specular = true; opaque_specular_framebuffer = render_buffer->color_specular_fb; } - RID radiance_uniform_set; + RID radiance_texture; bool draw_sky = false; bool draw_sky_fog_only = false; @@ -1831,7 +1824,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf RID sky = environment_get_sky(p_environment); if (sky.is_valid()) { _update_sky(p_environment, projection, p_cam_transform); - radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET); + radiance_texture = sky_get_radiance_texture_rd(sky); } else { // do not try to draw sky if invalid draw_sky = false; @@ -1841,7 +1834,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf clear_color = p_default_bg_color; } - _setup_view_dependant_uniform_set(p_shadow_atlas, p_reflection_atlas, p_gi_probe_cull_result, p_gi_probe_cull_count); + RID rp_uniform_set = _setup_render_pass_uniform_set(p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_gi_probe_cull_result, p_gi_probe_cull_count); render_list.sort_by_key(false); @@ -1850,8 +1843,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES; - bool depth_pre_pass = depth_framebuffer.is_valid(); - RID render_buffers_uniform_set; + bool depth_pre_pass = !low_end && depth_framebuffer.is_valid(); bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment); bool continue_depth = false; @@ -1860,7 +1852,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf bool finish_depth = using_ssao || using_sdfgi || using_giprobe; RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, radiance_uniform_set, RID(), get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); RD::get_singleton()->draw_list_end(); if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { @@ -1884,12 +1876,6 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf _process_gi(p_render_buffer, render_buffer->normal_roughness_buffer, render_buffer->ambient_buffer, render_buffer->reflection_buffer, render_buffer->giprobe_buffer, p_environment, p_cam_projection, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count); } - if (p_render_buffer.is_valid()) { - //update the render buffers uniform set in case it changed - _update_render_buffers_uniform_set(p_render_buffer); - render_buffers_uniform_set = render_buffer->uniform_set; - } - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid()); RENDER_TIMESTAMP("Render Opaque Pass"); @@ -1914,7 +1900,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer; RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); RD::get_singleton()->draw_list_end(); if (will_continue_color && using_separate_specular) { @@ -2002,7 +1988,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); RD::get_singleton()->draw_list_end(); } @@ -2028,7 +2014,7 @@ void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, InstanceBase _fill_render_list(p_cull_result, p_cull_count, pass_mode); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), nullptr, 0); RENDER_TIMESTAMP("Render Shadow"); @@ -2039,7 +2025,7 @@ void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, InstanceBase { //regular forward for now RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, RID(), RID()); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, rp_uniform_set); RD::get_singleton()->draw_list_end(); } } @@ -2061,7 +2047,7 @@ void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, _fill_render_list(p_cull_result, p_cull_count, pass_mode); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), nullptr, 0); RENDER_TIMESTAMP("Render Collider Heightield"); @@ -2072,7 +2058,7 @@ void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, { //regular forward for now RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_fb), render_list.elements, render_list.element_count, false, pass_mode, true, RID(), RID()); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_fb), render_list.elements, render_list.element_count, false, pass_mode, true, rp_uniform_set); RD::get_singleton()->draw_list_end(); } } @@ -2094,7 +2080,7 @@ void RendererSceneRenderForward::_render_material(const Transform &p_cam_transfo PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; _fill_render_list(p_cull_result, p_cull_count, pass_mode); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), nullptr, 0); RENDER_TIMESTAMP("Render Material"); @@ -2111,7 +2097,7 @@ void RendererSceneRenderForward::_render_material(const Transform &p_cam_transfo clear.push_back(Color(0, 0, 0, 0)); clear.push_back(Color(0, 0, 0, 0)); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID()); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set); RD::get_singleton()->draw_list_end(); } } @@ -2133,7 +2119,7 @@ void RendererSceneRenderForward::_render_uv2(InstanceBase **p_cull_result, int p PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; _fill_render_list(p_cull_result, p_cull_count, pass_mode); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), nullptr, 0); RENDER_TIMESTAMP("Render Material"); @@ -2169,9 +2155,9 @@ void RendererSceneRenderForward::_render_uv2(InstanceBase **p_cull_result, int p Vector2 ofs = uv_offsets[i]; ofs.x /= p_region.size.width; ofs.y /= p_region.size.height; - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID(), true, ofs); //first wireframe, for pseudo conservative + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, true, ofs); //first wireframe, for pseudo conservative } - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID(), false); //second regular triangles + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, false); //second regular triangles RD::get_singleton()->draw_list_end(); } @@ -2182,7 +2168,7 @@ void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vecto _update_render_base_uniform_set(); - RenderBufferDataHighEnd *render_buffer = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); + RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); ERR_FAIL_COND(!render_buffer); render_pass++; @@ -2193,45 +2179,11 @@ void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vecto render_list.sort_by_key(false); _fill_instances(render_list.elements, render_list.element_count, true); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture); Vector3 half_extents = p_bounds.size * 0.5; Vector3 center = p_bounds.position + half_extents; - if (render_buffer->render_sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_buffer->render_sdfgi_uniform_set)) { - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 0; - u.ids.push_back(p_albedo_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 1; - u.ids.push_back(p_emission_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 2; - u.ids.push_back(p_emission_aniso_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 3; - u.ids.push_back(p_geom_facing_texture); - uniforms.push_back(u); - } - - render_buffer->render_sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_BUFFERS_UNIFORM_SET); - } - Vector<RID> sbs; sbs.push_back(p_albedo_texture); sbs.push_back(p_emission_texture); @@ -2287,7 +2239,7 @@ void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vecto } RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), sbs); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(E->get()), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), render_buffer->render_sdfgi_uniform_set, false); //second regular triangles + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(E->get()), render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, false); //second regular triangles RD::get_singleton()->draw_list_end(); } } @@ -2311,7 +2263,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 1; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -2333,7 +2285,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(shadow_sampler); uniforms.push_back(u); } @@ -2341,14 +2293,14 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(scene_state.uniform_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(scene_state.instance_buffer); uniforms.push_back(u); } @@ -2356,7 +2308,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_positional_light_buffer()); uniforms.push_back(u); } @@ -2364,42 +2316,42 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 6; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_reflection_probe_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 7; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(get_directional_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 10; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(scene_state.lightmap_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 11; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids = storage->lightmap_array_get_textures(); uniforms.push_back(u); } { RD::Uniform u; u.binding = 12; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(scene_state.lightmap_capture_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 13; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID decal_atlas = storage->decal_atlas_get_texture(); u.ids.push_back(decal_atlas); uniforms.push_back(u); @@ -2407,7 +2359,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 14; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID decal_atlas = storage->decal_atlas_get_texture_srgb(); u.ids.push_back(decal_atlas); uniforms.push_back(u); @@ -2415,7 +2367,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 15; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_decal_buffer()); uniforms.push_back(u); } @@ -2423,14 +2375,14 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 16; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(get_cluster_builder_texture()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 17; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_cluster_builder_indices_buffer()); uniforms.push_back(u); } @@ -2438,7 +2390,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 18; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; if (directional_shadow_get_texture().is_valid()) { u.ids.push_back(directional_shadow_get_texture()); } else { @@ -2449,15 +2401,15 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 19; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); } - { + if (!low_end) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 20; u.ids.push_back(sdfgi_get_ubo()); uniforms.push_back(u); @@ -2467,9 +2419,14 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { } } -void RendererSceneRenderForward::_setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) { - if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) { - RD::get_singleton()->free(view_dependant_uniform_set); +RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) { + if (render_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_set)) { + RD::get_singleton()->free(render_pass_uniform_set); + } + + RenderBufferDataForward *rb = nullptr; + if (p_render_buffers.is_valid()) { + rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); } //default render buffer and scene state uniform set @@ -2477,10 +2434,24 @@ void RendererSceneRenderForward::_setup_view_dependant_uniform_set(RID p_shadow_ Vector<RD::Uniform> uniforms; { - RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); + RID radiance_texture; + if (p_radiance_texture.is_valid()) { + radiance_texture = p_radiance_texture; + } else { + radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + } RD::Uniform u; u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(radiance_texture); + uniforms.push_back(u); + } + + { + RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; if (ref_texture.is_valid()) { u.ids.push_back(ref_texture); } else { @@ -2491,8 +2462,8 @@ void RendererSceneRenderForward::_setup_view_dependant_uniform_set(RID p_shadow_ { RD::Uniform u; - u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture; if (p_shadow_atlas.is_valid()) { texture = shadow_atlas_get_texture(p_shadow_atlas); @@ -2506,8 +2477,9 @@ void RendererSceneRenderForward::_setup_view_dependant_uniform_set(RID p_shadow_ { RD::Uniform u; - u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(MAX_GI_PROBES); RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); for (int i = 0; i < MAX_GI_PROBES; i++) { if (i < p_gi_probe_cull_count) { @@ -2515,84 +2487,47 @@ void RendererSceneRenderForward::_setup_view_dependant_uniform_set(RID p_shadow_ if (!tex.is_valid()) { tex = default_tex; } - u.ids.push_back(tex); + u.ids.write[i] = tex; } else { - u.ids.push_back(default_tex); + u.ids.write[i] = default_tex; } } uniforms.push_back(u); } - view_dependant_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, VIEW_DEPENDANT_UNIFORM_SET); -} -void RendererSceneRenderForward::_render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb) { - if (!rb->uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) { - RD::get_singleton()->free(rb->uniform_set); + { + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = false && rb && rb->depth.is_valid() ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); } - rb->uniform_set = RID(); -} - -void RendererSceneRenderForward::_render_buffers_uniform_set_changed(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - _render_buffers_clear_uniform_set(rb); -} - -RID RendererSceneRenderForward::_render_buffers_get_normal_texture(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - return rb->normal_roughness_buffer; -} - -RID RendererSceneRenderForward::_render_buffers_get_ambient_texture(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - return rb->ambient_buffer; -} - -RID RendererSceneRenderForward::_render_buffers_get_reflection_texture(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - return rb->reflection_buffer; -} - -void RendererSceneRenderForward::_update_render_buffers_uniform_set(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - if (rb->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) { - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = false && rb->depth.is_valid() ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID bbt = render_buffers_get_back_buffer_texture(p_render_buffers); - RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - } + { + RD::Uniform u; + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_buffers) : RID(); + RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } + if (!low_end) { { RD::Uniform u; - u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_NORMAL); + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = rb && rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_NORMAL); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID aot = render_buffers_get_ao_texture(p_render_buffers); + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID aot = rb ? render_buffers_get_ao_texture(p_render_buffers) : RID(); RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); @@ -2600,27 +2535,27 @@ void RendererSceneRenderForward::_update_render_buffers_uniform_set(RID p_render { RD::Uniform u; - u.binding = 5; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb->ambient_buffer.is_valid() ? rb->ambient_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = rb && rb->ambient_buffer.is_valid() ? rb->ambient_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 6; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb->reflection_buffer.is_valid() ? rb->reflection_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.binding = 9; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = rb && rb->reflection_buffer.is_valid() ? rb->reflection_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 7; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 10; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID t; - if (render_buffers_is_sdfgi_enabled(p_render_buffers)) { + if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { t = render_buffers_get_sdfgi_irradiance_probes(p_render_buffers); } else { t = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); @@ -2630,9 +2565,9 @@ void RendererSceneRenderForward::_update_render_buffers_uniform_set(RID p_render } { RD::Uniform u; - u.binding = 8; - u.type = RD::UNIFORM_TYPE_TEXTURE; - if (render_buffers_is_sdfgi_enabled(p_render_buffers)) { + u.binding = 11; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_buffers)); } else { u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); @@ -2641,17 +2576,17 @@ void RendererSceneRenderForward::_update_render_buffers_uniform_set(RID p_render } { RD::Uniform u; - u.binding = 9; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers)); + u.binding = 12; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(rb ? render_buffers_get_default_gi_probe_buffer() : render_buffers_get_gi_probe_buffer(p_render_buffers)); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 10; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 13; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID vfog = RID(); - if (p_render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_buffers)) { + if (rb && render_buffers_has_volumetric_fog(p_render_buffers)) { vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers); if (vfog.is_null()) { vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); @@ -2662,8 +2597,122 @@ void RendererSceneRenderForward::_update_render_buffers_uniform_set(RID p_render u.ids.push_back(vfog); uniforms.push_back(u); } - rb->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET); } + + render_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET); + return render_pass_uniform_set; +} + +RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) { + if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { + RD::get_singleton()->free(sdfgi_pass_uniform_set); + } + + Vector<RD::Uniform> uniforms; + + { + // No radiance texture. + RID radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(radiance_texture); + uniforms.push_back(u); + } + + { + // No reflection atlas. + RID ref_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK); + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(ref_texture); + uniforms.push_back(u); + } + + { + // No shadow atlas. + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + // No GIProbes + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(MAX_GI_PROBES); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + for (int i = 0; i < MAX_GI_PROBES; i++) { + u.ids.write[i] = default_tex; + } + + uniforms.push_back(u); + } + // actual sdfgi stuff + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 4; + u.ids.push_back(p_albedo_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 5; + u.ids.push_back(p_emission_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 6; + u.ids.push_back(p_emission_aniso_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 7; + u.ids.push_back(p_geom_facing_texture); + uniforms.push_back(u); + } + + sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET); + return sdfgi_pass_uniform_set; +} + +void RendererSceneRenderForward::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) { +} + +void RendererSceneRenderForward::_render_buffers_uniform_set_changed(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + _render_buffers_clear_uniform_set(rb); +} + +RID RendererSceneRenderForward::_render_buffers_get_normal_texture(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + return rb->normal_roughness_buffer; +} + +RID RendererSceneRenderForward::_render_buffers_get_ambient_texture(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + return rb->ambient_buffer; +} + +RID RendererSceneRenderForward::_render_buffers_get_reflection_texture(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + return rb->reflection_buffer; } RendererSceneRenderForward *RendererSceneRenderForward::singleton = nullptr; @@ -2676,12 +2725,17 @@ void RendererSceneRenderForward::set_time(double p_time, double p_step) { RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_storage) : RendererSceneRenderRD(p_storage) { singleton = this; + low_end = is_low_end(); storage = p_storage; /* SCENE SHADER */ { String defines; + if (low_end) { + defines += "\n#define LOW_END_MODE \n"; + } + defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; if (is_using_radiance_cubemap_array()) { defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; @@ -2721,6 +2775,16 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor shader_versions.push_back("\n#define USE_LIGHTMAP\n"); shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); shader.scene_shader.initialize(shader_versions, defines); + + if (is_low_end()) { + //disable the high end versions + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); + } } storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs); @@ -2924,7 +2988,9 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); - default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + if (!low_end) { + default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + } } { @@ -2943,7 +3009,7 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256); Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(default_vec4_xform_buffer); u.binding = 0; uniforms.push_back(u); @@ -2958,74 +3024,20 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor sampler.compare_op = RD::COMPARE_OP_LESS; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } - - { - Vector<RD::Uniform> uniforms; - - RD::Uniform u; - u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - - default_radiance_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RADIANCE_UNIFORM_SET); - } - - { //render buffers - Vector<RD::Uniform> uniforms; - for (int i = 0; i < 7; i++) { - RD::Uniform u; - u.binding = i; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(i == 0 ? RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE : (i == 2 ? RendererStorageRD::DEFAULT_RD_TEXTURE_NORMAL : RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK)); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 7; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 8; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 9; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(render_buffers_get_default_gi_probe_buffer()); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 10; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); - uniforms.push_back(u); - } - - default_render_buffers_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET); - } } RendererSceneRenderForward::~RendererSceneRenderForward() { directional_shadow_atlas_set_size(0); //clear base uniform set if still valid - if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) { - RD::get_singleton()->free(view_dependant_uniform_set); + if (render_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_set)) { + RD::get_singleton()->free(render_pass_uniform_set); + } + + if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { + RD::get_singleton()->free(sdfgi_pass_uniform_set); } - RD::get_singleton()->free(default_render_buffers_uniform_set); - RD::get_singleton()->free(default_radiance_uniform_set); RD::get_singleton()->free(default_vec4_xform_buffer); RD::get_singleton()->free(shadow_sampler); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.h b/servers/rendering/renderer_rd/renderer_scene_render_forward.h index 7cea44cd38..6d76d5f0eb 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.h @@ -34,16 +34,14 @@ #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" #include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" -#include "servers/rendering/renderer_rd/shaders/scene_high_end.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/scene_forward.glsl.gen.h" class RendererSceneRenderForward : public RendererSceneRenderRD { enum { SCENE_UNIFORM_SET = 0, - RADIANCE_UNIFORM_SET = 1, - VIEW_DEPENDANT_UNIFORM_SET = 2, - RENDER_BUFFERS_UNIFORM_SET = 3, - TRANSFORMS_UNIFORM_SET = 4, - MATERIAL_UNIFORM_SET = 5 + RENDER_PASS_UNIFORM_SET = 1, + TRANSFORMS_UNIFORM_SET = 2, + MATERIAL_UNIFORM_SET = 3 }; enum { @@ -69,7 +67,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { }; struct { - SceneHighEndShaderRD scene_shader; + SceneForwardShaderRD scene_shader; ShaderCompilerRD compiler; } shader; @@ -209,7 +207,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { /* Framebuffer */ - struct RenderBufferDataHighEnd : public RenderBufferData { + struct RenderBufferDataForward : public RenderBufferData { //for rendering, may be MSAAd RID color; @@ -246,30 +244,29 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { void clear(); virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); - RID uniform_set; - - ~RenderBufferDataHighEnd(); + ~RenderBufferDataForward(); }; virtual RenderBufferData *_create_render_buffer_data(); - void _allocate_normal_roughness_texture(RenderBufferDataHighEnd *rb); + void _allocate_normal_roughness_texture(RenderBufferDataForward *rb); RID shadow_sampler; RID render_base_uniform_set; - RID view_dependant_uniform_set; + RID render_pass_uniform_set; + RID sdfgi_pass_uniform_set; uint64_t lightmap_texture_array_version = 0xFFFFFFFF; virtual void _base_uniforms_changed(); - void _render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb); + void _render_buffers_clear_uniform_set(RenderBufferDataForward *rb); virtual void _render_buffers_uniform_set_changed(RID p_render_buffers); virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); virtual RID _render_buffers_get_ambient_texture(RID p_render_buffers); virtual RID _render_buffers_get_reflection_texture(RID p_render_buffers); void _update_render_base_uniform_set(); - void _setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count); - void _update_render_buffers_uniform_set(RID p_render_buffers); + RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); + RID _setup_render_pass_uniform_set(RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count); struct LightmapData { float normal_xform[12]; @@ -552,8 +549,6 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { RID wireframe_material; RID default_shader_rd; RID default_shader_sdfgi_rd; - RID default_radiance_uniform_set; - RID default_render_buffers_uniform_set; RID default_vec4_xform_buffer; RID default_vec4_xform_uniform_set; @@ -575,7 +570,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { void _setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform); void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth, bool p_has_sdfgi = false, bool p_has_opaque_gi = false); - void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2()); + void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2()); _FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false); _FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false); @@ -583,6 +578,8 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { Map<Size2i, RID> sdfgi_framebuffer_size_cache; + bool low_end = false; + protected: virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color); virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 2804b1337d..f880eb7d8a 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -129,7 +129,7 @@ void RendererSceneRenderRD::_update_reflection_data(ReflectionData &rd, int p_si tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = 64; // Always 64x64 tf.height = 64; - tf.type = RD::TEXTURE_TYPE_CUBE; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.array_layers = 6; tf.mipmaps = 7; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; @@ -284,7 +284,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment tf_sdf.width = sdfgi->cascade_size; // Always 64x64 tf_sdf.height = sdfgi->cascade_size; tf_sdf.depth = sdfgi->cascade_size; - tf_sdf.type = RD::TEXTURE_TYPE_3D; + tf_sdf.texture_type = RD::TEXTURE_TYPE_3D; tf_sdf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; { @@ -341,7 +341,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment tf_probes.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count; tf_probes.height = sdfgi->probe_axis_count * SDFGI::SH_SIZE; tf_probes.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; - tf_probes.type = RD::TEXTURE_TYPE_2D_ARRAY; + tf_probes.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; sdfgi->history_size = requested_history_size; @@ -351,7 +351,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment RD::TextureFormat tf_probe_average = tf_probes; tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed - tf_probe_average.type = RD::TEXTURE_TYPE_2D; + tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D; sdfgi->lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); sdfgi->lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); @@ -378,7 +378,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE tf_ambient.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count; tf_ambient.height = sdfgi->probe_axis_count; - tf_ambient.type = RD::TEXTURE_TYPE_2D_ARRAY; + tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; //lightprobe texture is an octahedral texture sdfgi->ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView()); } @@ -443,21 +443,21 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 1 : 0]); //if passes are even, we read from buffer 0, else we read from buffer 1 uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; for (int j = 0; j < 8; j++) { u.ids.push_back(sdfgi->render_occlusion[j]); @@ -466,21 +466,21 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(sdfgi->render_emission); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(sdfgi->render_emission_aniso); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 6; u.ids.push_back(sdfgi->render_geom_facing); uniforms.push_back(u); @@ -488,28 +488,28 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 7; u.ids.push_back(cascade.sdf_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(sdfgi->occlusion_data); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 10; u.ids.push_back(cascade.solid_cell_dispatch_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 11; u.ids.push_back(cascade.solid_cell_buffer); uniforms.push_back(u); @@ -522,42 +522,42 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_geom_facing); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(sdfgi->render_emission); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(sdfgi->render_emission_aniso); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 5; u.ids.push_back(cascade.solid_cell_dispatch_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 6; u.ids.push_back(cascade.solid_cell_buffer); uniforms.push_back(u); @@ -569,7 +569,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; for (int j = 0; j < 8; j++) { u.ids.push_back(sdfgi->render_occlusion[j]); @@ -578,7 +578,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->occlusion_data); uniforms.push_back(u); @@ -596,7 +596,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex); @@ -609,63 +609,63 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cascade.solid_cell_dispatch_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cascade.solid_cell_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(cascade.light_data); uniforms.push_back(u); } { RD::Uniform u; u.binding = 6; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(cascade.light_aniso_0_tex); uniforms.push_back(u); } { RD::Uniform u; u.binding = 7; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(cascade.light_aniso_1_tex); uniforms.push_back(u); } { RD::Uniform u; u.binding = 8; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb->sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; u.binding = 9; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cascade.lights_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 10; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->lightprobe_texture); uniforms.push_back(u); } @@ -678,14 +678,14 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf[0]); uniforms.push_back(u); @@ -698,14 +698,14 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf_half[0]); uniforms.push_back(u); @@ -719,14 +719,14 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_sdf[0]); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf[1]); uniforms.push_back(u); @@ -741,14 +741,14 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_sdf_half[0]); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf_half[1]); uniforms.push_back(u); @@ -764,21 +764,21 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf_half[(passes & 1) ? 0 : 1]); //reverse pass order because half size uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 0 : 1]); //reverse pass order because it needs an extra JFA pass uniforms.push_back(u); @@ -793,14 +793,14 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; for (int i = 0; i < 8; i++) { u.ids.push_back(sdfgi->render_occlusion[i]); @@ -809,7 +809,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(sdfgi->render_geom_facing); uniforms.push_back(u); @@ -826,7 +826,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].sdf_tex); @@ -839,7 +839,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].light_tex); @@ -852,7 +852,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].light_aniso_0_tex); @@ -865,7 +865,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].light_aniso_1_tex); @@ -877,7 +877,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 6; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -885,14 +885,14 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 7; u.ids.push_back(sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(sdfgi->lightprobe_data); uniforms.push_back(u); @@ -900,14 +900,14 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; u.ids.push_back(sdfgi->cascades[i].lightprobe_history_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 10; u.ids.push_back(sdfgi->cascades[i].lightprobe_average_tex); uniforms.push_back(u); @@ -915,21 +915,21 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 11; u.ids.push_back(sdfgi->lightprobe_history_scroll); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 12; u.ids.push_back(sdfgi->lightprobe_average_scroll); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 13; RID parent_average; if (i < sdfgi->cascades.size() - 1) { @@ -942,7 +942,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 14; u.ids.push_back(sdfgi->ambient_texture); uniforms.push_back(u); @@ -1338,7 +1338,7 @@ void RendererSceneRenderRD::sdfgi_update_probes(RID p_render_buffers, RID p_envi { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; u.ids.push_back(sky->radiance); uniforms.push_back(u); @@ -1346,7 +1346,7 @@ void RendererSceneRenderRD::sdfgi_update_probes(RID p_render_buffers, RID p_envi { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 1; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -1614,7 +1614,7 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex); @@ -1627,7 +1627,7 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].light_tex); @@ -1640,7 +1640,7 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_0_tex); @@ -1653,7 +1653,7 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_1_tex); @@ -1665,7 +1665,7 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 5; if (rb->sdfgi) { u.ids.push_back(rb->sdfgi->occlusion_texture); @@ -1676,14 +1676,14 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 6; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 7; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -1691,7 +1691,7 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; u.ids.push_back(p_ambient_buffer); uniforms.push_back(u); @@ -1699,7 +1699,7 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 10; u.ids.push_back(p_reflection_buffer); uniforms.push_back(u); @@ -1707,7 +1707,7 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 11; if (rb->sdfgi) { u.ids.push_back(rb->sdfgi->lightprobe_texture); @@ -1718,21 +1718,21 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 12; u.ids.push_back(rb->depth_texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 13; u.ids.push_back(p_normal_roughness_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 14; RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(buffer); @@ -1740,21 +1740,21 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 15; u.ids.push_back(gi.sdfgi_ubo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 16; u.ids.push_back(rb->giprobe_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 17; for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { u.ids.push_back(rb->giprobe_textures[i]); @@ -1897,7 +1897,7 @@ void RendererSceneRenderRD::_update_dirty_skys() { RD::TextureFormat tf; tf.array_layers = layers * 6; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; tf.mipmaps = mipmaps; tf.width = w; tf.height = h; @@ -1912,7 +1912,7 @@ void RendererSceneRenderRD::_update_dirty_skys() { RD::TextureFormat tf; tf.array_layers = 6; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.mipmaps = MIN(mipmaps, layers); tf.width = w; tf.height = h; @@ -1932,7 +1932,7 @@ void RendererSceneRenderRD::_update_dirty_skys() { tformat.width = sky->screen_size.x / 2; tformat.height = sky->screen_size.y / 2; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); Vector<RID> texs; @@ -1947,7 +1947,7 @@ void RendererSceneRenderRD::_update_dirty_skys() { tformat.width = sky->screen_size.x / 4; tformat.height = sky->screen_size.y / 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); Vector<RID> texs; @@ -1994,7 +1994,7 @@ RID RendererSceneRenderRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shad Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; u.ids.push_back(sky->radiance); uniforms.push_back(u); @@ -2014,7 +2014,7 @@ RID RendererSceneRenderRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_ Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; if (p_sky->radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) { u.ids.push_back(p_sky->radiance); @@ -2025,7 +2025,7 @@ RID RendererSceneRenderRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_ } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; // half res if (p_sky->half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) { if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { @@ -2044,7 +2044,7 @@ RID RendererSceneRenderRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_ } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; // quarter res if (p_sky->quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) { if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { @@ -2755,7 +2755,7 @@ void RendererSceneRenderRD::SkyMaterialData::update_parameters(const Map<StringN { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -2764,7 +2764,7 @@ void RendererSceneRenderRD::SkyMaterialData::update_parameters(const Map<StringN const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -2971,6 +2971,10 @@ void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS:: Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->sdfgi_enabled = p_enable; env->sdfgi_cascades = p_cascades; env->sdfgi_min_cell_size = p_min_cell_size; @@ -3045,6 +3049,10 @@ void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_ena Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->volumetric_fog_enabled = p_enable; env->volumetric_fog_density = p_density; env->volumetric_fog_light = p_light; @@ -3095,6 +3103,10 @@ void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_ Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->ssr_enabled = p_enable; env->ssr_max_steps = p_max_steps; env->ssr_fade_in = p_fade_int; @@ -3114,6 +3126,10 @@ void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->ssao_enabled = p_enable; env->ssao_radius = p_radius; env->ssao_intensity = p_intensity; @@ -3136,13 +3152,13 @@ bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const { float RendererSceneRenderRD::environment_get_ssao_ao_affect(RID p_env) const { Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, false); + ERR_FAIL_COND_V(!env, 0.0); return env->ssao_ao_channel_affect; } float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const { Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, false); + ERR_FAIL_COND_V(!env, 0.0); return env->ssao_direct_light_affect; } @@ -3331,7 +3347,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc RD::TextureFormat tf; tf.array_layers = 6 * atlas->count; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; tf.mipmaps = mipmaps; tf.width = atlas->size; tf.height = atlas->size; @@ -3948,7 +3964,7 @@ RendererSceneRenderRD::ShadowCubemap *RendererSceneRenderRD::_get_shadow_cubemap tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; tf.width = p_size; tf.height = p_size; - tf.type = RD::TEXTURE_TYPE_CUBE; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.array_layers = 6; tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -4024,6 +4040,10 @@ bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND_V(!gi_probe, false); + if (low_end) { + return false; + } + //return true; return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe); } @@ -4032,6 +4052,10 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND(!gi_probe); + if (low_end) { + return; + } + uint32_t data_version = storage->gi_probe_get_data_version(gi_probe->probe); // (RE)CREATE IF NEEDED @@ -4062,7 +4086,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins tf.width = octree_size.x; tf.height = octree_size.y; tf.depth = octree_size.z; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.mipmaps = levels.size(); tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; @@ -4093,14 +4117,14 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(storage->gi_probe_get_octree_buffer(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe)); uniforms.push_back(u); @@ -4108,21 +4132,21 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 4; u.ids.push_back(gi_probe->write_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -4133,7 +4157,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins if (i == 0) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 3; u.ids.push_back(gi_probe_lights_uniform); copy_uniforms.push_back(u); @@ -4145,7 +4169,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 5; u.ids.push_back(gi_probe->texture); copy_uniforms.push_back(u); @@ -4158,7 +4182,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(mipmap.texture); uniforms.push_back(u); @@ -4232,7 +4256,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 3; u.ids.push_back(gi_probe_lights_uniform); uniforms.push_back(u); @@ -4240,56 +4264,56 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(dmap.albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 6; u.ids.push_back(dmap.normal); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 7; u.ids.push_back(dmap.orm); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 8; u.ids.push_back(dmap.fb_depth); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 11; u.ids.push_back(dmap.texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 12; u.ids.push_back(dmap.depth); uniforms.push_back(u); @@ -4305,14 +4329,14 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 6; u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth); uniforms.push_back(u); @@ -4321,14 +4345,14 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins if (write) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 7; u.ids.push_back(dmap.texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(dmap.depth); uniforms.push_back(u); @@ -4337,14 +4361,14 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -4353,7 +4377,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins if (plot) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 11; u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture); uniforms.push_back(u); @@ -4764,21 +4788,21 @@ void RendererSceneRenderRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(gi_probe->texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 3; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -4837,28 +4861,28 @@ void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawLi { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb->sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->lightprobe_texture); uniforms.push_back(u); } { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->occlusion_texture); uniforms.push_back(u); } @@ -4950,7 +4974,7 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = rb->width; tf.height = rb->height; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; @@ -5123,7 +5147,7 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb tf.format = RD::DATA_FORMAT_R32_SFLOAT; tf.width = rb->width / 2; tf.height = rb->height / 2; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; rb->ssr.depth_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -5138,7 +5162,7 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb tf.format = RD::DATA_FORMAT_R8_UNORM; tf.width = rb->width / 2; tf.height = rb->height / 2; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; rb->ssr.blur_radius[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -5444,7 +5468,7 @@ void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const Camera { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].sdf_tex); @@ -5457,7 +5481,7 @@ void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const Camera { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].light_tex); @@ -5470,7 +5494,7 @@ void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const Camera { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_0_tex); @@ -5483,7 +5507,7 @@ void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const Camera { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_1_tex); @@ -5496,35 +5520,35 @@ void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const Camera { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->occlusion_texture); uniforms.push_back(u); } { RD::Uniform u; u.binding = 8; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; u.binding = 9; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb->sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; u.binding = 10; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(rb->texture); uniforms.push_back(u); } { RD::Uniform u; u.binding = 11; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->lightprobe_texture); uniforms.push_back(u); } @@ -5687,8 +5711,8 @@ bool RendererSceneRenderRD::render_buffers_is_sdfgi_using_occlusion(RID p_render float RendererSceneRenderRD::render_buffers_get_sdfgi_energy(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); - ERR_FAIL_COND_V(!rb, 0); - ERR_FAIL_COND_V(!rb->sdfgi, false); + ERR_FAIL_COND_V(!rb, 0.0); + ERR_FAIL_COND_V(!rb->sdfgi, 0.0); return rb->sdfgi->energy; } @@ -6543,7 +6567,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e tf.width = target_width; tf.height = target_height; tf.depth = volumetric_fog_depth; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -6557,7 +6581,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->volumetric_fog->fog_map); uniforms.push_back(u); } @@ -6730,7 +6754,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; if (shadow_atlas == nullptr || shadow_atlas->shrink_stages.size() == 0) { u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK)); @@ -6743,7 +6767,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; if (directional_shadow.shrink_stages.size() == 0) { u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK)); @@ -6755,7 +6779,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; u.ids.push_back(get_positional_light_buffer()); uniforms.push_back(u); @@ -6763,7 +6787,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 4; u.ids.push_back(get_directional_light_buffer()); uniforms.push_back(u); @@ -6771,7 +6795,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 5; u.ids.push_back(get_cluster_builder_texture()); uniforms.push_back(u); @@ -6779,7 +6803,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 6; u.ids.push_back(get_cluster_builder_indices_buffer()); uniforms.push_back(u); @@ -6787,7 +6811,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 7; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -6795,7 +6819,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(rb->volumetric_fog->light_density_map); uniforms.push_back(u); @@ -6803,7 +6827,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; u.ids.push_back(rb->volumetric_fog->fog_map); uniforms.push_back(u); @@ -6811,7 +6835,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(shadow_sampler); uniforms.push_back(u); @@ -6819,7 +6843,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 11; u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers)); uniforms.push_back(u); @@ -6827,7 +6851,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 12; for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { u.ids.push_back(rb->giprobe_textures[i]); @@ -6836,7 +6860,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 13; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -6857,7 +6881,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(gi.sdfgi_ubo); uniforms.push_back(u); @@ -6865,7 +6889,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(rb->sdfgi->ambient_texture); uniforms.push_back(u); @@ -6873,7 +6897,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(rb->sdfgi->occlusion_texture); uniforms.push_back(u); @@ -7337,7 +7361,6 @@ void RendererSceneRenderRD::render_sdfgi(RID p_render_buffers, int p_region, Ins ipush_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count; - ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count; int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; ipush_constant.cascade = cascade; @@ -7952,6 +7975,10 @@ int RendererSceneRenderRD::get_max_directional_lights() const { return cluster.max_directional_lights; } +bool RendererSceneRenderRD::is_low_end() const { + return low_end; +} + RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { storage = p_storage; singleton = this; @@ -7961,9 +7988,15 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections"); // sky_use_cubemap_array = false; - //uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); + uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); - { + low_end = GLOBAL_GET("rendering/quality/rd_renderer/use_low_end_renderer"); + + if (textures_per_stage < 48) { + low_end = true; + } + + if (!low_end) { //kinda complicated to compute the amount of slots, we try to use as many as we can gi_probe_max_lights = 32; @@ -7992,7 +8025,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { } } - { + if (!low_end) { String defines; Vector<String> versions; versions.push_back("\n#define MODE_DEBUG_COLOR\n"); @@ -8115,7 +8148,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 0; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -8136,7 +8169,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); @@ -8145,7 +8178,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(sky_scene_state.uniform_buffer); uniforms.push_back(u); } @@ -8153,7 +8186,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(sky_scene_state.directional_light_buffer); uniforms.push_back(u); } @@ -8166,7 +8199,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { { RD::Uniform u; u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); u.ids.push_back(vfog); uniforms.push_back(u); @@ -8185,21 +8218,21 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); uniforms.push_back(u); @@ -8208,121 +8241,125 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES); } - { - Vector<String> preprocess_modes; - preprocess_modes.push_back("\n#define MODE_SCROLL\n"); - preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n"); - preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n"); - preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n"); - preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n"); - preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n"); - preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n"); - preprocess_modes.push_back("\n#define MODE_OCCLUSION\n"); - preprocess_modes.push_back("\n#define MODE_STORE\n"); - String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n"; - sdfgi_shader.preprocess.initialize(preprocess_modes, defines); - sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create(); - for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) { - sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i)); + if (!low_end) { + //SDFGI + { + Vector<String> preprocess_modes; + preprocess_modes.push_back("\n#define MODE_SCROLL\n"); + preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n"); + preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n"); + preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n"); + preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n"); + preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n"); + preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n"); + preprocess_modes.push_back("\n#define MODE_OCCLUSION\n"); + preprocess_modes.push_back("\n#define MODE_STORE\n"); + String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n"; + sdfgi_shader.preprocess.initialize(preprocess_modes, defines); + sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create(); + for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) { + sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i)); + } } - } - { - //calculate tables - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + { + //calculate tables + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - Vector<String> direct_light_modes; - direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n"); - direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n"); - sdfgi_shader.direct_light.initialize(direct_light_modes, defines); - sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create(); - for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) { - sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i)); + Vector<String> direct_light_modes; + direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n"); + direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n"); + sdfgi_shader.direct_light.initialize(direct_light_modes, defines); + sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create(); + for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) { + sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i)); + } } - } - { - //calculate tables - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n"; - - Vector<String> integrate_modes; - integrate_modes.push_back("\n#define MODE_PROCESS\n"); - integrate_modes.push_back("\n#define MODE_STORE\n"); - integrate_modes.push_back("\n#define MODE_SCROLL\n"); - integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n"); - sdfgi_shader.integrate.initialize(integrate_modes, defines); - sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create(); + { + //calculate tables + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n"; - for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) { - sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i)); - } + Vector<String> integrate_modes; + integrate_modes.push_back("\n#define MODE_PROCESS\n"); + integrate_modes.push_back("\n#define MODE_STORE\n"); + integrate_modes.push_back("\n#define MODE_SCROLL\n"); + integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n"); + sdfgi_shader.integrate.initialize(integrate_modes, defines); + sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create(); - { - Vector<RD::Uniform> uniforms; + for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) { + sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i)); + } { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 0; - u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); - uniforms.push_back(u); + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 0; + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 1; + u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); + uniforms.push_back(u); + } + + sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1); } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 1; - u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); - uniforms.push_back(u); + } + { + //calculate tables + String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + Vector<String> gi_modes; + gi_modes.push_back(""); + gi.shader.initialize(gi_modes, defines); + gi.shader_version = gi.shader.version_create(); + for (int i = 0; i < GI::MODE_MAX; i++) { + gi.pipelines[i] = RD::get_singleton()->compute_pipeline_create(gi.shader.version_get_shader(gi.shader_version, i)); } - sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1); + gi.sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(GI::SDFGIData)); } - } - { - //calculate tables - String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - Vector<String> gi_modes; - gi_modes.push_back(""); - gi.shader.initialize(gi_modes, defines); - gi.shader_version = gi.shader.version_create(); - for (int i = 0; i < GI::MODE_MAX; i++) { - gi.pipelines[i] = RD::get_singleton()->compute_pipeline_create(gi.shader.version_get_shader(gi.shader_version, i)); + { + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + Vector<String> debug_modes; + debug_modes.push_back(""); + sdfgi_shader.debug.initialize(debug_modes, defines); + sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create(); + sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0); + sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version); } + { + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - gi.sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(GI::SDFGIData)); - } - { - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - Vector<String> debug_modes; - debug_modes.push_back(""); - sdfgi_shader.debug.initialize(debug_modes, defines); - sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create(); - sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0); - sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version); - } - { - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - - Vector<String> versions; - versions.push_back("\n#define MODE_PROBES\n"); - versions.push_back("\n#define MODE_VISIBILITY\n"); + Vector<String> versions; + versions.push_back("\n#define MODE_PROBES\n"); + versions.push_back("\n#define MODE_VISIBILITY\n"); - sdfgi_shader.debug_probes.initialize(versions, defines); - sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create(); + sdfgi_shader.debug_probes.initialize(versions, defines); + sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create(); - { - RD::PipelineRasterizationState rs; - rs.cull_mode = RD::POLYGON_CULL_DISABLED; - RD::PipelineDepthStencilState ds; - ds.enable_depth_test = true; - ds.enable_depth_write = true; - ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) { - RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i); - sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + { + RD::PipelineRasterizationState rs; + rs.cull_mode = RD::POLYGON_CULL_DISABLED; + RD::PipelineDepthStencilState ds; + ds.enable_depth_test = true; + ds.enable_depth_write = true; + ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) { + RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i); + sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + } } } + default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES); } //cluster setup @@ -8366,7 +8403,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { cluster.builder.setup(16, 8, 24); - { + if (!low_end) { String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n"; Vector<String> volumetric_fog_modes; volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n"); @@ -8379,7 +8416,6 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { volumetric_fog.pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, i)); } } - default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES); { RD::SamplerState sampler; @@ -8427,22 +8463,25 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { RD::get_singleton()->free(sky_scene_state.uniform_set); } - RD::get_singleton()->free(default_giprobe_buffer); - RD::get_singleton()->free(gi_probe_lights_uniform); - RD::get_singleton()->free(gi.sdfgi_ubo); + if (!low_end) { + RD::get_singleton()->free(default_giprobe_buffer); + RD::get_singleton()->free(gi_probe_lights_uniform); + RD::get_singleton()->free(gi.sdfgi_ubo); - giprobe_debug_shader.version_free(giprobe_debug_shader_version); - giprobe_shader.version_free(giprobe_lighting_shader_version); - gi.shader.version_free(gi.shader_version); - sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader); - sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader); - sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader); - sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader); - sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); + giprobe_debug_shader.version_free(giprobe_debug_shader_version); + giprobe_shader.version_free(giprobe_lighting_shader_version); + gi.shader.version_free(gi.shader_version); + sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader); + sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader); + sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader); + sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader); + sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); - volumetric_fog.shader.version_free(volumetric_fog.shader_version); + volumetric_fog.shader.version_free(volumetric_fog.shader_version); + + memdelete_arr(gi_probe_lights); + } - memdelete_arr(gi_probe_lights); SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); sky_shader.shader.version_free(md->shader_data->version); RD::get_singleton()->free(sky_scene_state.directional_light_buffer); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 8c994849c3..e3dfee2da7 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -1456,6 +1456,8 @@ private: float weight; }; + bool low_end = false; + public: /* SHADOW ATLAS API */ @@ -1952,6 +1954,8 @@ public: void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir); + bool is_low_end() const; + RendererSceneRenderRD(RendererStorageRD *p_storage); ~RendererSceneRenderRD(); }; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index b28fe97856..564d61f9fb 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -318,7 +318,7 @@ Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; //unsigned float bc6hu - case Image::FORMAT_PVRTC2: { + case Image::FORMAT_PVRTC1_2: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; @@ -336,7 +336,7 @@ Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; //pvrtc - case Image::FORMAT_PVRTC2A: { + case Image::FORMAT_PVRTC1_2A: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; @@ -353,7 +353,7 @@ Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; } break; - case Image::FORMAT_PVRTC4: { + case Image::FORMAT_PVRTC1_4: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; @@ -370,7 +370,7 @@ Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; - case Image::FORMAT_PVRTC4A: { + case Image::FORMAT_PVRTC1_4A: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; @@ -567,7 +567,7 @@ RID RendererStorageRD::texture_2d_create(const Ref<Image> &p_image) { rd_format.depth = 1; rd_format.array_layers = 1; rd_format.mipmaps = texture.mipmaps; - rd_format.type = texture.rd_type; + rd_format.texture_type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { @@ -675,7 +675,7 @@ RID RendererStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_lay rd_format.depth = 1; rd_format.array_layers = texture.layers; rd_format.mipmaps = texture.mipmaps; - rd_format.type = texture.rd_type; + rd_format.texture_type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { @@ -793,7 +793,7 @@ RID RendererStorageRD::texture_3d_create(Image::Format p_format, int p_width, in rd_format.depth = texture.depth; rd_format.array_layers = 1; rd_format.mipmaps = texture.mipmaps; - rd_format.type = texture.rd_type; + rd_format.texture_type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { @@ -1298,7 +1298,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas Vector<RD::Uniform> uniforms; { //diffuse RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; t = texture_owner.getornull(ct->diffuse); @@ -1313,7 +1313,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas } { //normal RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; t = texture_owner.getornull(ct->normalmap); @@ -1328,7 +1328,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas } { //specular RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; t = texture_owner.getornull(ct->specular); @@ -1343,7 +1343,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas } { //sampler RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 3; u.ids.push_back(sampler_rd_get_default(filter, repeat)); uniforms.push_back(u); @@ -3591,14 +3591,14 @@ void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(particles->particle_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(particles->particle_instance_buffer); uniforms.push_back(u); @@ -3901,14 +3901,14 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(p_particles->frame_params_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(p_particles->particle_buffer); uniforms.push_back(u); @@ -3916,7 +3916,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; if (p_particles->emission_storage_buffer.is_valid()) { u.ids.push_back(p_particles->emission_storage_buffer); @@ -3927,7 +3927,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter); if (sub_emitter) { @@ -4134,7 +4134,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; for (uint32_t i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) { RID rd_tex; @@ -4154,7 +4154,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; if (collision_heightmap_texture.is_valid()) { u.ids.push_back(collision_heightmap_texture); @@ -4255,7 +4255,7 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 & { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(particles->particles_sort_buffer); uniforms.push_back(u); @@ -4614,7 +4614,7 @@ void RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<Strin { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -4623,7 +4623,7 @@ void RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<Strin const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -4679,7 +4679,7 @@ RID RendererStorageRD::particles_collision_get_heightfield_framebuffer(RID p_par tf.format = RD::DATA_FORMAT_D32_SFLOAT; tf.width = size.x; tf.height = size.y; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; particles_collision->heightfield_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -5588,7 +5588,7 @@ void RendererStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_ tf.width = gi_probe->octree_size.x; tf.height = gi_probe->octree_size.y; tf.depth = gi_probe->octree_size.z; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; Vector<Vector<uint8_t>> s; s.push_back(p_distance_field); @@ -5617,21 +5617,21 @@ void RendererStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_ Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(gi_probe->octree_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(gi_probe->data_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(shared_tex); uniforms.push_back(u); @@ -6122,7 +6122,7 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) { rd_format.depth = 1; rd_format.array_layers = 1; rd_format.mipmaps = 1; - rd_format.type = RD::TEXTURE_TYPE_2D; + rd_format.texture_type = RD::TEXTURE_TYPE_2D; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; rd_format.shareable_formats.push_back(rt->color_format); @@ -6191,7 +6191,7 @@ void RendererStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { tf.format = rt->color_format; tf.width = rt->size.width; tf.height = rt->size.height; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; @@ -6420,7 +6420,7 @@ RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) { tformat.width = 4; tformat.height = 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -6447,7 +6447,7 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { tformat.width = size.width; tformat.height = size.height; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; rt->sdf_buffer_write = RD::get_singleton()->texture_create(tformat, RD::TextureView()); @@ -6494,28 +6494,28 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(rt->sdf_buffer_write); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(rt->sdf_buffer_read); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(rt->sdf_buffer_process[0]); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(rt->sdf_buffer_process[1]); uniforms.push_back(u); @@ -6983,7 +6983,7 @@ void RendererStorageRD::_update_decal_atlas() { tformat.width = decal_atlas.size.width; tformat.height = decal_atlas.size.height; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; tformat.mipmaps = decal_atlas.mipmaps; tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM); tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB); @@ -7946,7 +7946,7 @@ RendererStorageRD::RendererStorageRD() { tformat.width = 4; tformat.height = 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -8038,7 +8038,7 @@ RendererStorageRD::RendererStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tformat.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -8066,7 +8066,7 @@ RendererStorageRD::RendererStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE; + tformat.texture_type = RD::TEXTURE_TYPE_CUBE; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -8094,7 +8094,7 @@ RendererStorageRD::RendererStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE; + tformat.texture_type = RD::TEXTURE_TYPE_CUBE; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -8122,7 +8122,7 @@ RendererStorageRD::RendererStorageRD() { tformat.height = 4; tformat.depth = 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_3D; + tformat.texture_type = RD::TEXTURE_TYPE_3D; Vector<uint8_t> pv; pv.resize(64 * 4); @@ -8148,7 +8148,7 @@ RendererStorageRD::RendererStorageRD() { tformat.height = 4; tformat.array_layers = 1; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_2D_ARRAY; + tformat.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -8453,7 +8453,7 @@ RendererStorageRD::RendererStorageRD() { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 1; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -8474,7 +8474,7 @@ RendererStorageRD::RendererStorageRD() { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(global_variables_get_storage_buffer()); uniforms.push_back(u); @@ -8544,6 +8544,7 @@ RendererStorageRD::~RendererStorageRD() { giprobe_sdf_shader.version_free(giprobe_sdf_shader_version); particles_shader.copy_shader.version_free(particles_shader.copy_shader_version); + rt_sdf.shader.version_free(rt_sdf.shader_version); RenderingServer::get_singleton()->free(particles_shader.default_material); RenderingServer::get_singleton()->free(particles_shader.default_shader); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 2b67075369..b6a26fc9d0 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -1463,7 +1463,7 @@ public: if (!multimesh->uniform_set_3d.is_valid()) { Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(multimesh->buffer); uniforms.push_back(u); @@ -1511,7 +1511,7 @@ public: if (!skeleton->uniform_set_3d.is_valid()) { Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(skeleton->buffer); uniforms.push_back(u); @@ -1900,7 +1900,7 @@ public: { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(particles->particle_instance_buffer); uniforms.push_back(u); diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index bf7ec54b9c..41126218ae 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -199,6 +199,10 @@ void ShaderRD::_clear_version(Version *p_version) { } void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { + if (!variants_enabled[p_variant]) { + return; //variant is disabled, return + } + Vector<RD::ShaderStageData> stages; String error; @@ -365,6 +369,9 @@ void ShaderRD::_compile_version(Version *p_version) { bool all_valid = true; for (int i = 0; i < variant_defines.size(); i++) { + if (!variants_enabled[i]) { + continue; //disabled + } if (p_version->variants[i].is_null()) { all_valid = false; break; @@ -374,6 +381,9 @@ void ShaderRD::_compile_version(Version *p_version) { if (!all_valid) { //clear versions if they exist for (int i = 0; i < variant_defines.size(); i++) { + if (!variants_enabled[i]) { + continue; //disabled + } if (!p_version->variants[i].is_null()) { RD::get_singleton()->free(p_version->variants[i]); } @@ -454,12 +464,26 @@ bool ShaderRD::version_free(RID p_version) { return true; } +void ShaderRD::set_variant_enabled(int p_variant, bool p_enabled) { + ERR_FAIL_COND(version_owner.get_rid_count() > 0); //versions exist + ERR_FAIL_INDEX(p_variant, variants_enabled.size()); + variants_enabled.write[p_variant] = p_enabled; +} + +bool ShaderRD::is_variant_enabled(int p_variant) const { + ERR_FAIL_INDEX_V(p_variant, variants_enabled.size(), false); + return variants_enabled[p_variant]; +} + void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String &p_general_defines) { ERR_FAIL_COND(variant_defines.size()); ERR_FAIL_COND(p_variant_defines.size() == 0); + general_defines = p_general_defines.utf8(); + for (int i = 0; i < p_variant_defines.size(); i++) { variant_defines.push_back(p_variant_defines[i].utf8()); + variants_enabled.push_back(true); } } diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 0c379db6f2..05e07d3cf3 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -46,6 +46,7 @@ class ShaderRD { //versions CharString general_defines; Vector<CharString> variant_defines; + Vector<bool> variants_enabled; struct Version { CharString uniforms; @@ -109,6 +110,7 @@ public: _FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) { ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID()); + ERR_FAIL_COND_V(!variants_enabled[p_variant], RID()); Version *version = version_owner.getornull(p_version); ERR_FAIL_COND_V(!version, RID()); @@ -128,6 +130,9 @@ public: bool version_free(RID p_version); + void set_variant_enabled(int p_variant, bool p_enabled); + bool is_variant_enabled(int p_variant) const; + void initialize(const Vector<String> &p_variant_defines, const String &p_general_defines = ""); virtual ~ShaderRD(); }; diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub index 4cddf0f685..1fe43b25f6 100644 --- a/servers/rendering/renderer_rd/shaders/SCsub +++ b/servers/rendering/renderer_rd/shaders/SCsub @@ -11,7 +11,7 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("cubemap_roughness.glsl") env.RD_GLSL("cubemap_downsampler.glsl") env.RD_GLSL("cubemap_filter.glsl") - env.RD_GLSL("scene_high_end.glsl") + env.RD_GLSL("scene_forward.glsl") env.RD_GLSL("sky.glsl") env.RD_GLSL("tonemap.glsl") env.RD_GLSL("cube_to_dp.glsl") diff --git a/servers/rendering/renderer_rd/shaders/scene_high_end.glsl b/servers/rendering/renderer_rd/shaders/scene_forward.glsl index 5d87dec79f..5b01cb1f82 100644 --- a/servers/rendering/renderer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward.glsl @@ -4,7 +4,7 @@ VERSION_DEFINES -#include "scene_high_end_inc.glsl" +#include "scene_forward_inc.glsl" /* INPUT ATTRIBS */ @@ -296,7 +296,7 @@ VERTEX_SHADER_CODE VERSION_DEFINES -#include "scene_high_end_inc.glsl" +#include "scene_forward_inc.glsl" /* Varyings */ @@ -1548,8 +1548,6 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 out_spec += vec4(irr_light.rgb * blend, blend); } -#endif //USE_FORWARD_GI - vec2 octahedron_wrap(vec2 v) { vec2 signVal; signVal.x = v.x >= 0.0 ? 1.0 : -1.0; @@ -1683,10 +1681,14 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal } } +#endif //USE_FORWARD_GI + #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifndef MODE_RENDER_DEPTH +#ifndef LOW_END_MODE + vec4 volumetric_fog_process(vec2 screen_uv, float z) { vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length); if (fog_pos.z < 0.0) { @@ -1697,6 +1699,7 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) { return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); } +#endif vec4 fog_process(vec3 vertex) { vec3 fog_color = scene_data.fog_light_color; @@ -2221,30 +2224,13 @@ FRAGMENT_SHADER_CODE specular_light = spec_accum.rgb; ambient_light = amb_accum.rgb; } -#else +#elif !defined(LOW_END_MODE) + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers ivec2 coord; if (scene_data.gi_upscale_for_msaa) { - /* - //find the closest depth to upscale from, based on neighbours - ivec2 base_coord = ivec2(gl_FragCoord.xy); - float z_dist = gl_FragCoord.z; - ivec2 closest_coord = base_coord; - float closest_z_dist = abs(texelFetch(sampler2D(depth_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord,0).r-z_dist); - - for(int i=0;i<4;i++) { - const ivec2 neighbours[4]=ivec2[](ivec2(-1,0),ivec2(1,0),ivec2(0,-1),ivec2(0,1)); - ivec2 neighbour_coord = base_coord + neighbours[i]; - float neighbour_z_dist = abs(texelFetch(sampler2D(depth_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord,0).r-z_dist); - if (neighbour_z_dist < closest_z_dist) { - closest_z_dist = neighbour_z_dist; - closest_coord = neighbour_coord; - } - } - -*/ ivec2 base_coord = ivec2(gl_FragCoord.xy); ivec2 closest_coord = base_coord; float closest_ang = dot(normal, texelFetch(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord, 0).xyz * 2.0 - 1.0); @@ -2823,11 +2809,13 @@ FRAGMENT_SHADER_CODE //ambient occlusion #if defined(AO_USED) +#ifndef LOW_END_MODE if (scene_data.ssao_enabled && scene_data.ssao_ao_affect > 0.0) { float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; ao = mix(ao, min(ao, ssao), scene_data.ssao_ao_affect); ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); } +#endif //LOW_END_MODE ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao); ao_light_affect = mix(1.0, ao, ao_light_affect); @@ -2835,6 +2823,7 @@ FRAGMENT_SHADER_CODE diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect); #else +#ifndef LOW_END_MODE if (scene_data.ssao_enabled) { float ao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao); @@ -2842,6 +2831,7 @@ FRAGMENT_SHADER_CODE specular_light = mix(scene_data.ao_color.rgb, specular_light, ao_light_affect); diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect); } +#endif //LOW_END_MODE #endif // AO_USED @@ -2871,11 +2861,13 @@ FRAGMENT_SHADER_CODE specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); } +#ifndef LOW_END_MODE if (scene_data.volumetric_fog_enabled) { vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); } +#endif // LOW_END_MODE #if defined(CUSTOM_FOG_USED) diffuse_buffer.rgb = mix(diffuse_buffer.rgb, custom_fog.rgb, custom_fog.a); @@ -2896,11 +2888,12 @@ FRAGMENT_SHADER_CODE vec4 fog = fog_process(vertex); frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); } - +#ifndef LOW_END_MODE if (scene_data.volumetric_fog_enabled) { vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); } +#endif #if defined(CUSTOM_FOG_USED) frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_fog.a); diff --git a/servers/rendering/renderer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl index e29a490ca1..d18581c1b3 100644 --- a/servers/rendering/renderer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl @@ -204,6 +204,8 @@ layout(set = 0, binding = 19, std430) restrict readonly buffer GlobalVariableDat } global_variables; +#ifndef LOW_END_MODE + struct SDFGIProbeCascadeData { vec3 position; float to_probe; @@ -239,6 +241,8 @@ layout(set = 0, binding = 20, std140) uniform SDFGI { } sdfgi; +#endif //LOW_END_MODE + // decal atlas /* Set 1, Radiance */ @@ -255,20 +259,22 @@ layout(set = 1, binding = 0) uniform textureCube radiance_cubemap; /* Set 2, Reflection and Shadow Atlases (view dependent) */ -layout(set = 2, binding = 0) uniform textureCubeArray reflection_atlas; +layout(set = 1, binding = 1) uniform textureCubeArray reflection_atlas; -layout(set = 2, binding = 1) uniform texture2D shadow_atlas; +layout(set = 1, binding = 2) uniform texture2D shadow_atlas; -layout(set = 2, binding = 2) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +#ifndef LOW_END_MODE +layout(set = 1, binding = 3) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +#endif /* Set 3, Render Buffers */ #ifdef MODE_RENDER_SDF -layout(r16ui, set = 3, binding = 0) uniform restrict writeonly uimage3D albedo_volume_grid; -layout(r32ui, set = 3, binding = 1) uniform restrict writeonly uimage3D emission_grid; -layout(r32ui, set = 3, binding = 2) uniform restrict writeonly uimage3D emission_aniso_grid; -layout(r32ui, set = 3, binding = 3) uniform restrict uimage3D geom_facing_grid; +layout(r16ui, set = 1, binding = 4) uniform restrict writeonly uimage3D albedo_volume_grid; +layout(r32ui, set = 1, binding = 5) uniform restrict writeonly uimage3D emission_grid; +layout(r32ui, set = 1, binding = 6) uniform restrict writeonly uimage3D emission_aniso_grid; +layout(r32ui, set = 1, binding = 7) uniform restrict uimage3D geom_facing_grid; //still need to be present for shaders that use it, so remap them to something #define depth_buffer shadow_atlas @@ -277,14 +283,17 @@ layout(r32ui, set = 3, binding = 3) uniform restrict uimage3D geom_facing_grid; #else -layout(set = 3, binding = 0) uniform texture2D depth_buffer; -layout(set = 3, binding = 1) uniform texture2D color_buffer; -layout(set = 3, binding = 2) uniform texture2D normal_roughness_buffer; -layout(set = 3, binding = 4) uniform texture2D ao_buffer; -layout(set = 3, binding = 5) uniform texture2D ambient_buffer; -layout(set = 3, binding = 6) uniform texture2D reflection_buffer; -layout(set = 3, binding = 7) uniform texture2DArray sdfgi_lightprobe_texture; -layout(set = 3, binding = 8) uniform texture3D sdfgi_occlusion_cascades; +layout(set = 1, binding = 4) uniform texture2D depth_buffer; +layout(set = 1, binding = 5) uniform texture2D color_buffer; + +#ifndef LOW_END_MODE + +layout(set = 1, binding = 6) uniform texture2D normal_roughness_buffer; +layout(set = 1, binding = 7) uniform texture2D ao_buffer; +layout(set = 1, binding = 8) uniform texture2D ambient_buffer; +layout(set = 1, binding = 9) uniform texture2D reflection_buffer; +layout(set = 1, binding = 10) uniform texture2DArray sdfgi_lightprobe_texture; +layout(set = 1, binding = 11) uniform texture3D sdfgi_occlusion_cascades; struct GIProbeData { mat4 xform; @@ -302,18 +311,20 @@ struct GIProbeData { uint mipmaps; }; -layout(set = 3, binding = 9, std140) uniform GIProbes { +layout(set = 1, binding = 12, std140) uniform GIProbes { GIProbeData data[MAX_GI_PROBES]; } gi_probes; -layout(set = 3, binding = 10) uniform texture3D volumetric_fog_texture; +layout(set = 1, binding = 13) uniform texture3D volumetric_fog_texture; + +#endif // LOW_END_MODE #endif /* Set 4 Skeleton & Instancing (Multimesh) */ -layout(set = 4, binding = 0, std430) restrict readonly buffer Transforms { +layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { vec4 data[]; } transforms; diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index cc543a7599..0aae67fd34 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -260,6 +260,8 @@ public: virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; + virtual bool is_low_end() const = 0; + virtual void update() = 0; virtual ~RendererSceneRender() {} }; diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index f1f8b3cda0..5fa37c2ce4 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -392,7 +392,7 @@ public: uint32_t depth; uint32_t array_layers; uint32_t mipmaps; - TextureType type; + TextureType texture_type; TextureSamples samples; uint32_t usage_bits; Vector<DataFormat> shareable_formats; @@ -404,7 +404,7 @@ public: depth = 1; array_layers = 1; mipmaps = 1; - type = TEXTURE_TYPE_2D; + texture_type = TEXTURE_TYPE_2D; samples = TEXTURE_SAMPLES_1; usage_bits = 0; } @@ -629,7 +629,7 @@ public: virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0; struct Uniform { - UniformType type; + UniformType uniform_type; int binding; //binding index as specified in shader //for single items, provide one ID, for @@ -640,7 +640,7 @@ public: Vector<RID> ids; Uniform() { - type = UNIFORM_TYPE_IMAGE; + uniform_type = UNIFORM_TYPE_IMAGE; binding = 0; } }; diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index 66c6a1c3a9..5deeec3ffe 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -64,7 +64,7 @@ public: RD_SETGET(uint32_t, depth) RD_SETGET(uint32_t, array_layers) RD_SETGET(uint32_t, mipmaps) - RD_SETGET(RD::TextureType, type) + RD_SETGET(RD::TextureType, texture_type) RD_SETGET(RD::TextureSamples, samples) RD_SETGET(uint32_t, usage_bits) @@ -79,7 +79,7 @@ protected: RD_BIND(Variant::INT, RDTextureFormat, depth); RD_BIND(Variant::INT, RDTextureFormat, array_layers); RD_BIND(Variant::INT, RDTextureFormat, mipmaps); - RD_BIND(Variant::INT, RDTextureFormat, type); + RD_BIND(Variant::INT, RDTextureFormat, texture_type); RD_BIND(Variant::INT, RDTextureFormat, samples); RD_BIND(Variant::INT, RDTextureFormat, usage_bits); ClassDB::bind_method(D_METHOD("add_shareable_format", "format"), &RDTextureFormat::add_shareable_format); @@ -392,7 +392,7 @@ class RDUniform : public Reference { RD::Uniform base; public: - RD_SETGET(RD::UniformType, type) + RD_SETGET(RD::UniformType, uniform_type) RD_SETGET(int32_t, binding) void add_id(const RID &p_id) { base.ids.push_back(p_id); } @@ -415,7 +415,7 @@ protected: } } static void _bind_methods() { - RD_BIND(Variant::INT, RDUniform, type); + RD_BIND(Variant::INT, RDUniform, uniform_type); RD_BIND(Variant::INT, RDUniform, binding); ClassDB::bind_method(D_METHOD("add_id", "id"), &RDUniform::add_id); ClassDB::bind_method(D_METHOD("clear_ids"), &RDUniform::clear_ids); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 2f7e950841..742ad8a7bf 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -3174,7 +3174,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi } bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) { - for (int i = 0; shader->functions.size(); i++) { + for (int i = 0; i < shader->functions.size(); i++) { if (shader->functions[i].name == p_name) { ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; @@ -3208,7 +3208,7 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam } bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) { - for (int i = 0; shader->functions.size(); i++) { + for (int i = 0; i < shader->functions.size(); i++) { if (shader->functions[i].name == p_name) { ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index cb77324489..9d2d591542 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -519,7 +519,7 @@ public: DataType basetype = TYPE_VOID; bool basetype_const = false; StringName base_struct_name; - DataPrecision precision; + DataPrecision precision = PRECISION_DEFAULT; DataType datatype = TYPE_VOID; int array_size = 0; StringName struct_name; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 433b56ab41..b033b09303 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2184,15 +2184,6 @@ void RenderingServer::_bind_methods() { ADD_SIGNAL(MethodInfo("frame_post_draw")); } -void RenderingServer::_canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate) { - ERR_FAIL_COND(p_margins.size() != 4); - //canvas_item_add_style_box(p_item,p_rect,p_source,p_texture,Vector2(p_margins[0],p_margins[1]),Vector2(p_margins[2],p_margins[3]),true,p_modulate); -} - -void RenderingServer::_camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) { - camera_set_orthogonal(p_camera, p_size, p_z_near, p_z_far); -} - void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry3D::MeshData &p_mesh_data) { Vector<Vector3> vertices; Vector<Vector3> normals; @@ -2268,6 +2259,9 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/quality/2d_shadow_atlas/size", 2048); + GLOBAL_DEF("rendering/quality/rd_renderer/use_low_end_renderer", false); + GLOBAL_DEF("rendering/quality/rd_renderer/use_low_end_renderer.mobile", true); + GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096); GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index abe3cc6975..5865cc7adf 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -50,8 +50,6 @@ class RenderingServer : public Object { int mm_policy; bool render_loop_enabled = true; - void _camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far); - void _canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate = Color(1, 1, 1)); Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const; protected: diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 74bf437a25..b2584d9ffd 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -231,6 +231,10 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_get_antialiased", "font"), &TextServer::font_get_antialiased); ClassDB::bind_method(D_METHOD("font_get_feature_list", "font"), &TextServer::font_get_feature_list); + ClassDB::bind_method(D_METHOD("font_get_variation_list", "font"), &TextServer::font_get_variation_list); + + ClassDB::bind_method(D_METHOD("font_set_variation", "font", "tag", "value"), &TextServer::font_set_variation); + ClassDB::bind_method(D_METHOD("font_get_variation", "font", "tag"), &TextServer::font_get_variation); ClassDB::bind_method(D_METHOD("font_set_hinting", "font", "hinting"), &TextServer::font_set_hinting); ClassDB::bind_method(D_METHOD("font_get_hinting", "font"), &TextServer::font_get_hinting); @@ -385,6 +389,7 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_KASHIDA_JUSTIFICATION); BIND_ENUM_CONSTANT(FEATURE_BREAK_ITERATORS); BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM); + BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE); BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA); } @@ -554,14 +559,18 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const int line_start = MAX(p_start, range.x); int last_safe_break = -1; int chunk = 0; - for (int i = 0; i < logical.size(); i++) { - if (logical[i].start < p_start) { + + int l_size = logical.size(); + const Glyph *l_gl = logical.ptr(); + + for (int i = 0; i < l_size; i++) { + if (l_gl[i].start < p_start) { continue; } - if (logical[i].count > 0) { - if ((p_width[chunk] > 0) && (width + logical[i].advance > p_width[chunk]) && (last_safe_break >= 0)) { - lines.push_back(Vector2i(line_start, logical[last_safe_break].end)); - line_start = logical[last_safe_break].end; + if (l_gl[i].count > 0) { + if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) { + lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end)); + line_start = l_gl[last_safe_break].end; i = last_safe_break; last_safe_break = -1; width = 0; @@ -575,9 +584,9 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const continue; } if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) { - if ((logical[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { - lines.push_back(Vector2i(line_start, logical[i].end)); - line_start = logical[i].end; + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { + lines.push_back(Vector2i(line_start, l_gl[i].end)); + line_start = l_gl[i].end; last_safe_break = -1; width = 0; chunk = 0; @@ -588,7 +597,7 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const } } if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) { - if ((logical[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { last_safe_break = i; } } @@ -596,10 +605,10 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const last_safe_break = i; } } - width += logical[i].advance; + width += l_gl[i].advance; } - if (logical.size() > 0) { + if (l_size > 0) { lines.push_back(Vector2i(line_start, range.y)); } else { lines.push_back(Vector2i(0, 0)); @@ -618,30 +627,34 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w float width = 0.f; int line_start = MAX(p_start, range.x); int last_safe_break = -1; - for (int i = 0; i < logical.size(); i++) { - if (logical[i].start < p_start) { + + int l_size = logical.size(); + const Glyph *l_gl = logical.ptr(); + + for (int i = 0; i < l_size; i++) { + if (l_gl[i].start < p_start) { continue; } - if (logical[i].count > 0) { - if ((p_width > 0) && (width + logical[i].advance > p_width) && (last_safe_break >= 0)) { - lines.push_back(Vector2i(line_start, logical[last_safe_break].end)); - line_start = logical[last_safe_break].end; + if (l_gl[i].count > 0) { + if ((p_width > 0) && (width + l_gl[i].advance > p_width) && (last_safe_break >= 0)) { + lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end)); + line_start = l_gl[last_safe_break].end; i = last_safe_break; last_safe_break = -1; width = 0; continue; } if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) { - if ((logical[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { - lines.push_back(Vector2i(line_start, logical[i].end)); - line_start = logical[i].end; + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { + lines.push_back(Vector2i(line_start, l_gl[i].end)); + line_start = l_gl[i].end; last_safe_break = -1; width = 0; continue; } } if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) { - if ((logical[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { last_safe_break = i; } } @@ -649,10 +662,10 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w last_safe_break = i; } } - width += logical[i].advance; + width += l_gl[i].advance; } - if (logical.size() > 0) { + if (l_size > 0) { if (lines.size() == 0 || lines[lines.size() - 1].y < range.y) { lines.push_back(Vector2i(line_start, range.y)); } @@ -671,15 +684,19 @@ Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const { const Vector2i &range = shaped_text_get_range(p_shaped); int word_start = range.x; - for (int i = 0; i < logical.size(); i++) { - if (logical[i].count > 0) { - if ((logical[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { - words.push_back(Vector2i(word_start, logical[i].end - 1)); - word_start = logical[i].end; + + int l_size = logical.size(); + const Glyph *l_gl = logical.ptr(); + + for (int i = 0; i < l_size; i++) { + if (l_gl[i].count > 0) { + if ((l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { + words.push_back(Vector2i(word_start, l_gl[i].end - 1)); + word_start = l_gl[i].end; } } } - if (logical.size() > 0) { + if (l_size > 0) { words.push_back(Vector2i(word_start, range.y)); } @@ -688,7 +705,7 @@ Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const { void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const { Vector<Rect2> carets; - const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped); + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); const Vector2 &range = shaped_text_get_range(p_shaped); float ascent = shaped_text_get_ascent(p_shaped); @@ -698,7 +715,11 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l float off = 0.0f; p_leading_dir = DIRECTION_AUTO; p_trailing_dir = DIRECTION_AUTO; - for (int i = 0; i < glyphs.size(); i++) { + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + for (int i = 0; i < v_size; i++) { if (glyphs[i].count > 0) { // Caret before grapheme (top / left). if (p_position == glyphs[i].start && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { @@ -831,7 +852,7 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l } TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const { - const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped); + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); if (p_start == p_end) { return DIRECTION_AUTO; @@ -843,7 +864,10 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RI int rtl = 0; int ltr = 0; - for (int i = 0; i < glyphs.size(); i++) { + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + for (int i = 0; i < v_size; i++) { if ((glyphs[i].end > start) && (glyphs[i].start < end)) { if (glyphs[i].count > 0) { if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { @@ -865,7 +889,7 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RI Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const { Vector<Vector2> ranges; - const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped); + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); if (p_start == p_end) { return ranges; @@ -874,8 +898,11 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int start = MIN(p_start, p_end); int end = MAX(p_start, p_end); + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + float off = 0.0f; - for (int i = 0; i < glyphs.size(); i++) { + for (int i = 0; i < v_size; i++) { for (int k = 0; k < glyphs[i].repeat; k++) { if (glyphs[i].count > 0 && glyphs[i].index != 0) { if (glyphs[i].start < end && glyphs[i].end > start) { @@ -951,11 +978,15 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, } int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const { - const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped); + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); // Exact grapheme hit test, return -1 if missed. float off = 0.0f; - for (int i = 0; i < glyphs.size(); i++) { + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + for (int i = 0; i < v_size; i++) { for (int j = 0; j < glyphs[i].repeat; j++) { if (p_coords >= off && p_coords < off + glyphs[i].advance) { return i; @@ -967,13 +998,16 @@ int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) cons } int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) const { - const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped); + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); // Cursor placement hit test. // Place caret to the left of the leftmost grapheme, or to position 0 if string is empty. if (p_coords <= 0) { - if (glyphs.size() > 0) { + if (v_size > 0) { if ((glyphs[0].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { return glyphs[0].end; } else { @@ -986,11 +1020,11 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) cons // Place caret to the right of the rightmost grapheme, or to position 0 if string is empty. if (p_coords >= shaped_text_get_width(p_shaped)) { - if (glyphs.size() > 0) { - if ((glyphs[glyphs.size() - 1].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { - return glyphs[glyphs.size() - 1].start; + if (v_size > 0) { + if ((glyphs[v_size - 1].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[v_size - 1].start; } else { - return glyphs[glyphs.size() - 1].end; + return glyphs[v_size - 1].end; } } else { return 0; @@ -998,7 +1032,7 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) cons } float off = 0.0f; - for (int i = 0; i < glyphs.size(); i++) { + for (int i = 0; i < v_size; i++) { for (int k = 0; k < glyphs[i].repeat; k++) { if (glyphs[i].count > 0) { float advance = 0.f; @@ -1029,8 +1063,10 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) cons } int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) { - const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped); - for (int i = 0; i < glyphs.size(); i++) { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + for (int i = 0; i < v_size; i++) { if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) { return glyphs[i].end; } @@ -1039,8 +1075,10 @@ int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) { } int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) { - const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped); - for (int i = 0; i < glyphs.size(); i++) { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + for (int i = 0; i < v_size; i++) { if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) { return glyphs[i].start; } @@ -1050,13 +1088,16 @@ int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) { } void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, const Color &p_color) const { - const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped); + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped); + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + Vector2 ofs = p_pos; // Draw at the baseline. - for (int i = 0; i < glyphs.size(); i++) { + for (int i = 0; i < v_size; i++) { for (int j = 0; j < glyphs[i].repeat; j++) { if (p_clip_r > 0) { // Clip right / bottom. @@ -1099,12 +1140,14 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p } void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, int p_outline_size, const Color &p_color) const { - const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped); + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); Vector2 ofs = p_pos; // Draw at the baseline. - for (int i = 0; i < glyphs.size(); i++) { + for (int i = 0; i < v_size; i++) { for (int j = 0; j < glyphs[i].repeat; j++) { if (p_clip_r > 0) { // Clip right / bottom. diff --git a/servers/text_server.h b/servers/text_server.h index 6796b7f1d6..09179cd218 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -94,7 +94,8 @@ public: FEATURE_KASHIDA_JUSTIFICATION = 1 << 3, FEATURE_BREAK_ITERATORS = 1 << 4, FEATURE_FONT_SYSTEM = 1 << 5, - FEATURE_USE_SUPPORT_DATA = 1 << 6 + FEATURE_FONT_VARIABLE = 1 << 6, + FEATURE_USE_SUPPORT_DATA = 1 << 7 }; struct Glyph { @@ -246,6 +247,10 @@ public: virtual bool font_get_antialiased(RID p_font) const = 0; virtual Dictionary font_get_feature_list(RID p_font) const { return Dictionary(); }; + virtual Dictionary font_get_variation_list(RID p_font) const { return Dictionary(); }; + + virtual void font_set_variation(RID p_font, const String &p_name, double p_value){}; + virtual double font_get_variation(RID p_font, const String &p_name) const { return 0; }; virtual void font_set_distance_field_hint(RID p_font, bool p_distance_field) = 0; virtual bool font_get_distance_field_hint(RID p_font) const = 0; diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index ad5cee92ea..a59565fe0d 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -38,9 +38,9 @@ void XRPositionalTracker::_bind_methods() { BIND_ENUM_CONSTANT(TRACKER_RIGHT_HAND); // this class is read only from GDScript, so we only have access to getters.. - ClassDB::bind_method(D_METHOD("get_type"), &XRPositionalTracker::get_type); + ClassDB::bind_method(D_METHOD("get_tracker_type"), &XRPositionalTracker::get_tracker_type); ClassDB::bind_method(D_METHOD("get_tracker_id"), &XRPositionalTracker::get_tracker_id); - ClassDB::bind_method(D_METHOD("get_name"), &XRPositionalTracker::get_name); + ClassDB::bind_method(D_METHOD("get_tracker_name"), &XRPositionalTracker::get_tracker_name); ClassDB::bind_method(D_METHOD("get_joy_id"), &XRPositionalTracker::get_joy_id); ClassDB::bind_method(D_METHOD("get_tracks_orientation"), &XRPositionalTracker::get_tracks_orientation); ClassDB::bind_method(D_METHOD("get_orientation"), &XRPositionalTracker::get_orientation); @@ -77,7 +77,7 @@ void XRPositionalTracker::set_type(XRServer::TrackerType p_type) { }; }; -XRServer::TrackerType XRPositionalTracker::get_type() const { +XRServer::TrackerType XRPositionalTracker::get_tracker_type() const { return type; }; @@ -85,7 +85,7 @@ void XRPositionalTracker::set_name(const String &p_name) { name = p_name; }; -StringName XRPositionalTracker::get_name() const { +StringName XRPositionalTracker::get_tracker_name() const { return name; }; diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index 515359e9b1..8834b64464 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -72,9 +72,9 @@ protected: public: void set_type(XRServer::TrackerType p_type); - XRServer::TrackerType get_type() const; + XRServer::TrackerType get_tracker_type() const; void set_name(const String &p_name); - StringName get_name() const; + StringName get_tracker_name() const; int get_tracker_id() const; void set_joy_id(int p_joy_id); int get_joy_id() const; diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index ba9f26e7c7..9d35825ae9 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -235,7 +235,7 @@ Array XRServer::get_interfaces() const { bool XRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const { for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { return true; }; }; @@ -264,7 +264,7 @@ void XRServer::add_tracker(XRPositionalTracker *p_tracker) { ERR_FAIL_NULL(p_tracker); trackers.push_back(p_tracker); - emit_signal("tracker_added", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); + emit_signal("tracker_added", p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id()); }; void XRServer::remove_tracker(XRPositionalTracker *p_tracker) { @@ -280,7 +280,7 @@ void XRServer::remove_tracker(XRPositionalTracker *p_tracker) { ERR_FAIL_COND(idx == -1); - emit_signal("tracker_removed", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); + emit_signal("tracker_removed", p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id()); trackers.remove(idx); }; @@ -298,7 +298,7 @@ XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, i ERR_FAIL_COND_V(p_tracker_id == 0, nullptr); for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { return trackers[i]; }; }; diff --git a/tests/data/translations.csv b/tests/data/translations.csv new file mode 100644 index 0000000000..4c9ad4996a --- /dev/null +++ b/tests/data/translations.csv @@ -0,0 +1,3 @@ +keys,en,de +GOOD_MORNING,"Good Morning","Guten Morgen" +GOOD_EVENING,"Good Evening","" diff --git a/core/io/file_access_buffered.h b/tests/test_file_access.h index 7fd99b6373..0d5c9d79ce 100644 --- a/core/io/file_access_buffered.h +++ b/tests/test_file_access.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* file_access_buffered.h */ +/* test_file_access.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,64 +28,37 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef FILE_ACCESS_BUFFERED_H -#define FILE_ACCESS_BUFFERED_H +#ifndef TEST_FILE_ACCESS_H +#define TEST_FILE_ACCESS_H #include "core/os/file_access.h" -#include "core/string/ustring.h" +namespace TestFileAccess { -class FileAccessBuffered : public FileAccess { -public: - enum { - DEFAULT_CACHE_SIZE = 128 * 1024, - }; +TEST_CASE("[FileAccess] CSV read") { + FileAccess *f = FileAccess::open("tests/data/translations.csv", FileAccess::READ); -private: - int cache_size = DEFAULT_CACHE_SIZE; + Vector<String> header = f->get_csv_line(); // Default delimiter: "," + REQUIRE(header.size() == 3); - int cache_data_left() const; - mutable Error last_error; + Vector<String> row1 = f->get_csv_line(","); + REQUIRE(row1.size() == 3); + CHECK(row1[0] == "GOOD_MORNING"); + CHECK(row1[1] == "Good Morning"); + CHECK(row1[2] == "Guten Morgen"); -protected: - Error set_error(Error p_error) const; + Vector<String> row2 = f->get_csv_line(); + REQUIRE(row2.size() == 3); + CHECK(row2[0] == "GOOD_EVENING"); + CHECK(row2[1] == "Good Evening"); + CHECK(row2[2] == ""); // Use case: not yet translated! - mutable struct File { - bool open = false; - int size = 0; - int offset = 0; - String name; - int access_flags = 0; - } file; + // https://github.com/godotengine/godot/issues/44269 + CHECK_MESSAGE(row2[2] != "\"", "Should not parse empty string as a single double quote."); - mutable struct Cache { - Vector<uint8_t> buffer; - int offset = 0; - } cache; + f->close(); + memdelete(f); +} +} // namespace TestFileAccess - virtual int read_data_block(int p_offset, int p_size, uint8_t *p_dest = nullptr) const = 0; - - void set_cache_size(int p_size); - int get_cache_size(); - -public: - virtual size_t get_position() const; ///< get position in the file - virtual size_t get_len() const; ///< get size of the file - - virtual void seek(size_t p_position); ///< seek to a given position - virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file - - virtual bool eof_reached() const; - - virtual uint8_t get_8() const; - virtual int get_buffer(uint8_t *p_dest, int p_length) const; ///< get an array of bytes - - virtual bool is_open() const; - - virtual Error get_error() const; - - FileAccessBuffered() {} - virtual ~FileAccessBuffered() {} -}; - -#endif +#endif // TEST_FILE_ACCESS_H diff --git a/tests/test_main.cpp b/tests/test_main.cpp index dd8c36e737..9f2c2d6911 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -42,6 +42,7 @@ #include "test_crypto.h" #include "test_curve.h" #include "test_expression.h" +#include "test_file_access.h" #include "test_gradient.h" #include "test_gui.h" #include "test_json.h" @@ -56,6 +57,7 @@ #include "test_pck_packer.h" #include "test_physics_2d.h" #include "test_physics_3d.h" +#include "test_random_number_generator.h" #include "test_rect2.h" #include "test_render.h" #include "test_shader_lang.h" diff --git a/tests/test_random_number_generator.h b/tests/test_random_number_generator.h new file mode 100644 index 0000000000..50ad5ee362 --- /dev/null +++ b/tests/test_random_number_generator.h @@ -0,0 +1,111 @@ +/*************************************************************************/ +/* test_random_number_generator.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 TEST_RANDOM_NUMBER_GENERATOR_H +#define TEST_RANDOM_NUMBER_GENERATOR_H + +#include "core/math/random_number_generator.h" +#include "tests/test_macros.h" + +namespace TestRandomNumberGenerator { + +TEST_CASE("[RandomNumberGenerator] Zero for first number immediately after seeding") { + Ref<RandomNumberGenerator> rng = memnew(RandomNumberGenerator); + rng->set_seed(0); + uint32_t n1 = rng->randi(); + uint32_t n2 = rng->randi(); + INFO("Initial random values: " << n1 << " " << n2); + CHECK(n1 != 0); + + rng->set_seed(1); + uint32_t n3 = rng->randi(); + uint32_t n4 = rng->randi(); + INFO("Values after changing the seed: " << n3 << " " << n4); + CHECK(n3 != 0); +} + +TEST_CASE("[RandomNumberGenerator] Restore state") { + Ref<RandomNumberGenerator> rng = memnew(RandomNumberGenerator); + rng->randomize(); + uint64_t last_seed = rng->get_seed(); + INFO("Current seed: " << last_seed); + + rng->randi(); + rng->randi(); + + CHECK_MESSAGE(rng->get_seed() == last_seed, + "The seed should remain the same after generating some numbers"); + + uint64_t saved_state = rng->get_state(); + INFO("Current state: " << saved_state); + + real_t f1_before = rng->randf(); + real_t f2_before = rng->randf(); + INFO("This seed produces: " << f1_before << " " << f2_before); + + // Restore now. + rng->set_state(saved_state); + + real_t f1_after = rng->randf(); + real_t f2_after = rng->randf(); + INFO("Resetting the state produces: " << f1_after << " " << f2_after); + + String msg = "Should restore the sequence of numbers after resetting the state"; + CHECK_MESSAGE(f1_before == f1_after, msg); + CHECK_MESSAGE(f2_before == f2_after, msg); +} + +TEST_CASE("[RandomNumberGenerator] Restore from seed") { + Ref<RandomNumberGenerator> rng = memnew(RandomNumberGenerator); + rng->set_seed(0); + INFO("Current seed: " << rng->get_seed()); + uint32_t s0_1_before = rng->randi(); + uint32_t s0_2_before = rng->randi(); + INFO("This seed produces: " << s0_1_before << " " << s0_2_before); + + rng->set_seed(9000); + INFO("Current seed: " << rng->get_seed()); + uint32_t s9000_1 = rng->randi(); + uint32_t s9000_2 = rng->randi(); + INFO("This seed produces: " << s9000_1 << " " << s9000_2); + + rng->set_seed(0); + INFO("Current seed: " << rng->get_seed()); + uint32_t s0_1_after = rng->randi(); + uint32_t s0_2_after = rng->randi(); + INFO("This seed produces: " << s0_1_after << " " << s0_2_after); + + String msg = "Should restore the sequence of numbers after resetting the seed"; + CHECK_MESSAGE(s0_1_before == s0_1_after, msg); + CHECK_MESSAGE(s0_2_before == s0_2_after, msg); +} +} // namespace TestRandomNumberGenerator + +#endif // TEST_RANDOM_NUMBER_GENERATOR_H diff --git a/thirdparty/README.md b/thirdparty/README.md index b2707e7f7c..3962a83597 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -357,6 +357,16 @@ File extracted from upstream release tarball: - Added 2 files `godot_core_mbedtls_platform.{c,h}` providing configuration for light bundling with core. +## meshoptimizer + +- Upstream: https://github.com/zeux/meshoptimizer +- Version: 0.15(2020) +- License: MIT + +File extracted from upstream release tarball: + +- Files in src/ go to thirdparty/meshoptimizer + ## miniupnpc diff --git a/thirdparty/meshoptimizer/LICENSE.md b/thirdparty/meshoptimizer/LICENSE.md new file mode 100644 index 0000000000..4fcd766d22 --- /dev/null +++ b/thirdparty/meshoptimizer/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016-2020 Arseny Kapoulkine + +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. diff --git a/thirdparty/meshoptimizer/allocator.cpp b/thirdparty/meshoptimizer/allocator.cpp new file mode 100644 index 0000000000..da7cc540b2 --- /dev/null +++ b/thirdparty/meshoptimizer/allocator.cpp @@ -0,0 +1,8 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +void meshopt_setAllocator(void* (*allocate)(size_t), void (*deallocate)(void*)) +{ + meshopt_Allocator::Storage::allocate = allocate; + meshopt_Allocator::Storage::deallocate = deallocate; +} diff --git a/thirdparty/meshoptimizer/clusterizer.cpp b/thirdparty/meshoptimizer/clusterizer.cpp new file mode 100644 index 0000000000..f7d88c5136 --- /dev/null +++ b/thirdparty/meshoptimizer/clusterizer.cpp @@ -0,0 +1,351 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <math.h> +#include <string.h> + +// This work is based on: +// Graham Wihlidal. Optimizing the Graphics Pipeline with Compute. 2016 +// Matthaeus Chajdas. GeometryFX 1.2 - Cluster Culling. 2016 +// Jack Ritter. An Efficient Bounding Sphere. 1990 +namespace meshopt +{ + +static void computeBoundingSphere(float result[4], const float points[][3], size_t count) +{ + assert(count > 0); + + // find extremum points along all 3 axes; for each axis we get a pair of points with min/max coordinates + size_t pmin[3] = {0, 0, 0}; + size_t pmax[3] = {0, 0, 0}; + + for (size_t i = 0; i < count; ++i) + { + const float* p = points[i]; + + for (int axis = 0; axis < 3; ++axis) + { + pmin[axis] = (p[axis] < points[pmin[axis]][axis]) ? i : pmin[axis]; + pmax[axis] = (p[axis] > points[pmax[axis]][axis]) ? i : pmax[axis]; + } + } + + // find the pair of points with largest distance + float paxisd2 = 0; + int paxis = 0; + + for (int axis = 0; axis < 3; ++axis) + { + const float* p1 = points[pmin[axis]]; + const float* p2 = points[pmax[axis]]; + + float d2 = (p2[0] - p1[0]) * (p2[0] - p1[0]) + (p2[1] - p1[1]) * (p2[1] - p1[1]) + (p2[2] - p1[2]) * (p2[2] - p1[2]); + + if (d2 > paxisd2) + { + paxisd2 = d2; + paxis = axis; + } + } + + // use the longest segment as the initial sphere diameter + const float* p1 = points[pmin[paxis]]; + const float* p2 = points[pmax[paxis]]; + + float center[3] = {(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2, (p1[2] + p2[2]) / 2}; + float radius = sqrtf(paxisd2) / 2; + + // iteratively adjust the sphere up until all points fit + for (size_t i = 0; i < count; ++i) + { + const float* p = points[i]; + float d2 = (p[0] - center[0]) * (p[0] - center[0]) + (p[1] - center[1]) * (p[1] - center[1]) + (p[2] - center[2]) * (p[2] - center[2]); + + if (d2 > radius * radius) + { + float d = sqrtf(d2); + assert(d > 0); + + float k = 0.5f + (radius / d) / 2; + + center[0] = center[0] * k + p[0] * (1 - k); + center[1] = center[1] * k + p[1] * (1 - k); + center[2] = center[2] * k + p[2] * (1 - k); + radius = (radius + d) / 2; + } + } + + result[0] = center[0]; + result[1] = center[1]; + result[2] = center[2]; + result[3] = radius; +} + +} // namespace meshopt + +size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles) +{ + assert(index_count % 3 == 0); + assert(max_vertices >= 3); + assert(max_triangles >= 1); + + // meshlet construction is limited by max vertices and max triangles per meshlet + // the worst case is that the input is an unindexed stream since this equally stresses both limits + // note that we assume that in the worst case, we leave 2 vertices unpacked in each meshlet - if we have space for 3 we can pack any triangle + size_t max_vertices_conservative = max_vertices - 2; + size_t meshlet_limit_vertices = (index_count + max_vertices_conservative - 1) / max_vertices_conservative; + size_t meshlet_limit_triangles = (index_count / 3 + max_triangles - 1) / max_triangles; + + return meshlet_limit_vertices > meshlet_limit_triangles ? meshlet_limit_vertices : meshlet_limit_triangles; +} + +size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles) +{ + assert(index_count % 3 == 0); + assert(max_vertices >= 3); + assert(max_triangles >= 1); + + meshopt_Allocator allocator; + + meshopt_Meshlet meshlet; + memset(&meshlet, 0, sizeof(meshlet)); + + assert(max_vertices <= sizeof(meshlet.vertices) / sizeof(meshlet.vertices[0])); + assert(max_triangles <= sizeof(meshlet.indices) / 3); + + // index of the vertex in the meshlet, 0xff if the vertex isn't used + unsigned char* used = allocator.allocate<unsigned char>(vertex_count); + memset(used, -1, vertex_count); + + size_t offset = 0; + + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2]; + assert(a < vertex_count && b < vertex_count && c < vertex_count); + + unsigned char& av = used[a]; + unsigned char& bv = used[b]; + unsigned char& cv = used[c]; + + unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff); + + if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles) + { + destination[offset++] = meshlet; + + for (size_t j = 0; j < meshlet.vertex_count; ++j) + used[meshlet.vertices[j]] = 0xff; + + memset(&meshlet, 0, sizeof(meshlet)); + } + + if (av == 0xff) + { + av = meshlet.vertex_count; + meshlet.vertices[meshlet.vertex_count++] = a; + } + + if (bv == 0xff) + { + bv = meshlet.vertex_count; + meshlet.vertices[meshlet.vertex_count++] = b; + } + + if (cv == 0xff) + { + cv = meshlet.vertex_count; + meshlet.vertices[meshlet.vertex_count++] = c; + } + + meshlet.indices[meshlet.triangle_count][0] = av; + meshlet.indices[meshlet.triangle_count][1] = bv; + meshlet.indices[meshlet.triangle_count][2] = cv; + meshlet.triangle_count++; + } + + if (meshlet.triangle_count) + destination[offset++] = meshlet; + + assert(offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles)); + + return offset; +} + +meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + + assert(index_count / 3 <= 256); + + (void)vertex_count; + + size_t vertex_stride_float = vertex_positions_stride / sizeof(float); + + // compute triangle normals and gather triangle corners + float normals[256][3]; + float corners[256][3][3]; + size_t triangles = 0; + + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2]; + assert(a < vertex_count && b < vertex_count && c < vertex_count); + + const float* p0 = vertex_positions + vertex_stride_float * a; + const float* p1 = vertex_positions + vertex_stride_float * b; + const float* p2 = vertex_positions + vertex_stride_float * c; + + float p10[3] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]}; + float p20[3] = {p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]}; + + float normalx = p10[1] * p20[2] - p10[2] * p20[1]; + float normaly = p10[2] * p20[0] - p10[0] * p20[2]; + float normalz = p10[0] * p20[1] - p10[1] * p20[0]; + + float area = sqrtf(normalx * normalx + normaly * normaly + normalz * normalz); + + // no need to include degenerate triangles - they will be invisible anyway + if (area == 0.f) + continue; + + // record triangle normals & corners for future use; normal and corner 0 define a plane equation + normals[triangles][0] = normalx / area; + normals[triangles][1] = normaly / area; + normals[triangles][2] = normalz / area; + memcpy(corners[triangles][0], p0, 3 * sizeof(float)); + memcpy(corners[triangles][1], p1, 3 * sizeof(float)); + memcpy(corners[triangles][2], p2, 3 * sizeof(float)); + triangles++; + } + + meshopt_Bounds bounds = {}; + + // degenerate cluster, no valid triangles => trivial reject (cone data is 0) + if (triangles == 0) + return bounds; + + // compute cluster bounding sphere; we'll use the center to determine normal cone apex as well + float psphere[4] = {}; + computeBoundingSphere(psphere, corners[0], triangles * 3); + + float center[3] = {psphere[0], psphere[1], psphere[2]}; + + // treating triangle normals as points, find the bounding sphere - the sphere center determines the optimal cone axis + float nsphere[4] = {}; + computeBoundingSphere(nsphere, normals, triangles); + + float axis[3] = {nsphere[0], nsphere[1], nsphere[2]}; + float axislength = sqrtf(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]); + float invaxislength = axislength == 0.f ? 0.f : 1.f / axislength; + + axis[0] *= invaxislength; + axis[1] *= invaxislength; + axis[2] *= invaxislength; + + // compute a tight cone around all normals, mindp = cos(angle/2) + float mindp = 1.f; + + for (size_t i = 0; i < triangles; ++i) + { + float dp = normals[i][0] * axis[0] + normals[i][1] * axis[1] + normals[i][2] * axis[2]; + + mindp = (dp < mindp) ? dp : mindp; + } + + // fill bounding sphere info; note that below we can return bounds without cone information for degenerate cones + bounds.center[0] = center[0]; + bounds.center[1] = center[1]; + bounds.center[2] = center[2]; + bounds.radius = psphere[3]; + + // degenerate cluster, normal cone is larger than a hemisphere => trivial accept + // note that if mindp is positive but close to 0, the triangle intersection code below gets less stable + // we arbitrarily decide that if a normal cone is ~168 degrees wide or more, the cone isn't useful + if (mindp <= 0.1f) + { + bounds.cone_cutoff = 1; + bounds.cone_cutoff_s8 = 127; + return bounds; + } + + float maxt = 0; + + // we need to find the point on center-t*axis ray that lies in negative half-space of all triangles + for (size_t i = 0; i < triangles; ++i) + { + // dot(center-t*axis-corner, trinormal) = 0 + // dot(center-corner, trinormal) - t * dot(axis, trinormal) = 0 + float cx = center[0] - corners[i][0][0]; + float cy = center[1] - corners[i][0][1]; + float cz = center[2] - corners[i][0][2]; + + float dc = cx * normals[i][0] + cy * normals[i][1] + cz * normals[i][2]; + float dn = axis[0] * normals[i][0] + axis[1] * normals[i][1] + axis[2] * normals[i][2]; + + // dn should be larger than mindp cutoff above + assert(dn > 0.f); + float t = dc / dn; + + maxt = (t > maxt) ? t : maxt; + } + + // cone apex should be in the negative half-space of all cluster triangles by construction + bounds.cone_apex[0] = center[0] - axis[0] * maxt; + bounds.cone_apex[1] = center[1] - axis[1] * maxt; + bounds.cone_apex[2] = center[2] - axis[2] * maxt; + + // note: this axis is the axis of the normal cone, but our test for perspective camera effectively negates the axis + bounds.cone_axis[0] = axis[0]; + bounds.cone_axis[1] = axis[1]; + bounds.cone_axis[2] = axis[2]; + + // cos(a) for normal cone is mindp; we need to add 90 degrees on both sides and invert the cone + // which gives us -cos(a+90) = -(-sin(a)) = sin(a) = sqrt(1 - cos^2(a)) + bounds.cone_cutoff = sqrtf(1 - mindp * mindp); + + // quantize axis & cutoff to 8-bit SNORM format + bounds.cone_axis_s8[0] = (signed char)(meshopt_quantizeSnorm(bounds.cone_axis[0], 8)); + bounds.cone_axis_s8[1] = (signed char)(meshopt_quantizeSnorm(bounds.cone_axis[1], 8)); + bounds.cone_axis_s8[2] = (signed char)(meshopt_quantizeSnorm(bounds.cone_axis[2], 8)); + + // for the 8-bit test to be conservative, we need to adjust the cutoff by measuring the max. error + float cone_axis_s8_e0 = fabsf(bounds.cone_axis_s8[0] / 127.f - bounds.cone_axis[0]); + float cone_axis_s8_e1 = fabsf(bounds.cone_axis_s8[1] / 127.f - bounds.cone_axis[1]); + float cone_axis_s8_e2 = fabsf(bounds.cone_axis_s8[2] / 127.f - bounds.cone_axis[2]); + + // note that we need to round this up instead of rounding to nearest, hence +1 + int cone_cutoff_s8 = int(127 * (bounds.cone_cutoff + cone_axis_s8_e0 + cone_axis_s8_e1 + cone_axis_s8_e2) + 1); + + bounds.cone_cutoff_s8 = (cone_cutoff_s8 > 127) ? 127 : (signed char)(cone_cutoff_s8); + + return bounds; +} + +meshopt_Bounds meshopt_computeMeshletBounds(const meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + + unsigned int indices[sizeof(meshlet->indices) / sizeof(meshlet->indices[0][0])]; + + for (size_t i = 0; i < meshlet->triangle_count; ++i) + { + unsigned int a = meshlet->vertices[meshlet->indices[i][0]]; + unsigned int b = meshlet->vertices[meshlet->indices[i][1]]; + unsigned int c = meshlet->vertices[meshlet->indices[i][2]]; + + assert(a < vertex_count && b < vertex_count && c < vertex_count); + + indices[i * 3 + 0] = a; + indices[i * 3 + 1] = b; + indices[i * 3 + 2] = c; + } + + return meshopt_computeClusterBounds(indices, meshlet->triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride); +} diff --git a/thirdparty/meshoptimizer/indexcodec.cpp b/thirdparty/meshoptimizer/indexcodec.cpp new file mode 100644 index 0000000000..eeb541e5be --- /dev/null +++ b/thirdparty/meshoptimizer/indexcodec.cpp @@ -0,0 +1,752 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <string.h> + +#ifndef TRACE +#define TRACE 0 +#endif + +#if TRACE +#include <stdio.h> +#endif + +// This work is based on: +// Fabian Giesen. Simple lossless index buffer compression & follow-up. 2013 +// Conor Stokes. Vertex Cache Optimised Index Buffer Compression. 2014 +namespace meshopt +{ + +const unsigned char kIndexHeader = 0xe0; +const unsigned char kSequenceHeader = 0xd0; + +static int gEncodeIndexVersion = 0; + +typedef unsigned int VertexFifo[16]; +typedef unsigned int EdgeFifo[16][2]; + +static const unsigned int kTriangleIndexOrder[3][3] = { + {0, 1, 2}, + {1, 2, 0}, + {2, 0, 1}, +}; + +static const unsigned char kCodeAuxEncodingTable[16] = { + 0x00, 0x76, 0x87, 0x56, 0x67, 0x78, 0xa9, 0x86, 0x65, 0x89, 0x68, 0x98, 0x01, 0x69, + 0, 0, // last two entries aren't used for encoding +}; + +static int rotateTriangle(unsigned int a, unsigned int b, unsigned int c, unsigned int next) +{ + (void)a; + + return (b == next) ? 1 : (c == next) ? 2 : 0; +} + +static int getEdgeFifo(EdgeFifo fifo, unsigned int a, unsigned int b, unsigned int c, size_t offset) +{ + for (int i = 0; i < 16; ++i) + { + size_t index = (offset - 1 - i) & 15; + + unsigned int e0 = fifo[index][0]; + unsigned int e1 = fifo[index][1]; + + if (e0 == a && e1 == b) + return (i << 2) | 0; + if (e0 == b && e1 == c) + return (i << 2) | 1; + if (e0 == c && e1 == a) + return (i << 2) | 2; + } + + return -1; +} + +static void pushEdgeFifo(EdgeFifo fifo, unsigned int a, unsigned int b, size_t& offset) +{ + fifo[offset][0] = a; + fifo[offset][1] = b; + offset = (offset + 1) & 15; +} + +static int getVertexFifo(VertexFifo fifo, unsigned int v, size_t offset) +{ + for (int i = 0; i < 16; ++i) + { + size_t index = (offset - 1 - i) & 15; + + if (fifo[index] == v) + return i; + } + + return -1; +} + +static void pushVertexFifo(VertexFifo fifo, unsigned int v, size_t& offset, int cond = 1) +{ + fifo[offset] = v; + offset = (offset + cond) & 15; +} + +static void encodeVByte(unsigned char*& data, unsigned int v) +{ + // encode 32-bit value in up to 5 7-bit groups + do + { + *data++ = (v & 127) | (v > 127 ? 128 : 0); + v >>= 7; + } while (v); +} + +static unsigned int decodeVByte(const unsigned char*& data) +{ + unsigned char lead = *data++; + + // fast path: single byte + if (lead < 128) + return lead; + + // slow path: up to 4 extra bytes + // note that this loop always terminates, which is important for malformed data + unsigned int result = lead & 127; + unsigned int shift = 7; + + for (int i = 0; i < 4; ++i) + { + unsigned char group = *data++; + result |= (group & 127) << shift; + shift += 7; + + if (group < 128) + break; + } + + return result; +} + +static void encodeIndex(unsigned char*& data, unsigned int index, unsigned int last) +{ + unsigned int d = index - last; + unsigned int v = (d << 1) ^ (int(d) >> 31); + + encodeVByte(data, v); +} + +static unsigned int decodeIndex(const unsigned char*& data, unsigned int last) +{ + unsigned int v = decodeVByte(data); + unsigned int d = (v >> 1) ^ -int(v & 1); + + return last + d; +} + +static int getCodeAuxIndex(unsigned char v, const unsigned char* table) +{ + for (int i = 0; i < 16; ++i) + if (table[i] == v) + return i; + + return -1; +} + +static void writeTriangle(void* destination, size_t offset, size_t index_size, unsigned int a, unsigned int b, unsigned int c) +{ + if (index_size == 2) + { + static_cast<unsigned short*>(destination)[offset + 0] = (unsigned short)(a); + static_cast<unsigned short*>(destination)[offset + 1] = (unsigned short)(b); + static_cast<unsigned short*>(destination)[offset + 2] = (unsigned short)(c); + } + else + { + static_cast<unsigned int*>(destination)[offset + 0] = a; + static_cast<unsigned int*>(destination)[offset + 1] = b; + static_cast<unsigned int*>(destination)[offset + 2] = c; + } +} + +#if TRACE +static size_t sortTop16(unsigned char dest[16], size_t stats[256]) +{ + size_t destsize = 0; + + for (size_t i = 0; i < 256; ++i) + { + size_t j = 0; + for (; j < destsize; ++j) + { + if (stats[i] >= stats[dest[j]]) + { + if (destsize < 16) + destsize++; + + memmove(&dest[j + 1], &dest[j], destsize - 1 - j); + dest[j] = (unsigned char)i; + break; + } + } + + if (j == destsize && destsize < 16) + { + dest[destsize] = (unsigned char)i; + destsize++; + } + } + + return destsize; +} +#endif + +} // namespace meshopt + +size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + +#if TRACE + size_t codestats[256] = {}; + size_t codeauxstats[256] = {}; +#endif + + // the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table + if (buffer_size < 1 + index_count / 3 + 16) + return 0; + + int version = gEncodeIndexVersion; + + buffer[0] = (unsigned char)(kIndexHeader | version); + + EdgeFifo edgefifo; + memset(edgefifo, -1, sizeof(edgefifo)); + + VertexFifo vertexfifo; + memset(vertexfifo, -1, sizeof(vertexfifo)); + + size_t edgefifooffset = 0; + size_t vertexfifooffset = 0; + + unsigned int next = 0; + unsigned int last = 0; + + unsigned char* code = buffer + 1; + unsigned char* data = code + index_count / 3; + unsigned char* data_safe_end = buffer + buffer_size - 16; + + int fecmax = version >= 1 ? 13 : 15; + + // use static encoding table; it's possible to pack the result and then build an optimal table and repack + // for now we keep it simple and use the table that has been generated based on symbol frequency on a training mesh set + const unsigned char* codeaux_table = kCodeAuxEncodingTable; + + for (size_t i = 0; i < index_count; i += 3) + { + // make sure we have enough space to write a triangle + // each triangle writes at most 16 bytes: 1b for codeaux and 5b for each free index + // after this we can be sure we can write without extra bounds checks + if (data > data_safe_end) + return 0; + + int fer = getEdgeFifo(edgefifo, indices[i + 0], indices[i + 1], indices[i + 2], edgefifooffset); + + if (fer >= 0 && (fer >> 2) < 15) + { + const unsigned int* order = kTriangleIndexOrder[fer & 3]; + + unsigned int a = indices[i + order[0]], b = indices[i + order[1]], c = indices[i + order[2]]; + + // encode edge index and vertex fifo index, next or free index + int fe = fer >> 2; + int fc = getVertexFifo(vertexfifo, c, vertexfifooffset); + + int fec = (fc >= 1 && fc < fecmax) ? fc : (c == next) ? (next++, 0) : 15; + + if (fec == 15 && version >= 1) + { + // encode last-1 and last+1 to optimize strip-like sequences + if (c + 1 == last) + fec = 13, last = c; + if (c == last + 1) + fec = 14, last = c; + } + + *code++ = (unsigned char)((fe << 4) | fec); + +#if TRACE + codestats[code[-1]]++; +#endif + + // note that we need to update the last index since free indices are delta-encoded + if (fec == 15) + encodeIndex(data, c, last), last = c; + + // we only need to push third vertex since first two are likely already in the vertex fifo + if (fec == 0 || fec >= fecmax) + pushVertexFifo(vertexfifo, c, vertexfifooffset); + + // we only need to push two new edges to edge fifo since the third one is already there + pushEdgeFifo(edgefifo, c, b, edgefifooffset); + pushEdgeFifo(edgefifo, a, c, edgefifooffset); + } + else + { + int rotation = rotateTriangle(indices[i + 0], indices[i + 1], indices[i + 2], next); + const unsigned int* order = kTriangleIndexOrder[rotation]; + + unsigned int a = indices[i + order[0]], b = indices[i + order[1]], c = indices[i + order[2]]; + + // if a/b/c are 0/1/2, we emit a reset code + bool reset = false; + + if (a == 0 && b == 1 && c == 2 && next > 0 && version >= 1) + { + reset = true; + next = 0; + + // reset vertex fifo to make sure we don't accidentally reference vertices from that in the future + // this makes sure next continues to get incremented instead of being stuck + memset(vertexfifo, -1, sizeof(vertexfifo)); + } + + int fb = getVertexFifo(vertexfifo, b, vertexfifooffset); + int fc = getVertexFifo(vertexfifo, c, vertexfifooffset); + + // after rotation, a is almost always equal to next, so we don't waste bits on FIFO encoding for a + int fea = (a == next) ? (next++, 0) : 15; + int feb = (fb >= 0 && fb < 14) ? (fb + 1) : (b == next) ? (next++, 0) : 15; + int fec = (fc >= 0 && fc < 14) ? (fc + 1) : (c == next) ? (next++, 0) : 15; + + // we encode feb & fec in 4 bits using a table if possible, and as a full byte otherwise + unsigned char codeaux = (unsigned char)((feb << 4) | fec); + int codeauxindex = getCodeAuxIndex(codeaux, codeaux_table); + + // <14 encodes an index into codeaux table, 14 encodes fea=0, 15 encodes fea=15 + if (fea == 0 && codeauxindex >= 0 && codeauxindex < 14 && !reset) + { + *code++ = (unsigned char)((15 << 4) | codeauxindex); + } + else + { + *code++ = (unsigned char)((15 << 4) | 14 | fea); + *data++ = codeaux; + } + +#if TRACE + codestats[code[-1]]++; + codeauxstats[codeaux]++; +#endif + + // note that we need to update the last index since free indices are delta-encoded + if (fea == 15) + encodeIndex(data, a, last), last = a; + + if (feb == 15) + encodeIndex(data, b, last), last = b; + + if (fec == 15) + encodeIndex(data, c, last), last = c; + + // only push vertices that weren't already in fifo + if (fea == 0 || fea == 15) + pushVertexFifo(vertexfifo, a, vertexfifooffset); + + if (feb == 0 || feb == 15) + pushVertexFifo(vertexfifo, b, vertexfifooffset); + + if (fec == 0 || fec == 15) + pushVertexFifo(vertexfifo, c, vertexfifooffset); + + // all three edges aren't in the fifo; pushing all of them is important so that we can match them for later triangles + pushEdgeFifo(edgefifo, b, a, edgefifooffset); + pushEdgeFifo(edgefifo, c, b, edgefifooffset); + pushEdgeFifo(edgefifo, a, c, edgefifooffset); + } + } + + // make sure we have enough space to write codeaux table + if (data > data_safe_end) + return 0; + + // add codeaux encoding table to the end of the stream; this is used for decoding codeaux *and* as padding + // we need padding for decoding to be able to assume that each triangle is encoded as <= 16 bytes of extra data + // this is enough space for aux byte + 5 bytes per varint index which is the absolute worst case for any input + for (size_t i = 0; i < 16; ++i) + { + // decoder assumes that table entries never refer to separately encoded indices + assert((codeaux_table[i] & 0xf) != 0xf && (codeaux_table[i] >> 4) != 0xf); + + *data++ = codeaux_table[i]; + } + + // since we encode restarts as codeaux without a table reference, we need to make sure 00 is encoded as a table reference + assert(codeaux_table[0] == 0); + + assert(data >= buffer + index_count / 3 + 16); + assert(data <= buffer + buffer_size); + +#if TRACE + unsigned char codetop[16], codeauxtop[16]; + size_t codetopsize = sortTop16(codetop, codestats); + size_t codeauxtopsize = sortTop16(codeauxtop, codeauxstats); + + size_t sumcode = 0, sumcodeaux = 0; + for (size_t i = 0; i < 256; ++i) + sumcode += codestats[i], sumcodeaux += codeauxstats[i]; + + size_t acccode = 0, acccodeaux = 0; + + printf("code\t\t\t\t\tcodeaux\n"); + + for (size_t i = 0; i < codetopsize && i < codeauxtopsize; ++i) + { + acccode += codestats[codetop[i]]; + acccodeaux += codeauxstats[codeauxtop[i]]; + + printf("%2d: %02x = %d (%.1f%% ..%.1f%%)\t\t%2d: %02x = %d (%.1f%% ..%.1f%%)\n", + int(i), codetop[i], int(codestats[codetop[i]]), double(codestats[codetop[i]]) / double(sumcode) * 100, double(acccode) / double(sumcode) * 100, + int(i), codeauxtop[i], int(codeauxstats[codeauxtop[i]]), double(codeauxstats[codeauxtop[i]]) / double(sumcodeaux) * 100, double(acccodeaux) / double(sumcodeaux) * 100); + } +#endif + + return data - buffer; +} + +size_t meshopt_encodeIndexBufferBound(size_t index_count, size_t vertex_count) +{ + assert(index_count % 3 == 0); + + // compute number of bits required for each index + unsigned int vertex_bits = 1; + + while (vertex_bits < 32 && vertex_count > size_t(1) << vertex_bits) + vertex_bits++; + + // worst-case encoding is 2 header bytes + 3 varint-7 encoded index deltas + unsigned int vertex_groups = (vertex_bits + 1 + 6) / 7; + + return 1 + (index_count / 3) * (2 + 3 * vertex_groups) + 16; +} + +void meshopt_encodeIndexVersion(int version) +{ + assert(unsigned(version) <= 1); + + meshopt::gEncodeIndexVersion = version; +} + +int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(index_size == 2 || index_size == 4); + + // the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table + if (buffer_size < 1 + index_count / 3 + 16) + return -2; + + if ((buffer[0] & 0xf0) != kIndexHeader) + return -1; + + int version = buffer[0] & 0x0f; + if (version > 1) + return -1; + + EdgeFifo edgefifo; + memset(edgefifo, -1, sizeof(edgefifo)); + + VertexFifo vertexfifo; + memset(vertexfifo, -1, sizeof(vertexfifo)); + + size_t edgefifooffset = 0; + size_t vertexfifooffset = 0; + + unsigned int next = 0; + unsigned int last = 0; + + int fecmax = version >= 1 ? 13 : 15; + + // since we store 16-byte codeaux table at the end, triangle data has to begin before data_safe_end + const unsigned char* code = buffer + 1; + const unsigned char* data = code + index_count / 3; + const unsigned char* data_safe_end = buffer + buffer_size - 16; + + const unsigned char* codeaux_table = data_safe_end; + + for (size_t i = 0; i < index_count; i += 3) + { + // make sure we have enough data to read for a triangle + // each triangle reads at most 16 bytes of data: 1b for codeaux and 5b for each free index + // after this we can be sure we can read without extra bounds checks + if (data > data_safe_end) + return -2; + + unsigned char codetri = *code++; + + if (codetri < 0xf0) + { + int fe = codetri >> 4; + + // fifo reads are wrapped around 16 entry buffer + unsigned int a = edgefifo[(edgefifooffset - 1 - fe) & 15][0]; + unsigned int b = edgefifo[(edgefifooffset - 1 - fe) & 15][1]; + + int fec = codetri & 15; + + // note: this is the most common path in the entire decoder + // inside this if we try to stay branchless (by using cmov/etc.) since these aren't predictable + if (fec < fecmax) + { + // fifo reads are wrapped around 16 entry buffer + unsigned int cf = vertexfifo[(vertexfifooffset - 1 - fec) & 15]; + unsigned int c = (fec == 0) ? next : cf; + + int fec0 = fec == 0; + next += fec0; + + // output triangle + writeTriangle(destination, i, index_size, a, b, c); + + // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly + pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0); + + pushEdgeFifo(edgefifo, c, b, edgefifooffset); + pushEdgeFifo(edgefifo, a, c, edgefifooffset); + } + else + { + unsigned int c = 0; + + // fec - (fec ^ 3) decodes 13, 14 into -1, 1 + // note that we need to update the last index since free indices are delta-encoded + last = c = (fec != 15) ? last + (fec - (fec ^ 3)) : decodeIndex(data, last); + + // output triangle + writeTriangle(destination, i, index_size, a, b, c); + + // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly + pushVertexFifo(vertexfifo, c, vertexfifooffset); + + pushEdgeFifo(edgefifo, c, b, edgefifooffset); + pushEdgeFifo(edgefifo, a, c, edgefifooffset); + } + } + else + { + // fast path: read codeaux from the table + if (codetri < 0xfe) + { + unsigned char codeaux = codeaux_table[codetri & 15]; + + // note: table can't contain feb/fec=15 + int feb = codeaux >> 4; + int fec = codeaux & 15; + + // fifo reads are wrapped around 16 entry buffer + // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior + unsigned int a = next++; + + unsigned int bf = vertexfifo[(vertexfifooffset - feb) & 15]; + unsigned int b = (feb == 0) ? next : bf; + + int feb0 = feb == 0; + next += feb0; + + unsigned int cf = vertexfifo[(vertexfifooffset - fec) & 15]; + unsigned int c = (fec == 0) ? next : cf; + + int fec0 = fec == 0; + next += fec0; + + // output triangle + writeTriangle(destination, i, index_size, a, b, c); + + // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly + pushVertexFifo(vertexfifo, a, vertexfifooffset); + pushVertexFifo(vertexfifo, b, vertexfifooffset, feb0); + pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0); + + pushEdgeFifo(edgefifo, b, a, edgefifooffset); + pushEdgeFifo(edgefifo, c, b, edgefifooffset); + pushEdgeFifo(edgefifo, a, c, edgefifooffset); + } + else + { + // slow path: read a full byte for codeaux instead of using a table lookup + unsigned char codeaux = *data++; + + int fea = codetri == 0xfe ? 0 : 15; + int feb = codeaux >> 4; + int fec = codeaux & 15; + + // reset: codeaux is 0 but encoded as not-a-table + if (codeaux == 0) + next = 0; + + // fifo reads are wrapped around 16 entry buffer + // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior + unsigned int a = (fea == 0) ? next++ : 0; + unsigned int b = (feb == 0) ? next++ : vertexfifo[(vertexfifooffset - feb) & 15]; + unsigned int c = (fec == 0) ? next++ : vertexfifo[(vertexfifooffset - fec) & 15]; + + // note that we need to update the last index since free indices are delta-encoded + if (fea == 15) + last = a = decodeIndex(data, last); + + if (feb == 15) + last = b = decodeIndex(data, last); + + if (fec == 15) + last = c = decodeIndex(data, last); + + // output triangle + writeTriangle(destination, i, index_size, a, b, c); + + // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly + pushVertexFifo(vertexfifo, a, vertexfifooffset); + pushVertexFifo(vertexfifo, b, vertexfifooffset, (feb == 0) | (feb == 15)); + pushVertexFifo(vertexfifo, c, vertexfifooffset, (fec == 0) | (fec == 15)); + + pushEdgeFifo(edgefifo, b, a, edgefifooffset); + pushEdgeFifo(edgefifo, c, b, edgefifooffset); + pushEdgeFifo(edgefifo, a, c, edgefifooffset); + } + } + } + + // we should've read all data bytes and stopped at the boundary between data and codeaux table + if (data != data_safe_end) + return -3; + + return 0; +} + +size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count) +{ + using namespace meshopt; + + // the minimum valid encoding is header, 1 byte per index and a 4-byte tail + if (buffer_size < 1 + index_count + 4) + return 0; + + int version = gEncodeIndexVersion; + + buffer[0] = (unsigned char)(kSequenceHeader | version); + + unsigned int last[2] = {}; + unsigned int current = 0; + + unsigned char* data = buffer + 1; + unsigned char* data_safe_end = buffer + buffer_size - 4; + + for (size_t i = 0; i < index_count; ++i) + { + // make sure we have enough data to write + // each index writes at most 5 bytes of data; there's a 4 byte tail after data_safe_end + // after this we can be sure we can write without extra bounds checks + if (data >= data_safe_end) + return 0; + + unsigned int index = indices[i]; + + // this is a heuristic that switches between baselines when the delta grows too large + // we want the encoded delta to fit into one byte (7 bits), but 2 bits are used for sign and baseline index + // for now we immediately switch the baseline when delta grows too large - this can be adjusted arbitrarily + int cd = int(index - last[current]); + current ^= ((cd < 0 ? -cd : cd) >= 30); + + // encode delta from the last index + unsigned int d = index - last[current]; + unsigned int v = (d << 1) ^ (int(d) >> 31); + + // note: low bit encodes the index of the last baseline which will be used for reconstruction + encodeVByte(data, (v << 1) | current); + + // update last for the next iteration that uses it + last[current] = index; + } + + // make sure we have enough space to write tail + if (data > data_safe_end) + return 0; + + for (int k = 0; k < 4; ++k) + *data++ = 0; + + return data - buffer; +} + +size_t meshopt_encodeIndexSequenceBound(size_t index_count, size_t vertex_count) +{ + // compute number of bits required for each index + unsigned int vertex_bits = 1; + + while (vertex_bits < 32 && vertex_count > size_t(1) << vertex_bits) + vertex_bits++; + + // worst-case encoding is 1 varint-7 encoded index delta for a K bit value and an extra bit + unsigned int vertex_groups = (vertex_bits + 1 + 1 + 6) / 7; + + return 1 + index_count * vertex_groups + 4; +} + +int meshopt_decodeIndexSequence(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size) +{ + using namespace meshopt; + + // the minimum valid encoding is header, 1 byte per index and a 4-byte tail + if (buffer_size < 1 + index_count + 4) + return -2; + + if ((buffer[0] & 0xf0) != kSequenceHeader) + return -1; + + int version = buffer[0] & 0x0f; + if (version > 1) + return -1; + + const unsigned char* data = buffer + 1; + const unsigned char* data_safe_end = buffer + buffer_size - 4; + + unsigned int last[2] = {}; + + for (size_t i = 0; i < index_count; ++i) + { + // make sure we have enough data to read + // each index reads at most 5 bytes of data; there's a 4 byte tail after data_safe_end + // after this we can be sure we can read without extra bounds checks + if (data >= data_safe_end) + return -2; + + unsigned int v = decodeVByte(data); + + // decode the index of the last baseline + unsigned int current = v & 1; + v >>= 1; + + // reconstruct index as a delta + unsigned int d = (v >> 1) ^ -int(v & 1); + unsigned int index = last[current] + d; + + // update last for the next iteration that uses it + last[current] = index; + + if (index_size == 2) + { + static_cast<unsigned short*>(destination)[i] = (unsigned short)(index); + } + else + { + static_cast<unsigned int*>(destination)[i] = index; + } + } + + // we should've read all data bytes and stopped at the boundary between data and tail + if (data != data_safe_end) + return -3; + + return 0; +} diff --git a/thirdparty/meshoptimizer/indexgenerator.cpp b/thirdparty/meshoptimizer/indexgenerator.cpp new file mode 100644 index 0000000000..aa4a30efa4 --- /dev/null +++ b/thirdparty/meshoptimizer/indexgenerator.cpp @@ -0,0 +1,347 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <string.h> + +namespace meshopt +{ + +static unsigned int hashUpdate4(unsigned int h, const unsigned char* key, size_t len) +{ + // MurmurHash2 + const unsigned int m = 0x5bd1e995; + const int r = 24; + + while (len >= 4) + { + unsigned int k = *reinterpret_cast<const unsigned int*>(key); + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + key += 4; + len -= 4; + } + + return h; +} + +struct VertexHasher +{ + const unsigned char* vertices; + size_t vertex_size; + size_t vertex_stride; + + size_t hash(unsigned int index) const + { + return hashUpdate4(0, vertices + index * vertex_stride, vertex_size); + } + + bool equal(unsigned int lhs, unsigned int rhs) const + { + return memcmp(vertices + lhs * vertex_stride, vertices + rhs * vertex_stride, vertex_size) == 0; + } +}; + +struct VertexStreamHasher +{ + const meshopt_Stream* streams; + size_t stream_count; + + size_t hash(unsigned int index) const + { + unsigned int h = 0; + + for (size_t i = 0; i < stream_count; ++i) + { + const meshopt_Stream& s = streams[i]; + const unsigned char* data = static_cast<const unsigned char*>(s.data); + + h = hashUpdate4(h, data + index * s.stride, s.size); + } + + return h; + } + + bool equal(unsigned int lhs, unsigned int rhs) const + { + for (size_t i = 0; i < stream_count; ++i) + { + const meshopt_Stream& s = streams[i]; + const unsigned char* data = static_cast<const unsigned char*>(s.data); + + if (memcmp(data + lhs * s.stride, data + rhs * s.stride, s.size) != 0) + return false; + } + + return true; + } +}; + +static size_t hashBuckets(size_t count) +{ + size_t buckets = 1; + while (buckets < count) + buckets *= 2; + + return buckets; +} + +template <typename T, typename Hash> +static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, const T& empty) +{ + assert(buckets > 0); + assert((buckets & (buckets - 1)) == 0); + + size_t hashmod = buckets - 1; + size_t bucket = hash.hash(key) & hashmod; + + for (size_t probe = 0; probe <= hashmod; ++probe) + { + T& item = table[bucket]; + + if (item == empty) + return &item; + + if (hash.equal(item, key)) + return &item; + + // hash collision, quadratic probing + bucket = (bucket + probe + 1) & hashmod; + } + + assert(false && "Hash table is full"); // unreachable + return 0; +} + +} // namespace meshopt + +size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size) +{ + using namespace meshopt; + + assert(indices || index_count == vertex_count); + assert(index_count % 3 == 0); + assert(vertex_size > 0 && vertex_size <= 256); + + meshopt_Allocator allocator; + + memset(destination, -1, vertex_count * sizeof(unsigned int)); + + VertexHasher hasher = {static_cast<const unsigned char*>(vertices), vertex_size, vertex_size}; + + size_t table_size = hashBuckets(vertex_count); + unsigned int* table = allocator.allocate<unsigned int>(table_size); + memset(table, -1, table_size * sizeof(unsigned int)); + + unsigned int next_vertex = 0; + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices ? indices[i] : unsigned(i); + assert(index < vertex_count); + + if (destination[index] == ~0u) + { + unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u); + + if (*entry == ~0u) + { + *entry = index; + + destination[index] = next_vertex++; + } + else + { + assert(destination[*entry] != ~0u); + + destination[index] = destination[*entry]; + } + } + } + + assert(next_vertex <= vertex_count); + + return next_vertex; +} + +size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count) +{ + using namespace meshopt; + + assert(indices || index_count == vertex_count); + assert(index_count % 3 == 0); + assert(stream_count > 0 && stream_count <= 16); + + for (size_t i = 0; i < stream_count; ++i) + { + assert(streams[i].size > 0 && streams[i].size <= 256); + assert(streams[i].size <= streams[i].stride); + } + + meshopt_Allocator allocator; + + memset(destination, -1, vertex_count * sizeof(unsigned int)); + + VertexStreamHasher hasher = {streams, stream_count}; + + size_t table_size = hashBuckets(vertex_count); + unsigned int* table = allocator.allocate<unsigned int>(table_size); + memset(table, -1, table_size * sizeof(unsigned int)); + + unsigned int next_vertex = 0; + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices ? indices[i] : unsigned(i); + assert(index < vertex_count); + + if (destination[index] == ~0u) + { + unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u); + + if (*entry == ~0u) + { + *entry = index; + + destination[index] = next_vertex++; + } + else + { + assert(destination[*entry] != ~0u); + + destination[index] = destination[*entry]; + } + } + } + + assert(next_vertex <= vertex_count); + + return next_vertex; +} + +void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap) +{ + assert(vertex_size > 0 && vertex_size <= 256); + + meshopt_Allocator allocator; + + // support in-place remap + if (destination == vertices) + { + unsigned char* vertices_copy = allocator.allocate<unsigned char>(vertex_count * vertex_size); + memcpy(vertices_copy, vertices, vertex_count * vertex_size); + vertices = vertices_copy; + } + + for (size_t i = 0; i < vertex_count; ++i) + { + if (remap[i] != ~0u) + { + assert(remap[i] < vertex_count); + + memcpy(static_cast<unsigned char*>(destination) + remap[i] * vertex_size, static_cast<const unsigned char*>(vertices) + i * vertex_size, vertex_size); + } + } +} + +void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap) +{ + assert(index_count % 3 == 0); + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices ? indices[i] : unsigned(i); + assert(remap[index] != ~0u); + + destination[i] = remap[index]; + } +} + +void meshopt_generateShadowIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride) +{ + using namespace meshopt; + + assert(indices); + assert(index_count % 3 == 0); + assert(vertex_size > 0 && vertex_size <= 256); + assert(vertex_size <= vertex_stride); + + meshopt_Allocator allocator; + + unsigned int* remap = allocator.allocate<unsigned int>(vertex_count); + memset(remap, -1, vertex_count * sizeof(unsigned int)); + + VertexHasher hasher = {static_cast<const unsigned char*>(vertices), vertex_size, vertex_stride}; + + size_t table_size = hashBuckets(vertex_count); + unsigned int* table = allocator.allocate<unsigned int>(table_size); + memset(table, -1, table_size * sizeof(unsigned int)); + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices[i]; + assert(index < vertex_count); + + if (remap[index] == ~0u) + { + unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u); + + if (*entry == ~0u) + *entry = index; + + remap[index] = *entry; + } + + destination[i] = remap[index]; + } +} + +void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count) +{ + using namespace meshopt; + + assert(indices); + assert(index_count % 3 == 0); + assert(stream_count > 0 && stream_count <= 16); + + for (size_t i = 0; i < stream_count; ++i) + { + assert(streams[i].size > 0 && streams[i].size <= 256); + assert(streams[i].size <= streams[i].stride); + } + + meshopt_Allocator allocator; + + unsigned int* remap = allocator.allocate<unsigned int>(vertex_count); + memset(remap, -1, vertex_count * sizeof(unsigned int)); + + VertexStreamHasher hasher = {streams, stream_count}; + + size_t table_size = hashBuckets(vertex_count); + unsigned int* table = allocator.allocate<unsigned int>(table_size); + memset(table, -1, table_size * sizeof(unsigned int)); + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices[i]; + assert(index < vertex_count); + + if (remap[index] == ~0u) + { + unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u); + + if (*entry == ~0u) + *entry = index; + + remap[index] = *entry; + } + + destination[i] = remap[index]; + } +} diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h new file mode 100644 index 0000000000..a442d103c8 --- /dev/null +++ b/thirdparty/meshoptimizer/meshoptimizer.h @@ -0,0 +1,948 @@ +/** + * meshoptimizer - version 0.15 + * + * Copyright (C) 2016-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at https://github.com/zeux/meshoptimizer + * + * This library is distributed under the MIT License. See notice at the end of this file. + */ +#pragma once + +#include <assert.h> +#include <stddef.h> + +/* Version macro; major * 1000 + minor * 10 + patch */ +#define MESHOPTIMIZER_VERSION 150 /* 0.15 */ + +/* If no API is defined, assume default */ +#ifndef MESHOPTIMIZER_API +#define MESHOPTIMIZER_API +#endif + +/* Experimental APIs have unstable interface and might have implementation that's not fully tested or optimized */ +#define MESHOPTIMIZER_EXPERIMENTAL MESHOPTIMIZER_API + +/* C interface */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Vertex attribute stream, similar to glVertexPointer + * Each element takes size bytes, with stride controlling the spacing between successive elements. + */ +struct meshopt_Stream +{ + const void* data; + size_t size; + size_t stride; +}; + +/** + * Generates a vertex remap table from the vertex buffer and an optional index buffer and returns number of unique vertices + * As a result, all vertices that are binary equivalent map to the same (new) location, with no gaps in the resulting sequence. + * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer/meshopt_remapIndexBuffer. + * Note that binary equivalence considers all vertex_size bytes, including padding which should be zero-initialized. + * + * destination must contain enough space for the resulting remap table (vertex_count elements) + * indices can be NULL if the input is unindexed + */ +MESHOPTIMIZER_API size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); + +/** + * Generates a vertex remap table from multiple vertex streams and an optional index buffer and returns number of unique vertices + * As a result, all vertices that are binary equivalent map to the same (new) location, with no gaps in the resulting sequence. + * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer/meshopt_remapIndexBuffer. + * To remap vertex buffers, you will need to call meshopt_remapVertexBuffer for each vertex stream. + * Note that binary equivalence considers all size bytes in each stream, including padding which should be zero-initialized. + * + * destination must contain enough space for the resulting remap table (vertex_count elements) + * indices can be NULL if the input is unindexed + */ +MESHOPTIMIZER_API size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count); + +/** + * Generates vertex buffer from the source vertex buffer and remap table generated by meshopt_generateVertexRemap + * + * destination must contain enough space for the resulting vertex buffer (unique_vertex_count elements, returned by meshopt_generateVertexRemap) + * vertex_count should be the initial vertex count and not the value returned by meshopt_generateVertexRemap + */ +MESHOPTIMIZER_API void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap); + +/** + * Generate index buffer from the source index buffer and remap table generated by meshopt_generateVertexRemap + * + * destination must contain enough space for the resulting index buffer (index_count elements) + * indices can be NULL if the input is unindexed + */ +MESHOPTIMIZER_API void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap); + +/** + * Generate index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary + * All vertices that are binary equivalent (wrt first vertex_size bytes) map to the first vertex in the original vertex buffer. + * This makes it possible to use the index buffer for Z pre-pass or shadowmap rendering, while using the original index buffer for regular rendering. + * Note that binary equivalence considers all vertex_size bytes, including padding which should be zero-initialized. + * + * destination must contain enough space for the resulting index buffer (index_count elements) + */ +MESHOPTIMIZER_API void meshopt_generateShadowIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride); + +/** + * Generate index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary + * All vertices that are binary equivalent (wrt specified streams) map to the first vertex in the original vertex buffer. + * This makes it possible to use the index buffer for Z pre-pass or shadowmap rendering, while using the original index buffer for regular rendering. + * Note that binary equivalence considers all size bytes in each stream, including padding which should be zero-initialized. + * + * destination must contain enough space for the resulting index buffer (index_count elements) + */ +MESHOPTIMIZER_API void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count); + +/** + * Vertex transform cache optimizer + * Reorders indices to reduce the number of GPU vertex shader invocations + * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually. + * + * destination must contain enough space for the resulting index buffer (index_count elements) + */ +MESHOPTIMIZER_API void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count); + +/** + * Vertex transform cache optimizer for strip-like caches + * Produces inferior results to meshopt_optimizeVertexCache from the GPU vertex cache perspective + * However, the resulting index order is more optimal if the goal is to reduce the triangle strip length or improve compression efficiency + * + * destination must contain enough space for the resulting index buffer (index_count elements) + */ +MESHOPTIMIZER_API void meshopt_optimizeVertexCacheStrip(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count); + +/** + * Vertex transform cache optimizer for FIFO caches + * Reorders indices to reduce the number of GPU vertex shader invocations + * Generally takes ~3x less time to optimize meshes but produces inferior results compared to meshopt_optimizeVertexCache + * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually. + * + * destination must contain enough space for the resulting index buffer (index_count elements) + * cache_size should be less than the actual GPU cache size to avoid cache thrashing + */ +MESHOPTIMIZER_API void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size); + +/** + * Overdraw optimizer + * Reorders indices to reduce the number of GPU vertex shader invocations and the pixel overdraw + * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually. + * + * destination must contain enough space for the resulting index buffer (index_count elements) + * indices must contain index data that is the result of meshopt_optimizeVertexCache (*not* the original mesh indices!) + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + * threshold indicates how much the overdraw optimizer can degrade vertex cache efficiency (1.05 = up to 5%) to reduce overdraw more efficiently + */ +MESHOPTIMIZER_API void meshopt_optimizeOverdraw(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold); + +/** + * Vertex fetch cache optimizer + * Reorders vertices and changes indices to reduce the amount of GPU memory fetches during vertex processing + * Returns the number of unique vertices, which is the same as input vertex count unless some vertices are unused + * This functions works for a single vertex stream; for multiple vertex streams, use meshopt_optimizeVertexFetchRemap + meshopt_remapVertexBuffer for each stream. + * + * destination must contain enough space for the resulting vertex buffer (vertex_count elements) + * indices is used both as an input and as an output index buffer + */ +MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetch(void* destination, unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); + +/** + * Vertex fetch cache optimizer + * Generates vertex remap to reduce the amount of GPU memory fetches during vertex processing + * Returns the number of unique vertices, which is the same as input vertex count unless some vertices are unused + * The resulting remap table should be used to reorder vertex/index buffers using meshopt_remapVertexBuffer/meshopt_remapIndexBuffer + * + * destination must contain enough space for the resulting remap table (vertex_count elements) + */ +MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count); + +/** + * Index buffer encoder + * Encodes index data into an array of bytes that is generally much smaller (<1.5 bytes/triangle) and compresses better (<1 bytes/triangle) compared to original. + * Input index buffer must represent a triangle list. + * Returns encoded data size on success, 0 on error; the only error condition is if buffer doesn't have enough space + * For maximum efficiency the index buffer being encoded has to be optimized for vertex cache and vertex fetch first. + * + * buffer must contain enough space for the encoded index buffer (use meshopt_encodeIndexBufferBound to compute worst case size) + */ +MESHOPTIMIZER_API size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count); +MESHOPTIMIZER_API size_t meshopt_encodeIndexBufferBound(size_t index_count, size_t vertex_count); + +/** + * Experimental: Set index encoder format version + * version must specify the data format version to encode; valid values are 0 (decodable by all library versions) and 1 (decodable by 0.14+) + */ +MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeIndexVersion(int version); + +/** + * Index buffer decoder + * Decodes index data from an array of bytes generated by meshopt_encodeIndexBuffer + * Returns 0 if decoding was successful, and an error code otherwise + * The decoder is safe to use for untrusted input, but it may produce garbage data (e.g. out of range indices). + * + * destination must contain enough space for the resulting index buffer (index_count elements) + */ +MESHOPTIMIZER_API int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size); + +/** + * Experimental: Index sequence encoder + * Encodes index sequence into an array of bytes that is generally smaller and compresses better compared to original. + * Input index sequence can represent arbitrary topology; for triangle lists meshopt_encodeIndexBuffer is likely to be better. + * Returns encoded data size on success, 0 on error; the only error condition is if buffer doesn't have enough space + * + * buffer must contain enough space for the encoded index sequence (use meshopt_encodeIndexSequenceBound to compute worst case size) + */ +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count); +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_encodeIndexSequenceBound(size_t index_count, size_t vertex_count); + +/** + * Index sequence decoder + * Decodes index data from an array of bytes generated by meshopt_encodeIndexSequence + * Returns 0 if decoding was successful, and an error code otherwise + * The decoder is safe to use for untrusted input, but it may produce garbage data (e.g. out of range indices). + * + * destination must contain enough space for the resulting index sequence (index_count elements) + */ +MESHOPTIMIZER_EXPERIMENTAL int meshopt_decodeIndexSequence(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size); + +/** + * Vertex buffer encoder + * Encodes vertex data into an array of bytes that is generally smaller and compresses better compared to original. + * Returns encoded data size on success, 0 on error; the only error condition is if buffer doesn't have enough space + * This function works for a single vertex stream; for multiple vertex streams, call meshopt_encodeVertexBuffer for each stream. + * Note that all vertex_size bytes of each vertex are encoded verbatim, including padding which should be zero-initialized. + * + * buffer must contain enough space for the encoded vertex buffer (use meshopt_encodeVertexBufferBound to compute worst case size) + */ +MESHOPTIMIZER_API size_t meshopt_encodeVertexBuffer(unsigned char* buffer, size_t buffer_size, const void* vertices, size_t vertex_count, size_t vertex_size); +MESHOPTIMIZER_API size_t meshopt_encodeVertexBufferBound(size_t vertex_count, size_t vertex_size); + +/** + * Experimental: Set vertex encoder format version + * version must specify the data format version to encode; valid values are 0 (decodable by all library versions) + */ +MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeVertexVersion(int version); + +/** + * Vertex buffer decoder + * Decodes vertex data from an array of bytes generated by meshopt_encodeVertexBuffer + * Returns 0 if decoding was successful, and an error code otherwise + * The decoder is safe to use for untrusted input, but it may produce garbage data. + * + * destination must contain enough space for the resulting vertex buffer (vertex_count * vertex_size bytes) + */ +MESHOPTIMIZER_API int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t vertex_size, const unsigned char* buffer, size_t buffer_size); + +/** + * Vertex buffer filters + * These functions can be used to filter output of meshopt_decodeVertexBuffer in-place. + * count must be aligned by 4 and stride is fixed for each function to facilitate SIMD implementation. + * + * meshopt_decodeFilterOct decodes octahedral encoding of a unit vector with K-bit (K <= 16) signed X/Y as an input; Z must store 1.0f. + * Each component is stored as an 8-bit or 16-bit normalized integer; stride must be equal to 4 or 8. W is preserved as is. + * + * meshopt_decodeFilterQuat decodes 3-component quaternion encoding with K-bit (4 <= K <= 16) component encoding and a 2-bit component index indicating which component to reconstruct. + * Each component is stored as an 16-bit integer; stride must be equal to 8. + * + * meshopt_decodeFilterExp decodes exponential encoding of floating-point data with 8-bit exponent and 24-bit integer mantissa as 2^E*M. + * Each 32-bit component is decoded in isolation; stride must be divisible by 4. + */ +MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterOct(void* buffer, size_t vertex_count, size_t vertex_size); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterQuat(void* buffer, size_t vertex_count, size_t vertex_size); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t vertex_count, size_t vertex_size); + +/** + * Experimental: Mesh simplifier + * Reduces the number of triangles in the mesh, attempting to preserve mesh appearance as much as possible + * The algorithm tries to preserve mesh topology and can stop short of the target goal based on topology constraints or target error. + * If not all attributes from the input mesh are required, it's recommended to reindex the mesh using meshopt_generateShadowIndexBuffer prior to simplification. + * Returns the number of indices after simplification, with destination containing new index data + * The resulting index buffer references vertices from the original vertex buffer. + * If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended. + * + * destination must contain enough space for the *source* index buffer (since optimization is iterative, this means index_count elements - *not* target_index_count!) + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + */ +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error); + +/** + * Experimental: Mesh simplifier (sloppy) + * Reduces the number of triangles in the mesh, sacrificing mesh apperance for simplification performance + * The algorithm doesn't preserve mesh topology but is always able to reach target triangle count. + * Returns the number of indices after simplification, with destination containing new index data + * The resulting index buffer references vertices from the original vertex buffer. + * If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended. + * + * destination must contain enough space for the target index buffer + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + */ +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count); + +/** + * Experimental: Point cloud simplifier + * Reduces the number of points in the cloud to reach the given target + * Returns the number of points after simplification, with destination containing new index data + * The resulting index buffer references vertices from the original vertex buffer. + * If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended. + * + * destination must contain enough space for the target index buffer + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + */ +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_vertex_count); + +/** + * Mesh stripifier + * Converts a previously vertex cache optimized triangle list to triangle strip, stitching strips using restart index or degenerate triangles + * Returns the number of indices in the resulting strip, with destination containing new index data + * For maximum efficiency the index buffer being converted has to be optimized for vertex cache first. + * Using restart indices can result in ~10% smaller index buffers, but on some GPUs restart indices may result in decreased performance. + * + * destination must contain enough space for the target index buffer, worst case can be computed with meshopt_stripifyBound + * restart_index should be 0xffff or 0xffffffff depending on index size, or 0 to use degenerate triangles + */ +MESHOPTIMIZER_API size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int restart_index); +MESHOPTIMIZER_API size_t meshopt_stripifyBound(size_t index_count); + +/** + * Mesh unstripifier + * Converts a triangle strip to a triangle list + * Returns the number of indices in the resulting list, with destination containing new index data + * + * destination must contain enough space for the target index buffer, worst case can be computed with meshopt_unstripifyBound + */ +MESHOPTIMIZER_API size_t meshopt_unstripify(unsigned int* destination, const unsigned int* indices, size_t index_count, unsigned int restart_index); +MESHOPTIMIZER_API size_t meshopt_unstripifyBound(size_t index_count); + +struct meshopt_VertexCacheStatistics +{ + unsigned int vertices_transformed; + unsigned int warps_executed; + float acmr; /* transformed vertices / triangle count; best case 0.5, worst case 3.0, optimum depends on topology */ + float atvr; /* transformed vertices / vertex count; best case 1.0, worst case 6.0, optimum is 1.0 (each vertex is transformed once) */ +}; + +/** + * Vertex transform cache analyzer + * Returns cache hit statistics using a simplified FIFO model + * Results may not match actual GPU performance + */ +MESHOPTIMIZER_API struct meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int primgroup_size); + +struct meshopt_OverdrawStatistics +{ + unsigned int pixels_covered; + unsigned int pixels_shaded; + float overdraw; /* shaded pixels / covered pixels; best case 1.0 */ +}; + +/** + * Overdraw analyzer + * Returns overdraw statistics using a software rasterizer + * Results may not match actual GPU performance + * + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + */ +MESHOPTIMIZER_API struct meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); + +struct meshopt_VertexFetchStatistics +{ + unsigned int bytes_fetched; + float overfetch; /* fetched bytes / vertex buffer size; best case 1.0 (each byte is fetched once) */ +}; + +/** + * Vertex fetch cache analyzer + * Returns cache hit statistics using a simplified direct mapped model + * Results may not match actual GPU performance + */ +MESHOPTIMIZER_API struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* indices, size_t index_count, size_t vertex_count, size_t vertex_size); + +struct meshopt_Meshlet +{ + unsigned int vertices[64]; + unsigned char indices[126][3]; + unsigned char triangle_count; + unsigned char vertex_count; +}; + +/** + * Experimental: Meshlet builder + * Splits the mesh into a set of meshlets where each meshlet has a micro index buffer indexing into meshlet vertices that refer to the original vertex buffer + * The resulting data can be used to render meshes using NVidia programmable mesh shading pipeline, or in other cluster-based renderers. + * For maximum efficiency the index buffer being converted has to be optimized for vertex cache first. + * + * destination must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound + * max_vertices and max_triangles can't exceed limits statically declared in meshopt_Meshlet (max_vertices <= 64, max_triangles <= 126) + */ +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles); +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles); + +struct meshopt_Bounds +{ + /* bounding sphere, useful for frustum and occlusion culling */ + float center[3]; + float radius; + + /* normal cone, useful for backface culling */ + float cone_apex[3]; + float cone_axis[3]; + float cone_cutoff; /* = cos(angle/2) */ + + /* normal cone axis and cutoff, stored in 8-bit SNORM format; decode using x/127.0 */ + signed char cone_axis_s8[3]; + signed char cone_cutoff_s8; +}; + +/** + * Experimental: Cluster bounds generator + * Creates bounding volumes that can be used for frustum, backface and occlusion culling. + * + * For backface culling with orthographic projection, use the following formula to reject backfacing clusters: + * dot(view, cone_axis) >= cone_cutoff + * + * For perspective projection, you can the formula that needs cone apex in addition to axis & cutoff: + * dot(normalize(cone_apex - camera_position), cone_axis) >= cone_cutoff + * + * Alternatively, you can use the formula that doesn't need cone apex and uses bounding sphere instead: + * dot(normalize(center - camera_position), cone_axis) >= cone_cutoff + radius / length(center - camera_position) + * or an equivalent formula that doesn't have a singularity at center = camera_position: + * dot(center - camera_position, cone_axis) >= cone_cutoff * length(center - camera_position) + radius + * + * The formula that uses the apex is slightly more accurate but needs the apex; if you are already using bounding sphere + * to do frustum/occlusion culling, the formula that doesn't use the apex may be preferable. + * + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + * index_count should be less than or equal to 256*3 (the function assumes clusters of limited size) + */ +MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const struct meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); + +/** + * Experimental: Spatial sorter + * Generates a remap table that can be used to reorder points for spatial locality. + * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer. + * + * destination must contain enough space for the resulting remap table (vertex_count elements) + */ +MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortRemap(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); + +/** + * Experimental: Spatial sorter + * Reorders triangles for spatial locality, and generates a new index buffer. The resulting index buffer can be used with other functions like optimizeVertexCache. + * + * destination must contain enough space for the resulting index buffer (index_count elements) + * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer + */ +MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortTriangles(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); + +/** + * Set allocation callbacks + * These callbacks will be used instead of the default operator new/operator delete for all temporary allocations in the library. + * Note that all algorithms only allocate memory for temporary use. + * allocate/deallocate are always called in a stack-like order - last pointer to be allocated is deallocated first. + */ +MESHOPTIMIZER_API void meshopt_setAllocator(void* (*allocate)(size_t), void (*deallocate)(void*)); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* Quantization into commonly supported data formats */ +#ifdef __cplusplus +/** + * Quantize a float in [0..1] range into an N-bit fixed point unorm value + * Assumes reconstruction function (q / (2^N-1)), which is the case for fixed-function normalized fixed point conversion + * Maximum reconstruction error: 1/2^(N+1) + */ +inline int meshopt_quantizeUnorm(float v, int N); + +/** + * Quantize a float in [-1..1] range into an N-bit fixed point snorm value + * Assumes reconstruction function (q / (2^(N-1)-1)), which is the case for fixed-function normalized fixed point conversion (except early OpenGL versions) + * Maximum reconstruction error: 1/2^N + */ +inline int meshopt_quantizeSnorm(float v, int N); + +/** + * Quantize a float into half-precision floating point value + * Generates +-inf for overflow, preserves NaN, flushes denormals to zero, rounds to nearest + * Representable magnitude range: [6e-5; 65504] + * Maximum relative reconstruction error: 5e-4 + */ +inline unsigned short meshopt_quantizeHalf(float v); + +/** + * Quantize a float into a floating point value with a limited number of significant mantissa bits + * Generates +-inf for overflow, preserves NaN, flushes denormals to zero, rounds to nearest + * Assumes N is in a valid mantissa precision range, which is 1..23 + */ +inline float meshopt_quantizeFloat(float v, int N); +#endif + +/** + * C++ template interface + * + * These functions mirror the C interface the library provides, providing template-based overloads so that + * the caller can use an arbitrary type for the index data, both for input and output. + * When the supplied type is the same size as that of unsigned int, the wrappers are zero-cost; when it's not, + * the wrappers end up allocating memory and copying index data to convert from one type to another. + */ +#if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS) +template <typename T> +inline size_t meshopt_generateVertexRemap(unsigned int* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); +template <typename T> +inline size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count); +template <typename T> +inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap); +template <typename T> +inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride); +template <typename T> +inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count); +template <typename T> +inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count); +template <typename T> +inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count); +template <typename T> +inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size); +template <typename T> +inline void meshopt_optimizeOverdraw(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold); +template <typename T> +inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count); +template <typename T> +inline size_t meshopt_optimizeVertexFetch(void* destination, T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); +template <typename T> +inline size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count); +template <typename T> +inline int meshopt_decodeIndexBuffer(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size); +template <typename T> +inline size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count); +template <typename T> +inline int meshopt_decodeIndexSequence(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size); +template <typename T> +inline size_t meshopt_simplify(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error); +template <typename T> +inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count); +template <typename T> +inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index); +template <typename T> +inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index); +template <typename T> +inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int buffer_size); +template <typename T> +inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +template <typename T> +inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size); +template <typename T> +inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles); +template <typename T> +inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +template <typename T> +inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +#endif + +/* Inline implementation */ +#ifdef __cplusplus +inline int meshopt_quantizeUnorm(float v, int N) +{ + const float scale = float((1 << N) - 1); + + v = (v >= 0) ? v : 0; + v = (v <= 1) ? v : 1; + + return int(v * scale + 0.5f); +} + +inline int meshopt_quantizeSnorm(float v, int N) +{ + const float scale = float((1 << (N - 1)) - 1); + + float round = (v >= 0 ? 0.5f : -0.5f); + + v = (v >= -1) ? v : -1; + v = (v <= +1) ? v : +1; + + return int(v * scale + round); +} + +inline unsigned short meshopt_quantizeHalf(float v) +{ + union { float f; unsigned int ui; } u = {v}; + unsigned int ui = u.ui; + + int s = (ui >> 16) & 0x8000; + int em = ui & 0x7fffffff; + + /* bias exponent and round to nearest; 112 is relative exponent bias (127-15) */ + int h = (em - (112 << 23) + (1 << 12)) >> 13; + + /* underflow: flush to zero; 113 encodes exponent -14 */ + h = (em < (113 << 23)) ? 0 : h; + + /* overflow: infinity; 143 encodes exponent 16 */ + h = (em >= (143 << 23)) ? 0x7c00 : h; + + /* NaN; note that we convert all types of NaN to qNaN */ + h = (em > (255 << 23)) ? 0x7e00 : h; + + return (unsigned short)(s | h); +} + +inline float meshopt_quantizeFloat(float v, int N) +{ + union { float f; unsigned int ui; } u = {v}; + unsigned int ui = u.ui; + + const int mask = (1 << (23 - N)) - 1; + const int round = (1 << (23 - N)) >> 1; + + int e = ui & 0x7f800000; + unsigned int rui = (ui + round) & ~mask; + + /* round all numbers except inf/nan; this is important to make sure nan doesn't overflow into -0 */ + ui = e == 0x7f800000 ? ui : rui; + + /* flush denormals to zero */ + ui = e == 0 ? 0 : ui; + + u.ui = ui; + return u.f; +} +#endif + +/* Internal implementation helpers */ +#ifdef __cplusplus +class meshopt_Allocator +{ +public: + template <typename T> + struct StorageT + { + static void* (*allocate)(size_t); + static void (*deallocate)(void*); + }; + + typedef StorageT<void> Storage; + + meshopt_Allocator() + : blocks() + , count(0) + { + } + + ~meshopt_Allocator() + { + for (size_t i = count; i > 0; --i) + Storage::deallocate(blocks[i - 1]); + } + + template <typename T> T* allocate(size_t size) + { + assert(count < sizeof(blocks) / sizeof(blocks[0])); + T* result = static_cast<T*>(Storage::allocate(size > size_t(-1) / sizeof(T) ? size_t(-1) : size * sizeof(T))); + blocks[count++] = result; + return result; + } + +private: + void* blocks[24]; + size_t count; +}; + +// This makes sure that allocate/deallocate are lazily generated in translation units that need them and are deduplicated by the linker +template <typename T> void* (*meshopt_Allocator::StorageT<T>::allocate)(size_t) = operator new; +template <typename T> void (*meshopt_Allocator::StorageT<T>::deallocate)(void*) = operator delete; +#endif + +/* Inline implementation for C++ templated wrappers */ +#if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS) +template <typename T, bool ZeroCopy = sizeof(T) == sizeof(unsigned int)> +struct meshopt_IndexAdapter; + +template <typename T> +struct meshopt_IndexAdapter<T, false> +{ + T* result; + unsigned int* data; + size_t count; + + meshopt_IndexAdapter(T* result_, const T* input, size_t count_) + : result(result_) + , data(0) + , count(count_) + { + size_t size = count > size_t(-1) / sizeof(unsigned int) ? size_t(-1) : count * sizeof(unsigned int); + + data = static_cast<unsigned int*>(meshopt_Allocator::Storage::allocate(size)); + + if (input) + { + for (size_t i = 0; i < count; ++i) + data[i] = input[i]; + } + } + + ~meshopt_IndexAdapter() + { + if (result) + { + for (size_t i = 0; i < count; ++i) + result[i] = T(data[i]); + } + + meshopt_Allocator::Storage::deallocate(data); + } +}; + +template <typename T> +struct meshopt_IndexAdapter<T, true> +{ + unsigned int* data; + + meshopt_IndexAdapter(T* result, const T* input, size_t) + : data(reinterpret_cast<unsigned int*>(result ? result : const_cast<T*>(input))) + { + } +}; + +template <typename T> +inline size_t meshopt_generateVertexRemap(unsigned int* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size) +{ + meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0); + + return meshopt_generateVertexRemap(destination, indices ? in.data : 0, index_count, vertices, vertex_count, vertex_size); +} + +template <typename T> +inline size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count) +{ + meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0); + + return meshopt_generateVertexRemapMulti(destination, indices ? in.data : 0, index_count, vertex_count, streams, stream_count); +} + +template <typename T> +inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap) +{ + meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0); + meshopt_IndexAdapter<T> out(destination, 0, index_count); + + meshopt_remapIndexBuffer(out.data, indices ? in.data : 0, index_count, remap); +} + +template <typename T> +inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count); + + meshopt_generateShadowIndexBuffer(out.data, in.data, index_count, vertices, vertex_count, vertex_size, vertex_stride); +} + +template <typename T> +inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count); + + meshopt_generateShadowIndexBufferMulti(out.data, in.data, index_count, vertex_count, streams, stream_count); +} + +template <typename T> +inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count); + + meshopt_optimizeVertexCache(out.data, in.data, index_count, vertex_count); +} + +template <typename T> +inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count); + + meshopt_optimizeVertexCacheStrip(out.data, in.data, index_count, vertex_count); +} + +template <typename T> +inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count); + + meshopt_optimizeVertexCacheFifo(out.data, in.data, index_count, vertex_count, cache_size); +} + +template <typename T> +inline void meshopt_optimizeOverdraw(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count); + + meshopt_optimizeOverdraw(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, threshold); +} + +template <typename T> +inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + + return meshopt_optimizeVertexFetchRemap(destination, in.data, index_count, vertex_count); +} + +template <typename T> +inline size_t meshopt_optimizeVertexFetch(void* destination, T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size) +{ + meshopt_IndexAdapter<T> inout(indices, indices, index_count); + + return meshopt_optimizeVertexFetch(destination, inout.data, index_count, vertices, vertex_count, vertex_size); +} + +template <typename T> +inline size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + + return meshopt_encodeIndexBuffer(buffer, buffer_size, in.data, index_count); +} + +template <typename T> +inline int meshopt_decodeIndexBuffer(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size) +{ + char index_size_valid[sizeof(T) == 2 || sizeof(T) == 4 ? 1 : -1]; + (void)index_size_valid; + + return meshopt_decodeIndexBuffer(destination, index_count, sizeof(T), buffer, buffer_size); +} + +template <typename T> +inline size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + + return meshopt_encodeIndexSequence(buffer, buffer_size, in.data, index_count); +} + +template <typename T> +inline int meshopt_decodeIndexSequence(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size) +{ + char index_size_valid[sizeof(T) == 2 || sizeof(T) == 4 ? 1 : -1]; + (void)index_size_valid; + + return meshopt_decodeIndexSequence(destination, index_count, sizeof(T), buffer, buffer_size); +} + +template <typename T> +inline size_t meshopt_simplify(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count); + + return meshopt_simplify(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error); +} + +template <typename T> +inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, target_index_count); + + return meshopt_simplifySloppy(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count); +} + +template <typename T> +inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, (index_count / 3) * 5); + + return meshopt_stripify(out.data, in.data, index_count, vertex_count, unsigned(restart_index)); +} + +template <typename T> +inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, (index_count - 2) * 3); + + return meshopt_unstripify(out.data, in.data, index_count, unsigned(restart_index)); +} + +template <typename T> +inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int buffer_size) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + + return meshopt_analyzeVertexCache(in.data, index_count, vertex_count, cache_size, warp_size, buffer_size); +} + +template <typename T> +inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + + return meshopt_analyzeOverdraw(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); +} + +template <typename T> +inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + + return meshopt_analyzeVertexFetch(in.data, index_count, vertex_count, vertex_size); +} + +template <typename T> +inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + + return meshopt_buildMeshlets(destination, in.data, index_count, vertex_count, max_vertices, max_triangles); +} + +template <typename T> +inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + + return meshopt_computeClusterBounds(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); +} + +template <typename T> +inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + meshopt_IndexAdapter<T> in(0, indices, index_count); + meshopt_IndexAdapter<T> out(destination, 0, index_count); + + meshopt_spatialSortTriangles(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); +} +#endif + +/** + * Copyright (c) 2016-2020 Arseny Kapoulkine + * + * 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. + */ diff --git a/thirdparty/meshoptimizer/overdrawanalyzer.cpp b/thirdparty/meshoptimizer/overdrawanalyzer.cpp new file mode 100644 index 0000000000..8d5859ba39 --- /dev/null +++ b/thirdparty/meshoptimizer/overdrawanalyzer.cpp @@ -0,0 +1,230 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <float.h> +#include <string.h> + +// This work is based on: +// Nicolas Capens. Advanced Rasterization. 2004 +namespace meshopt +{ + +const int kViewport = 256; + +struct OverdrawBuffer +{ + float z[kViewport][kViewport][2]; + unsigned int overdraw[kViewport][kViewport][2]; +}; + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +static float computeDepthGradients(float& dzdx, float& dzdy, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) +{ + // z2 = z1 + dzdx * (x2 - x1) + dzdy * (y2 - y1) + // z3 = z1 + dzdx * (x3 - x1) + dzdy * (y3 - y1) + // (x2-x1 y2-y1)(dzdx) = (z2-z1) + // (x3-x1 y3-y1)(dzdy) (z3-z1) + // we'll solve it with Cramer's rule + float det = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1); + float invdet = (det == 0) ? 0 : 1 / det; + + dzdx = (z2 - z1) * (y3 - y1) - (y2 - y1) * (z3 - z1) * invdet; + dzdy = (x2 - x1) * (z3 - z1) - (z2 - z1) * (x3 - x1) * invdet; + + return det; +} + +// half-space fixed point triangle rasterizer +static void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, float v2x, float v2y, float v2z, float v3x, float v3y, float v3z) +{ + // compute depth gradients + float DZx, DZy; + float det = computeDepthGradients(DZx, DZy, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z); + int sign = det > 0; + + // flip backfacing triangles to simplify rasterization logic + if (sign) + { + // flipping v2 & v3 preserves depth gradients since they're based on v1 + float t; + t = v2x, v2x = v3x, v3x = t; + t = v2y, v2y = v3y, v3y = t; + t = v2z, v2z = v3z, v3z = t; + + // flip depth since we rasterize backfacing triangles to second buffer with reverse Z; only v1z is used below + v1z = kViewport - v1z; + DZx = -DZx; + DZy = -DZy; + } + + // coordinates, 28.4 fixed point + int X1 = int(16.0f * v1x + 0.5f); + int X2 = int(16.0f * v2x + 0.5f); + int X3 = int(16.0f * v3x + 0.5f); + + int Y1 = int(16.0f * v1y + 0.5f); + int Y2 = int(16.0f * v2y + 0.5f); + int Y3 = int(16.0f * v3y + 0.5f); + + // bounding rectangle, clipped against viewport + // since we rasterize pixels with covered centers, min >0.5 should round up + // as for max, due to top-left filling convention we will never rasterize right/bottom edges + // so max >= 0.5 should round down + int minx = max((min(X1, min(X2, X3)) + 7) >> 4, 0); + int maxx = min((max(X1, max(X2, X3)) + 7) >> 4, kViewport); + int miny = max((min(Y1, min(Y2, Y3)) + 7) >> 4, 0); + int maxy = min((max(Y1, max(Y2, Y3)) + 7) >> 4, kViewport); + + // deltas, 28.4 fixed point + int DX12 = X1 - X2; + int DX23 = X2 - X3; + int DX31 = X3 - X1; + + int DY12 = Y1 - Y2; + int DY23 = Y2 - Y3; + int DY31 = Y3 - Y1; + + // fill convention correction + int TL1 = DY12 < 0 || (DY12 == 0 && DX12 > 0); + int TL2 = DY23 < 0 || (DY23 == 0 && DX23 > 0); + int TL3 = DY31 < 0 || (DY31 == 0 && DX31 > 0); + + // half edge equations, 24.8 fixed point + // note that we offset minx/miny by half pixel since we want to rasterize pixels with covered centers + int FX = (minx << 4) + 8; + int FY = (miny << 4) + 8; + int CY1 = DX12 * (FY - Y1) - DY12 * (FX - X1) + TL1 - 1; + int CY2 = DX23 * (FY - Y2) - DY23 * (FX - X2) + TL2 - 1; + int CY3 = DX31 * (FY - Y3) - DY31 * (FX - X3) + TL3 - 1; + float ZY = v1z + (DZx * float(FX - X1) + DZy * float(FY - Y1)) * (1 / 16.f); + + for (int y = miny; y < maxy; y++) + { + int CX1 = CY1; + int CX2 = CY2; + int CX3 = CY3; + float ZX = ZY; + + for (int x = minx; x < maxx; x++) + { + // check if all CXn are non-negative + if ((CX1 | CX2 | CX3) >= 0) + { + if (ZX >= buffer->z[y][x][sign]) + { + buffer->z[y][x][sign] = ZX; + buffer->overdraw[y][x][sign]++; + } + } + + // signed left shift is UB for negative numbers so use unsigned-signed casts + CX1 -= int(unsigned(DY12) << 4); + CX2 -= int(unsigned(DY23) << 4); + CX3 -= int(unsigned(DY31) << 4); + ZX += DZx; + } + + // signed left shift is UB for negative numbers so use unsigned-signed casts + CY1 += int(unsigned(DX12) << 4); + CY2 += int(unsigned(DX23) << 4); + CY3 += int(unsigned(DX31) << 4); + ZY += DZy; + } +} + +} // namespace meshopt + +meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + + meshopt_Allocator allocator; + + size_t vertex_stride_float = vertex_positions_stride / sizeof(float); + + meshopt_OverdrawStatistics result = {}; + + float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX}; + float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + + for (size_t i = 0; i < vertex_count; ++i) + { + const float* v = vertex_positions + i * vertex_stride_float; + + for (int j = 0; j < 3; ++j) + { + minv[j] = min(minv[j], v[j]); + maxv[j] = max(maxv[j], v[j]); + } + } + + float extent = max(maxv[0] - minv[0], max(maxv[1] - minv[1], maxv[2] - minv[2])); + float scale = kViewport / extent; + + float* triangles = allocator.allocate<float>(index_count * 3); + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices[i]; + assert(index < vertex_count); + + const float* v = vertex_positions + index * vertex_stride_float; + + triangles[i * 3 + 0] = (v[0] - minv[0]) * scale; + triangles[i * 3 + 1] = (v[1] - minv[1]) * scale; + triangles[i * 3 + 2] = (v[2] - minv[2]) * scale; + } + + OverdrawBuffer* buffer = allocator.allocate<OverdrawBuffer>(1); + + for (int axis = 0; axis < 3; ++axis) + { + memset(buffer, 0, sizeof(OverdrawBuffer)); + + for (size_t i = 0; i < index_count; i += 3) + { + const float* vn0 = &triangles[3 * (i + 0)]; + const float* vn1 = &triangles[3 * (i + 1)]; + const float* vn2 = &triangles[3 * (i + 2)]; + + switch (axis) + { + case 0: + rasterize(buffer, vn0[2], vn0[1], vn0[0], vn1[2], vn1[1], vn1[0], vn2[2], vn2[1], vn2[0]); + break; + case 1: + rasterize(buffer, vn0[0], vn0[2], vn0[1], vn1[0], vn1[2], vn1[1], vn2[0], vn2[2], vn2[1]); + break; + case 2: + rasterize(buffer, vn0[1], vn0[0], vn0[2], vn1[1], vn1[0], vn1[2], vn2[1], vn2[0], vn2[2]); + break; + } + } + + for (int y = 0; y < kViewport; ++y) + for (int x = 0; x < kViewport; ++x) + for (int s = 0; s < 2; ++s) + { + unsigned int overdraw = buffer->overdraw[y][x][s]; + + result.pixels_covered += overdraw > 0; + result.pixels_shaded += overdraw; + } + } + + result.overdraw = result.pixels_covered ? float(result.pixels_shaded) / float(result.pixels_covered) : 0.f; + + return result; +} diff --git a/thirdparty/meshoptimizer/overdrawoptimizer.cpp b/thirdparty/meshoptimizer/overdrawoptimizer.cpp new file mode 100644 index 0000000000..143656ed76 --- /dev/null +++ b/thirdparty/meshoptimizer/overdrawoptimizer.cpp @@ -0,0 +1,333 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <math.h> +#include <string.h> + +// This work is based on: +// Pedro Sander, Diego Nehab and Joshua Barczak. Fast Triangle Reordering for Vertex Locality and Reduced Overdraw. 2007 +namespace meshopt +{ + +static void calculateSortData(float* sort_data, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_positions_stride, const unsigned int* clusters, size_t cluster_count) +{ + size_t vertex_stride_float = vertex_positions_stride / sizeof(float); + + float mesh_centroid[3] = {}; + + for (size_t i = 0; i < index_count; ++i) + { + const float* p = vertex_positions + vertex_stride_float * indices[i]; + + mesh_centroid[0] += p[0]; + mesh_centroid[1] += p[1]; + mesh_centroid[2] += p[2]; + } + + mesh_centroid[0] /= index_count; + mesh_centroid[1] /= index_count; + mesh_centroid[2] /= index_count; + + for (size_t cluster = 0; cluster < cluster_count; ++cluster) + { + size_t cluster_begin = clusters[cluster] * 3; + size_t cluster_end = (cluster + 1 < cluster_count) ? clusters[cluster + 1] * 3 : index_count; + assert(cluster_begin < cluster_end); + + float cluster_area = 0; + float cluster_centroid[3] = {}; + float cluster_normal[3] = {}; + + for (size_t i = cluster_begin; i < cluster_end; i += 3) + { + const float* p0 = vertex_positions + vertex_stride_float * indices[i + 0]; + const float* p1 = vertex_positions + vertex_stride_float * indices[i + 1]; + const float* p2 = vertex_positions + vertex_stride_float * indices[i + 2]; + + float p10[3] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]}; + float p20[3] = {p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]}; + + float normalx = p10[1] * p20[2] - p10[2] * p20[1]; + float normaly = p10[2] * p20[0] - p10[0] * p20[2]; + float normalz = p10[0] * p20[1] - p10[1] * p20[0]; + + float area = sqrtf(normalx * normalx + normaly * normaly + normalz * normalz); + + cluster_centroid[0] += (p0[0] + p1[0] + p2[0]) * (area / 3); + cluster_centroid[1] += (p0[1] + p1[1] + p2[1]) * (area / 3); + cluster_centroid[2] += (p0[2] + p1[2] + p2[2]) * (area / 3); + cluster_normal[0] += normalx; + cluster_normal[1] += normaly; + cluster_normal[2] += normalz; + cluster_area += area; + } + + float inv_cluster_area = cluster_area == 0 ? 0 : 1 / cluster_area; + + cluster_centroid[0] *= inv_cluster_area; + cluster_centroid[1] *= inv_cluster_area; + cluster_centroid[2] *= inv_cluster_area; + + float cluster_normal_length = sqrtf(cluster_normal[0] * cluster_normal[0] + cluster_normal[1] * cluster_normal[1] + cluster_normal[2] * cluster_normal[2]); + float inv_cluster_normal_length = cluster_normal_length == 0 ? 0 : 1 / cluster_normal_length; + + cluster_normal[0] *= inv_cluster_normal_length; + cluster_normal[1] *= inv_cluster_normal_length; + cluster_normal[2] *= inv_cluster_normal_length; + + float centroid_vector[3] = {cluster_centroid[0] - mesh_centroid[0], cluster_centroid[1] - mesh_centroid[1], cluster_centroid[2] - mesh_centroid[2]}; + + sort_data[cluster] = centroid_vector[0] * cluster_normal[0] + centroid_vector[1] * cluster_normal[1] + centroid_vector[2] * cluster_normal[2]; + } +} + +static void calculateSortOrderRadix(unsigned int* sort_order, const float* sort_data, unsigned short* sort_keys, size_t cluster_count) +{ + // compute sort data bounds and renormalize, using fixed point snorm + float sort_data_max = 1e-3f; + + for (size_t i = 0; i < cluster_count; ++i) + { + float dpa = fabsf(sort_data[i]); + + sort_data_max = (sort_data_max < dpa) ? dpa : sort_data_max; + } + + const int sort_bits = 11; + + for (size_t i = 0; i < cluster_count; ++i) + { + // note that we flip distribution since high dot product should come first + float sort_key = 0.5f - 0.5f * (sort_data[i] / sort_data_max); + + sort_keys[i] = meshopt_quantizeUnorm(sort_key, sort_bits) & ((1 << sort_bits) - 1); + } + + // fill histogram for counting sort + unsigned int histogram[1 << sort_bits]; + memset(histogram, 0, sizeof(histogram)); + + for (size_t i = 0; i < cluster_count; ++i) + { + histogram[sort_keys[i]]++; + } + + // compute offsets based on histogram data + size_t histogram_sum = 0; + + for (size_t i = 0; i < 1 << sort_bits; ++i) + { + size_t count = histogram[i]; + histogram[i] = unsigned(histogram_sum); + histogram_sum += count; + } + + assert(histogram_sum == cluster_count); + + // compute sort order based on offsets + for (size_t i = 0; i < cluster_count; ++i) + { + sort_order[histogram[sort_keys[i]]++] = unsigned(i); + } +} + +static unsigned int updateCache(unsigned int a, unsigned int b, unsigned int c, unsigned int cache_size, unsigned int* cache_timestamps, unsigned int& timestamp) +{ + unsigned int cache_misses = 0; + + // if vertex is not in cache, put it in cache + if (timestamp - cache_timestamps[a] > cache_size) + { + cache_timestamps[a] = timestamp++; + cache_misses++; + } + + if (timestamp - cache_timestamps[b] > cache_size) + { + cache_timestamps[b] = timestamp++; + cache_misses++; + } + + if (timestamp - cache_timestamps[c] > cache_size) + { + cache_timestamps[c] = timestamp++; + cache_misses++; + } + + return cache_misses; +} + +static size_t generateHardBoundaries(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int* cache_timestamps) +{ + memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int)); + + unsigned int timestamp = cache_size + 1; + + size_t face_count = index_count / 3; + + size_t result = 0; + + for (size_t i = 0; i < face_count; ++i) + { + unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], timestamp); + + // when all three vertices are not in the cache it's usually relatively safe to assume that this is a new patch in the mesh + // that is disjoint from previous vertices; sometimes it might come back to reference existing vertices but that frequently + // suggests an inefficiency in the vertex cache optimization algorithm + // usually the first triangle has 3 misses unless it's degenerate - thus we make sure the first cluster always starts with 0 + if (i == 0 || m == 3) + { + destination[result++] = unsigned(i); + } + } + + assert(result <= index_count / 3); + + return result; +} + +static size_t generateSoftBoundaries(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const unsigned int* clusters, size_t cluster_count, unsigned int cache_size, float threshold, unsigned int* cache_timestamps) +{ + memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int)); + + unsigned int timestamp = 0; + + size_t result = 0; + + for (size_t it = 0; it < cluster_count; ++it) + { + size_t start = clusters[it]; + size_t end = (it + 1 < cluster_count) ? clusters[it + 1] : index_count / 3; + assert(start < end); + + // reset cache + timestamp += cache_size + 1; + + // measure cluster ACMR + unsigned int cluster_misses = 0; + + for (size_t i = start; i < end; ++i) + { + unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], timestamp); + + cluster_misses += m; + } + + float cluster_threshold = threshold * (float(cluster_misses) / float(end - start)); + + // first cluster always starts from the hard cluster boundary + destination[result++] = unsigned(start); + + // reset cache + timestamp += cache_size + 1; + + unsigned int running_misses = 0; + unsigned int running_faces = 0; + + for (size_t i = start; i < end; ++i) + { + unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], timestamp); + + running_misses += m; + running_faces += 1; + + if (float(running_misses) / float(running_faces) <= cluster_threshold) + { + // we have reached the target ACMR with the current triangle so we need to start a new cluster on the next one + // note that this may mean that we add 'end` to destination for the last triangle, which will imply that the last + // cluster is empty; however, the 'pop_back' after the loop will clean it up + destination[result++] = unsigned(i + 1); + + // reset cache + timestamp += cache_size + 1; + + running_misses = 0; + running_faces = 0; + } + } + + // each time we reach the target ACMR we flush the cluster + // this means that the last cluster is by definition not very good - there are frequent cases where we are left with a few triangles + // in the last cluster, producing a very bad ACMR and significantly penalizing the overall results + // thus we remove the last cluster boundary, merging the last complete cluster with the last incomplete one + // there are sometimes cases when the last cluster is actually good enough - in which case the code above would have added 'end' + // to the cluster boundary array which we need to remove anyway - this code will do that automatically + if (destination[result - 1] != start) + { + result--; + } + } + + assert(result >= cluster_count); + assert(result <= index_count / 3); + + return result; +} + +} // namespace meshopt + +void meshopt_optimizeOverdraw(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + + meshopt_Allocator allocator; + + // guard for empty meshes + if (index_count == 0 || vertex_count == 0) + return; + + // support in-place optimization + if (destination == indices) + { + unsigned int* indices_copy = allocator.allocate<unsigned int>(index_count); + memcpy(indices_copy, indices, index_count * sizeof(unsigned int)); + indices = indices_copy; + } + + unsigned int cache_size = 16; + + unsigned int* cache_timestamps = allocator.allocate<unsigned int>(vertex_count); + + // generate hard boundaries from full-triangle cache misses + unsigned int* hard_clusters = allocator.allocate<unsigned int>(index_count / 3); + size_t hard_cluster_count = generateHardBoundaries(hard_clusters, indices, index_count, vertex_count, cache_size, cache_timestamps); + + // generate soft boundaries + unsigned int* soft_clusters = allocator.allocate<unsigned int>(index_count / 3 + 1); + size_t soft_cluster_count = generateSoftBoundaries(soft_clusters, indices, index_count, vertex_count, hard_clusters, hard_cluster_count, cache_size, threshold, cache_timestamps); + + const unsigned int* clusters = soft_clusters; + size_t cluster_count = soft_cluster_count; + + // fill sort data + float* sort_data = allocator.allocate<float>(cluster_count); + calculateSortData(sort_data, indices, index_count, vertex_positions, vertex_positions_stride, clusters, cluster_count); + + // sort clusters using sort data + unsigned short* sort_keys = allocator.allocate<unsigned short>(cluster_count); + unsigned int* sort_order = allocator.allocate<unsigned int>(cluster_count); + calculateSortOrderRadix(sort_order, sort_data, sort_keys, cluster_count); + + // fill output buffer + size_t offset = 0; + + for (size_t it = 0; it < cluster_count; ++it) + { + unsigned int cluster = sort_order[it]; + assert(cluster < cluster_count); + + size_t cluster_begin = clusters[cluster] * 3; + size_t cluster_end = (cluster + 1 < cluster_count) ? clusters[cluster + 1] * 3 : index_count; + assert(cluster_begin < cluster_end); + + memcpy(destination + offset, indices + cluster_begin, (cluster_end - cluster_begin) * sizeof(unsigned int)); + offset += cluster_end - cluster_begin; + } + + assert(offset == index_count); +} diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp new file mode 100644 index 0000000000..bd523275ce --- /dev/null +++ b/thirdparty/meshoptimizer/simplifier.cpp @@ -0,0 +1,1529 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <float.h> +#include <math.h> +#include <string.h> + +#ifndef TRACE +#define TRACE 0 +#endif + +#if TRACE +#include <stdio.h> +#endif + +// This work is based on: +// Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997 +// Michael Garland. Quadric-based polygonal surface simplification. 1999 +// Peter Lindstrom. Out-of-Core Simplification of Large Polygonal Models. 2000 +// Matthias Teschner, Bruno Heidelberger, Matthias Mueller, Danat Pomeranets, Markus Gross. Optimized Spatial Hashing for Collision Detection of Deformable Objects. 2003 +// Peter Van Sandt, Yannis Chronis, Jignesh M. Patel. Efficiently Searching In-Memory Sorted Arrays: Revenge of the Interpolation Search? 2019 +namespace meshopt +{ + +struct EdgeAdjacency +{ + unsigned int* counts; + unsigned int* offsets; + unsigned int* data; +}; + +static void buildEdgeAdjacency(EdgeAdjacency& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count, meshopt_Allocator& allocator) +{ + size_t face_count = index_count / 3; + + // allocate arrays + adjacency.counts = allocator.allocate<unsigned int>(vertex_count); + adjacency.offsets = allocator.allocate<unsigned int>(vertex_count); + adjacency.data = allocator.allocate<unsigned int>(index_count); + + // fill edge counts + memset(adjacency.counts, 0, vertex_count * sizeof(unsigned int)); + + for (size_t i = 0; i < index_count; ++i) + { + assert(indices[i] < vertex_count); + + adjacency.counts[indices[i]]++; + } + + // fill offset table + unsigned int offset = 0; + + for (size_t i = 0; i < vertex_count; ++i) + { + adjacency.offsets[i] = offset; + offset += adjacency.counts[i]; + } + + assert(offset == index_count); + + // fill edge data + for (size_t i = 0; i < face_count; ++i) + { + unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2]; + + adjacency.data[adjacency.offsets[a]++] = b; + adjacency.data[adjacency.offsets[b]++] = c; + adjacency.data[adjacency.offsets[c]++] = a; + } + + // fix offsets that have been disturbed by the previous pass + for (size_t i = 0; i < vertex_count; ++i) + { + assert(adjacency.offsets[i] >= adjacency.counts[i]); + + adjacency.offsets[i] -= adjacency.counts[i]; + } +} + +struct PositionHasher +{ + const float* vertex_positions; + size_t vertex_stride_float; + + size_t hash(unsigned int index) const + { + const unsigned int* key = reinterpret_cast<const unsigned int*>(vertex_positions + index * vertex_stride_float); + + // Optimized Spatial Hashing for Collision Detection of Deformable Objects + return (key[0] * 73856093) ^ (key[1] * 19349663) ^ (key[2] * 83492791); + } + + bool equal(unsigned int lhs, unsigned int rhs) const + { + return memcmp(vertex_positions + lhs * vertex_stride_float, vertex_positions + rhs * vertex_stride_float, sizeof(float) * 3) == 0; + } +}; + +static size_t hashBuckets2(size_t count) +{ + size_t buckets = 1; + while (buckets < count) + buckets *= 2; + + return buckets; +} + +template <typename T, typename Hash> +static T* hashLookup2(T* table, size_t buckets, const Hash& hash, const T& key, const T& empty) +{ + assert(buckets > 0); + assert((buckets & (buckets - 1)) == 0); + + size_t hashmod = buckets - 1; + size_t bucket = hash.hash(key) & hashmod; + + for (size_t probe = 0; probe <= hashmod; ++probe) + { + T& item = table[bucket]; + + if (item == empty) + return &item; + + if (hash.equal(item, key)) + return &item; + + // hash collision, quadratic probing + bucket = (bucket + probe + 1) & hashmod; + } + + assert(false && "Hash table is full"); // unreachable + return 0; +} + +static void buildPositionRemap(unsigned int* remap, unsigned int* wedge, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator) +{ + PositionHasher hasher = {vertex_positions_data, vertex_positions_stride / sizeof(float)}; + + size_t table_size = hashBuckets2(vertex_count); + unsigned int* table = allocator.allocate<unsigned int>(table_size); + memset(table, -1, table_size * sizeof(unsigned int)); + + // build forward remap: for each vertex, which other (canonical) vertex does it map to? + // we use position equivalence for this, and remap vertices to other existing vertices + for (size_t i = 0; i < vertex_count; ++i) + { + unsigned int index = unsigned(i); + unsigned int* entry = hashLookup2(table, table_size, hasher, index, ~0u); + + if (*entry == ~0u) + *entry = index; + + remap[index] = *entry; + } + + // build wedge table: for each vertex, which other vertex is the next wedge that also maps to the same vertex? + // entries in table form a (cyclic) wedge loop per vertex; for manifold vertices, wedge[i] == remap[i] == i + for (size_t i = 0; i < vertex_count; ++i) + wedge[i] = unsigned(i); + + for (size_t i = 0; i < vertex_count; ++i) + if (remap[i] != i) + { + unsigned int r = remap[i]; + + wedge[i] = wedge[r]; + wedge[r] = unsigned(i); + } +} + +enum VertexKind +{ + Kind_Manifold, // not on an attribute seam, not on any boundary + Kind_Border, // not on an attribute seam, has exactly two open edges + Kind_Seam, // on an attribute seam with exactly two attribute seam edges + Kind_Complex, // none of the above; these vertices can move as long as all wedges move to the target vertex + Kind_Locked, // none of the above; these vertices can't move + + Kind_Count +}; + +// manifold vertices can collapse onto anything +// border/seam vertices can only be collapsed onto border/seam respectively +// complex vertices can collapse onto complex/locked +// a rule of thumb is that collapsing kind A into kind B preserves the kind B in the target vertex +// for example, while we could collapse Complex into Manifold, this would mean the target vertex isn't Manifold anymore +const unsigned char kCanCollapse[Kind_Count][Kind_Count] = { + {1, 1, 1, 1, 1}, + {0, 1, 0, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 0, 1, 1}, + {0, 0, 0, 0, 0}, +}; + +// if a vertex is manifold or seam, adjoining edges are guaranteed to have an opposite edge +// note that for seam edges, the opposite edge isn't present in the attribute-based topology +// but is present if you consider a position-only mesh variant +const unsigned char kHasOpposite[Kind_Count][Kind_Count] = { + {1, 1, 1, 0, 1}, + {1, 0, 1, 0, 0}, + {1, 1, 1, 0, 1}, + {0, 0, 0, 0, 0}, + {1, 0, 1, 0, 0}, +}; + +static bool hasEdge(const EdgeAdjacency& adjacency, unsigned int a, unsigned int b) +{ + unsigned int count = adjacency.counts[a]; + const unsigned int* data = adjacency.data + adjacency.offsets[a]; + + for (size_t i = 0; i < count; ++i) + if (data[i] == b) + return true; + + return false; +} + +static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned int* loopback, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* wedge) +{ + memset(loop, -1, vertex_count * sizeof(unsigned int)); + memset(loopback, -1, vertex_count * sizeof(unsigned int)); + + // incoming & outgoing open edges: ~0u if no open edges, i if there are more than 1 + // note that this is the same data as required in loop[] arrays; loop[] data is only valid for border/seam + // but here it's okay to fill the data out for other types of vertices as well + unsigned int* openinc = loopback; + unsigned int* openout = loop; + + for (size_t i = 0; i < vertex_count; ++i) + { + unsigned int vertex = unsigned(i); + + unsigned int count = adjacency.counts[vertex]; + const unsigned int* data = adjacency.data + adjacency.offsets[vertex]; + + for (size_t j = 0; j < count; ++j) + { + unsigned int target = data[j]; + + if (!hasEdge(adjacency, target, vertex)) + { + openinc[target] = (openinc[target] == ~0u) ? vertex : target; + openout[vertex] = (openout[vertex] == ~0u) ? target : vertex; + } + } + } + +#if TRACE + size_t lockedstats[4] = {}; +#define TRACELOCKED(i) lockedstats[i]++; +#else +#define TRACELOCKED(i) (void)0 +#endif + + for (size_t i = 0; i < vertex_count; ++i) + { + if (remap[i] == i) + { + if (wedge[i] == i) + { + // no attribute seam, need to check if it's manifold + unsigned int openi = openinc[i], openo = openout[i]; + + // note: we classify any vertices with no open edges as manifold + // this is technically incorrect - if 4 triangles share an edge, we'll classify vertices as manifold + // it's unclear if this is a problem in practice + if (openi == ~0u && openo == ~0u) + { + result[i] = Kind_Manifold; + } + else if (openi != i && openo != i) + { + result[i] = Kind_Border; + } + else + { + result[i] = Kind_Locked; + TRACELOCKED(0); + } + } + else if (wedge[wedge[i]] == i) + { + // attribute seam; need to distinguish between Seam and Locked + unsigned int w = wedge[i]; + unsigned int openiv = openinc[i], openov = openout[i]; + unsigned int openiw = openinc[w], openow = openout[w]; + + // seam should have one open half-edge for each vertex, and the edges need to "connect" - point to the same vertex post-remap + if (openiv != ~0u && openiv != i && openov != ~0u && openov != i && + openiw != ~0u && openiw != w && openow != ~0u && openow != w) + { + if (remap[openiv] == remap[openow] && remap[openov] == remap[openiw]) + { + result[i] = Kind_Seam; + } + else + { + result[i] = Kind_Locked; + TRACELOCKED(1); + } + } + else + { + result[i] = Kind_Locked; + TRACELOCKED(2); + } + } + else + { + // more than one vertex maps to this one; we don't have classification available + result[i] = Kind_Locked; + TRACELOCKED(3); + } + } + else + { + assert(remap[i] < i); + + result[i] = result[remap[i]]; + } + } + +#if TRACE + printf("locked: many open edges %d, disconnected seam %d, many seam edges %d, many wedges %d\n", + int(lockedstats[0]), int(lockedstats[1]), int(lockedstats[2]), int(lockedstats[3])); +#endif +} + +struct Vector3 +{ + float x, y, z; +}; + +static void rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride) +{ + size_t vertex_stride_float = vertex_positions_stride / sizeof(float); + + float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX}; + float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + + for (size_t i = 0; i < vertex_count; ++i) + { + const float* v = vertex_positions_data + i * vertex_stride_float; + + result[i].x = v[0]; + result[i].y = v[1]; + result[i].z = v[2]; + + for (int j = 0; j < 3; ++j) + { + float vj = v[j]; + + minv[j] = minv[j] > vj ? vj : minv[j]; + maxv[j] = maxv[j] < vj ? vj : maxv[j]; + } + } + + float extent = 0.f; + + extent = (maxv[0] - minv[0]) < extent ? extent : (maxv[0] - minv[0]); + extent = (maxv[1] - minv[1]) < extent ? extent : (maxv[1] - minv[1]); + extent = (maxv[2] - minv[2]) < extent ? extent : (maxv[2] - minv[2]); + + float scale = extent == 0 ? 0.f : 1.f / extent; + + for (size_t i = 0; i < vertex_count; ++i) + { + result[i].x = (result[i].x - minv[0]) * scale; + result[i].y = (result[i].y - minv[1]) * scale; + result[i].z = (result[i].z - minv[2]) * scale; + } +} + +struct Quadric +{ + float a00, a11, a22; + float a10, a20, a21; + float b0, b1, b2, c; + float w; +}; + +struct Collapse +{ + unsigned int v0; + unsigned int v1; + + union + { + unsigned int bidi; + float error; + unsigned int errorui; + }; +}; + +static float normalize(Vector3& v) +{ + float length = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); + + if (length > 0) + { + v.x /= length; + v.y /= length; + v.z /= length; + } + + return length; +} + +static void quadricAdd(Quadric& Q, const Quadric& R) +{ + Q.a00 += R.a00; + Q.a11 += R.a11; + Q.a22 += R.a22; + Q.a10 += R.a10; + Q.a20 += R.a20; + Q.a21 += R.a21; + Q.b0 += R.b0; + Q.b1 += R.b1; + Q.b2 += R.b2; + Q.c += R.c; + Q.w += R.w; +} + +static float quadricError(const Quadric& Q, const Vector3& v) +{ + float rx = Q.b0; + float ry = Q.b1; + float rz = Q.b2; + + rx += Q.a10 * v.y; + ry += Q.a21 * v.z; + rz += Q.a20 * v.x; + + rx *= 2; + ry *= 2; + rz *= 2; + + rx += Q.a00 * v.x; + ry += Q.a11 * v.y; + rz += Q.a22 * v.z; + + float r = Q.c; + r += rx * v.x; + r += ry * v.y; + r += rz * v.z; + + float s = Q.w == 0.f ? 0.f : 1.f / Q.w; + + return fabsf(r) * s; +} + +static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, float w) +{ + float aw = a * w; + float bw = b * w; + float cw = c * w; + float dw = d * w; + + Q.a00 = a * aw; + Q.a11 = b * bw; + Q.a22 = c * cw; + Q.a10 = a * bw; + Q.a20 = a * cw; + Q.a21 = b * cw; + Q.b0 = a * dw; + Q.b1 = b * dw; + Q.b2 = c * dw; + Q.c = d * dw; + Q.w = w; +} + +static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w) +{ + // we need to encode (x - X) ^ 2 + (y - Y)^2 + (z - Z)^2 into the quadric + Q.a00 = w; + Q.a11 = w; + Q.a22 = w; + Q.a10 = 0.f; + Q.a20 = 0.f; + Q.a21 = 0.f; + Q.b0 = -2.f * x * w; + Q.b1 = -2.f * y * w; + Q.b2 = -2.f * z * w; + Q.c = (x * x + y * y + z * z) * w; + Q.w = w; +} + +static void quadricFromTriangle(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float weight) +{ + Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z}; + Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z}; + + // normal = cross(p1 - p0, p2 - p0) + Vector3 normal = {p10.y * p20.z - p10.z * p20.y, p10.z * p20.x - p10.x * p20.z, p10.x * p20.y - p10.y * p20.x}; + float area = normalize(normal); + + float distance = normal.x * p0.x + normal.y * p0.y + normal.z * p0.z; + + // we use sqrtf(area) so that the error is scaled linearly; this tends to improve silhouettes + quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, sqrtf(area) * weight); +} + +static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float weight) +{ + Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z}; + float length = normalize(p10); + + // p20p = length of projection of p2-p0 onto normalize(p1 - p0) + Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z}; + float p20p = p20.x * p10.x + p20.y * p10.y + p20.z * p10.z; + + // normal = altitude of triangle from point p2 onto edge p1-p0 + Vector3 normal = {p20.x - p10.x * p20p, p20.y - p10.y * p20p, p20.z - p10.z * p20p}; + normalize(normal); + + float distance = normal.x * p0.x + normal.y * p0.y + normal.z * p0.z; + + // note: the weight is scaled linearly with edge length; this has to match the triangle weight + quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, length * weight); +} + +static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap) +{ + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int i0 = indices[i + 0]; + unsigned int i1 = indices[i + 1]; + unsigned int i2 = indices[i + 2]; + + Quadric Q; + quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f); + + quadricAdd(vertex_quadrics[remap[i0]], Q); + quadricAdd(vertex_quadrics[remap[i1]], Q); + quadricAdd(vertex_quadrics[remap[i2]], Q); + } +} + +static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap, const unsigned char* vertex_kind, const unsigned int* loop, const unsigned int* loopback) +{ + for (size_t i = 0; i < index_count; i += 3) + { + static const int next[3] = {1, 2, 0}; + + for (int e = 0; e < 3; ++e) + { + unsigned int i0 = indices[i + e]; + unsigned int i1 = indices[i + next[e]]; + + unsigned char k0 = vertex_kind[i0]; + unsigned char k1 = vertex_kind[i1]; + + // check that either i0 or i1 are border/seam and are on the same edge loop + // note that we need to add the error even for edged that connect e.g. border & locked + // if we don't do that, the adjacent border->border edge won't have correct errors for corners + if (k0 != Kind_Border && k0 != Kind_Seam && k1 != Kind_Border && k1 != Kind_Seam) + continue; + + if ((k0 == Kind_Border || k0 == Kind_Seam) && loop[i0] != i1) + continue; + + if ((k1 == Kind_Border || k1 == Kind_Seam) && loopback[i1] != i0) + continue; + + // seam edges should occur twice (i0->i1 and i1->i0) - skip redundant edges + if (kHasOpposite[k0][k1] && remap[i1] > remap[i0]) + continue; + + unsigned int i2 = indices[i + next[next[e]]]; + + // we try hard to maintain border edge geometry; seam edges can move more freely + // due to topological restrictions on collapses, seam quadrics slightly improves collapse structure but aren't critical + const float kEdgeWeightSeam = 1.f; + const float kEdgeWeightBorder = 10.f; + + float edgeWeight = (k0 == Kind_Border || k1 == Kind_Border) ? kEdgeWeightBorder : kEdgeWeightSeam; + + Quadric Q; + quadricFromTriangleEdge(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], edgeWeight); + + quadricAdd(vertex_quadrics[remap[i0]], Q); + quadricAdd(vertex_quadrics[remap[i1]], Q); + } + } +} + +static size_t pickEdgeCollapses(Collapse* collapses, const unsigned int* indices, size_t index_count, const unsigned int* remap, const unsigned char* vertex_kind, const unsigned int* loop) +{ + size_t collapse_count = 0; + + for (size_t i = 0; i < index_count; i += 3) + { + static const int next[3] = {1, 2, 0}; + + for (int e = 0; e < 3; ++e) + { + unsigned int i0 = indices[i + e]; + unsigned int i1 = indices[i + next[e]]; + + // this can happen either when input has a zero-length edge, or when we perform collapses for complex + // topology w/seams and collapse a manifold vertex that connects to both wedges onto one of them + // we leave edges like this alone since they may be important for preserving mesh integrity + if (remap[i0] == remap[i1]) + continue; + + unsigned char k0 = vertex_kind[i0]; + unsigned char k1 = vertex_kind[i1]; + + // the edge has to be collapsible in at least one direction + if (!(kCanCollapse[k0][k1] | kCanCollapse[k1][k0])) + continue; + + // manifold and seam edges should occur twice (i0->i1 and i1->i0) - skip redundant edges + if (kHasOpposite[k0][k1] && remap[i1] > remap[i0]) + continue; + + // two vertices are on a border or a seam, but there's no direct edge between them + // this indicates that they belong to two different edge loops and we should not collapse this edge + // loop[] tracks half edges so we only need to check i0->i1 + if (k0 == k1 && (k0 == Kind_Border || k0 == Kind_Seam) && loop[i0] != i1) + continue; + + // edge can be collapsed in either direction - we will pick the one with minimum error + // note: we evaluate error later during collapse ranking, here we just tag the edge as bidirectional + if (kCanCollapse[k0][k1] & kCanCollapse[k1][k0]) + { + Collapse c = {i0, i1, {/* bidi= */ 1}}; + collapses[collapse_count++] = c; + } + else + { + // edge can only be collapsed in one direction + unsigned int e0 = kCanCollapse[k0][k1] ? i0 : i1; + unsigned int e1 = kCanCollapse[k0][k1] ? i1 : i0; + + Collapse c = {e0, e1, {/* bidi= */ 0}}; + collapses[collapse_count++] = c; + } + } + } + + return collapse_count; +} + +static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const Vector3* vertex_positions, const Quadric* vertex_quadrics, const unsigned int* remap) +{ + for (size_t i = 0; i < collapse_count; ++i) + { + Collapse& c = collapses[i]; + + unsigned int i0 = c.v0; + unsigned int i1 = c.v1; + + // most edges are bidirectional which means we need to evaluate errors for two collapses + // to keep this code branchless we just use the same edge for unidirectional edges + unsigned int j0 = c.bidi ? i1 : i0; + unsigned int j1 = c.bidi ? i0 : i1; + + const Quadric& qi = vertex_quadrics[remap[i0]]; + const Quadric& qj = vertex_quadrics[remap[j0]]; + + float ei = quadricError(qi, vertex_positions[i1]); + float ej = quadricError(qj, vertex_positions[j1]); + + // pick edge direction with minimal error + c.v0 = ei <= ej ? i0 : j0; + c.v1 = ei <= ej ? i1 : j1; + c.error = ei <= ej ? ei : ej; + } +} + +#if TRACE > 1 +static void dumpEdgeCollapses(const Collapse* collapses, size_t collapse_count, const unsigned char* vertex_kind) +{ + size_t ckinds[Kind_Count][Kind_Count] = {}; + float cerrors[Kind_Count][Kind_Count] = {}; + + for (int k0 = 0; k0 < Kind_Count; ++k0) + for (int k1 = 0; k1 < Kind_Count; ++k1) + cerrors[k0][k1] = FLT_MAX; + + for (size_t i = 0; i < collapse_count; ++i) + { + unsigned int i0 = collapses[i].v0; + unsigned int i1 = collapses[i].v1; + + unsigned char k0 = vertex_kind[i0]; + unsigned char k1 = vertex_kind[i1]; + + ckinds[k0][k1]++; + cerrors[k0][k1] = (collapses[i].error < cerrors[k0][k1]) ? collapses[i].error : cerrors[k0][k1]; + } + + for (int k0 = 0; k0 < Kind_Count; ++k0) + for (int k1 = 0; k1 < Kind_Count; ++k1) + if (ckinds[k0][k1]) + printf("collapses %d -> %d: %d, min error %e\n", k0, k1, int(ckinds[k0][k1]), cerrors[k0][k1]); +} + +static void dumpLockedCollapses(const unsigned int* indices, size_t index_count, const unsigned char* vertex_kind) +{ + size_t locked_collapses[Kind_Count][Kind_Count] = {}; + + for (size_t i = 0; i < index_count; i += 3) + { + static const int next[3] = {1, 2, 0}; + + for (int e = 0; e < 3; ++e) + { + unsigned int i0 = indices[i + e]; + unsigned int i1 = indices[i + next[e]]; + + unsigned char k0 = vertex_kind[i0]; + unsigned char k1 = vertex_kind[i1]; + + locked_collapses[k0][k1] += !kCanCollapse[k0][k1] && !kCanCollapse[k1][k0]; + } + } + + for (int k0 = 0; k0 < Kind_Count; ++k0) + for (int k1 = 0; k1 < Kind_Count; ++k1) + if (locked_collapses[k0][k1]) + printf("locked collapses %d -> %d: %d\n", k0, k1, int(locked_collapses[k0][k1])); +} +#endif + +static void sortEdgeCollapses(unsigned int* sort_order, const Collapse* collapses, size_t collapse_count) +{ + const int sort_bits = 11; + + // fill histogram for counting sort + unsigned int histogram[1 << sort_bits]; + memset(histogram, 0, sizeof(histogram)); + + for (size_t i = 0; i < collapse_count; ++i) + { + // skip sign bit since error is non-negative + unsigned int key = (collapses[i].errorui << 1) >> (32 - sort_bits); + + histogram[key]++; + } + + // compute offsets based on histogram data + size_t histogram_sum = 0; + + for (size_t i = 0; i < 1 << sort_bits; ++i) + { + size_t count = histogram[i]; + histogram[i] = unsigned(histogram_sum); + histogram_sum += count; + } + + assert(histogram_sum == collapse_count); + + // compute sort order based on offsets + for (size_t i = 0; i < collapse_count; ++i) + { + // skip sign bit since error is non-negative + unsigned int key = (collapses[i].errorui << 1) >> (32 - sort_bits); + + sort_order[histogram[key]++] = unsigned(i); + } +} + +static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char* collapse_locked, Quadric* vertex_quadrics, const Collapse* collapses, size_t collapse_count, const unsigned int* collapse_order, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, size_t triangle_collapse_goal, float error_goal, float error_limit) +{ + size_t edge_collapses = 0; + size_t triangle_collapses = 0; + + for (size_t i = 0; i < collapse_count; ++i) + { + const Collapse& c = collapses[collapse_order[i]]; + + if (c.error > error_limit) + break; + + if (c.error > error_goal && triangle_collapses > triangle_collapse_goal / 10) + break; + + if (triangle_collapses >= triangle_collapse_goal) + break; + + unsigned int i0 = c.v0; + unsigned int i1 = c.v1; + + unsigned int r0 = remap[i0]; + unsigned int r1 = remap[i1]; + + // we don't collapse vertices that had source or target vertex involved in a collapse + // it's important to not move the vertices twice since it complicates the tracking/remapping logic + // it's important to not move other vertices towards a moved vertex to preserve error since we don't re-rank collapses mid-pass + if (collapse_locked[r0] | collapse_locked[r1]) + continue; + + assert(collapse_remap[r0] == r0); + assert(collapse_remap[r1] == r1); + + quadricAdd(vertex_quadrics[r1], vertex_quadrics[r0]); + + if (vertex_kind[i0] == Kind_Complex) + { + unsigned int v = i0; + + do + { + collapse_remap[v] = r1; + v = wedge[v]; + } while (v != i0); + } + else if (vertex_kind[i0] == Kind_Seam) + { + // remap v0 to v1 and seam pair of v0 to seam pair of v1 + unsigned int s0 = wedge[i0]; + unsigned int s1 = wedge[i1]; + + assert(s0 != i0 && s1 != i1); + assert(wedge[s0] == i0 && wedge[s1] == i1); + + collapse_remap[i0] = i1; + collapse_remap[s0] = s1; + } + else + { + assert(wedge[i0] == i0); + + collapse_remap[i0] = i1; + } + + collapse_locked[r0] = 1; + collapse_locked[r1] = 1; + + // border edges collapse 1 triangle, other edges collapse 2 or more + triangle_collapses += (vertex_kind[i0] == Kind_Border) ? 1 : 2; + edge_collapses++; + } + + return edge_collapses; +} + +static size_t remapIndexBuffer(unsigned int* indices, size_t index_count, const unsigned int* collapse_remap) +{ + size_t write = 0; + + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int v0 = collapse_remap[indices[i + 0]]; + unsigned int v1 = collapse_remap[indices[i + 1]]; + unsigned int v2 = collapse_remap[indices[i + 2]]; + + // we never move the vertex twice during a single pass + assert(collapse_remap[v0] == v0); + assert(collapse_remap[v1] == v1); + assert(collapse_remap[v2] == v2); + + if (v0 != v1 && v0 != v2 && v1 != v2) + { + indices[write + 0] = v0; + indices[write + 1] = v1; + indices[write + 2] = v2; + write += 3; + } + } + + return write; +} + +static void remapEdgeLoops(unsigned int* loop, size_t vertex_count, const unsigned int* collapse_remap) +{ + for (size_t i = 0; i < vertex_count; ++i) + { + if (loop[i] != ~0u) + { + unsigned int l = loop[i]; + unsigned int r = collapse_remap[l]; + + // i == r is a special case when the seam edge is collapsed in a direction opposite to where loop goes + loop[i] = (i == r) ? loop[l] : r; + } + } +} + +struct CellHasher +{ + const unsigned int* vertex_ids; + + size_t hash(unsigned int i) const + { + unsigned int h = vertex_ids[i]; + + // MurmurHash2 finalizer + h ^= h >> 13; + h *= 0x5bd1e995; + h ^= h >> 15; + return h; + } + + bool equal(unsigned int lhs, unsigned int rhs) const + { + return vertex_ids[lhs] == vertex_ids[rhs]; + } +}; + +struct IdHasher +{ + size_t hash(unsigned int id) const + { + unsigned int h = id; + + // MurmurHash2 finalizer + h ^= h >> 13; + h *= 0x5bd1e995; + h ^= h >> 15; + return h; + } + + bool equal(unsigned int lhs, unsigned int rhs) const + { + return lhs == rhs; + } +}; + +struct TriangleHasher +{ + unsigned int* indices; + + size_t hash(unsigned int i) const + { + const unsigned int* tri = indices + i * 3; + + // Optimized Spatial Hashing for Collision Detection of Deformable Objects + return (tri[0] * 73856093) ^ (tri[1] * 19349663) ^ (tri[2] * 83492791); + } + + bool equal(unsigned int lhs, unsigned int rhs) const + { + const unsigned int* lt = indices + lhs * 3; + const unsigned int* rt = indices + rhs * 3; + + return lt[0] == rt[0] && lt[1] == rt[1] && lt[2] == rt[2]; + } +}; + +static void computeVertexIds(unsigned int* vertex_ids, const Vector3* vertex_positions, size_t vertex_count, int grid_size) +{ + assert(grid_size >= 1 && grid_size <= 1024); + float cell_scale = float(grid_size - 1); + + for (size_t i = 0; i < vertex_count; ++i) + { + const Vector3& v = vertex_positions[i]; + + int xi = int(v.x * cell_scale + 0.5f); + int yi = int(v.y * cell_scale + 0.5f); + int zi = int(v.z * cell_scale + 0.5f); + + vertex_ids[i] = (xi << 20) | (yi << 10) | zi; + } +} + +static size_t countTriangles(const unsigned int* vertex_ids, const unsigned int* indices, size_t index_count) +{ + size_t result = 0; + + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int id0 = vertex_ids[indices[i + 0]]; + unsigned int id1 = vertex_ids[indices[i + 1]]; + unsigned int id2 = vertex_ids[indices[i + 2]]; + + result += (id0 != id1) & (id0 != id2) & (id1 != id2); + } + + return result; +} + +static size_t fillVertexCells(unsigned int* table, size_t table_size, unsigned int* vertex_cells, const unsigned int* vertex_ids, size_t vertex_count) +{ + CellHasher hasher = {vertex_ids}; + + memset(table, -1, table_size * sizeof(unsigned int)); + + size_t result = 0; + + for (size_t i = 0; i < vertex_count; ++i) + { + unsigned int* entry = hashLookup2(table, table_size, hasher, unsigned(i), ~0u); + + if (*entry == ~0u) + { + *entry = unsigned(i); + vertex_cells[i] = unsigned(result++); + } + else + { + vertex_cells[i] = vertex_cells[*entry]; + } + } + + return result; +} + +static size_t countVertexCells(unsigned int* table, size_t table_size, const unsigned int* vertex_ids, size_t vertex_count) +{ + IdHasher hasher; + + memset(table, -1, table_size * sizeof(unsigned int)); + + size_t result = 0; + + for (size_t i = 0; i < vertex_count; ++i) + { + unsigned int id = vertex_ids[i]; + unsigned int* entry = hashLookup2(table, table_size, hasher, id, ~0u); + + result += (*entry == ~0u); + *entry = id; + } + + return result; +} + +static void fillCellQuadrics(Quadric* cell_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* vertex_cells) +{ + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int i0 = indices[i + 0]; + unsigned int i1 = indices[i + 1]; + unsigned int i2 = indices[i + 2]; + + unsigned int c0 = vertex_cells[i0]; + unsigned int c1 = vertex_cells[i1]; + unsigned int c2 = vertex_cells[i2]; + + bool single_cell = (c0 == c1) & (c0 == c2); + + Quadric Q; + quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], single_cell ? 3.f : 1.f); + + if (single_cell) + { + quadricAdd(cell_quadrics[c0], Q); + } + else + { + quadricAdd(cell_quadrics[c0], Q); + quadricAdd(cell_quadrics[c1], Q); + quadricAdd(cell_quadrics[c2], Q); + } + } +} + +static void fillCellQuadrics(Quadric* cell_quadrics, const Vector3* vertex_positions, size_t vertex_count, const unsigned int* vertex_cells) +{ + for (size_t i = 0; i < vertex_count; ++i) + { + unsigned int c = vertex_cells[i]; + const Vector3& v = vertex_positions[i]; + + Quadric Q; + quadricFromPoint(Q, v.x, v.y, v.z, 1.f); + + quadricAdd(cell_quadrics[c], Q); + } +} + +static void fillCellRemap(unsigned int* cell_remap, float* cell_errors, size_t cell_count, const unsigned int* vertex_cells, const Quadric* cell_quadrics, const Vector3* vertex_positions, size_t vertex_count) +{ + memset(cell_remap, -1, cell_count * sizeof(unsigned int)); + + for (size_t i = 0; i < vertex_count; ++i) + { + unsigned int cell = vertex_cells[i]; + float error = quadricError(cell_quadrics[cell], vertex_positions[i]); + + if (cell_remap[cell] == ~0u || cell_errors[cell] > error) + { + cell_remap[cell] = unsigned(i); + cell_errors[cell] = error; + } + } +} + +static size_t filterTriangles(unsigned int* destination, unsigned int* tritable, size_t tritable_size, const unsigned int* indices, size_t index_count, const unsigned int* vertex_cells, const unsigned int* cell_remap) +{ + TriangleHasher hasher = {destination}; + + memset(tritable, -1, tritable_size * sizeof(unsigned int)); + + size_t result = 0; + + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int c0 = vertex_cells[indices[i + 0]]; + unsigned int c1 = vertex_cells[indices[i + 1]]; + unsigned int c2 = vertex_cells[indices[i + 2]]; + + if (c0 != c1 && c0 != c2 && c1 != c2) + { + unsigned int a = cell_remap[c0]; + unsigned int b = cell_remap[c1]; + unsigned int c = cell_remap[c2]; + + if (b < a && b < c) + { + unsigned int t = a; + a = b, b = c, c = t; + } + else if (c < a && c < b) + { + unsigned int t = c; + c = b, b = a, a = t; + } + + destination[result * 3 + 0] = a; + destination[result * 3 + 1] = b; + destination[result * 3 + 2] = c; + + unsigned int* entry = hashLookup2(tritable, tritable_size, hasher, unsigned(result), ~0u); + + if (*entry == ~0u) + *entry = unsigned(result++); + } + } + + return result * 3; +} + +static float interpolate(float y, float x0, float y0, float x1, float y1, float x2, float y2) +{ + // three point interpolation from "revenge of interpolation search" paper + float num = (y1 - y) * (x1 - x2) * (x1 - x0) * (y2 - y0); + float den = (y2 - y) * (x1 - x2) * (y0 - y1) + (y0 - y) * (x1 - x0) * (y1 - y2); + return x1 + num / den; +} + +} // namespace meshopt + +#ifndef NDEBUG +unsigned char* meshopt_simplifyDebugKind = 0; +unsigned int* meshopt_simplifyDebugLoop = 0; +unsigned int* meshopt_simplifyDebugLoopBack = 0; +#endif + +size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + assert(target_index_count <= index_count); + + meshopt_Allocator allocator; + + unsigned int* result = destination; + + // build adjacency information + EdgeAdjacency adjacency = {}; + buildEdgeAdjacency(adjacency, indices, index_count, vertex_count, allocator); + + // build position remap that maps each vertex to the one with identical position + unsigned int* remap = allocator.allocate<unsigned int>(vertex_count); + unsigned int* wedge = allocator.allocate<unsigned int>(vertex_count); + buildPositionRemap(remap, wedge, vertex_positions_data, vertex_count, vertex_positions_stride, allocator); + + // classify vertices; vertex kind determines collapse rules, see kCanCollapse + unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count); + unsigned int* loop = allocator.allocate<unsigned int>(vertex_count); + unsigned int* loopback = allocator.allocate<unsigned int>(vertex_count); + classifyVertices(vertex_kind, loop, loopback, vertex_count, adjacency, remap, wedge); + +#if TRACE + size_t unique_positions = 0; + for (size_t i = 0; i < vertex_count; ++i) + unique_positions += remap[i] == i; + + printf("position remap: %d vertices => %d positions\n", int(vertex_count), int(unique_positions)); + + size_t kinds[Kind_Count] = {}; + for (size_t i = 0; i < vertex_count; ++i) + kinds[vertex_kind[i]] += remap[i] == i; + + printf("kinds: manifold %d, border %d, seam %d, complex %d, locked %d\n", + int(kinds[Kind_Manifold]), int(kinds[Kind_Border]), int(kinds[Kind_Seam]), int(kinds[Kind_Complex]), int(kinds[Kind_Locked])); +#endif + + Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count); + rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride); + + Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count); + memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric)); + + fillFaceQuadrics(vertex_quadrics, indices, index_count, vertex_positions, remap); + fillEdgeQuadrics(vertex_quadrics, indices, index_count, vertex_positions, remap, vertex_kind, loop, loopback); + + if (result != indices) + memcpy(result, indices, index_count * sizeof(unsigned int)); + +#if TRACE + size_t pass_count = 0; + float worst_error = 0; +#endif + + Collapse* edge_collapses = allocator.allocate<Collapse>(index_count); + unsigned int* collapse_order = allocator.allocate<unsigned int>(index_count); + unsigned int* collapse_remap = allocator.allocate<unsigned int>(vertex_count); + unsigned char* collapse_locked = allocator.allocate<unsigned char>(vertex_count); + + size_t result_count = index_count; + + // target_error input is linear; we need to adjust it to match quadricError units + float error_limit = target_error * target_error; + + while (result_count > target_index_count) + { + size_t edge_collapse_count = pickEdgeCollapses(edge_collapses, result, result_count, remap, vertex_kind, loop); + + // no edges can be collapsed any more due to topology restrictions + if (edge_collapse_count == 0) + break; + + rankEdgeCollapses(edge_collapses, edge_collapse_count, vertex_positions, vertex_quadrics, remap); + +#if TRACE > 1 + dumpEdgeCollapses(edge_collapses, edge_collapse_count, vertex_kind); +#endif + + sortEdgeCollapses(collapse_order, edge_collapses, edge_collapse_count); + + // most collapses remove 2 triangles; use this to establish a bound on the pass in terms of error limit + // note that edge_collapse_goal is an estimate; triangle_collapse_goal will be used to actually limit collapses + size_t triangle_collapse_goal = (result_count - target_index_count) / 3; + size_t edge_collapse_goal = triangle_collapse_goal / 2; + + // we limit the error in each pass based on the error of optimal last collapse; since many collapses will be locked + // as they will share vertices with other successfull collapses, we need to increase the acceptable error by this factor + const float kPassErrorBound = 1.5f; + + float error_goal = edge_collapse_goal < edge_collapse_count ? edge_collapses[collapse_order[edge_collapse_goal]].error * kPassErrorBound : FLT_MAX; + + for (size_t i = 0; i < vertex_count; ++i) + collapse_remap[i] = unsigned(i); + + memset(collapse_locked, 0, vertex_count); + + size_t collapses = performEdgeCollapses(collapse_remap, collapse_locked, vertex_quadrics, edge_collapses, edge_collapse_count, collapse_order, remap, wedge, vertex_kind, triangle_collapse_goal, error_goal, error_limit); + + // no edges can be collapsed any more due to hitting the error limit or triangle collapse limit + if (collapses == 0) + break; + + remapEdgeLoops(loop, vertex_count, collapse_remap); + remapEdgeLoops(loopback, vertex_count, collapse_remap); + + size_t new_count = remapIndexBuffer(result, result_count, collapse_remap); + assert(new_count < result_count); + +#if TRACE + float pass_error = 0.f; + for (size_t i = 0; i < edge_collapse_count; ++i) + { + Collapse& c = edge_collapses[collapse_order[i]]; + + if (collapse_remap[c.v0] == c.v1) + pass_error = c.error; + } + + pass_count++; + worst_error = (worst_error < pass_error) ? pass_error : worst_error; + + printf("pass %d: triangles: %d -> %d, collapses: %d/%d (goal: %d), error: %e (limit %e goal %e)\n", int(pass_count), int(result_count / 3), int(new_count / 3), int(collapses), int(edge_collapse_count), int(edge_collapse_goal), pass_error, error_limit, error_goal); +#endif + + result_count = new_count; + } + +#if TRACE + printf("passes: %d, worst error: %e\n", int(pass_count), worst_error); +#endif + +#if TRACE > 1 + dumpLockedCollapses(result, result_count, vertex_kind); +#endif + +#ifndef NDEBUG + if (meshopt_simplifyDebugKind) + memcpy(meshopt_simplifyDebugKind, vertex_kind, vertex_count); + + if (meshopt_simplifyDebugLoop) + memcpy(meshopt_simplifyDebugLoop, loop, vertex_count * sizeof(unsigned int)); + + if (meshopt_simplifyDebugLoopBack) + memcpy(meshopt_simplifyDebugLoopBack, loopback, vertex_count * sizeof(unsigned int)); +#endif + + return result_count; +} + +size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + assert(target_index_count <= index_count); + + // we expect to get ~2 triangles/vertex in the output + size_t target_cell_count = target_index_count / 6; + + if (target_cell_count == 0) + return 0; + + meshopt_Allocator allocator; + + Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count); + rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride); + + // find the optimal grid size using guided binary search +#if TRACE + printf("source: %d vertices, %d triangles\n", int(vertex_count), int(index_count / 3)); + printf("target: %d cells, %d triangles\n", int(target_cell_count), int(target_index_count / 3)); +#endif + + unsigned int* vertex_ids = allocator.allocate<unsigned int>(vertex_count); + + const int kInterpolationPasses = 5; + + // invariant: # of triangles in min_grid <= target_count + int min_grid = 0; + int max_grid = 1025; + size_t min_triangles = 0; + size_t max_triangles = index_count / 3; + + // instead of starting in the middle, let's guess as to what the answer might be! triangle count usually grows as a square of grid size... + int next_grid_size = int(sqrtf(float(target_cell_count)) + 0.5f); + + for (int pass = 0; pass < 10 + kInterpolationPasses; ++pass) + { + assert(min_triangles < target_index_count / 3); + assert(max_grid - min_grid > 1); + + // we clamp the prediction of the grid size to make sure that the search converges + int grid_size = next_grid_size; + grid_size = (grid_size <= min_grid) ? min_grid + 1 : (grid_size >= max_grid) ? max_grid - 1 : grid_size; + + computeVertexIds(vertex_ids, vertex_positions, vertex_count, grid_size); + size_t triangles = countTriangles(vertex_ids, indices, index_count); + +#if TRACE + printf("pass %d (%s): grid size %d, triangles %d, %s\n", + pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", + grid_size, int(triangles), + (triangles <= target_index_count / 3) ? "under" : "over"); +#endif + + float tip = interpolate(float(target_index_count / 3), float(min_grid), float(min_triangles), float(grid_size), float(triangles), float(max_grid), float(max_triangles)); + + if (triangles <= target_index_count / 3) + { + min_grid = grid_size; + min_triangles = triangles; + } + else + { + max_grid = grid_size; + max_triangles = triangles; + } + + if (triangles == target_index_count / 3 || max_grid - min_grid <= 1) + break; + + // we start by using interpolation search - it usually converges faster + // however, interpolation search has a worst case of O(N) so we switch to binary search after a few iterations which converges in O(logN) + next_grid_size = (pass < kInterpolationPasses) ? int(tip + 0.5f) : (min_grid + max_grid) / 2; + } + + if (min_triangles == 0) + return 0; + + // build vertex->cell association by mapping all vertices with the same quantized position to the same cell + size_t table_size = hashBuckets2(vertex_count); + unsigned int* table = allocator.allocate<unsigned int>(table_size); + + unsigned int* vertex_cells = allocator.allocate<unsigned int>(vertex_count); + + computeVertexIds(vertex_ids, vertex_positions, vertex_count, min_grid); + size_t cell_count = fillVertexCells(table, table_size, vertex_cells, vertex_ids, vertex_count); + + // build a quadric for each target cell + Quadric* cell_quadrics = allocator.allocate<Quadric>(cell_count); + memset(cell_quadrics, 0, cell_count * sizeof(Quadric)); + + fillCellQuadrics(cell_quadrics, indices, index_count, vertex_positions, vertex_cells); + + // for each target cell, find the vertex with the minimal error + unsigned int* cell_remap = allocator.allocate<unsigned int>(cell_count); + float* cell_errors = allocator.allocate<float>(cell_count); + + fillCellRemap(cell_remap, cell_errors, cell_count, vertex_cells, cell_quadrics, vertex_positions, vertex_count); + + // collapse triangles! + // note that we need to filter out triangles that we've already output because we very frequently generate redundant triangles between cells :( + size_t tritable_size = hashBuckets2(min_triangles); + unsigned int* tritable = allocator.allocate<unsigned int>(tritable_size); + + size_t write = filterTriangles(destination, tritable, tritable_size, indices, index_count, vertex_cells, cell_remap); + assert(write <= target_index_count); + +#if TRACE + printf("result: %d cells, %d triangles (%d unfiltered)\n", int(cell_count), int(write / 3), int(min_triangles)); +#endif + + return write; +} + +size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_vertex_count) +{ + using namespace meshopt; + + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + assert(target_vertex_count <= vertex_count); + + size_t target_cell_count = target_vertex_count; + + if (target_cell_count == 0) + return 0; + + meshopt_Allocator allocator; + + Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count); + rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride); + + // find the optimal grid size using guided binary search +#if TRACE + printf("source: %d vertices\n", int(vertex_count)); + printf("target: %d cells\n", int(target_cell_count)); +#endif + + unsigned int* vertex_ids = allocator.allocate<unsigned int>(vertex_count); + + size_t table_size = hashBuckets2(vertex_count); + unsigned int* table = allocator.allocate<unsigned int>(table_size); + + const int kInterpolationPasses = 5; + + // invariant: # of vertices in min_grid <= target_count + int min_grid = 0; + int max_grid = 1025; + size_t min_vertices = 0; + size_t max_vertices = vertex_count; + + // instead of starting in the middle, let's guess as to what the answer might be! triangle count usually grows as a square of grid size... + int next_grid_size = int(sqrtf(float(target_cell_count)) + 0.5f); + + for (int pass = 0; pass < 10 + kInterpolationPasses; ++pass) + { + assert(min_vertices < target_vertex_count); + assert(max_grid - min_grid > 1); + + // we clamp the prediction of the grid size to make sure that the search converges + int grid_size = next_grid_size; + grid_size = (grid_size <= min_grid) ? min_grid + 1 : (grid_size >= max_grid) ? max_grid - 1 : grid_size; + + computeVertexIds(vertex_ids, vertex_positions, vertex_count, grid_size); + size_t vertices = countVertexCells(table, table_size, vertex_ids, vertex_count); + +#if TRACE + printf("pass %d (%s): grid size %d, vertices %d, %s\n", + pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", + grid_size, int(vertices), + (vertices <= target_vertex_count) ? "under" : "over"); +#endif + + float tip = interpolate(float(target_vertex_count), float(min_grid), float(min_vertices), float(grid_size), float(vertices), float(max_grid), float(max_vertices)); + + if (vertices <= target_vertex_count) + { + min_grid = grid_size; + min_vertices = vertices; + } + else + { + max_grid = grid_size; + max_vertices = vertices; + } + + if (vertices == target_vertex_count || max_grid - min_grid <= 1) + break; + + // we start by using interpolation search - it usually converges faster + // however, interpolation search has a worst case of O(N) so we switch to binary search after a few iterations which converges in O(logN) + next_grid_size = (pass < kInterpolationPasses) ? int(tip + 0.5f) : (min_grid + max_grid) / 2; + } + + if (min_vertices == 0) + return 0; + + // build vertex->cell association by mapping all vertices with the same quantized position to the same cell + unsigned int* vertex_cells = allocator.allocate<unsigned int>(vertex_count); + + computeVertexIds(vertex_ids, vertex_positions, vertex_count, min_grid); + size_t cell_count = fillVertexCells(table, table_size, vertex_cells, vertex_ids, vertex_count); + + // build a quadric for each target cell + Quadric* cell_quadrics = allocator.allocate<Quadric>(cell_count); + memset(cell_quadrics, 0, cell_count * sizeof(Quadric)); + + fillCellQuadrics(cell_quadrics, vertex_positions, vertex_count, vertex_cells); + + // for each target cell, find the vertex with the minimal error + unsigned int* cell_remap = allocator.allocate<unsigned int>(cell_count); + float* cell_errors = allocator.allocate<float>(cell_count); + + fillCellRemap(cell_remap, cell_errors, cell_count, vertex_cells, cell_quadrics, vertex_positions, vertex_count); + + // copy results to the output + assert(cell_count <= target_vertex_count); + memcpy(destination, cell_remap, sizeof(unsigned int) * cell_count); + +#if TRACE + printf("result: %d cells\n", int(cell_count)); +#endif + + return cell_count; +} diff --git a/thirdparty/meshoptimizer/spatialorder.cpp b/thirdparty/meshoptimizer/spatialorder.cpp new file mode 100644 index 0000000000..b09f80ac6f --- /dev/null +++ b/thirdparty/meshoptimizer/spatialorder.cpp @@ -0,0 +1,194 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <float.h> +#include <string.h> + +// This work is based on: +// Fabian Giesen. Decoding Morton codes. 2009 +namespace meshopt +{ + +// "Insert" two 0 bits after each of the 10 low bits of x +inline unsigned int part1By2(unsigned int x) +{ + x &= 0x000003ff; // x = ---- ---- ---- ---- ---- --98 7654 3210 + x = (x ^ (x << 16)) & 0xff0000ff; // x = ---- --98 ---- ---- ---- ---- 7654 3210 + x = (x ^ (x << 8)) & 0x0300f00f; // x = ---- --98 ---- ---- 7654 ---- ---- 3210 + x = (x ^ (x << 4)) & 0x030c30c3; // x = ---- --98 ---- 76-- --54 ---- 32-- --10 + x = (x ^ (x << 2)) & 0x09249249; // x = ---- 9--8 --7- -6-- 5--4 --3- -2-- 1--0 + return x; +} + +static void computeOrder(unsigned int* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride) +{ + size_t vertex_stride_float = vertex_positions_stride / sizeof(float); + + float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX}; + float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + + for (size_t i = 0; i < vertex_count; ++i) + { + const float* v = vertex_positions_data + i * vertex_stride_float; + + for (int j = 0; j < 3; ++j) + { + float vj = v[j]; + + minv[j] = minv[j] > vj ? vj : minv[j]; + maxv[j] = maxv[j] < vj ? vj : maxv[j]; + } + } + + float extent = 0.f; + + extent = (maxv[0] - minv[0]) < extent ? extent : (maxv[0] - minv[0]); + extent = (maxv[1] - minv[1]) < extent ? extent : (maxv[1] - minv[1]); + extent = (maxv[2] - minv[2]) < extent ? extent : (maxv[2] - minv[2]); + + float scale = extent == 0 ? 0.f : 1.f / extent; + + // generate Morton order based on the position inside a unit cube + for (size_t i = 0; i < vertex_count; ++i) + { + const float* v = vertex_positions_data + i * vertex_stride_float; + + int x = int((v[0] - minv[0]) * scale * 1023.f + 0.5f); + int y = int((v[1] - minv[1]) * scale * 1023.f + 0.5f); + int z = int((v[2] - minv[2]) * scale * 1023.f + 0.5f); + + result[i] = part1By2(x) | (part1By2(y) << 1) | (part1By2(z) << 2); + } +} + +static void computeHistogram(unsigned int (&hist)[1024][3], const unsigned int* data, size_t count) +{ + memset(hist, 0, sizeof(hist)); + + // compute 3 10-bit histograms in parallel + for (size_t i = 0; i < count; ++i) + { + unsigned int id = data[i]; + + hist[(id >> 0) & 1023][0]++; + hist[(id >> 10) & 1023][1]++; + hist[(id >> 20) & 1023][2]++; + } + + unsigned int sumx = 0, sumy = 0, sumz = 0; + + // replace histogram data with prefix histogram sums in-place + for (int i = 0; i < 1024; ++i) + { + unsigned int hx = hist[i][0], hy = hist[i][1], hz = hist[i][2]; + + hist[i][0] = sumx; + hist[i][1] = sumy; + hist[i][2] = sumz; + + sumx += hx; + sumy += hy; + sumz += hz; + } + + assert(sumx == count && sumy == count && sumz == count); +} + +static void radixPass(unsigned int* destination, const unsigned int* source, const unsigned int* keys, size_t count, unsigned int (&hist)[1024][3], int pass) +{ + int bitoff = pass * 10; + + for (size_t i = 0; i < count; ++i) + { + unsigned int id = (keys[source[i]] >> bitoff) & 1023; + + destination[hist[id][pass]++] = source[i]; + } +} + +} // namespace meshopt + +void meshopt_spatialSortRemap(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + using namespace meshopt; + + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + + meshopt_Allocator allocator; + + unsigned int* keys = allocator.allocate<unsigned int>(vertex_count); + computeOrder(keys, vertex_positions, vertex_count, vertex_positions_stride); + + unsigned int hist[1024][3]; + computeHistogram(hist, keys, vertex_count); + + unsigned int* scratch = allocator.allocate<unsigned int>(vertex_count); + + for (size_t i = 0; i < vertex_count; ++i) + destination[i] = unsigned(i); + + // 3-pass radix sort computes the resulting order into scratch + radixPass(scratch, destination, keys, vertex_count, hist, 0); + radixPass(destination, scratch, keys, vertex_count, hist, 1); + radixPass(scratch, destination, keys, vertex_count, hist, 2); + + // since our remap table is mapping old=>new, we need to reverse it + for (size_t i = 0; i < vertex_count; ++i) + destination[scratch[i]] = unsigned(i); +} + +void meshopt_spatialSortTriangles(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256); + assert(vertex_positions_stride % sizeof(float) == 0); + + (void)vertex_count; + + size_t face_count = index_count / 3; + size_t vertex_stride_float = vertex_positions_stride / sizeof(float); + + meshopt_Allocator allocator; + + float* centroids = allocator.allocate<float>(face_count * 3); + + for (size_t i = 0; i < face_count; ++i) + { + unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2]; + assert(a < vertex_count && b < vertex_count && c < vertex_count); + + const float* va = vertex_positions + a * vertex_stride_float; + const float* vb = vertex_positions + b * vertex_stride_float; + const float* vc = vertex_positions + c * vertex_stride_float; + + centroids[i * 3 + 0] = (va[0] + vb[0] + vc[0]) / 3.f; + centroids[i * 3 + 1] = (va[1] + vb[1] + vc[1]) / 3.f; + centroids[i * 3 + 2] = (va[2] + vb[2] + vc[2]) / 3.f; + } + + unsigned int* remap = allocator.allocate<unsigned int>(face_count); + + meshopt_spatialSortRemap(remap, centroids, face_count, sizeof(float) * 3); + + // support in-order remap + if (destination == indices) + { + unsigned int* indices_copy = allocator.allocate<unsigned int>(index_count); + memcpy(indices_copy, indices, index_count * sizeof(unsigned int)); + indices = indices_copy; + } + + for (size_t i = 0; i < face_count; ++i) + { + unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2]; + unsigned int r = remap[i]; + + destination[r * 3 + 0] = a; + destination[r * 3 + 1] = b; + destination[r * 3 + 2] = c; + } +} diff --git a/thirdparty/meshoptimizer/stripifier.cpp b/thirdparty/meshoptimizer/stripifier.cpp new file mode 100644 index 0000000000..8ce17ef3dc --- /dev/null +++ b/thirdparty/meshoptimizer/stripifier.cpp @@ -0,0 +1,295 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <limits.h> +#include <string.h> + +// This work is based on: +// Francine Evans, Steven Skiena and Amitabh Varshney. Optimizing Triangle Strips for Fast Rendering. 1996 +namespace meshopt +{ + +static unsigned int findStripFirst(const unsigned int buffer[][3], unsigned int buffer_size, const unsigned int* valence) +{ + unsigned int index = 0; + unsigned int iv = ~0u; + + for (size_t i = 0; i < buffer_size; ++i) + { + unsigned int va = valence[buffer[i][0]], vb = valence[buffer[i][1]], vc = valence[buffer[i][2]]; + unsigned int v = (va < vb && va < vc) ? va : (vb < vc) ? vb : vc; + + if (v < iv) + { + index = unsigned(i); + iv = v; + } + } + + return index; +} + +static int findStripNext(const unsigned int buffer[][3], unsigned int buffer_size, unsigned int e0, unsigned int e1) +{ + for (size_t i = 0; i < buffer_size; ++i) + { + unsigned int a = buffer[i][0], b = buffer[i][1], c = buffer[i][2]; + + if (e0 == a && e1 == b) + return (int(i) << 2) | 2; + else if (e0 == b && e1 == c) + return (int(i) << 2) | 0; + else if (e0 == c && e1 == a) + return (int(i) << 2) | 1; + } + + return -1; +} + +} // namespace meshopt + +size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int restart_index) +{ + assert(destination != indices); + assert(index_count % 3 == 0); + + using namespace meshopt; + + meshopt_Allocator allocator; + + const size_t buffer_capacity = 8; + + unsigned int buffer[buffer_capacity][3] = {}; + unsigned int buffer_size = 0; + + size_t index_offset = 0; + + unsigned int strip[2] = {}; + unsigned int parity = 0; + + size_t strip_size = 0; + + // compute vertex valence; this is used to prioritize starting triangle for strips + unsigned int* valence = allocator.allocate<unsigned int>(vertex_count); + memset(valence, 0, vertex_count * sizeof(unsigned int)); + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices[i]; + assert(index < vertex_count); + + valence[index]++; + } + + int next = -1; + + while (buffer_size > 0 || index_offset < index_count) + { + assert(next < 0 || (size_t(next >> 2) < buffer_size && (next & 3) < 3)); + + // fill triangle buffer + while (buffer_size < buffer_capacity && index_offset < index_count) + { + buffer[buffer_size][0] = indices[index_offset + 0]; + buffer[buffer_size][1] = indices[index_offset + 1]; + buffer[buffer_size][2] = indices[index_offset + 2]; + + buffer_size++; + index_offset += 3; + } + + assert(buffer_size > 0); + + if (next >= 0) + { + unsigned int i = next >> 2; + unsigned int a = buffer[i][0], b = buffer[i][1], c = buffer[i][2]; + unsigned int v = buffer[i][next & 3]; + + // ordered removal from the buffer + memmove(buffer[i], buffer[i + 1], (buffer_size - i - 1) * sizeof(buffer[0])); + buffer_size--; + + // update vertex valences for strip start heuristic + valence[a]--; + valence[b]--; + valence[c]--; + + // find next triangle (note that edge order flips on every iteration) + // in some cases we need to perform a swap to pick a different outgoing triangle edge + // for [a b c], the default strip edge is [b c], but we might want to use [a c] + int cont = findStripNext(buffer, buffer_size, parity ? strip[1] : v, parity ? v : strip[1]); + int swap = cont < 0 ? findStripNext(buffer, buffer_size, parity ? v : strip[0], parity ? strip[0] : v) : -1; + + if (cont < 0 && swap >= 0) + { + // [a b c] => [a b a c] + destination[strip_size++] = strip[0]; + destination[strip_size++] = v; + + // next strip has same winding + // ? a b => b a v + strip[1] = v; + + next = swap; + } + else + { + // emit the next vertex in the strip + destination[strip_size++] = v; + + // next strip has flipped winding + strip[0] = strip[1]; + strip[1] = v; + parity ^= 1; + + next = cont; + } + } + else + { + // if we didn't find anything, we need to find the next new triangle + // we use a heuristic to maximize the strip length + unsigned int i = findStripFirst(buffer, buffer_size, &valence[0]); + unsigned int a = buffer[i][0], b = buffer[i][1], c = buffer[i][2]; + + // ordered removal from the buffer + memmove(buffer[i], buffer[i + 1], (buffer_size - i - 1) * sizeof(buffer[0])); + buffer_size--; + + // update vertex valences for strip start heuristic + valence[a]--; + valence[b]--; + valence[c]--; + + // we need to pre-rotate the triangle so that we will find a match in the existing buffer on the next iteration + int ea = findStripNext(buffer, buffer_size, c, b); + int eb = findStripNext(buffer, buffer_size, a, c); + int ec = findStripNext(buffer, buffer_size, b, a); + + // in some cases we can have several matching edges; since we can pick any edge, we pick the one with the smallest + // triangle index in the buffer. this reduces the effect of stripification on ACMR and additionally - for unclear + // reasons - slightly improves the stripification efficiency + int mine = INT_MAX; + mine = (ea >= 0 && mine > ea) ? ea : mine; + mine = (eb >= 0 && mine > eb) ? eb : mine; + mine = (ec >= 0 && mine > ec) ? ec : mine; + + if (ea == mine) + { + // keep abc + next = ea; + } + else if (eb == mine) + { + // abc -> bca + unsigned int t = a; + a = b, b = c, c = t; + + next = eb; + } + else if (ec == mine) + { + // abc -> cab + unsigned int t = c; + c = b, b = a, a = t; + + next = ec; + } + + if (restart_index) + { + if (strip_size) + destination[strip_size++] = restart_index; + + destination[strip_size++] = a; + destination[strip_size++] = b; + destination[strip_size++] = c; + + // new strip always starts with the same edge winding + strip[0] = b; + strip[1] = c; + parity = 1; + } + else + { + if (strip_size) + { + // connect last strip using degenerate triangles + destination[strip_size++] = strip[1]; + destination[strip_size++] = a; + } + + // note that we may need to flip the emitted triangle based on parity + // we always end up with outgoing edge "cb" in the end + unsigned int e0 = parity ? c : b; + unsigned int e1 = parity ? b : c; + + destination[strip_size++] = a; + destination[strip_size++] = e0; + destination[strip_size++] = e1; + + strip[0] = e0; + strip[1] = e1; + parity ^= 1; + } + } + } + + return strip_size; +} + +size_t meshopt_stripifyBound(size_t index_count) +{ + assert(index_count % 3 == 0); + + // worst case without restarts is 2 degenerate indices and 3 indices per triangle + // worst case with restarts is 1 restart index and 3 indices per triangle + return (index_count / 3) * 5; +} + +size_t meshopt_unstripify(unsigned int* destination, const unsigned int* indices, size_t index_count, unsigned int restart_index) +{ + assert(destination != indices); + + size_t offset = 0; + size_t start = 0; + + for (size_t i = 0; i < index_count; ++i) + { + if (restart_index && indices[i] == restart_index) + { + start = i + 1; + } + else if (i - start >= 2) + { + unsigned int a = indices[i - 2], b = indices[i - 1], c = indices[i]; + + // flip winding for odd triangles + if ((i - start) & 1) + { + unsigned int t = a; + a = b, b = t; + } + + // although we use restart indices, strip swaps still produce degenerate triangles, so skip them + if (a != b && a != c && b != c) + { + destination[offset + 0] = a; + destination[offset + 1] = b; + destination[offset + 2] = c; + offset += 3; + } + } + } + + return offset; +} + +size_t meshopt_unstripifyBound(size_t index_count) +{ + assert(index_count == 0 || index_count >= 3); + + return (index_count == 0) ? 0 : (index_count - 2) * 3; +} diff --git a/thirdparty/meshoptimizer/vcacheanalyzer.cpp b/thirdparty/meshoptimizer/vcacheanalyzer.cpp new file mode 100644 index 0000000000..3682743820 --- /dev/null +++ b/thirdparty/meshoptimizer/vcacheanalyzer.cpp @@ -0,0 +1,73 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <string.h> + +meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int primgroup_size) +{ + assert(index_count % 3 == 0); + assert(cache_size >= 3); + assert(warp_size == 0 || warp_size >= 3); + + meshopt_Allocator allocator; + + meshopt_VertexCacheStatistics result = {}; + + unsigned int warp_offset = 0; + unsigned int primgroup_offset = 0; + + unsigned int* cache_timestamps = allocator.allocate<unsigned int>(vertex_count); + memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int)); + + unsigned int timestamp = cache_size + 1; + + for (size_t i = 0; i < index_count; i += 3) + { + unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2]; + assert(a < vertex_count && b < vertex_count && c < vertex_count); + + bool ac = (timestamp - cache_timestamps[a]) > cache_size; + bool bc = (timestamp - cache_timestamps[b]) > cache_size; + bool cc = (timestamp - cache_timestamps[c]) > cache_size; + + // flush cache if triangle doesn't fit into warp or into the primitive buffer + if ((primgroup_size && primgroup_offset == primgroup_size) || (warp_size && warp_offset + ac + bc + cc > warp_size)) + { + result.warps_executed += warp_offset > 0; + + warp_offset = 0; + primgroup_offset = 0; + + // reset cache + timestamp += cache_size + 1; + } + + // update cache and add vertices to warp + for (int j = 0; j < 3; ++j) + { + unsigned int index = indices[i + j]; + + if (timestamp - cache_timestamps[index] > cache_size) + { + cache_timestamps[index] = timestamp++; + result.vertices_transformed++; + warp_offset++; + } + } + + primgroup_offset++; + } + + size_t unique_vertex_count = 0; + + for (size_t i = 0; i < vertex_count; ++i) + unique_vertex_count += cache_timestamps[i] > 0; + + result.warps_executed += warp_offset > 0; + + result.acmr = index_count == 0 ? 0 : float(result.vertices_transformed) / float(index_count / 3); + result.atvr = unique_vertex_count == 0 ? 0 : float(result.vertices_transformed) / float(unique_vertex_count); + + return result; +} diff --git a/thirdparty/meshoptimizer/vcacheoptimizer.cpp b/thirdparty/meshoptimizer/vcacheoptimizer.cpp new file mode 100644 index 0000000000..fb8ade4b77 --- /dev/null +++ b/thirdparty/meshoptimizer/vcacheoptimizer.cpp @@ -0,0 +1,473 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <string.h> + +// This work is based on: +// Tom Forsyth. Linear-Speed Vertex Cache Optimisation. 2006 +// Pedro Sander, Diego Nehab and Joshua Barczak. Fast Triangle Reordering for Vertex Locality and Reduced Overdraw. 2007 +namespace meshopt +{ + +const size_t kCacheSizeMax = 16; +const size_t kValenceMax = 8; + +struct VertexScoreTable +{ + float cache[1 + kCacheSizeMax]; + float live[1 + kValenceMax]; +}; + +// Tuned to minimize the ACMR of a GPU that has a cache profile similar to NVidia and AMD +static const VertexScoreTable kVertexScoreTable = { + {0.f, 0.779f, 0.791f, 0.789f, 0.981f, 0.843f, 0.726f, 0.847f, 0.882f, 0.867f, 0.799f, 0.642f, 0.613f, 0.600f, 0.568f, 0.372f, 0.234f}, + {0.f, 0.995f, 0.713f, 0.450f, 0.404f, 0.059f, 0.005f, 0.147f, 0.006f}, +}; + +// Tuned to minimize the encoded index buffer size +static const VertexScoreTable kVertexScoreTableStrip = { + {0.f, 1.000f, 1.000f, 1.000f, 0.453f, 0.561f, 0.490f, 0.459f, 0.179f, 0.526f, 0.000f, 0.227f, 0.184f, 0.490f, 0.112f, 0.050f, 0.131f}, + {0.f, 0.956f, 0.786f, 0.577f, 0.558f, 0.618f, 0.549f, 0.499f, 0.489f}, +}; + +struct TriangleAdjacency +{ + unsigned int* counts; + unsigned int* offsets; + unsigned int* data; +}; + +static void buildTriangleAdjacency(TriangleAdjacency& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count, meshopt_Allocator& allocator) +{ + size_t face_count = index_count / 3; + + // allocate arrays + adjacency.counts = allocator.allocate<unsigned int>(vertex_count); + adjacency.offsets = allocator.allocate<unsigned int>(vertex_count); + adjacency.data = allocator.allocate<unsigned int>(index_count); + + // fill triangle counts + memset(adjacency.counts, 0, vertex_count * sizeof(unsigned int)); + + for (size_t i = 0; i < index_count; ++i) + { + assert(indices[i] < vertex_count); + + adjacency.counts[indices[i]]++; + } + + // fill offset table + unsigned int offset = 0; + + for (size_t i = 0; i < vertex_count; ++i) + { + adjacency.offsets[i] = offset; + offset += adjacency.counts[i]; + } + + assert(offset == index_count); + + // fill triangle data + for (size_t i = 0; i < face_count; ++i) + { + unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2]; + + adjacency.data[adjacency.offsets[a]++] = unsigned(i); + adjacency.data[adjacency.offsets[b]++] = unsigned(i); + adjacency.data[adjacency.offsets[c]++] = unsigned(i); + } + + // fix offsets that have been disturbed by the previous pass + for (size_t i = 0; i < vertex_count; ++i) + { + assert(adjacency.offsets[i] >= adjacency.counts[i]); + + adjacency.offsets[i] -= adjacency.counts[i]; + } +} + +static unsigned int getNextVertexDeadEnd(const unsigned int* dead_end, unsigned int& dead_end_top, unsigned int& input_cursor, const unsigned int* live_triangles, size_t vertex_count) +{ + // check dead-end stack + while (dead_end_top) + { + unsigned int vertex = dead_end[--dead_end_top]; + + if (live_triangles[vertex] > 0) + return vertex; + } + + // input order + while (input_cursor < vertex_count) + { + if (live_triangles[input_cursor] > 0) + return input_cursor; + + ++input_cursor; + } + + return ~0u; +} + +static unsigned int getNextVertexNeighbour(const unsigned int* next_candidates_begin, const unsigned int* next_candidates_end, const unsigned int* live_triangles, const unsigned int* cache_timestamps, unsigned int timestamp, unsigned int cache_size) +{ + unsigned int best_candidate = ~0u; + int best_priority = -1; + + for (const unsigned int* next_candidate = next_candidates_begin; next_candidate != next_candidates_end; ++next_candidate) + { + unsigned int vertex = *next_candidate; + + // otherwise we don't need to process it + if (live_triangles[vertex] > 0) + { + int priority = 0; + + // will it be in cache after fanning? + if (2 * live_triangles[vertex] + timestamp - cache_timestamps[vertex] <= cache_size) + { + priority = timestamp - cache_timestamps[vertex]; // position in cache + } + + if (priority > best_priority) + { + best_candidate = vertex; + best_priority = priority; + } + } + } + + return best_candidate; +} + +static float vertexScore(const VertexScoreTable* table, int cache_position, unsigned int live_triangles) +{ + assert(cache_position >= -1 && cache_position < int(kCacheSizeMax)); + + unsigned int live_triangles_clamped = live_triangles < kValenceMax ? live_triangles : kValenceMax; + + return table->cache[1 + cache_position] + table->live[live_triangles_clamped]; +} + +static unsigned int getNextTriangleDeadEnd(unsigned int& input_cursor, const unsigned char* emitted_flags, size_t face_count) +{ + // input order + while (input_cursor < face_count) + { + if (!emitted_flags[input_cursor]) + return input_cursor; + + ++input_cursor; + } + + return ~0u; +} + +} // namespace meshopt + +void meshopt_optimizeVertexCacheTable(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const meshopt::VertexScoreTable* table) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + + meshopt_Allocator allocator; + + // guard for empty meshes + if (index_count == 0 || vertex_count == 0) + return; + + // support in-place optimization + if (destination == indices) + { + unsigned int* indices_copy = allocator.allocate<unsigned int>(index_count); + memcpy(indices_copy, indices, index_count * sizeof(unsigned int)); + indices = indices_copy; + } + + unsigned int cache_size = 16; + assert(cache_size <= kCacheSizeMax); + + size_t face_count = index_count / 3; + + // build adjacency information + TriangleAdjacency adjacency = {}; + buildTriangleAdjacency(adjacency, indices, index_count, vertex_count, allocator); + + // live triangle counts + unsigned int* live_triangles = allocator.allocate<unsigned int>(vertex_count); + memcpy(live_triangles, adjacency.counts, vertex_count * sizeof(unsigned int)); + + // emitted flags + unsigned char* emitted_flags = allocator.allocate<unsigned char>(face_count); + memset(emitted_flags, 0, face_count); + + // compute initial vertex scores + float* vertex_scores = allocator.allocate<float>(vertex_count); + + for (size_t i = 0; i < vertex_count; ++i) + vertex_scores[i] = vertexScore(table, -1, live_triangles[i]); + + // compute triangle scores + float* triangle_scores = allocator.allocate<float>(face_count); + + for (size_t i = 0; i < face_count; ++i) + { + unsigned int a = indices[i * 3 + 0]; + unsigned int b = indices[i * 3 + 1]; + unsigned int c = indices[i * 3 + 2]; + + triangle_scores[i] = vertex_scores[a] + vertex_scores[b] + vertex_scores[c]; + } + + unsigned int cache_holder[2 * (kCacheSizeMax + 3)]; + unsigned int* cache = cache_holder; + unsigned int* cache_new = cache_holder + kCacheSizeMax + 3; + size_t cache_count = 0; + + unsigned int current_triangle = 0; + unsigned int input_cursor = 1; + + unsigned int output_triangle = 0; + + while (current_triangle != ~0u) + { + assert(output_triangle < face_count); + + unsigned int a = indices[current_triangle * 3 + 0]; + unsigned int b = indices[current_triangle * 3 + 1]; + unsigned int c = indices[current_triangle * 3 + 2]; + + // output indices + destination[output_triangle * 3 + 0] = a; + destination[output_triangle * 3 + 1] = b; + destination[output_triangle * 3 + 2] = c; + output_triangle++; + + // update emitted flags + emitted_flags[current_triangle] = true; + triangle_scores[current_triangle] = 0; + + // new triangle + size_t cache_write = 0; + cache_new[cache_write++] = a; + cache_new[cache_write++] = b; + cache_new[cache_write++] = c; + + // old triangles + for (size_t i = 0; i < cache_count; ++i) + { + unsigned int index = cache[i]; + + if (index != a && index != b && index != c) + { + cache_new[cache_write++] = index; + } + } + + unsigned int* cache_temp = cache; + cache = cache_new, cache_new = cache_temp; + cache_count = cache_write > cache_size ? cache_size : cache_write; + + // update live triangle counts + live_triangles[a]--; + live_triangles[b]--; + live_triangles[c]--; + + // remove emitted triangle from adjacency data + // this makes sure that we spend less time traversing these lists on subsequent iterations + for (size_t k = 0; k < 3; ++k) + { + unsigned int index = indices[current_triangle * 3 + k]; + + unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index]; + size_t neighbours_size = adjacency.counts[index]; + + for (size_t i = 0; i < neighbours_size; ++i) + { + unsigned int tri = neighbours[i]; + + if (tri == current_triangle) + { + neighbours[i] = neighbours[neighbours_size - 1]; + adjacency.counts[index]--; + break; + } + } + } + + unsigned int best_triangle = ~0u; + float best_score = 0; + + // update cache positions, vertex scores and triangle scores, and find next best triangle + for (size_t i = 0; i < cache_write; ++i) + { + unsigned int index = cache[i]; + + int cache_position = i >= cache_size ? -1 : int(i); + + // update vertex score + float score = vertexScore(table, cache_position, live_triangles[index]); + float score_diff = score - vertex_scores[index]; + + vertex_scores[index] = score; + + // update scores of vertex triangles + const unsigned int* neighbours_begin = &adjacency.data[0] + adjacency.offsets[index]; + const unsigned int* neighbours_end = neighbours_begin + adjacency.counts[index]; + + for (const unsigned int* it = neighbours_begin; it != neighbours_end; ++it) + { + unsigned int tri = *it; + assert(!emitted_flags[tri]); + + float tri_score = triangle_scores[tri] + score_diff; + assert(tri_score > 0); + + if (best_score < tri_score) + { + best_triangle = tri; + best_score = tri_score; + } + + triangle_scores[tri] = tri_score; + } + } + + // step through input triangles in order if we hit a dead-end + current_triangle = best_triangle; + + if (current_triangle == ~0u) + { + current_triangle = getNextTriangleDeadEnd(input_cursor, &emitted_flags[0], face_count); + } + } + + assert(input_cursor == face_count); + assert(output_triangle == face_count); +} + +void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count) +{ + meshopt_optimizeVertexCacheTable(destination, indices, index_count, vertex_count, &meshopt::kVertexScoreTable); +} + +void meshopt_optimizeVertexCacheStrip(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count) +{ + meshopt_optimizeVertexCacheTable(destination, indices, index_count, vertex_count, &meshopt::kVertexScoreTableStrip); +} + +void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size) +{ + using namespace meshopt; + + assert(index_count % 3 == 0); + assert(cache_size >= 3); + + meshopt_Allocator allocator; + + // guard for empty meshes + if (index_count == 0 || vertex_count == 0) + return; + + // support in-place optimization + if (destination == indices) + { + unsigned int* indices_copy = allocator.allocate<unsigned int>(index_count); + memcpy(indices_copy, indices, index_count * sizeof(unsigned int)); + indices = indices_copy; + } + + size_t face_count = index_count / 3; + + // build adjacency information + TriangleAdjacency adjacency = {}; + buildTriangleAdjacency(adjacency, indices, index_count, vertex_count, allocator); + + // live triangle counts + unsigned int* live_triangles = allocator.allocate<unsigned int>(vertex_count); + memcpy(live_triangles, adjacency.counts, vertex_count * sizeof(unsigned int)); + + // cache time stamps + unsigned int* cache_timestamps = allocator.allocate<unsigned int>(vertex_count); + memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int)); + + // dead-end stack + unsigned int* dead_end = allocator.allocate<unsigned int>(index_count); + unsigned int dead_end_top = 0; + + // emitted flags + unsigned char* emitted_flags = allocator.allocate<unsigned char>(face_count); + memset(emitted_flags, 0, face_count); + + unsigned int current_vertex = 0; + + unsigned int timestamp = cache_size + 1; + unsigned int input_cursor = 1; // vertex to restart from in case of dead-end + + unsigned int output_triangle = 0; + + while (current_vertex != ~0u) + { + const unsigned int* next_candidates_begin = &dead_end[0] + dead_end_top; + + // emit all vertex neighbours + const unsigned int* neighbours_begin = &adjacency.data[0] + adjacency.offsets[current_vertex]; + const unsigned int* neighbours_end = neighbours_begin + adjacency.counts[current_vertex]; + + for (const unsigned int* it = neighbours_begin; it != neighbours_end; ++it) + { + unsigned int triangle = *it; + + if (!emitted_flags[triangle]) + { + unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2]; + + // output indices + destination[output_triangle * 3 + 0] = a; + destination[output_triangle * 3 + 1] = b; + destination[output_triangle * 3 + 2] = c; + output_triangle++; + + // update dead-end stack + dead_end[dead_end_top + 0] = a; + dead_end[dead_end_top + 1] = b; + dead_end[dead_end_top + 2] = c; + dead_end_top += 3; + + // update live triangle counts + live_triangles[a]--; + live_triangles[b]--; + live_triangles[c]--; + + // update cache info + // if vertex is not in cache, put it in cache + if (timestamp - cache_timestamps[a] > cache_size) + cache_timestamps[a] = timestamp++; + + if (timestamp - cache_timestamps[b] > cache_size) + cache_timestamps[b] = timestamp++; + + if (timestamp - cache_timestamps[c] > cache_size) + cache_timestamps[c] = timestamp++; + + // update emitted flags + emitted_flags[triangle] = true; + } + } + + // next candidates are the ones we pushed to dead-end stack just now + const unsigned int* next_candidates_end = &dead_end[0] + dead_end_top; + + // get next vertex + current_vertex = getNextVertexNeighbour(next_candidates_begin, next_candidates_end, &live_triangles[0], &cache_timestamps[0], timestamp, cache_size); + + if (current_vertex == ~0u) + { + current_vertex = getNextVertexDeadEnd(&dead_end[0], dead_end_top, input_cursor, &live_triangles[0], vertex_count); + } + } + + assert(output_triangle == face_count); +} diff --git a/thirdparty/meshoptimizer/vertexcodec.cpp b/thirdparty/meshoptimizer/vertexcodec.cpp new file mode 100644 index 0000000000..784c9a13db --- /dev/null +++ b/thirdparty/meshoptimizer/vertexcodec.cpp @@ -0,0 +1,1265 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <string.h> + +// The block below auto-detects SIMD ISA that can be used on the target platform +#ifndef MESHOPTIMIZER_NO_SIMD + +// The SIMD implementation requires SSSE3, which can be enabled unconditionally through compiler settings +#if defined(__AVX__) || defined(__SSSE3__) +#define SIMD_SSE +#endif + +// An experimental implementation using AVX512 instructions; it's only enabled when AVX512 is enabled through compiler settings +#if defined(__AVX512VBMI2__) && defined(__AVX512VBMI__) && defined(__AVX512VL__) && defined(__POPCNT__) +#undef SIMD_SSE +#define SIMD_AVX +#endif + +// MSVC supports compiling SSSE3 code regardless of compile options; we use a cpuid-based scalar fallback +#if !defined(SIMD_SSE) && !defined(SIMD_AVX) && defined(_MSC_VER) && !defined(__clang__) && (defined(_M_IX86) || defined(_M_X64)) +#define SIMD_SSE +#define SIMD_FALLBACK +#endif + +// GCC 4.9+ and clang 3.8+ support targeting SIMD ISA from individual functions; we use a cpuid-based scalar fallback +#if !defined(SIMD_SSE) && !defined(SIMD_AVX) && ((defined(__clang__) && __clang_major__ * 100 + __clang_minor__ >= 308) || (defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 409)) && (defined(__i386__) || defined(__x86_64__)) +#define SIMD_SSE +#define SIMD_FALLBACK +#define SIMD_TARGET __attribute__((target("ssse3"))) +#endif + +// GCC/clang define these when NEON support is available +#if defined(__ARM_NEON__) || defined(__ARM_NEON) +#define SIMD_NEON +#endif + +// On MSVC, we assume that ARM builds always target NEON-capable devices +#if !defined(SIMD_NEON) && defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) +#define SIMD_NEON +#endif + +// When targeting Wasm SIMD we can't use runtime cpuid checks so we unconditionally enable SIMD +#if defined(__wasm_simd128__) +#define SIMD_WASM +#endif + +#ifndef SIMD_TARGET +#define SIMD_TARGET +#endif + +#endif // !MESHOPTIMIZER_NO_SIMD + +#ifdef SIMD_SSE +#include <tmmintrin.h> +#endif + +#if defined(SIMD_SSE) && defined(SIMD_FALLBACK) +#ifdef _MSC_VER +#include <intrin.h> // __cpuid +#else +#include <cpuid.h> // __cpuid +#endif +#endif + +#ifdef SIMD_AVX +#include <immintrin.h> +#endif + +#ifdef SIMD_NEON +#if defined(_MSC_VER) && defined(_M_ARM64) +#include <arm64_neon.h> +#else +#include <arm_neon.h> +#endif +#endif + +#ifdef SIMD_WASM +#include <wasm_simd128.h> +#endif + +#ifndef TRACE +#define TRACE 0 +#endif + +#if TRACE +#include <stdio.h> +#endif + +#ifdef SIMD_WASM +#define wasmx_splat_v32x4(v, i) wasm_v32x4_shuffle(v, v, i, i, i, i) +#define wasmx_unpacklo_v8x16(a, b) wasm_v8x16_shuffle(a, b, 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23) +#define wasmx_unpackhi_v8x16(a, b) wasm_v8x16_shuffle(a, b, 8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31) +#define wasmx_unpacklo_v16x8(a, b) wasm_v16x8_shuffle(a, b, 0, 8, 1, 9, 2, 10, 3, 11) +#define wasmx_unpackhi_v16x8(a, b) wasm_v16x8_shuffle(a, b, 4, 12, 5, 13, 6, 14, 7, 15) +#define wasmx_unpacklo_v64x2(a, b) wasm_v64x2_shuffle(a, b, 0, 2) +#define wasmx_unpackhi_v64x2(a, b) wasm_v64x2_shuffle(a, b, 1, 3) +#endif + +namespace meshopt +{ + +const unsigned char kVertexHeader = 0xa0; + +static int gEncodeVertexVersion = 0; + +const size_t kVertexBlockSizeBytes = 8192; +const size_t kVertexBlockMaxSize = 256; +const size_t kByteGroupSize = 16; +const size_t kByteGroupDecodeLimit = 24; +const size_t kTailMaxSize = 32; + +static size_t getVertexBlockSize(size_t vertex_size) +{ + // make sure the entire block fits into the scratch buffer + size_t result = kVertexBlockSizeBytes / vertex_size; + + // align to byte group size; we encode each byte as a byte group + // if vertex block is misaligned, it results in wasted bytes, so just truncate the block size + result &= ~(kByteGroupSize - 1); + + return (result < kVertexBlockMaxSize) ? result : kVertexBlockMaxSize; +} + +inline unsigned char zigzag8(unsigned char v) +{ + return ((signed char)(v) >> 7) ^ (v << 1); +} + +inline unsigned char unzigzag8(unsigned char v) +{ + return -(v & 1) ^ (v >> 1); +} + +#if TRACE +struct Stats +{ + size_t size; + size_t header; + size_t bitg[4]; + size_t bitb[4]; +}; + +Stats* bytestats; +Stats vertexstats[256]; +#endif + +static bool encodeBytesGroupZero(const unsigned char* buffer) +{ + for (size_t i = 0; i < kByteGroupSize; ++i) + if (buffer[i]) + return false; + + return true; +} + +static size_t encodeBytesGroupMeasure(const unsigned char* buffer, int bits) +{ + assert(bits >= 1 && bits <= 8); + + if (bits == 1) + return encodeBytesGroupZero(buffer) ? 0 : size_t(-1); + + if (bits == 8) + return kByteGroupSize; + + size_t result = kByteGroupSize * bits / 8; + + unsigned char sentinel = (1 << bits) - 1; + + for (size_t i = 0; i < kByteGroupSize; ++i) + result += buffer[i] >= sentinel; + + return result; +} + +static unsigned char* encodeBytesGroup(unsigned char* data, const unsigned char* buffer, int bits) +{ + assert(bits >= 1 && bits <= 8); + + if (bits == 1) + return data; + + if (bits == 8) + { + memcpy(data, buffer, kByteGroupSize); + return data + kByteGroupSize; + } + + size_t byte_size = 8 / bits; + assert(kByteGroupSize % byte_size == 0); + + // fixed portion: bits bits for each value + // variable portion: full byte for each out-of-range value (using 1...1 as sentinel) + unsigned char sentinel = (1 << bits) - 1; + + for (size_t i = 0; i < kByteGroupSize; i += byte_size) + { + unsigned char byte = 0; + + for (size_t k = 0; k < byte_size; ++k) + { + unsigned char enc = (buffer[i + k] >= sentinel) ? sentinel : buffer[i + k]; + + byte <<= bits; + byte |= enc; + } + + *data++ = byte; + } + + for (size_t i = 0; i < kByteGroupSize; ++i) + { + if (buffer[i] >= sentinel) + { + *data++ = buffer[i]; + } + } + + return data; +} + +static unsigned char* encodeBytes(unsigned char* data, unsigned char* data_end, const unsigned char* buffer, size_t buffer_size) +{ + assert(buffer_size % kByteGroupSize == 0); + + unsigned char* header = data; + + // round number of groups to 4 to get number of header bytes + size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; + + if (size_t(data_end - data) < header_size) + return 0; + + data += header_size; + + memset(header, 0, header_size); + + for (size_t i = 0; i < buffer_size; i += kByteGroupSize) + { + if (size_t(data_end - data) < kByteGroupDecodeLimit) + return 0; + + int best_bits = 8; + size_t best_size = encodeBytesGroupMeasure(buffer + i, 8); + + for (int bits = 1; bits < 8; bits *= 2) + { + size_t size = encodeBytesGroupMeasure(buffer + i, bits); + + if (size < best_size) + { + best_bits = bits; + best_size = size; + } + } + + int bitslog2 = (best_bits == 1) ? 0 : (best_bits == 2) ? 1 : (best_bits == 4) ? 2 : 3; + assert((1 << bitslog2) == best_bits); + + size_t header_offset = i / kByteGroupSize; + + header[header_offset / 4] |= bitslog2 << ((header_offset % 4) * 2); + + unsigned char* next = encodeBytesGroup(data, buffer + i, best_bits); + + assert(data + best_size == next); + data = next; + +#if TRACE > 1 + bytestats->bitg[bitslog2]++; + bytestats->bitb[bitslog2] += best_size; +#endif + } + +#if TRACE > 1 + bytestats->header += header_size; +#endif + + return data; +} + +static unsigned char* encodeVertexBlock(unsigned char* data, unsigned char* data_end, const unsigned char* vertex_data, size_t vertex_count, size_t vertex_size, unsigned char last_vertex[256]) +{ + assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize); + + unsigned char buffer[kVertexBlockMaxSize]; + assert(sizeof(buffer) % kByteGroupSize == 0); + + // we sometimes encode elements we didn't fill when rounding to kByteGroupSize + memset(buffer, 0, sizeof(buffer)); + + for (size_t k = 0; k < vertex_size; ++k) + { + size_t vertex_offset = k; + + unsigned char p = last_vertex[k]; + + for (size_t i = 0; i < vertex_count; ++i) + { + buffer[i] = zigzag8(vertex_data[vertex_offset] - p); + + p = vertex_data[vertex_offset]; + + vertex_offset += vertex_size; + } + +#if TRACE + const unsigned char* olddata = data; + bytestats = &vertexstats[k]; +#endif + + data = encodeBytes(data, data_end, buffer, (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1)); + if (!data) + return 0; + +#if TRACE + bytestats = 0; + vertexstats[k].size += data - olddata; +#endif + } + + memcpy(last_vertex, &vertex_data[vertex_size * (vertex_count - 1)], vertex_size); + + return data; +} + +#if defined(SIMD_FALLBACK) || (!defined(SIMD_SSE) && !defined(SIMD_NEON) && !defined(SIMD_AVX)) +static const unsigned char* decodeBytesGroup(const unsigned char* data, unsigned char* buffer, int bitslog2) +{ +#define READ() byte = *data++ +#define NEXT(bits) enc = byte >> (8 - bits), byte <<= bits, encv = *data_var, *buffer++ = (enc == (1 << bits) - 1) ? encv : enc, data_var += (enc == (1 << bits) - 1) + + unsigned char byte, enc, encv; + const unsigned char* data_var; + + switch (bitslog2) + { + case 0: + memset(buffer, 0, kByteGroupSize); + return data; + case 1: + data_var = data + 4; + + // 4 groups with 4 2-bit values in each byte + READ(), NEXT(2), NEXT(2), NEXT(2), NEXT(2); + READ(), NEXT(2), NEXT(2), NEXT(2), NEXT(2); + READ(), NEXT(2), NEXT(2), NEXT(2), NEXT(2); + READ(), NEXT(2), NEXT(2), NEXT(2), NEXT(2); + + return data_var; + case 2: + data_var = data + 8; + + // 8 groups with 2 4-bit values in each byte + READ(), NEXT(4), NEXT(4); + READ(), NEXT(4), NEXT(4); + READ(), NEXT(4), NEXT(4); + READ(), NEXT(4), NEXT(4); + READ(), NEXT(4), NEXT(4); + READ(), NEXT(4), NEXT(4); + READ(), NEXT(4), NEXT(4); + READ(), NEXT(4), NEXT(4); + + return data_var; + case 3: + memcpy(buffer, data, kByteGroupSize); + return data + kByteGroupSize; + default: + assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value + return data; + } + +#undef READ +#undef NEXT +} + +static const unsigned char* decodeBytes(const unsigned char* data, const unsigned char* data_end, unsigned char* buffer, size_t buffer_size) +{ + assert(buffer_size % kByteGroupSize == 0); + + const unsigned char* header = data; + + // round number of groups to 4 to get number of header bytes + size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; + + if (size_t(data_end - data) < header_size) + return 0; + + data += header_size; + + for (size_t i = 0; i < buffer_size; i += kByteGroupSize) + { + if (size_t(data_end - data) < kByteGroupDecodeLimit) + return 0; + + size_t header_offset = i / kByteGroupSize; + + int bitslog2 = (header[header_offset / 4] >> ((header_offset % 4) * 2)) & 3; + + data = decodeBytesGroup(data, buffer + i, bitslog2); + } + + return data; +} + +static const unsigned char* decodeVertexBlock(const unsigned char* data, const unsigned char* data_end, unsigned char* vertex_data, size_t vertex_count, size_t vertex_size, unsigned char last_vertex[256]) +{ + assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize); + + unsigned char buffer[kVertexBlockMaxSize]; + unsigned char transposed[kVertexBlockSizeBytes]; + + size_t vertex_count_aligned = (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1); + + for (size_t k = 0; k < vertex_size; ++k) + { + data = decodeBytes(data, data_end, buffer, vertex_count_aligned); + if (!data) + return 0; + + size_t vertex_offset = k; + + unsigned char p = last_vertex[k]; + + for (size_t i = 0; i < vertex_count; ++i) + { + unsigned char v = unzigzag8(buffer[i]) + p; + + transposed[vertex_offset] = v; + p = v; + + vertex_offset += vertex_size; + } + } + + memcpy(vertex_data, transposed, vertex_count * vertex_size); + + memcpy(last_vertex, &transposed[vertex_size * (vertex_count - 1)], vertex_size); + + return data; +} +#endif + +#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) +static unsigned char kDecodeBytesGroupShuffle[256][8]; +static unsigned char kDecodeBytesGroupCount[256]; + +#ifdef __wasm__ +__attribute__((cold)) // this saves 500 bytes in the output binary - we don't need to vectorize this loop! +#endif +static bool +decodeBytesGroupBuildTables() +{ + for (int mask = 0; mask < 256; ++mask) + { + unsigned char shuffle[8]; + unsigned char count = 0; + + for (int i = 0; i < 8; ++i) + { + int maski = (mask >> i) & 1; + shuffle[i] = maski ? count : 0x80; + count += (unsigned char)(maski); + } + + memcpy(kDecodeBytesGroupShuffle[mask], shuffle, 8); + kDecodeBytesGroupCount[mask] = count; + } + + return true; +} + +static bool gDecodeBytesGroupInitialized = decodeBytesGroupBuildTables(); +#endif + +#ifdef SIMD_SSE +SIMD_TARGET +static __m128i decodeShuffleMask(unsigned char mask0, unsigned char mask1) +{ + __m128i sm0 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&kDecodeBytesGroupShuffle[mask0])); + __m128i sm1 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&kDecodeBytesGroupShuffle[mask1])); + __m128i sm1off = _mm_set1_epi8(kDecodeBytesGroupCount[mask0]); + + __m128i sm1r = _mm_add_epi8(sm1, sm1off); + + return _mm_unpacklo_epi64(sm0, sm1r); +} + +SIMD_TARGET +static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2) +{ + switch (bitslog2) + { + case 0: + { + __m128i result = _mm_setzero_si128(); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); + + return data; + } + + case 1: + { +#ifdef __GNUC__ + typedef int __attribute__((aligned(1))) unaligned_int; +#else + typedef int unaligned_int; +#endif + + __m128i sel2 = _mm_cvtsi32_si128(*reinterpret_cast<const unaligned_int*>(data)); + __m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data + 4)); + + __m128i sel22 = _mm_unpacklo_epi8(_mm_srli_epi16(sel2, 4), sel2); + __m128i sel2222 = _mm_unpacklo_epi8(_mm_srli_epi16(sel22, 2), sel22); + __m128i sel = _mm_and_si128(sel2222, _mm_set1_epi8(3)); + + __m128i mask = _mm_cmpeq_epi8(sel, _mm_set1_epi8(3)); + int mask16 = _mm_movemask_epi8(mask); + unsigned char mask0 = (unsigned char)(mask16 & 255); + unsigned char mask1 = (unsigned char)(mask16 >> 8); + + __m128i shuf = decodeShuffleMask(mask0, mask1); + + __m128i result = _mm_or_si128(_mm_shuffle_epi8(rest, shuf), _mm_andnot_si128(mask, sel)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); + + return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1]; + } + + case 2: + { + __m128i sel4 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(data)); + __m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data + 8)); + + __m128i sel44 = _mm_unpacklo_epi8(_mm_srli_epi16(sel4, 4), sel4); + __m128i sel = _mm_and_si128(sel44, _mm_set1_epi8(15)); + + __m128i mask = _mm_cmpeq_epi8(sel, _mm_set1_epi8(15)); + int mask16 = _mm_movemask_epi8(mask); + unsigned char mask0 = (unsigned char)(mask16 & 255); + unsigned char mask1 = (unsigned char)(mask16 >> 8); + + __m128i shuf = decodeShuffleMask(mask0, mask1); + + __m128i result = _mm_or_si128(_mm_shuffle_epi8(rest, shuf), _mm_andnot_si128(mask, sel)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); + + return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1]; + } + + case 3: + { + __m128i result = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); + + return data + 16; + } + + default: + assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value + return data; + } +} +#endif + +#ifdef SIMD_AVX +static const __m128i decodeBytesGroupConfig[] = { + _mm_set1_epi8(3), + _mm_set1_epi8(15), + _mm_setr_epi8(6, 4, 2, 0, 14, 12, 10, 8, 22, 20, 18, 16, 30, 28, 26, 24), + _mm_setr_epi8(4, 0, 12, 8, 20, 16, 28, 24, 36, 32, 44, 40, 52, 48, 60, 56), +}; + +static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2) +{ + switch (bitslog2) + { + case 0: + { + __m128i result = _mm_setzero_si128(); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); + + return data; + } + + case 1: + case 2: + { + const unsigned char* skip = data + (bitslog2 << 2); + + __m128i selb = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(data)); + __m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(skip)); + + __m128i sent = decodeBytesGroupConfig[bitslog2 - 1]; + __m128i ctrl = decodeBytesGroupConfig[bitslog2 + 1]; + + __m128i selw = _mm_shuffle_epi32(selb, 0x44); + __m128i sel = _mm_and_si128(sent, _mm_multishift_epi64_epi8(ctrl, selw)); + __mmask16 mask16 = _mm_cmp_epi8_mask(sel, sent, _MM_CMPINT_EQ); + + __m128i result = _mm_mask_expand_epi8(sel, mask16, rest); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); + + return skip + _mm_popcnt_u32(mask16); + } + + case 3: + { + __m128i result = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result); + + return data + 16; + } + + default: + assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value + return data; + } +} +#endif + +#ifdef SIMD_NEON +static uint8x16_t shuffleBytes(unsigned char mask0, unsigned char mask1, uint8x8_t rest0, uint8x8_t rest1) +{ + uint8x8_t sm0 = vld1_u8(kDecodeBytesGroupShuffle[mask0]); + uint8x8_t sm1 = vld1_u8(kDecodeBytesGroupShuffle[mask1]); + + uint8x8_t r0 = vtbl1_u8(rest0, sm0); + uint8x8_t r1 = vtbl1_u8(rest1, sm1); + + return vcombine_u8(r0, r1); +} + +static void neonMoveMask(uint8x16_t mask, unsigned char& mask0, unsigned char& mask1) +{ + static const unsigned char byte_mask_data[16] = {1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128}; + + uint8x16_t byte_mask = vld1q_u8(byte_mask_data); + uint8x16_t masked = vandq_u8(mask, byte_mask); + +#ifdef __aarch64__ + // aarch64 has horizontal sums; MSVC doesn't expose this via arm64_neon.h so this path is exclusive to clang/gcc + mask0 = vaddv_u8(vget_low_u8(masked)); + mask1 = vaddv_u8(vget_high_u8(masked)); +#else + // we need horizontal sums of each half of masked, which can be done in 3 steps (yielding sums of sizes 2, 4, 8) + uint8x8_t sum1 = vpadd_u8(vget_low_u8(masked), vget_high_u8(masked)); + uint8x8_t sum2 = vpadd_u8(sum1, sum1); + uint8x8_t sum3 = vpadd_u8(sum2, sum2); + + mask0 = vget_lane_u8(sum3, 0); + mask1 = vget_lane_u8(sum3, 1); +#endif +} + +static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2) +{ + switch (bitslog2) + { + case 0: + { + uint8x16_t result = vdupq_n_u8(0); + + vst1q_u8(buffer, result); + + return data; + } + + case 1: + { + uint8x8_t sel2 = vld1_u8(data); + uint8x8_t sel22 = vzip_u8(vshr_n_u8(sel2, 4), sel2).val[0]; + uint8x8x2_t sel2222 = vzip_u8(vshr_n_u8(sel22, 2), sel22); + uint8x16_t sel = vandq_u8(vcombine_u8(sel2222.val[0], sel2222.val[1]), vdupq_n_u8(3)); + + uint8x16_t mask = vceqq_u8(sel, vdupq_n_u8(3)); + unsigned char mask0, mask1; + neonMoveMask(mask, mask0, mask1); + + uint8x8_t rest0 = vld1_u8(data + 4); + uint8x8_t rest1 = vld1_u8(data + 4 + kDecodeBytesGroupCount[mask0]); + + uint8x16_t result = vbslq_u8(mask, shuffleBytes(mask0, mask1, rest0, rest1), sel); + + vst1q_u8(buffer, result); + + return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1]; + } + + case 2: + { + uint8x8_t sel4 = vld1_u8(data); + uint8x8x2_t sel44 = vzip_u8(vshr_n_u8(sel4, 4), vand_u8(sel4, vdup_n_u8(15))); + uint8x16_t sel = vcombine_u8(sel44.val[0], sel44.val[1]); + + uint8x16_t mask = vceqq_u8(sel, vdupq_n_u8(15)); + unsigned char mask0, mask1; + neonMoveMask(mask, mask0, mask1); + + uint8x8_t rest0 = vld1_u8(data + 8); + uint8x8_t rest1 = vld1_u8(data + 8 + kDecodeBytesGroupCount[mask0]); + + uint8x16_t result = vbslq_u8(mask, shuffleBytes(mask0, mask1, rest0, rest1), sel); + + vst1q_u8(buffer, result); + + return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1]; + } + + case 3: + { + uint8x16_t result = vld1q_u8(data); + + vst1q_u8(buffer, result); + + return data + 16; + } + + default: + assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value + return data; + } +} +#endif + +#ifdef SIMD_WASM +SIMD_TARGET +static v128_t decodeShuffleMask(unsigned char mask0, unsigned char mask1) +{ + v128_t sm0 = wasm_v128_load(&kDecodeBytesGroupShuffle[mask0]); + v128_t sm1 = wasm_v128_load(&kDecodeBytesGroupShuffle[mask1]); + + v128_t sm1off = wasm_v128_load(&kDecodeBytesGroupCount[mask0]); + sm1off = wasm_v8x16_shuffle(sm1off, sm1off, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + v128_t sm1r = wasm_i8x16_add(sm1, sm1off); + + return wasmx_unpacklo_v64x2(sm0, sm1r); +} + +SIMD_TARGET +static void wasmMoveMask(v128_t mask, unsigned char& mask0, unsigned char& mask1) +{ + v128_t mask_0 = wasm_v32x4_shuffle(mask, mask, 0, 2, 1, 3); + + uint64_t mask_1a = wasm_i64x2_extract_lane(mask_0, 0) & 0x0804020108040201ull; + uint64_t mask_1b = wasm_i64x2_extract_lane(mask_0, 1) & 0x8040201080402010ull; + + // TODO: This can use v8x16_bitmask in the future + uint64_t mask_2 = mask_1a | mask_1b; + uint64_t mask_4 = mask_2 | (mask_2 >> 16); + uint64_t mask_8 = mask_4 | (mask_4 >> 8); + + mask0 = uint8_t(mask_8); + mask1 = uint8_t(mask_8 >> 32); +} + +SIMD_TARGET +static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2) +{ + unsigned char byte, enc, encv; + const unsigned char* data_var; + + switch (bitslog2) + { + case 0: + { + v128_t result = wasm_i8x16_splat(0); + + wasm_v128_store(buffer, result); + + return data; + } + + case 1: + { + v128_t sel2 = wasm_v128_load(data); + v128_t rest = wasm_v128_load(data + 4); + + v128_t sel22 = wasmx_unpacklo_v8x16(wasm_i16x8_shr(sel2, 4), sel2); + v128_t sel2222 = wasmx_unpacklo_v8x16(wasm_i16x8_shr(sel22, 2), sel22); + v128_t sel = wasm_v128_and(sel2222, wasm_i8x16_splat(3)); + + v128_t mask = wasm_i8x16_eq(sel, wasm_i8x16_splat(3)); + + unsigned char mask0, mask1; + wasmMoveMask(mask, mask0, mask1); + + v128_t shuf = decodeShuffleMask(mask0, mask1); + + v128_t result = wasm_v128_bitselect(wasm_v8x16_swizzle(rest, shuf), sel, mask); + + wasm_v128_store(buffer, result); + + return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1]; + } + + case 2: + { + v128_t sel4 = wasm_v128_load(data); + v128_t rest = wasm_v128_load(data + 8); + + v128_t sel44 = wasmx_unpacklo_v8x16(wasm_i16x8_shr(sel4, 4), sel4); + v128_t sel = wasm_v128_and(sel44, wasm_i8x16_splat(15)); + + v128_t mask = wasm_i8x16_eq(sel, wasm_i8x16_splat(15)); + + unsigned char mask0, mask1; + wasmMoveMask(mask, mask0, mask1); + + v128_t shuf = decodeShuffleMask(mask0, mask1); + + v128_t result = wasm_v128_bitselect(wasm_v8x16_swizzle(rest, shuf), sel, mask); + + wasm_v128_store(buffer, result); + + return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1]; + } + + case 3: + { + v128_t result = wasm_v128_load(data); + + wasm_v128_store(buffer, result); + + return data + 16; + } + + default: + assert(!"Unexpected bit length"); // unreachable since bitslog2 is a 2-bit value + return data; + } +} +#endif + +#if defined(SIMD_SSE) || defined(SIMD_AVX) +SIMD_TARGET +static void transpose8(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3) +{ + __m128i t0 = _mm_unpacklo_epi8(x0, x1); + __m128i t1 = _mm_unpackhi_epi8(x0, x1); + __m128i t2 = _mm_unpacklo_epi8(x2, x3); + __m128i t3 = _mm_unpackhi_epi8(x2, x3); + + x0 = _mm_unpacklo_epi16(t0, t2); + x1 = _mm_unpackhi_epi16(t0, t2); + x2 = _mm_unpacklo_epi16(t1, t3); + x3 = _mm_unpackhi_epi16(t1, t3); +} + +SIMD_TARGET +static __m128i unzigzag8(__m128i v) +{ + __m128i xl = _mm_sub_epi8(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi8(1))); + __m128i xr = _mm_and_si128(_mm_srli_epi16(v, 1), _mm_set1_epi8(127)); + + return _mm_xor_si128(xl, xr); +} +#endif + +#ifdef SIMD_NEON +static void transpose8(uint8x16_t& x0, uint8x16_t& x1, uint8x16_t& x2, uint8x16_t& x3) +{ + uint8x16x2_t t01 = vzipq_u8(x0, x1); + uint8x16x2_t t23 = vzipq_u8(x2, x3); + + uint16x8x2_t x01 = vzipq_u16(vreinterpretq_u16_u8(t01.val[0]), vreinterpretq_u16_u8(t23.val[0])); + uint16x8x2_t x23 = vzipq_u16(vreinterpretq_u16_u8(t01.val[1]), vreinterpretq_u16_u8(t23.val[1])); + + x0 = vreinterpretq_u8_u16(x01.val[0]); + x1 = vreinterpretq_u8_u16(x01.val[1]); + x2 = vreinterpretq_u8_u16(x23.val[0]); + x3 = vreinterpretq_u8_u16(x23.val[1]); +} + +static uint8x16_t unzigzag8(uint8x16_t v) +{ + uint8x16_t xl = vreinterpretq_u8_s8(vnegq_s8(vreinterpretq_s8_u8(vandq_u8(v, vdupq_n_u8(1))))); + uint8x16_t xr = vshrq_n_u8(v, 1); + + return veorq_u8(xl, xr); +} +#endif + +#ifdef SIMD_WASM +SIMD_TARGET +static void transpose8(v128_t& x0, v128_t& x1, v128_t& x2, v128_t& x3) +{ + v128_t t0 = wasmx_unpacklo_v8x16(x0, x1); + v128_t t1 = wasmx_unpackhi_v8x16(x0, x1); + v128_t t2 = wasmx_unpacklo_v8x16(x2, x3); + v128_t t3 = wasmx_unpackhi_v8x16(x2, x3); + + x0 = wasmx_unpacklo_v16x8(t0, t2); + x1 = wasmx_unpackhi_v16x8(t0, t2); + x2 = wasmx_unpacklo_v16x8(t1, t3); + x3 = wasmx_unpackhi_v16x8(t1, t3); +} + +SIMD_TARGET +static v128_t unzigzag8(v128_t v) +{ + v128_t xl = wasm_i8x16_neg(wasm_v128_and(v, wasm_i8x16_splat(1))); + v128_t xr = wasm_u8x16_shr(v, 1); + + return wasm_v128_xor(xl, xr); +} +#endif + +#if defined(SIMD_SSE) || defined(SIMD_AVX) || defined(SIMD_NEON) || defined(SIMD_WASM) +SIMD_TARGET +static const unsigned char* decodeBytesSimd(const unsigned char* data, const unsigned char* data_end, unsigned char* buffer, size_t buffer_size) +{ + assert(buffer_size % kByteGroupSize == 0); + assert(kByteGroupSize == 16); + + const unsigned char* header = data; + + // round number of groups to 4 to get number of header bytes + size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; + + if (size_t(data_end - data) < header_size) + return 0; + + data += header_size; + + size_t i = 0; + + // fast-path: process 4 groups at a time, do a shared bounds check - each group reads <=24b + for (; i + kByteGroupSize * 4 <= buffer_size && size_t(data_end - data) >= kByteGroupDecodeLimit * 4; i += kByteGroupSize * 4) + { + size_t header_offset = i / kByteGroupSize; + unsigned char header_byte = header[header_offset / 4]; + + data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 0, (header_byte >> 0) & 3); + data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 1, (header_byte >> 2) & 3); + data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 2, (header_byte >> 4) & 3); + data = decodeBytesGroupSimd(data, buffer + i + kByteGroupSize * 3, (header_byte >> 6) & 3); + } + + // slow-path: process remaining groups + for (; i < buffer_size; i += kByteGroupSize) + { + if (size_t(data_end - data) < kByteGroupDecodeLimit) + return 0; + + size_t header_offset = i / kByteGroupSize; + + int bitslog2 = (header[header_offset / 4] >> ((header_offset % 4) * 2)) & 3; + + data = decodeBytesGroupSimd(data, buffer + i, bitslog2); + } + + return data; +} + +SIMD_TARGET +static const unsigned char* decodeVertexBlockSimd(const unsigned char* data, const unsigned char* data_end, unsigned char* vertex_data, size_t vertex_count, size_t vertex_size, unsigned char last_vertex[256]) +{ + assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize); + + unsigned char buffer[kVertexBlockMaxSize * 4]; + unsigned char transposed[kVertexBlockSizeBytes]; + + size_t vertex_count_aligned = (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1); + + for (size_t k = 0; k < vertex_size; k += 4) + { + for (size_t j = 0; j < 4; ++j) + { + data = decodeBytesSimd(data, data_end, buffer + j * vertex_count_aligned, vertex_count_aligned); + if (!data) + return 0; + } + +#if defined(SIMD_SSE) || defined(SIMD_AVX) +#define TEMP __m128i +#define PREP() __m128i pi = _mm_cvtsi32_si128(*reinterpret_cast<const int*>(last_vertex + k)) +#define LOAD(i) __m128i r##i = _mm_loadu_si128(reinterpret_cast<const __m128i*>(buffer + j + i * vertex_count_aligned)) +#define GRP4(i) t0 = _mm_shuffle_epi32(r##i, 0), t1 = _mm_shuffle_epi32(r##i, 1), t2 = _mm_shuffle_epi32(r##i, 2), t3 = _mm_shuffle_epi32(r##i, 3) +#define FIXD(i) t##i = pi = _mm_add_epi8(pi, t##i) +#define SAVE(i) *reinterpret_cast<int*>(savep) = _mm_cvtsi128_si32(t##i), savep += vertex_size +#endif + +#ifdef SIMD_NEON +#define TEMP uint8x8_t +#define PREP() uint8x8_t pi = vreinterpret_u8_u32(vld1_lane_u32(reinterpret_cast<uint32_t*>(last_vertex + k), vdup_n_u32(0), 0)) +#define LOAD(i) uint8x16_t r##i = vld1q_u8(buffer + j + i * vertex_count_aligned) +#define GRP4(i) t0 = vget_low_u8(r##i), t1 = vreinterpret_u8_u32(vdup_lane_u32(vreinterpret_u32_u8(t0), 1)), t2 = vget_high_u8(r##i), t3 = vreinterpret_u8_u32(vdup_lane_u32(vreinterpret_u32_u8(t2), 1)) +#define FIXD(i) t##i = pi = vadd_u8(pi, t##i) +#define SAVE(i) vst1_lane_u32(reinterpret_cast<uint32_t*>(savep), vreinterpret_u32_u8(t##i), 0), savep += vertex_size +#endif + +#ifdef SIMD_WASM +#define TEMP v128_t +#define PREP() v128_t pi = wasm_v128_load(last_vertex + k) +#define LOAD(i) v128_t r##i = wasm_v128_load(buffer + j + i * vertex_count_aligned) +#define GRP4(i) t0 = wasmx_splat_v32x4(r##i, 0), t1 = wasmx_splat_v32x4(r##i, 1), t2 = wasmx_splat_v32x4(r##i, 2), t3 = wasmx_splat_v32x4(r##i, 3) +#define FIXD(i) t##i = pi = wasm_i8x16_add(pi, t##i) +#define SAVE(i) *reinterpret_cast<int*>(savep) = wasm_i32x4_extract_lane(t##i, 0), savep += vertex_size +#endif + + PREP(); + + unsigned char* savep = transposed + k; + + for (size_t j = 0; j < vertex_count_aligned; j += 16) + { + LOAD(0); + LOAD(1); + LOAD(2); + LOAD(3); + + r0 = unzigzag8(r0); + r1 = unzigzag8(r1); + r2 = unzigzag8(r2); + r3 = unzigzag8(r3); + + transpose8(r0, r1, r2, r3); + + TEMP t0, t1, t2, t3; + + GRP4(0); + FIXD(0), FIXD(1), FIXD(2), FIXD(3); + SAVE(0), SAVE(1), SAVE(2), SAVE(3); + + GRP4(1); + FIXD(0), FIXD(1), FIXD(2), FIXD(3); + SAVE(0), SAVE(1), SAVE(2), SAVE(3); + + GRP4(2); + FIXD(0), FIXD(1), FIXD(2), FIXD(3); + SAVE(0), SAVE(1), SAVE(2), SAVE(3); + + GRP4(3); + FIXD(0), FIXD(1), FIXD(2), FIXD(3); + SAVE(0), SAVE(1), SAVE(2), SAVE(3); + +#undef TEMP +#undef PREP +#undef LOAD +#undef GRP4 +#undef FIXD +#undef SAVE + } + } + + memcpy(vertex_data, transposed, vertex_count * vertex_size); + + memcpy(last_vertex, &transposed[vertex_size * (vertex_count - 1)], vertex_size); + + return data; +} +#endif + +#if defined(SIMD_SSE) && defined(SIMD_FALLBACK) +static unsigned int getCpuFeatures() +{ + int cpuinfo[4] = {}; +#ifdef _MSC_VER + __cpuid(cpuinfo, 1); +#else + __cpuid(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); +#endif + return cpuinfo[2]; +} + +unsigned int cpuid = getCpuFeatures(); +#endif + +} // namespace meshopt + +size_t meshopt_encodeVertexBuffer(unsigned char* buffer, size_t buffer_size, const void* vertices, size_t vertex_count, size_t vertex_size) +{ + using namespace meshopt; + + assert(vertex_size > 0 && vertex_size <= 256); + assert(vertex_size % 4 == 0); + +#if TRACE + memset(vertexstats, 0, sizeof(vertexstats)); +#endif + + const unsigned char* vertex_data = static_cast<const unsigned char*>(vertices); + + unsigned char* data = buffer; + unsigned char* data_end = buffer + buffer_size; + + if (size_t(data_end - data) < 1 + vertex_size) + return 0; + + int version = gEncodeVertexVersion; + + *data++ = (unsigned char)(kVertexHeader | version); + + unsigned char first_vertex[256] = {}; + if (vertex_count > 0) + memcpy(first_vertex, vertex_data, vertex_size); + + unsigned char last_vertex[256] = {}; + memcpy(last_vertex, first_vertex, vertex_size); + + size_t vertex_block_size = getVertexBlockSize(vertex_size); + + size_t vertex_offset = 0; + + while (vertex_offset < vertex_count) + { + size_t block_size = (vertex_offset + vertex_block_size < vertex_count) ? vertex_block_size : vertex_count - vertex_offset; + + data = encodeVertexBlock(data, data_end, vertex_data + vertex_offset * vertex_size, block_size, vertex_size, last_vertex); + if (!data) + return 0; + + vertex_offset += block_size; + } + + size_t tail_size = vertex_size < kTailMaxSize ? kTailMaxSize : vertex_size; + + if (size_t(data_end - data) < tail_size) + return 0; + + // write first vertex to the end of the stream and pad it to 32 bytes; this is important to simplify bounds checks in decoder + if (vertex_size < kTailMaxSize) + { + memset(data, 0, kTailMaxSize - vertex_size); + data += kTailMaxSize - vertex_size; + } + + memcpy(data, first_vertex, vertex_size); + data += vertex_size; + + assert(data >= buffer + tail_size); + assert(data <= buffer + buffer_size); + +#if TRACE + size_t total_size = data - buffer; + + for (size_t k = 0; k < vertex_size; ++k) + { + const Stats& vsk = vertexstats[k]; + + printf("%2d: %d bytes\t%.1f%%\t%.1f bpv", int(k), int(vsk.size), double(vsk.size) / double(total_size) * 100, double(vsk.size) / double(vertex_count) * 8); + +#if TRACE > 1 + printf("\t\thdr %d bytes\tbit0 %d (%d bytes)\tbit1 %d (%d bytes)\tbit2 %d (%d bytes)\tbit3 %d (%d bytes)", + int(vsk.header), + int(vsk.bitg[0]), int(vsk.bitb[0]), + int(vsk.bitg[1]), int(vsk.bitb[1]), + int(vsk.bitg[2]), int(vsk.bitb[2]), + int(vsk.bitg[3]), int(vsk.bitb[3])); +#endif + + printf("\n"); + } +#endif + + return data - buffer; +} + +size_t meshopt_encodeVertexBufferBound(size_t vertex_count, size_t vertex_size) +{ + using namespace meshopt; + + assert(vertex_size > 0 && vertex_size <= 256); + assert(vertex_size % 4 == 0); + + size_t vertex_block_size = getVertexBlockSize(vertex_size); + size_t vertex_block_count = (vertex_count + vertex_block_size - 1) / vertex_block_size; + + size_t vertex_block_header_size = (vertex_block_size / kByteGroupSize + 3) / 4; + size_t vertex_block_data_size = vertex_block_size; + + size_t tail_size = vertex_size < kTailMaxSize ? kTailMaxSize : vertex_size; + + return 1 + vertex_block_count * vertex_size * (vertex_block_header_size + vertex_block_data_size) + tail_size; +} + +void meshopt_encodeVertexVersion(int version) +{ + assert(unsigned(version) <= 0); + + meshopt::gEncodeVertexVersion = version; +} + +int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t vertex_size, const unsigned char* buffer, size_t buffer_size) +{ + using namespace meshopt; + + assert(vertex_size > 0 && vertex_size <= 256); + assert(vertex_size % 4 == 0); + + const unsigned char* (*decode)(const unsigned char*, const unsigned char*, unsigned char*, size_t, size_t, unsigned char[256]) = 0; + +#if defined(SIMD_SSE) && defined(SIMD_FALLBACK) + decode = (cpuid & (1 << 9)) ? decodeVertexBlockSimd : decodeVertexBlock; +#elif defined(SIMD_SSE) || defined(SIMD_AVX) || defined(SIMD_NEON) || defined(SIMD_WASM) + decode = decodeVertexBlockSimd; +#else + decode = decodeVertexBlock; +#endif + +#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) + assert(gDecodeBytesGroupInitialized); + (void)gDecodeBytesGroupInitialized; +#endif + + unsigned char* vertex_data = static_cast<unsigned char*>(destination); + + const unsigned char* data = buffer; + const unsigned char* data_end = buffer + buffer_size; + + if (size_t(data_end - data) < 1 + vertex_size) + return -2; + + unsigned char data_header = *data++; + + if ((data_header & 0xf0) != kVertexHeader) + return -1; + + int version = data_header & 0x0f; + if (version > 0) + return -1; + + unsigned char last_vertex[256]; + memcpy(last_vertex, data_end - vertex_size, vertex_size); + + size_t vertex_block_size = getVertexBlockSize(vertex_size); + + size_t vertex_offset = 0; + + while (vertex_offset < vertex_count) + { + size_t block_size = (vertex_offset + vertex_block_size < vertex_count) ? vertex_block_size : vertex_count - vertex_offset; + + data = decode(data, data_end, vertex_data + vertex_offset * vertex_size, block_size, vertex_size, last_vertex); + if (!data) + return -2; + + vertex_offset += block_size; + } + + size_t tail_size = vertex_size < kTailMaxSize ? kTailMaxSize : vertex_size; + + if (size_t(data_end - data) != tail_size) + return -3; + + return 0; +} + +#undef SIMD_NEON +#undef SIMD_SSE +#undef SIMD_AVX +#undef SIMD_WASM +#undef SIMD_FALLBACK +#undef SIMD_TARGET diff --git a/thirdparty/meshoptimizer/vertexfilter.cpp b/thirdparty/meshoptimizer/vertexfilter.cpp new file mode 100644 index 0000000000..e7ad2c9d39 --- /dev/null +++ b/thirdparty/meshoptimizer/vertexfilter.cpp @@ -0,0 +1,825 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <math.h> + +// The block below auto-detects SIMD ISA that can be used on the target platform +#ifndef MESHOPTIMIZER_NO_SIMD + +// The SIMD implementation requires SSE2, which can be enabled unconditionally through compiler settings +#if defined(__SSE2__) +#define SIMD_SSE +#endif + +// MSVC supports compiling SSE2 code regardless of compile options; we assume all 32-bit CPUs support SSE2 +#if !defined(SIMD_SSE) && defined(_MSC_VER) && !defined(__clang__) && (defined(_M_IX86) || defined(_M_X64)) +#define SIMD_SSE +#endif + +// GCC/clang define these when NEON support is available +#if defined(__ARM_NEON__) || defined(__ARM_NEON) +#define SIMD_NEON +#endif + +// On MSVC, we assume that ARM builds always target NEON-capable devices +#if !defined(SIMD_NEON) && defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) +#define SIMD_NEON +#endif + +// When targeting Wasm SIMD we can't use runtime cpuid checks so we unconditionally enable SIMD +#if defined(__wasm_simd128__) +#define SIMD_WASM +#endif + +#endif // !MESHOPTIMIZER_NO_SIMD + +#ifdef SIMD_SSE +#include <emmintrin.h> +#include <stdint.h> +#endif + +#ifdef _MSC_VER +#include <intrin.h> +#endif + +#ifdef SIMD_NEON +#if defined(_MSC_VER) && defined(_M_ARM64) +#include <arm64_neon.h> +#else +#include <arm_neon.h> +#endif +#endif + +#ifdef SIMD_WASM +#include <wasm_simd128.h> +#endif + +#ifdef SIMD_WASM +#define wasmx_unpacklo_v16x8(a, b) wasm_v16x8_shuffle(a, b, 0, 8, 1, 9, 2, 10, 3, 11) +#define wasmx_unpackhi_v16x8(a, b) wasm_v16x8_shuffle(a, b, 4, 12, 5, 13, 6, 14, 7, 15) +#define wasmx_unziplo_v32x4(a, b) wasm_v32x4_shuffle(a, b, 0, 2, 4, 6) +#define wasmx_unziphi_v32x4(a, b) wasm_v32x4_shuffle(a, b, 1, 3, 5, 7) +#endif + +namespace meshopt +{ + +#if !defined(SIMD_SSE) && !defined(SIMD_NEON) && !defined(SIMD_WASM) +template <typename T> +static void decodeFilterOct(T* data, size_t count) +{ + const float max = float((1 << (sizeof(T) * 8 - 1)) - 1); + + for (size_t i = 0; i < count; ++i) + { + // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count + float x = float(data[i * 4 + 0]); + float y = float(data[i * 4 + 1]); + float z = float(data[i * 4 + 2]) - fabsf(x) - fabsf(y); + + // fixup octahedral coordinates for z<0 + float t = (z >= 0.f) ? 0.f : z; + + x += (x >= 0.f) ? t : -t; + y += (y >= 0.f) ? t : -t; + + // compute normal length & scale + float l = sqrtf(x * x + y * y + z * z); + float s = max / l; + + // rounded signed float->int + int xf = int(x * s + (x >= 0.f ? 0.5f : -0.5f)); + int yf = int(y * s + (y >= 0.f ? 0.5f : -0.5f)); + int zf = int(z * s + (z >= 0.f ? 0.5f : -0.5f)); + + data[i * 4 + 0] = T(xf); + data[i * 4 + 1] = T(yf); + data[i * 4 + 2] = T(zf); + } +} + +static void decodeFilterQuat(short* data, size_t count) +{ + const float scale = 1.f / sqrtf(2.f); + + for (size_t i = 0; i < count; ++i) + { + // recover scale from the high byte of the component + int sf = data[i * 4 + 3] | 3; + float ss = scale / float(sf); + + // convert x/y/z to [-1..1] (scaled...) + float x = float(data[i * 4 + 0]) * ss; + float y = float(data[i * 4 + 1]) * ss; + float z = float(data[i * 4 + 2]) * ss; + + // reconstruct w as a square root; we clamp to 0.f to avoid NaN due to precision errors + float ww = 1.f - x * x - y * y - z * z; + float w = sqrtf(ww >= 0.f ? ww : 0.f); + + // rounded signed float->int + int xf = int(x * 32767.f + (x >= 0.f ? 0.5f : -0.5f)); + int yf = int(y * 32767.f + (y >= 0.f ? 0.5f : -0.5f)); + int zf = int(z * 32767.f + (z >= 0.f ? 0.5f : -0.5f)); + int wf = int(w * 32767.f + 0.5f); + + int qc = data[i * 4 + 3] & 3; + + // output order is dictated by input index + data[i * 4 + ((qc + 1) & 3)] = short(xf); + data[i * 4 + ((qc + 2) & 3)] = short(yf); + data[i * 4 + ((qc + 3) & 3)] = short(zf); + data[i * 4 + ((qc + 0) & 3)] = short(wf); + } +} + +static void decodeFilterExp(unsigned int* data, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + unsigned int v = data[i]; + + // decode mantissa and exponent + int m = int(v << 8) >> 8; + int e = int(v) >> 24; + + union + { + float f; + unsigned int ui; + } u; + + // optimized version of ldexp(float(m), e) + u.ui = unsigned(e + 127) << 23; + u.f = u.f * float(m); + + data[i] = u.ui; + } +} +#endif + +#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) +inline uint64_t rotateleft64(uint64_t v, int x) +{ +#if defined(_MSC_VER) && !defined(__clang__) + return _rotl64(v, x); +// Apple's Clang 8 is actually vanilla Clang 3.9, there we need to look for +// version 11 instead: https://en.wikipedia.org/wiki/Xcode#Toolchain_versions +#elif defined(__clang__) && ((!defined(__apple_build_version__) && __clang_major__ >= 8) || __clang_major__ >= 11) + return __builtin_rotateleft64(v, x); +#else + return (v << (x & 63)) | (v >> ((64 - x) & 63)); +#endif +} +#endif + +#ifdef SIMD_SSE +static void decodeFilterOctSimd(signed char* data, size_t count) +{ + const __m128 sign = _mm_set1_ps(-0.f); + + for (size_t i = 0; i < count; i += 4) + { + __m128i n4 = _mm_loadu_si128(reinterpret_cast<__m128i*>(&data[i * 4])); + + // sign-extends each of x,y in [x y ? ?] with arithmetic shifts + __m128i xf = _mm_srai_epi32(_mm_slli_epi32(n4, 24), 24); + __m128i yf = _mm_srai_epi32(_mm_slli_epi32(n4, 16), 24); + + // unpack z; note that z is unsigned so we technically don't need to sign extend it + __m128i zf = _mm_srai_epi32(_mm_slli_epi32(n4, 8), 24); + + // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count + __m128 x = _mm_cvtepi32_ps(xf); + __m128 y = _mm_cvtepi32_ps(yf); + __m128 z = _mm_sub_ps(_mm_cvtepi32_ps(zf), _mm_add_ps(_mm_andnot_ps(sign, x), _mm_andnot_ps(sign, y))); + + // fixup octahedral coordinates for z<0 + __m128 t = _mm_min_ps(z, _mm_setzero_ps()); + + x = _mm_add_ps(x, _mm_xor_ps(t, _mm_and_ps(x, sign))); + y = _mm_add_ps(y, _mm_xor_ps(t, _mm_and_ps(y, sign))); + + // compute normal length & scale + __m128 ll = _mm_add_ps(_mm_mul_ps(x, x), _mm_add_ps(_mm_mul_ps(y, y), _mm_mul_ps(z, z))); + __m128 s = _mm_mul_ps(_mm_set1_ps(127.f), _mm_rsqrt_ps(ll)); + + // rounded signed float->int + __m128i xr = _mm_cvtps_epi32(_mm_mul_ps(x, s)); + __m128i yr = _mm_cvtps_epi32(_mm_mul_ps(y, s)); + __m128i zr = _mm_cvtps_epi32(_mm_mul_ps(z, s)); + + // combine xr/yr/zr into final value + __m128i res = _mm_and_si128(n4, _mm_set1_epi32(0xff000000)); + res = _mm_or_si128(res, _mm_and_si128(xr, _mm_set1_epi32(0xff))); + res = _mm_or_si128(res, _mm_slli_epi32(_mm_and_si128(yr, _mm_set1_epi32(0xff)), 8)); + res = _mm_or_si128(res, _mm_slli_epi32(_mm_and_si128(zr, _mm_set1_epi32(0xff)), 16)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(&data[i * 4]), res); + } +} + +static void decodeFilterOctSimd(short* data, size_t count) +{ + const __m128 sign = _mm_set1_ps(-0.f); + + for (size_t i = 0; i < count; i += 4) + { + __m128 n4_0 = _mm_loadu_ps(reinterpret_cast<float*>(&data[(i + 0) * 4])); + __m128 n4_1 = _mm_loadu_ps(reinterpret_cast<float*>(&data[(i + 2) * 4])); + + // gather both x/y 16-bit pairs in each 32-bit lane + __m128i n4 = _mm_castps_si128(_mm_shuffle_ps(n4_0, n4_1, _MM_SHUFFLE(2, 0, 2, 0))); + + // sign-extends each of x,y in [x y] with arithmetic shifts + __m128i xf = _mm_srai_epi32(_mm_slli_epi32(n4, 16), 16); + __m128i yf = _mm_srai_epi32(n4, 16); + + // unpack z; note that z is unsigned so we don't need to sign extend it + __m128i z4 = _mm_castps_si128(_mm_shuffle_ps(n4_0, n4_1, _MM_SHUFFLE(3, 1, 3, 1))); + __m128i zf = _mm_and_si128(z4, _mm_set1_epi32(0x7fff)); + + // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count + __m128 x = _mm_cvtepi32_ps(xf); + __m128 y = _mm_cvtepi32_ps(yf); + __m128 z = _mm_sub_ps(_mm_cvtepi32_ps(zf), _mm_add_ps(_mm_andnot_ps(sign, x), _mm_andnot_ps(sign, y))); + + // fixup octahedral coordinates for z<0 + __m128 t = _mm_min_ps(z, _mm_setzero_ps()); + + x = _mm_add_ps(x, _mm_xor_ps(t, _mm_and_ps(x, sign))); + y = _mm_add_ps(y, _mm_xor_ps(t, _mm_and_ps(y, sign))); + + // compute normal length & scale + __m128 ll = _mm_add_ps(_mm_mul_ps(x, x), _mm_add_ps(_mm_mul_ps(y, y), _mm_mul_ps(z, z))); + __m128 s = _mm_div_ps(_mm_set1_ps(32767.f), _mm_sqrt_ps(ll)); + + // rounded signed float->int + __m128i xr = _mm_cvtps_epi32(_mm_mul_ps(x, s)); + __m128i yr = _mm_cvtps_epi32(_mm_mul_ps(y, s)); + __m128i zr = _mm_cvtps_epi32(_mm_mul_ps(z, s)); + + // mix x/z and y/0 to make 16-bit unpack easier + __m128i xzr = _mm_or_si128(_mm_and_si128(xr, _mm_set1_epi32(0xffff)), _mm_slli_epi32(zr, 16)); + __m128i y0r = _mm_and_si128(yr, _mm_set1_epi32(0xffff)); + + // pack x/y/z using 16-bit unpacks; note that this has 0 where we should have .w + __m128i res_0 = _mm_unpacklo_epi16(xzr, y0r); + __m128i res_1 = _mm_unpackhi_epi16(xzr, y0r); + + // patch in .w + res_0 = _mm_or_si128(res_0, _mm_and_si128(_mm_castps_si128(n4_0), _mm_set1_epi64x(0xffff000000000000))); + res_1 = _mm_or_si128(res_1, _mm_and_si128(_mm_castps_si128(n4_1), _mm_set1_epi64x(0xffff000000000000))); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(&data[(i + 0) * 4]), res_0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(&data[(i + 2) * 4]), res_1); + } +} + +static void decodeFilterQuatSimd(short* data, size_t count) +{ + const float scale = 1.f / sqrtf(2.f); + + for (size_t i = 0; i < count; i += 4) + { + __m128 q4_0 = _mm_loadu_ps(reinterpret_cast<float*>(&data[(i + 0) * 4])); + __m128 q4_1 = _mm_loadu_ps(reinterpret_cast<float*>(&data[(i + 2) * 4])); + + // gather both x/y 16-bit pairs in each 32-bit lane + __m128i q4_xy = _mm_castps_si128(_mm_shuffle_ps(q4_0, q4_1, _MM_SHUFFLE(2, 0, 2, 0))); + __m128i q4_zc = _mm_castps_si128(_mm_shuffle_ps(q4_0, q4_1, _MM_SHUFFLE(3, 1, 3, 1))); + + // sign-extends each of x,y in [x y] with arithmetic shifts + __m128i xf = _mm_srai_epi32(_mm_slli_epi32(q4_xy, 16), 16); + __m128i yf = _mm_srai_epi32(q4_xy, 16); + __m128i zf = _mm_srai_epi32(_mm_slli_epi32(q4_zc, 16), 16); + __m128i cf = _mm_srai_epi32(q4_zc, 16); + + // get a floating-point scaler using zc with bottom 2 bits set to 1 (which represents 1.f) + __m128i sf = _mm_or_si128(cf, _mm_set1_epi32(3)); + __m128 ss = _mm_div_ps(_mm_set1_ps(scale), _mm_cvtepi32_ps(sf)); + + // convert x/y/z to [-1..1] (scaled...) + __m128 x = _mm_mul_ps(_mm_cvtepi32_ps(xf), ss); + __m128 y = _mm_mul_ps(_mm_cvtepi32_ps(yf), ss); + __m128 z = _mm_mul_ps(_mm_cvtepi32_ps(zf), ss); + + // reconstruct w as a square root; we clamp to 0.f to avoid NaN due to precision errors + __m128 ww = _mm_sub_ps(_mm_set1_ps(1.f), _mm_add_ps(_mm_mul_ps(x, x), _mm_add_ps(_mm_mul_ps(y, y), _mm_mul_ps(z, z)))); + __m128 w = _mm_sqrt_ps(_mm_max_ps(ww, _mm_setzero_ps())); + + __m128 s = _mm_set1_ps(32767.f); + + // rounded signed float->int + __m128i xr = _mm_cvtps_epi32(_mm_mul_ps(x, s)); + __m128i yr = _mm_cvtps_epi32(_mm_mul_ps(y, s)); + __m128i zr = _mm_cvtps_epi32(_mm_mul_ps(z, s)); + __m128i wr = _mm_cvtps_epi32(_mm_mul_ps(w, s)); + + // mix x/z and w/y to make 16-bit unpack easier + __m128i xzr = _mm_or_si128(_mm_and_si128(xr, _mm_set1_epi32(0xffff)), _mm_slli_epi32(zr, 16)); + __m128i wyr = _mm_or_si128(_mm_and_si128(wr, _mm_set1_epi32(0xffff)), _mm_slli_epi32(yr, 16)); + + // pack x/y/z/w using 16-bit unpacks; we pack wxyz by default (for qc=0) + __m128i res_0 = _mm_unpacklo_epi16(wyr, xzr); + __m128i res_1 = _mm_unpackhi_epi16(wyr, xzr); + + // store results to stack so that we can rotate using scalar instructions + uint64_t res[4]; + _mm_storeu_si128(reinterpret_cast<__m128i*>(&res[0]), res_0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(&res[2]), res_1); + + // rotate and store + uint64_t* out = reinterpret_cast<uint64_t*>(&data[i * 4]); + + out[0] = rotateleft64(res[0], data[(i + 0) * 4 + 3] << 4); + out[1] = rotateleft64(res[1], data[(i + 1) * 4 + 3] << 4); + out[2] = rotateleft64(res[2], data[(i + 2) * 4 + 3] << 4); + out[3] = rotateleft64(res[3], data[(i + 3) * 4 + 3] << 4); + } +} + +static void decodeFilterExpSimd(unsigned int* data, size_t count) +{ + for (size_t i = 0; i < count; i += 4) + { + __m128i v = _mm_loadu_si128(reinterpret_cast<__m128i*>(&data[i])); + + // decode exponent into 2^x directly + __m128i ef = _mm_srai_epi32(v, 24); + __m128i es = _mm_slli_epi32(_mm_add_epi32(ef, _mm_set1_epi32(127)), 23); + + // decode 24-bit mantissa into floating-point value + __m128i mf = _mm_srai_epi32(_mm_slli_epi32(v, 8), 8); + __m128 m = _mm_cvtepi32_ps(mf); + + __m128 r = _mm_mul_ps(_mm_castsi128_ps(es), m); + + _mm_storeu_ps(reinterpret_cast<float*>(&data[i]), r); + } +} +#endif + +#if defined(SIMD_NEON) && !defined(__aarch64__) && !defined(_M_ARM64) +inline float32x4_t vsqrtq_f32(float32x4_t x) +{ + float32x4_t r = vrsqrteq_f32(x); + r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(r, x), r)); // refine rsqrt estimate + return vmulq_f32(r, x); +} + +inline float32x4_t vdivq_f32(float32x4_t x, float32x4_t y) +{ + float32x4_t r = vrecpeq_f32(y); + r = vmulq_f32(r, vrecpsq_f32(y, r)); // refine rcp estimate + return vmulq_f32(x, r); +} +#endif + +#ifdef SIMD_NEON +static void decodeFilterOctSimd(signed char* data, size_t count) +{ + const int32x4_t sign = vdupq_n_s32(0x80000000); + + for (size_t i = 0; i < count; i += 4) + { + int32x4_t n4 = vld1q_s32(reinterpret_cast<int32_t*>(&data[i * 4])); + + // sign-extends each of x,y in [x y ? ?] with arithmetic shifts + int32x4_t xf = vshrq_n_s32(vshlq_n_s32(n4, 24), 24); + int32x4_t yf = vshrq_n_s32(vshlq_n_s32(n4, 16), 24); + + // unpack z; note that z is unsigned so we technically don't need to sign extend it + int32x4_t zf = vshrq_n_s32(vshlq_n_s32(n4, 8), 24); + + // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count + float32x4_t x = vcvtq_f32_s32(xf); + float32x4_t y = vcvtq_f32_s32(yf); + float32x4_t z = vsubq_f32(vcvtq_f32_s32(zf), vaddq_f32(vabsq_f32(x), vabsq_f32(y))); + + // fixup octahedral coordinates for z<0 + float32x4_t t = vminq_f32(z, vdupq_n_f32(0.f)); + + x = vaddq_f32(x, vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(t), vandq_s32(vreinterpretq_s32_f32(x), sign)))); + y = vaddq_f32(y, vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(t), vandq_s32(vreinterpretq_s32_f32(y), sign)))); + + // compute normal length & scale + float32x4_t ll = vaddq_f32(vmulq_f32(x, x), vaddq_f32(vmulq_f32(y, y), vmulq_f32(z, z))); + float32x4_t rl = vrsqrteq_f32(ll); + float32x4_t s = vmulq_f32(vdupq_n_f32(127.f), rl); + + // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value + // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction + const float32x4_t fsnap = vdupq_n_f32(3 << 22); + + int32x4_t xr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(x, s), fsnap)); + int32x4_t yr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(y, s), fsnap)); + int32x4_t zr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(z, s), fsnap)); + + // combine xr/yr/zr into final value + int32x4_t res = vandq_s32(n4, vdupq_n_s32(0xff000000)); + res = vorrq_s32(res, vandq_s32(xr, vdupq_n_s32(0xff))); + res = vorrq_s32(res, vshlq_n_s32(vandq_s32(yr, vdupq_n_s32(0xff)), 8)); + res = vorrq_s32(res, vshlq_n_s32(vandq_s32(zr, vdupq_n_s32(0xff)), 16)); + + vst1q_s32(reinterpret_cast<int32_t*>(&data[i * 4]), res); + } +} + +static void decodeFilterOctSimd(short* data, size_t count) +{ + const int32x4_t sign = vdupq_n_s32(0x80000000); + + for (size_t i = 0; i < count; i += 4) + { + int32x4_t n4_0 = vld1q_s32(reinterpret_cast<int32_t*>(&data[(i + 0) * 4])); + int32x4_t n4_1 = vld1q_s32(reinterpret_cast<int32_t*>(&data[(i + 2) * 4])); + + // gather both x/y 16-bit pairs in each 32-bit lane + int32x4_t n4 = vuzpq_s32(n4_0, n4_1).val[0]; + + // sign-extends each of x,y in [x y] with arithmetic shifts + int32x4_t xf = vshrq_n_s32(vshlq_n_s32(n4, 16), 16); + int32x4_t yf = vshrq_n_s32(n4, 16); + + // unpack z; note that z is unsigned so we don't need to sign extend it + int32x4_t z4 = vuzpq_s32(n4_0, n4_1).val[1]; + int32x4_t zf = vandq_s32(z4, vdupq_n_s32(0x7fff)); + + // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count + float32x4_t x = vcvtq_f32_s32(xf); + float32x4_t y = vcvtq_f32_s32(yf); + float32x4_t z = vsubq_f32(vcvtq_f32_s32(zf), vaddq_f32(vabsq_f32(x), vabsq_f32(y))); + + // fixup octahedral coordinates for z<0 + float32x4_t t = vminq_f32(z, vdupq_n_f32(0.f)); + + x = vaddq_f32(x, vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(t), vandq_s32(vreinterpretq_s32_f32(x), sign)))); + y = vaddq_f32(y, vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(t), vandq_s32(vreinterpretq_s32_f32(y), sign)))); + + // compute normal length & scale + float32x4_t ll = vaddq_f32(vmulq_f32(x, x), vaddq_f32(vmulq_f32(y, y), vmulq_f32(z, z))); + float32x4_t rl = vrsqrteq_f32(ll); + rl = vmulq_f32(rl, vrsqrtsq_f32(vmulq_f32(rl, ll), rl)); // refine rsqrt estimate + float32x4_t s = vmulq_f32(vdupq_n_f32(32767.f), rl); + + // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value + // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction + const float32x4_t fsnap = vdupq_n_f32(3 << 22); + + int32x4_t xr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(x, s), fsnap)); + int32x4_t yr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(y, s), fsnap)); + int32x4_t zr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(z, s), fsnap)); + + // mix x/z and y/0 to make 16-bit unpack easier + int32x4_t xzr = vorrq_s32(vandq_s32(xr, vdupq_n_s32(0xffff)), vshlq_n_s32(zr, 16)); + int32x4_t y0r = vandq_s32(yr, vdupq_n_s32(0xffff)); + + // pack x/y/z using 16-bit unpacks; note that this has 0 where we should have .w + int32x4_t res_0 = vreinterpretq_s32_s16(vzipq_s16(vreinterpretq_s16_s32(xzr), vreinterpretq_s16_s32(y0r)).val[0]); + int32x4_t res_1 = vreinterpretq_s32_s16(vzipq_s16(vreinterpretq_s16_s32(xzr), vreinterpretq_s16_s32(y0r)).val[1]); + + // patch in .w + res_0 = vbslq_s32(vreinterpretq_u32_u64(vdupq_n_u64(0xffff000000000000)), n4_0, res_0); + res_1 = vbslq_s32(vreinterpretq_u32_u64(vdupq_n_u64(0xffff000000000000)), n4_1, res_1); + + vst1q_s32(reinterpret_cast<int32_t*>(&data[(i + 0) * 4]), res_0); + vst1q_s32(reinterpret_cast<int32_t*>(&data[(i + 2) * 4]), res_1); + } +} + +static void decodeFilterQuatSimd(short* data, size_t count) +{ + const float scale = 1.f / sqrtf(2.f); + + for (size_t i = 0; i < count; i += 4) + { + int32x4_t q4_0 = vld1q_s32(reinterpret_cast<int32_t*>(&data[(i + 0) * 4])); + int32x4_t q4_1 = vld1q_s32(reinterpret_cast<int32_t*>(&data[(i + 2) * 4])); + + // gather both x/y 16-bit pairs in each 32-bit lane + int32x4_t q4_xy = vuzpq_s32(q4_0, q4_1).val[0]; + int32x4_t q4_zc = vuzpq_s32(q4_0, q4_1).val[1]; + + // sign-extends each of x,y in [x y] with arithmetic shifts + int32x4_t xf = vshrq_n_s32(vshlq_n_s32(q4_xy, 16), 16); + int32x4_t yf = vshrq_n_s32(q4_xy, 16); + int32x4_t zf = vshrq_n_s32(vshlq_n_s32(q4_zc, 16), 16); + int32x4_t cf = vshrq_n_s32(q4_zc, 16); + + // get a floating-point scaler using zc with bottom 2 bits set to 1 (which represents 1.f) + int32x4_t sf = vorrq_s32(cf, vdupq_n_s32(3)); + float32x4_t ss = vdivq_f32(vdupq_n_f32(scale), vcvtq_f32_s32(sf)); + + // convert x/y/z to [-1..1] (scaled...) + float32x4_t x = vmulq_f32(vcvtq_f32_s32(xf), ss); + float32x4_t y = vmulq_f32(vcvtq_f32_s32(yf), ss); + float32x4_t z = vmulq_f32(vcvtq_f32_s32(zf), ss); + + // reconstruct w as a square root; we clamp to 0.f to avoid NaN due to precision errors + float32x4_t ww = vsubq_f32(vdupq_n_f32(1.f), vaddq_f32(vmulq_f32(x, x), vaddq_f32(vmulq_f32(y, y), vmulq_f32(z, z)))); + float32x4_t w = vsqrtq_f32(vmaxq_f32(ww, vdupq_n_f32(0.f))); + + float32x4_t s = vdupq_n_f32(32767.f); + + // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value + // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction + const float32x4_t fsnap = vdupq_n_f32(3 << 22); + + int32x4_t xr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(x, s), fsnap)); + int32x4_t yr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(y, s), fsnap)); + int32x4_t zr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(z, s), fsnap)); + int32x4_t wr = vreinterpretq_s32_f32(vaddq_f32(vmulq_f32(w, s), fsnap)); + + // mix x/z and w/y to make 16-bit unpack easier + int32x4_t xzr = vorrq_s32(vandq_s32(xr, vdupq_n_s32(0xffff)), vshlq_n_s32(zr, 16)); + int32x4_t wyr = vorrq_s32(vandq_s32(wr, vdupq_n_s32(0xffff)), vshlq_n_s32(yr, 16)); + + // pack x/y/z/w using 16-bit unpacks; we pack wxyz by default (for qc=0) + int32x4_t res_0 = vreinterpretq_s32_s16(vzipq_s16(vreinterpretq_s16_s32(wyr), vreinterpretq_s16_s32(xzr)).val[0]); + int32x4_t res_1 = vreinterpretq_s32_s16(vzipq_s16(vreinterpretq_s16_s32(wyr), vreinterpretq_s16_s32(xzr)).val[1]); + + // rotate and store + uint64_t* out = (uint64_t*)&data[i * 4]; + + out[0] = rotateleft64(vgetq_lane_u64(vreinterpretq_u64_s32(res_0), 0), vgetq_lane_s32(cf, 0) << 4); + out[1] = rotateleft64(vgetq_lane_u64(vreinterpretq_u64_s32(res_0), 1), vgetq_lane_s32(cf, 1) << 4); + out[2] = rotateleft64(vgetq_lane_u64(vreinterpretq_u64_s32(res_1), 0), vgetq_lane_s32(cf, 2) << 4); + out[3] = rotateleft64(vgetq_lane_u64(vreinterpretq_u64_s32(res_1), 1), vgetq_lane_s32(cf, 3) << 4); + } +} + +static void decodeFilterExpSimd(unsigned int* data, size_t count) +{ + for (size_t i = 0; i < count; i += 4) + { + int32x4_t v = vld1q_s32(reinterpret_cast<int32_t*>(&data[i])); + + // decode exponent into 2^x directly + int32x4_t ef = vshrq_n_s32(v, 24); + int32x4_t es = vshlq_n_s32(vaddq_s32(ef, vdupq_n_s32(127)), 23); + + // decode 24-bit mantissa into floating-point value + int32x4_t mf = vshrq_n_s32(vshlq_n_s32(v, 8), 8); + float32x4_t m = vcvtq_f32_s32(mf); + + float32x4_t r = vmulq_f32(vreinterpretq_f32_s32(es), m); + + vst1q_f32(reinterpret_cast<float*>(&data[i]), r); + } +} +#endif + +#ifdef SIMD_WASM +static void decodeFilterOctSimd(signed char* data, size_t count) +{ + const v128_t sign = wasm_f32x4_splat(-0.f); + + for (size_t i = 0; i < count; i += 4) + { + v128_t n4 = wasm_v128_load(&data[i * 4]); + + // sign-extends each of x,y in [x y ? ?] with arithmetic shifts + v128_t xf = wasm_i32x4_shr(wasm_i32x4_shl(n4, 24), 24); + v128_t yf = wasm_i32x4_shr(wasm_i32x4_shl(n4, 16), 24); + + // unpack z; note that z is unsigned so we technically don't need to sign extend it + v128_t zf = wasm_i32x4_shr(wasm_i32x4_shl(n4, 8), 24); + + // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count + v128_t x = wasm_f32x4_convert_i32x4(xf); + v128_t y = wasm_f32x4_convert_i32x4(yf); + v128_t z = wasm_f32x4_sub(wasm_f32x4_convert_i32x4(zf), wasm_f32x4_add(wasm_f32x4_abs(x), wasm_f32x4_abs(y))); + + // fixup octahedral coordinates for z<0 + // note: i32x4_min with 0 is equvalent to f32x4_min + v128_t t = wasm_i32x4_min(z, wasm_i32x4_splat(0)); + + x = wasm_f32x4_add(x, wasm_v128_xor(t, wasm_v128_and(x, sign))); + y = wasm_f32x4_add(y, wasm_v128_xor(t, wasm_v128_and(y, sign))); + + // compute normal length & scale + v128_t ll = wasm_f32x4_add(wasm_f32x4_mul(x, x), wasm_f32x4_add(wasm_f32x4_mul(y, y), wasm_f32x4_mul(z, z))); + v128_t s = wasm_f32x4_div(wasm_f32x4_splat(127.f), wasm_f32x4_sqrt(ll)); + + // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value + // note: the result is offset by 0x4B40_0000, but we only need the low 8 bits so we can omit the subtraction + const v128_t fsnap = wasm_f32x4_splat(3 << 22); + + v128_t xr = wasm_f32x4_add(wasm_f32x4_mul(x, s), fsnap); + v128_t yr = wasm_f32x4_add(wasm_f32x4_mul(y, s), fsnap); + v128_t zr = wasm_f32x4_add(wasm_f32x4_mul(z, s), fsnap); + + // combine xr/yr/zr into final value + v128_t res = wasm_v128_and(n4, wasm_i32x4_splat(0xff000000)); + res = wasm_v128_or(res, wasm_v128_and(xr, wasm_i32x4_splat(0xff))); + res = wasm_v128_or(res, wasm_i32x4_shl(wasm_v128_and(yr, wasm_i32x4_splat(0xff)), 8)); + res = wasm_v128_or(res, wasm_i32x4_shl(wasm_v128_and(zr, wasm_i32x4_splat(0xff)), 16)); + + wasm_v128_store(&data[i * 4], res); + } +} + +static void decodeFilterOctSimd(short* data, size_t count) +{ + const v128_t sign = wasm_f32x4_splat(-0.f); + const v128_t zmask = wasm_i32x4_splat(0x7fff); + + for (size_t i = 0; i < count; i += 4) + { + v128_t n4_0 = wasm_v128_load(&data[(i + 0) * 4]); + v128_t n4_1 = wasm_v128_load(&data[(i + 2) * 4]); + + // gather both x/y 16-bit pairs in each 32-bit lane + v128_t n4 = wasmx_unziplo_v32x4(n4_0, n4_1); + + // sign-extends each of x,y in [x y] with arithmetic shifts + v128_t xf = wasm_i32x4_shr(wasm_i32x4_shl(n4, 16), 16); + v128_t yf = wasm_i32x4_shr(n4, 16); + + // unpack z; note that z is unsigned so we don't need to sign extend it + v128_t z4 = wasmx_unziphi_v32x4(n4_0, n4_1); + v128_t zf = wasm_v128_and(z4, zmask); + + // convert x and y to floats and reconstruct z; this assumes zf encodes 1.f at the same bit count + v128_t x = wasm_f32x4_convert_i32x4(xf); + v128_t y = wasm_f32x4_convert_i32x4(yf); + v128_t z = wasm_f32x4_sub(wasm_f32x4_convert_i32x4(zf), wasm_f32x4_add(wasm_f32x4_abs(x), wasm_f32x4_abs(y))); + + // fixup octahedral coordinates for z<0 + // note: i32x4_min with 0 is equvalent to f32x4_min + v128_t t = wasm_i32x4_min(z, wasm_i32x4_splat(0)); + + x = wasm_f32x4_add(x, wasm_v128_xor(t, wasm_v128_and(x, sign))); + y = wasm_f32x4_add(y, wasm_v128_xor(t, wasm_v128_and(y, sign))); + + // compute normal length & scale + v128_t ll = wasm_f32x4_add(wasm_f32x4_mul(x, x), wasm_f32x4_add(wasm_f32x4_mul(y, y), wasm_f32x4_mul(z, z))); + v128_t s = wasm_f32x4_div(wasm_f32x4_splat(32767.f), wasm_f32x4_sqrt(ll)); + + // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value + // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction + const v128_t fsnap = wasm_f32x4_splat(3 << 22); + + v128_t xr = wasm_f32x4_add(wasm_f32x4_mul(x, s), fsnap); + v128_t yr = wasm_f32x4_add(wasm_f32x4_mul(y, s), fsnap); + v128_t zr = wasm_f32x4_add(wasm_f32x4_mul(z, s), fsnap); + + // mix x/z and y/0 to make 16-bit unpack easier + v128_t xzr = wasm_v128_or(wasm_v128_and(xr, wasm_i32x4_splat(0xffff)), wasm_i32x4_shl(zr, 16)); + v128_t y0r = wasm_v128_and(yr, wasm_i32x4_splat(0xffff)); + + // pack x/y/z using 16-bit unpacks; note that this has 0 where we should have .w + v128_t res_0 = wasmx_unpacklo_v16x8(xzr, y0r); + v128_t res_1 = wasmx_unpackhi_v16x8(xzr, y0r); + + // patch in .w + res_0 = wasm_v128_or(res_0, wasm_v128_and(n4_0, wasm_i64x2_splat(0xffff000000000000))); + res_1 = wasm_v128_or(res_1, wasm_v128_and(n4_1, wasm_i64x2_splat(0xffff000000000000))); + + wasm_v128_store(&data[(i + 0) * 4], res_0); + wasm_v128_store(&data[(i + 2) * 4], res_1); + } +} + +static void decodeFilterQuatSimd(short* data, size_t count) +{ + const float scale = 1.f / sqrtf(2.f); + + for (size_t i = 0; i < count; i += 4) + { + v128_t q4_0 = wasm_v128_load(&data[(i + 0) * 4]); + v128_t q4_1 = wasm_v128_load(&data[(i + 2) * 4]); + + // gather both x/y 16-bit pairs in each 32-bit lane + v128_t q4_xy = wasmx_unziplo_v32x4(q4_0, q4_1); + v128_t q4_zc = wasmx_unziphi_v32x4(q4_0, q4_1); + + // sign-extends each of x,y in [x y] with arithmetic shifts + v128_t xf = wasm_i32x4_shr(wasm_i32x4_shl(q4_xy, 16), 16); + v128_t yf = wasm_i32x4_shr(q4_xy, 16); + v128_t zf = wasm_i32x4_shr(wasm_i32x4_shl(q4_zc, 16), 16); + v128_t cf = wasm_i32x4_shr(q4_zc, 16); + + // get a floating-point scaler using zc with bottom 2 bits set to 1 (which represents 1.f) + v128_t sf = wasm_v128_or(cf, wasm_i32x4_splat(3)); + v128_t ss = wasm_f32x4_div(wasm_f32x4_splat(scale), wasm_f32x4_convert_i32x4(sf)); + + // convert x/y/z to [-1..1] (scaled...) + v128_t x = wasm_f32x4_mul(wasm_f32x4_convert_i32x4(xf), ss); + v128_t y = wasm_f32x4_mul(wasm_f32x4_convert_i32x4(yf), ss); + v128_t z = wasm_f32x4_mul(wasm_f32x4_convert_i32x4(zf), ss); + + // reconstruct w as a square root; we clamp to 0.f to avoid NaN due to precision errors + // note: i32x4_max with 0 is equivalent to f32x4_max + v128_t ww = wasm_f32x4_sub(wasm_f32x4_splat(1.f), wasm_f32x4_add(wasm_f32x4_mul(x, x), wasm_f32x4_add(wasm_f32x4_mul(y, y), wasm_f32x4_mul(z, z)))); + v128_t w = wasm_f32x4_sqrt(wasm_i32x4_max(ww, wasm_i32x4_splat(0))); + + v128_t s = wasm_f32x4_splat(32767.f); + + // fast rounded signed float->int: addition triggers renormalization after which mantissa stores the integer value + // note: the result is offset by 0x4B40_0000, but we only need the low 16 bits so we can omit the subtraction + const v128_t fsnap = wasm_f32x4_splat(3 << 22); + + v128_t xr = wasm_f32x4_add(wasm_f32x4_mul(x, s), fsnap); + v128_t yr = wasm_f32x4_add(wasm_f32x4_mul(y, s), fsnap); + v128_t zr = wasm_f32x4_add(wasm_f32x4_mul(z, s), fsnap); + v128_t wr = wasm_f32x4_add(wasm_f32x4_mul(w, s), fsnap); + + // mix x/z and w/y to make 16-bit unpack easier + v128_t xzr = wasm_v128_or(wasm_v128_and(xr, wasm_i32x4_splat(0xffff)), wasm_i32x4_shl(zr, 16)); + v128_t wyr = wasm_v128_or(wasm_v128_and(wr, wasm_i32x4_splat(0xffff)), wasm_i32x4_shl(yr, 16)); + + // pack x/y/z/w using 16-bit unpacks; we pack wxyz by default (for qc=0) + v128_t res_0 = wasmx_unpacklo_v16x8(wyr, xzr); + v128_t res_1 = wasmx_unpackhi_v16x8(wyr, xzr); + + // compute component index shifted left by 4 (and moved into i32x4 slot) + // TODO: volatile here works around LLVM mis-optimizing code; https://github.com/emscripten-core/emscripten/issues/11449 + volatile v128_t cm = wasm_i32x4_shl(cf, 4); + + // rotate and store + uint64_t* out = reinterpret_cast<uint64_t*>(&data[i * 4]); + + out[0] = rotateleft64(wasm_i64x2_extract_lane(res_0, 0), wasm_i32x4_extract_lane(cm, 0)); + out[1] = rotateleft64(wasm_i64x2_extract_lane(res_0, 1), wasm_i32x4_extract_lane(cm, 1)); + out[2] = rotateleft64(wasm_i64x2_extract_lane(res_1, 0), wasm_i32x4_extract_lane(cm, 2)); + out[3] = rotateleft64(wasm_i64x2_extract_lane(res_1, 1), wasm_i32x4_extract_lane(cm, 3)); + } +} + +static void decodeFilterExpSimd(unsigned int* data, size_t count) +{ + for (size_t i = 0; i < count; i += 4) + { + v128_t v = wasm_v128_load(&data[i]); + + // decode exponent into 2^x directly + v128_t ef = wasm_i32x4_shr(v, 24); + v128_t es = wasm_i32x4_shl(wasm_i32x4_add(ef, wasm_i32x4_splat(127)), 23); + + // decode 24-bit mantissa into floating-point value + v128_t mf = wasm_i32x4_shr(wasm_i32x4_shl(v, 8), 8); + v128_t m = wasm_f32x4_convert_i32x4(mf); + + v128_t r = wasm_f32x4_mul(es, m); + + wasm_v128_store(&data[i], r); + } +} +#endif + +} // namespace meshopt + +void meshopt_decodeFilterOct(void* buffer, size_t vertex_count, size_t vertex_size) +{ + using namespace meshopt; + + assert(vertex_count % 4 == 0); + assert(vertex_size == 4 || vertex_size == 8); + +#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) + if (vertex_size == 4) + decodeFilterOctSimd(static_cast<signed char*>(buffer), vertex_count); + else + decodeFilterOctSimd(static_cast<short*>(buffer), vertex_count); +#else + if (vertex_size == 4) + decodeFilterOct(static_cast<signed char*>(buffer), vertex_count); + else + decodeFilterOct(static_cast<short*>(buffer), vertex_count); +#endif +} + +void meshopt_decodeFilterQuat(void* buffer, size_t vertex_count, size_t vertex_size) +{ + using namespace meshopt; + + assert(vertex_count % 4 == 0); + assert(vertex_size == 8); + (void)vertex_size; + +#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) + decodeFilterQuatSimd(static_cast<short*>(buffer), vertex_count); +#else + decodeFilterQuat(static_cast<short*>(buffer), vertex_count); +#endif +} + +void meshopt_decodeFilterExp(void* buffer, size_t vertex_count, size_t vertex_size) +{ + using namespace meshopt; + + assert(vertex_count % 4 == 0); + assert(vertex_size % 4 == 0); + +#if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) + decodeFilterExpSimd(static_cast<unsigned int*>(buffer), vertex_count * (vertex_size / 4)); +#else + decodeFilterExp(static_cast<unsigned int*>(buffer), vertex_count * (vertex_size / 4)); +#endif +} + +#undef SIMD_SSE +#undef SIMD_NEON +#undef SIMD_WASM diff --git a/thirdparty/meshoptimizer/vfetchanalyzer.cpp b/thirdparty/meshoptimizer/vfetchanalyzer.cpp new file mode 100644 index 0000000000..51dca873f8 --- /dev/null +++ b/thirdparty/meshoptimizer/vfetchanalyzer.cpp @@ -0,0 +1,58 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <string.h> + +meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* indices, size_t index_count, size_t vertex_count, size_t vertex_size) +{ + assert(index_count % 3 == 0); + assert(vertex_size > 0 && vertex_size <= 256); + + meshopt_Allocator allocator; + + meshopt_VertexFetchStatistics result = {}; + + unsigned char* vertex_visited = allocator.allocate<unsigned char>(vertex_count); + memset(vertex_visited, 0, vertex_count); + + const size_t kCacheLine = 64; + const size_t kCacheSize = 128 * 1024; + + // simple direct mapped cache; on typical mesh data this is close to 4-way cache, and this model is a gross approximation anyway + size_t cache[kCacheSize / kCacheLine] = {}; + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices[i]; + assert(index < vertex_count); + + vertex_visited[index] = 1; + + size_t start_address = index * vertex_size; + size_t end_address = start_address + vertex_size; + + size_t start_tag = start_address / kCacheLine; + size_t end_tag = (end_address + kCacheLine - 1) / kCacheLine; + + assert(start_tag < end_tag); + + for (size_t tag = start_tag; tag < end_tag; ++tag) + { + size_t line = tag % (sizeof(cache) / sizeof(cache[0])); + + // we store +1 since cache is filled with 0 by default + result.bytes_fetched += (cache[line] != tag + 1) * kCacheLine; + cache[line] = tag + 1; + } + } + + size_t unique_vertex_count = 0; + + for (size_t i = 0; i < vertex_count; ++i) + unique_vertex_count += vertex_visited[i]; + + result.overfetch = unique_vertex_count == 0 ? 0 : float(result.bytes_fetched) / float(unique_vertex_count * vertex_size); + + return result; +} diff --git a/thirdparty/meshoptimizer/vfetchoptimizer.cpp b/thirdparty/meshoptimizer/vfetchoptimizer.cpp new file mode 100644 index 0000000000..465d6df5ca --- /dev/null +++ b/thirdparty/meshoptimizer/vfetchoptimizer.cpp @@ -0,0 +1,74 @@ +// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details +#include "meshoptimizer.h" + +#include <assert.h> +#include <string.h> + +size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count) +{ + assert(index_count % 3 == 0); + + memset(destination, -1, vertex_count * sizeof(unsigned int)); + + unsigned int next_vertex = 0; + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices[i]; + assert(index < vertex_count); + + if (destination[index] == ~0u) + { + destination[index] = next_vertex++; + } + } + + assert(next_vertex <= vertex_count); + + return next_vertex; +} + +size_t meshopt_optimizeVertexFetch(void* destination, unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size) +{ + assert(index_count % 3 == 0); + assert(vertex_size > 0 && vertex_size <= 256); + + meshopt_Allocator allocator; + + // support in-place optimization + if (destination == vertices) + { + unsigned char* vertices_copy = allocator.allocate<unsigned char>(vertex_count * vertex_size); + memcpy(vertices_copy, vertices, vertex_count * vertex_size); + vertices = vertices_copy; + } + + // build vertex remap table + unsigned int* vertex_remap = allocator.allocate<unsigned int>(vertex_count); + memset(vertex_remap, -1, vertex_count * sizeof(unsigned int)); + + unsigned int next_vertex = 0; + + for (size_t i = 0; i < index_count; ++i) + { + unsigned int index = indices[i]; + assert(index < vertex_count); + + unsigned int& remap = vertex_remap[index]; + + if (remap == ~0u) // vertex was not added to destination VB + { + // add vertex + memcpy(static_cast<unsigned char*>(destination) + next_vertex * vertex_size, static_cast<const unsigned char*>(vertices) + index * vertex_size, vertex_size); + + remap = next_vertex++; + } + + // modify indices in place + indices[i] = remap; + } + + assert(next_vertex <= vertex_count); + + return next_vertex; +} diff --git a/thirdparty/minimp3/LICENSE b/thirdparty/minimp3/LICENSE new file mode 100644 index 0000000000..2c4afabdb6 --- /dev/null +++ b/thirdparty/minimp3/LICENSE @@ -0,0 +1,117 @@ +CC0 1.0 Universal + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later +claims of infringement build upon, modify, incorporate in other works, reuse +and redistribute as freely as possible in any form whatsoever and for any +purposes, including without limitation commercial purposes. These owners may +contribute to the Commons to promote the ideal of a free culture and the +further production of creative, cultural and scientific works, or to gain +reputation or greater distribution for their Work in part through the use and +efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with a +Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not limited +to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + + v. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time +extensions), (iii) in any current or future medium and for any number of +copies, and (iv) for any purpose whatsoever, including without limitation +commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes +the Waiver for the benefit of each member of the public at large and to the +detriment of Affirmer's heirs and successors, fully intending that such Waiver +shall not be subject to revocation, rescission, cancellation, termination, or +any other legal or equitable action to disrupt the quiet enjoyment of the Work +by the public as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account +Affirmer's express Statement of Purpose. In addition, to the extent the Waiver +is so judged Affirmer hereby grants to each affected person a royalty-free, +non transferable, non sublicensable, non exclusive, irrevocable and +unconditional license to exercise Affirmer's Copyright and Related Rights in +the Work (i) in all territories worldwide, (ii) for the maximum duration +provided by applicable law or treaty (including future time extensions), (iii) +in any current or future medium and for any number of copies, and (iv) for any +purpose whatsoever, including without limitation commercial, advertising or +promotional purposes (the "License"). The License shall be deemed effective as +of the date CC0 was applied by Affirmer to the Work. Should any part of the +License for any reason be judged legally invalid or ineffective under +applicable law, such partial invalidity or ineffectiveness shall not +invalidate the remainder of the License, and in such case Affirmer hereby +affirms that he or she will not (i) exercise any of his or her remaining +Copyright and Related Rights in the Work or (ii) assert any associated claims +and causes of action with respect to the Work, in either case contrary to +Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without limitation + any person's Copyright and Related Rights in the Work. Further, Affirmer + disclaims responsibility for obtaining any necessary consents, permissions + or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see +<http://creativecommons.org/publicdomain/zero/1.0/> + diff --git a/thirdparty/minimp3/minimp3.h b/thirdparty/minimp3/minimp3.h new file mode 100644 index 0000000000..796cbc1f8e --- /dev/null +++ b/thirdparty/minimp3/minimp3.h @@ -0,0 +1,1855 @@ +#ifndef MINIMP3_H +#define MINIMP3_H +/* + https://github.com/lieff/minimp3 + To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. + This software is distributed without any warranty. + See <http://creativecommons.org/publicdomain/zero/1.0/>. +*/ +#include <stdint.h> + +#define MINIMP3_MAX_SAMPLES_PER_FRAME (1152*2) + +typedef struct +{ + int frame_bytes, frame_offset, channels, hz, layer, bitrate_kbps; +} mp3dec_frame_info_t; + +typedef struct +{ + float mdct_overlap[2][9*32], qmf_state[15*2*32]; + int reserv, free_format_bytes; + unsigned char header[4], reserv_buf[511]; +} mp3dec_t; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void mp3dec_init(mp3dec_t *dec); +#ifndef MINIMP3_FLOAT_OUTPUT +typedef int16_t mp3d_sample_t; +#else /* MINIMP3_FLOAT_OUTPUT */ +typedef float mp3d_sample_t; +void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples); +#endif /* MINIMP3_FLOAT_OUTPUT */ +int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MINIMP3_H */ +#if defined(MINIMP3_IMPLEMENTATION) && !defined(_MINIMP3_IMPLEMENTATION_GUARD) +#define _MINIMP3_IMPLEMENTATION_GUARD + +#include <stdlib.h> +#include <string.h> + +#define MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */ +#ifndef MAX_FRAME_SYNC_MATCHES +#define MAX_FRAME_SYNC_MATCHES 10 +#endif /* MAX_FRAME_SYNC_MATCHES */ + +#define MAX_L3_FRAME_PAYLOAD_BYTES MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */ + +#define MAX_BITRESERVOIR_BYTES 511 +#define SHORT_BLOCK_TYPE 2 +#define STOP_BLOCK_TYPE 3 +#define MODE_MONO 3 +#define MODE_JOINT_STEREO 1 +#define HDR_SIZE 4 +#define HDR_IS_MONO(h) (((h[3]) & 0xC0) == 0xC0) +#define HDR_IS_MS_STEREO(h) (((h[3]) & 0xE0) == 0x60) +#define HDR_IS_FREE_FORMAT(h) (((h[2]) & 0xF0) == 0) +#define HDR_IS_CRC(h) (!((h[1]) & 1)) +#define HDR_TEST_PADDING(h) ((h[2]) & 0x2) +#define HDR_TEST_MPEG1(h) ((h[1]) & 0x8) +#define HDR_TEST_NOT_MPEG25(h) ((h[1]) & 0x10) +#define HDR_TEST_I_STEREO(h) ((h[3]) & 0x10) +#define HDR_TEST_MS_STEREO(h) ((h[3]) & 0x20) +#define HDR_GET_STEREO_MODE(h) (((h[3]) >> 6) & 3) +#define HDR_GET_STEREO_MODE_EXT(h) (((h[3]) >> 4) & 3) +#define HDR_GET_LAYER(h) (((h[1]) >> 1) & 3) +#define HDR_GET_BITRATE(h) ((h[2]) >> 4) +#define HDR_GET_SAMPLE_RATE(h) (((h[2]) >> 2) & 3) +#define HDR_GET_MY_SAMPLE_RATE(h) (HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3) +#define HDR_IS_FRAME_576(h) ((h[1] & 14) == 2) +#define HDR_IS_LAYER_1(h) ((h[1] & 6) == 6) + +#define BITS_DEQUANTIZER_OUT -1 +#define MAX_SCF (255 + BITS_DEQUANTIZER_OUT*4 - 210) +#define MAX_SCFI ((MAX_SCF + 3) & ~3) + +#define MINIMP3_MIN(a, b) ((a) > (b) ? (b) : (a)) +#define MINIMP3_MAX(a, b) ((a) < (b) ? (b) : (a)) + +#if !defined(MINIMP3_NO_SIMD) + +#if !defined(MINIMP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64)) +/* x64 always have SSE2, arm64 always have neon, no need for generic code */ +#define MINIMP3_ONLY_SIMD +#endif /* SIMD checks... */ + +#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) +#if defined(_MSC_VER) +#include <intrin.h> +#endif /* defined(_MSC_VER) */ +#include <immintrin.h> +#define HAVE_SSE 1 +#define HAVE_SIMD 1 +#define VSTORE _mm_storeu_ps +#define VLD _mm_loadu_ps +#define VSET _mm_set1_ps +#define VADD _mm_add_ps +#define VSUB _mm_sub_ps +#define VMUL _mm_mul_ps +#define VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y)) +#define VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y)) +#define VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s)) +#define VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3)) +typedef __m128 f4; +#if defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) +#define minimp3_cpuid __cpuid +#else /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ +static __inline__ __attribute__((always_inline)) void minimp3_cpuid(int CPUInfo[], const int InfoType) +{ +#if defined(__PIC__) + __asm__ __volatile__( +#if defined(__x86_64__) + "push %%rbx\n" + "cpuid\n" + "xchgl %%ebx, %1\n" + "pop %%rbx\n" +#else /* defined(__x86_64__) */ + "xchgl %%ebx, %1\n" + "cpuid\n" + "xchgl %%ebx, %1\n" +#endif /* defined(__x86_64__) */ + : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#else /* defined(__PIC__) */ + __asm__ __volatile__( + "cpuid" + : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#endif /* defined(__PIC__)*/ +} +#endif /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ +static int have_simd(void) +{ +#ifdef MINIMP3_ONLY_SIMD + return 1; +#else /* MINIMP3_ONLY_SIMD */ + static int g_have_simd; + int CPUInfo[4]; +#ifdef MINIMP3_TEST + static int g_counter; + if (g_counter++ > 100) + return 0; +#endif /* MINIMP3_TEST */ + if (g_have_simd) + goto end; + minimp3_cpuid(CPUInfo, 0); + g_have_simd = 1; + if (CPUInfo[0] > 0) + { + minimp3_cpuid(CPUInfo, 1); + g_have_simd = (CPUInfo[3] & (1 << 26)) + 1; /* SSE2 */ + } +end: + return g_have_simd - 1; +#endif /* MINIMP3_ONLY_SIMD */ +} +#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) +#include <arm_neon.h> +#define HAVE_SSE 0 +#define HAVE_SIMD 1 +#define VSTORE vst1q_f32 +#define VLD vld1q_f32 +#define VSET vmovq_n_f32 +#define VADD vaddq_f32 +#define VSUB vsubq_f32 +#define VMUL vmulq_f32 +#define VMAC(a, x, y) vmlaq_f32(a, x, y) +#define VMSB(a, x, y) vmlsq_f32(a, x, y) +#define VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s)) +#define VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x))) +typedef float32x4_t f4; +static int have_simd() +{ /* TODO: detect neon for !MINIMP3_ONLY_SIMD */ + return 1; +} +#else /* SIMD checks... */ +#define HAVE_SSE 0 +#define HAVE_SIMD 0 +#ifdef MINIMP3_ONLY_SIMD +#error MINIMP3_ONLY_SIMD used, but SSE/NEON not enabled +#endif /* MINIMP3_ONLY_SIMD */ +#endif /* SIMD checks... */ +#else /* !defined(MINIMP3_NO_SIMD) */ +#define HAVE_SIMD 0 +#endif /* !defined(MINIMP3_NO_SIMD) */ + +#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) +#define HAVE_ARMV6 1 +static __inline__ __attribute__((always_inline)) int32_t minimp3_clip_int16_arm(int32_t a) +{ + int32_t x = 0; + __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); + return x; +} +#else +#define HAVE_ARMV6 0 +#endif + +typedef struct +{ + const uint8_t *buf; + int pos, limit; +} bs_t; + +typedef struct +{ + float scf[3*64]; + uint8_t total_bands, stereo_bands, bitalloc[64], scfcod[64]; +} L12_scale_info; + +typedef struct +{ + uint8_t tab_offset, code_tab_width, band_count; +} L12_subband_alloc_t; + +typedef struct +{ + const uint8_t *sfbtab; + uint16_t part_23_length, big_values, scalefac_compress; + uint8_t global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; + uint8_t table_select[3], region_count[3], subblock_gain[3]; + uint8_t preflag, scalefac_scale, count1_table, scfsi; +} L3_gr_info_t; + +typedef struct +{ + bs_t bs; + uint8_t maindata[MAX_BITRESERVOIR_BYTES + MAX_L3_FRAME_PAYLOAD_BYTES]; + L3_gr_info_t gr_info[4]; + float grbuf[2][576], scf[40], syn[18 + 15][2*32]; + uint8_t ist_pos[2][39]; +} mp3dec_scratch_t; + +static void bs_init(bs_t *bs, const uint8_t *data, int bytes) +{ + bs->buf = data; + bs->pos = 0; + bs->limit = bytes*8; +} + +static uint32_t get_bits(bs_t *bs, int n) +{ + uint32_t next, cache = 0, s = bs->pos & 7; + int shl = n + s; + const uint8_t *p = bs->buf + (bs->pos >> 3); + if ((bs->pos += n) > bs->limit) + return 0; + next = *p++ & (255 >> s); + while ((shl -= 8) > 0) + { + cache |= next << shl; + next = *p++; + } + return cache | (next >> -shl); +} + +static int hdr_valid(const uint8_t *h) +{ + return h[0] == 0xff && + ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) && + (HDR_GET_LAYER(h) != 0) && + (HDR_GET_BITRATE(h) != 15) && + (HDR_GET_SAMPLE_RATE(h) != 3); +} + +static int hdr_compare(const uint8_t *h1, const uint8_t *h2) +{ + return hdr_valid(h2) && + ((h1[1] ^ h2[1]) & 0xFE) == 0 && + ((h1[2] ^ h2[2]) & 0x0C) == 0 && + !(HDR_IS_FREE_FORMAT(h1) ^ HDR_IS_FREE_FORMAT(h2)); +} + +static unsigned hdr_bitrate_kbps(const uint8_t *h) +{ + static const uint8_t halfrate[2][3][15] = { + { { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,16,24,28,32,40,48,56,64,72,80,88,96,112,128 } }, + { { 0,16,20,24,28,32,40,48,56,64,80,96,112,128,160 }, { 0,16,24,28,32,40,48,56,64,80,96,112,128,160,192 }, { 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } }, + }; + return 2*halfrate[!!HDR_TEST_MPEG1(h)][HDR_GET_LAYER(h) - 1][HDR_GET_BITRATE(h)]; +} + +static unsigned hdr_sample_rate_hz(const uint8_t *h) +{ + static const unsigned g_hz[3] = { 44100, 48000, 32000 }; + return g_hz[HDR_GET_SAMPLE_RATE(h)] >> (int)!HDR_TEST_MPEG1(h) >> (int)!HDR_TEST_NOT_MPEG25(h); +} + +static unsigned hdr_frame_samples(const uint8_t *h) +{ + return HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)HDR_IS_FRAME_576(h)); +} + +static int hdr_frame_bytes(const uint8_t *h, int free_format_size) +{ + int frame_bytes = hdr_frame_samples(h)*hdr_bitrate_kbps(h)*125/hdr_sample_rate_hz(h); + if (HDR_IS_LAYER_1(h)) + { + frame_bytes &= ~3; /* slot align */ + } + return frame_bytes ? frame_bytes : free_format_size; +} + +static int hdr_padding(const uint8_t *h) +{ + return HDR_TEST_PADDING(h) ? (HDR_IS_LAYER_1(h) ? 4 : 1) : 0; +} + +#ifndef MINIMP3_ONLY_MP3 +static const L12_subband_alloc_t *L12_subband_alloc_table(const uint8_t *hdr, L12_scale_info *sci) +{ + const L12_subband_alloc_t *alloc; + int mode = HDR_GET_STEREO_MODE(hdr); + int nbands, stereo_bands = (mode == MODE_MONO) ? 0 : (mode == MODE_JOINT_STEREO) ? (HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32; + + if (HDR_IS_LAYER_1(hdr)) + { + static const L12_subband_alloc_t g_alloc_L1[] = { { 76, 4, 32 } }; + alloc = g_alloc_L1; + nbands = 32; + } else if (!HDR_TEST_MPEG1(hdr)) + { + static const L12_subband_alloc_t g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } }; + alloc = g_alloc_L2M2; + nbands = 30; + } else + { + static const L12_subband_alloc_t g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } }; + int sample_rate_idx = HDR_GET_SAMPLE_RATE(hdr); + unsigned kbps = hdr_bitrate_kbps(hdr) >> (int)(mode != MODE_MONO); + if (!kbps) /* free-format */ + { + kbps = 192; + } + + alloc = g_alloc_L2M1; + nbands = 27; + if (kbps < 56) + { + static const L12_subband_alloc_t g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } }; + alloc = g_alloc_L2M1_lowrate; + nbands = sample_rate_idx == 2 ? 12 : 8; + } else if (kbps >= 96 && sample_rate_idx != 1) + { + nbands = 30; + } + } + + sci->total_bands = (uint8_t)nbands; + sci->stereo_bands = (uint8_t)MINIMP3_MIN(stereo_bands, nbands); + + return alloc; +} + +static void L12_read_scalefactors(bs_t *bs, uint8_t *pba, uint8_t *scfcod, int bands, float *scf) +{ + static const float g_deq_L12[18*3] = { +#define DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x + DQ(3),DQ(7),DQ(15),DQ(31),DQ(63),DQ(127),DQ(255),DQ(511),DQ(1023),DQ(2047),DQ(4095),DQ(8191),DQ(16383),DQ(32767),DQ(65535),DQ(3),DQ(5),DQ(9) + }; + int i, m; + for (i = 0; i < bands; i++) + { + float s = 0; + int ba = *pba++; + int mask = ba ? 4 + ((19 >> scfcod[i]) & 3) : 0; + for (m = 4; m; m >>= 1) + { + if (mask & m) + { + int b = get_bits(bs, 6); + s = g_deq_L12[ba*3 - 6 + b % 3]*(1 << 21 >> b/3); + } + *scf++ = s; + } + } +} + +static void L12_read_scale_info(const uint8_t *hdr, bs_t *bs, L12_scale_info *sci) +{ + static const uint8_t g_bitalloc_code_tab[] = { + 0,17, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16, + 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,16, + 0,17,18, 3,19,4,5,16, + 0,17,18,16, + 0,17,18,19, 4,5,6, 7,8, 9,10,11,12,13,14,15, + 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14, + 0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16 + }; + const L12_subband_alloc_t *subband_alloc = L12_subband_alloc_table(hdr, sci); + + int i, k = 0, ba_bits = 0; + const uint8_t *ba_code_tab = g_bitalloc_code_tab; + + for (i = 0; i < sci->total_bands; i++) + { + uint8_t ba; + if (i == k) + { + k += subband_alloc->band_count; + ba_bits = subband_alloc->code_tab_width; + ba_code_tab = g_bitalloc_code_tab + subband_alloc->tab_offset; + subband_alloc++; + } + ba = ba_code_tab[get_bits(bs, ba_bits)]; + sci->bitalloc[2*i] = ba; + if (i < sci->stereo_bands) + { + ba = ba_code_tab[get_bits(bs, ba_bits)]; + } + sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0; + } + + for (i = 0; i < 2*sci->total_bands; i++) + { + sci->scfcod[i] = sci->bitalloc[i] ? HDR_IS_LAYER_1(hdr) ? 2 : get_bits(bs, 2) : 6; + } + + L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf); + + for (i = sci->stereo_bands; i < sci->total_bands; i++) + { + sci->bitalloc[2*i + 1] = 0; + } +} + +static int L12_dequantize_granule(float *grbuf, bs_t *bs, L12_scale_info *sci, int group_size) +{ + int i, j, k, choff = 576; + for (j = 0; j < 4; j++) + { + float *dst = grbuf + group_size*j; + for (i = 0; i < 2*sci->total_bands; i++) + { + int ba = sci->bitalloc[i]; + if (ba != 0) + { + if (ba < 17) + { + int half = (1 << (ba - 1)) - 1; + for (k = 0; k < group_size; k++) + { + dst[k] = (float)((int)get_bits(bs, ba) - half); + } + } else + { + unsigned mod = (2 << (ba - 17)) + 1; /* 3, 5, 9 */ + unsigned code = get_bits(bs, mod + 2 - (mod >> 3)); /* 5, 7, 10 */ + for (k = 0; k < group_size; k++, code /= mod) + { + dst[k] = (float)((int)(code % mod - mod/2)); + } + } + } + dst += choff; + choff = 18 - choff; + } + } + return group_size*4; +} + +static void L12_apply_scf_384(L12_scale_info *sci, const float *scf, float *dst) +{ + int i, k; + memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); + for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6) + { + for (k = 0; k < 12; k++) + { + dst[k + 0] *= scf[0]; + dst[k + 576] *= scf[3]; + } + } +} +#endif /* MINIMP3_ONLY_MP3 */ + +static int L3_read_side_info(bs_t *bs, L3_gr_info_t *gr, const uint8_t *hdr) +{ + static const uint8_t g_scf_long[8][23] = { + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 4,4,4,4,4,4,6,6,8,8,10,12,16,20,24,28,34,42,50,54,76,158,0 }, + { 4,4,4,4,4,4,6,6,6,8,10,12,16,18,22,28,34,40,46,54,54,192,0 }, + { 4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102,26,0 } + }; + static const uint8_t g_scf_short[8][40] = { + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 8,8,8,8,8,8,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } + }; + static const uint8_t g_scf_mixed[8][40] = { + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 12,12,12,4,4,4,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, + { 6,6,6,6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } + }; + + unsigned tables, scfsi = 0; + int main_data_begin, part_23_sum = 0; + int sr_idx = HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0); + int gr_count = HDR_IS_MONO(hdr) ? 1 : 2; + + if (HDR_TEST_MPEG1(hdr)) + { + gr_count *= 2; + main_data_begin = get_bits(bs, 9); + scfsi = get_bits(bs, 7 + gr_count); + } else + { + main_data_begin = get_bits(bs, 8 + gr_count) >> gr_count; + } + + do + { + if (HDR_IS_MONO(hdr)) + { + scfsi <<= 4; + } + gr->part_23_length = (uint16_t)get_bits(bs, 12); + part_23_sum += gr->part_23_length; + gr->big_values = (uint16_t)get_bits(bs, 9); + if (gr->big_values > 288) + { + return -1; + } + gr->global_gain = (uint8_t)get_bits(bs, 8); + gr->scalefac_compress = (uint16_t)get_bits(bs, HDR_TEST_MPEG1(hdr) ? 4 : 9); + gr->sfbtab = g_scf_long[sr_idx]; + gr->n_long_sfb = 22; + gr->n_short_sfb = 0; + if (get_bits(bs, 1)) + { + gr->block_type = (uint8_t)get_bits(bs, 2); + if (!gr->block_type) + { + return -1; + } + gr->mixed_block_flag = (uint8_t)get_bits(bs, 1); + gr->region_count[0] = 7; + gr->region_count[1] = 255; + if (gr->block_type == SHORT_BLOCK_TYPE) + { + scfsi &= 0x0F0F; + if (!gr->mixed_block_flag) + { + gr->region_count[0] = 8; + gr->sfbtab = g_scf_short[sr_idx]; + gr->n_long_sfb = 0; + gr->n_short_sfb = 39; + } else + { + gr->sfbtab = g_scf_mixed[sr_idx]; + gr->n_long_sfb = HDR_TEST_MPEG1(hdr) ? 8 : 6; + gr->n_short_sfb = 30; + } + } + tables = get_bits(bs, 10); + tables <<= 5; + gr->subblock_gain[0] = (uint8_t)get_bits(bs, 3); + gr->subblock_gain[1] = (uint8_t)get_bits(bs, 3); + gr->subblock_gain[2] = (uint8_t)get_bits(bs, 3); + } else + { + gr->block_type = 0; + gr->mixed_block_flag = 0; + tables = get_bits(bs, 15); + gr->region_count[0] = (uint8_t)get_bits(bs, 4); + gr->region_count[1] = (uint8_t)get_bits(bs, 3); + gr->region_count[2] = 255; + } + gr->table_select[0] = (uint8_t)(tables >> 10); + gr->table_select[1] = (uint8_t)((tables >> 5) & 31); + gr->table_select[2] = (uint8_t)((tables) & 31); + gr->preflag = HDR_TEST_MPEG1(hdr) ? get_bits(bs, 1) : (gr->scalefac_compress >= 500); + gr->scalefac_scale = (uint8_t)get_bits(bs, 1); + gr->count1_table = (uint8_t)get_bits(bs, 1); + gr->scfsi = (uint8_t)((scfsi >> 12) & 15); + scfsi <<= 4; + gr++; + } while(--gr_count); + + if (part_23_sum + bs->pos > bs->limit + main_data_begin*8) + { + return -1; + } + + return main_data_begin; +} + +static void L3_read_scalefactors(uint8_t *scf, uint8_t *ist_pos, const uint8_t *scf_size, const uint8_t *scf_count, bs_t *bitbuf, int scfsi) +{ + int i, k; + for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2) + { + int cnt = scf_count[i]; + if (scfsi & 8) + { + memcpy(scf, ist_pos, cnt); + } else + { + int bits = scf_size[i]; + if (!bits) + { + memset(scf, 0, cnt); + memset(ist_pos, 0, cnt); + } else + { + int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1; + for (k = 0; k < cnt; k++) + { + int s = get_bits(bitbuf, bits); + ist_pos[k] = (s == max_scf ? -1 : s); + scf[k] = s; + } + } + } + ist_pos += cnt; + scf += cnt; + } + scf[0] = scf[1] = scf[2] = 0; +} + +static float L3_ldexp_q2(float y, int exp_q2) +{ + static const float g_expfrac[4] = { 9.31322575e-10f,7.83145814e-10f,6.58544508e-10f,5.53767716e-10f }; + int e; + do + { + e = MINIMP3_MIN(30*4, exp_q2); + y *= g_expfrac[e & 3]*(1 << 30 >> (e >> 2)); + } while ((exp_q2 -= e) > 0); + return y; +} + +static void L3_decode_scalefactors(const uint8_t *hdr, uint8_t *ist_pos, bs_t *bs, const L3_gr_info_t *gr, float *scf, int ch) +{ + static const uint8_t g_scf_partitions[3][28] = { + { 6,5,5, 5,6,5,5,5,6,5, 7,3,11,10,0,0, 7, 7, 7,0, 6, 6,6,3, 8, 8,5,0 }, + { 8,9,6,12,6,9,9,9,6,9,12,6,15,18,0,0, 6,15,12,0, 6,12,9,6, 6,18,9,0 }, + { 9,9,6,12,9,9,9,9,9,9,12,6,18,18,0,0,12,12,12,0,12, 9,9,6,15,12,9,0 } + }; + const uint8_t *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb]; + uint8_t scf_size[4], iscf[40]; + int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi; + float gain; + + if (HDR_TEST_MPEG1(hdr)) + { + static const uint8_t g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 }; + int part = g_scfc_decode[gr->scalefac_compress]; + scf_size[1] = scf_size[0] = (uint8_t)(part >> 2); + scf_size[3] = scf_size[2] = (uint8_t)(part & 3); + } else + { + static const uint8_t g_mod[6*4] = { 5,5,4,4,5,5,4,1,4,3,1,1,5,6,6,1,4,4,4,1,4,3,1,1 }; + int k, modprod, sfc, ist = HDR_TEST_I_STEREO(hdr) && ch; + sfc = gr->scalefac_compress >> ist; + for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4) + { + for (modprod = 1, i = 3; i >= 0; i--) + { + scf_size[i] = (uint8_t)(sfc / modprod % g_mod[k + i]); + modprod *= g_mod[k + i]; + } + } + scf_partition += k; + scfsi = -16; + } + L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi); + + if (gr->n_short_sfb) + { + int sh = 3 - scf_shift; + for (i = 0; i < gr->n_short_sfb; i += 3) + { + iscf[gr->n_long_sfb + i + 0] += gr->subblock_gain[0] << sh; + iscf[gr->n_long_sfb + i + 1] += gr->subblock_gain[1] << sh; + iscf[gr->n_long_sfb + i + 2] += gr->subblock_gain[2] << sh; + } + } else if (gr->preflag) + { + static const uint8_t g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 }; + for (i = 0; i < 10; i++) + { + iscf[11 + i] += g_preamp[i]; + } + } + + gain_exp = gr->global_gain + BITS_DEQUANTIZER_OUT*4 - 210 - (HDR_IS_MS_STEREO(hdr) ? 2 : 0); + gain = L3_ldexp_q2(1 << (MAX_SCFI/4), MAX_SCFI - gain_exp); + for (i = 0; i < (int)(gr->n_long_sfb + gr->n_short_sfb); i++) + { + scf[i] = L3_ldexp_q2(gain, iscf[i] << scf_shift); + } +} + +static const float g_pow43[129 + 16] = { + 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, + 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f +}; + +static float L3_pow_43(int x) +{ + float frac; + int sign, mult = 256; + + if (x < 129) + { + return g_pow43[16 + x]; + } + + if (x < 1024) + { + mult = 16; + x <<= 3; + } + + sign = 2*x & 64; + frac = (float)((x & 63) - sign) / ((x & ~63) + sign); + return g_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; +} + +static void L3_huffman(float *dst, bs_t *bs, const L3_gr_info_t *gr_info, const float *scf, int layer3gr_limit) +{ + static const int16_t tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 785,785,785,785,784,784,784,784,513,513,513,513,513,513,513,513,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256, + -255,1313,1298,1282,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,290,288, + -255,1313,1298,1282,769,769,769,769,529,529,529,529,529,529,529,529,528,528,528,528,528,528,528,528,512,512,512,512,512,512,512,512,290,288, + -253,-318,-351,-367,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258, + -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259, + -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258, + -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258, + -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259, + -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258, + -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290, + -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259, + -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258, + -250,-1179,-1579,-1836,-1996,-2124,-2253,-2333,-2413,-2477,-2542,-2574,-2607,-2622,-2655,1314,1313,1298,1312,1282,785,785,785,785,1040,1040,1025,1025,768,768,768,768,-766,-798,-830,-862,-895,-911,-927,-943,-959,-975,-991,-1007,-1023,-1039,-1055,-1070,1724,1647,-1103,-1119,1631,1767,1662,1738,1708,1723,-1135,1780,1615,1779,1599,1677,1646,1778,1583,-1151,1777,1567,1737,1692,1765,1722,1707,1630,1751,1661,1764,1614,1736,1676,1763,1750,1645,1598,1721,1691,1762,1706,1582,1761,1566,-1167,1749,1629,767,766,751,765,494,494,735,764,719,749,734,763,447,447,748,718,477,506,431,491,446,476,461,505,415,430,475,445,504,399,460,489,414,503,383,474,429,459,502,502,746,752,488,398,501,473,413,472,486,271,480,270,-1439,-1455,1357,-1471,-1487,-1503,1341,1325,-1519,1489,1463,1403,1309,-1535,1372,1448,1418,1476,1356,1462,1387,-1551,1475,1340,1447,1402,1386,-1567,1068,1068,1474,1461,455,380,468,440,395,425,410,454,364,467,466,464,453,269,409,448,268,432,1371,1473,1432,1417,1308,1460,1355,1446,1459,1431,1083,1083,1401,1416,1458,1445,1067,1067,1370,1457,1051,1051,1291,1430,1385,1444,1354,1415,1400,1443,1082,1082,1173,1113,1186,1066,1185,1050,-1967,1158,1128,1172,1097,1171,1081,-1983,1157,1112,416,266,375,400,1170,1142,1127,1065,793,793,1169,1033,1156,1096,1141,1111,1155,1080,1126,1140,898,898,808,808,897,897,792,792,1095,1152,1032,1125,1110,1139,1079,1124,882,807,838,881,853,791,-2319,867,368,263,822,852,837,866,806,865,-2399,851,352,262,534,534,821,836,594,594,549,549,593,593,533,533,848,773,579,579,564,578,548,563,276,276,577,576,306,291,516,560,305,305,275,259, + -251,-892,-2058,-2620,-2828,-2957,-3023,-3039,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,-559,1530,-575,-591,1528,1527,1407,1526,1391,1023,1023,1023,1023,1525,1375,1268,1268,1103,1103,1087,1087,1039,1039,1523,-604,815,815,815,815,510,495,509,479,508,463,507,447,431,505,415,399,-734,-782,1262,-815,1259,1244,-831,1258,1228,-847,-863,1196,-879,1253,987,987,748,-767,493,493,462,477,414,414,686,669,478,446,461,445,474,429,487,458,412,471,1266,1264,1009,1009,799,799,-1019,-1276,-1452,-1581,-1677,-1757,-1821,-1886,-1933,-1997,1257,1257,1483,1468,1512,1422,1497,1406,1467,1496,1421,1510,1134,1134,1225,1225,1466,1451,1374,1405,1252,1252,1358,1480,1164,1164,1251,1251,1238,1238,1389,1465,-1407,1054,1101,-1423,1207,-1439,830,830,1248,1038,1237,1117,1223,1148,1236,1208,411,426,395,410,379,269,1193,1222,1132,1235,1221,1116,976,976,1192,1162,1177,1220,1131,1191,963,963,-1647,961,780,-1663,558,558,994,993,437,408,393,407,829,978,813,797,947,-1743,721,721,377,392,844,950,828,890,706,706,812,859,796,960,948,843,934,874,571,571,-1919,690,555,689,421,346,539,539,944,779,918,873,932,842,903,888,570,570,931,917,674,674,-2575,1562,-2591,1609,-2607,1654,1322,1322,1441,1441,1696,1546,1683,1593,1669,1624,1426,1426,1321,1321,1639,1680,1425,1425,1305,1305,1545,1668,1608,1623,1667,1592,1638,1666,1320,1320,1652,1607,1409,1409,1304,1304,1288,1288,1664,1637,1395,1395,1335,1335,1622,1636,1394,1394,1319,1319,1606,1621,1392,1392,1137,1137,1137,1137,345,390,360,375,404,373,1047,-2751,-2767,-2783,1062,1121,1046,-2799,1077,-2815,1106,1061,789,789,1105,1104,263,355,310,340,325,354,352,262,339,324,1091,1076,1029,1090,1060,1075,833,833,788,788,1088,1028,818,818,803,803,561,561,531,531,816,771,546,546,289,274,288,258, + -253,-317,-381,-446,-478,-509,1279,1279,-811,-1179,-1451,-1756,-1900,-2028,-2189,-2253,-2333,-2414,-2445,-2511,-2526,1313,1298,-2559,1041,1041,1040,1040,1025,1025,1024,1024,1022,1007,1021,991,1020,975,1019,959,687,687,1018,1017,671,671,655,655,1016,1015,639,639,758,758,623,623,757,607,756,591,755,575,754,559,543,543,1009,783,-575,-621,-685,-749,496,-590,750,749,734,748,974,989,1003,958,988,973,1002,942,987,957,972,1001,926,986,941,971,956,1000,910,985,925,999,894,970,-1071,-1087,-1102,1390,-1135,1436,1509,1451,1374,-1151,1405,1358,1480,1420,-1167,1507,1494,1389,1342,1465,1435,1450,1326,1505,1310,1493,1373,1479,1404,1492,1464,1419,428,443,472,397,736,526,464,464,486,457,442,471,484,482,1357,1449,1434,1478,1388,1491,1341,1490,1325,1489,1463,1403,1309,1477,1372,1448,1418,1433,1476,1356,1462,1387,-1439,1475,1340,1447,1402,1474,1324,1461,1371,1473,269,448,1432,1417,1308,1460,-1711,1459,-1727,1441,1099,1099,1446,1386,1431,1401,-1743,1289,1083,1083,1160,1160,1458,1445,1067,1067,1370,1457,1307,1430,1129,1129,1098,1098,268,432,267,416,266,400,-1887,1144,1187,1082,1173,1113,1186,1066,1050,1158,1128,1143,1172,1097,1171,1081,420,391,1157,1112,1170,1142,1127,1065,1169,1049,1156,1096,1141,1111,1155,1080,1126,1154,1064,1153,1140,1095,1048,-2159,1125,1110,1137,-2175,823,823,1139,1138,807,807,384,264,368,263,868,838,853,791,867,822,852,837,866,806,865,790,-2319,851,821,836,352,262,850,805,849,-2399,533,533,835,820,336,261,578,548,563,577,532,532,832,772,562,562,547,547,305,275,560,515,290,290,288,258 }; + static const uint8_t tab32[] = { 130,162,193,209,44,28,76,140,9,9,9,9,9,9,9,9,190,254,222,238,126,94,157,157,109,61,173,205 }; + static const uint8_t tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 }; + static const int16_t tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 }; + static const uint8_t g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; + +#define PEEK_BITS(n) (bs_cache >> (32 - n)) +#define FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } +#define CHECK_BITS while (bs_sh >= 0) { bs_cache |= (uint32_t)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } +#define BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) + + float one = 0.0f; + int ireg = 0, big_val_cnt = gr_info->big_values; + const uint8_t *sfb = gr_info->sfbtab; + const uint8_t *bs_next_ptr = bs->buf + bs->pos/8; + uint32_t bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7); + int pairs_to_decode, np, bs_sh = (bs->pos & 7) - 8; + bs_next_ptr += 4; + + while (big_val_cnt > 0) + { + int tab_num = gr_info->table_select[ireg]; + int sfb_cnt = gr_info->region_count[ireg++]; + const int16_t *codebook = tabs + tabindex[tab_num]; + int linbits = g_linbits[tab_num]; + if (linbits) + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[PEEK_BITS(w)]; + while (leaf < 0) + { + FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; + } + FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + if (lsb == 15) + { + lsb += PEEK_BITS(linbits); + FLUSH_BITS(linbits); + CHECK_BITS; + *dst = one*L3_pow_43(lsb)*((int32_t)bs_cache < 0 ? -1: 1); + } else + { + *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + } + FLUSH_BITS(lsb ? 1 : 0); + } + CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } else + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[PEEK_BITS(w)]; + while (leaf < 0) + { + FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; + } + FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + FLUSH_BITS(lsb ? 1 : 0); + } + CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } + } + + for (np = 1 - big_val_cnt;; dst += 4) + { + const uint8_t *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32; + int leaf = codebook_count1[PEEK_BITS(4)]; + if (!(leaf & 8)) + { + leaf = codebook_count1[(leaf >> 3) + (bs_cache << 4 >> (32 - (leaf & 3)))]; + } + FLUSH_BITS(leaf & 7); + if (BSPOS > layer3gr_limit) + { + break; + } +#define RELOAD_SCALEFACTOR if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; } +#define DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((int32_t)bs_cache < 0) ? -one : one; FLUSH_BITS(1) } + RELOAD_SCALEFACTOR; + DEQ_COUNT1(0); + DEQ_COUNT1(1); + RELOAD_SCALEFACTOR; + DEQ_COUNT1(2); + DEQ_COUNT1(3); + CHECK_BITS; + } + + bs->pos = layer3gr_limit; +} + +static void L3_midside_stereo(float *left, int n) +{ + int i = 0; + float *right = left + 576; +#if HAVE_SIMD + if (have_simd()) for (; i < n - 3; i += 4) + { + f4 vl = VLD(left + i); + f4 vr = VLD(right + i); + VSTORE(left + i, VADD(vl, vr)); + VSTORE(right + i, VSUB(vl, vr)); + } +#endif /* HAVE_SIMD */ + for (; i < n; i++) + { + float a = left[i]; + float b = right[i]; + left[i] = a + b; + right[i] = a - b; + } +} + +static void L3_intensity_stereo_band(float *left, int n, float kl, float kr) +{ + int i; + for (i = 0; i < n; i++) + { + left[i + 576] = left[i]*kr; + left[i] = left[i]*kl; + } +} + +static void L3_stereo_top_band(const float *right, const uint8_t *sfb, int nbands, int max_band[3]) +{ + int i, k; + + max_band[0] = max_band[1] = max_band[2] = -1; + + for (i = 0; i < nbands; i++) + { + for (k = 0; k < sfb[i]; k += 2) + { + if (right[k] != 0 || right[k + 1] != 0) + { + max_band[i % 3] = i; + break; + } + } + right += sfb[i]; + } +} + +static void L3_stereo_process(float *left, const uint8_t *ist_pos, const uint8_t *sfb, const uint8_t *hdr, int max_band[3], int mpeg2_sh) +{ + static const float g_pan[7*2] = { 0,1,0.21132487f,0.78867513f,0.36602540f,0.63397460f,0.5f,0.5f,0.63397460f,0.36602540f,0.78867513f,0.21132487f,1,0 }; + unsigned i, max_pos = HDR_TEST_MPEG1(hdr) ? 7 : 64; + + for (i = 0; sfb[i]; i++) + { + unsigned ipos = ist_pos[i]; + if ((int)i > max_band[i % 3] && ipos < max_pos) + { + float kl, kr, s = HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1; + if (HDR_TEST_MPEG1(hdr)) + { + kl = g_pan[2*ipos]; + kr = g_pan[2*ipos + 1]; + } else + { + kl = 1; + kr = L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh); + if (ipos & 1) + { + kl = kr; + kr = 1; + } + } + L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s); + } else if (HDR_TEST_MS_STEREO(hdr)) + { + L3_midside_stereo(left, sfb[i]); + } + left += sfb[i]; + } +} + +static void L3_intensity_stereo(float *left, uint8_t *ist_pos, const L3_gr_info_t *gr, const uint8_t *hdr) +{ + int max_band[3], n_sfb = gr->n_long_sfb + gr->n_short_sfb; + int i, max_blocks = gr->n_short_sfb ? 3 : 1; + + L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band); + if (gr->n_long_sfb) + { + max_band[0] = max_band[1] = max_band[2] = MINIMP3_MAX(MINIMP3_MAX(max_band[0], max_band[1]), max_band[2]); + } + for (i = 0; i < max_blocks; i++) + { + int default_pos = HDR_TEST_MPEG1(hdr) ? 3 : 0; + int itop = n_sfb - max_blocks + i; + int prev = itop - max_blocks; + ist_pos[itop] = max_band[i] >= prev ? default_pos : ist_pos[prev]; + } + L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1); +} + +static void L3_reorder(float *grbuf, float *scratch, const uint8_t *sfb) +{ + int i, len; + float *src = grbuf, *dst = scratch; + + for (;0 != (len = *sfb); sfb += 3, src += 2*len) + { + for (i = 0; i < len; i++, src++) + { + *dst++ = src[0*len]; + *dst++ = src[1*len]; + *dst++ = src[2*len]; + } + } + memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); +} + +static void L3_antialias(float *grbuf, int nbands) +{ + static const float g_aa[2][8] = { + {0.85749293f,0.88174200f,0.94962865f,0.98331459f,0.99551782f,0.99916056f,0.99989920f,0.99999316f}, + {0.51449576f,0.47173197f,0.31337745f,0.18191320f,0.09457419f,0.04096558f,0.01419856f,0.00369997f} + }; + + for (; nbands > 0; nbands--, grbuf += 18) + { + int i = 0; +#if HAVE_SIMD + if (have_simd()) for (; i < 8; i += 4) + { + f4 vu = VLD(grbuf + 18 + i); + f4 vd = VLD(grbuf + 14 - i); + f4 vc0 = VLD(g_aa[0] + i); + f4 vc1 = VLD(g_aa[1] + i); + vd = VREV(vd); + VSTORE(grbuf + 18 + i, VSUB(VMUL(vu, vc0), VMUL(vd, vc1))); + vd = VADD(VMUL(vu, vc1), VMUL(vd, vc0)); + VSTORE(grbuf + 14 - i, VREV(vd)); + } +#endif /* HAVE_SIMD */ +#ifndef MINIMP3_ONLY_SIMD + for(; i < 8; i++) + { + float u = grbuf[18 + i]; + float d = grbuf[17 - i]; + grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i]; + grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i]; + } +#endif /* MINIMP3_ONLY_SIMD */ + } +} + +static void L3_dct3_9(float *y) +{ + float s0, s1, s2, s3, s4, s5, s6, s7, s8, t0, t2, t4; + + s0 = y[0]; s2 = y[2]; s4 = y[4]; s6 = y[6]; s8 = y[8]; + t0 = s0 + s6*0.5f; + s0 -= s6; + t4 = (s4 + s2)*0.93969262f; + t2 = (s8 + s2)*0.76604444f; + s6 = (s4 - s8)*0.17364818f; + s4 += s8 - s2; + + s2 = s0 - s4*0.5f; + y[4] = s4 + s0; + s8 = t0 - t2 + s6; + s0 = t0 - t4 + t2; + s4 = t0 + t4 - s6; + + s1 = y[1]; s3 = y[3]; s5 = y[5]; s7 = y[7]; + + s3 *= 0.86602540f; + t0 = (s5 + s1)*0.98480775f; + t4 = (s5 - s7)*0.34202014f; + t2 = (s1 + s7)*0.64278761f; + s1 = (s1 - s5 - s7)*0.86602540f; + + s5 = t0 - s3 - t2; + s7 = t4 - s3 - t0; + s3 = t4 + s3 - t2; + + y[0] = s4 - s7; + y[1] = s2 + s1; + y[2] = s0 - s3; + y[3] = s8 + s5; + y[5] = s8 - s5; + y[6] = s0 + s3; + y[7] = s2 - s1; + y[8] = s4 + s7; +} + +static void L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands) +{ + int i, j; + static const float g_twid9[18] = { + 0.73727734f,0.79335334f,0.84339145f,0.88701083f,0.92387953f,0.95371695f,0.97629601f,0.99144486f,0.99904822f,0.67559021f,0.60876143f,0.53729961f,0.46174861f,0.38268343f,0.30070580f,0.21643961f,0.13052619f,0.04361938f + }; + + for (j = 0; j < nbands; j++, grbuf += 18, overlap += 9) + { + float co[9], si[9]; + co[0] = -grbuf[0]; + si[0] = grbuf[17]; + for (i = 0; i < 4; i++) + { + si[8 - 2*i] = grbuf[4*i + 1] - grbuf[4*i + 2]; + co[1 + 2*i] = grbuf[4*i + 1] + grbuf[4*i + 2]; + si[7 - 2*i] = grbuf[4*i + 4] - grbuf[4*i + 3]; + co[2 + 2*i] = -(grbuf[4*i + 3] + grbuf[4*i + 4]); + } + L3_dct3_9(co); + L3_dct3_9(si); + + si[1] = -si[1]; + si[3] = -si[3]; + si[5] = -si[5]; + si[7] = -si[7]; + + i = 0; + +#if HAVE_SIMD + if (have_simd()) for (; i < 8; i += 4) + { + f4 vovl = VLD(overlap + i); + f4 vc = VLD(co + i); + f4 vs = VLD(si + i); + f4 vr0 = VLD(g_twid9 + i); + f4 vr1 = VLD(g_twid9 + 9 + i); + f4 vw0 = VLD(window + i); + f4 vw1 = VLD(window + 9 + i); + f4 vsum = VADD(VMUL(vc, vr1), VMUL(vs, vr0)); + VSTORE(overlap + i, VSUB(VMUL(vc, vr0), VMUL(vs, vr1))); + VSTORE(grbuf + i, VSUB(VMUL(vovl, vw0), VMUL(vsum, vw1))); + vsum = VADD(VMUL(vovl, vw1), VMUL(vsum, vw0)); + VSTORE(grbuf + 14 - i, VREV(vsum)); + } +#endif /* HAVE_SIMD */ + for (; i < 9; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid9[9 + i] + si[i]*g_twid9[0 + i]; + overlap[i] = co[i]*g_twid9[0 + i] - si[i]*g_twid9[9 + i]; + grbuf[i] = ovl*window[0 + i] - sum*window[9 + i]; + grbuf[17 - i] = ovl*window[9 + i] + sum*window[0 + i]; + } + } +} + +static void L3_idct3(float x0, float x1, float x2, float *dst) +{ + float m1 = x1*0.86602540f; + float a1 = x0 - x2*0.5f; + dst[1] = x0 + x2; + dst[0] = a1 + m1; + dst[2] = a1 - m1; +} + +static void L3_imdct12(float *x, float *dst, float *overlap) +{ + static const float g_twid3[6] = { 0.79335334f,0.92387953f,0.99144486f, 0.60876143f,0.38268343f,0.13052619f }; + float co[3], si[3]; + int i; + + L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co); + L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si); + si[1] = -si[1]; + + for (i = 0; i < 3; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid3[3 + i] + si[i]*g_twid3[0 + i]; + overlap[i] = co[i]*g_twid3[0 + i] - si[i]*g_twid3[3 + i]; + dst[i] = ovl*g_twid3[2 - i] - sum*g_twid3[5 - i]; + dst[5 - i] = ovl*g_twid3[5 - i] + sum*g_twid3[2 - i]; + } +} + +static void L3_imdct_short(float *grbuf, float *overlap, int nbands) +{ + for (;nbands > 0; nbands--, overlap += 9, grbuf += 18) + { + float tmp[18]; + memcpy(tmp, grbuf, sizeof(tmp)); + memcpy(grbuf, overlap, 6*sizeof(float)); + L3_imdct12(tmp, grbuf + 6, overlap + 6); + L3_imdct12(tmp + 1, grbuf + 12, overlap + 6); + L3_imdct12(tmp + 2, overlap, overlap + 6); + } +} + +static void L3_change_sign(float *grbuf) +{ + int b, i; + for (b = 0, grbuf += 18; b < 32; b += 2, grbuf += 36) + for (i = 1; i < 18; i += 2) + grbuf[i] = -grbuf[i]; +} + +static void L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands) +{ + static const float g_mdct_window[2][18] = { + { 0.99904822f,0.99144486f,0.97629601f,0.95371695f,0.92387953f,0.88701083f,0.84339145f,0.79335334f,0.73727734f,0.04361938f,0.13052619f,0.21643961f,0.30070580f,0.38268343f,0.46174861f,0.53729961f,0.60876143f,0.67559021f }, + { 1,1,1,1,1,1,0.99144486f,0.92387953f,0.79335334f,0,0,0,0,0,0,0.13052619f,0.38268343f,0.60876143f } + }; + if (n_long_bands) + { + L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands); + grbuf += 18*n_long_bands; + overlap += 9*n_long_bands; + } + if (block_type == SHORT_BLOCK_TYPE) + L3_imdct_short(grbuf, overlap, 32 - n_long_bands); + else + L3_imdct36(grbuf, overlap, g_mdct_window[block_type == STOP_BLOCK_TYPE], 32 - n_long_bands); +} + +static void L3_save_reservoir(mp3dec_t *h, mp3dec_scratch_t *s) +{ + int pos = (s->bs.pos + 7)/8u; + int remains = s->bs.limit/8u - pos; + if (remains > MAX_BITRESERVOIR_BYTES) + { + pos += remains - MAX_BITRESERVOIR_BYTES; + remains = MAX_BITRESERVOIR_BYTES; + } + if (remains > 0) + { + memmove(h->reserv_buf, s->maindata + pos, remains); + } + h->reserv = remains; +} + +static int L3_restore_reservoir(mp3dec_t *h, bs_t *bs, mp3dec_scratch_t *s, int main_data_begin) +{ + int frame_bytes = (bs->limit - bs->pos)/8; + int bytes_have = MINIMP3_MIN(h->reserv, main_data_begin); + memcpy(s->maindata, h->reserv_buf + MINIMP3_MAX(0, h->reserv - main_data_begin), MINIMP3_MIN(h->reserv, main_data_begin)); + memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); + bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); + return h->reserv >= main_data_begin; +} + +static void L3_decode(mp3dec_t *h, mp3dec_scratch_t *s, L3_gr_info_t *gr_info, int nch) +{ + int ch; + + for (ch = 0; ch < nch; ch++) + { + int layer3gr_limit = s->bs.pos + gr_info[ch].part_23_length; + L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch); + L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit); + } + + if (HDR_TEST_I_STEREO(h->header)) + { + L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header); + } else if (HDR_IS_MS_STEREO(h->header)) + { + L3_midside_stereo(s->grbuf[0], 576); + } + + for (ch = 0; ch < nch; ch++, gr_info++) + { + int aa_bands = 31; + int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(HDR_GET_MY_SAMPLE_RATE(h->header) == 2); + + if (gr_info->n_short_sfb) + { + aa_bands = n_long_bands - 1; + L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb); + } + + L3_antialias(s->grbuf[ch], aa_bands); + L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands); + L3_change_sign(s->grbuf[ch]); + } +} + +static void mp3d_DCT_II(float *grbuf, int n) +{ + static const float g_sec[24] = { + 10.19000816f,0.50060302f,0.50241929f,3.40760851f,0.50547093f,0.52249861f,2.05778098f,0.51544732f,0.56694406f,1.48416460f,0.53104258f,0.64682180f,1.16943991f,0.55310392f,0.78815460f,0.97256821f,0.58293498f,1.06067765f,0.83934963f,0.62250412f,1.72244716f,0.74453628f,0.67480832f,5.10114861f + }; + int i, k = 0; +#if HAVE_SIMD + if (have_simd()) for (; k < n; k += 4) + { + f4 t[4][8], *x; + float *y = grbuf + k; + + for (x = t[0], i = 0; i < 8; i++, x++) + { + f4 x0 = VLD(&y[i*18]); + f4 x1 = VLD(&y[(15 - i)*18]); + f4 x2 = VLD(&y[(16 + i)*18]); + f4 x3 = VLD(&y[(31 - i)*18]); + f4 t0 = VADD(x0, x3); + f4 t1 = VADD(x1, x2); + f4 t2 = VMUL_S(VSUB(x1, x2), g_sec[3*i + 0]); + f4 t3 = VMUL_S(VSUB(x0, x3), g_sec[3*i + 1]); + x[0] = VADD(t0, t1); + x[8] = VMUL_S(VSUB(t0, t1), g_sec[3*i + 2]); + x[16] = VADD(t3, t2); + x[24] = VMUL_S(VSUB(t3, t2), g_sec[3*i + 2]); + } + for (x = t[0], i = 0; i < 4; i++, x += 8) + { + f4 x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; + xt = VSUB(x0, x7); x0 = VADD(x0, x7); + x7 = VSUB(x1, x6); x1 = VADD(x1, x6); + x6 = VSUB(x2, x5); x2 = VADD(x2, x5); + x5 = VSUB(x3, x4); x3 = VADD(x3, x4); + x4 = VSUB(x0, x3); x0 = VADD(x0, x3); + x3 = VSUB(x1, x2); x1 = VADD(x1, x2); + x[0] = VADD(x0, x1); + x[4] = VMUL_S(VSUB(x0, x1), 0.70710677f); + x5 = VADD(x5, x6); + x6 = VMUL_S(VADD(x6, x7), 0.70710677f); + x7 = VADD(x7, xt); + x3 = VMUL_S(VADD(x3, x4), 0.70710677f); + x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); /* rotate by PI/8 */ + x7 = VADD(x7, VMUL_S(x5, 0.382683432f)); + x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); + x0 = VSUB(xt, x6); xt = VADD(xt, x6); + x[1] = VMUL_S(VADD(xt, x7), 0.50979561f); + x[2] = VMUL_S(VADD(x4, x3), 0.54119611f); + x[3] = VMUL_S(VSUB(x0, x5), 0.60134488f); + x[5] = VMUL_S(VADD(x0, x5), 0.89997619f); + x[6] = VMUL_S(VSUB(x4, x3), 1.30656302f); + x[7] = VMUL_S(VSUB(xt, x7), 2.56291556f); + } + + if (k > n - 3) + { +#if HAVE_SSE +#define VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v) +#else /* HAVE_SSE */ +#define VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v)) +#endif /* HAVE_SSE */ + for (i = 0; i < 7; i++, y += 4*18) + { + f4 s = VADD(t[3][i], t[3][i + 1]); + VSAVE2(0, t[0][i]); + VSAVE2(1, VADD(t[2][i], s)); + VSAVE2(2, VADD(t[1][i], t[1][i + 1])); + VSAVE2(3, VADD(t[2][1 + i], s)); + } + VSAVE2(0, t[0][7]); + VSAVE2(1, VADD(t[2][7], t[3][7])); + VSAVE2(2, t[1][7]); + VSAVE2(3, t[3][7]); + } else + { +#define VSAVE4(i, v) VSTORE(&y[i*18], v) + for (i = 0; i < 7; i++, y += 4*18) + { + f4 s = VADD(t[3][i], t[3][i + 1]); + VSAVE4(0, t[0][i]); + VSAVE4(1, VADD(t[2][i], s)); + VSAVE4(2, VADD(t[1][i], t[1][i + 1])); + VSAVE4(3, VADD(t[2][1 + i], s)); + } + VSAVE4(0, t[0][7]); + VSAVE4(1, VADD(t[2][7], t[3][7])); + VSAVE4(2, t[1][7]); + VSAVE4(3, t[3][7]); + } + } else +#endif /* HAVE_SIMD */ +#ifdef MINIMP3_ONLY_SIMD + {} +#else /* MINIMP3_ONLY_SIMD */ + for (; k < n; k++) + { + float t[4][8], *x, *y = grbuf + k; + + for (x = t[0], i = 0; i < 8; i++, x++) + { + float x0 = y[i*18]; + float x1 = y[(15 - i)*18]; + float x2 = y[(16 + i)*18]; + float x3 = y[(31 - i)*18]; + float t0 = x0 + x3; + float t1 = x1 + x2; + float t2 = (x1 - x2)*g_sec[3*i + 0]; + float t3 = (x0 - x3)*g_sec[3*i + 1]; + x[0] = t0 + t1; + x[8] = (t0 - t1)*g_sec[3*i + 2]; + x[16] = t3 + t2; + x[24] = (t3 - t2)*g_sec[3*i + 2]; + } + for (x = t[0], i = 0; i < 4; i++, x += 8) + { + float x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; + xt = x0 - x7; x0 += x7; + x7 = x1 - x6; x1 += x6; + x6 = x2 - x5; x2 += x5; + x5 = x3 - x4; x3 += x4; + x4 = x0 - x3; x0 += x3; + x3 = x1 - x2; x1 += x2; + x[0] = x0 + x1; + x[4] = (x0 - x1)*0.70710677f; + x5 = x5 + x6; + x6 = (x6 + x7)*0.70710677f; + x7 = x7 + xt; + x3 = (x3 + x4)*0.70710677f; + x5 -= x7*0.198912367f; /* rotate by PI/8 */ + x7 += x5*0.382683432f; + x5 -= x7*0.198912367f; + x0 = xt - x6; xt += x6; + x[1] = (xt + x7)*0.50979561f; + x[2] = (x4 + x3)*0.54119611f; + x[3] = (x0 - x5)*0.60134488f; + x[5] = (x0 + x5)*0.89997619f; + x[6] = (x4 - x3)*1.30656302f; + x[7] = (xt - x7)*2.56291556f; + + } + for (i = 0; i < 7; i++, y += 4*18) + { + y[0*18] = t[0][i]; + y[1*18] = t[2][i] + t[3][i] + t[3][i + 1]; + y[2*18] = t[1][i] + t[1][i + 1]; + y[3*18] = t[2][i + 1] + t[3][i] + t[3][i + 1]; + } + y[0*18] = t[0][7]; + y[1*18] = t[2][7] + t[3][7]; + y[2*18] = t[1][7]; + y[3*18] = t[3][7]; + } +#endif /* MINIMP3_ONLY_SIMD */ +} + +#ifndef MINIMP3_FLOAT_OUTPUT +static int16_t mp3d_scale_pcm(float sample) +{ +#if HAVE_ARMV6 + int32_t s32 = (int32_t)(sample + .5f); + s32 -= (s32 < 0); + int16_t s = (int16_t)minimp3_clip_int16_arm(s32); +#else + if (sample >= 32766.5) return (int16_t) 32767; + if (sample <= -32767.5) return (int16_t)-32768; + int16_t s = (int16_t)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ +#endif + return s; +} +#else /* MINIMP3_FLOAT_OUTPUT */ +static float mp3d_scale_pcm(float sample) +{ + return sample*(1.f/32768.f); +} +#endif /* MINIMP3_FLOAT_OUTPUT */ + +static void mp3d_synth_pair(mp3d_sample_t *pcm, int nch, const float *z) +{ + float a; + a = (z[14*64] - z[ 0]) * 29; + a += (z[ 1*64] + z[13*64]) * 213; + a += (z[12*64] - z[ 2*64]) * 459; + a += (z[ 3*64] + z[11*64]) * 2037; + a += (z[10*64] - z[ 4*64]) * 5153; + a += (z[ 5*64] + z[ 9*64]) * 6574; + a += (z[ 8*64] - z[ 6*64]) * 37489; + a += z[ 7*64] * 75038; + pcm[0] = mp3d_scale_pcm(a); + + z += 2; + a = z[14*64] * 104; + a += z[12*64] * 1567; + a += z[10*64] * 9727; + a += z[ 8*64] * 64019; + a += z[ 6*64] * -9975; + a += z[ 4*64] * -45; + a += z[ 2*64] * 146; + a += z[ 0*64] * -5; + pcm[16*nch] = mp3d_scale_pcm(a); +} + +static void mp3d_synth(float *xl, mp3d_sample_t *dstl, int nch, float *lins) +{ + int i; + float *xr = xl + 576*(nch - 1); + mp3d_sample_t *dstr = dstl + (nch - 1); + + static const float g_win[] = { + -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992, + -1,24,-35,202,222,347,-581,2080,1952,4425,-5879,7640,5288,33791,-41176,74856, + -1,21,-38,196,225,294,-645,2087,1893,4063,-6237,8092,4561,31947,-43006,74630, + -1,19,-41,190,227,244,-711,2085,1822,3705,-6589,8492,3776,30112,-44821,74313, + -1,17,-45,183,228,197,-779,2075,1739,3351,-6935,8840,2935,28289,-46617,73908, + -1,16,-49,176,228,153,-848,2057,1644,3004,-7271,9139,2037,26482,-48390,73415, + -2,14,-53,169,227,111,-919,2032,1535,2663,-7597,9389,1082,24694,-50137,72835, + -2,13,-58,161,224,72,-991,2001,1414,2330,-7910,9592,70,22929,-51853,72169, + -2,11,-63,154,221,36,-1064,1962,1280,2006,-8209,9750,-998,21189,-53534,71420, + -2,10,-68,147,215,2,-1137,1919,1131,1692,-8491,9863,-2122,19478,-55178,70590, + -3,9,-73,139,208,-29,-1210,1870,970,1388,-8755,9935,-3300,17799,-56778,69679, + -3,8,-79,132,200,-57,-1283,1817,794,1095,-8998,9966,-4533,16155,-58333,68692, + -4,7,-85,125,189,-83,-1356,1759,605,814,-9219,9959,-5818,14548,-59838,67629, + -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494, + -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290 + }; + float *zlin = lins + 15*64; + const float *w = g_win; + + zlin[4*15] = xl[18*16]; + zlin[4*15 + 1] = xr[18*16]; + zlin[4*15 + 2] = xl[0]; + zlin[4*15 + 3] = xr[0]; + + zlin[4*31] = xl[1 + 18*16]; + zlin[4*31 + 1] = xr[1 + 18*16]; + zlin[4*31 + 2] = xl[1]; + zlin[4*31 + 3] = xr[1]; + + mp3d_synth_pair(dstr, nch, lins + 4*15 + 1); + mp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1); + mp3d_synth_pair(dstl, nch, lins + 4*15); + mp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64); + +#if HAVE_SIMD + if (have_simd()) for (i = 14; i >= 0; i--) + { +#define VLOAD(k) f4 w0 = VSET(*w++); f4 w1 = VSET(*w++); f4 vz = VLD(&zlin[4*i - 64*k]); f4 vy = VLD(&zlin[4*i - 64*(15 - k)]); +#define V0(k) { VLOAD(k) b = VADD(VMUL(vz, w1), VMUL(vy, w0)) ; a = VSUB(VMUL(vz, w0), VMUL(vy, w1)); } +#define V1(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vz, w0), VMUL(vy, w1))); } +#define V2(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vy, w1), VMUL(vz, w0))); } + f4 a, b; + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*i + 64] = xl[1 + 18*(1 + i)]; + zlin[4*i + 64 + 1] = xr[1 + 18*(1 + i)]; + zlin[4*i - 64 + 2] = xl[18*(1 + i)]; + zlin[4*i - 64 + 3] = xr[18*(1 + i)]; + + V0(0) V2(1) V1(2) V2(3) V1(4) V2(5) V1(6) V2(7) + + { +#ifndef MINIMP3_FLOAT_OUTPUT +#if HAVE_SSE + static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + dstr[(15 - i)*nch] = _mm_extract_epi16(pcm8, 1); + dstr[(17 + i)*nch] = _mm_extract_epi16(pcm8, 5); + dstl[(15 - i)*nch] = _mm_extract_epi16(pcm8, 0); + dstl[(17 + i)*nch] = _mm_extract_epi16(pcm8, 4); + dstr[(47 - i)*nch] = _mm_extract_epi16(pcm8, 3); + dstr[(49 + i)*nch] = _mm_extract_epi16(pcm8, 7); + dstl[(47 - i)*nch] = _mm_extract_epi16(pcm8, 2); + dstl[(49 + i)*nch] = _mm_extract_epi16(pcm8, 6); +#else /* HAVE_SSE */ + int16x4_t pcma, pcmb; + a = VADD(a, VSET(0.5f)); + b = VADD(b, VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); + vst1_lane_s16(dstr + (15 - i)*nch, pcma, 1); + vst1_lane_s16(dstr + (17 + i)*nch, pcmb, 1); + vst1_lane_s16(dstl + (15 - i)*nch, pcma, 0); + vst1_lane_s16(dstl + (17 + i)*nch, pcmb, 0); + vst1_lane_s16(dstr + (47 - i)*nch, pcma, 3); + vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3); + vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2); + vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); +#endif /* HAVE_SSE */ + +#else /* MINIMP3_FLOAT_OUTPUT */ + + static const f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; + a = VMUL(a, g_scale); + b = VMUL(b, g_scale); +#if HAVE_SSE + _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2))); + _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2))); +#else /* HAVE_SSE */ + vst1q_lane_f32(dstr + (15 - i)*nch, a, 1); + vst1q_lane_f32(dstr + (17 + i)*nch, b, 1); + vst1q_lane_f32(dstl + (15 - i)*nch, a, 0); + vst1q_lane_f32(dstl + (17 + i)*nch, b, 0); + vst1q_lane_f32(dstr + (47 - i)*nch, a, 3); + vst1q_lane_f32(dstr + (49 + i)*nch, b, 3); + vst1q_lane_f32(dstl + (47 - i)*nch, a, 2); + vst1q_lane_f32(dstl + (49 + i)*nch, b, 2); +#endif /* HAVE_SSE */ +#endif /* MINIMP3_FLOAT_OUTPUT */ + } + } else +#endif /* HAVE_SIMD */ +#ifdef MINIMP3_ONLY_SIMD + {} +#else /* MINIMP3_ONLY_SIMD */ + for (i = 14; i >= 0; i--) + { +#define LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64]; +#define S0(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j]*w1 + vy[j]*w0, a[j] = vz[j]*w0 - vy[j]*w1; } +#define S1(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; } +#define S2(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; } + float a[4], b[4]; + + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*(i + 16)] = xl[1 + 18*(1 + i)]; + zlin[4*(i + 16) + 1] = xr[1 + 18*(1 + i)]; + zlin[4*(i - 16) + 2] = xl[18*(1 + i)]; + zlin[4*(i - 16) + 3] = xr[18*(1 + i)]; + + S0(0) S2(1) S1(2) S2(3) S1(4) S2(5) S1(6) S2(7) + + dstr[(15 - i)*nch] = mp3d_scale_pcm(a[1]); + dstr[(17 + i)*nch] = mp3d_scale_pcm(b[1]); + dstl[(15 - i)*nch] = mp3d_scale_pcm(a[0]); + dstl[(17 + i)*nch] = mp3d_scale_pcm(b[0]); + dstr[(47 - i)*nch] = mp3d_scale_pcm(a[3]); + dstr[(49 + i)*nch] = mp3d_scale_pcm(b[3]); + dstl[(47 - i)*nch] = mp3d_scale_pcm(a[2]); + dstl[(49 + i)*nch] = mp3d_scale_pcm(b[2]); + } +#endif /* MINIMP3_ONLY_SIMD */ +} + +static void mp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, mp3d_sample_t *pcm, float *lins) +{ + int i; + for (i = 0; i < nch; i++) + { + mp3d_DCT_II(grbuf + 576*i, nbands); + } + + memcpy(lins, qmf_state, sizeof(float)*15*64); + + for (i = 0; i < nbands; i += 2) + { + mp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64); + } +#ifndef MINIMP3_NONSTANDARD_BUT_LOGICAL + if (nch == 1) + { + for (i = 0; i < 15*64; i += 2) + { + qmf_state[i] = lins[nbands*64 + i]; + } + } else +#endif /* MINIMP3_NONSTANDARD_BUT_LOGICAL */ + { + memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64); + } +} + +static int mp3d_match_frame(const uint8_t *hdr, int mp3_bytes, int frame_bytes) +{ + int i, nmatch; + for (i = 0, nmatch = 0; nmatch < MAX_FRAME_SYNC_MATCHES; nmatch++) + { + i += hdr_frame_bytes(hdr + i, frame_bytes) + hdr_padding(hdr + i); + if (i + HDR_SIZE > mp3_bytes) + return nmatch > 0; + if (!hdr_compare(hdr, hdr + i)) + return 0; + } + return 1; +} + +static int mp3d_find_frame(const uint8_t *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes) +{ + int i, k; + for (i = 0; i < mp3_bytes - HDR_SIZE; i++, mp3++) + { + if (hdr_valid(mp3)) + { + int frame_bytes = hdr_frame_bytes(mp3, *free_format_bytes); + int frame_and_padding = frame_bytes + hdr_padding(mp3); + + for (k = HDR_SIZE; !frame_bytes && k < MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - HDR_SIZE; k++) + { + if (hdr_compare(mp3, mp3 + k)) + { + int fb = k - hdr_padding(mp3); + int nextfb = fb + hdr_padding(mp3 + k); + if (i + k + nextfb + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + k + nextfb)) + continue; + frame_and_padding = k; + frame_bytes = fb; + *free_format_bytes = fb; + } + } + if ((frame_bytes && i + frame_and_padding <= mp3_bytes && + mp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) || + (!i && frame_and_padding == mp3_bytes)) + { + *ptr_frame_bytes = frame_and_padding; + return i; + } + *free_format_bytes = 0; + } + } + *ptr_frame_bytes = 0; + return mp3_bytes; +} + +void mp3dec_init(mp3dec_t *dec) +{ + dec->header[0] = 0; +} + +int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info) +{ + int i = 0, igr, frame_size = 0, success = 1; + const uint8_t *hdr; + bs_t bs_frame[1]; + mp3dec_scratch_t scratch; + + if (mp3_bytes > 4 && dec->header[0] == 0xff && hdr_compare(dec->header, mp3)) + { + frame_size = hdr_frame_bytes(mp3, dec->free_format_bytes) + hdr_padding(mp3); + if (frame_size != mp3_bytes && (frame_size + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + frame_size))) + { + frame_size = 0; + } + } + if (!frame_size) + { + memset(dec, 0, sizeof(mp3dec_t)); + i = mp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); + if (!frame_size || i + frame_size > mp3_bytes) + { + info->frame_bytes = i; + return 0; + } + } + + hdr = mp3 + i; + memcpy(dec->header, hdr, HDR_SIZE); + info->frame_bytes = i + frame_size; + info->frame_offset = i; + info->channels = HDR_IS_MONO(hdr) ? 1 : 2; + info->hz = hdr_sample_rate_hz(hdr); + info->layer = 4 - HDR_GET_LAYER(hdr); + info->bitrate_kbps = hdr_bitrate_kbps(hdr); + + if (!pcm) + { + return hdr_frame_samples(hdr); + } + + bs_init(bs_frame, hdr + HDR_SIZE, frame_size - HDR_SIZE); + if (HDR_IS_CRC(hdr)) + { + get_bits(bs_frame, 16); + } + + if (info->layer == 3) + { + int main_data_begin = L3_read_side_info(bs_frame, scratch.gr_info, hdr); + if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit) + { + mp3dec_init(dec); + return 0; + } + success = L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); + if (success) + { + for (igr = 0; igr < (HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm += 576*info->channels) + { + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); + mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, pcm, scratch.syn[0]); + } + } + L3_save_reservoir(dec, &scratch); + } else + { +#ifdef MINIMP3_ONLY_MP3 + return 0; +#else /* MINIMP3_ONLY_MP3 */ + L12_scale_info sci[1]; + L12_read_scale_info(hdr, bs_frame, sci); + + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + for (i = 0, igr = 0; igr < 3; igr++) + { + if (12 == (i += L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) + { + i = 0; + L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); + mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, pcm, scratch.syn[0]); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + pcm += 384*info->channels; + } + if (bs_frame->pos > bs_frame->limit) + { + mp3dec_init(dec); + return 0; + } + } +#endif /* MINIMP3_ONLY_MP3 */ + } + return success*hdr_frame_samples(dec->header); +} + +#ifdef MINIMP3_FLOAT_OUTPUT +void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples) +{ + int i = 0; +#if HAVE_SIMD + int aligned_count = num_samples & ~7; + for(; i < aligned_count; i += 8) + { + static const f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f }; + f4 a = VMUL(VLD(&in[i ]), g_scale); + f4 b = VMUL(VLD(&in[i+4]), g_scale); +#if HAVE_SSE + static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + out[i ] = _mm_extract_epi16(pcm8, 0); + out[i+1] = _mm_extract_epi16(pcm8, 1); + out[i+2] = _mm_extract_epi16(pcm8, 2); + out[i+3] = _mm_extract_epi16(pcm8, 3); + out[i+4] = _mm_extract_epi16(pcm8, 4); + out[i+5] = _mm_extract_epi16(pcm8, 5); + out[i+6] = _mm_extract_epi16(pcm8, 6); + out[i+7] = _mm_extract_epi16(pcm8, 7); +#else /* HAVE_SSE */ + int16x4_t pcma, pcmb; + a = VADD(a, VSET(0.5f)); + b = VADD(b, VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); + vst1_lane_s16(out+i , pcma, 0); + vst1_lane_s16(out+i+1, pcma, 1); + vst1_lane_s16(out+i+2, pcma, 2); + vst1_lane_s16(out+i+3, pcma, 3); + vst1_lane_s16(out+i+4, pcmb, 0); + vst1_lane_s16(out+i+5, pcmb, 1); + vst1_lane_s16(out+i+6, pcmb, 2); + vst1_lane_s16(out+i+7, pcmb, 3); +#endif /* HAVE_SSE */ + } +#endif /* HAVE_SIMD */ + for(; i < num_samples; i++) + { + float sample = in[i] * 32768.0f; + if (sample >= 32766.5) + out[i] = (int16_t) 32767; + else if (sample <= -32767.5) + out[i] = (int16_t)-32768; + else + { + int16_t s = (int16_t)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ + out[i] = s; + } + } +} +#endif /* MINIMP3_FLOAT_OUTPUT */ +#endif /* MINIMP3_IMPLEMENTATION && !_MINIMP3_IMPLEMENTATION_GUARD */ diff --git a/thirdparty/minimp3/minimp3_ex.h b/thirdparty/minimp3/minimp3_ex.h new file mode 100644 index 0000000000..e29dd15b2e --- /dev/null +++ b/thirdparty/minimp3/minimp3_ex.h @@ -0,0 +1,1394 @@ +#ifndef MINIMP3_EXT_H +#define MINIMP3_EXT_H +/* + https://github.com/lieff/minimp3 + To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. + This software is distributed without any warranty. + See <http://creativecommons.org/publicdomain/zero/1.0/>. +*/ +#include "minimp3.h" + +/* flags for mp3dec_ex_open_* functions */ +#define MP3D_SEEK_TO_BYTE 0 /* mp3dec_ex_seek seeks to byte in stream */ +#define MP3D_SEEK_TO_SAMPLE 1 /* mp3dec_ex_seek precisely seeks to sample using index (created during duration calculation scan or when mp3dec_ex_seek called) */ +#define MP3D_DO_NOT_SCAN 2 /* do not scan whole stream for duration if vbrtag not found, mp3dec_ex_t::samples will be filled only if mp3dec_ex_t::vbr_tag_found == 1 */ +#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION +#define MP3D_ALLOW_MONO_STEREO_TRANSITION 4 +#define MP3D_FLAGS_MASK 7 +#else +#define MP3D_FLAGS_MASK 3 +#endif + +/* compile-time config */ +#define MINIMP3_PREDECODE_FRAMES 2 /* frames to pre-decode and skip after seek (to fill internal structures) */ +/*#define MINIMP3_SEEK_IDX_LINEAR_SEARCH*/ /* define to use linear index search instead of binary search on seek */ +#define MINIMP3_IO_SIZE (128*1024) /* io buffer size for streaming functions, must be greater than MINIMP3_BUF_SIZE */ +#define MINIMP3_BUF_SIZE (16*1024) /* buffer which can hold minimum 10 consecutive mp3 frames (~16KB) worst case */ +/*#define MINIMP3_SCAN_LIMIT (256*1024)*/ /* how many bytes will be scanned to search first valid mp3 frame, to prevent stall on large non-mp3 files */ +#define MINIMP3_ENABLE_RING 0 /* WIP enable hardware magic ring buffer if available, to make less input buffer memmove(s) in callback IO mode */ + +/* return error codes */ +#define MP3D_E_PARAM -1 +#define MP3D_E_MEMORY -2 +#define MP3D_E_IOERROR -3 +#define MP3D_E_USER -4 /* can be used to stop processing from callbacks without indicating specific error */ +#define MP3D_E_DECODE -5 /* decode error which can't be safely skipped, such as sample rate, layer and channels change */ + +typedef struct +{ + mp3d_sample_t *buffer; + size_t samples; /* channels included, byte size = samples*sizeof(mp3d_sample_t) */ + int channels, hz, layer, avg_bitrate_kbps; +} mp3dec_file_info_t; + +typedef struct +{ + const uint8_t *buffer; + size_t size; +} mp3dec_map_info_t; + +typedef struct +{ + uint64_t sample; + uint64_t offset; +} mp3dec_frame_t; + +typedef struct +{ + mp3dec_frame_t *frames; + size_t num_frames, capacity; +} mp3dec_index_t; + +typedef size_t (*MP3D_READ_CB)(void *buf, size_t size, void *user_data); +typedef int (*MP3D_SEEK_CB)(uint64_t position, void *user_data); + +typedef struct +{ + MP3D_READ_CB read; + void *read_data; + MP3D_SEEK_CB seek; + void *seek_data; +} mp3dec_io_t; + +typedef struct +{ + mp3dec_t mp3d; + mp3dec_map_info_t file; + mp3dec_io_t *io; + mp3dec_index_t index; + uint64_t offset, samples, detected_samples, cur_sample, start_offset, end_offset; + mp3dec_frame_info_t info; + mp3d_sample_t buffer[MINIMP3_MAX_SAMPLES_PER_FRAME]; + size_t input_consumed, input_filled; + int is_file, flags, vbr_tag_found, indexes_built; + int free_format_bytes; + int buffer_samples, buffer_consumed, to_skip, start_delay; + int last_error; +} mp3dec_ex_t; + +typedef int (*MP3D_ITERATE_CB)(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info); +typedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, uint64_t offset, mp3dec_frame_info_t *info); + +#ifdef __cplusplus +extern "C" { +#endif + +/* detect mp3/mpa format */ +int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size); +int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size); +/* decode whole buffer block */ +int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +/* iterate through frames */ +int mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data); +int mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data); +/* streaming decoder with seeking capability */ +int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int flags); +int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int flags); +void mp3dec_ex_close(mp3dec_ex_t *dec); +int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position); +size_t mp3dec_ex_read_frame(mp3dec_ex_t *dec, mp3d_sample_t **buf, mp3dec_frame_info_t *frame_info, size_t max_samples); +size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples); +#ifndef MINIMP3_NO_STDIO +/* stdio versions of file detect, load, iterate and stream */ +int mp3dec_detect(const char *file_name); +int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data); +int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int flags); +#ifdef _WIN32 +int mp3dec_detect_w(const wchar_t *file_name); +int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data); +int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int flags); +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif /*MINIMP3_EXT_H*/ + +#ifdef MINIMP3_IMPLEMENTATION +#include <limits.h> + +static void mp3dec_skip_id3v1(const uint8_t *buf, size_t *pbuf_size) +{ + size_t buf_size = *pbuf_size; +#ifndef MINIMP3_NOSKIP_ID3V1 + if (buf_size >= 128 && !memcmp(buf + buf_size - 128, "TAG", 3)) + { + buf_size -= 128; + if (buf_size >= 227 && !memcmp(buf + buf_size - 227, "TAG+", 4)) + buf_size -= 227; + } +#endif +#ifndef MINIMP3_NOSKIP_APEV2 + if (buf_size > 32 && !memcmp(buf + buf_size - 32, "APETAGEX", 8)) + { + buf_size -= 32; + const uint8_t *tag = buf + buf_size + 8 + 4; + uint32_t tag_size = (uint32_t)(tag[3] << 24) | (tag[2] << 16) | (tag[1] << 8) | tag[0]; + if (buf_size >= tag_size) + buf_size -= tag_size; + } +#endif + *pbuf_size = buf_size; +} + +static size_t mp3dec_skip_id3v2(const uint8_t *buf, size_t buf_size) +{ +#define MINIMP3_ID3_DETECT_SIZE 10 +#ifndef MINIMP3_NOSKIP_ID3V2 + if (buf_size >= MINIMP3_ID3_DETECT_SIZE && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80))) + { + size_t id3v2size = (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10; + if ((buf[5] & 16)) + id3v2size += 10; /* footer */ + return id3v2size; + } +#endif + return 0; +} + +static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size) +{ + uint8_t *buf = (uint8_t *)(*pbuf); + size_t buf_size = *pbuf_size; + size_t id3v2size = mp3dec_skip_id3v2(buf, buf_size); + if (id3v2size) + { + if (id3v2size >= buf_size) + id3v2size = buf_size; + buf += id3v2size; + buf_size -= id3v2size; + } + mp3dec_skip_id3v1(buf, &buf_size); + *pbuf = (const uint8_t *)buf; + *pbuf_size = buf_size; +} + +static int mp3dec_check_vbrtag(const uint8_t *frame, int frame_size, uint32_t *frames, int *delay, int *padding) +{ + static const char g_xing_tag[4] = { 'X', 'i', 'n', 'g' }; + static const char g_info_tag[4] = { 'I', 'n', 'f', 'o' }; +#define FRAMES_FLAG 1 +#define BYTES_FLAG 2 +#define TOC_FLAG 4 +#define VBR_SCALE_FLAG 8 + /* Side info offsets after header: + / Mono Stereo + / MPEG1 17 32 + / MPEG2 & 2.5 9 17*/ + bs_t bs[1]; + L3_gr_info_t gr_info[4]; + bs_init(bs, frame + HDR_SIZE, frame_size - HDR_SIZE); + if (HDR_IS_CRC(frame)) + get_bits(bs, 16); + if (L3_read_side_info(bs, gr_info, frame) < 0) + return 0; /* side info corrupted */ + + const uint8_t *tag = frame + HDR_SIZE + bs->pos/8; + if (memcmp(g_xing_tag, tag, 4) && memcmp(g_info_tag, tag, 4)) + return 0; + int flags = tag[7]; + if (!((flags & FRAMES_FLAG))) + return -1; + tag += 8; + *frames = (uint32_t)(tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3]; + tag += 4; + if (flags & BYTES_FLAG) + tag += 4; + if (flags & TOC_FLAG) + tag += 100; + if (flags & VBR_SCALE_FLAG) + tag += 4; + *delay = *padding = 0; + if (*tag) + { /* extension, LAME, Lavc, etc. Should be the same structure. */ + tag += 21; + if (tag - frame + 14 >= frame_size) + return 0; + *delay = ((tag[0] << 4) | (tag[1] >> 4)) + (528 + 1); + *padding = (((tag[1] & 0xF) << 8) | tag[2]) - (528 + 1); + } + return 1; +} + +int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size) +{ + return mp3dec_detect_cb(0, (uint8_t *)buf, buf_size); +} + +int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size) +{ + if (!buf || (size_t)-1 == buf_size || (io && buf_size < MINIMP3_BUF_SIZE)) + return MP3D_E_PARAM; + size_t filled = buf_size; + if (io) + { + if (io->seek(0, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (filled > MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_IOERROR; + } + if (filled < MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_USER; /* too small, can't be mp3/mpa */ + if (mp3dec_skip_id3v2(buf, filled)) + return 0; /* id3v2 tag is enough evidence */ + if (io) + { + size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) + return MP3D_E_IOERROR; + filled += readed; + if (filled < MINIMP3_BUF_SIZE) + mp3dec_skip_id3v1(buf, &filled); + } else + { + mp3dec_skip_id3v1(buf, &filled); + if (filled > MINIMP3_BUF_SIZE) + filled = MINIMP3_BUF_SIZE; + } + int free_format_bytes, frame_size; + mp3d_find_frame(buf, filled, &free_format_bytes, &frame_size); + if (frame_size) + return 0; /* MAX_FRAME_SYNC_MATCHES consecutive frames found */ + return MP3D_E_USER; +} + +int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + return mp3dec_load_cb(dec, 0, (uint8_t *)buf, buf_size, info, progress_cb, user_data); +} + +int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + if (!dec || !buf || !info || (size_t)-1 == buf_size || (io && buf_size < MINIMP3_BUF_SIZE)) + return MP3D_E_PARAM; + uint64_t detected_samples = 0; + size_t orig_buf_size = buf_size; + int to_skip = 0; + mp3dec_frame_info_t frame_info; + memset(info, 0, sizeof(*info)); + memset(&frame_info, 0, sizeof(frame_info)); + + /* skip id3 */ + size_t filled = 0, consumed = 0; + int eof = 0, ret = 0; + if (io) + { + if (io->seek(0, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (filled > MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_IOERROR; + if (MINIMP3_ID3_DETECT_SIZE != filled) + return 0; + size_t id3v2size = mp3dec_skip_id3v2(buf, filled); + if (id3v2size) + { + if (io->seek(id3v2size, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, buf_size, io->read_data); + if (filled > buf_size) + return MP3D_E_IOERROR; + } else + { + size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) + return MP3D_E_IOERROR; + filled += readed; + } + if (filled < MINIMP3_BUF_SIZE) + mp3dec_skip_id3v1(buf, &filled); + } else + { + mp3dec_skip_id3((const uint8_t **)&buf, &buf_size); + if (!buf_size) + return 0; + } + /* try to make allocation size assumption by first frame or vbr tag */ + mp3dec_init(dec); + int samples; + do + { + uint32_t frames; + int i, delay, padding, free_format_bytes = 0, frame_size = 0; + const uint8_t *hdr; + if (io) + { + if (!eof && filled - consumed < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove(buf, buf + consumed, filled - consumed); + filled -= consumed; + consumed = 0; + size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); + if (readed > (buf_size - filled)) + return MP3D_E_IOERROR; + if (readed != (buf_size - filled)) + eof = 1; + filled += readed; + if (eof) + mp3dec_skip_id3v1(buf, &filled); + } + i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size); + consumed += i; + hdr = buf + consumed; + } else + { + i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); + buf += i; + buf_size -= i; + hdr = buf; + } + if (i && !frame_size) + continue; + if (!frame_size) + return 0; + frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; + frame_info.hz = hdr_sample_rate_hz(hdr); + frame_info.layer = 4 - HDR_GET_LAYER(hdr); + frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); + frame_info.frame_bytes = frame_size; + samples = hdr_frame_samples(hdr)*frame_info.channels; + if (3 != frame_info.layer) + break; + int ret = mp3dec_check_vbrtag(hdr, frame_size, &frames, &delay, &padding); + if (ret > 0) + { + padding *= frame_info.channels; + to_skip = delay*frame_info.channels; + detected_samples = samples*(uint64_t)frames; + if (detected_samples >= (uint64_t)to_skip) + detected_samples -= to_skip; + if (padding > 0 && detected_samples >= (uint64_t)padding) + detected_samples -= padding; + if (!detected_samples) + return 0; + } + if (ret) + { + if (io) + { + consumed += frame_size; + } else + { + buf += frame_size; + buf_size -= frame_size; + } + } + break; + } while(1); + size_t allocated = MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t); + if (detected_samples) + allocated += detected_samples*sizeof(mp3d_sample_t); + else + allocated += (buf_size/frame_info.frame_bytes)*samples*sizeof(mp3d_sample_t); + info->buffer = (mp3d_sample_t*)malloc(allocated); + if (!info->buffer) + return MP3D_E_MEMORY; + /* save info */ + info->channels = frame_info.channels; + info->hz = frame_info.hz; + info->layer = frame_info.layer; + /* decode all frames */ + size_t avg_bitrate_kbps = 0, frames = 0; + do + { + if ((allocated - info->samples*sizeof(mp3d_sample_t)) < MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t)) + { + allocated *= 2; + mp3d_sample_t *alloc_buf = (mp3d_sample_t*)realloc(info->buffer, allocated); + if (!alloc_buf) + return MP3D_E_MEMORY; + info->buffer = alloc_buf; + } + if (io) + { + if (!eof && filled - consumed < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove(buf, buf + consumed, filled - consumed); + filled -= consumed; + consumed = 0; + size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); + if (readed != (buf_size - filled)) + eof = 1; + filled += readed; + if (eof) + mp3dec_skip_id3v1(buf, &filled); + } + samples = mp3dec_decode_frame(dec, buf + consumed, filled - consumed, info->buffer + info->samples, &frame_info); + consumed += frame_info.frame_bytes; + } else + { + samples = mp3dec_decode_frame(dec, buf, MINIMP3_MIN(buf_size, (size_t)INT_MAX), info->buffer + info->samples, &frame_info); + buf += frame_info.frame_bytes; + buf_size -= frame_info.frame_bytes; + } + if (samples) + { + if (info->hz != frame_info.hz || info->layer != frame_info.layer) + { + ret = MP3D_E_DECODE; + break; + } + if (info->channels && info->channels != frame_info.channels) + { +#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION + info->channels = 0; /* mark file with mono-stereo transition */ +#else + ret = MP3D_E_DECODE; + break; +#endif + } + samples *= frame_info.channels; + if (to_skip) + { + size_t skip = MINIMP3_MIN(samples, to_skip); + to_skip -= skip; + samples -= skip; + memmove(info->buffer, info->buffer + skip, samples*sizeof(mp3d_sample_t)); + } + info->samples += samples; + avg_bitrate_kbps += frame_info.bitrate_kbps; + frames++; + if (progress_cb) + { + ret = progress_cb(user_data, orig_buf_size, orig_buf_size - buf_size, &frame_info); + if (ret) + break; + } + } + } while (frame_info.frame_bytes); + if (detected_samples && info->samples > detected_samples) + info->samples = detected_samples; /* cut padding */ + /* reallocate to normal buffer size */ + if (allocated != info->samples*sizeof(mp3d_sample_t)) + { + mp3d_sample_t *alloc_buf = (mp3d_sample_t*)realloc(info->buffer, info->samples*sizeof(mp3d_sample_t)); + if (!alloc_buf && info->samples) + return MP3D_E_MEMORY; + info->buffer = alloc_buf; + } + if (frames) + info->avg_bitrate_kbps = avg_bitrate_kbps/frames; + return ret; +} + +int mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data) +{ + const uint8_t *orig_buf = buf; + if (!buf || (size_t)-1 == buf_size || !callback) + return MP3D_E_PARAM; + /* skip id3 */ + mp3dec_skip_id3(&buf, &buf_size); + if (!buf_size) + return 0; + mp3dec_frame_info_t frame_info; + memset(&frame_info, 0, sizeof(frame_info)); + do + { + int free_format_bytes = 0, frame_size = 0, ret; + int i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); + buf += i; + buf_size -= i; + if (i && !frame_size) + continue; + if (!frame_size) + break; + const uint8_t *hdr = buf; + frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; + frame_info.hz = hdr_sample_rate_hz(hdr); + frame_info.layer = 4 - HDR_GET_LAYER(hdr); + frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); + frame_info.frame_bytes = frame_size; + + if (callback) + { + if ((ret = callback(user_data, hdr, frame_size, free_format_bytes, buf_size, hdr - orig_buf, &frame_info))) + return ret; + } + buf += frame_size; + buf_size -= frame_size; + } while (1); + return 0; +} + +int mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data) +{ + if (!io || !buf || (size_t)-1 == buf_size || buf_size < MINIMP3_BUF_SIZE || !callback) + return MP3D_E_PARAM; + size_t filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data), consumed = 0; + uint64_t readed = 0; + mp3dec_frame_info_t frame_info; + int eof = 0; + memset(&frame_info, 0, sizeof(frame_info)); + if (filled > MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_IOERROR; + if (MINIMP3_ID3_DETECT_SIZE != filled) + return 0; + size_t id3v2size = mp3dec_skip_id3v2(buf, filled); + if (id3v2size) + { + if (io->seek(id3v2size, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, buf_size, io->read_data); + if (filled > buf_size) + return MP3D_E_IOERROR; + readed += id3v2size; + } else + { + size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) + return MP3D_E_IOERROR; + filled += readed; + } + if (filled < MINIMP3_BUF_SIZE) + mp3dec_skip_id3v1(buf, &filled); + do + { + int free_format_bytes = 0, frame_size = 0, ret; + int i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size); + if (i && !frame_size) + { + consumed += i; + continue; + } + if (!frame_size) + break; + const uint8_t *hdr = buf + consumed + i; + frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; + frame_info.hz = hdr_sample_rate_hz(hdr); + frame_info.layer = 4 - HDR_GET_LAYER(hdr); + frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); + frame_info.frame_bytes = frame_size; + + readed += i; + if (callback) + { + if ((ret = callback(user_data, hdr, frame_size, free_format_bytes, filled - consumed, readed, &frame_info))) + return ret; + } + readed += frame_size; + consumed += i + frame_size; + if (!eof && filled - consumed < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove(buf, buf + consumed, filled - consumed); + filled -= consumed; + consumed = 0; + size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); + if (readed > (buf_size - filled)) + return MP3D_E_IOERROR; + if (readed != (buf_size - filled)) + eof = 1; + filled += readed; + if (eof) + mp3dec_skip_id3v1(buf, &filled); + } + } while (1); + return 0; +} + +static int mp3dec_load_index(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info) +{ + mp3dec_frame_t *idx_frame; + mp3dec_ex_t *dec = (mp3dec_ex_t *)user_data; + if (!dec->index.frames && !dec->start_offset) + { /* detect VBR tag and try to avoid full scan */ + uint32_t frames; + int delay, padding; + dec->info = *info; + dec->start_offset = dec->offset = offset; + dec->end_offset = offset + buf_size; + dec->free_format_bytes = free_format_bytes; /* should not change */ + if (3 == dec->info.layer) + { + int ret = mp3dec_check_vbrtag(frame, frame_size, &frames, &delay, &padding); + if (ret) + dec->start_offset = dec->offset = offset + frame_size; + if (ret > 0) + { + padding *= info->channels; + dec->start_delay = dec->to_skip = delay*info->channels; + dec->samples = hdr_frame_samples(frame)*info->channels*(uint64_t)frames; + if (dec->samples >= (uint64_t)dec->start_delay) + dec->samples -= dec->start_delay; + if (padding > 0 && dec->samples >= (uint64_t)padding) + dec->samples -= padding; + dec->detected_samples = dec->samples; + dec->vbr_tag_found = 1; + return MP3D_E_USER; + } else if (ret < 0) + return 0; + } + } + if (dec->flags & MP3D_DO_NOT_SCAN) + return MP3D_E_USER; + if (dec->index.num_frames + 1 > dec->index.capacity) + { + if (!dec->index.capacity) + dec->index.capacity = 4096; + else + dec->index.capacity *= 2; + mp3dec_frame_t *alloc_buf = (mp3dec_frame_t *)realloc((void*)dec->index.frames, sizeof(mp3dec_frame_t)*dec->index.capacity); + if (!alloc_buf) + return MP3D_E_MEMORY; + dec->index.frames = alloc_buf; + } + idx_frame = &dec->index.frames[dec->index.num_frames++]; + idx_frame->offset = offset; + idx_frame->sample = dec->samples; + if (!dec->buffer_samples && dec->index.num_frames < 256) + { /* for some cutted mp3 frames, bit-reservoir not filled and decoding can't be started from first frames */ + /* try to decode up to 255 first frames till samples starts to decode */ + dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, frame, MINIMP3_MIN(buf_size, (size_t)INT_MAX), dec->buffer, info); + dec->samples += dec->buffer_samples*info->channels; + } else + dec->samples += hdr_frame_samples(frame)*info->channels; + return 0; +} + +int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int flags) +{ + if (!dec || !buf || (size_t)-1 == buf_size || (flags & (~MP3D_FLAGS_MASK))) + return MP3D_E_PARAM; + memset(dec, 0, sizeof(*dec)); + dec->file.buffer = buf; + dec->file.size = buf_size; + dec->flags = flags; + mp3dec_init(&dec->mp3d); + int ret = mp3dec_iterate_buf(dec->file.buffer, dec->file.size, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + mp3dec_init(&dec->mp3d); + dec->buffer_samples = 0; + dec->indexes_built = !(dec->vbr_tag_found || (flags & MP3D_DO_NOT_SCAN)); + dec->flags &= (~MP3D_DO_NOT_SCAN); + return 0; +} + +#ifndef MINIMP3_SEEK_IDX_LINEAR_SEARCH +static size_t mp3dec_idx_binary_search(mp3dec_index_t *idx, uint64_t position) +{ + size_t end = idx->num_frames, start = 0, index = 0; + while (start <= end) + { + size_t mid = (start + end) / 2; + if (idx->frames[mid].sample >= position) + { /* move left side. */ + if (idx->frames[mid].sample == position) + return mid; + end = mid - 1; + } else + { /* move to right side */ + index = mid; + start = mid + 1; + if (start == idx->num_frames) + break; + } + } + return index; +} +#endif + +int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position) +{ + size_t i; + if (!dec) + return MP3D_E_PARAM; + if (!(dec->flags & MP3D_SEEK_TO_SAMPLE)) + { + if (dec->io) + { + dec->offset = position; + } else + { + dec->offset = MINIMP3_MIN(position, dec->file.size); + } + dec->cur_sample = 0; + goto do_exit; + } + dec->cur_sample = position; + position += dec->start_delay; + if (0 == position) + { /* optimize seek to zero, no index needed */ +seek_zero: + dec->offset = dec->start_offset; + dec->to_skip = 0; + goto do_exit; + } + if (!dec->indexes_built) + { /* no index created yet (vbr tag used to calculate track length or MP3D_DO_NOT_SCAN open flag used) */ + dec->indexes_built = 1; + dec->samples = 0; + dec->buffer_samples = 0; + if (dec->io) + { + if (dec->io->seek(dec->start_offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + int ret = mp3dec_iterate_cb(dec->io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + } else + { + int ret = mp3dec_iterate_buf(dec->file.buffer + dec->start_offset, dec->file.size - dec->start_offset, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + } + for (i = 0; i < dec->index.num_frames; i++) + dec->index.frames[i].offset += dec->start_offset; + dec->samples = dec->detected_samples; + } + if (!dec->index.frames) + goto seek_zero; /* no frames in file - seek to zero */ +#ifdef MINIMP3_SEEK_IDX_LINEAR_SEARCH + for (i = 0; i < dec->index.num_frames; i++) + { + if (dec->index.frames[i].sample >= position) + break; + } +#else + i = mp3dec_idx_binary_search(&dec->index, position); +#endif + if (i) + { + int to_fill_bytes = 511; + int skip_frames = MINIMP3_PREDECODE_FRAMES +#ifdef MINIMP3_SEEK_IDX_LINEAR_SEARCH + + ((dec->index.frames[i].sample == position) ? 0 : 1) +#endif + ; + i -= MINIMP3_MIN(i, (size_t)skip_frames); + if (3 == dec->info.layer) + { + while (i && to_fill_bytes) + { /* make sure bit-reservoir is filled when we start decoding */ + bs_t bs[1]; + L3_gr_info_t gr_info[4]; + int frame_bytes, frame_size; + const uint8_t *hdr; + if (dec->io) + { + hdr = dec->file.buffer; + if (dec->io->seek(dec->index.frames[i - 1].offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + size_t readed = dec->io->read((uint8_t *)hdr, HDR_SIZE, dec->io->read_data); + if (readed != HDR_SIZE) + return MP3D_E_IOERROR; + frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr); + readed = dec->io->read((uint8_t *)hdr + HDR_SIZE, frame_size - HDR_SIZE, dec->io->read_data); + if (readed != (size_t)(frame_size - HDR_SIZE)) + return MP3D_E_IOERROR; + bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE); + } else + { + hdr = dec->file.buffer + dec->index.frames[i - 1].offset; + frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr); + bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE); + } + if (HDR_IS_CRC(hdr)) + get_bits(bs, 16); + i--; + if (L3_read_side_info(bs, gr_info, hdr) < 0) + break; /* frame not decodable, we can start from here */ + frame_bytes = (bs->limit - bs->pos)/8; + to_fill_bytes -= MINIMP3_MIN(to_fill_bytes, frame_bytes); + } + } + } + dec->offset = dec->index.frames[i].offset; + dec->to_skip = position - dec->index.frames[i].sample; + while ((i + 1) < dec->index.num_frames && !dec->index.frames[i].sample && !dec->index.frames[i + 1].sample) + { /* skip not decodable first frames */ + const uint8_t *hdr; + if (dec->io) + { + hdr = dec->file.buffer; + if (dec->io->seek(dec->index.frames[i].offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + size_t readed = dec->io->read((uint8_t *)hdr, HDR_SIZE, dec->io->read_data); + if (readed != HDR_SIZE) + return MP3D_E_IOERROR; + } else + hdr = dec->file.buffer + dec->index.frames[i].offset; + dec->to_skip += hdr_frame_samples(hdr)*dec->info.channels; + i++; + } +do_exit: + if (dec->io) + { + if (dec->io->seek(dec->offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + } + dec->buffer_samples = 0; + dec->buffer_consumed = 0; + dec->input_consumed = 0; + dec->input_filled = 0; + dec->last_error = 0; + mp3dec_init(&dec->mp3d); + return 0; +} + +size_t mp3dec_ex_read_frame(mp3dec_ex_t *dec, mp3d_sample_t **buf, mp3dec_frame_info_t *frame_info, size_t max_samples) +{ + if (!dec || !buf || !frame_info) + { + if (dec) + dec->last_error = MP3D_E_PARAM; + return 0; + } + if (dec->detected_samples && dec->cur_sample >= dec->detected_samples) + return 0; /* at end of stream */ + if (dec->last_error) + return 0; /* error eof state, seek can reset it */ + *buf = NULL; + uint64_t end_offset = dec->end_offset ? dec->end_offset : dec->file.size; + int eof = 0; + while (dec->buffer_consumed == dec->buffer_samples) + { + const uint8_t *dec_buf; + if (dec->io) + { + if (!eof && (dec->input_filled - dec->input_consumed) < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove((uint8_t*)dec->file.buffer, (uint8_t*)dec->file.buffer + dec->input_consumed, dec->input_filled - dec->input_consumed); + dec->input_filled -= dec->input_consumed; + dec->input_consumed = 0; + size_t readed = dec->io->read((uint8_t*)dec->file.buffer + dec->input_filled, dec->file.size - dec->input_filled, dec->io->read_data); + if (readed > (dec->file.size - dec->input_filled)) + { + dec->last_error = MP3D_E_IOERROR; + readed = 0; + } + if (readed != (dec->file.size - dec->input_filled)) + eof = 1; + dec->input_filled += readed; + if (eof) + mp3dec_skip_id3v1((uint8_t*)dec->file.buffer, &dec->input_filled); + } + dec_buf = dec->file.buffer + dec->input_consumed; + if (!(dec->input_filled - dec->input_consumed)) + return 0; + dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, dec->input_filled - dec->input_consumed, dec->buffer, frame_info); + dec->input_consumed += frame_info->frame_bytes; + } else + { + dec_buf = dec->file.buffer + dec->offset; + uint64_t buf_size = end_offset - dec->offset; + if (!buf_size) + return 0; + dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, MINIMP3_MIN(buf_size, (uint64_t)INT_MAX), dec->buffer, frame_info); + } + dec->buffer_consumed = 0; + if (dec->info.hz != frame_info->hz || dec->info.layer != frame_info->layer) + { +return_e_decode: + dec->last_error = MP3D_E_DECODE; + return 0; + } + if (dec->buffer_samples) + { + dec->buffer_samples *= frame_info->channels; + if (dec->to_skip) + { + size_t skip = MINIMP3_MIN(dec->buffer_samples, dec->to_skip); + dec->buffer_consumed += skip; + dec->to_skip -= skip; + } + if ( +#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION + !(dec->flags & MP3D_ALLOW_MONO_STEREO_TRANSITION) && +#endif + dec->buffer_consumed != dec->buffer_samples && dec->info.channels != frame_info->channels) + { + goto return_e_decode; + } + } else if (dec->to_skip) + { /* In mp3 decoding not always can start decode from any frame because of bit reservoir, + count skip samples for such frames */ + int frame_samples = hdr_frame_samples(dec_buf)*frame_info->channels; + dec->to_skip -= MINIMP3_MIN(frame_samples, dec->to_skip); + } + dec->offset += frame_info->frame_bytes; + } + size_t out_samples = MINIMP3_MIN((size_t)(dec->buffer_samples - dec->buffer_consumed), max_samples); + if (dec->detected_samples) + { /* count decoded samples to properly cut padding */ + if (dec->cur_sample + out_samples >= dec->detected_samples) + out_samples = dec->detected_samples - dec->cur_sample; + } + dec->cur_sample += out_samples; + *buf = dec->buffer + dec->buffer_consumed; + dec->buffer_consumed += out_samples; + return out_samples; +} + +size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples) +{ + if (!dec || !buf) + { + if (dec) + dec->last_error = MP3D_E_PARAM; + return 0; + } + mp3dec_frame_info_t frame_info; + memset(&frame_info, 0, sizeof(frame_info)); + size_t samples_requested = samples; + while (samples) + { + mp3d_sample_t *buf_frame = NULL; + size_t read_samples = mp3dec_ex_read_frame(dec, &buf_frame, &frame_info, samples); + if (!read_samples) + { + break; + } + memcpy(buf, buf_frame, read_samples * sizeof(mp3d_sample_t)); + buf += read_samples; + samples -= read_samples; + } + return samples_requested - samples; +} + +int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int flags) +{ + if (!dec || !io || (flags & (~MP3D_FLAGS_MASK))) + return MP3D_E_PARAM; + memset(dec, 0, sizeof(*dec)); +#ifdef MINIMP3_HAVE_RING + int ret; + if (ret = mp3dec_open_ring(&dec->file, MINIMP3_IO_SIZE)) + return ret; +#else + dec->file.size = MINIMP3_IO_SIZE; + dec->file.buffer = (const uint8_t*)malloc(dec->file.size); + if (!dec->file.buffer) + return MP3D_E_MEMORY; +#endif + dec->flags = flags; + dec->io = io; + mp3dec_init(&dec->mp3d); + if (io->seek(0, io->seek_data)) + return MP3D_E_IOERROR; + int ret = mp3dec_iterate_cb(io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + if (dec->io->seek(dec->start_offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + mp3dec_init(&dec->mp3d); + dec->buffer_samples = 0; + dec->indexes_built = !(dec->vbr_tag_found || (flags & MP3D_DO_NOT_SCAN)); + dec->flags &= (~MP3D_DO_NOT_SCAN); + return 0; +} + + +#ifndef MINIMP3_NO_STDIO + +#if defined(__linux__) || defined(__FreeBSD__) +#include <errno.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#if !defined(_GNU_SOURCE) +#include <sys/ipc.h> +#include <sys/shm.h> +#endif +#if !defined(MAP_POPULATE) && defined(__linux__) +#define MAP_POPULATE 0x08000 +#elif !defined(MAP_POPULATE) +#define MAP_POPULATE 0 +#endif + +static void mp3dec_close_file(mp3dec_map_info_t *map_info) +{ + if (map_info->buffer && MAP_FAILED != map_info->buffer) + munmap((void *)map_info->buffer, map_info->size); + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + int file; + struct stat st; + memset(map_info, 0, sizeof(*map_info)); +retry_open: + file = open(file_name, O_RDONLY); + if (file < 0 && (errno == EAGAIN || errno == EINTR)) + goto retry_open; + if (file < 0 || fstat(file, &st) < 0) + { + close(file); + return MP3D_E_IOERROR; + } + + map_info->size = st.st_size; +retry_mmap: + map_info->buffer = (const uint8_t *)mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, file, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap; + close(file); + if (MAP_FAILED == map_info->buffer) + return MP3D_E_IOERROR; + return 0; +} + +#if MINIMP3_ENABLE_RING && defined(__linux__) && defined(_GNU_SOURCE) +#define MINIMP3_HAVE_RING +static void mp3dec_close_ring(mp3dec_map_info_t *map_info) +{ +#if defined(__linux__) && defined(_GNU_SOURCE) + if (map_info->buffer && MAP_FAILED != map_info->buffer) + munmap((void *)map_info->buffer, map_info->size*2); +#else + if (map_info->buffer) + { + shmdt(map_info->buffer); + shmdt(map_info->buffer + map_info->size); + } +#endif + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_ring(mp3dec_map_info_t *map_info, size_t size) +{ + int memfd, page_size; +#if defined(__linux__) && defined(_GNU_SOURCE) + void *buffer; + int res; +#endif + memset(map_info, 0, sizeof(*map_info)); + +#ifdef _SC_PAGESIZE + page_size = sysconf(_SC_PAGESIZE); +#else + page_size = getpagesize(); +#endif + map_info->size = (size + page_size - 1)/page_size*page_size; + +#if defined(__linux__) && defined(_GNU_SOURCE) + memfd = memfd_create("mp3_ring", 0); + if (memfd < 0) + return MP3D_E_MEMORY; + +retry_ftruncate: + res = ftruncate(memfd, map_info->size); + if (res && (errno == EAGAIN || errno == EINTR)) + goto retry_ftruncate; + if (res) + goto error; + +retry_mmap: + map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap; + if (MAP_FAILED == map_info->buffer || !map_info->buffer) + goto error; +retry_mmap2: + buffer = mmap((void *)map_info->buffer, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap2; + if (MAP_FAILED == map_info->buffer || buffer != (void *)map_info->buffer) + goto error; +retry_mmap3: + buffer = mmap((void *)map_info->buffer + map_info->size, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap3; + if (MAP_FAILED == map_info->buffer || buffer != (void *)(map_info->buffer + map_info->size)) + goto error; + + close(memfd); + return 0; +error: + close(memfd); + mp3dec_close_ring(map_info); + return MP3D_E_MEMORY; +#else + memfd = shmget(IPC_PRIVATE, map_info->size, IPC_CREAT | 0700); + if (memfd < 0) + return MP3D_E_MEMORY; +retry_mmap: + map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_PRIVATE, -1, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap; + if (MAP_FAILED == map_info->buffer) + goto error; + if (map_info->buffer != shmat(memfd, map_info->buffer, 0)) + goto error; + if ((map_info->buffer + map_info->size) != shmat(memfd, map_info->buffer + map_info->size, 0)) + goto error; + if (shmctl(memfd, IPC_RMID, NULL) < 0) + return MP3D_E_MEMORY; + return 0; +error: + shmctl(memfd, IPC_RMID, NULL); + mp3dec_close_ring(map_info); + return MP3D_E_MEMORY; +#endif +} +#endif /*MINIMP3_ENABLE_RING*/ +#elif defined(_WIN32) +#include <windows.h> + +static void mp3dec_close_file(mp3dec_map_info_t *map_info) +{ + if (map_info->buffer) + UnmapViewOfFile(map_info->buffer); + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_file_h(HANDLE file, mp3dec_map_info_t *map_info) +{ + memset(map_info, 0, sizeof(*map_info)); + + HANDLE mapping = NULL; + LARGE_INTEGER s; + s.LowPart = GetFileSize(file, (DWORD*)&s.HighPart); + if (s.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) + goto error; + map_info->size = s.QuadPart; + + mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); + if (!mapping) + goto error; + map_info->buffer = (const uint8_t*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, s.QuadPart); + CloseHandle(mapping); + if (!map_info->buffer) + goto error; + + CloseHandle(file); + return 0; +error: + mp3dec_close_file(map_info); + CloseHandle(file); + return MP3D_E_IOERROR; +} + +static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + HANDLE file = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (INVALID_HANDLE_VALUE == file) + return MP3D_E_IOERROR; + return mp3dec_open_file_h(file, map_info); +} + +static int mp3dec_open_file_w(const wchar_t *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + HANDLE file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (INVALID_HANDLE_VALUE == file) + return MP3D_E_IOERROR; + return mp3dec_open_file_h(file, map_info); +} +#else +#include <stdio.h> + +static void mp3dec_close_file(mp3dec_map_info_t *map_info) +{ + if (map_info->buffer) + free((void *)map_info->buffer); + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + memset(map_info, 0, sizeof(*map_info)); + FILE *file = fopen(file_name, "rb"); + if (!file) + return MP3D_E_IOERROR; + int res = MP3D_E_IOERROR; + long size = -1; + if (fseek(file, 0, SEEK_END)) + goto error; + size = ftell(file); + if (size < 0) + goto error; + map_info->size = (size_t)size; + if (fseek(file, 0, SEEK_SET)) + goto error; + map_info->buffer = (uint8_t *)malloc(map_info->size); + if (!map_info->buffer) + { + res = MP3D_E_MEMORY; + goto error; + } + if (fread((void *)map_info->buffer, 1, map_info->size, file) != map_info->size) + goto error; + fclose(file); + return 0; +error: + mp3dec_close_file(map_info); + fclose(file); + return res; +} +#endif + +static int mp3dec_detect_mapinfo(mp3dec_map_info_t *map_info) +{ + int ret = mp3dec_detect_buf(map_info->buffer, map_info->size); + mp3dec_close_file(map_info); + return ret; +} + +static int mp3dec_load_mapinfo(mp3dec_t *dec, mp3dec_map_info_t *map_info, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + int ret = mp3dec_load_buf(dec, map_info->buffer, map_info->size, info, progress_cb, user_data); + mp3dec_close_file(map_info); + return ret; +} + +static int mp3dec_iterate_mapinfo(mp3dec_map_info_t *map_info, MP3D_ITERATE_CB callback, void *user_data) +{ + int ret = mp3dec_iterate_buf(map_info->buffer, map_info->size, callback, user_data); + mp3dec_close_file(map_info); + return ret; +} + +static int mp3dec_ex_open_mapinfo(mp3dec_ex_t *dec, int flags) +{ + int ret = mp3dec_ex_open_buf(dec, dec->file.buffer, dec->file.size, flags); + dec->is_file = 1; + if (ret) + mp3dec_ex_close(dec); + return ret; +} + +int mp3dec_detect(const char *file_name) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file(file_name, &map_info))) + return ret; + return mp3dec_detect_mapinfo(&map_info); +} + +int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file(file_name, &map_info))) + return ret; + return mp3dec_load_mapinfo(dec, &map_info, info, progress_cb, user_data); +} + +int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file(file_name, &map_info))) + return ret; + return mp3dec_iterate_mapinfo(&map_info, callback, user_data); +} + +int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int flags) +{ + int ret; + if (!dec) + return MP3D_E_PARAM; + if ((ret = mp3dec_open_file(file_name, &dec->file))) + return ret; + return mp3dec_ex_open_mapinfo(dec, flags); +} + +void mp3dec_ex_close(mp3dec_ex_t *dec) +{ +#ifdef MINIMP3_HAVE_RING + if (dec->io) + mp3dec_close_ring(&dec->file); +#else + if (dec->io && dec->file.buffer) + free((void*)dec->file.buffer); +#endif + if (dec->is_file) + mp3dec_close_file(&dec->file); + if (dec->index.frames) + free(dec->index.frames); + memset(dec, 0, sizeof(*dec)); +} + +#ifdef _WIN32 +int mp3dec_detect_w(const wchar_t *file_name) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file_w(file_name, &map_info))) + return ret; + return mp3dec_detect_mapinfo(&map_info); +} + +int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file_w(file_name, &map_info))) + return ret; + return mp3dec_load_mapinfo(dec, &map_info, info, progress_cb, user_data); +} + +int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file_w(file_name, &map_info))) + return ret; + return mp3dec_iterate_mapinfo(&map_info, callback, user_data); +} + +int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int flags) +{ + int ret; + if ((ret = mp3dec_open_file_w(file_name, &dec->file))) + return ret; + return mp3dec_ex_open_mapinfo(dec, flags); +} +#endif +#else /* MINIMP3_NO_STDIO */ +void mp3dec_ex_close(mp3dec_ex_t *dec) +{ +#ifdef MINIMP3_HAVE_RING + if (dec->io) + mp3dec_close_ring(&dec->file); +#else + if (dec->io && dec->file.buffer) + free((void*)dec->file.buffer); +#endif + if (dec->index.frames) + free(dec->index.frames); + memset(dec, 0, sizeof(*dec)); +} +#endif + +#endif /*MINIMP3_IMPLEMENTATION*/ diff --git a/thirdparty/misc/easing_equations.cpp b/thirdparty/misc/easing_equations.cpp index bc84564b19..af48aaf079 100644 --- a/thirdparty/misc/easing_equations.cpp +++ b/thirdparty/misc/easing_equations.cpp @@ -188,7 +188,8 @@ static real_t out_in(real_t t, real_t b, real_t c, real_t d) { /////////////////////////////////////////////////////////////////////////// namespace cubic { static real_t in(real_t t, real_t b, real_t c, real_t d) { - return c * (t /= d) * t * t + b; + t /= d; + return c * t * t * t + b; } static real_t out(real_t t, real_t b, real_t c, real_t d) { @@ -197,8 +198,10 @@ static real_t out(real_t t, real_t b, real_t c, real_t d) { } static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - if ((t /= d / 2) < 1) return c / 2 * t * t * t + b; - return c / 2 * ((t -= 2) * t * t + 2) + b; + t /= d / 2; + if (t < 1) return c / 2 * t * t * t + b; + t -= 2; + return c / 2 * (t * t * t + 2) + b; } static real_t out_in(real_t t, real_t b, real_t c, real_t d) { @@ -210,16 +213,22 @@ static real_t out_in(real_t t, real_t b, real_t c, real_t d) { /////////////////////////////////////////////////////////////////////////// namespace circ { static real_t in(real_t t, real_t b, real_t c, real_t d) { - return -c * (sqrt(1 - (t /= d) * t) - 1) + b; // TODO: ehrich: operation with t is undefined + t /= d; + return -c * (sqrt(1 - t * t) - 1) + b; } static real_t out(real_t t, real_t b, real_t c, real_t d) { - return c * sqrt(1 - (t = t / d - 1) * t) + b; // TODO: ehrich: operation with t is undefined + t = t / d - 1; + return c * sqrt(1 - t * t) + b; } static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; - return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b; // TODO: ehrich: operation with t is undefined + t /= d / 2; + if (t < 1) { + return -c / 2 * (sqrt(1 - t * t) - 1) + b; + } + t -= 2; + return c / 2 * (sqrt(1 - t * t) + 1) + b; } static real_t out_in(real_t t, real_t b, real_t c, real_t d) { @@ -271,14 +280,16 @@ static real_t in(real_t t, real_t b, real_t c, real_t d) { static real_t out(real_t t, real_t b, real_t c, real_t d) { float s = 1.70158f; - return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; // TODO: ehrich: operation with t is undefined + t = t / d - 1; + return c * (t * t * ((s + 1) * t + s) + 1) + b; } static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - float s = 1.70158f; - if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b; // TODO: ehrich: operation with s is undefined - float postFix = t -= 2; - return c / 2 * ((postFix)*t * (((s *= (1.525f)) + 1) * t + s) + 2) + b; // TODO: ehrich: operation with s is undefined + float s = 1.70158f * 1.525f; + t /= d / 2; + if (t < 1) return c / 2 * (t * t * ((s + 1) * t - s)) + b; + t -= 2; + return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b; } static real_t out_in(real_t t, real_t b, real_t c, real_t d) { |