Merge pull request #44039 from akien-mga/3.2-cherrypicks

Cherry-picks for the 3.2 branch (future 3.2.4) - 11th batch
This commit is contained in:
Rémi Verschelde 2020-12-02 17:09:27 +01:00 committed by GitHub
commit 77e6164a3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 2785 additions and 3359 deletions

View File

@ -136,6 +136,10 @@ void MultiplayerAPI::set_root_node(Node *p_node) {
root_node = p_node; root_node = p_node;
} }
Node *MultiplayerAPI::get_root_node() {
return root_node;
}
void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer) { void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer) {
if (p_peer == network_peer) return; // Nothing to do if (p_peer == network_peer) return; // Nothing to do
@ -947,6 +951,7 @@ void MultiplayerAPI::_init_node_profile(ObjectID p_node) {
void MultiplayerAPI::_bind_methods() { void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
ClassDB::bind_method(D_METHOD("get_root_node"), &MultiplayerAPI::get_root_node);
ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE)); ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer); ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer);
ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer); ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer);
@ -971,6 +976,7 @@ void MultiplayerAPI::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_node", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_root_node", "get_root_node");
ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false); ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false);
ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id")));

View File

@ -131,6 +131,7 @@ public:
void poll(); void poll();
void clear(); void clear();
void set_root_node(Node *p_node); void set_root_node(Node *p_node);
Node *get_root_node();
void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer); void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer);
Ref<NetworkedMultiplayerPeer> get_network_peer() const; Ref<NetworkedMultiplayerPeer> get_network_peer() const;
Error send_bytes(PoolVector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); Error send_bytes(PoolVector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);

View File

@ -178,7 +178,6 @@ Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
_sock->set_blocking_enabled(false); _sock->set_blocking_enabled(false);
_sock->set_reuse_address_enabled(true);
_sock->set_broadcasting_enabled(broadcast); _sock->set_broadcasting_enabled(broadcast);
err = _sock->bind(p_bind_address, p_port); err = _sock->bind(p_bind_address, p_port);

View File

@ -380,7 +380,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
#ifdef OSX_ENABLED #ifdef OSX_ENABLED
if (!found) { if (!found) {
// Attempt to load PCK from macOS .app bundle resources. // Attempt to load PCK from macOS .app bundle resources.
found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck")); found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_filename + ".pck"));
} }
#endif #endif

View File

@ -145,7 +145,7 @@
<argument index="1" name="cubic" type="bool" default="false"> <argument index="1" name="cubic" type="bool" default="false">
</argument> </argument>
<description> <description>
Returns a point within the curve at position [code]offset[/code], where [code]offset[/code] is measured as a pixel distance along the curve. Returns a point within the curve at position [code]offset[/code], where [code]offset[/code] is measured as a distance in 3D units along the curve.
To do that, it finds the two cached points where the [code]offset[/code] lies between, then interpolates the values. This interpolation is cubic if [code]cubic[/code] is set to [code]true[/code], or linear if set to [code]false[/code]. To do that, it finds the two cached points where the [code]offset[/code] lies between, then interpolates the values. This interpolation is cubic if [code]cubic[/code] is set to [code]true[/code], or linear if set to [code]false[/code].
Cubic interpolation tends to follow the curves better, but linear is faster (and often, precise enough). Cubic interpolation tends to follow the curves better, but linear is faster (and often, precise enough).
</description> </description>

View File

