OBJ: Avoid retrieving mesh arrays, improve const correctness
Store the potentially owned mesh separately from the original/evaluated mesh which is now stored with a const pointer. Also store mesh spans separately in the class so they don't have to be retrieved for every index.
This commit is contained in:
parent
a459018a99
commit
a5f9f7e2fc
|
@ -250,7 +250,7 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
|
|||
{
|
||||
const int tot_count = obj_mesh_data.tot_vertices();
|
||||
|
||||
Mesh *mesh = obj_mesh_data.get_mesh();
|
||||
const Mesh *mesh = obj_mesh_data.get_mesh();
|
||||
const CustomDataLayer *colors_layer = nullptr;
|
||||
if (write_colors) {
|
||||
colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
|
||||
|
|
|
@ -33,21 +33,23 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj
|
|||
/* We need to copy the object because it may be in temporary space. */
|
||||
Object *obj_eval = DEG_get_evaluated_object(depsgraph, mesh_object);
|
||||
export_object_eval_ = dna::shallow_copy(*obj_eval);
|
||||
export_mesh_eval_ = export_params.apply_modifiers ?
|
||||
BKE_object_get_evaluated_mesh(&export_object_eval_) :
|
||||
BKE_object_get_pre_modified_mesh(&export_object_eval_);
|
||||
mesh_eval_needs_free_ = false;
|
||||
|
||||
if (!export_mesh_eval_) {
|
||||
export_mesh_ = export_params.apply_modifiers ?
|
||||
BKE_object_get_evaluated_mesh(&export_object_eval_) :
|
||||
BKE_object_get_pre_modified_mesh(&export_object_eval_);
|
||||
if (export_mesh_) {
|
||||
mesh_verts_ = export_mesh_->verts();
|
||||
mesh_edges_ = export_mesh_->edges();
|
||||
mesh_polys_ = export_mesh_->polys();
|
||||
mesh_loops_ = export_mesh_->loops();
|
||||
}
|
||||
else {
|
||||
/* Curves and NURBS surfaces need a new mesh when they're
|
||||
* exported in the form of vertices and edges.
|
||||
*/
|
||||
export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true);
|
||||
/* Since a new mesh been allocated, it needs to be freed in the destructor. */
|
||||
mesh_eval_needs_free_ = true;
|
||||
this->set_mesh(BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true));
|
||||
}
|
||||
if (export_params.export_triangulated_mesh && export_object_eval_.type == OB_MESH) {
|
||||
std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval();
|
||||
this->triangulate_mesh_eval();
|
||||
}
|
||||
set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
|
||||
}
|
||||
|
@ -60,18 +62,26 @@ OBJMesh::~OBJMesh()
|
|||
clear();
|
||||
}
|
||||
|
||||
void OBJMesh::free_mesh_if_needed()
|
||||
void OBJMesh::set_mesh(Mesh *mesh)
|
||||
{
|
||||
if (mesh_eval_needs_free_ && export_mesh_eval_) {
|
||||
BKE_id_free(nullptr, export_mesh_eval_);
|
||||
export_mesh_eval_ = nullptr;
|
||||
mesh_eval_needs_free_ = false;
|
||||
if (owned_export_mesh_) {
|
||||
BKE_id_free(nullptr, owned_export_mesh_);
|
||||
}
|
||||
owned_export_mesh_ = mesh;
|
||||
export_mesh_ = owned_export_mesh_;
|
||||
mesh_verts_ = mesh->verts();
|
||||
mesh_edges_ = mesh->edges();
|
||||
mesh_polys_ = mesh->polys();
|
||||
mesh_loops_ = mesh->loops();
|
||||
}
|
||||
|
||||
void OBJMesh::clear()
|
||||
{
|
||||
free_mesh_if_needed();
|
||||
if (owned_export_mesh_) {
|
||||
BKE_id_free(nullptr, owned_export_mesh_);
|
||||
owned_export_mesh_ = nullptr;
|
||||
}
|
||||
export_mesh_ = nullptr;
|
||||
uv_indices_.clear_and_make_inline();
|
||||
uv_coords_.clear_and_make_inline();
|
||||
loop_to_normal_index_.clear_and_make_inline();
|
||||
|
@ -83,10 +93,10 @@ void OBJMesh::clear()
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
||||
void OBJMesh::triangulate_mesh_eval()
|
||||
{
|
||||
if (export_mesh_eval_->totpoly <= 0) {
|
||||
return {export_mesh_eval_, false};
|
||||
if (export_mesh_->totpoly <= 0) {
|
||||
return;
|
||||
}
|
||||
const BMeshCreateParams bm_create_params = {false};
|
||||
BMeshFromMeshParams bm_convert_params{};
|
||||
|
@ -99,7 +109,7 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
|||
* triangulated here. */
|
||||
const int triangulate_min_verts = 4;
|
||||
|
||||
BMesh *bmesh = BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params);
|
||||
BMesh *bmesh = BKE_mesh_to_bmesh_ex(export_mesh_, &bm_create_params, &bm_convert_params);
|
||||
BM_mesh_triangulate(bmesh,
|
||||
MOD_TRIANGULATE_NGON_BEAUTY,
|
||||
MOD_TRIANGULATE_QUAD_SHORTEDGE,
|
||||
|
@ -108,11 +118,9 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
|
|||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(bmesh, nullptr, export_mesh_eval_);
|
||||
Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(bmesh, nullptr, export_mesh_);
|
||||
BM_mesh_free(bmesh);
|
||||
free_mesh_if_needed();
|
||||
return {triangulated, true};
|
||||
this->set_mesh(triangulated);
|
||||
}
|
||||
|
||||
void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
|
||||
|
@ -137,12 +145,12 @@ void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
|
|||
|
||||
int OBJMesh::tot_vertices() const
|
||||
{
|
||||
return export_mesh_eval_->totvert;
|
||||
return export_mesh_->totvert;
|
||||
}
|
||||
|
||||
int OBJMesh::tot_polygons() const
|
||||
{
|
||||
return export_mesh_eval_->totpoly;
|
||||
return export_mesh_->totpoly;
|
||||
}
|
||||
|
||||
int OBJMesh::tot_uv_vertices() const
|
||||
|
@ -152,12 +160,12 @@ int OBJMesh::tot_uv_vertices() const
|
|||
|
||||
int OBJMesh::tot_edges() const
|
||||
{
|
||||
return export_mesh_eval_->totedge;
|
||||
return export_mesh_->totedge;
|
||||
}
|
||||
|
||||
int16_t OBJMesh::tot_materials() const
|
||||
{
|
||||
return export_mesh_eval_->totcol;
|
||||
return export_mesh_->totcol;
|
||||
}
|
||||
|
||||
int OBJMesh::tot_normal_indices() const
|
||||
|
@ -175,27 +183,25 @@ int OBJMesh::ith_smooth_group(const int poly_index) const
|
|||
|
||||
void OBJMesh::ensure_mesh_normals() const
|
||||
{
|
||||
BKE_mesh_calc_normals_split(export_mesh_eval_);
|
||||
/* Const cast can be removed when calculating face corner normals lazily is possible. */
|
||||
BKE_mesh_calc_normals_split(const_cast<Mesh *>(export_mesh_));
|
||||
}
|
||||
|
||||
void OBJMesh::calc_smooth_groups(const bool use_bitflags)
|
||||
{
|
||||
const Span<MEdge> edges = export_mesh_eval_->edges();
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(edges.data(),
|
||||
edges.size(),
|
||||
polys.data(),
|
||||
polys.size(),
|
||||
loops.data(),
|
||||
loops.size(),
|
||||
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.data(),
|
||||
mesh_edges_.size(),
|
||||
mesh_polys_.data(),
|
||||
mesh_polys_.size(),
|
||||
mesh_loops_.data(),
|
||||
mesh_loops_.size(),
|
||||
&tot_smooth_groups_,
|
||||
use_bitflags);
|
||||
}
|
||||
|
||||
void OBJMesh::calc_poly_order()
|
||||
{
|
||||
const bke::AttributeAccessor attributes = export_mesh_eval_->attributes();
|
||||
const bke::AttributeAccessor attributes = export_mesh_->attributes();
|
||||
const VArray<int> material_indices = attributes.lookup_or_default<int>(
|
||||
"material_index", ATTR_DOMAIN_FACE, 0);
|
||||
if (material_indices.is_single() && material_indices.get_internal_single() == 0) {
|
||||
|
@ -234,8 +240,7 @@ const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
|
|||
|
||||
bool OBJMesh::is_ith_poly_smooth(const int poly_index) const
|
||||
{
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
return polys[poly_index].flag & ME_SMOOTH;
|
||||
return mesh_polys_[poly_index].flag & ME_SMOOTH;
|
||||
}
|
||||
|
||||
const char *OBJMesh::get_object_name() const
|
||||
|
@ -245,7 +250,7 @@ const char *OBJMesh::get_object_name() const
|
|||
|
||||
const char *OBJMesh::get_object_mesh_name() const
|
||||
{
|
||||
return export_mesh_eval_->id.name + 2;
|
||||
return export_mesh_->id.name + 2;
|
||||
}
|
||||
|
||||
const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
|
||||
|
@ -260,8 +265,7 @@ const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
|
|||
float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scale) const
|
||||
{
|
||||
float3 r_coords;
|
||||
const Span<MVert> verts = export_mesh_eval_->verts();
|
||||
copy_v3_v3(r_coords, verts[vert_index].co);
|
||||
copy_v3_v3(r_coords, mesh_verts_[vert_index].co);
|
||||
mul_m4_v3(world_and_axes_transform_, r_coords);
|
||||
mul_v3_fl(r_coords, global_scale);
|
||||
return r_coords;
|
||||
|
@ -269,10 +273,8 @@ float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scal
|
|||
|
||||
Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const
|
||||
{
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
const MPoly &mpoly = polys[poly_index];
|
||||
const MLoop *mloop = &loops[mpoly.loopstart];
|
||||
const MPoly &mpoly = mesh_polys_[poly_index];
|
||||
const MLoop *mloop = &mesh_loops_[mpoly.loopstart];
|
||||
const int totloop = mpoly.totloop;
|
||||
Vector<int> r_poly_vertex_indices(totloop);
|
||||
for (int loop_index = 0; loop_index < totloop; loop_index++) {
|
||||
|
@ -283,29 +285,27 @@ Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const
|
|||
|
||||
void OBJMesh::store_uv_coords_and_indices()
|
||||
{
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
const int totvert = export_mesh_eval_->totvert;
|
||||
const int totvert = export_mesh_->totvert;
|
||||
const MLoopUV *mloopuv = static_cast<const MLoopUV *>(
|
||||
CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
|
||||
CustomData_get_layer(&export_mesh_->ldata, CD_MLOOPUV));
|
||||
if (!mloopuv) {
|
||||
tot_uv_vertices_ = 0;
|
||||
return;
|
||||
}
|
||||
const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
|
||||
|
||||
UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(polys.data(),
|
||||
UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(mesh_polys_.data(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
loops.data(),
|
||||
mesh_loops_.data(),
|
||||
mloopuv,
|
||||
polys.size(),
|
||||
mesh_polys_.size(),
|
||||
totvert,
|
||||
limit,
|
||||
false,
|
||||
false);
|
||||
|
||||
uv_indices_.resize(polys.size());
|
||||
uv_indices_.resize(mesh_polys_.size());
|
||||
/* At least total vertices of a mesh will be present in its texture map. So
|
||||
* reserve minimum space early. */
|
||||
uv_coords_.reserve(totvert);
|
||||
|
@ -317,11 +317,11 @@ void OBJMesh::store_uv_coords_and_indices()
|
|||
if (uv_vert->separate) {
|
||||
tot_uv_vertices_ += 1;
|
||||
}
|
||||
const int verts_in_poly = polys[uv_vert->poly_index].totloop;
|
||||
const int verts_in_poly = mesh_polys_[uv_vert->poly_index].totloop;
|
||||
|
||||
/* Store UV vertex coordinates. */
|
||||
uv_coords_.resize(tot_uv_vertices_);
|
||||
const int loopstart = polys[uv_vert->poly_index].loopstart;
|
||||
const int loopstart = mesh_polys_[uv_vert->poly_index].loopstart;
|
||||
Span<float> vert_uv_coords(mloopuv[loopstart + uv_vert->loop_of_poly_index].uv, 2);
|
||||
uv_coords_[tot_uv_vertices_ - 1] = float2(vert_uv_coords[0], vert_uv_coords[1]);
|
||||
|
||||
|
@ -339,7 +339,7 @@ Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
|
|||
if (uv_indices_.size() <= 0) {
|
||||
return {};
|
||||
}
|
||||
BLI_assert(poly_index < export_mesh_eval_->totpoly);
|
||||
BLI_assert(poly_index < export_mesh_->totpoly);
|
||||
BLI_assert(poly_index < uv_indices_.size());
|
||||
return uv_indices_[poly_index];
|
||||
}
|
||||
|
@ -347,11 +347,9 @@ Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
|
|||
float3 OBJMesh::calc_poly_normal(const int poly_index) const
|
||||
{
|
||||
float3 r_poly_normal;
|
||||
const Span<MVert> verts = export_mesh_eval_->verts();
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
const MPoly &poly = polys[poly_index];
|
||||
BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], verts.data(), r_poly_normal);
|
||||
const MPoly &poly = mesh_polys_[poly_index];
|
||||
BKE_mesh_calc_poly_normal(
|
||||
&poly, &mesh_loops_[poly.loopstart], mesh_verts_.data(), r_poly_normal);
|
||||
mul_m3_v3(world_and_axes_normal_transform_, r_poly_normal);
|
||||
normalize_v3(r_poly_normal);
|
||||
return r_poly_normal;
|
||||
|
@ -375,8 +373,6 @@ static float3 round_float3_to_n_digits(const float3 &v, int round_digits)
|
|||
|
||||
void OBJMesh::store_normal_coords_and_indices()
|
||||
{
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
|
||||
/* We'll round normal components to 4 digits.
|
||||
* This will cover up some minor differences
|
||||
* between floating point calculations on different platforms.
|
||||
|
@ -386,19 +382,19 @@ void OBJMesh::store_normal_coords_and_indices()
|
|||
int cur_normal_index = 0;
|
||||
Map<float3, int> normal_to_index;
|
||||
/* We don't know how many unique normals there will be, but this is a guess. */
|
||||
normal_to_index.reserve(export_mesh_eval_->totpoly);
|
||||
loop_to_normal_index_.resize(export_mesh_eval_->totloop);
|
||||
normal_to_index.reserve(export_mesh_->totpoly);
|
||||
loop_to_normal_index_.resize(export_mesh_->totloop);
|
||||
loop_to_normal_index_.fill(-1);
|
||||
const float(*lnors)[3] = static_cast<const float(*)[3]>(
|
||||
CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
|
||||
for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) {
|
||||
const MPoly &mpoly = polys[poly_index];
|
||||
CustomData_get_layer(&export_mesh_->ldata, CD_NORMAL));
|
||||
for (int poly_index = 0; poly_index < export_mesh_->totpoly; ++poly_index) {
|
||||
const MPoly &mpoly = mesh_polys_[poly_index];
|
||||
bool need_per_loop_normals = lnors != nullptr || (mpoly.flag & ME_SMOOTH);
|
||||
if (need_per_loop_normals) {
|
||||
for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; ++loop_of_poly) {
|
||||
float3 loop_normal;
|
||||
int loop_index = mpoly.loopstart + loop_of_poly;
|
||||
BLI_assert(loop_index < export_mesh_eval_->totloop);
|
||||
BLI_assert(loop_index < export_mesh_->totloop);
|
||||
copy_v3_v3(loop_normal, lnors[loop_index]);
|
||||
mul_m3_v3(world_and_axes_normal_transform_, loop_normal);
|
||||
normalize_v3(loop_normal);
|
||||
|
@ -423,7 +419,7 @@ void OBJMesh::store_normal_coords_and_indices()
|
|||
}
|
||||
for (int i = 0; i < mpoly.totloop; ++i) {
|
||||
int loop_index = mpoly.loopstart + i;
|
||||
BLI_assert(loop_index < export_mesh_eval_->totloop);
|
||||
BLI_assert(loop_index < export_mesh_->totloop);
|
||||
loop_to_normal_index_[loop_index] = poly_norm_index;
|
||||
}
|
||||
}
|
||||
|
@ -436,8 +432,7 @@ Vector<int> OBJMesh::calc_poly_normal_indices(const int poly_index) const
|
|||
if (loop_to_normal_index_.is_empty()) {
|
||||
return {};
|
||||
}
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const MPoly &mpoly = polys[poly_index];
|
||||
const MPoly &mpoly = mesh_polys_[poly_index];
|
||||
const int totloop = mpoly.totloop;
|
||||
Vector<int> r_poly_normal_indices(totloop);
|
||||
for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) {
|
||||
|
@ -458,19 +453,17 @@ int OBJMesh::tot_deform_groups() const
|
|||
int16_t OBJMesh::get_poly_deform_group_index(const int poly_index,
|
||||
MutableSpan<float> group_weights) const
|
||||
{
|
||||
BLI_assert(poly_index < export_mesh_eval_->totpoly);
|
||||
BLI_assert(poly_index < export_mesh_->totpoly);
|
||||
BLI_assert(group_weights.size() == BKE_object_defgroup_count(&export_object_eval_));
|
||||
const Span<MPoly> polys = export_mesh_eval_->polys();
|
||||
const Span<MLoop> loops = export_mesh_eval_->loops();
|
||||
const Span<MDeformVert> dverts = export_mesh_eval_->deform_verts();
|
||||
const Span<MDeformVert> dverts = export_mesh_->deform_verts();
|
||||
if (dverts.is_empty()) {
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
group_weights.fill(0);
|
||||
bool found_any_group = false;
|
||||
const MPoly &mpoly = polys[poly_index];
|
||||
const MLoop *mloop = &loops[mpoly.loopstart];
|
||||
const MPoly &mpoly = mesh_polys_[poly_index];
|
||||
const MLoop *mloop = &mesh_loops_[mpoly.loopstart];
|
||||
for (int loop_i = 0; loop_i < mpoly.totloop; ++loop_i, ++mloop) {
|
||||
const MDeformVert &dv = dverts[mloop->v];
|
||||
for (int weight_i = 0; weight_i < dv.totweight; ++weight_i) {
|
||||
|
|
|
@ -35,11 +35,15 @@ class OBJMesh : NonCopyable {
|
|||
* sometimes builds an Object in a temporary space that doesn't persist.
|
||||
*/
|
||||
Object export_object_eval_;
|
||||
Mesh *export_mesh_eval_;
|
||||
/**
|
||||
* For curves which are converted to mesh, and triangulated meshes, a new mesh is allocated.
|
||||
*/
|
||||
bool mesh_eval_needs_free_ = false;
|
||||
/** A pointer to #owned_export_mesh_ or the object'ed evaluated/original mesh. */
|
||||
const Mesh *export_mesh_;
|
||||
/** A mesh owned here, if created or modified for the export. May be null. */
|
||||
Mesh *owned_export_mesh_ = nullptr;
|
||||
Span<MVert> mesh_verts_;
|
||||
Span<MEdge> mesh_edges_;
|
||||
Span<MPoly> mesh_polys_;
|
||||
Span<MLoop> mesh_loops_;
|
||||
|
||||
/**
|
||||
* Final transform of an object obtained from export settings (up_axis, forward_axis) and the
|
||||
* object's world transform matrix.
|
||||
|
@ -216,23 +220,19 @@ class OBJMesh : NonCopyable {
|
|||
return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
|
||||
}
|
||||
|
||||
Mesh *get_mesh() const
|
||||
const Mesh *get_mesh() const
|
||||
{
|
||||
return export_mesh_eval_;
|
||||
return export_mesh_;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Override the mesh from the export scene's object. Takes ownership of the mesh. */
|
||||
void set_mesh(Mesh *mesh);
|
||||
/**
|
||||
* Free the mesh if _the exporter_ created it.
|
||||
* Triangulate the mesh pointed to by this object, potentially replacing it with a newly created
|
||||
* mesh.
|
||||
*/
|
||||
void free_mesh_if_needed();
|
||||
/**
|
||||
* Allocate a new Mesh with triangulated polygons.
|
||||
*
|
||||
* The returned mesh can be the same as the old one.
|
||||
* \return Owning pointer to the new Mesh, and whether a new Mesh was created.
|
||||
*/
|
||||
std::pair<Mesh *, bool> triangulate_mesh_eval();
|
||||
void triangulate_mesh_eval();
|
||||
/**
|
||||
* Set the final transform after applying axes settings and an Object's world transform.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue