mirror of https://github.com/godotengine/godot
Add ArrayMesh::surface_remove
This commit is contained in:
parent
bbc54692c0
commit
97e0b43faa
|
|
@ -165,6 +165,13 @@
|
||||||
Returns the primitive type of the requested surface (see [method add_surface_from_arrays]).
|
Returns the primitive type of the requested surface (see [method add_surface_from_arrays]).
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</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">
|
<method name="surface_set_name">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="surf_idx" type="int" />
|
<param index="0" name="surf_idx" type="int" />
|
||||||
|
|
|
||||||
|
|
@ -2475,6 +2475,14 @@
|
||||||
Returns a mesh's surface's material.
|
Returns a mesh's surface's material.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</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">
|
<method name="mesh_surface_set_material">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="mesh" type="RID" />
|
<param index="0" name="mesh" type="RID" />
|
||||||
|
|
|
||||||
|
|
@ -448,6 +448,72 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
|
||||||
mesh->material_cache.clear();
|
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.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 {
|
int MeshStorage::mesh_get_blend_shape_count(RID p_mesh) const {
|
||||||
const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
||||||
ERR_FAIL_NULL_V(mesh, -1);
|
ERR_FAIL_NULL_V(mesh, -1);
|
||||||
|
|
@ -772,69 +838,7 @@ void MeshStorage::mesh_clear(RID p_mesh) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mesh->surface_count; i++) {
|
for (uint32_t i = 0; i < mesh->surface_count; i++) {
|
||||||
Mesh::Surface &s = *mesh->surfaces[i];
|
_mesh_surface_clear(mesh, 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]);
|
|
||||||
}
|
}
|
||||||
if (mesh->surfaces) {
|
if (mesh->surfaces) {
|
||||||
memfree(mesh->surfaces);
|
memfree(mesh->surfaces);
|
||||||
|
|
@ -1033,6 +1037,56 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
|
||||||
v.input_mask = p_input_mask;
|
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 */
|
/* MESH INSTANCE API */
|
||||||
|
|
||||||
RID MeshStorage::mesh_instance_create(RID p_base) {
|
RID MeshStorage::mesh_instance_create(RID p_base) {
|
||||||
|
|
@ -1083,30 +1137,10 @@ void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
|
void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
|
||||||
for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
|
while (mi->surfaces.size()) {
|
||||||
if (mi->surfaces[i].version_count != 0) {
|
_mesh_instance_remove_surface(mi, mi->surfaces.size() - 1);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mi->surfaces.clear();
|
mi->dirty = false;
|
||||||
mi->blend_weights.clear();
|
|
||||||
mi->skeleton_version = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) {
|
void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) {
|
||||||
|
|
@ -1159,6 +1193,39 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
|
||||||
mi->dirty = true;
|
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) {
|
void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) {
|
||||||
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
|
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
|
||||||
|
|
||||||
|
|
@ -1259,7 +1326,7 @@ void MeshStorage::update_mesh_instances() {
|
||||||
|
|
||||||
// Precompute base weight if using blend shapes.
|
// Precompute base weight if using blend shapes.
|
||||||
float base_weight = 1.0;
|
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++) {
|
for (uint32_t i = 0; i < mi->mesh->blend_shape_count; i++) {
|
||||||
base_weight -= mi->blend_weights[i];
|
base_weight -= mi->blend_weights[i];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,7 @@ private:
|
||||||
mutable RID_Owner<Mesh, true> mesh_owner;
|
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_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 */
|
/* Mesh Instance API */
|
||||||
|
|
||||||
|
|
@ -248,6 +249,7 @@ private:
|
||||||
|
|
||||||
void _mesh_instance_clear(MeshInstance *mi);
|
void _mesh_instance_clear(MeshInstance *mi);
|
||||||
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
|
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);
|
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_weights;
|
||||||
SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
|
SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
|
||||||
|
|
@ -315,7 +317,9 @@ public:
|
||||||
virtual String mesh_get_path(RID p_mesh) const override;
|
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_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;
|
||||||
|
|
||||||
virtual void mesh_clear(RID p_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) {
|
_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);
|
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
||||||
|
|
|
||||||
|
|
@ -381,21 +381,24 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
|
||||||
|
|
||||||
void MeshInstance3D::_mesh_changed() {
|
void MeshInstance3D::_mesh_changed() {
|
||||||
ERR_FAIL_COND(mesh.is_null());
|
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();
|
uint32_t initialize_bs_from = blend_shape_tracks.size();
|
||||||
blend_shape_tracks.resize(mesh->get_blend_shape_count());
|
blend_shape_tracks.resize(mesh->get_blend_shape_count());
|
||||||
|
|
||||||
for (uint32_t i = 0; i < blend_shape_tracks.size(); i++) {
|
if (surface_count > 0) {
|
||||||
blend_shape_properties["blend_shapes/" + String(mesh->get_blend_shape_name(i))] = i;
|
for (uint32_t i = 0; i < blend_shape_tracks.size(); i++) {
|
||||||
if (i < initialize_bs_from) {
|
blend_shape_properties["blend_shapes/" + String(mesh->get_blend_shape_name(i))] = i;
|
||||||
set_blend_shape_value(i, blend_shape_tracks[i]);
|
if (i < initialize_bs_from) {
|
||||||
} else {
|
set_blend_shape_value(i, blend_shape_tracks[i]);
|
||||||
set_blend_shape_value(i, 0);
|
} 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) {
|
for (int surface_index = 0; surface_index < surface_count; ++surface_index) {
|
||||||
if (surface_override_materials[surface_index].is_valid()) {
|
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());
|
RS::get_singleton()->instance_set_surface_override_material(get_instance(), surface_index, surface_override_materials[surface_index]->get_rid());
|
||||||
|
|
|
||||||
|
|
@ -2007,6 +2007,17 @@ void ArrayMesh::clear_surfaces() {
|
||||||
aabb = AABB();
|
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) {
|
void ArrayMesh::set_custom_aabb(const AABB &p_custom) {
|
||||||
_create_if_empty();
|
_create_if_empty();
|
||||||
custom_aabb = p_custom;
|
custom_aabb = p_custom;
|
||||||
|
|
@ -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("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("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_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_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);
|
ClassDB::bind_method(D_METHOD("surface_update_skin_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_skin_region);
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,7 @@ public:
|
||||||
|
|
||||||
int get_surface_count() const override;
|
int get_surface_count() const override;
|
||||||
|
|
||||||
|
void surface_remove(int p_surface);
|
||||||
void clear_surfaces();
|
void clear_surfaces();
|
||||||
|
|
||||||
void surface_set_custom_aabb(int p_idx, const AABB &p_aabb); //only recognized by driver
|
void surface_set_custom_aabb(int p_idx, const AABB &p_aabb); //only recognized by driver
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,12 @@ void MeshStorage::mesh_free(RID p_rid) {
|
||||||
mesh_owner.free(p_rid);
|
mesh_owner.free(p_rid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MeshStorage::mesh_surface_remove(RID p_mesh, int p_surface) {
|
||||||
|
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
|
||||||
|
ERR_FAIL_NULL(m);
|
||||||
|
m->surfaces.remove_at(p_surface);
|
||||||
|
}
|
||||||
|
|
||||||
void MeshStorage::mesh_clear(RID p_mesh) {
|
void MeshStorage::mesh_clear(RID p_mesh) {
|
||||||
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
|
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
|
||||||
ERR_FAIL_NULL(m);
|
ERR_FAIL_NULL(m);
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,8 @@ public:
|
||||||
virtual String mesh_get_path(RID p_mesh) const override { return String(); }
|
virtual String mesh_get_path(RID p_mesh) const override { return String(); }
|
||||||
|
|
||||||
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override {}
|
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override {}
|
||||||
|
|
||||||
|
virtual void mesh_surface_remove(RID p_mesh, int p_surface) override;
|
||||||
virtual void mesh_clear(RID p_mesh) override;
|
virtual void mesh_clear(RID p_mesh) override;
|
||||||
|
|
||||||
/* MESH INSTANCE */
|
/* MESH INSTANCE */
|
||||||
|
|
|
||||||
|
|
@ -505,6 +505,40 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
|
||||||
mesh->material_cache.clear();
|
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.is_valid()) {
|
||||||
|
RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions
|
||||||
|
}
|
||||||
|
if (s.attribute_buffer.is_valid()) {
|
||||||
|
RD::get_singleton()->free(s.attribute_buffer);
|
||||||
|
}
|
||||||
|
if (s.skin_buffer.is_valid()) {
|
||||||
|
RD::get_singleton()->free(s.skin_buffer);
|
||||||
|
}
|
||||||
|
if (s.versions) {
|
||||||
|
memfree(s.versions); //reallocs, so free with memfree.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.index_buffer.is_valid()) {
|
||||||
|
RD::get_singleton()->free(s.index_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.lod_count) {
|
||||||
|
for (uint32_t j = 0; j < s.lod_count; j++) {
|
||||||
|
RD::get_singleton()->free(s.lods[j].index_buffer);
|
||||||
|
}
|
||||||
|
memdelete_arr(s.lods);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.blend_shape_buffer.is_valid()) {
|
||||||
|
RD::get_singleton()->free(s.blend_shape_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
memdelete(mesh->surfaces[p_surface]);
|
||||||
|
}
|
||||||
|
|
||||||
int MeshStorage::mesh_get_blend_shape_count(RID p_mesh) const {
|
int MeshStorage::mesh_get_blend_shape_count(RID p_mesh) const {
|
||||||
const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
||||||
ERR_FAIL_NULL_V(mesh, -1);
|
ERR_FAIL_NULL_V(mesh, -1);
|
||||||
|
|
@ -812,36 +846,7 @@ void MeshStorage::mesh_clear(RID p_mesh) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mesh->surface_count; i++) {
|
for (uint32_t i = 0; i < mesh->surface_count; i++) {
|
||||||
Mesh::Surface &s = *mesh->surfaces[i];
|
_mesh_surface_clear(mesh, i);
|
||||||
if (s.vertex_buffer.is_valid()) {
|
|
||||||
RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions
|
|
||||||
}
|
|
||||||
if (s.attribute_buffer.is_valid()) {
|
|
||||||
RD::get_singleton()->free(s.attribute_buffer);
|
|
||||||
}
|
|
||||||
if (s.skin_buffer.is_valid()) {
|
|
||||||
RD::get_singleton()->free(s.skin_buffer);
|
|
||||||
}
|
|
||||||
if (s.versions) {
|
|
||||||
memfree(s.versions); //reallocs, so free with memfree.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s.index_buffer.is_valid()) {
|
|
||||||
RD::get_singleton()->free(s.index_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s.lod_count) {
|
|
||||||
for (uint32_t j = 0; j < s.lod_count; j++) {
|
|
||||||
RD::get_singleton()->free(s.lods[j].index_buffer);
|
|
||||||
}
|
|
||||||
memdelete_arr(s.lods);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s.blend_shape_buffer.is_valid()) {
|
|
||||||
RD::get_singleton()->free(s.blend_shape_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
memdelete(mesh->surfaces[i]);
|
|
||||||
}
|
}
|
||||||
if (mesh->surfaces) {
|
if (mesh->surfaces) {
|
||||||
memfree(mesh->surfaces);
|
memfree(mesh->surfaces);
|
||||||
|
|
@ -860,6 +865,56 @@ void MeshStorage::mesh_clear(RID p_mesh) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
|
bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
|
||||||
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
||||||
ERR_FAIL_NULL_V(mesh, false);
|
ERR_FAIL_NULL_V(mesh, false);
|
||||||
|
|
@ -925,29 +980,10 @@ void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
|
void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
|
||||||
for (const RendererRD::MeshStorage::MeshInstance::Surface &surface : mi->surfaces) {
|
while (mi->surfaces.size()) {
|
||||||
if (surface.versions) {
|
_mesh_instance_remove_surface(mi, mi->surfaces.size() - 1);
|
||||||
for (uint32_t j = 0; j < surface.version_count; j++) {
|
|
||||||
RD::get_singleton()->free(surface.versions[j].vertex_array);
|
|
||||||
}
|
|
||||||
memfree(surface.versions);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
|
||||||
if (surface.vertex_buffer[i].is_valid()) {
|
|
||||||
RD::get_singleton()->free(surface.vertex_buffer[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mi->surfaces.clear();
|
mi->dirty = false;
|
||||||
|
|
||||||
if (mi->blend_weights_buffer.is_valid()) {
|
|
||||||
RD::get_singleton()->free(mi->blend_weights_buffer);
|
|
||||||
mi->blend_weights_buffer = RID();
|
|
||||||
}
|
|
||||||
mi->blend_weights.clear();
|
|
||||||
mi->weights_dirty = false;
|
|
||||||
mi->skeleton_version = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) {
|
void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) {
|
||||||
|
|
@ -994,6 +1030,36 @@ void MeshStorage::_mesh_instance_add_surface_buffer(MeshInstance *mi, Mesh *mesh
|
||||||
s->uniform_set[p_buffer_index] = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE);
|
s->uniform_set[p_buffer_index] = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MeshStorage::_mesh_instance_remove_surface(MeshInstance *mi, int p_surface) {
|
||||||
|
MeshInstance::Surface &surface = mi->surfaces[p_surface];
|
||||||
|
|
||||||
|
if (surface.versions) {
|
||||||
|
for (uint32_t j = 0; j < surface.version_count; j++) {
|
||||||
|
RD::get_singleton()->free(surface.versions[j].vertex_array);
|
||||||
|
}
|
||||||
|
memfree(surface.versions);
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < 2; i++) {
|
||||||
|
if (surface.vertex_buffer[i].is_valid()) {
|
||||||
|
RD::get_singleton()->free(surface.vertex_buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mi->surfaces.remove_at(p_surface);
|
||||||
|
|
||||||
|
if (mi->surfaces.is_empty()) {
|
||||||
|
if (mi->blend_weights_buffer.is_valid()) {
|
||||||
|
RD::get_singleton()->free(mi->blend_weights_buffer);
|
||||||
|
mi->blend_weights_buffer = RID();
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) {
|
||||||
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
|
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,10 +201,12 @@ private:
|
||||||
|
|
||||||
RD::VertexFormatID _mesh_surface_generate_vertex_format(uint64_t p_surface_format, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors, uint32_t &r_position_stride);
|
RD::VertexFormatID _mesh_surface_generate_vertex_format(uint64_t p_surface_format, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors, uint32_t &r_position_stride);
|
||||||
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0);
|
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0);
|
||||||
|
void _mesh_surface_clear(Mesh *mesh, int p_surface);
|
||||||
|
|
||||||
void _mesh_instance_clear(MeshInstance *mi);
|
void _mesh_instance_clear(MeshInstance *mi);
|
||||||
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
|
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
|
||||||
void _mesh_instance_add_surface_buffer(MeshInstance *mi, Mesh *mesh, MeshInstance::Surface *s, uint32_t p_surface, uint32_t p_buffer_index);
|
void _mesh_instance_add_surface_buffer(MeshInstance *mi, Mesh *mesh, MeshInstance::Surface *s, uint32_t p_surface, uint32_t p_buffer_index);
|
||||||
|
void _mesh_instance_remove_surface(MeshInstance *mi, int p_surface);
|
||||||
|
|
||||||
mutable RID_Owner<MeshInstance> mesh_instance_owner;
|
mutable RID_Owner<MeshInstance> mesh_instance_owner;
|
||||||
|
|
||||||
|
|
@ -388,6 +390,7 @@ public:
|
||||||
virtual String mesh_get_path(RID p_mesh) const override;
|
virtual String mesh_get_path(RID p_mesh) const override;
|
||||||
|
|
||||||
virtual void mesh_clear(RID p_mesh) override;
|
virtual void mesh_clear(RID p_mesh) override;
|
||||||
|
virtual void mesh_surface_remove(RID p_mesh, int p_surface) override;
|
||||||
|
|
||||||
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override;
|
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -376,6 +376,7 @@ public:
|
||||||
|
|
||||||
FUNC2(mesh_set_shadow_mesh, RID, RID)
|
FUNC2(mesh_set_shadow_mesh, RID, RID)
|
||||||
|
|
||||||
|
FUNC2(mesh_surface_remove, RID, int)
|
||||||
FUNC1(mesh_clear, RID)
|
FUNC1(mesh_clear, RID)
|
||||||
|
|
||||||
/* MULTIMESH API */
|
/* MULTIMESH API */
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ public:
|
||||||
|
|
||||||
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
|
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
|
||||||
|
|
||||||
|
virtual void mesh_surface_remove(RID p_mesh, int p_surface) = 0;
|
||||||
virtual void mesh_clear(RID p_mesh) = 0;
|
virtual void mesh_clear(RID p_mesh) = 0;
|
||||||
|
|
||||||
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0;
|
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0;
|
||||||
|
|
|
||||||
|
|
@ -2346,6 +2346,7 @@ void RenderingServer::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("mesh_get_surface_count", "mesh"), &RenderingServer::mesh_get_surface_count);
|
ClassDB::bind_method(D_METHOD("mesh_get_surface_count", "mesh"), &RenderingServer::mesh_get_surface_count);
|
||||||
ClassDB::bind_method(D_METHOD("mesh_set_custom_aabb", "mesh", "aabb"), &RenderingServer::mesh_set_custom_aabb);
|
ClassDB::bind_method(D_METHOD("mesh_set_custom_aabb", "mesh", "aabb"), &RenderingServer::mesh_set_custom_aabb);
|
||||||
ClassDB::bind_method(D_METHOD("mesh_get_custom_aabb", "mesh"), &RenderingServer::mesh_get_custom_aabb);
|
ClassDB::bind_method(D_METHOD("mesh_get_custom_aabb", "mesh"), &RenderingServer::mesh_get_custom_aabb);
|
||||||
|
ClassDB::bind_method(D_METHOD("mesh_surface_remove", "mesh", "surface"), &RenderingServer::mesh_surface_remove);
|
||||||
ClassDB::bind_method(D_METHOD("mesh_clear", "mesh"), &RenderingServer::mesh_clear);
|
ClassDB::bind_method(D_METHOD("mesh_clear", "mesh"), &RenderingServer::mesh_clear);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("mesh_surface_update_vertex_region", "mesh", "surface", "offset", "data"), &RenderingServer::mesh_surface_update_vertex_region);
|
ClassDB::bind_method(D_METHOD("mesh_surface_update_vertex_region", "mesh", "surface", "offset", "data"), &RenderingServer::mesh_surface_update_vertex_region);
|
||||||
|
|
|
||||||
|
|
@ -438,6 +438,7 @@ public:
|
||||||
|
|
||||||
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
|
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
|
||||||
|
|
||||||
|
virtual void mesh_surface_remove(RID p_mesh, int p_surface) = 0;
|
||||||
virtual void mesh_clear(RID p_mesh) = 0;
|
virtual void mesh_clear(RID p_mesh) = 0;
|
||||||
|
|
||||||
/* MULTIMESH API */
|
/* MULTIMESH API */
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,25 @@ TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") {
|
||||||
CHECK(mesh->get_blend_shape_count() == 0);
|
CHECK(mesh->get_blend_shape_count() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SUBCASE("Adding blend shapes once all surfaces have been removed is allowed") {
|
||||||
|
Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
|
||||||
|
Array cylinder_array{};
|
||||||
|
cylinder_array.resize(Mesh::ARRAY_MAX);
|
||||||
|
cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
|
||||||
|
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
|
||||||
|
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
|
||||||
|
|
||||||
|
mesh->surface_remove(0);
|
||||||
|
ERR_PRINT_OFF
|
||||||
|
mesh->add_blend_shape(name_a);
|
||||||
|
ERR_PRINT_ON
|
||||||
|
CHECK(mesh->get_blend_shape_count() == 0);
|
||||||
|
|
||||||
|
mesh->surface_remove(0);
|
||||||
|
mesh->add_blend_shape(name_a);
|
||||||
|
CHECK(mesh->get_blend_shape_count() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
SUBCASE("Change blend shape name after adding.") {
|
SUBCASE("Change blend shape name after adding.") {
|
||||||
mesh->add_blend_shape(name_a);
|
mesh->add_blend_shape(name_a);
|
||||||
mesh->set_blend_shape_name(0, name_b);
|
mesh->set_blend_shape_name(0, name_b);
|
||||||
|
|
@ -114,6 +133,35 @@ TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") {
|
||||||
CHECK(mesh->get_blend_shape_count() == 0);
|
CHECK(mesh->get_blend_shape_count() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SUBCASE("Clearing all blend shapes once all surfaces have been removed is allowed") {
|
||||||
|
mesh->add_blend_shape(name_a);
|
||||||
|
mesh->add_blend_shape(name_b);
|
||||||
|
Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
|
||||||
|
Array cylinder_array{};
|
||||||
|
cylinder_array.resize(Mesh::ARRAY_MAX);
|
||||||
|
cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
|
||||||
|
Array blend_shape{};
|
||||||
|
blend_shape.resize(Mesh::ARRAY_MAX);
|
||||||
|
blend_shape[Mesh::ARRAY_VERTEX] = cylinder_array[Mesh::ARRAY_VERTEX];
|
||||||
|
blend_shape[Mesh::ARRAY_NORMAL] = cylinder_array[Mesh::ARRAY_NORMAL];
|
||||||
|
blend_shape[Mesh::ARRAY_TANGENT] = cylinder_array[Mesh::ARRAY_TANGENT];
|
||||||
|
Array blend_shapes{};
|
||||||
|
blend_shapes.push_back(blend_shape);
|
||||||
|
blend_shapes.push_back(blend_shape);
|
||||||
|
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array, blend_shapes);
|
||||||
|
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array, blend_shapes);
|
||||||
|
|
||||||
|
mesh->surface_remove(0);
|
||||||
|
ERR_PRINT_OFF
|
||||||
|
mesh->clear_blend_shapes();
|
||||||
|
ERR_PRINT_ON
|
||||||
|
CHECK(mesh->get_blend_shape_count() == 2);
|
||||||
|
|
||||||
|
mesh->surface_remove(0);
|
||||||
|
mesh->clear_blend_shapes();
|
||||||
|
CHECK(mesh->get_blend_shape_count() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
SUBCASE("Can't add surface with incorrect number of blend shapes.") {
|
SUBCASE("Can't add surface with incorrect number of blend shapes.") {
|
||||||
mesh->add_blend_shape(name_a);
|
mesh->add_blend_shape(name_a);
|
||||||
mesh->add_blend_shape(name_b);
|
mesh->add_blend_shape(name_b);
|
||||||
|
|
@ -249,13 +297,16 @@ TEST_CASE("[SceneTree][ArrayMesh] Get/Set mesh metadata and actions") {
|
||||||
Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
|
Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
|
||||||
Array cylinder_array{};
|
Array cylinder_array{};
|
||||||
cylinder_array.resize(Mesh::ARRAY_MAX);
|
cylinder_array.resize(Mesh::ARRAY_MAX);
|
||||||
cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
|
constexpr float cylinder_radius = 3.f;
|
||||||
|
constexpr float cylinder_height = 5.f;
|
||||||
|
cylinder->create_mesh_array(cylinder_array, cylinder_radius, cylinder_radius, cylinder_height);
|
||||||
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
|
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
|
||||||
|
|
||||||
Ref<BoxMesh> box = memnew(BoxMesh);
|
Ref<BoxMesh> box = memnew(BoxMesh);
|
||||||
Array box_array{};
|
Array box_array{};
|
||||||
box_array.resize(Mesh::ARRAY_MAX);
|
box_array.resize(Mesh::ARRAY_MAX);
|
||||||
box->create_mesh_array(box_array, Vector3(2.f, 1.2f, 1.6f));
|
const Vector3 box_size = Vector3(2.f, 1.2f, 1.6f);
|
||||||
|
box->create_mesh_array(box_array, box_size);
|
||||||
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, box_array);
|
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, box_array);
|
||||||
|
|
||||||
SUBCASE("Set the shadow mesh.") {
|
SUBCASE("Set the shadow mesh.") {
|
||||||
|
|
@ -337,6 +388,43 @@ TEST_CASE("[SceneTree][ArrayMesh] Get/Set mesh metadata and actions") {
|
||||||
CHECK((mesh2->surface_get_format(0) & surface_data.format) != 0);
|
CHECK((mesh2->surface_get_format(0) & surface_data.format) != 0);
|
||||||
CHECK(mesh2->get_aabb().is_equal_approx(surface_data.aabb));
|
CHECK(mesh2->get_aabb().is_equal_approx(surface_data.aabb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SUBCASE("Removing a surface decreases surface count.") {
|
||||||
|
REQUIRE(mesh->get_surface_count() == 2);
|
||||||
|
mesh->surface_remove(0);
|
||||||
|
CHECK(mesh->get_surface_count() == 1);
|
||||||
|
mesh->surface_remove(0);
|
||||||
|
CHECK(mesh->get_surface_count() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("Remove the first surface and check the mesh's AABB.") {
|
||||||
|
REQUIRE(mesh->get_surface_count() >= 1);
|
||||||
|
mesh->surface_remove(0);
|
||||||
|
const AABB box_aabb = AABB(-box_size / 2, box_size);
|
||||||
|
CHECK(mesh->get_aabb().is_equal_approx(box_aabb));
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("Remove the last surface and check the mesh's AABB.") {
|
||||||
|
REQUIRE(mesh->get_surface_count() >= 1);
|
||||||
|
mesh->surface_remove(mesh->get_surface_count() - 1);
|
||||||
|
const AABB cylinder_aabb = AABB(Vector3(-cylinder_radius, -cylinder_height / 2, -cylinder_radius),
|
||||||
|
Vector3(2 * cylinder_radius, cylinder_height, 2 * cylinder_radius));
|
||||||
|
CHECK(mesh->get_aabb().is_equal_approx(cylinder_aabb));
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("Remove all surfaces and check the mesh's AABB.") {
|
||||||
|
while (mesh->get_surface_count()) {
|
||||||
|
mesh->surface_remove(0);
|
||||||
|
}
|
||||||
|
CHECK(mesh->get_aabb() == AABB());
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("Removing a non-existent surface causes error.") {
|
||||||
|
ERR_PRINT_OFF
|
||||||
|
mesh->surface_remove(42);
|
||||||
|
ERR_PRINT_ON
|
||||||
|
CHECK(mesh->get_surface_count() == 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace TestArrayMesh
|
} // namespace TestArrayMesh
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue