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;
}
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")));

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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>

View File

@ -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">

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.
</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">

View File

@ -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">

View File

@ -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) {

View File

@ -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);

View File

@ -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(

View File

@ -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);

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();
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;

View File

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

View File

@ -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();

View File

@ -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

View File

@ -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
{
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
{
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
{
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
{
enum class ProgressCategory {
AddMesh,
ComputeCharts,
ParameterizeCharts,
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