@ -49,7 +49,7 @@
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns the acceleration of the device's accelerometer, if the device has one. Otherwise, the method returns [constant Vector3.ZERO]. Returns the acceleration of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
Note this method returns an empty [Vector3] when running from the editor even when your device has an accelerometer. You must export your project to a supported device to read values from the accelerometer. Note this method returns an empty [Vector3] when running from the editor even when your device has an accelerometer. You must export your project to a supported device to read values from the accelerometer.
[b]Note:[/b] This method only works on iOS, Android, and UWP. On other platforms, it always returns [constant Vector3.ZERO]. [b]Note:[/b] This method only works on iOS, Android, and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description> </description>
@ -81,7 +81,7 @@
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns the gravity of the device's accelerometer, if the device has one. Otherwise, the method returns [constant Vector3.ZERO]. Returns the gravity of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
[b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO]. [b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO].
</description> </description>
</method> </method>
@ -89,8 +89,8 @@
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns the rotation rate in rad/s around a device's X, Y, and Z axes of the gyroscope, if the device has one. Otherwise, the method returns [constant Vector3.ZERO]. Returns the rotation rate in rad/s around a device's X, Y, and Z axes of the gyroscope sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
[b]Note:[/b] This method only works on Android. On other platforms, it always returns [constant Vector3.ZERO]. [b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO].
</description> </description>
</method> </method>
<method name="get_joy_axis" qualifiers="const"> <method name="get_joy_axis" qualifiers="const">
@ -187,8 +187,8 @@
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns the the magnetic field strength in micro-Tesla for all axes of the device's magnetometer, if the device has one. Otherwise, the method returns [constant Vector3.ZERO]. Returns the the magnetic field strength in micro-Tesla for all axes of the device's magnetometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
[b]Note:[/b] This method only works on Android and UWP. On other platforms, it always returns [constant Vector3.ZERO]. [b]Note:[/b] This method only works on Android, iOS and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description> </description>
</method> </method>
<method name="get_mouse_button_mask" qualifiers="const"> <method name="get_mouse_button_mask" qualifiers="const">
@ -391,7 +391,7 @@
</argument> </argument>
<description> <description>
Vibrate Android and iOS devices. Vibrate Android and iOS devices.
[b]Note:[/b] It needs VIBRATE permission for Android at export settings. iOS does not support duration. [b]Note:[/b] It needs [code]VIBRATE[/code] permission for Android at export settings. iOS does not support duration.
</description> </description>
</method> </method>
<method name="warp_mouse_position"> <method name="warp_mouse_position">

View File

@ -75,16 +75,6 @@
Sends the given raw [code]bytes[/code] to a specific peer identified by [code]id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). Default ID is [code]0[/code], i.e. broadcast to all peers. Sends the given raw [code]bytes[/code] to a specific peer identified by [code]id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). Default ID is [code]0[/code], i.e. broadcast to all peers.
</description> </description>
</method> </method>
<method name="set_root_node">
<return type="void">
</return>
<argument index="0" name="node" type="Node">
</argument>
<description>
Sets the base root node to use for RPCs. Instead of an absolute path, a relative path will be used to find the node upon which the RPC should be executed.
This effectively allows to have different branches of the scene tree to be managed by different MultiplayerAPI, allowing for example to run both client and server in the same scene.
</description>
</method>
</methods> </methods>
<members> <members>
<member name="allow_object_decoding" type="bool" setter="set_allow_object_decoding" getter="is_object_decoding_allowed" default="false"> <member name="allow_object_decoding" type="bool" setter="set_allow_object_decoding" getter="is_object_decoding_allowed" default="false">
@ -97,6 +87,10 @@
<member name="refuse_new_network_connections" type="bool" setter="set_refuse_new_network_connections" getter="is_refusing_new_network_connections" default="false"> <member name="refuse_new_network_connections" type="bool" setter="set_refuse_new_network_connections" getter="is_refusing_new_network_connections" default="false">
If [code]true[/code], the MultiplayerAPI's [member network_peer] refuses new incoming connections. If [code]true[/code], the MultiplayerAPI's [member network_peer] refuses new incoming connections.
</member> </member>
<member name="root_node" type="Node" setter="set_root_node" getter="get_root_node">
The root node to use for RPCs. Instead of an absolute path, a relative path will be used to find the node upon which the RPC should be executed.
This effectively allows to have different branches of the scene tree to be managed by different MultiplayerAPI, allowing for example to run both client and server in the same scene.
</member>
</members> </members>
<signals> <signals>
<signal name="connected_to_server"> <signal name="connected_to_server">

View File

@ -76,7 +76,21 @@
<argument index="0" name="path" type="String"> <argument index="0" name="path" type="String">
</argument> </argument>
<description> <description>
Converts a localized path ([code]res://[/code]) to a full native OS path. Returns the absolute, native OS path corresponding to the localized [code]path[/code] (starting with [code]res://[/code] or [code]user://[/code]). The returned path will vary depending on the operating system and user preferences. See [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]File paths in Godot projects[/url] to see what those paths convert to. See also [method localize_path].
[b]Note:[/b] [method globalize_path] with [code]res://[/code] will not work in an exported project. Instead, prepend the executable's base directory to the path when running from an exported project:
[codeblock]
var path = ""
if OS.has_feature("editor"):
# Running from an editor binary.
# `path` will contain the absolute path to `hello.txt` located in the project root.
path = ProjectSettings.globalize_path("res://hello.txt")
else:
# Running from an exported project.
# `path` will contain the absolute path to `hello.txt` next to the executable.
# This is *not* identical to using `ProjectSettings.globalize_path()` with a `res://` path,
# but is close enough in spirit.
path = OS.get_executable_path().get_base_dir().plus_file("hello.txt")
[/codeblock]
</description> </description>
</method> </method>
<method name="has_setting" qualifiers="const"> <method name="has_setting" qualifiers="const">
@ -109,7 +123,7 @@
<argument index="0" name="path" type="String"> <argument index="0" name="path" type="String">
</argument> </argument>
<description> <description>
Convert a path to a localized path ([code]res://[/code] path). Returns the localized path (starting with [code]res://[/code]) corresponding to the absolute, native OS [code]path[/code]. See also [method globalize_path].
</description> </description>
</method> </method>
<method name="property_can_revert"> <method name="property_can_revert">

View File

@ -187,7 +187,7 @@ void AudioDriverALSA::thread_func(void *p_udata) {
int total = 0; int total = 0;
while (todo && !ad->exit_thread) { while (todo && !ad->exit_thread) {
uint8_t *src = (uint8_t *)ad->samples_out.ptr(); int16_t *src = (int16_t *)ad->samples_out.ptr();
int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo); int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo);
if (wrote > 0) { if (wrote > 0) {

View File

@ -398,6 +398,7 @@ ConnectDialog::ConnectDialog() {
tree = memnew(SceneTreeEditor(false)); tree = memnew(SceneTreeEditor(false));
tree->set_connecting_signal(true); tree->set_connecting_signal(true);
tree->set_show_enabled_subscene(true);
tree->get_scene_tree()->connect("item_activated", this, "_ok"); tree->get_scene_tree()->connect("item_activated", this, "_ok");
tree->connect("node_selected", this, "_tree_node_selected"); tree->connect("node_selected", this, "_tree_node_selected");
tree->set_connect_to_script_mode(true); tree->set_connect_to_script_mode(true);

View File

@ -63,12 +63,11 @@
#define GIZMO_SCALE_OFFSET (GIZMO_CIRCLE_SIZE + 0.3) #define GIZMO_SCALE_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
#define GIZMO_ARROW_OFFSET (GIZMO_CIRCLE_SIZE + 0.3) #define GIZMO_ARROW_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
#define ZOOM_MIN_DISTANCE 0.001 #define ZOOM_FREELOOK_MIN 0.01
#define ZOOM_MULTIPLIER 1.08 #define ZOOM_FREELOOK_MULTIPLIER 1.08
#define ZOOM_INDICATOR_DELAY_S 1.5 #define ZOOM_FREELOOK_INDICATOR_DELAY_S 1.5
#define FREELOOK_MIN_SPEED 0.01 #define ZOOM_FREELOOK_MAX 10'000
#define FREELOOK_SPEED_MULTIPLIER 1.08
#define MIN_Z 0.01 #define MIN_Z 0.01
#define MAX_Z 1000000.0 #define MAX_Z 1000000.0
@ -1099,9 +1098,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (b.is_valid()) { if (b.is_valid()) {
emit_signal("clicked", this); emit_signal("clicked", this);
float zoom_factor = 1 + (ZOOM_MULTIPLIER - 1) * b->get_factor(); float zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor();
switch (b->get_button_index()) { switch (b->get_button_index()) {
case BUTTON_WHEEL_UP: { case BUTTON_WHEEL_UP: {
if (is_freelook_active()) if (is_freelook_active())
scale_freelook_speed(zoom_factor); scale_freelook_speed(zoom_factor);
@ -2216,32 +2214,28 @@ void SpatialEditorViewport::set_freelook_active(bool active_now) {
} }
void SpatialEditorViewport::scale_cursor_distance(real_t scale) { void SpatialEditorViewport::scale_cursor_distance(real_t scale) {
real_t min_distance = MAX(camera->get_znear() * 4, ZOOM_FREELOOK_MIN);
real_t max_distance = MIN(camera->get_zfar() / 4, ZOOM_FREELOOK_MAX);
if (unlikely(min_distance > max_distance)) {
cursor.distance = (min_distance + max_distance) / 2;
} else {
cursor.distance = CLAMP(cursor.distance * scale, min_distance, max_distance);
}
// Prevents zero distance which would short-circuit any scaling zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
if (cursor.distance < ZOOM_MIN_DISTANCE)
cursor.distance = ZOOM_MIN_DISTANCE;
cursor.distance *= scale;
if (cursor.distance < ZOOM_MIN_DISTANCE)
cursor.distance = ZOOM_MIN_DISTANCE;
zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
surface->update(); surface->update();
} }
void SpatialEditorViewport::scale_freelook_speed(real_t scale) { void SpatialEditorViewport::scale_freelook_speed(real_t scale) {
real_t min_speed = MAX(camera->get_znear() * 4, ZOOM_FREELOOK_MIN);
real_t max_speed = MIN(camera->get_zfar() / 4, ZOOM_FREELOOK_MAX);
if (unlikely(min_speed > max_speed)) {
freelook_speed = (min_speed + max_speed) / 2;
} else {
freelook_speed = CLAMP(freelook_speed * scale, min_speed, max_speed);
}
// Prevents zero distance which would short-circuit any scaling zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
if (freelook_speed < FREELOOK_MIN_SPEED)
freelook_speed = FREELOOK_MIN_SPEED;
freelook_speed *= scale;
if (freelook_speed < FREELOOK_MIN_SPEED)
freelook_speed = FREELOOK_MIN_SPEED;
zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
surface->update(); surface->update();
} }
@ -2694,18 +2688,13 @@ void SpatialEditorViewport::_draw() {
if (is_freelook_active()) { if (is_freelook_active()) {
// Show speed // Show speed
real_t min_speed = FREELOOK_MIN_SPEED; real_t min_speed = MAX(camera->get_znear() * 4, ZOOM_FREELOOK_MIN);
real_t max_speed = camera->get_zfar(); real_t max_speed = MIN(camera->get_zfar() / 4, ZOOM_FREELOOK_MAX);
real_t scale_length = (max_speed - min_speed); real_t scale_length = (max_speed - min_speed);
if (!Math::is_zero_approx(scale_length)) { if (!Math::is_zero_approx(scale_length)) {
real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length); real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length);
// There is no real maximum speed so that factor can become negative,
// Let's make it look asymptotic instead (will decrease slower and slower).
if (logscale_t < 0.25)
logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
// Display the freelook speed to help the user get a better sense of scale. // Display the freelook speed to help the user get a better sense of scale.
const int precision = freelook_speed < 1.0 ? 2 : 1; const int precision = freelook_speed < 1.0 ? 2 : 1;
draw_indicator_bar( draw_indicator_bar(
@ -2719,18 +2708,13 @@ void SpatialEditorViewport::_draw() {
} else { } else {
// Show zoom // Show zoom
real_t min_distance = ZOOM_MIN_DISTANCE; // TODO Why not pick znear to limit zoom? real_t min_distance = MAX(camera->get_znear() * 4, ZOOM_FREELOOK_MIN);
real_t max_distance = camera->get_zfar(); real_t max_distance = MIN(camera->get_zfar() / 4, ZOOM_FREELOOK_MAX);
real_t scale_length = (max_distance - min_distance); real_t scale_length = (max_distance - min_distance);
if (!Math::is_zero_approx(scale_length)) { if (!Math::is_zero_approx(scale_length)) {
real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length); real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length);
// There is no real maximum distance so that factor can become negative,
// Let's make it look asymptotic instead (will decrease slower and slower).
if (logscale_t < 0.25)
logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
// Display the zoom center distance to help the user get a better sense of scale. // Display the zoom center distance to help the user get a better sense of scale.
const int precision = cursor.distance < 1.0 ? 2 : 1; const int precision = cursor.distance < 1.0 ? 2 : 1;
draw_indicator_bar( draw_indicator_bar(

View File

@ -1559,7 +1559,7 @@ bool Main::start() {
{ {
DirAccessRef da = DirAccess::open(doc_tool); DirAccessRef da = DirAccess::open(doc_tool);
ERR_FAIL_COND_V_MSG(!da, false, "Argument supplied to --doctool must be a base Godot build directory."); ERR_FAIL_COND_V_MSG(!da, false, "Argument supplied to --doctool must be a valid directory path.");
} }
DocData doc; DocData doc;
doc.generate(doc_base); doc.generate(doc_base);

View File

@ -64,11 +64,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
xatlas::Atlas *atlas = xatlas::Create(); xatlas::Atlas *atlas = xatlas::Create();
printf("Adding mesh..\n"); printf("Adding mesh..\n");
xatlas::AddMeshError::Enum err = xatlas::AddMesh(atlas, input_mesh, 1); xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Enum::Success, false, xatlas::StringForEnum(err)); ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
printf("Generate..\n"); printf("Generate..\n");
xatlas::Generate(atlas, chart_options, xatlas::ParameterizeOptions(), pack_options); xatlas::Generate(atlas, chart_options, xatlas::PackOptions());
*r_size_hint_x = atlas->width; *r_size_hint_x = atlas->width;
*r_size_hint_y = atlas->height; *r_size_hint_y = atlas->height;

View File

@ -45,6 +45,7 @@
#endif #endif
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@ -800,6 +800,11 @@ Error ResourceInteractiveLoaderText::rename_dependencies(FileAccess *p_f, const
f->seek(tag_end); f->seek(tag_end);
uint8_t c = f->get_8(); uint8_t c = f->get_8();
if (c == '\n' && !f->eof_reached()) {
// Skip first newline character since we added one
c = f->get_8();
}
while (!f->eof_reached()) { while (!f->eof_reached()) {
fw->store_8(c); fw->store_8(c);
c = f->get_8(); c = f->get_8();

View File

@ -488,7 +488,7 @@ File extracted from upstream release tarball:
## xatlas ## xatlas
- Upstream: https://github.com/jpcy/xatlas - Upstream: https://github.com/jpcy/xatlas
- Version: git (470576d3516f7e6d8b4554e7c941194a935969fd, 2020) - Version: git (5571fc7ef0d06832947c0a935ccdcf083f7a9264, 2020)
- License: MIT - License: MIT
Files extracted from upstream source: Files extracted from upstream source:

File diff suppressed because it is too large Load Diff

View File

@ -31,35 +31,30 @@ Copyright NVIDIA Corporation 2006 -- Ignacio Castano <icastano@nvidia.com>
#pragma once #pragma once
#ifndef XATLAS_H #ifndef XATLAS_H
#define XATLAS_H #define XATLAS_H
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
namespace xatlas { namespace xatlas {
struct ChartType enum class ChartType {
{ Planar,
enum Enum Ortho,
{ LSCM,
Planar, Piecewise,
Ortho, Invalid
LSCM,
Piecewise,
Invalid
};
}; };
// A group of connected faces, belonging to a single atlas. // A group of connected faces, belonging to a single atlas.
struct Chart struct Chart {
{
uint32_t *faceArray; uint32_t *faceArray;
uint32_t atlasIndex; // Sub-atlas index. uint32_t atlasIndex; // Sub-atlas index.
uint32_t faceCount; uint32_t faceCount;
ChartType::Enum type; ChartType type;
uint32_t material; uint32_t material;
}; };
// Output vertex. // Output vertex.
struct Vertex struct Vertex {
{
int32_t atlasIndex; // Sub-atlas index. -1 if the vertex doesn't exist in any atlas. int32_t atlasIndex; // Sub-atlas index. -1 if the vertex doesn't exist in any atlas.
int32_t chartIndex; // -1 if the vertex doesn't exist in any chart. int32_t chartIndex; // -1 if the vertex doesn't exist in any chart.
float uv[2]; // Not normalized - values are in Atlas width and height range. float uv[2]; // Not normalized - values are in Atlas width and height range.
@ -67,8 +62,7 @@ struct Vertex
}; };
// Output mesh. // Output mesh.
struct Mesh struct Mesh {
{
Chart *chartArray; Chart *chartArray;
uint32_t *indexArray; uint32_t *indexArray;
Vertex *vertexArray; Vertex *vertexArray;
@ -83,16 +77,15 @@ static const uint32_t kImageIsBilinearBit = 0x40000000;
static const uint32_t kImageIsPaddingBit = 0x20000000; static const uint32_t kImageIsPaddingBit = 0x20000000;
// Empty on creation. Populated after charts are packed. // Empty on creation. Populated after charts are packed.
struct Atlas struct Atlas {
{
uint32_t *image; uint32_t *image;
Mesh *meshes; // The output meshes, corresponding to each AddMesh call. Mesh *meshes; // The output meshes, corresponding to each AddMesh call.
float *utilization; // Normalized atlas texel utilization array. E.g. a value of 0.8 means 20% empty space. atlasCount in length.
uint32_t width; // Atlas width in texels. uint32_t width; // Atlas width in texels.
uint32_t height; // Atlas height in texels. uint32_t height; // Atlas height in texels.
uint32_t atlasCount; // Number of sub-atlases. Equal to 0 unless PackOptions resolution is changed from default (0). uint32_t atlasCount; // Number of sub-atlases. Equal to 0 unless PackOptions resolution is changed from default (0).
uint32_t chartCount; // Total number of charts in all meshes. uint32_t chartCount; // Total number of charts in all meshes.
uint32_t meshCount; // Number of output meshes. Equal to the number of times AddMesh was called. uint32_t meshCount; // Number of output meshes. Equal to the number of times AddMesh was called.
float *utilization; // Normalized atlas texel utilization array. E.g. a value of 0.8 means 20% empty space. atlasCount in length.
float texelsPerUnit; // Equal to PackOptions texelsPerUnit if texelsPerUnit > 0, otherwise an estimated value to match PackOptions resolution. float texelsPerUnit; // Equal to PackOptions texelsPerUnit if texelsPerUnit > 0, otherwise an estimated value to match PackOptions resolution.
}; };
@ -101,73 +94,76 @@ Atlas *Create();
void Destroy(Atlas *atlas); void Destroy(Atlas *atlas);
struct IndexFormat enum class IndexFormat {
{ UInt16,
enum Enum UInt32
{
UInt16,
UInt32
};
}; };
// Input mesh declaration. // Input mesh declaration.
struct MeshDecl struct MeshDecl {
{
const void *vertexPositionData = nullptr; const void *vertexPositionData = nullptr;
const void *vertexNormalData = nullptr; // optional const void *vertexNormalData = nullptr; // optional
const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator. const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator.
const void *indexData = nullptr; // optional const void *indexData = nullptr; // optional
// Optional. indexCount / 3 (triangle count) in length. // Optional. Must be faceCount in length.
// Don't atlas faces set to true. Ignored faces still exist in the output meshes, Vertex uv is set to (0, 0) and Vertex atlasIndex to -1. // Don't atlas faces set to true. Ignored faces still exist in the output meshes, Vertex uv is set to (0, 0) and Vertex atlasIndex to -1.
const bool *faceIgnoreData = nullptr; const bool *faceIgnoreData = nullptr;
// Optional. Must be faceCount in length.
// Only faces with the same material will be assigned to the same chart.
const uint32_t *faceMaterialData = nullptr;
// Optional. Must be faceCount in length.
// Polygon / n-gon support. Faces are assumed to be triangles if this is null.
const uint8_t *faceVertexCount = nullptr;
uint32_t vertexCount = 0; uint32_t vertexCount = 0;
uint32_t vertexPositionStride = 0; uint32_t vertexPositionStride = 0;
uint32_t vertexNormalStride = 0; // optional uint32_t vertexNormalStride = 0; // optional
uint32_t vertexUvStride = 0; // optional uint32_t vertexUvStride = 0; // optional
uint32_t indexCount = 0; uint32_t indexCount = 0;
int32_t indexOffset = 0; // optional. Add this offset to all indices. int32_t indexOffset = 0; // optional. Add this offset to all indices.
IndexFormat::Enum indexFormat = IndexFormat::UInt16; uint32_t faceCount = 0; // Optional if faceVertexCount is null. Otherwise assumed to be indexCount / 3.
IndexFormat indexFormat = IndexFormat::UInt16;
// Vertex positions within epsilon distance of each other are considered colocal. // Vertex positions within epsilon distance of each other are considered colocal.
float epsilon = 1.192092896e-07F; float epsilon = 1.192092896e-07F;
}; };
struct AddMeshError enum class AddMeshError {
{ Success, // No error.
enum Enum Error, // Unspecified error.
{ IndexOutOfRange, // An index is >= MeshDecl vertexCount.
Success, // No error. InvalidFaceVertexCount, // Must be >= 3.
Error, // Unspecified error. InvalidIndexCount // Not evenly divisible by 3 - expecting triangles.
IndexOutOfRange, // An index is >= MeshDecl vertexCount.
InvalidIndexCount // Not evenly divisible by 3 - expecting triangles.
};
}; };
// Add a mesh to the atlas. MeshDecl data is copied, so it can be freed after AddMesh returns. // Add a mesh to the atlas. MeshDecl data is copied, so it can be freed after AddMesh returns.
AddMeshError::Enum AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint = 0); AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint = 0);
// Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally. // Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally.
void AddMeshJoin(Atlas *atlas); void AddMeshJoin(Atlas *atlas);
struct UvMeshDecl struct UvMeshDecl {
{
const void *vertexUvData = nullptr; const void *vertexUvData = nullptr;
const void *indexData = nullptr; // optional const void *indexData = nullptr; // optional
const uint32_t *faceMaterialData = nullptr; // Optional. Faces with different materials won't be assigned to the same chart. Must be indexCount / 3 in length. const uint32_t *faceMaterialData = nullptr; // Optional. Overlapping UVs should be assigned a different material. Must be indexCount / 3 in length.
uint32_t vertexCount = 0; uint32_t vertexCount = 0;
uint32_t vertexStride = 0; uint32_t vertexStride = 0;
uint32_t indexCount = 0; uint32_t indexCount = 0;
int32_t indexOffset = 0; // optional. Add this offset to all indices. int32_t indexOffset = 0; // optional. Add this offset to all indices.
IndexFormat::Enum indexFormat = IndexFormat::UInt16; IndexFormat indexFormat = IndexFormat::UInt16;
bool rotateCharts = true;
}; };
AddMeshError::Enum AddUvMesh(Atlas *atlas, const UvMeshDecl &decl); AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl);
// Custom parameterization function. texcoords initial values are an orthogonal parameterization.
typedef void (*ParameterizeFunc)(const float *positions, float *texcoords, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount);
struct ChartOptions {
ParameterizeFunc paramFunc = nullptr;
struct ChartOptions
{
float maxChartArea = 0.0f; // Don't grow charts to be larger than this. 0 means no limit. float maxChartArea = 0.0f; // Don't grow charts to be larger than this. 0 means no limit.
float maxBoundaryLength = 0.0f; // Don't grow charts to have a longer boundary than this. 0 means no limit. float maxBoundaryLength = 0.0f; // Don't grow charts to have a longer boundary than this. 0 means no limit.
@ -180,38 +176,15 @@ struct ChartOptions
float maxCost = 2.0f; // If total of all metrics * weights > maxCost, don't grow chart. Lower values result in more charts. float maxCost = 2.0f; // If total of all metrics * weights > maxCost, don't grow chart. Lower values result in more charts.
uint32_t maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts. uint32_t maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts.
bool useInputMeshUvs = false; // Use MeshDecl::vertexUvData for charts.
bool fixWinding = false; // Enforce consistent texture coordinate winding.
}; };
// Call after all AddMesh calls. Can be called multiple times to recompute charts with different options. // Call after all AddMesh calls. Can be called multiple times to recompute charts with different options.
void ComputeCharts(Atlas *atlas, ChartOptions options = ChartOptions()); void ComputeCharts(Atlas *atlas, ChartOptions options = ChartOptions());
// Custom parameterization function. texcoords initial values are an orthogonal parameterization. struct PackOptions {
typedef void (*ParameterizeFunc)(const float *positions, float *texcoords, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount);
struct ParameterizeOptions
{
ParameterizeFunc func = nullptr;
bool closeHoles = true; // If the custom parameterization function works with multiple boundaries, this can be set to false to improve performance.
bool fixTJunctions = true; // If meshes don't have T-junctions, this can be set to false to improve performance.
};
// Call after ComputeCharts. Can be called multiple times to re-parameterize charts with a different ParameterizeFunc.
void ParameterizeCharts(Atlas *atlas, ParameterizeOptions options = ParameterizeOptions());
struct PackOptions
{
// Leave space around charts for texels that would be sampled by bilinear filtering.
bool bilinear = true;
// Align charts to 4x4 blocks. Also improves packing speed, since there are fewer possible chart locations to consider.
bool blockAlign = false;
// Slower, but gives the best result. If false, use random chart placement.
bool bruteForce = false;
// Create Atlas::image
bool createImage = false;
// Charts larger than this will be scaled down. 0 means no limit. // Charts larger than this will be scaled down. 0 means no limit.
uint32_t maxChartSize = 0; uint32_t maxChartSize = 0;
@ -227,29 +200,42 @@ struct PackOptions
// If not 0, and texelsPerUnit is not 0, generate one or more atlases with that exact resolution. // If not 0, and texelsPerUnit is not 0, generate one or more atlases with that exact resolution.
// If not 0, and texelsPerUnit is 0, texelsPerUnit is estimated to approximately match the resolution. // If not 0, and texelsPerUnit is 0, texelsPerUnit is estimated to approximately match the resolution.
uint32_t resolution = 0; uint32_t resolution = 0;
// Leave space around charts for texels that would be sampled by bilinear filtering.
bool bilinear = true;
// Align charts to 4x4 blocks. Also improves packing speed, since there are fewer possible chart locations to consider.
bool blockAlign = false;
// Slower, but gives the best result. If false, use random chart placement.
bool bruteForce = false;
// Create Atlas::image
bool createImage = false;
// Rotate charts to the axis of their convex hull.
bool rotateChartsToAxis = true;
// Rotate charts to improve packing.
bool rotateCharts = true;
}; };
// Call after ParameterizeCharts. Can be called multiple times to re-pack charts with different options. // Call after ComputeCharts. Can be called multiple times to re-pack charts with different options.
void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions()); void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions());
// Equivalent to calling ComputeCharts, ParameterizeCharts and PackCharts in sequence. Can be called multiple times to regenerate with different options. // Equivalent to calling ComputeCharts and PackCharts in sequence. Can be called multiple times to regenerate with different options.
void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), ParameterizeOptions parameterizeOptions = ParameterizeOptions(), PackOptions packOptions = PackOptions()); void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), PackOptions packOptions = PackOptions());
// Progress tracking. // Progress tracking.
struct ProgressCategory enum class ProgressCategory {
{ AddMesh,
enum Enum ComputeCharts,
{ PackCharts,
AddMesh, BuildOutputMeshes
ComputeCharts,
ParameterizeCharts,
PackCharts,
BuildOutputMeshes
};
}; };
// May be called from any thread. Return false to cancel. // May be called from any thread. Return false to cancel.
typedef bool (*ProgressFunc)(ProgressCategory::Enum category, int progress, void *userData); typedef bool (*ProgressFunc)(ProgressCategory category, int progress, void *userData);
void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc = nullptr, void *progressUserData = nullptr); void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc = nullptr, void *progressUserData = nullptr);
@ -263,8 +249,8 @@ typedef int (*PrintFunc)(const char *, ...);
void SetPrint(PrintFunc print, bool verbose); void SetPrint(PrintFunc print, bool verbose);
// Helper functions for error messages. // Helper functions for error messages.
const char *StringForEnum(AddMeshError::Enum error); const char *StringForEnum(AddMeshError error);
const char *StringForEnum(ProgressCategory::Enum category); const char *StringForEnum(ProgressCategory category);
} // namespace xatlas } // namespace xatlas