diff options
| -rw-r--r-- | core/os/midi_driver.cpp | 3 | ||||
| -rw-r--r-- | core/os/midi_driver.h | 2 | ||||
| -rw-r--r-- | drivers/alsamidi/midi_driver_alsamidi.cpp | 14 | ||||
| -rw-r--r-- | drivers/alsamidi/midi_driver_alsamidi.h | 4 | ||||
| -rw-r--r-- | drivers/coremidi/midi_driver_coremidi.cpp | 5 | ||||
| -rw-r--r-- | drivers/winmidi/midi_driver_winmidi.cpp | 4 | ||||
| -rw-r--r-- | editor/editor_help_search.cpp | 178 | ||||
| -rw-r--r-- | editor/editor_help_search.h | 49 | ||||
| -rw-r--r-- | modules/basis_universal/image_compress_basisu.cpp | 251 | ||||
| -rw-r--r-- | modules/basis_universal/image_compress_basisu.h | 52 | ||||
| -rw-r--r-- | modules/basis_universal/register_types.cpp | 252 | ||||
| -rw-r--r-- | platform/android/export/export_plugin.cpp | 5 | ||||
| -rw-r--r-- | platform/ios/export/export_plugin.cpp | 4 | ||||
| -rw-r--r-- | scene/audio/audio_stream_player_internal.cpp | 2 |
14 files changed, 480 insertions, 345 deletions
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp index 037851661b..6870c84b49 100644 --- a/core/os/midi_driver.cpp +++ b/core/os/midi_driver.cpp @@ -42,9 +42,10 @@ void MIDIDriver::set_singleton() { singleton = this; } -void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length) { +void MIDIDriver::receive_input_packet(int device_index, uint64_t timestamp, uint8_t *data, uint32_t length) { Ref<InputEventMIDI> event; event.instantiate(); + event->set_device(device_index); uint32_t param_position = 1; if (length >= 1) { diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h index 6ad21c319e..cad3d8189e 100644 --- a/core/os/midi_driver.h +++ b/core/os/midi_driver.h @@ -51,7 +51,7 @@ public: virtual PackedStringArray get_connected_inputs(); - static void receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length); + static void receive_input_packet(int device_index, uint64_t timestamp, uint8_t *data, uint32_t length); MIDIDriver(); virtual ~MIDIDriver() {} diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp index 6b35987f70..b87be69cc5 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.cpp +++ b/drivers/alsamidi/midi_driver_alsamidi.cpp @@ -82,13 +82,13 @@ size_t MIDIDriverALSAMidi::msg_expected_data(uint8_t status_byte) { } void MIDIDriverALSAMidi::InputConnection::parse_byte(uint8_t byte, MIDIDriverALSAMidi &driver, - uint64_t timestamp) { + uint64_t timestamp, int device_index) { switch (msg_category(byte)) { case MessageCategory::RealTime: // Real-Time messages are single byte messages that can // occur at any point. // We pass them straight through. - driver.receive_input_packet(timestamp, &byte, 1); + driver.receive_input_packet(device_index, timestamp, &byte, 1); break; case MessageCategory::Data: @@ -100,7 +100,7 @@ void MIDIDriverALSAMidi::InputConnection::parse_byte(uint8_t byte, MIDIDriverALS // Forward a complete message and reset relevant state. if (received_data == expected_data) { - driver.receive_input_packet(timestamp, buffer, received_data + 1); + driver.receive_input_packet(device_index, timestamp, buffer, received_data + 1); received_data = 0; if (msg_category(buffer[0]) != MessageCategory::Voice) { @@ -130,13 +130,13 @@ void MIDIDriverALSAMidi::InputConnection::parse_byte(uint8_t byte, MIDIDriverALS expected_data = msg_expected_data(byte); skipping_sys_ex = false; if (expected_data == 0) { - driver.receive_input_packet(timestamp, &byte, 1); + driver.receive_input_packet(device_index, timestamp, &byte, 1); } break; } } -int MIDIDriverALSAMidi::InputConnection::read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp) { +int MIDIDriverALSAMidi::InputConnection::read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp, int device_index) { int ret; do { uint8_t byte = 0; @@ -147,7 +147,7 @@ int MIDIDriverALSAMidi::InputConnection::read_in(MIDIDriverALSAMidi &driver, uin ERR_PRINT("snd_rawmidi_read error: " + String(snd_strerror(ret))); } } else { - parse_byte(byte, driver, timestamp); + parse_byte(byte, driver, timestamp, device_index); } } while (ret > 0); @@ -165,7 +165,7 @@ void MIDIDriverALSAMidi::thread_func(void *p_udata) { size_t connection_count = md->connected_inputs.size(); for (size_t i = 0; i < connection_count; i++) { - connections[i].read_in(*md, timestamp); + connections[i].read_in(*md, timestamp, (int)i); } md->unlock(); diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h index 80cc96310f..95ded3b1c9 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.h +++ b/drivers/alsamidi/midi_driver_alsamidi.h @@ -58,7 +58,7 @@ class MIDIDriverALSAMidi : public MIDIDriver { rawmidi_ptr{ midi_in } {} // Read in and parse available data, forwarding any complete messages through the driver. - int read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp); + int read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp, int device_index); snd_rawmidi_t *rawmidi_ptr = nullptr; @@ -68,7 +68,7 @@ class MIDIDriverALSAMidi : public MIDIDriver { size_t expected_data = 0; size_t received_data = 0; bool skipping_sys_ex = false; - void parse_byte(uint8_t byte, MIDIDriverALSAMidi &driver, uint64_t timestamp); + void parse_byte(uint8_t byte, MIDIDriverALSAMidi &driver, uint64_t timestamp, int device_index); }; Vector<InputConnection> connected_inputs; diff --git a/drivers/coremidi/midi_driver_coremidi.cpp b/drivers/coremidi/midi_driver_coremidi.cpp index ed991b3d9d..87fc7612f7 100644 --- a/drivers/coremidi/midi_driver_coremidi.cpp +++ b/drivers/coremidi/midi_driver_coremidi.cpp @@ -39,8 +39,9 @@ void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con) { MIDIPacket *packet = const_cast<MIDIPacket *>(packet_list->packet); + int *device_index = static_cast<int *>(src_conn_ref_con); for (UInt32 i = 0; i < packet_list->numPackets; i++) { - receive_input_packet(packet->timeStamp, packet->data, packet->length); + receive_input_packet(*device_index, packet->timeStamp, packet->data, packet->length); packet = MIDIPacketNext(packet); } } @@ -64,7 +65,7 @@ Error MIDIDriverCoreMidi::open() { for (int i = 0; i < sources; i++) { MIDIEndpointRef source = MIDIGetSource(i); if (source) { - MIDIPortConnectSource(port_in, source, (void *)this); + MIDIPortConnectSource(port_in, source, static_cast<void *>(&i)); connected_sources.insert(i, source); } } diff --git a/drivers/winmidi/midi_driver_winmidi.cpp b/drivers/winmidi/midi_driver_winmidi.cpp index cdbab489c4..07f0226c5d 100644 --- a/drivers/winmidi/midi_driver_winmidi.cpp +++ b/drivers/winmidi/midi_driver_winmidi.cpp @@ -36,7 +36,7 @@ void MIDIDriverWinMidi::read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { if (wMsg == MIM_DATA) { - receive_input_packet((uint64_t)dwParam2, (uint8_t *)&dwParam1, 3); + receive_input_packet((int)dwInstance, (uint64_t)dwParam2, (uint8_t *)&dwParam1, 3); } } @@ -44,7 +44,7 @@ Error MIDIDriverWinMidi::open() { for (UINT i = 0; i < midiInGetNumDevs(); i++) { HMIDIIN midi_in; - MMRESULT res = midiInOpen(&midi_in, i, (DWORD_PTR)read, (DWORD_PTR)this, CALLBACK_FUNCTION); + MMRESULT res = midiInOpen(&midi_in, i, (DWORD_PTR)read, (DWORD_PTR)i, CALLBACK_FUNCTION); if (res == MMSYSERR_NOERROR) { midiInStart(midi_in); connected_sources.insert(i, midi_in); diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 7ece509731..99459df96c 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -476,7 +476,8 @@ bool EditorHelpSearch::Runner::_phase_match_classes() { // If the search term is empty, add any classes which are not script docs or which don't start with // a double-quotation. This will ensure that only C++ classes and explicitly named classes will // be added. - match.name = (term.is_empty() && (!class_doc->is_script_doc || class_doc->name[0] != '\"')) || _match_string(term, class_doc->name) || _match_keywords(term, class_doc->keywords); + match.name = (term.is_empty() && (!class_doc->is_script_doc || class_doc->name[0] != '\"')) || _match_string(term, class_doc->name); + match.keyword = _match_keywords(term, class_doc->keywords); } // Match members only if the term is long enough, to avoid slow performance from building a large tree. @@ -493,36 +494,56 @@ bool EditorHelpSearch::Runner::_phase_match_classes() { } if (search_flags & SEARCH_SIGNALS) { for (int i = 0; i < class_doc->signals.size(); i++) { - if (_all_terms_in_name(class_doc->signals[i].name) || _all_terms_in_keywords(class_doc->signals[i].keywords)) { - match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc->signals[i])); + MemberMatch<DocData::MethodDoc> signal; + signal.name = _all_terms_in_name(class_doc->signals[i].name); + signal.keyword = _match_keywords_in_all_terms(class_doc->signals[i].keywords); + if (signal.name || !signal.keyword.is_empty()) { + signal.doc = const_cast<DocData::MethodDoc *>(&class_doc->signals[i]); + match.signals.push_back(signal); } } } if (search_flags & SEARCH_CONSTANTS) { for (int i = 0; i < class_doc->constants.size(); i++) { - if (_all_terms_in_name(class_doc->constants[i].name) || _all_terms_in_keywords(class_doc->constants[i].keywords)) { - match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc->constants[i])); + MemberMatch<DocData::ConstantDoc> constant; + constant.name = _all_terms_in_name(class_doc->constants[i].name); + constant.keyword = _match_keywords_in_all_terms(class_doc->constants[i].keywords); + if (constant.name || !constant.keyword.is_empty()) { + constant.doc = const_cast<DocData::ConstantDoc *>(&class_doc->constants[i]); + match.constants.push_back(constant); } } } if (search_flags & SEARCH_PROPERTIES) { for (int i = 0; i < class_doc->properties.size(); i++) { - if (_all_terms_in_name(class_doc->properties[i].name) || _all_terms_in_keywords(class_doc->properties[i].keywords)) { - match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc->properties[i])); + MemberMatch<DocData::PropertyDoc> property; + property.name = _all_terms_in_name(class_doc->properties[i].name); + property.keyword = _match_keywords_in_all_terms(class_doc->properties[i].keywords); + if (property.name || !property.keyword.is_empty()) { + property.doc = const_cast<DocData::PropertyDoc *>(&class_doc->properties[i]); + match.properties.push_back(property); } } } if (search_flags & SEARCH_THEME_ITEMS) { for (int i = 0; i < class_doc->theme_properties.size(); i++) { - if (_all_terms_in_name(class_doc->theme_properties[i].name) || _all_terms_in_keywords(class_doc->theme_properties[i].keywords)) { - match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc->theme_properties[i])); + MemberMatch<DocData::ThemeItemDoc> theme_property; + theme_property.name = _all_terms_in_name(class_doc->theme_properties[i].name); + theme_property.keyword = _match_keywords_in_all_terms(class_doc->theme_properties[i].keywords); + if (theme_property.name || !theme_property.keyword.is_empty()) { + theme_property.doc = const_cast<DocData::ThemeItemDoc *>(&class_doc->theme_properties[i]); + match.theme_properties.push_back(theme_property); } } } if (search_flags & SEARCH_ANNOTATIONS) { for (int i = 0; i < class_doc->annotations.size(); i++) { - if (_match_string(term, class_doc->annotations[i].name) || _all_terms_in_keywords(class_doc->annotations[i].keywords)) { - match.annotations.push_back(const_cast<DocData::MethodDoc *>(&class_doc->annotations[i])); + MemberMatch<DocData::MethodDoc> annotation; + annotation.name = _all_terms_in_name(class_doc->annotations[i].name); + annotation.keyword = _match_keywords_in_all_terms(class_doc->annotations[i].keywords); + if (annotation.name || !annotation.keyword.is_empty()) { + annotation.doc = const_cast<DocData::MethodDoc *>(&class_doc->annotations[i]); + match.annotations.push_back(annotation); } } } @@ -606,8 +627,8 @@ bool EditorHelpSearch::Runner::_phase_class_items() { _create_class_hierarchy(match); } } else { - if (match.name) { - _create_class_item(root_item, match.doc, false); + if (match.name || !match.keyword.is_empty()) { + _create_class_item(root_item, match.doc, false, match.name ? String() : match.keyword); } } @@ -636,14 +657,14 @@ bool EditorHelpSearch::Runner::_phase_member_items() { TreeItem *parent_item = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item; bool constructor_created = false; for (int i = 0; i < match.methods.size(); i++) { - String text = match.methods[i]->name; + String text = match.methods[i].doc->name; if (!constructor_created) { - if (match.doc->name == match.methods[i]->name) { + if (match.doc->name == match.methods[i].doc->name) { text += " " + TTR("(constructors)"); constructor_created = true; } } else { - if (match.doc->name == match.methods[i]->name) { + if (match.doc->name == match.methods[i].doc->name) { continue; } } @@ -662,8 +683,7 @@ bool EditorHelpSearch::Runner::_phase_member_items() { _create_theme_property_item(parent_item, match.doc, match.theme_properties[i]); } for (int i = 0; i < match.annotations.size(); i++) { - // Hide the redundant leading @ symbol. - _create_annotation_item(parent_item, match.doc, match.annotations[i]->name.substr(1), match.annotations[i]); + _create_annotation_item(parent_item, match.doc, match.annotations[i]); } ++iterator_match; @@ -677,16 +697,20 @@ bool EditorHelpSearch::Runner::_phase_select_match() { return true; } -void EditorHelpSearch::Runner::_match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, Vector<DocData::MethodDoc *> *r_match_methods) { +void EditorHelpSearch::Runner::_match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, Vector<MemberMatch<DocData::MethodDoc>> *r_match_methods) { // Constructors, Methods, Operators... for (int i = 0; i < p_methods.size(); i++) { String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? p_methods[i].name : p_methods[i].name.to_lower(); String keywords = (search_flags & SEARCH_CASE_SENSITIVE) ? p_methods[i].keywords : p_methods[i].keywords.to_lower(); - if (_all_terms_in_name(method_name) || _all_terms_in_keywords(keywords) || + MemberMatch<DocData::MethodDoc> method; + method.name = _all_terms_in_name(method_name); + method.keyword = _match_keywords_in_all_terms(keywords); + if (method.name || !method.keyword.is_empty() || (term.begins_with(".") && method_name.begins_with(term.substr(1))) || (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) || (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) { - r_match_methods->push_back(const_cast<DocData::MethodDoc *>(&p_methods[i])); + method.doc = const_cast<DocData::MethodDoc *>(&p_methods[i]); + r_match_methods->push_back(method); } } } @@ -700,13 +724,15 @@ bool EditorHelpSearch::Runner::_all_terms_in_name(const String &p_name) const { return true; } -bool EditorHelpSearch::Runner::_all_terms_in_keywords(const String &p_keywords) const { - for (const String &keyword : p_keywords.split(",")) { - if (_all_terms_in_name(keyword.strip_edges())) { - return true; +String EditorHelpSearch::Runner::_match_keywords_in_all_terms(const String &p_keywords) const { + String matching_keyword; + for (int i = 0; i < terms.size(); i++) { + matching_keyword = _match_keywords(terms[i], p_keywords); + if (matching_keyword.is_empty()) { + return String(); } } - return false; + return matching_keyword; } bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String &p_string) const { @@ -717,13 +743,14 @@ bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String } } -bool EditorHelpSearch::Runner::_match_keywords(const String &p_term, const String &p_keywords) const { - for (const String &keyword : p_keywords.split(",")) { - if (_match_string(p_term, keyword.strip_edges())) { - return true; +String EditorHelpSearch::Runner::_match_keywords(const String &p_term, const String &p_keywords) const { + for (const String &k : p_keywords.split(",")) { + const String keyword = k.strip_edges(); + if (_match_string(p_term, keyword)) { + return keyword; } } - return false; + return String(); } void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_text, bool p_is_keywords) { @@ -766,9 +793,26 @@ String EditorHelpSearch::Runner::_build_method_tooltip(const DocData::ClassDoc * } } tooltip += ")"; + tooltip += _build_keywords_tooltip(p_doc->keywords); return tooltip; } +String EditorHelpSearch::Runner::_build_keywords_tooltip(const String &p_keywords) const { + String tooltip; + if (p_keywords.is_empty()) { + return tooltip; + } + + tooltip = "\n\n" + TTR("Keywords") + ": "; + + for (const String &keyword : p_keywords.split(",")) { + tooltip += keyword.strip_edges().quote() + ", "; + } + + // Remove trailing comma and space. + return tooltip.left(-2); +} + TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_match) { if (p_match.doc->name.is_empty()) { return nullptr; @@ -790,7 +834,7 @@ TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_ } } - TreeItem *class_item = _create_class_item(parent_item, p_match.doc, !p_match.name); + TreeItem *class_item = _create_class_item(parent_item, p_match.doc, !p_match.name && p_match.keyword.is_empty(), p_match.name ? String() : p_match.keyword); class_items[p_match.doc->name] = class_item; return class_item; } @@ -815,15 +859,15 @@ bool EditorHelpSearch::Runner::_find_or_create_item(TreeItem *p_parent, const St } } -TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) { +TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray, const String &p_matching_keyword) { String tooltip = DTR(p_doc->brief_description.strip_edges()); + tooltip += _build_keywords_tooltip(p_doc->keywords); const String item_meta = "class_name:" + p_doc->name; TreeItem *item = nullptr; if (_find_or_create_item(p_parent, item_meta, item)) { item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_doc->name)); - item->set_text(0, p_doc->name); item->set_text(1, TTR("Class")); item->set_tooltip_text(0, tooltip); item->set_tooltip_text(1, tooltip); @@ -845,6 +889,12 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const item->clear_custom_color(1); } + if (p_matching_keyword.is_empty()) { + item->set_text(0, p_doc->name); + } else { + item->set_text(0, p_doc->name + " - " + TTR(vformat("Matches the \"%s\" keyword.", p_matching_keyword))); + } + _match_item(item, p_doc->name); for (const String &keyword : p_doc->keywords.split(",")) { _match_item(item, keyword.strip_edges(), true); @@ -853,39 +903,44 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const return item; } -TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) { - String tooltip = _build_method_tooltip(p_class_doc, p_doc); - return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental); +TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const MemberMatch<DocData::MethodDoc> &p_match) { + String tooltip = _build_method_tooltip(p_class_doc, p_match.doc); + return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_match.doc->name, p_text, TTRC("Method"), "method", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } -TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) { - String tooltip = _build_method_tooltip(p_class_doc, p_doc); - return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental); +TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match) { + String tooltip = _build_method_tooltip(p_class_doc, p_match.doc); + return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_match.doc->name, p_match.doc->name, TTRC("Signal"), "signal", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } -TreeItem *EditorHelpSearch::Runner::_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) { - String tooltip = _build_method_tooltip(p_class_doc, p_doc); - return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_doc->name, p_text, TTRC("Annotation"), "annotation", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental); +TreeItem *EditorHelpSearch::Runner::_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match) { + String tooltip = _build_method_tooltip(p_class_doc, p_match.doc); + // Hide the redundant leading @ symbol. + String text = p_match.doc->name.substr(1); + return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_match.doc->name, text, TTRC("Annotation"), "annotation", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } -TreeItem *EditorHelpSearch::Runner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) { - String tooltip = p_class_doc->name + "." + p_doc->name; - return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental); +TreeItem *EditorHelpSearch::Runner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::ConstantDoc> &p_match) { + String tooltip = p_class_doc->name + "." + p_match.doc->name; + tooltip += _build_keywords_tooltip(p_match.doc->keywords); + return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_match.doc->name, p_match.doc->name, TTRC("Constant"), "constant", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } -TreeItem *EditorHelpSearch::Runner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) { - String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name; - tooltip += "\n " + p_class_doc->name + "." + p_doc->setter + "(value) setter"; - tooltip += "\n " + p_class_doc->name + "." + p_doc->getter + "() getter"; - return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, p_doc->name, TTRC("Property"), "property", tooltip, p_doc->keywords, p_doc->is_deprecated, p_doc->is_experimental); +TreeItem *EditorHelpSearch::Runner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::PropertyDoc> &p_match) { + String tooltip = p_match.doc->type + " " + p_class_doc->name + "." + p_match.doc->name; + tooltip += "\n " + p_class_doc->name + "." + p_match.doc->setter + "(value) setter"; + tooltip += "\n " + p_class_doc->name + "." + p_match.doc->getter + "() getter"; + tooltip += _build_keywords_tooltip(p_match.doc->keywords); + return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_match.doc->name, p_match.doc->name, TTRC("Property"), "property", tooltip, p_match.doc->keywords, p_match.doc->is_deprecated, p_match.doc->is_experimental, p_match.name ? String() : p_match.keyword); } -TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc) { - String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name; - return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, p_doc->name, TTRC("Theme Property"), "theme_item", p_doc->keywords, tooltip, false, false); +TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::ThemeItemDoc> &p_match) { + String tooltip = p_match.doc->type + " " + p_class_doc->name + "." + p_match.doc->name; + tooltip += _build_keywords_tooltip(p_match.doc->keywords); + return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_match.doc->name, p_match.doc->name, TTRC("Theme Property"), "theme_item", p_match.doc->keywords, tooltip, false, false, p_match.name ? String() : p_match.keyword); } -TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool is_deprecated, bool is_experimental) { +TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool p_is_deprecated, bool p_is_experimental, const String &p_matching_keyword) { const String item_meta = "class_" + p_metatype + ":" + p_class_name + ":" + p_name; TreeItem *item = nullptr; @@ -896,20 +951,25 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons item->set_tooltip_text(1, p_tooltip); item->set_metadata(0, item_meta); - if (is_deprecated) { + if (p_is_deprecated) { Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon(SNAME("StatusError")); item->add_button(0, error_icon, 0, false, TTR("This member is marked as deprecated.")); - } else if (is_experimental) { + } else if (p_is_experimental) { Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon(SNAME("NodeWarning")); item->add_button(0, warning_icon, 0, false, TTR("This member is marked as experimental.")); } } + String text; if (search_flags & SEARCH_SHOW_HIERARCHY) { - item->set_text(0, p_text); + text = p_text; } else { - item->set_text(0, p_class_name + "." + p_text); + text = p_class_name + "." + p_text; + } + if (!p_matching_keyword.is_empty()) { + text += " - " + TTR(vformat("Matches the \"%s\" keyword.", p_matching_keyword)); } + item->set_text(0, text); _match_item(item, p_name); for (const String &keyword : p_keywords.split(",")) { diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h index 1982da04e8..003b98adf0 100644 --- a/editor/editor_help_search.h +++ b/editor/editor_help_search.h @@ -117,20 +117,28 @@ class EditorHelpSearch::Runner : public RefCounted { }; int phase = 0; + template <class T> + struct MemberMatch { + T *doc = nullptr; + bool name = false; + String keyword; + }; + struct ClassMatch { DocData::ClassDoc *doc = nullptr; bool name = false; - Vector<DocData::MethodDoc *> constructors; - Vector<DocData::MethodDoc *> methods; - Vector<DocData::MethodDoc *> operators; - Vector<DocData::MethodDoc *> signals; - Vector<DocData::ConstantDoc *> constants; - Vector<DocData::PropertyDoc *> properties; - Vector<DocData::ThemeItemDoc *> theme_properties; - Vector<DocData::MethodDoc *> annotations; + String keyword; + Vector<MemberMatch<DocData::MethodDoc>> constructors; + Vector<MemberMatch<DocData::MethodDoc>> methods; + Vector<MemberMatch<DocData::MethodDoc>> operators; + Vector<MemberMatch<DocData::MethodDoc>> signals; + Vector<MemberMatch<DocData::ConstantDoc>> constants; + Vector<MemberMatch<DocData::PropertyDoc>> properties; + Vector<MemberMatch<DocData::ThemeItemDoc>> theme_properties; + Vector<MemberMatch<DocData::MethodDoc>> annotations; bool required() { - return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size() || annotations.size(); + return name || !keyword.is_empty() || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size() || annotations.size(); } }; @@ -167,22 +175,23 @@ class EditorHelpSearch::Runner : public RefCounted { bool _phase_select_match(); String _build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const; + String _build_keywords_tooltip(const String &p_keywords) const; - void _match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, Vector<DocData::MethodDoc *> *r_match_methods); + void _match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, Vector<MemberMatch<DocData::MethodDoc>> *r_match_methods); bool _all_terms_in_name(const String &p_name) const; - bool _all_terms_in_keywords(const String &p_name) const; + String _match_keywords_in_all_terms(const String &p_keywords) const; bool _match_string(const String &p_term, const String &p_string) const; - bool _match_keywords(const String &p_term, const String &p_keywords) const; + String _match_keywords(const String &p_term, const String &p_keywords) const; void _match_item(TreeItem *p_item, const String &p_text, bool p_is_keywords = false); TreeItem *_create_class_hierarchy(const ClassMatch &p_match); - TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray); - TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc); - TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc); - TreeItem *_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc); - TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc); - TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc); - TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc); - TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool is_deprecated, bool is_experimental); + TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray, const String &p_matching_keyword); + TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const MemberMatch<DocData::MethodDoc> &p_match); + TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); + TreeItem *_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::MethodDoc> &p_match); + TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::ConstantDoc> &p_match); + TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::PropertyDoc> &p_match); + TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const MemberMatch<DocData::ThemeItemDoc> &p_match); + TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_keywords, bool p_is_deprecated, bool p_is_experimental, const String &p_matching_keyword); public: bool work(uint64_t slot = 100000); diff --git a/modules/basis_universal/image_compress_basisu.cpp b/modules/basis_universal/image_compress_basisu.cpp new file mode 100644 index 0000000000..41de62b20b --- /dev/null +++ b/modules/basis_universal/image_compress_basisu.cpp @@ -0,0 +1,251 @@ +/**************************************************************************/ +/* image_compress_basisu.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "image_compress_basisu.h" + +#include "servers/rendering_server.h" + +#include <transcoder/basisu_transcoder.h> +#ifdef TOOLS_ENABLED +#include <encoder/basisu_comp.h> +#endif + +void basis_universal_init() { +#ifdef TOOLS_ENABLED + basisu::basisu_encoder_init(); +#endif + + basist::basisu_transcoder_init(); +} + +#ifdef TOOLS_ENABLED +Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels) { + Ref<Image> image = p_image->duplicate(); + image->convert(Image::FORMAT_RGBA8); + + basisu::basis_compressor_params params; + + params.m_uastc = true; + params.m_quality_level = basisu::BASISU_QUALITY_MIN; + params.m_pack_uastc_flags &= ~basisu::cPackUASTCLevelMask; + params.m_pack_uastc_flags |= basisu::cPackUASTCLevelFastest; + + params.m_rdo_uastc = 0.0f; + params.m_rdo_uastc_quality_scalar = 0.0f; + params.m_rdo_uastc_dict_size = 1024; + + params.m_mip_fast = true; + params.m_multithreading = true; + params.m_check_for_alpha = false; + + basisu::job_pool job_pool(OS::get_singleton()->get_processor_count()); + params.m_pJob_pool = &job_pool; + + BasisDecompressFormat decompress_format = BASIS_DECOMPRESS_RG; + switch (p_channels) { + case Image::USED_CHANNELS_L: { + decompress_format = BASIS_DECOMPRESS_RGB; + } break; + case Image::USED_CHANNELS_LA: { + params.m_force_alpha = true; + decompress_format = BASIS_DECOMPRESS_RGBA; + } break; + case Image::USED_CHANNELS_R: { + decompress_format = BASIS_DECOMPRESS_RGB; + } break; + case Image::USED_CHANNELS_RG: { + // Currently RG textures are compressed as DXT5/ETC2_RGBA8 with a RA -> RG swizzle, + // as BasisUniversal didn't use to support ETC2_RG11 transcoding. + params.m_force_alpha = true; + image->convert_rg_to_ra_rgba8(); + decompress_format = BASIS_DECOMPRESS_RG_AS_RA; + } break; + case Image::USED_CHANNELS_RGB: { + decompress_format = BASIS_DECOMPRESS_RGB; + } break; + case Image::USED_CHANNELS_RGBA: { + params.m_force_alpha = true; + decompress_format = BASIS_DECOMPRESS_RGBA; + } break; + } + + { + // Encode the image with mipmaps. + Vector<uint8_t> image_data = image->get_data(); + basisu::vector<basisu::image> basisu_mipmaps; + + for (int32_t i = 0; i <= image->get_mipmap_count(); i++) { + int ofs, size, width, height; + image->get_mipmap_offset_size_and_dimensions(i, ofs, size, width, height); + + basisu::image basisu_image(width, height); + memcpy(basisu_image.get_ptr(), image_data.ptr() + ofs, size); + + if (i == 0) { + params.m_source_images.push_back(basisu_image); + } else { + basisu_mipmaps.push_back(basisu_image); + } + } + + params.m_source_mipmap_images.push_back(basisu_mipmaps); + } + + // Encode the image data. + Vector<uint8_t> basisu_data; + + basisu::basis_compressor compressor; + compressor.init(params); + + int basisu_err = compressor.process(); + ERR_FAIL_COND_V(basisu_err != basisu::basis_compressor::cECSuccess, basisu_data); + + const basisu::uint8_vec &basisu_out = compressor.get_output_basis_file(); + basisu_data.resize(basisu_out.size() + 4); + + // Copy the encoded data to the buffer. + { + uint8_t *w = basisu_data.ptrw(); + *(uint32_t *)w = decompress_format; + + memcpy(w + 4, basisu_out.get_ptr(), basisu_out.size()); + } + + return basisu_data; +} +#endif // TOOLS_ENABLED + +Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { + Ref<Image> image; + ERR_FAIL_NULL_V_MSG(p_data, image, "Cannot unpack invalid BasisUniversal data."); + + const uint8_t *src_ptr = p_data; + int src_size = p_size; + + basist::transcoder_texture_format basisu_format = basist::transcoder_texture_format::cTFTotalTextureFormats; + Image::Format image_format = Image::FORMAT_MAX; + + // Get supported compression formats. + bool bptc_supported = RS::get_singleton()->has_os_feature("bptc"); + bool s3tc_supported = RS::get_singleton()->has_os_feature("s3tc"); + bool etc2_supported = RS::get_singleton()->has_os_feature("etc2"); + + switch (*(uint32_t *)(src_ptr)) { + case BASIS_DECOMPRESS_RG: { + // RGTC transcoding is currently performed with RG_AS_RA, fail. + ERR_FAIL_V(image); + } break; + case BASIS_DECOMPRESS_RGB: { + if (bptc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC7_M6_OPAQUE_ONLY; + image_format = Image::FORMAT_BPTC_RGBA; + } else if (s3tc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC1; + image_format = Image::FORMAT_DXT1; + } else if (etc2_supported) { + basisu_format = basist::transcoder_texture_format::cTFETC1; + image_format = Image::FORMAT_ETC2_RGB8; + } else { + // No supported VRAM compression formats, decompress. + basisu_format = basist::transcoder_texture_format::cTFRGBA32; + image_format = Image::FORMAT_RGBA8; + } + + } break; + case BASIS_DECOMPRESS_RGBA: { + if (bptc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC7_M5; + image_format = Image::FORMAT_BPTC_RGBA; + } else if (s3tc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC3; + image_format = Image::FORMAT_DXT5; + } else if (etc2_supported) { + basisu_format = basist::transcoder_texture_format::cTFETC2; + image_format = Image::FORMAT_ETC2_RGBA8; + } else { + // No supported VRAM compression formats, decompress. + basisu_format = basist::transcoder_texture_format::cTFRGBA32; + image_format = Image::FORMAT_RGBA8; + } + } break; + case BASIS_DECOMPRESS_RG_AS_RA: { + if (s3tc_supported) { + basisu_format = basist::transcoder_texture_format::cTFBC3; + image_format = Image::FORMAT_DXT5_RA_AS_RG; + } else if (etc2_supported) { + basisu_format = basist::transcoder_texture_format::cTFETC2; + image_format = Image::FORMAT_ETC2_RA_AS_RG; + } else { + // No supported VRAM compression formats, decompress. + basisu_format = basist::transcoder_texture_format::cTFRGBA32; + image_format = Image::FORMAT_RGBA8; + } + } break; + } + + src_ptr += 4; + src_size -= 4; + + basist::basisu_transcoder transcoder; + ERR_FAIL_COND_V(!transcoder.validate_header(src_ptr, src_size), image); + + transcoder.start_transcoding(src_ptr, src_size); + + basist::basisu_image_info basisu_info; + transcoder.get_image_info(src_ptr, src_size, basisu_info, 0); + + Vector<uint8_t> out_data; + out_data.resize(Image::get_image_data_size(basisu_info.m_width, basisu_info.m_height, image_format, basisu_info.m_total_levels > 1)); + + uint8_t *dst = out_data.ptrw(); + memset(dst, 0, out_data.size()); + + uint32_t mip_count = Image::get_image_required_mipmaps(basisu_info.m_orig_width, basisu_info.m_orig_height, image_format); + for (uint32_t i = 0; i <= mip_count; i++) { + basist::basisu_image_level_info basisu_level; + transcoder.get_image_level_info(src_ptr, src_size, basisu_level, 0, i); + + int ofs = Image::get_image_mipmap_offset(basisu_info.m_width, basisu_info.m_height, image_format, i); + bool result = transcoder.transcode_image_level(src_ptr, src_size, 0, i, dst + ofs, basisu_level.m_total_blocks, basisu_format); + + if (!result) { + print_line(vformat("BasisUniversal cannot unpack level %d.", i)); + break; + } + } + + image = Image::create_from_data(basisu_info.m_width, basisu_info.m_height, basisu_info.m_total_levels > 1, image_format, out_data); + + return image; +} + +Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { + return basis_universal_unpacker_ptr(p_buffer.ptr(), p_buffer.size()); +} diff --git a/modules/basis_universal/image_compress_basisu.h b/modules/basis_universal/image_compress_basisu.h new file mode 100644 index 0000000000..ac5d62ae73 --- /dev/null +++ b/modules/basis_universal/image_compress_basisu.h @@ -0,0 +1,52 @@ +/**************************************************************************/ +/* image_compress_basisu.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef IMAGE_COMPRESS_BASISU_H +#define IMAGE_COMPRESS_BASISU_H + +#include "core/io/image.h" + +enum BasisDecompressFormat { + BASIS_DECOMPRESS_RG, + BASIS_DECOMPRESS_RGB, + BASIS_DECOMPRESS_RGBA, + BASIS_DECOMPRESS_RG_AS_RA, +}; + +void basis_universal_init(); + +#ifdef TOOLS_ENABLED +Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels); +#endif + +Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size); +Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer); + +#endif // IMAGE_COMPRESS_BASISU_H diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index c9ea67cb09..06a3fb76cb 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -30,262 +30,19 @@ #include "register_types.h" -#include "core/os/os.h" -#include "servers/rendering_server.h" - -#include <transcoder/basisu_transcoder.h> - -#ifdef TOOLS_ENABLED -#include <encoder/basisu_comp.h> -#endif - -enum BasisDecompressFormat { - BASIS_DECOMPRESS_RG, - BASIS_DECOMPRESS_RGB, - BASIS_DECOMPRESS_RGBA, - BASIS_DECOMPRESS_RG_AS_RA -}; - -//workaround for lack of ETC2 RG -#define USE_RG_AS_RGBA - -#ifdef TOOLS_ENABLED -static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels) { - Vector<uint8_t> budata; - { - basisu::basis_compressor_params params; - Ref<Image> image = p_image->duplicate(); - if (image->get_format() != Image::FORMAT_RGBA8) { - image->convert(Image::FORMAT_RGBA8); - } - - params.m_uastc = true; - params.m_quality_level = basisu::BASISU_QUALITY_MIN; - - params.m_pack_uastc_flags &= ~basisu::cPackUASTCLevelMask; - - static const uint32_t s_level_flags[basisu::TOTAL_PACK_UASTC_LEVELS] = { basisu::cPackUASTCLevelFastest, basisu::cPackUASTCLevelFaster, basisu::cPackUASTCLevelDefault, basisu::cPackUASTCLevelSlower, basisu::cPackUASTCLevelVerySlow }; - params.m_pack_uastc_flags |= s_level_flags[0]; - params.m_rdo_uastc = 0.0f; - params.m_rdo_uastc_quality_scalar = 0.0f; - params.m_rdo_uastc_dict_size = 1024; - - params.m_mip_fast = true; - params.m_multithreading = true; - - basisu::job_pool jpool(OS::get_singleton()->get_processor_count()); - params.m_pJob_pool = &jpool; - - BasisDecompressFormat decompress_format = BASIS_DECOMPRESS_RG; - params.m_check_for_alpha = false; - - switch (p_channels) { - case Image::USED_CHANNELS_L: { - decompress_format = BASIS_DECOMPRESS_RGB; - } break; - case Image::USED_CHANNELS_LA: { - params.m_force_alpha = true; - decompress_format = BASIS_DECOMPRESS_RGBA; - } break; - case Image::USED_CHANNELS_R: { - decompress_format = BASIS_DECOMPRESS_RGB; - } break; - case Image::USED_CHANNELS_RG: { -#ifdef USE_RG_AS_RGBA - params.m_force_alpha = true; - image->convert_rg_to_ra_rgba8(); - decompress_format = BASIS_DECOMPRESS_RG_AS_RA; -#else - params.m_seperate_rg_to_color_alpha = true; - decompress_format = BASIS_DECOMPRESS_RG; -#endif - } break; - case Image::USED_CHANNELS_RGB: { - decompress_format = BASIS_DECOMPRESS_RGB; - } break; - case Image::USED_CHANNELS_RGBA: { - params.m_force_alpha = true; - decompress_format = BASIS_DECOMPRESS_RGBA; - } break; - } - - if (!image->has_mipmaps()) { - basisu::image buimg(image->get_width(), image->get_height()); - Vector<uint8_t> vec = image->get_data(); - const uint8_t *r = vec.ptr(); - memcpy(buimg.get_ptr(), r, vec.size()); - params.m_source_images.push_back(buimg); - } else { - { - Ref<Image> base_image = image->get_image_from_mipmap(0); - Vector<uint8_t> image_vec = base_image->get_data(); - basisu::image buimg_image(base_image->get_width(), base_image->get_height()); - const uint8_t *r = image_vec.ptr(); - memcpy(buimg_image.get_ptr(), r, image_vec.size()); - params.m_source_images.push_back(buimg_image); - } - basisu::vector<basisu::image> images; - for (int32_t mip_map_i = 1; mip_map_i <= image->get_mipmap_count(); mip_map_i++) { - Ref<Image> mip_map = image->get_image_from_mipmap(mip_map_i); - Vector<uint8_t> mip_map_vec = mip_map->get_data(); - basisu::image buimg_mipmap(mip_map->get_width(), mip_map->get_height()); - const uint8_t *r = mip_map_vec.ptr(); - memcpy(buimg_mipmap.get_ptr(), r, mip_map_vec.size()); - images.push_back(buimg_mipmap); - } - params.m_source_mipmap_images.push_back(images); - } - - basisu::basis_compressor c; - c.init(params); - - int buerr = c.process(); - ERR_FAIL_COND_V(buerr != basisu::basis_compressor::cECSuccess, budata); - - const basisu::uint8_vec &buvec = c.get_output_basis_file(); - budata.resize(buvec.size() + 4); - - { - uint8_t *w = budata.ptrw(); - uint32_t *decf = (uint32_t *)w; - *decf = decompress_format; - memcpy(w + 4, &buvec[0], buvec.size()); - } - } - - return budata; -} -#endif // TOOLS_ENABLED - -static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) { - Ref<Image> image; - - const uint8_t *ptr = p_data; - int size = p_size; - ERR_FAIL_NULL_V_MSG(p_data, image, "Cannot unpack invalid basis universal data."); - - basist::transcoder_texture_format format = basist::transcoder_texture_format::cTFTotalTextureFormats; - Image::Format imgfmt = Image::FORMAT_MAX; - - switch (*(uint32_t *)(ptr)) { - case BASIS_DECOMPRESS_RG: { - if (RS::get_singleton()->has_os_feature("rgtc")) { - format = basist::transcoder_texture_format::cTFBC5; // get this from renderer - imgfmt = Image::FORMAT_RGTC_RG; - } else if (RS::get_singleton()->has_os_feature("etc2")) { - //unfortunately, basis universal does not support - // - ERR_FAIL_V(image); //unimplemented here - //format = basist::transcoder_texture_format::cTFETC1; // get this from renderer - //imgfmt = Image::FORMAT_RGTC_RG; - } else { - // FIXME: There wasn't anything here, but then imgformat is used uninitialized. - ERR_FAIL_V(image); - } - } break; - case BASIS_DECOMPRESS_RGB: { - if (RS::get_singleton()->has_os_feature("bptc")) { - format = basist::transcoder_texture_format::cTFBC7_M6_OPAQUE_ONLY; // get this from renderer - imgfmt = Image::FORMAT_BPTC_RGBA; - } else if (RS::get_singleton()->has_os_feature("s3tc")) { - format = basist::transcoder_texture_format::cTFBC1; // get this from renderer - imgfmt = Image::FORMAT_DXT1; - } else if (RS::get_singleton()->has_os_feature("etc2")) { - format = basist::transcoder_texture_format::cTFETC1; // get this from renderer - imgfmt = Image::FORMAT_ETC2_RGB8; - } else { - format = basist::transcoder_texture_format::cTFBGR565; // get this from renderer - imgfmt = Image::FORMAT_RGB565; - } - - } break; - case BASIS_DECOMPRESS_RGBA: { - if (RS::get_singleton()->has_os_feature("bptc")) { - format = basist::transcoder_texture_format::cTFBC7_M5; // get this from renderer - imgfmt = Image::FORMAT_BPTC_RGBA; - } else if (RS::get_singleton()->has_os_feature("s3tc")) { - format = basist::transcoder_texture_format::cTFBC3; // get this from renderer - imgfmt = Image::FORMAT_DXT5; - } else if (RS::get_singleton()->has_os_feature("etc2")) { - format = basist::transcoder_texture_format::cTFETC2; // get this from renderer - imgfmt = Image::FORMAT_ETC2_RGBA8; - } else { - //opengl most likely - format = basist::transcoder_texture_format::cTFRGBA4444; // get this from renderer - imgfmt = Image::FORMAT_RGBA4444; - } - } break; - case BASIS_DECOMPRESS_RG_AS_RA: { - if (RS::get_singleton()->has_os_feature("s3tc")) { - format = basist::transcoder_texture_format::cTFBC3; // get this from renderer - imgfmt = Image::FORMAT_DXT5_RA_AS_RG; - } else if (RS::get_singleton()->has_os_feature("etc2")) { - format = basist::transcoder_texture_format::cTFETC2; // get this from renderer - imgfmt = Image::FORMAT_ETC2_RA_AS_RG; - } else { - //opengl most likely, bad for normal maps, nothing to do about this. - format = basist::transcoder_texture_format::cTFRGBA32; - imgfmt = Image::FORMAT_RGBA8; - } - } break; - } - - ptr += 4; - size -= 4; - - basist::basisu_transcoder tr; - - ERR_FAIL_COND_V(!tr.validate_header(ptr, size), image); - - tr.start_transcoding(ptr, size); - - basist::basisu_image_info info; - tr.get_image_info(ptr, size, info, 0); - Vector<uint8_t> gpudata; - gpudata.resize(Image::get_image_data_size(info.m_width, info.m_height, imgfmt, info.m_total_levels > 1)); - - uint8_t *w = gpudata.ptrw(); - uint8_t *dst = w; - for (int i = 0; i < gpudata.size(); i++) { - dst[i] = 0x00; - } - uint32_t mip_count = Image::get_image_required_mipmaps(info.m_orig_width, info.m_orig_height, imgfmt); - for (uint32_t level_i = 0; level_i <= mip_count; level_i++) { - basist::basisu_image_level_info level; - tr.get_image_level_info(ptr, size, level, 0, level_i); - int ofs = Image::get_image_mipmap_offset(info.m_width, info.m_height, imgfmt, level_i); - bool ret = tr.transcode_image_level(ptr, size, 0, level_i, dst + ofs, level.m_total_blocks, format); - if (!ret) { - print_line(vformat("Basis universal cannot unpack level %d.", level_i)); - break; - }; - } - - image = Image::create_from_data(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata); - - return image; -} - -static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { - Ref<Image> image; - - const uint8_t *r = p_buffer.ptr(); - int size = p_buffer.size(); - return basis_universal_unpacker_ptr(r, size); -} +#include "image_compress_basisu.h" void initialize_basis_universal_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } + basis_universal_init(); + #ifdef TOOLS_ENABLED - using namespace basisu; - using namespace basist; - basisu_encoder_init(); Image::basis_universal_packer = basis_universal_packer; #endif - basist::basisu_transcoder_init(); + Image::basis_universal_unpacker = basis_universal_unpacker; Image::basis_universal_unpacker_ptr = basis_universal_unpacker_ptr; } @@ -298,6 +55,7 @@ void uninitialize_basis_universal_module(ModuleInitializationLevel p_level) { #ifdef TOOLS_ENABLED Image::basis_universal_packer = nullptr; #endif + Image::basis_universal_unpacker = nullptr; Image::basis_universal_unpacker_ptr = nullptr; } diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index a485b57a64..28ab8e3335 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -830,8 +830,9 @@ bool EditorExportPlatformAndroid::_uses_vulkan() { void EditorExportPlatformAndroid::_notification(int p_what) { #ifndef ANDROID_ENABLED if (p_what == NOTIFICATION_POSTINITIALIZE) { - ERR_FAIL_NULL(EditorExport::get_singleton()); - EditorExport::get_singleton()->connect_presets_runnable_updated(callable_mp(this, &EditorExportPlatformAndroid::_update_preset_status)); + if (EditorExport::get_singleton()) { + EditorExport::get_singleton()->connect_presets_runnable_updated(callable_mp(this, &EditorExportPlatformAndroid::_update_preset_status)); + } } #endif } diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index ea2b23cfb9..91d75b0629 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -127,7 +127,9 @@ String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPres void EditorExportPlatformIOS::_notification(int p_what) { #ifdef MACOS_ENABLED if (p_what == NOTIFICATION_POSTINITIALIZE) { - EditorExport::get_singleton()->connect_presets_runnable_updated(callable_mp(this, &EditorExportPlatformIOS::_update_preset_status)); + if (EditorExport::get_singleton()) { + EditorExport::get_singleton()->connect_presets_runnable_updated(callable_mp(this, &EditorExportPlatformIOS::_update_preset_status)); + } } #endif } diff --git a/scene/audio/audio_stream_player_internal.cpp b/scene/audio/audio_stream_player_internal.cpp index d5f6f91c88..19b3ec481b 100644 --- a/scene/audio/audio_stream_player_internal.cpp +++ b/scene/audio/audio_stream_player_internal.cpp @@ -38,7 +38,7 @@ void AudioStreamPlayerInternal::_set_process(bool p_enabled) { if (physical) { node->set_physics_process_internal(p_enabled); } else { - node->set_process(p_enabled); + node->set_process_internal(p_enabled); } } |
