Skip to content

Commit

Permalink
Implementation of ArrayMesh::surface_remove
Browse files Browse the repository at this point in the history
  • Loading branch information
ze2j committed Dec 2, 2023
1 parent 46dc277 commit 9b24a9c
Show file tree
Hide file tree
Showing 16 changed files with 413 additions and 143 deletions.
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.
</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 @@ -2254,6 +2254,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.
</description>
</method>
<method name="mesh_surface_set_material">
<return type="void" />
<param index="0" name="mesh" type="RID" />
Expand Down
231 changes: 149 additions & 82 deletions drivers/gles3/storage/mesh_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,67 @@ 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.
}

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 @@ -679,64 +740,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.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 @@ -932,6 +936,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 @@ -982,30 +1036,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 @@ -1058,6 +1092,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 @@ -1160,7 +1227,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 @@ -224,13 +224,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 @@ -295,7 +297,9 @@ class MeshStorage : public RendererMeshStorage {

virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) 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
16 changes: 9 additions & 7 deletions scene/3d/mesh_instance_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,16 +386,18 @@ void MeshInstance3D::_mesh_changed() {
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);
int surface_count = mesh->get_surface_count();
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 @@ -1999,6 +1999,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 @@ -2266,6 +2277,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
1 change: 1 addition & 0 deletions scene/resources/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ class ArrayMesh : public Mesh {

int get_surface_count() const override;

void surface_remove(int p_surface);
void clear_surfaces();

void surface_set_custom_aabb(int p_idx, const AABB &p_aabb); //only recognized by driver
Expand Down
Loading

0 comments on commit 9b24a9c

Please sign in to comment.