| … | … | @@ -161,7 +161,7 @@ Error BlenderBridge::start_server(const String &socket_path) { |
| 161 | 161 | _known_instance_ids.clear(); |
| 162 | 162 | _next_object_id = 1; |
| 163 | 163 | |
| 164 | | UtilityFunctions::print("BlenderBridge v0.7.0: Server started (shm=", _shm_name, ", sock=", socket_path, ", regions=2x", (int)_region_size, ")"); |
| 164 | UtilityFunctions::print("BlenderBridge v0.8.0: Server started (shm=", _shm_name, ", sock=", socket_path, ", regions=2x", (int)_region_size, ")"); |
| 165 | 165 | return OK; |
| 166 | 166 | } |
| 167 | 167 | |
| … | … | @@ -706,10 +706,17 @@ void BlenderBridge::import_changes(Node *root) { |
| 706 | 706 | MeshInstance3D *mesh_inst = Object::cast_to<MeshInstance3D>(target); |
| 707 | 707 | if (mesh_inst && entry.data_size > TRANSFORM_SIZE + 4) { |
| 708 | 708 | uint32_t cursor = transform_offset + TRANSFORM_SIZE; |
| 709 | uint32_t data_end = entry.data_offset + entry.data_size; |
| 709 | 710 | uint32_t vert_count; |
| 710 | 711 | memcpy(&vert_count, base + cursor, 4); |
| 711 | 712 | cursor += 4; |
| 712 | 713 | |
| 714 | // Bounds check: ensure position data fits within the entry |
| 715 | if (vert_count > 100000 || cursor + vert_count * 12 > data_end) { |
| 716 | UtilityFunctions::printerr("BlenderBridge: vert_count out of bounds: ", (int)vert_count); |
| 717 | continue; |
| 718 | } |
| 719 | |
| 713 | 720 | PackedVector3Array positions; |
| 714 | 721 | positions.resize(vert_count); |
| 715 | 722 | Vector3 *pos_w = positions.ptrw(); |
| … | … | @@ -725,12 +732,12 @@ void BlenderBridge::import_changes(Node *root) { |
| 725 | 732 | // Read has_normals flag |
| 726 | 733 | PackedVector3Array normals; |
| 727 | 734 | uint32_t has_normals = 0; |
| 728 | | if (cursor + 4 <= entry.data_offset + entry.data_size) { |
| 735 | if (cursor + 4 <= data_end) { |
| 729 | 736 | memcpy(&has_normals, base + cursor, 4); |
| 730 | 737 | cursor += 4; |
| 731 | 738 | } |
| 732 | 739 | |
| 733 | | if (has_normals && cursor + vert_count * 12 <= entry.data_offset + entry.data_size) { |
| 740 | if (has_normals && cursor + vert_count * 12 <= data_end) { |
| 734 | 741 | normals.resize(vert_count); |
| 735 | 742 | Vector3 *norm_w = normals.ptrw(); |
| 736 | 743 | for (uint32_t v = 0; v < vert_count; v++) { |
| … | … | @@ -746,12 +753,12 @@ void BlenderBridge::import_changes(Node *root) { |
| 746 | 753 | // Read index buffer |
| 747 | 754 | PackedInt32Array indices; |
| 748 | 755 | uint32_t idx_count = 0; |
| 749 | | if (cursor + 4 <= entry.data_offset + entry.data_size) { |
| 756 | if (cursor + 4 <= data_end) { |
| 750 | 757 | memcpy(&idx_count, base + cursor, 4); |
| 751 | 758 | cursor += 4; |
| 752 | 759 | } |
| 753 | 760 | |
| 754 | | if (idx_count > 0 && cursor + idx_count * 4 <= entry.data_offset + entry.data_size) { |
| 761 | if (idx_count > 0 && cursor + idx_count * 4 <= data_end) { |
| 755 | 762 | indices.resize(idx_count); |
| 756 | 763 | memcpy(indices.ptrw(), base + cursor, idx_count * 4); |
| 757 | 764 | cursor += idx_count * 4; |
| … | … | @@ -763,6 +770,21 @@ void BlenderBridge::import_changes(Node *root) { |
| 763 | 770 | idx_w[t + 1] = idx_w[t + 2]; |
| 764 | 771 | idx_w[t + 2] = tmp; |
| 765 | 772 | } |
| 773 | } else if (idx_count == 0 && vert_count >= 3) { |
| 774 | // Per-corner data (no index buffer): reverse winding by |
| 775 | // swapping vertices 1 and 2 of each triangle in-place. |
| 776 | Vector3 *pw = positions.ptrw(); |
| 777 | Vector3 *nw = normals.size() > 0 ? normals.ptrw() : nullptr; |
| 778 | for (uint32_t t = 0; t + 2 < vert_count; t += 3) { |
| 779 | Vector3 tmp = pw[t + 1]; |
| 780 | pw[t + 1] = pw[t + 2]; |
| 781 | pw[t + 2] = tmp; |
| 782 | if (nw) { |
| 783 | tmp = nw[t + 1]; |
| 784 | nw[t + 1] = nw[t + 2]; |
| 785 | nw[t + 2] = tmp; |
| 786 | } |
| 787 | } |
| 766 | 788 | } |
| 767 | 789 | |
| 768 | 790 | // Read per-triangle smooth flags (after indices) |
| … | … | @@ -858,14 +880,16 @@ void BlenderBridge::import_changes(Node *root) { |
| 858 | 880 | |
| 859 | 881 | if (entry.update_type == UPDATE_DELETE) { |
| 860 | 882 | // Remove from tracking before freeing |
| 861 | | uint64_t del_id = target->get_instance_id(); |
| 862 | | _known_instance_ids.erase(del_id); |
| 883 | if (target) { |
| 884 | uint64_t del_id = target->get_instance_id(); |
| 885 | _known_instance_ids.erase(del_id); |
| 886 | target->queue_free(); |
| 887 | } |
| 863 | 888 | _tracked_objects.erase( |
| 864 | 889 | std::remove_if(_tracked_objects.begin(), _tracked_objects.end(), |
| 865 | 890 | [&](const TrackedObject &t) { return t.object_id == entry.object_id; }), |
| 866 | 891 | _tracked_objects.end()); |
| 867 | 892 | _last_export_node_count--; |
| 868 | | target->queue_free(); |
| 869 | 893 | } |
| 870 | 894 | |
| 871 | 895 | imported++; |