Merge pull request #53387 from akien-mga/3.x-cherrypicks
This commit is contained in:
commit
cd2c2f8da4
|
@ -14,7 +14,7 @@ struct CullParams {
|
||||||
uint32_t pairable_type;
|
uint32_t pairable_type;
|
||||||
|
|
||||||
// optional components for different tests
|
// optional components for different tests
|
||||||
Vector3 point;
|
Point point;
|
||||||
BVHABB_CLASS abb;
|
BVHABB_CLASS abb;
|
||||||
typename BVHABB_CLASS::ConvexHull hull;
|
typename BVHABB_CLASS::ConvexHull hull;
|
||||||
typename BVHABB_CLASS::Segment segment;
|
typename BVHABB_CLASS::Segment segment;
|
||||||
|
|
|
@ -6,24 +6,21 @@ void _debug_recursive_print_tree(int p_tree_id) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
String _debug_aabb_to_string(const BVHABB_CLASS &aabb) const {
|
String _debug_aabb_to_string(const BVHABB_CLASS &aabb) const {
|
||||||
String sz = "(";
|
Point size = aabb.calculate_size();
|
||||||
sz += itos(aabb.min.x);
|
|
||||||
sz += " ~ ";
|
|
||||||
sz += itos(-aabb.neg_max.x);
|
|
||||||
sz += ") (";
|
|
||||||
|
|
||||||
sz += itos(aabb.min.y);
|
String sz;
|
||||||
sz += " ~ ";
|
float vol = 0.0;
|
||||||
sz += itos(-aabb.neg_max.y);
|
|
||||||
sz += ") (";
|
|
||||||
|
|
||||||
sz += itos(aabb.min.z);
|
for (int i = 0; i < Point::AXES_COUNT; ++i) {
|
||||||
|
sz += "(";
|
||||||
|
sz += itos(aabb.min[i]);
|
||||||
sz += " ~ ";
|
sz += " ~ ";
|
||||||
sz += itos(-aabb.neg_max.z);
|
sz += itos(-aabb.neg_max[i]);
|
||||||
sz += ") ";
|
sz += ") ";
|
||||||
|
|
||||||
Vector3 size = aabb.calculate_size();
|
vol += size[i];
|
||||||
float vol = size.x * size.y * size.z;
|
}
|
||||||
|
|
||||||
sz += "vol " + itos(vol);
|
sz += "vol " + itos(vol);
|
||||||
|
|
||||||
return sz;
|
return sz;
|
||||||
|
|
|
@ -28,11 +28,15 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
|
||||||
Point centre = full_bound.calculate_centre();
|
Point centre = full_bound.calculate_centre();
|
||||||
Point size = full_bound.calculate_size();
|
Point size = full_bound.calculate_size();
|
||||||
|
|
||||||
int order[3];
|
int order[Point::AXIS_COUNT];
|
||||||
|
|
||||||
order[0] = size.min_axis();
|
order[0] = size.min_axis();
|
||||||
order[2] = size.max_axis();
|
order[Point::AXIS_COUNT - 1] = size.max_axis();
|
||||||
|
|
||||||
|
static_assert(Point::AXIS_COUNT <= 3, "BVH Point::AXIS_COUNT has unexpected size");
|
||||||
|
if (Point::AXIS_COUNT == 3) {
|
||||||
order[1] = 3 - (order[0] + order[2]);
|
order[1] = 3 - (order[0] + order[2]);
|
||||||
|
}
|
||||||
|
|
||||||
// simplest case, split on the longest axis
|
// simplest case, split on the longest axis
|
||||||
int split_axis = order[0];
|
int split_axis = order[0];
|
||||||
|
@ -54,7 +58,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
|
||||||
|
|
||||||
// detect when split on longest axis failed
|
// detect when split on longest axis failed
|
||||||
int min_threshold = MAX_ITEMS / 4;
|
int min_threshold = MAX_ITEMS / 4;
|
||||||
int min_group_size[3];
|
int min_group_size[Point::AXIS_COUNT];
|
||||||
min_group_size[0] = MIN(num_a, num_b);
|
min_group_size[0] = MIN(num_a, num_b);
|
||||||
if (min_group_size[0] < min_threshold) {
|
if (min_group_size[0] < min_threshold) {
|
||||||
// slow but sure .. first move everything back into a
|
// slow but sure .. first move everything back into a
|
||||||
|
@ -64,7 +68,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
|
||||||
num_b = 0;
|
num_b = 0;
|
||||||
|
|
||||||
// now calculate the best split
|
// now calculate the best split
|
||||||
for (int axis = 1; axis < 3; axis++) {
|
for (int axis = 1; axis < Point::AXIS_COUNT; axis++) {
|
||||||
split_axis = order[axis];
|
split_axis = order[axis];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
@ -82,7 +86,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
|
||||||
// best axis
|
// best axis
|
||||||
int best_axis = 0;
|
int best_axis = 0;
|
||||||
int best_min = min_group_size[0];
|
int best_min = min_group_size[0];
|
||||||
for (int axis = 1; axis < 3; axis++) {
|
for (int axis = 1; axis < Point::AXIS_COUNT; axis++) {
|
||||||
if (min_group_size[axis] > best_min) {
|
if (min_group_size[axis] > best_min) {
|
||||||
best_min = min_group_size[axis];
|
best_min = min_group_size[axis];
|
||||||
best_axis = axis;
|
best_axis = axis;
|
||||||
|
|
|
@ -1540,7 +1540,7 @@ void Object::_disconnect(const StringName &p_signal, Object *p_to_object, const
|
||||||
|
|
||||||
if (!p_force) {
|
if (!p_force) {
|
||||||
slot->reference_count--; // by default is zero, if it was not referenced it will go below it
|
slot->reference_count--; // by default is zero, if it was not referenced it will go below it
|
||||||
if (slot->reference_count >= 0) {
|
if (slot->reference_count > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,7 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
// Define PLATFORM_CUSTOM_THREAD_H in platform_config.h
|
#ifndef PLATFORM_THREAD_OVERRIDE // See details in thread.h
|
||||||
// Overriding the platform implementation is required in some proprietary platforms
|
|
||||||
#ifndef PLATFORM_CUSTOM_THREAD_H
|
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
|
@ -138,4 +136,4 @@ Thread::ID Thread::get_caller_id() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif // PLATFORM_CUSTOM_THREAD_H
|
#endif // PLATFORM_THREAD_OVERRIDE
|
||||||
|
|
|
@ -28,10 +28,11 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
// Define PLATFORM_CUSTOM_THREAD_H in platform_config.h
|
// Define PLATFORM_THREAD_OVERRIDE in your platform's `platform_config.h`
|
||||||
|
// to use a custom Thread implementation defined in `platform/[your_platform]/platform_thread.h`
|
||||||
// Overriding the platform implementation is required in some proprietary platforms
|
// Overriding the platform implementation is required in some proprietary platforms
|
||||||
#ifdef PLATFORM_CUSTOM_THREAD_H
|
#ifdef PLATFORM_THREAD_OVERRIDE
|
||||||
#include PLATFORM_CUSTOM_THREAD_H
|
#include "platform_thread.h"
|
||||||
#else
|
#else
|
||||||
#ifndef THREAD_H
|
#ifndef THREAD_H
|
||||||
#define THREAD_H
|
#define THREAD_H
|
||||||
|
@ -119,4 +120,4 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // THREAD_H
|
#endif // THREAD_H
|
||||||
#endif // PLATFORM_CUSTOM_THREAD_H
|
#endif // PLATFORM_THREAD_OVERRIDE
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
some_key = 42,
|
some_key = 42,
|
||||||
}
|
}
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
You can access a dictionary's values by referencing the appropriate key. In the above example, [code]points_dir["White"][/code] will return [code]50[/code]. You can also write [code]points_dir.White[/code], which is equivalent. However, you'll have to use the bracket syntax if the key you're accessing the dictionary with isn't a fixed string (such as a number or variable).
|
You can access a dictionary's values by referencing the appropriate key. In the above example, [code]points_dict["White"][/code] will return [code]50[/code]. You can also write [code]points_dict.White[/code], which is equivalent. However, you'll have to use the bracket syntax if the key you're accessing the dictionary with isn't a fixed string (such as a number or variable).
|
||||||
[codeblock]
|
[codeblock]
|
||||||
export(string, "White", "Yellow", "Orange") var my_color
|
export(string, "White", "Yellow", "Orange") var my_color
|
||||||
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
|
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
Finally, dictionaries can contain different types of keys and values in the same dictionary:
|
Finally, dictionaries can contain different types of keys and values in the same dictionary:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
# This is a valid dictionary.
|
# This is a valid dictionary.
|
||||||
# To access the string "Nested value" below, use `my_dir.sub_dir.sub_key` or `my_dir["sub_dir"]["sub_key"]`.
|
# To access the string "Nested value" below, use `my_dict.sub_dict.sub_key` or `my_dict["sub_dict"]["sub_key"]`.
|
||||||
# Indexing styles can be mixed and matched depending on your needs.
|
# Indexing styles can be mixed and matched depending on your needs.
|
||||||
var my_dict = {
|
var my_dict = {
|
||||||
"String Key": 5,
|
"String Key": 5,
|
||||||
|
|
|
@ -170,14 +170,14 @@
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<argument index="0" name="flip" type="bool" default="false" />
|
<argument index="0" name="flip" type="bool" default="false" />
|
||||||
<description>
|
<description>
|
||||||
Generates normals from vertices so you do not have to do it manually. If [code]flip[/code] is [code]true[/code], the resulting normals will be inverted. [method generate_normals] should be called [i]after[/i] generating geometry and [i]before[/i] committing the mesh using [method commit] or [method commit_to_arrays].
|
Generates normals from vertices so you do not have to do it manually. If [code]flip[/code] is [code]true[/code], the resulting normals will be inverted. [method generate_normals] should be called [i]after[/i] generating geometry and [i]before[/i] committing the mesh using [method commit] or [method commit_to_arrays]. For correct display of normal-mapped surfaces, you will also have to generate tangents using [method generate_tangents].
|
||||||
[b]Note:[/b] [method generate_normals] only works if the primitive type to be set to [constant Mesh.PRIMITIVE_TRIANGLES].
|
[b]Note:[/b] [method generate_normals] only works if the primitive type to be set to [constant Mesh.PRIMITIVE_TRIANGLES].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="generate_tangents">
|
<method name="generate_tangents">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<description>
|
<description>
|
||||||
Generates a tangent vector for each vertex. Requires that each vertex have UVs and normals set already.
|
Generates a tangent vector for each vertex. Requires that each vertex have UVs and normals set already (see [method generate_normals]).
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="index">
|
<method name="index">
|
||||||
|
|
|
@ -257,6 +257,11 @@ Error DirAccessWindows::rename(String p_path, String p_new_path) {
|
||||||
|
|
||||||
// If we're only changing file name case we need to do a little juggling
|
// If we're only changing file name case we need to do a little juggling
|
||||||
if (p_path.to_lower() == p_new_path.to_lower()) {
|
if (p_path.to_lower() == p_new_path.to_lower()) {
|
||||||
|
if (dir_exists(p_path)) {
|
||||||
|
// The path is a dir; just rename
|
||||||
|
return ::_wrename(p_path.c_str(), p_new_path.c_str()) == 0 ? OK : FAILED;
|
||||||
|
}
|
||||||
|
// The path is a file; juggle
|
||||||
WCHAR tmpfile[MAX_PATH];
|
WCHAR tmpfile[MAX_PATH];
|
||||||
|
|
||||||
if (!GetTempFileNameW(fix_path(get_current_dir()).c_str(), NULL, 0, tmpfile)) {
|
if (!GetTempFileNameW(fix_path(get_current_dir()).c_str(), NULL, 0, tmpfile)) {
|
||||||
|
|
Binary file not shown.
|
@ -91,11 +91,13 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
|
||||||
// the data width in case of 8/4/1 bit images
|
// the data width in case of 8/4/1 bit images
|
||||||
const uint32_t w = bits_per_pixel >= 24 ? width : width_bytes;
|
const uint32_t w = bits_per_pixel >= 24 ? width : width_bytes;
|
||||||
const uint8_t *line = p_buffer + (line_width * (height - 1));
|
const uint8_t *line = p_buffer + (line_width * (height - 1));
|
||||||
|
const uint8_t *end_buffer = p_buffer + p_header.bmp_file_header.bmp_file_size - p_header.bmp_file_header.bmp_file_offset;
|
||||||
|
|
||||||
for (uint64_t i = 0; i < height; i++) {
|
for (uint64_t i = 0; i < height; i++) {
|
||||||
const uint8_t *line_ptr = line;
|
const uint8_t *line_ptr = line;
|
||||||
|
|
||||||
for (unsigned int j = 0; j < w; j++) {
|
for (unsigned int j = 0; j < w; j++) {
|
||||||
|
ERR_FAIL_COND_V(line_ptr >= end_buffer, ERR_FILE_CORRUPT);
|
||||||
switch (bits_per_pixel) {
|
switch (bits_per_pixel) {
|
||||||
case 1: {
|
case 1: {
|
||||||
uint8_t color_index = *line_ptr;
|
uint8_t color_index = *line_ptr;
|
||||||
|
|
|
@ -833,7 +833,8 @@
|
||||||
<method name="range" qualifiers="vararg">
|
<method name="range" qualifiers="vararg">
|
||||||
<return type="Array" />
|
<return type="Array" />
|
||||||
<description>
|
<description>
|
||||||
Returns an array with the given range. Range can be 1 argument N (0 to N-1), two arguments (initial, final-1) or three arguments (initial, final-1, increment).
|
Returns an array with the given range. Range can be 1 argument [code]N[/code] (0 to [code]N[/code] - 1), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). Returns an empty array if the range isn't valid (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]).
|
||||||
|
Returns an array with the given range. [code]range()[/code] can have 1 argument N ([code]0[/code] to [code]N - 1[/code]), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). [code]increment[/code] can be negative. If [code]increment[/code] is negative, [code]final - 1[/code] will become [code]final + 1[/code]. Also, the initial value must be greater than the final value for the loop to run.
|
||||||
[codeblock]
|
[codeblock]
|
||||||
print(range(4))
|
print(range(4))
|
||||||
print(range(2, 5))
|
print(range(2, 5))
|
||||||
|
@ -845,6 +846,20 @@
|
||||||
[2, 3, 4]
|
[2, 3, 4]
|
||||||
[0, 2, 4]
|
[0, 2, 4]
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
|
To iterate over an [Array] backwards, use:
|
||||||
|
[codeblock]
|
||||||
|
var array = [3, 6, 9]
|
||||||
|
var i := array.size() - 1
|
||||||
|
while i >= 0:
|
||||||
|
print(array[i])
|
||||||
|
i -= 1
|
||||||
|
[/codeblock]
|
||||||
|
Output:
|
||||||
|
[codeblock]
|
||||||
|
9
|
||||||
|
6
|
||||||
|
3
|
||||||
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="range_lerp">
|
<method name="range_lerp">
|
||||||
|
|
|
@ -16,6 +16,38 @@
|
||||||
[codeblock]
|
[codeblock]
|
||||||
upnp.delete_port_mapping(port)
|
upnp.delete_port_mapping(port)
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
|
[b]Note:[/b] UPnP discovery blocks the current thread. To perform discovery without blocking the main thread, use [Thread]s like this:
|
||||||
|
[codeblock]
|
||||||
|
# Emitted when UPnP port mapping setup is completed (regardless of success or failure).
|
||||||
|
signal upnp_completed(error)
|
||||||
|
|
||||||
|
# Replace this with your own server port number between 1025 and 65535.
|
||||||
|
const SERVER_PORT = 3928
|
||||||
|
var thread = null
|
||||||
|
|
||||||
|
func _upnp_setup(server_port):
|
||||||
|
# UPNP queries take some time.
|
||||||
|
var upnp = UPNP.new()
|
||||||
|
var err = upnp.discover()
|
||||||
|
|
||||||
|
if err != OK:
|
||||||
|
push_error(str(err))
|
||||||
|
emit_signal("upnp_completed", err)
|
||||||
|
return
|
||||||
|
|
||||||
|
if upnp.get_gateway() and upnp.get_gateway().is_valid_gateway():
|
||||||
|
upnp.add_port_mapping(server_port, server_port, ProjectSettings.get_setting("application/config/name"), "UDP")
|
||||||
|
upnp.add_port_mapping(server_port, server_port, ProjectSettings.get_setting("application/config/name"), "TCP")
|
||||||
|
emit_signal("upnp_completed", OK)
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
thread = Thread.new()
|
||||||
|
thread.start(self, "_upnp_setup", SERVER_PORT)
|
||||||
|
|
||||||
|
func _exit_tree():
|
||||||
|
# Wait for thread finish here to handle game exit while the thread is running.
|
||||||
|
thread.wait_to_finish()
|
||||||
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
|
|
|
@ -327,11 +327,17 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_st
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// teleport to start
|
// teleport to start
|
||||||
|
if (p_state_machine->states.has(start_request)) {
|
||||||
path.clear();
|
path.clear();
|
||||||
current = start_request;
|
current = start_request;
|
||||||
playing = true;
|
playing = true;
|
||||||
play_start = true;
|
play_start = true;
|
||||||
start_request = StringName(); //clear start request
|
start_request = StringName(); //clear start request
|
||||||
|
} else {
|
||||||
|
StringName node = start_request;
|
||||||
|
start_request = StringName(); //clear start request
|
||||||
|
ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue