ソースを参照

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

Cherry-picks for the 3.2 branch (future 3.2.4) - 11th batch
Rémi Verschelde 4 年 前
コミット
77e6164a3d

+ 6 - 0
core/io/multiplayer_api.cpp

@@ -136,6 +136,10 @@ void MultiplayerAPI::set_root_node(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) {
 
 	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() {
 	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("has_network_peer"), &MultiplayerAPI::has_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, "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, "root_node", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_root_node", "get_root_node");
 	ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false);
 
 	ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id")));

+ 1 - 0
core/io/multiplayer_api.h

@@ -131,6 +131,7 @@ public:
 	void poll();
 	void clear();
 	void set_root_node(Node *p_node);
+	Node *get_root_node();
 	void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer);
 	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);

+ 0 - 1
core/io/packet_peer_udp.cpp

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

+ 1 - 1
core/project_settings.cpp

@@ -380,7 +380,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
 #ifdef OSX_ENABLED
 		if (!found) {
 			// 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
 

+ 1 - 1
doc/classes/Curve3D.xml

@@ -145,7 +145,7 @@
 			<argument index="1" name="cubic" type="bool" default="false">
 			</argument>
 			<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].
 				Cubic interpolation tends to follow the curves better, but linear is faster (and often, precise enough).
 			</description>

+ 7 - 7
doc/classes/Input.xml

@@ -49,7 +49,7 @@
 			<return type="Vector3">
 			</return>
 			<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.
 				[b]Note:[/b] This method only works on iOS, Android, and UWP. On other platforms, it always returns [constant Vector3.ZERO].
 			</description>
@@ -81,7 +81,7 @@
 			<return type="Vector3">
 			</return>
 			<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].
 			</description>
 		</method>
@@ -89,8 +89,8 @@
 			<return type="Vector3">
 			</return>
 			<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].
-				[b]Note:[/b] This method only works on Android. On other platforms, it always 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 and iOS. On other platforms, it always returns [constant Vector3.ZERO].
 			</description>
 		</method>
 		<method name="get_joy_axis" qualifiers="const">
@@ -187,8 +187,8 @@
 			<return type="Vector3">
 			</return>
 			<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].
-				[b]Note:[/b] This method only works on Android and UWP. On other platforms, it always 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, iOS and UWP. On other platforms, it always returns [constant Vector3.ZERO].
 			</description>
 		</method>
 		<method name="get_mouse_button_mask" qualifiers="const">
@@ -391,7 +391,7 @@
 			</argument>
 			<description>
 				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>
 		</method>
 		<method name="warp_mouse_position">

+ 4 - 10
doc/classes/MultiplayerAPI.xml

@@ -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.
 			</description>
 		</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>
 	<members>
 		<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">
 			If [code]true[/code], the MultiplayerAPI's [member network_peer] refuses new incoming connections.
 		</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>
 	<signals>
 		<signal name="connected_to_server">

+ 16 - 2
doc/classes/ProjectSettings.xml

@@ -76,7 +76,21 @@
 			<argument index="0" name="path" type="String">
 			</argument>
 			<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>
 		</method>
 		<method name="has_setting" qualifiers="const">
@@ -109,7 +123,7 @@
 			<argument index="0" name="path" type="String">
 			</argument>
 			<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>
 		</method>
 		<method name="property_can_revert">

+ 1 - 1
drivers/alsa/audio_driver_alsa.cpp

@@ -187,7 +187,7 @@ void AudioDriverALSA::thread_func(void *p_udata) {
 		int total = 0;
 
 		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);
 
 			if (wrote > 0) {

+ 1 - 0
editor/connections_dialog.cpp

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

+ 25 - 41
editor/plugins/spatial_editor_plugin.cpp

@@ -63,12 +63,11 @@
 #define GIZMO_SCALE_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
 #define GIZMO_ARROW_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
 
-#define ZOOM_MIN_DISTANCE 0.001
-#define ZOOM_MULTIPLIER 1.08
-#define ZOOM_INDICATOR_DELAY_S 1.5
+#define ZOOM_FREELOOK_MIN 0.01
+#define ZOOM_FREELOOK_MULTIPLIER 1.08
+#define ZOOM_FREELOOK_INDICATOR_DELAY_S 1.5
 
-#define FREELOOK_MIN_SPEED 0.01
-#define FREELOOK_SPEED_MULTIPLIER 1.08
+#define ZOOM_FREELOOK_MAX 10'000
 
 #define MIN_Z 0.01
 #define MAX_Z 1000000.0
@@ -1099,9 +1098,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
 	if (b.is_valid()) {
 		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()) {
-
 			case BUTTON_WHEEL_UP: {
 				if (is_freelook_active())
 					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) {
+	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
-	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;
+	zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
 	surface->update();
 }
 
 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
-	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;
+	zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
 	surface->update();
 }
 
@@ -2694,18 +2688,13 @@ void SpatialEditorViewport::_draw() {
 			if (is_freelook_active()) {
 				// Show speed
 
-				real_t min_speed = FREELOOK_MIN_SPEED;
-				real_t max_speed = camera->get_zfar();
+				real_t min_speed = MAX(camera->get_znear() * 4, ZOOM_FREELOOK_MIN);
+				real_t max_speed = MIN(camera->get_zfar() / 4, ZOOM_FREELOOK_MAX);
 				real_t scale_length = (max_speed - min_speed);
 
 				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);
 
-					// 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.
 					const int precision = freelook_speed < 1.0 ? 2 : 1;
 					draw_indicator_bar(
@@ -2719,18 +2708,13 @@ void SpatialEditorViewport::_draw() {
 			} else {
 				// Show zoom
 
-				real_t min_distance = ZOOM_MIN_DISTANCE; // TODO Why not pick znear to limit zoom?
-				real_t max_distance = camera->get_zfar();
+				real_t min_distance = MAX(camera->get_znear() * 4, ZOOM_FREELOOK_MIN);
+				real_t max_distance = MIN(camera->get_zfar() / 4, ZOOM_FREELOOK_MAX);
 				real_t scale_length = (max_distance - min_distance);
 
 				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);
 
-					// 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.
 					const int precision = cursor.distance < 1.0 ? 2 : 1;
 					draw_indicator_bar(

+ 1 - 1
main/main.cpp

@@ -1559,7 +1559,7 @@ bool Main::start() {
 
 		{
 			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;
 		doc.generate(doc_base);

+ 3 - 3
modules/xatlas_unwrap/register_types.cpp

@@ -64,11 +64,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
 
 	xatlas::Atlas *atlas = xatlas::Create();
 	printf("Adding mesh..\n");
-	xatlas::AddMeshError::Enum err = xatlas::AddMesh(atlas, input_mesh, 1);
-	ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Enum::Success, false, xatlas::StringForEnum(err));
+	xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
+	ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
 
 	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_y = atlas->height;

+ 1 - 0
platform/x11/os_x11.cpp

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

+ 5 - 0
scene/resources/resource_format_text.cpp

@@ -800,6 +800,11 @@ Error ResourceInteractiveLoaderText::rename_dependencies(FileAccess *p_f, const
 	f->seek(tag_end);
 
 	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()) {
 		fw->store_8(c);
 		c = f->get_8();

+ 1 - 1
thirdparty/README.md

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

ファイルの差分が大きいため隠しています
+ 217 - 370
thirdparty/xatlas/xatlas.cpp


+ 78 - 92
thirdparty/xatlas/xatlas.h

@@ -31,35 +31,30 @@ Copyright NVIDIA Corporation 2006 -- Ignacio Castano <[email protected]>
 #pragma once
 #ifndef XATLAS_H
 #define XATLAS_H
+#include <stddef.h>
 #include <stdint.h>
 
 namespace xatlas {
 
-struct ChartType
-{
-	enum Enum
-	{
-		Planar,
-		Ortho,
-		LSCM,
-		Piecewise,
-		Invalid
-	};
+enum class ChartType {
+	Planar,
+	Ortho,
+	LSCM,
+	Piecewise,
+	Invalid
 };
 
 // A group of connected faces, belonging to a single atlas.
-struct Chart
-{
+struct Chart {
 	uint32_t *faceArray;
 	uint32_t atlasIndex; // Sub-atlas index.
 	uint32_t faceCount;
-	ChartType::Enum type;
+	ChartType type;
 	uint32_t material;
 };
 
 // Output vertex.
-struct Vertex
-{
+struct Vertex {
 	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.
 	float uv[2]; // Not normalized - values are in Atlas width and height range.
@@ -67,8 +62,7 @@ struct Vertex
 };
 
 // Output mesh.
-struct Mesh
-{
+struct Mesh {
 	Chart *chartArray;
 	uint32_t *indexArray;
 	Vertex *vertexArray;
@@ -83,16 +77,15 @@ static const uint32_t kImageIsBilinearBit = 0x40000000;
 static const uint32_t kImageIsPaddingBit = 0x20000000;
 
 // Empty on creation. Populated after charts are packed.
-struct Atlas
-{
+struct Atlas {
 	uint32_t *image;
 	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 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 chartCount; // Total number of charts in all meshes.
 	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.
 };
 
@@ -101,73 +94,76 @@ Atlas *Create();
 
 void Destroy(Atlas *atlas);
 
-struct IndexFormat
-{
-	enum Enum
-	{
-		UInt16,
-		UInt32
-	};
+enum class IndexFormat {
+	UInt16,
+	UInt32
 };
 
 // Input mesh declaration.
-struct MeshDecl
-{
+struct MeshDecl {
 	const void *vertexPositionData = nullptr;
 	const void *vertexNormalData = nullptr; // optional
 	const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator.
 	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.
 	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 vertexPositionStride = 0;
 	uint32_t vertexNormalStride = 0; // optional
 	uint32_t vertexUvStride = 0; // optional
 	uint32_t indexCount = 0;
 	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.
 	float epsilon = 1.192092896e-07F;
 };
 
-struct AddMeshError
-{
-	enum Enum
-	{
-		Success, // No error.
-		Error, // Unspecified error.
-		IndexOutOfRange, // An index is >= MeshDecl vertexCount.
-		InvalidIndexCount // Not evenly divisible by 3 - expecting triangles.
-	};
+enum class AddMeshError {
+	Success, // No error.
+	Error, // Unspecified error.
+	IndexOutOfRange, // An index is >= MeshDecl vertexCount.
+	InvalidFaceVertexCount, // Must be >= 3.
+	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.
-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.
 void AddMeshJoin(Atlas *atlas);
 
-struct UvMeshDecl
-{
+struct UvMeshDecl {
 	const void *vertexUvData = nullptr;
 	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 vertexStride = 0;
 	uint32_t indexCount = 0;
 	int32_t indexOffset = 0; // optional. Add this offset to all indices.
-	IndexFormat::Enum indexFormat = IndexFormat::UInt16;
-	bool rotateCharts = true;
+	IndexFormat indexFormat = IndexFormat::UInt16;
 };
 
-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 maxBoundaryLength = 0.0f; // Don't grow charts to have a longer boundary than this. 0 means no limit.
 
@@ -180,26 +176,31 @@ struct ChartOptions
 
 	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.
+
+	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.
 void ComputeCharts(Atlas *atlas, ChartOptions options = ChartOptions());
 
-// 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 PackOptions {
+	// Charts larger than this will be scaled down. 0 means no limit.
+	uint32_t maxChartSize = 0;
 
-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.
-};
+	// Number of pixels to pad charts with.
+	uint32_t padding = 0;
+
+	// Unit to texel scale. e.g. a 1x1 quad with texelsPerUnit of 32 will take up approximately 32x32 texels in the atlas.
+	// If 0, an estimated value will be calculated to approximately match the given resolution.
+	// If resolution is also 0, the estimated value will approximately match a 1024x1024 atlas.
+	float texelsPerUnit = 0.0f;
 
-// Call after ComputeCharts. Can be called multiple times to re-parameterize charts with a different ParameterizeFunc.
-void ParameterizeCharts(Atlas *atlas, ParameterizeOptions options = ParameterizeOptions());
+	// If 0, generate a single atlas with texelsPerUnit determining the final 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.
+	uint32_t resolution = 0;
 
-struct PackOptions
-{
 	// Leave space around charts for texels that would be sampled by bilinear filtering.
 	bool bilinear = true;
 
@@ -212,44 +213,29 @@ struct PackOptions
 	// Create Atlas::image
 	bool createImage = false;
 
-	// Charts larger than this will be scaled down. 0 means no limit.
-	uint32_t maxChartSize = 0;
-
-	// Number of pixels to pad charts with.
-	uint32_t padding = 0;
+	// Rotate charts to the axis of their convex hull.
+	bool rotateChartsToAxis = true;
 
-	// Unit to texel scale. e.g. a 1x1 quad with texelsPerUnit of 32 will take up approximately 32x32 texels in the atlas.
-	// If 0, an estimated value will be calculated to approximately match the given resolution.
-	// If resolution is also 0, the estimated value will approximately match a 1024x1024 atlas.
-	float texelsPerUnit = 0.0f;
-
-	// If 0, generate a single atlas with texelsPerUnit determining the final 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.
-	uint32_t resolution = 0;
+	// 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());
 
-// Equivalent to calling ComputeCharts, ParameterizeCharts 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());
+// 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(), PackOptions packOptions = PackOptions());
 
 // Progress tracking.
-struct ProgressCategory
-{
-	enum Enum
-	{
-		AddMesh,
-		ComputeCharts,
-		ParameterizeCharts,
-		PackCharts,
-		BuildOutputMeshes
-	};
+enum class ProgressCategory {
+	AddMesh,
+	ComputeCharts,
+	PackCharts,
+	BuildOutputMeshes
 };
 
 // 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);
 
@@ -263,8 +249,8 @@ typedef int (*PrintFunc)(const char *, ...);
 void SetPrint(PrintFunc print, bool verbose);
 
 // Helper functions for error messages.
-const char *StringForEnum(AddMeshError::Enum error);
-const char *StringForEnum(ProgressCategory::Enum category);
+const char *StringForEnum(AddMeshError error);
+const char *StringForEnum(ProgressCategory category);
 
 } // namespace xatlas
 

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません