Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/classes/ArrayMesh.xml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@
Returns the primitive type of the requested surface (see [method add_surface_from_arrays]).
</description>
</method>
<method name="surface_remove">
<return type="void" />
<param index="0" name="surf_idx" type="int" />
<description>
Removes a surface at position surf_idx, shifting greater surfaces one surf_idx slot down.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Removes a surface at position surf_idx, shifting greater surfaces one surf_idx slot down.
Removes the surface at the given index from the Mesh, shifting surfaces with higher index down by one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@clayjohn @Repiteo These changes should really not have been dismissed just because there was disagreement over codestyle changes, please pay attention to all suggested changes and don't skip some ones by relevant teams

</description>
</method>
<method name="surface_set_name">
<return type="void" />
<param index="0" name="surf_idx" type="int" />
Expand Down
8 changes: 8 additions & 0 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2475,6 +2475,14 @@
Returns a mesh's surface's material.
</description>
</method>
<method name="mesh_surface_remove">
<return type="void" />
<param index="0" name="mesh" type="RID" />
<param index="1" name="surface" type="int" />
<description>
Removes a mesh's surface at position surf_idx, shifting greater surfaces one surf_idx slot down.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Removes a mesh's surface at position surf_idx, shifting greater surfaces one surf_idx slot down.
Removes the surface at the given index from the Mesh, shifting surfaces with higher index down by one.

</description>
</method>
<method name="mesh_surface_set_material">
<return type="void" />
<param index="0" name="mesh" type="RID" />
Expand Down
241 changes: 154 additions & 87 deletions drivers/gles3/storage/mesh_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,72 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
mesh->material_cache.clear();
}

void MeshStorage::_mesh_surface_clear(Mesh *mesh, int p_surface) {
Mesh::Surface &s = *mesh->surfaces[p_surface];

if (s.vertex_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.vertex_buffer);
s.vertex_buffer = 0;
}

if (s.version_count != 0) {
for (uint32_t j = 0; j < s.version_count; j++) {
glDeleteVertexArrays(1, &s.versions[j].vertex_array);
s.versions[j].vertex_array = 0;
}
}

if (s.attribute_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.attribute_buffer);
s.attribute_buffer = 0;
}

if (s.skin_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.skin_buffer);
s.skin_buffer = 0;
}

if (s.index_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.index_buffer);
s.index_buffer = 0;
}

if (s.versions) {
memfree(s.versions); //reallocs, so free with memfree.
Comment thread
AThousandShips marked this conversation as resolved.
Outdated
}

if (s.wireframe) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.wireframe->index_buffer);
memdelete(s.wireframe);
}

if (s.lod_count) {
for (uint32_t j = 0; j < s.lod_count; j++) {
if (s.lods[j].index_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.lods[j].index_buffer);
s.lods[j].index_buffer = 0;
}
}
memdelete_arr(s.lods);
}

if (mesh->blend_shape_count) {
for (uint32_t j = 0; j < mesh->blend_shape_count; j++) {
if (s.blend_shapes[j].vertex_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.blend_shapes[j].vertex_buffer);
s.blend_shapes[j].vertex_buffer = 0;
}
if (s.blend_shapes[j].vertex_array != 0) {
glDeleteVertexArrays(1, &s.blend_shapes[j].vertex_array);
s.blend_shapes[j].vertex_array = 0;
}
}
memdelete_arr(s.blend_shapes);
}

memdelete(mesh->surfaces[p_surface]);
}

int MeshStorage::mesh_get_blend_shape_count(RID p_mesh) const {
const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL_V(mesh, -1);
Expand Down Expand Up @@ -772,69 +838,7 @@ void MeshStorage::mesh_clear(RID p_mesh) {
}

for (uint32_t i = 0; i < mesh->surface_count; i++) {
Mesh::Surface &s = *mesh->surfaces[i];

if (s.vertex_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.vertex_buffer);
s.vertex_buffer = 0;
}

if (s.version_count != 0) {
for (uint32_t j = 0; j < s.version_count; j++) {
glDeleteVertexArrays(1, &s.versions[j].vertex_array);
s.versions[j].vertex_array = 0;
}
}

if (s.attribute_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.attribute_buffer);
s.attribute_buffer = 0;
}

if (s.skin_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.skin_buffer);
s.skin_buffer = 0;
}

if (s.index_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.index_buffer);
s.index_buffer = 0;
}

if (s.versions) {
memfree(s.versions); //reallocs, so free with memfree.
}

if (s.wireframe) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.wireframe->index_buffer);
memdelete(s.wireframe);
}

if (s.lod_count) {
for (uint32_t j = 0; j < s.lod_count; j++) {
if (s.lods[j].index_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.lods[j].index_buffer);
s.lods[j].index_buffer = 0;
}
}
memdelete_arr(s.lods);
}

if (mesh->blend_shape_count) {
for (uint32_t j = 0; j < mesh->blend_shape_count; j++) {
if (s.blend_shapes[j].vertex_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(s.blend_shapes[j].vertex_buffer);
s.blend_shapes[j].vertex_buffer = 0;
}
if (s.blend_shapes[j].vertex_array != 0) {
glDeleteVertexArrays(1, &s.blend_shapes[j].vertex_array);
s.blend_shapes[j].vertex_array = 0;
}
}
memdelete_arr(s.blend_shapes);
}

memdelete(mesh->surfaces[i]);
_mesh_surface_clear(mesh, i);
}
if (mesh->surfaces) {
memfree(mesh->surfaces);
Expand Down Expand Up @@ -1033,6 +1037,56 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
v.input_mask = p_input_mask;
}

void MeshStorage::mesh_surface_remove(RID p_mesh, int p_surface) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL(mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);

// Clear instance data before mesh data.
for (MeshInstance *mi : mesh->instances) {
_mesh_instance_remove_surface(mi, p_surface);
}

_mesh_surface_clear(mesh, p_surface);

if ((uint32_t)p_surface < mesh->surface_count - 1) {
memmove(mesh->surfaces + p_surface, mesh->surfaces + p_surface + 1, sizeof(Mesh::Surface *) * (mesh->surface_count - (p_surface + 1)));
}
mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count - 1));
--mesh->surface_count;

mesh->material_cache.clear();

mesh->skeleton_aabb_version = 0;

if (mesh->has_bone_weights) {
mesh->has_bone_weights = false;
for (uint32_t i = 0; i < mesh->surface_count; i++) {
if (mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES) {
mesh->has_bone_weights = true;
break;
}
}
}

if (mesh->surface_count == 0) {
mesh->aabb = AABB();
} else {
mesh->aabb = mesh->surfaces[0]->aabb;
for (uint32_t i = 1; i < mesh->surface_count; i++) {
mesh->aabb.merge_with(mesh->surfaces[i]->aabb);
}
}

mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);

for (Mesh *E : mesh->shadow_owners) {
Mesh *shadow_owner = E;
shadow_owner->shadow_mesh = RID();
shadow_owner->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
}
}

/* MESH INSTANCE API */

RID MeshStorage::mesh_instance_create(RID p_base) {
Expand Down Expand Up @@ -1083,30 +1137,10 @@ void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int
}

void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
if (mi->surfaces[i].version_count != 0) {
for (uint32_t j = 0; j < mi->surfaces[i].version_count; j++) {
glDeleteVertexArrays(1, &mi->surfaces[i].versions[j].vertex_array);
mi->surfaces[i].versions[j].vertex_array = 0;
}
memfree(mi->surfaces[i].versions);
}

if (mi->surfaces[i].vertex_buffers[0] != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(mi->surfaces[i].vertex_buffers[0]);
GLES3::Utilities::get_singleton()->buffer_free_data(mi->surfaces[i].vertex_buffers[1]);
mi->surfaces[i].vertex_buffers[0] = 0;
mi->surfaces[i].vertex_buffers[1] = 0;
}

if (mi->surfaces[i].vertex_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(mi->surfaces[i].vertex_buffer);
mi->surfaces[i].vertex_buffer = 0;
}
while (mi->surfaces.size()) {
_mesh_instance_remove_surface(mi, mi->surfaces.size() - 1);
}
mi->surfaces.clear();
mi->blend_weights.clear();
mi->skeleton_version = 0;
mi->dirty = false;
}

void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) {
Expand Down Expand Up @@ -1159,6 +1193,39 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
mi->dirty = true;
}

void MeshStorage::_mesh_instance_remove_surface(MeshInstance *mi, int p_surface) {
MeshInstance::Surface &surface = mi->surfaces[p_surface];

if (surface.version_count != 0) {
for (uint32_t j = 0; j < surface.version_count; j++) {
glDeleteVertexArrays(1, &surface.versions[j].vertex_array);
surface.versions[j].vertex_array = 0;
}
memfree(surface.versions);
}

if (surface.vertex_buffers[0] != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(surface.vertex_buffers[0]);
GLES3::Utilities::get_singleton()->buffer_free_data(surface.vertex_buffers[1]);
surface.vertex_buffers[0] = 0;
surface.vertex_buffers[1] = 0;
}

if (surface.vertex_buffer != 0) {
GLES3::Utilities::get_singleton()->buffer_free_data(surface.vertex_buffer);
surface.vertex_buffer = 0;
}

mi->surfaces.remove_at(p_surface);

if (mi->surfaces.is_empty()) {
mi->blend_weights.clear();
mi->weights_dirty = false;
mi->skeleton_version = 0;
}
mi->dirty = true;
}

void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);

Expand Down Expand Up @@ -1259,7 +1326,7 @@ void MeshStorage::update_mesh_instances() {

// Precompute base weight if using blend shapes.
float base_weight = 1.0;
if (mi->mesh->blend_shape_count && mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED) {
if (mi->surfaces.size() && mi->mesh->blend_shape_count && mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED) {
for (uint32_t i = 0; i < mi->mesh->blend_shape_count; i++) {
base_weight -= mi->blend_weights[i];
}
Expand Down
4 changes: 4 additions & 0 deletions drivers/gles3/storage/mesh_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,15 @@ class MeshStorage : public RendererMeshStorage {
mutable RID_Owner<Mesh, true> mesh_owner;

void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, MeshInstance::Surface *mis = nullptr);
void _mesh_surface_clear(Mesh *mesh, int p_surface);

/* Mesh Instance API */

mutable RID_Owner<MeshInstance> mesh_instance_owner;

void _mesh_instance_clear(MeshInstance *mi);
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
void _mesh_instance_remove_surface(MeshInstance *mi, int p_surface);
void _blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uint32_t p_surface);
SelfList<MeshInstance>::List dirty_mesh_instance_weights;
SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
Expand Down Expand Up @@ -315,7 +317,9 @@ class MeshStorage : public RendererMeshStorage {
virtual String mesh_get_path(RID p_mesh) const override;

virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;

virtual void mesh_clear(RID p_mesh) override;
virtual void mesh_surface_remove(RID p_mesh, int p_surface) override;

_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
Expand Down
19 changes: 11 additions & 8 deletions scene/3d/mesh_instance_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,21 +381,24 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {

void MeshInstance3D::_mesh_changed() {
ERR_FAIL_COND(mesh.is_null());
surface_override_materials.resize(mesh->get_surface_count());
const int surface_count = mesh->get_surface_count();

surface_override_materials.resize(surface_count);

uint32_t initialize_bs_from = blend_shape_tracks.size();
blend_shape_tracks.resize(mesh->get_blend_shape_count());

for (uint32_t i = 0; i < blend_shape_tracks.size(); i++) {
blend_shape_properties["blend_shapes/" + String(mesh->get_blend_shape_name(i))] = i;
if (i < initialize_bs_from) {
set_blend_shape_value(i, blend_shape_tracks[i]);
} else {
set_blend_shape_value(i, 0);
if (surface_count > 0) {
for (uint32_t i = 0; i < blend_shape_tracks.size(); i++) {
blend_shape_properties["blend_shapes/" + String(mesh->get_blend_shape_name(i))] = i;
if (i < initialize_bs_from) {
set_blend_shape_value(i, blend_shape_tracks[i]);
} else {
set_blend_shape_value(i, 0);
}
}
}

int surface_count = mesh->get_surface_count();
for (int surface_index = 0; surface_index < surface_count; ++surface_index) {
if (surface_override_materials[surface_index].is_valid()) {
RS::get_singleton()->instance_set_surface_override_material(get_instance(), surface_index, surface_override_materials[surface_index]->get_rid());
Expand Down
12 changes: 12 additions & 0 deletions scene/resources/mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2007,6 +2007,17 @@ void ArrayMesh::clear_surfaces() {
aabb = AABB();
}

void ArrayMesh::surface_remove(int p_surface) {
ERR_FAIL_INDEX(p_surface, surfaces.size());
RS::get_singleton()->mesh_surface_remove(mesh, p_surface);
surfaces.remove_at(p_surface);

clear_cache();
_recompute_aabb();
notify_property_list_changed();
emit_changed();
}

void ArrayMesh::set_custom_aabb(const AABB &p_custom) {
_create_if_empty();
custom_aabb = p_custom;
Expand Down Expand Up @@ -2275,6 +2286,7 @@ void ArrayMesh::_bind_methods() {

ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0));
ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces);
ClassDB::bind_method(D_METHOD("surface_remove", "surf_idx"), &ArrayMesh::surface_remove);
ClassDB::bind_method(D_METHOD("surface_update_vertex_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_vertex_region);
ClassDB::bind_method(D_METHOD("surface_update_attribute_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_attribute_region);
ClassDB::bind_method(D_METHOD("surface_update_skin_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_skin_region);
Expand Down
Loading