Merge pull request #69400 from akien-mga/3.x-cherrypicks

Cherry-picks for the 3.x branch (future 3.6) - 6th batch
This commit is contained in:
Rémi Verschelde 2022-11-30 18:23:54 +01:00 committed by GitHub
commit 87296b3ea5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 177 additions and 112 deletions

View file

@ -3098,6 +3098,7 @@ Ref<Image> Image::rgbe_to_srgb() {
void Image::bumpmap_to_normalmap(float bump_scale) { void Image::bumpmap_to_normalmap(float bump_scale) {
ERR_FAIL_COND(!_can_modify(format)); ERR_FAIL_COND(!_can_modify(format));
ERR_FAIL_COND_MSG(write_lock.ptr(), "Cannot modify image when it is locked."); ERR_FAIL_COND_MSG(write_lock.ptr(), "Cannot modify image when it is locked.");
clear_mipmaps();
convert(Image::FORMAT_RF); convert(Image::FORMAT_RF);
PoolVector<uint8_t> result_image; //rgba output PoolVector<uint8_t> result_image; //rgba output

View file

@ -301,7 +301,7 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) {
const size_t copy_buffer_limit = 65536; // 64 KB const size_t copy_buffer_limit = 65536; // 64 KB
fsrc->seek_end(0); fsrc->seek_end(0);
int size = fsrc->get_position(); uint64_t size = fsrc->get_position();
fsrc->seek(0); fsrc->seek(0);
err = OK; err = OK;
size_t buffer_size = MIN(size * sizeof(uint8_t), copy_buffer_limit); size_t buffer_size = MIN(size * sizeof(uint8_t), copy_buffer_limit);

View file

@ -87,11 +87,6 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_
if (length >= 2 + param_position) { if (length >= 2 + param_position) {
event->set_pitch(data[param_position]); event->set_pitch(data[param_position]);
event->set_velocity(data[param_position + 1]); event->set_velocity(data[param_position + 1]);
if (event->get_message() == MIDI_MESSAGE_NOTE_ON && event->get_velocity() == 0) {
// https://www.midi.org/forum/228-writing-midi-software-send-note-off,-or-zero-velocity-note-on
event->set_message(MIDI_MESSAGE_NOTE_OFF);
}
} }
break; break;

View file

@ -1049,6 +1049,7 @@ ProjectSettings::ProjectSettings() {
// Initialization of engine variables should be done in the setup() method, // Initialization of engine variables should be done in the setup() method,
// so that the values can be overridden from project.godot or project.binary. // so that the values can be overridden from project.godot or project.binary.
CRASH_COND_MSG(singleton != nullptr, "Instantiating a new ProjectSettings singleton is not supported.");
singleton = this; singleton = this;
last_order = NO_BUILTIN_ORDER_BASE; last_order = NO_BUILTIN_ORDER_BASE;
last_builtin_order = 0; last_builtin_order = 0;

View file

@ -27,7 +27,7 @@
<method name="get_frames_available" qualifiers="const"> <method name="get_frames_available" qualifiers="const">
<return type="int" /> <return type="int" />
<description> <description>
Returns the number of audio data frames left to play. If this returned number reaches [code]0[/code], the audio will stop playing until frames are added again. Therefore, make sure your script can always generate and push new audio frames fast enough to avoid audio cracking. Returns the number of frames that can be pushed to the audio sample data buffer without overflowing it. If the result is [code]0[/code], the buffer is full.
</description> </description>
</method> </method>
<method name="get_skips" qualifiers="const"> <method name="get_skips" qualifiers="const">

View file

@ -42,7 +42,7 @@
The pressure of the MIDI signal. This value ranges from 0 to 127. For many devices, this value is always zero. The pressure of the MIDI signal. This value ranges from 0 to 127. For many devices, this value is always zero.
</member> </member>
<member name="velocity" type="int" setter="set_velocity" getter="get_velocity" default="0"> <member name="velocity" type="int" setter="set_velocity" getter="get_velocity" default="0">
The velocity of the MIDI signal. This value ranges from 0 to 127. For a piano, this corresponds to how quickly the key was pressed, and is rarely above about 110 in practice. The velocity of the MIDI signal. This value ranges from 0 to 127. For a piano, this corresponds to how quickly the key was pressed, and is rarely above about 110 in practice. Note that some MIDI devices may send a [constant MIDI_MESSAGE_NOTE_ON] message with zero velocity and expect this to be treated the same as a [constant MIDI_MESSAGE_NOTE_OFF] message, but device implementations vary so Godot reports event data exactly as received.
</member> </member>
</members> </members>
<constants> <constants>

View file

@ -493,6 +493,7 @@
<argument index="0" name="id" type="int" /> <argument index="0" name="id" type="int" />
<description> <description>
Emitted when an item of some [code]id[/code] is pressed or its accelerator is activated. Emitted when an item of some [code]id[/code] is pressed or its accelerator is activated.
[b]Note:[/b] If [code]id[/code] is negative (either explicitly or due to overflow), this will return the correponding index instead.
</description> </description>
</signal> </signal>
<signal name="index_pressed"> <signal name="index_pressed">

View file

@ -237,10 +237,10 @@ vec4 apply_fxaa(vec4 color, vec2 uv_interp, vec2 pixel_size) {
const float FXAA_SPAN_MAX = 8.0; const float FXAA_SPAN_MAX = 8.0;
const vec3 luma = vec3(0.299, 0.587, 0.114); const vec3 luma = vec3(0.299, 0.587, 0.114);
vec4 rgbNW = texture2DLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0); vec4 rgbNW = textureLod(source, uv_interp + vec2(-0.5, -0.5) * pixel_size, 0.0);
vec4 rgbNE = texture2DLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0); vec4 rgbNE = textureLod(source, uv_interp + vec2(0.5, -0.5) * pixel_size, 0.0);
vec4 rgbSW = texture2DLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0); vec4 rgbSW = textureLod(source, uv_interp + vec2(-0.5, 0.5) * pixel_size, 0.0);
vec4 rgbSE = texture2DLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0); vec4 rgbSE = textureLod(source, uv_interp + vec2(0.5, 0.5) * pixel_size, 0.0);
vec3 rgbM = color.rgb; vec3 rgbM = color.rgb;
#ifdef DISABLE_ALPHA #ifdef DISABLE_ALPHA

View file

@ -325,10 +325,10 @@ vec4 apply_fxaa(vec4 color, float exposure, vec2 uv_interp, vec2 pixel_size) {
const float FXAA_SPAN_MAX = 8.0; const float FXAA_SPAN_MAX = 8.0;
const vec3 luma = vec3(0.299, 0.587, 0.114); const vec3 luma = vec3(0.299, 0.587, 0.114);
vec4 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0); vec4 rgbNW = textureLod(source, uv_interp + vec2(-0.5, -0.5) * pixel_size, 0.0);
vec4 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0); vec4 rgbNE = textureLod(source, uv_interp + vec2(0.5, -0.5) * pixel_size, 0.0);
vec4 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0); vec4 rgbSW = textureLod(source, uv_interp + vec2(-0.5, 0.5) * pixel_size, 0.0);
vec4 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0); vec4 rgbSE = textureLod(source, uv_interp + vec2(0.5, 0.5) * pixel_size, 0.0);
vec3 rgbM = color.rgb; vec3 rgbM = color.rgb;
#ifdef DISABLE_ALPHA #ifdef DISABLE_ALPHA

View file

@ -154,7 +154,7 @@ Error DirAccessWindows::make_dir(String p_dir) {
if (p_dir.is_rel_path()) if (p_dir.is_rel_path())
p_dir = current_dir.plus_file(p_dir); p_dir = current_dir.plus_file(p_dir);
p_dir = p_dir.replace("/", "\\"); p_dir = p_dir.simplify_path().replace("/", "\\");
bool success; bool success;
int err; int err;

View file

@ -845,6 +845,8 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
CurveData &curvedata = state.curve_data_map[p_id]; CurveData &curvedata = state.curve_data_map[p_id];
curvedata.name = p_name; curvedata.name = p_name;
String closed = parser.get_attribute_value_safe("closed").to_lower();
curvedata.closed = closed == "true" || closed == "1";
COLLADA_PRINT("curve name: " + p_name); COLLADA_PRINT("curve name: " + p_name);

View file

@ -549,7 +549,12 @@ bool EditorFileSystem::_update_scan_actions() {
if (_test_for_reimport(full_path, false)) { if (_test_for_reimport(full_path, false)) {
//must reimport //must reimport
reimports.push_back(full_path); reimports.push_back(full_path);
reimports.append_array(_get_dependencies(full_path)); Vector<String> dependencies = _get_dependencies(full_path);
for (int i = 0; i < dependencies.size(); i++) {
if (import_extensions.has(dependencies[i].get_extension())) {
reimports.push_back(dependencies[i]);
}
}
} else { } else {
//must not reimport, all was good //must not reimport, all was good
//update modified times, to avoid reimport //update modified times, to avoid reimport

View file

@ -3834,7 +3834,7 @@ void EditorNode::_quick_opened() {
List<String> scene_extensions; List<String> scene_extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions); ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
if (open_scene_dialog || scene_extensions.find(files[i].get_extension())) { if (open_scene_dialog || scene_extensions.find(files[i].get_extension().to_lower())) {
open_request(res_path); open_request(res_path);
} else { } else {
load_resource(res_path); load_resource(res_path);

View file

@ -431,8 +431,7 @@ void FindInFilesDialog::set_find_in_files_mode(FindInFilesMode p_mode) {
} }
String FindInFilesDialog::get_search_text() const { String FindInFilesDialog::get_search_text() const {
String text = _search_text_line_edit->get_text(); return _search_text_line_edit->get_text();
return text.strip_edges();
} }
String FindInFilesDialog::get_replace_text() const { String FindInFilesDialog::get_replace_text() const {

View file

@ -1074,6 +1074,12 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, uint32_t p_use_com
c->set_point_tilt(i, tilts->array[i]); c->set_point_tilt(i, tilts->array[i]);
} }
} }
if (cd.closed && pc > 1) {
Vector3 pos = c->get_point_position(0);
Vector3 in = c->get_point_in(0);
Vector3 out = c->get_point_out(0);
c->add_point(pos, in, out, -1);
}
curve_cache[ng->source] = c; curve_cache[ng->source] = c;
path->set_curve(c); path->set_curve(c);

View file

@ -1478,16 +1478,17 @@ bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_
} }
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) { static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) { // Check scripts only for the nodes belonging to the edited scene.
return nullptr; if (p_current_node == p_edited_scene || p_current_node->get_owner() == p_edited_scene) {
} Ref<Script> scr = p_current_node->get_script();
if (scr.is_valid() && scr == script) {
Ref<Script> scr = p_current_node->get_script(); return p_current_node;
}
if (scr.is_valid() && scr == script) {
return p_current_node;
} }
// Traverse all children, even the ones not owned by the edited scene as they
// can still have child nodes added within the edited scene and thus owned by
// it (e.g. nodes added to subscene's root or to its editable children).
for (int i = 0; i < p_current_node->get_child_count(); i++) { for (int i = 0; i < p_current_node->get_child_count(); i++) {
Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script); Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);
if (n) { if (n) {

View file

@ -4151,7 +4151,8 @@ bool SpatialEditorViewport::can_drop_data_fw(const Point2 &p_point, const Varian
ResourceLoader::get_recognized_extensions_for_type("Mesh", &mesh_extensions); ResourceLoader::get_recognized_extensions_for_type("Mesh", &mesh_extensions);
for (int i = 0; i < files.size(); i++) { for (int i = 0; i < files.size(); i++) {
if (mesh_extensions.find(files[i].get_extension()) || scene_extensions.find(files[i].get_extension())) { String extension = files[i].get_extension().to_lower();
if (mesh_extensions.find(extension) || scene_extensions.find(extension)) {
RES res = ResourceLoader::load(files[i]); RES res = ResourceLoader::load(files[i]);
if (res.is_null()) { if (res.is_null()) {
continue; continue;

View file

@ -67,14 +67,18 @@ int SpriteFramesEditor::_sheet_preview_position_to_frame_index(const Point2 &p_p
const Size2i block_size = frame_size + separation; const Size2i block_size = frame_size + separation;
const Point2i position = p_position / sheet_zoom - offset; const Point2i position = p_position / sheet_zoom - offset;
if (position.x % block_size.x > frame_size.x || position.y % block_size.y > frame_size.y) { if (position.x < 0 || position.y < 0) {
return -1; // Out of bounds.
}
if (position.x % block_size.x >= frame_size.x || position.y % block_size.y >= frame_size.y) {
return -1; // Gap between frames. return -1; // Gap between frames.
} }
const Point2i frame = position / block_size; const Point2i frame = position / block_size;
const Size2i frame_count = _get_frame_count(); const Size2i frame_count = _get_frame_count();
if (frame.x < 0 || frame.y < 0 || frame.x >= frame_count.x || frame.y >= frame_count.y) { if (frame.x >= frame_count.x || frame.y >= frame_count.y) {
return -1; // Out of bound. return -1; // Out of bounds.
} }
return frame_count.x * frame.y + frame.x; return frame_count.x * frame.y + frame.x;

View file

@ -431,17 +431,17 @@ private:
return; return;
} }
ProjectSettings *current = memnew(ProjectSettings); // Load project.godot as ConfigFile to set the new name.
ConfigFile cfg;
int err = current->setup(dir2, ""); String project_godot = dir2.plus_file("project.godot");
Error err = cfg.load(project_godot);
if (err != OK) { if (err != OK) {
set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR); set_message(vformat(TTR("Couldn't load project at '%s' (error %d). It may be missing or corrupted."), project_godot, err), MESSAGE_ERROR);
} else { } else {
ProjectSettings::CustomMap edited_settings; cfg.set_value("application", "config/name", project_name->get_text().strip_edges());
edited_settings["application/config/name"] = project_name->get_text().strip_edges(); err = cfg.save(project_godot);
if (err != OK) {
if (current->save_custom(dir2.plus_file("project.godot"), edited_settings, Vector<String>(), true) != OK) { set_message(vformat(TTR("Couldn't save project at '%s' (error %d)."), project_godot, err), MESSAGE_ERROR);
set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR);
} }
} }
@ -689,18 +689,19 @@ public:
rasterizer_container->hide(); rasterizer_container->hide();
get_ok()->set_disabled(false); get_ok()->set_disabled(false);
ProjectSettings *current = memnew(ProjectSettings); // Fetch current name from project.godot to prefill the text input.
ConfigFile cfg;
int err = current->setup(project_path->get_text(), ""); String project_godot = project_path->get_text().plus_file("project.godot");
Error err = cfg.load(project_godot);
if (err != OK) { if (err != OK) {
set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR); set_message(vformat(TTR("Couldn't load project at '%s' (error %d). It may be missing or corrupted."), project_godot, err), MESSAGE_ERROR);
status_rect->show(); status_rect->show();
msg->show(); msg->show();
get_ok()->set_disabled(true); get_ok()->set_disabled(true);
} else if (current->has_setting("application/config/name")) { } else {
String proj = current->get("application/config/name"); String cur_name = cfg.get_value("application", "config/name", "");
project_name->set_text(proj); project_name->set_text(cur_name);
_text_changed(proj); _text_changed(cur_name);
} }
project_name->call_deferred("grab_focus"); project_name->call_deferred("grab_focus");

View file

@ -2288,8 +2288,22 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
ti = ti->get_parent(); ti = ti->get_parent();
} }
// We only need the first child here (C++ source stack trace). // Find the child with the "C++ Source".
// It's not at a fixed position as "C++ Error" may come first.
TreeItem *ci = ti->get_children(); TreeItem *ci = ti->get_children();
const String cpp_source = "<" + TTR("C++ Source") + ">";
while (ci) {
if (ci->get_text(0) == cpp_source) {
break;
}
ci = ci->get_next();
}
if (!ci) {
WARN_PRINT("No C++ source reference is available for this error.");
return;
}
// Parse back the `file:line @ method()` string. // Parse back the `file:line @ method()` string.
const Vector<String> file_line_number = ci->get_text(1).split("@")[0].strip_edges().split(":"); const Vector<String> file_line_number = ci->get_text(1).split("@")[0].strip_edges().split(":");
ERR_FAIL_COND_MSG(file_line_number.size() < 2, "Incorrect C++ source stack trace file:line format (please report)."); ERR_FAIL_COND_MSG(file_line_number.size() < 2, "Incorrect C++ source stack trace file:line format (please report).");

View file

@ -265,14 +265,21 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
err = FAILED; err = FAILED;
} }
uint64_t color_map_size;
if (has_color_map) { if (has_color_map) {
if (tga_header.color_map_length > 256 || (tga_header.color_map_depth != 24) || tga_header.color_map_type != 1) { if (tga_header.color_map_length > 256 || (tga_header.color_map_depth != 24) || tga_header.color_map_type != 1) {
err = FAILED; err = FAILED;
} }
color_map_size = tga_header.color_map_length * (tga_header.color_map_depth >> 3);
} else { } else {
if (tga_header.color_map_type) { if (tga_header.color_map_type) {
err = FAILED; err = FAILED;
} }
color_map_size = 0;
}
if ((src_image_len - f->get_position()) < (tga_header.id_length + color_map_size)) {
err = FAILED; // TGA data appears to be truncated (fewer bytes than expected).
} }
if (tga_header.image_width <= 0 || tga_header.image_height <= 0) { if (tga_header.image_width <= 0 || tga_header.image_height <= 0) {
@ -289,7 +296,6 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
PoolVector<uint8_t> palette; PoolVector<uint8_t> palette;
if (has_color_map) { if (has_color_map) {
size_t color_map_size = tga_header.color_map_length * (tga_header.color_map_depth >> 3);
err = palette.resize(color_map_size); err = palette.resize(color_map_size);
if (err == OK) { if (err == OK) {
PoolVector<uint8_t>::Write palette_w = palette.write(); PoolVector<uint8_t>::Write palette_w = palette.write();

View file

@ -43,7 +43,6 @@ struct AndroidGodotCodePair {
static AndroidGodotCodePair android_godot_code_pairs[] = { static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_UNKNOWN, KEY_UNKNOWN }, // (0) Unknown key code. { AKEYCODE_UNKNOWN, KEY_UNKNOWN }, // (0) Unknown key code.
{ AKEYCODE_HOME, KEY_HOME }, // (3) Home key.
{ AKEYCODE_BACK, KEY_BACK }, // (4) Back key. { AKEYCODE_BACK, KEY_BACK }, // (4) Back key.
{ AKEYCODE_0, KEY_0 }, // (7) '0' key. { AKEYCODE_0, KEY_0 }, // (7) '0' key.
{ AKEYCODE_1, KEY_1 }, // (8) '1' key. { AKEYCODE_1, KEY_1 }, // (8) '1' key.
@ -63,6 +62,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_DPAD_RIGHT, KEY_RIGHT }, // (22) Directional Pad Right key. { AKEYCODE_DPAD_RIGHT, KEY_RIGHT }, // (22) Directional Pad Right key.
{ AKEYCODE_VOLUME_UP, KEY_VOLUMEUP }, // (24) Volume Up key. { AKEYCODE_VOLUME_UP, KEY_VOLUMEUP }, // (24) Volume Up key.
{ AKEYCODE_VOLUME_DOWN, KEY_VOLUMEDOWN }, // (25) Volume Down key. { AKEYCODE_VOLUME_DOWN, KEY_VOLUMEDOWN }, // (25) Volume Down key.
{ AKEYCODE_POWER, KEY_STANDBY }, // (26) Power key.
{ AKEYCODE_CLEAR, KEY_CLEAR }, // (28) Clear key. { AKEYCODE_CLEAR, KEY_CLEAR }, // (28) Clear key.
{ AKEYCODE_A, KEY_A }, // (29) 'A' key. { AKEYCODE_A, KEY_A }, // (29) 'A' key.
{ AKEYCODE_B, KEY_B }, // (30) 'B' key. { AKEYCODE_B, KEY_B }, // (30) 'B' key.
@ -98,6 +98,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_SHIFT_RIGHT, KEY_SHIFT }, // (60) Right Shift modifier key. { AKEYCODE_SHIFT_RIGHT, KEY_SHIFT }, // (60) Right Shift modifier key.
{ AKEYCODE_TAB, KEY_TAB }, // (61) Tab key. { AKEYCODE_TAB, KEY_TAB }, // (61) Tab key.
{ AKEYCODE_SPACE, KEY_SPACE }, // (62) Space key. { AKEYCODE_SPACE, KEY_SPACE }, // (62) Space key.
{ AKEYCODE_ENVELOPE, KEY_LAUNCHMAIL }, // (65) Envelope special function key.
{ AKEYCODE_ENTER, KEY_ENTER }, // (66) Enter key. { AKEYCODE_ENTER, KEY_ENTER }, // (66) Enter key.
{ AKEYCODE_DEL, KEY_BACKSPACE }, // (67) Backspace key. { AKEYCODE_DEL, KEY_BACKSPACE }, // (67) Backspace key.
{ AKEYCODE_GRAVE, KEY_QUOTELEFT }, // (68) '`' (backtick) key. { AKEYCODE_GRAVE, KEY_QUOTELEFT }, // (68) '`' (backtick) key.
@ -114,6 +115,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_MENU, KEY_MENU }, // (82) Menu key. { AKEYCODE_MENU, KEY_MENU }, // (82) Menu key.
{ AKEYCODE_SEARCH, KEY_SEARCH }, // (84) Search key. { AKEYCODE_SEARCH, KEY_SEARCH }, // (84) Search key.
{ AKEYCODE_MEDIA_STOP, KEY_MEDIASTOP }, // (86) Stop media key. { AKEYCODE_MEDIA_STOP, KEY_MEDIASTOP }, // (86) Stop media key.
{ AKEYCODE_MEDIA_NEXT, KEY_MEDIANEXT }, // (87) Play Next media key.
{ AKEYCODE_MEDIA_PREVIOUS, KEY_MEDIAPREVIOUS }, // (88) Play Previous media key. { AKEYCODE_MEDIA_PREVIOUS, KEY_MEDIAPREVIOUS }, // (88) Play Previous media key.
{ AKEYCODE_PAGE_UP, KEY_PAGEUP }, // (92) Page Up key. { AKEYCODE_PAGE_UP, KEY_PAGEUP }, // (92) Page Up key.
{ AKEYCODE_PAGE_DOWN, KEY_PAGEDOWN }, // (93) Page Down key. { AKEYCODE_PAGE_DOWN, KEY_PAGEDOWN }, // (93) Page Down key.
@ -127,6 +129,8 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_META_RIGHT, KEY_META }, // (118) Right Meta modifier key. { AKEYCODE_META_RIGHT, KEY_META }, // (118) Right Meta modifier key.
{ AKEYCODE_SYSRQ, KEY_PRINT }, // (120) System Request / Print Screen key. { AKEYCODE_SYSRQ, KEY_PRINT }, // (120) System Request / Print Screen key.
{ AKEYCODE_BREAK, KEY_PAUSE }, // (121) Break / Pause key. { AKEYCODE_BREAK, KEY_PAUSE }, // (121) Break / Pause key.
{ AKEYCODE_MOVE_HOME, KEY_HOME }, // (122) Home Movement key.
{ AKEYCODE_MOVE_END, KEY_END }, // (123) End Movement key.
{ AKEYCODE_INSERT, KEY_INSERT }, // (124) Insert key. { AKEYCODE_INSERT, KEY_INSERT }, // (124) Insert key.
{ AKEYCODE_FORWARD, KEY_FORWARD }, // (125) Forward key. { AKEYCODE_FORWARD, KEY_FORWARD }, // (125) Forward key.
{ AKEYCODE_MEDIA_PLAY, KEY_MEDIAPLAY }, // (126) Play media key. { AKEYCODE_MEDIA_PLAY, KEY_MEDIAPLAY }, // (126) Play media key.

View file

@ -392,7 +392,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onRegisterPluginWithGodotNative(); plugin.onRegisterPluginWithGodotNative();
} }
setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on"))); setKeepScreenOn(Boolean.parseBoolean(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")));
// The Godot Android plugins are setup on completion of GodotLib.setup // The Godot Android plugins are setup on completion of GodotLib.setup
mainThreadHandler.post(() -> { mainThreadHandler.post(() -> {

View file

@ -947,7 +947,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
Ref<Image> image; Ref<Image> image;
String image_path = p_dest_dir.plus_file("splash@2x.png"); String image_path = p_dest_dir.plus_file("splash@2x.png");
image.instance(); image.instance();
Error err = image->load(custom_launch_image_2x); Error err = ImageLoader::load_image(custom_launch_image_2x, image);
if (err) { if (err) {
image.unref(); image.unref();
@ -961,7 +961,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
image.unref(); image.unref();
image_path = p_dest_dir.plus_file("splash@3x.png"); image_path = p_dest_dir.plus_file("splash@3x.png");
image.instance(); image.instance();
err = image->load(custom_launch_image_3x); err = ImageLoader::load_image(custom_launch_image_3x, image);
if (err) { if (err) {
image.unref(); image.unref();
@ -978,7 +978,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
if (!splash_path.empty()) { if (!splash_path.empty()) {
splash.instance(); splash.instance();
const Error err = splash->load(splash_path); const Error err = ImageLoader::load_image(splash_path, splash);
if (err) { if (err) {
splash.unref(); splash.unref();
} }

View file

@ -31,6 +31,7 @@
#include "export.h" #include "export.h"
#include "codesign.h" #include "codesign.h"
#include "core/io/image_loader.h"
#include "core/io/marshalls.h" #include "core/io/marshalls.h"
#include "core/io/resource_saver.h" #include "core/io/resource_saver.h"
#include "core/io/zip_io.h" #include "core/io/zip_io.h"
@ -813,7 +814,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
String str; String str;
int exitcode = 0; int exitcode = 0;
Error err = OS::get_singleton()->execute("codesign", args, true, NULL, &str, NULL, true); Error err = OS::get_singleton()->execute("codesign", args, true, NULL, &str, &exitcode, true);
if (err != OK) { if (err != OK) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed.")); add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed."));
return err; return err;
@ -1180,8 +1181,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
} else { } else {
Ref<Image> icon; Ref<Image> icon;
icon.instance(); icon.instance();
icon->load(iconpath); err = ImageLoader::load_image(iconpath, icon);
if (!icon->empty()) { if (err == OK && !icon->empty()) {
_make_icon(p_preset, icon, data); _make_icon(p_preset, icon, data);
} }
} }
@ -1719,8 +1720,8 @@ bool EditorExportPlatformOSX::has_valid_project_configuration(const Ref<EditorEx
if (p_preset->get("notarization/apple_id_name") != "") { if (p_preset->get("notarization/apple_id_name") != "") {
if (p_preset->get("notarization/apple_id_password") == "") { if (p_preset->get("notarization/apple_id_password") == "") {
err += TTR("Notarization: Apple ID password not specified.") + "\n"; err += TTR("Notarization: Apple ID password not specified.") + "\n";
valid = false;
} }
valid = false;
} }
if (p_preset->get("notarization/api_uuid") != "") { if (p_preset->get("notarization/api_uuid") != "") {
if (p_preset->get("notarization/api_key") == "") { if (p_preset->get("notarization/api_key") == "") {

View file

@ -137,7 +137,7 @@ static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
// special case handling of command-period, which is traditionally a special // special case handling of command-period, which is traditionally a special
// shortcut in macOS and doesn't arrive at our regular keyDown handler. // shortcut in macOS and doesn't arrive at our regular keyDown handler.
if ([event type] == NSEventTypeKeyDown) { if ([event type] == NSEventTypeKeyDown) {
if (([event modifierFlags] & NSEventModifierFlagCommand) && [event keyCode] == 0x2f) { if ((([event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask) == NSEventModifierFlagCommand) && [event keyCode] == 0x2f) {
Ref<InputEventKey> k; Ref<InputEventKey> k;
k.instance(); k.instance();
@ -195,7 +195,9 @@ static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
- (void)applicationDidFinishLaunching:(NSNotification *)notice { - (void)applicationDidFinishLaunching:(NSNotification *)notice {
NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO)) { NSString *nsbundleid_env = [NSString stringWithUTF8String:getenv("__CFBundleIdentifier")];
NSString *nsbundleid = [[NSBundle mainBundle] bundleIdentifier];
if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO) || ![nsbundleid isEqualToString:nsbundleid_env]) {
// If the executable is started from terminal or is not bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored). // If the executable is started from terminal or is not bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
[self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02]; [self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02];
} }

View file

@ -4003,11 +4003,8 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
// //
// NOTE: The engine does not use ANSI escape codes to color error/warning messages; it uses Windows API calls instead. // NOTE: The engine does not use ANSI escape codes to color error/warning messages; it uses Windows API calls instead.
// Therefore, error/warning messages are still colored on Windows versions older than 10. // Therefore, error/warning messages are still colored on Windows versions older than 10.
HANDLE stdoutHandle; HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); DWORD outMode = ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
DWORD outMode = 0;
outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(stdoutHandle, outMode)) { if (!SetConsoleMode(stdoutHandle, outMode)) {
// Windows 8.1 or below, or Windows 10 prior to Anniversary Update. // Windows 8.1 or below, or Windows 10 prior to Anniversary Update.
print_verbose("Can't set the ENABLE_VIRTUAL_TERMINAL_PROCESSING Windows console mode."); print_verbose("Can't set the ENABLE_VIRTUAL_TERMINAL_PROCESSING Windows console mode.");

View file

@ -400,7 +400,10 @@ def configure(env):
if platform.system() == "Linux": if platform.system() == "Linux":
env.Append(LIBS=["dl"]) env.Append(LIBS=["dl"])
if platform.system().find("BSD") >= 0: if not env["execinfo"] and platform.libc_ver()[0] != "glibc":
# The default crash handler depends on glibc, so if the host uses
# a different libc (BSD libc, musl), fall back to libexecinfo.
print("Note: Using `execinfo=yes` for the crash handler as required on platforms where glibc is missing.")
env["execinfo"] = True env["execinfo"] = True
if env["execinfo"]: if env["execinfo"]:

View file

@ -203,7 +203,10 @@ int detect_prime() {
print_verbose("Couldn't write vendor/renderer string."); print_verbose("Couldn't write vendor/renderer string.");
} }
close(fdset[1]); close(fdset[1]);
exit(0);
// The function quick_exit() is used because exit() will call destructors on static objects copied by fork().
// These objects will be freed anyway when the process finishes execution.
quick_exit(0);
} }
} }

View file

@ -707,10 +707,14 @@ void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector
PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node); PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
if (pb) { if (pb) {
bool sim = false; bool sim = false;
for (int i = p_sim_bones.size() - 1; 0 <= i; --i) { if (p_sim_bones.empty()) { // If no bones is specified, activate ragdoll on full body.
if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) { sim = true;
sim = true; } else {
break; for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
sim = true;
break;
}
} }
} }
@ -725,9 +729,7 @@ void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector
void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) { void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) {
Vector<int> sim_bones; Vector<int> sim_bones;
if (p_bones.size() <= 0) { if (p_bones.size() > 0) {
sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body
} else {
sim_bones.resize(p_bones.size()); sim_bones.resize(p_bones.size());
int c = 0; int c = 0;
for (int i = sim_bones.size() - 1; 0 <= i; --i) { for (int i = sim_bones.size() - 1; 0 <= i; --i) {

View file

@ -195,12 +195,15 @@ void ColorPicker::_html_entered(const String &p_html) {
return; return;
} }
float last_alpha = color.a; Color previous_color = color;
color = Color::html(p_html); color = Color::html(p_html);
if (!is_editing_alpha()) { if (!is_editing_alpha()) {
color.a = last_alpha; color.a = previous_color.a;
} }
if (color == previous_color) {
return;
}
if (!is_inside_tree()) { if (!is_inside_tree()) {
return; return;
} }

View file

@ -2887,10 +2887,14 @@ void Node::print_stray_nodes() {
} }
void Node::queue_delete() { void Node::queue_delete() {
// There are users which instantiate multiple scene trees for their games.
// Use the node's own tree to handle its deletion when relevant.
if (is_inside_tree()) { if (is_inside_tree()) {
get_tree()->queue_delete(this); get_tree()->queue_delete(this);
} else { } else {
SceneTree::get_singleton()->queue_delete(this); SceneTree *tree = SceneTree::get_singleton();
ERR_FAIL_NULL_MSG(tree, "Can't queue free a node when no SceneTree is available.");
tree->queue_delete(this);
} }
} }

View file

@ -167,8 +167,10 @@ static bool _collect_inheritance_chain(const Ref<SceneState> &p_state, const Nod
state = state->get_base_scene_state(); state = state->get_base_scene_state();
} }
for (int i = inheritance_states.size() - 1; i >= 0; --i) { if (inheritance_states.size() > 0) {
r_states_stack.push_back(inheritance_states[i]); for (int i = inheritance_states.size() - 1; i >= 0; --i) {
r_states_stack.push_back(inheritance_states[i]);
}
} }
return found; return found;
@ -212,10 +214,12 @@ Vector<SceneState::PackState> PropertyUtils::get_node_states_stack(const Node *p
{ {
states_stack_ret.resize(states_stack.size()); states_stack_ret.resize(states_stack.size());
_FastPackState *ps = states_stack.ptr(); _FastPackState *ps = states_stack.ptr();
for (int i = states_stack.size() - 1; i >= 0; --i) { if (states_stack.size() > 0) {
states_stack_ret.write[i].state.reference_ptr(ps->state); for (int i = states_stack.size() - 1; i >= 0; --i) {
states_stack_ret.write[i].node = ps->node; states_stack_ret.write[i].state.reference_ptr(ps->state);
++ps; states_stack_ret.write[i].node = ps->node;
++ps;
}
} }
} }
return states_stack_ret; return states_stack_ret;

View file

@ -774,6 +774,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
thisrow = 0; thisrow = 0;
prevrow = 0; prevrow = 0;
const real_t side_normal_y = (bottom_radius - top_radius) / height;
for (j = 0; j <= (rings + 1); j++) { for (j = 0; j <= (rings + 1); j++) {
v = j; v = j;
v /= (rings + 1); v /= (rings + 1);
@ -792,7 +793,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
Vector3 p = Vector3(x * radius, y, z * radius); Vector3 p = Vector3(x * radius, y, z * radius);
points.push_back(p); points.push_back(p);
normals.push_back(Vector3(x, 0.0, z)); normals.push_back(Vector3(x, side_normal_y, z).normalized());
ADD_TANGENT(z, 0.0, -x, 1.0) ADD_TANGENT(z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v * 0.5)); uvs.push_back(Vector2(u, v * 0.5));
point++; point++;

View file

@ -494,7 +494,7 @@ Files extracted from upstream source:
## recastnavigation ## recastnavigation
- Upstream: https://github.com/recastnavigation/recastnavigation - Upstream: https://github.com/recastnavigation/recastnavigation
- Version: git (5a870d427e47abd4a8e4ce58a95582ec049434d5, 2022) - Version: git (4fef0446609b23d6ac180ed822817571525528a1, 2022)
- License: zlib - License: zlib
Files extracted from upstream source: Files extracted from upstream source:

View file

@ -22,13 +22,16 @@
/// The value of PI used by Recast. /// The value of PI used by Recast.
static const float RC_PI = 3.14159265f; static const float RC_PI = 3.14159265f;
/// Used to ignore unused function parameters and silence any compiler warnings.
template<class T> void rcIgnoreUnused(const T&) { }
/// Recast log categories. /// Recast log categories.
/// @see rcContext /// @see rcContext
enum rcLogCategory enum rcLogCategory
{ {
RC_LOG_PROGRESS = 1, ///< A progress log entry. RC_LOG_PROGRESS = 1, ///< A progress log entry.
RC_LOG_WARNING, ///< A warning log entry. RC_LOG_WARNING, ///< A warning log entry.
RC_LOG_ERROR, ///< An error log entry. RC_LOG_ERROR ///< An error log entry.
}; };
/// Recast performance timer categories. /// Recast performance timer categories.
@ -101,7 +104,6 @@ enum rcTimerLabel
class rcContext class rcContext
{ {
public: public:
/// Contructor. /// Contructor.
/// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true] /// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true]
inline rcContext(bool state = true) : m_logEnabled(state), m_timerEnabled(state) {} inline rcContext(bool state = true) : m_logEnabled(state), m_timerEnabled(state) {}
@ -140,31 +142,30 @@ public:
inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; } inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; }
protected: protected:
/// Clears all log entries. /// Clears all log entries.
virtual void doResetLog() {} virtual void doResetLog();
/// Logs a message. /// Logs a message.
/// @param[in] category The category of the message. /// @param[in] category The category of the message.
/// @param[in] msg The formatted message. /// @param[in] msg The formatted message.
/// @param[in] len The length of the formatted message. /// @param[in] len The length of the formatted message.
virtual void doLog(const rcLogCategory /*category*/, const char* /*msg*/, const int /*len*/) {} virtual void doLog(const rcLogCategory category, const char* msg, const int len) { rcIgnoreUnused(category); rcIgnoreUnused(msg); rcIgnoreUnused(len); }
/// Clears all timers. (Resets all to unused.) /// Clears all timers. (Resets all to unused.)
virtual void doResetTimers() {} virtual void doResetTimers() {}
/// Starts the specified performance timer. /// Starts the specified performance timer.
/// @param[in] label The category of timer. /// @param[in] label The category of timer.
virtual void doStartTimer(const rcTimerLabel /*label*/) {} virtual void doStartTimer(const rcTimerLabel label) { rcIgnoreUnused(label); }
/// Stops the specified performance timer. /// Stops the specified performance timer.
/// @param[in] label The category of the timer. /// @param[in] label The category of the timer.
virtual void doStopTimer(const rcTimerLabel /*label*/) {} virtual void doStopTimer(const rcTimerLabel label) { rcIgnoreUnused(label); }
/// Returns the total accumulated time of the specified performance timer. /// Returns the total accumulated time of the specified performance timer.
/// @param[in] label The category of the timer. /// @param[in] label The category of the timer.
/// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started. /// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started.
virtual int doGetAccumulatedTime(const rcTimerLabel /*label*/) const { return -1; } virtual int doGetAccumulatedTime(const rcTimerLabel label) const { rcIgnoreUnused(label); return -1; }
/// True if logging is enabled. /// True if logging is enabled.
bool m_logEnabled; bool m_logEnabled;
@ -564,7 +565,7 @@ static const int RC_AREA_BORDER = 0x20000;
enum rcBuildContoursFlags enum rcBuildContoursFlags
{ {
RC_CONTOUR_TESS_WALL_EDGES = 0x01, ///< Tessellate solid (impassable) edges during contour simplification. RC_CONTOUR_TESS_WALL_EDGES = 0x01, ///< Tessellate solid (impassable) edges during contour simplification.
RC_CONTOUR_TESS_AREA_EDGES = 0x02, ///< Tessellate edges between areas during contour simplification. RC_CONTOUR_TESS_AREA_EDGES = 0x02 ///< Tessellate edges between areas during contour simplification.
}; };
/// Applied to the region id field of contour vertices in order to extract the region id. /// Applied to the region id field of contour vertices in order to extract the region id.
@ -595,11 +596,6 @@ static const int RC_NOT_CONNECTED = 0x3f;
/// @name General helper functions /// @name General helper functions
/// @{ /// @{
/// Used to ignore a function parameter. VS complains about unused parameters
/// and this silences the warning.
/// @param [in] _ Unused parameter
template<class T> void rcIgnoreUnused(const T&) { }
/// Swaps the values of the two parameters. /// Swaps the values of the two parameters.
/// @param[in,out] a Value A /// @param[in,out] a Value A
/// @param[in,out] b Value B /// @param[in,out] b Value B
@ -996,6 +992,7 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
/// @ingroup recast /// @ingroup recast
/// @param[in] verts The vertices of the polygon [Form: (x, y, z) * @p nverts] /// @param[in] verts The vertices of the polygon [Form: (x, y, z) * @p nverts]
/// @param[in] nverts The number of vertices in the polygon. /// @param[in] nverts The number of vertices in the polygon.
/// @param[in] offset How much to offset the polygon by. [Units: wu]
/// @param[out] outVerts The offset vertices (should hold up to 2 * @p nverts) [Form: (x, y, z) * return value] /// @param[out] outVerts The offset vertices (should hold up to 2 * @p nverts) [Form: (x, y, z) * return value]
/// @param[in] maxOutVerts The max number of vertices that can be stored to @p outVerts. /// @param[in] maxOutVerts The max number of vertices that can be stored to @p outVerts.
/// @returns Number of vertices in the offset polygon or 0 if too few vertices in @p outVerts. /// @returns Number of vertices in the offset polygon or 0 if too few vertices in @p outVerts.

View file

@ -112,7 +112,7 @@ class rcVectorBase {
typedef rcSizeType size_type; typedef rcSizeType size_type;
typedef T value_type; typedef T value_type;
rcVectorBase() : m_size(0), m_cap(0), m_data(0) {}; rcVectorBase() : m_size(0), m_cap(0), m_data(0) {}
rcVectorBase(const rcVectorBase<T, H>& other) : m_size(0), m_cap(0), m_data(0) { assign(other.begin(), other.end()); } rcVectorBase(const rcVectorBase<T, H>& other) : m_size(0), m_cap(0), m_data(0) { assign(other.begin(), other.end()); }
explicit rcVectorBase(rcSizeType count) : m_size(0), m_cap(0), m_data(0) { resize(count); } explicit rcVectorBase(rcSizeType count) : m_size(0), m_cap(0), m_data(0) { resize(count); }
rcVectorBase(rcSizeType count, const T& value) : m_size(0), m_cap(0), m_data(0) { resize(count, value); } rcVectorBase(rcSizeType count, const T& value) : m_size(0), m_cap(0), m_data(0) { resize(count, value); }
@ -142,8 +142,8 @@ class rcVectorBase {
const T& front() const { rcAssert(m_size); return m_data[0]; } const T& front() const { rcAssert(m_size); return m_data[0]; }
T& front() { rcAssert(m_size); return m_data[0]; } T& front() { rcAssert(m_size); return m_data[0]; }
const T& back() const { rcAssert(m_size); return m_data[m_size - 1]; }; const T& back() const { rcAssert(m_size); return m_data[m_size - 1]; }
T& back() { rcAssert(m_size); return m_data[m_size - 1]; }; T& back() { rcAssert(m_size); return m_data[m_size - 1]; }
const T* data() const { return m_data; } const T* data() const { return m_data; }
T* data() { return m_data; } T* data() { return m_data; }

View file

@ -94,6 +94,11 @@ void rcContext::log(const rcLogCategory category, const char* format, ...)
doLog(category, msg, len); doLog(category, msg, len);
} }
void rcContext::doResetLog()
{
// Defined out of line to fix the weak v-tables warning
}
rcHeightfield* rcAllocHeightfield() rcHeightfield* rcAllocHeightfield()
{ {
return rcNew<rcHeightfield>(RC_ALLOC_PERM); return rcNew<rcHeightfield>(RC_ALLOC_PERM);

View file

@ -566,7 +566,6 @@ static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned sho
const int nvp = mesh.nvp; const int nvp = mesh.nvp;
// Count number of polygons to remove. // Count number of polygons to remove.
int numRemovedVerts = 0;
int numTouchedVerts = 0; int numTouchedVerts = 0;
int numRemainingEdges = 0; int numRemainingEdges = 0;
for (int i = 0; i < mesh.npolys; ++i) for (int i = 0; i < mesh.npolys; ++i)
@ -586,7 +585,6 @@ static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned sho
} }
if (numRemoved) if (numRemoved)
{ {
numRemovedVerts += numRemoved;
numRemainingEdges += numVerts-(numRemoved+1); numRemainingEdges += numVerts-(numRemoved+1);
} }
} }

View file

@ -284,7 +284,7 @@ static unsigned short getHeight(const float fx, const float fy, const float fz,
enum EdgeValues enum EdgeValues
{ {
EV_UNDEF = -1, EV_UNDEF = -1,
EV_HULL = -2, EV_HULL = -2
}; };
static int findEdge(const int* edges, int nedges, int s, int t) static int findEdge(const int* edges, int nedges, int s, int t)

View file

@ -264,7 +264,8 @@ static bool rasterizeTri(const float* v0, const float* v1, const float* v2,
// Calculate the footprint of the triangle on the grid's y-axis // Calculate the footprint of the triangle on the grid's y-axis
int y0 = (int)((tmin[2] - bmin[2])*ics); int y0 = (int)((tmin[2] - bmin[2])*ics);
int y1 = (int)((tmax[2] - bmin[2])*ics); int y1 = (int)((tmax[2] - bmin[2])*ics);
y0 = rcClamp(y0, 0, h-1); // use -1 rather than 0 to cut the polygon properly at the start of the tile
y0 = rcClamp(y0, -1, h-1);
y1 = rcClamp(y1, 0, h-1); y1 = rcClamp(y1, 0, h-1);
// Clip the triangle into all grid cells it touches. // Clip the triangle into all grid cells it touches.
@ -283,7 +284,7 @@ static bool rasterizeTri(const float* v0, const float* v1, const float* v2,
dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2); dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2);
rcSwap(in, p1); rcSwap(in, p1);
if (nvrow < 3) continue; if (nvrow < 3) continue;
if (y < 0) continue;
// find the horizontal bounds in the row // find the horizontal bounds in the row
float minX = inrow[0], maxX = inrow[0]; float minX = inrow[0], maxX = inrow[0];
for (int i=1; i<nvrow; ++i) for (int i=1; i<nvrow; ++i)
@ -293,7 +294,10 @@ static bool rasterizeTri(const float* v0, const float* v1, const float* v2,
} }
int x0 = (int)((minX - bmin[0])*ics); int x0 = (int)((minX - bmin[0])*ics);
int x1 = (int)((maxX - bmin[0])*ics); int x1 = (int)((maxX - bmin[0])*ics);
x0 = rcClamp(x0, 0, w-1); if (x1 < 0 || x0 >= w) {
continue;
}
x0 = rcClamp(x0, -1, w-1);
x1 = rcClamp(x1, 0, w-1); x1 = rcClamp(x1, 0, w-1);
int nv, nv2 = nvrow; int nv, nv2 = nvrow;
@ -305,7 +309,7 @@ static bool rasterizeTri(const float* v0, const float* v1, const float* v2,
dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0); dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0);
rcSwap(inrow, p2); rcSwap(inrow, p2);
if (nv < 3) continue; if (nv < 3) continue;
if (x < 0) continue;
// Calculate min and max of the span. // Calculate min and max of the span.
float smin = p1[1], smax = p1[1]; float smin = p1[1], smax = p1[1];
for (int i = 1; i < nv; ++i) for (int i = 1; i < nv; ++i)