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:
commit
77e6164a3d
|
@ -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")));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,35 +31,30 @@ Copyright NVIDIA Corporation 2006 -- Ignacio Castano <icastano@nvidia.com>
|
|||
#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,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.
|
||||
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 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;
|
||||
|
||||
struct PackOptions {
|
||||
// Charts larger than this will be scaled down. 0 means no limit.
|
||||
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 0, texelsPerUnit is estimated to approximately match the resolution.
|
||||
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());
|
||||
|
||||
// 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
|
||||
|
||||
|
|
Loading…
Reference in New Issue