1204 lines
37 KiB
C++
1204 lines
37 KiB
C++
/*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/** \file
|
|
* \ingroup collada
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
|
|
/* COLLADABU_ASSERT, may be able to remove later */
|
|
#include "COLLADABUPlatform.h"
|
|
|
|
#include "COLLADAFWMeshPrimitive.h"
|
|
#include "COLLADAFWMeshVertexData.h"
|
|
#include "COLLADAFWPolygons.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BKE_customdata.h"
|
|
#include "BKE_displist.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_lib_id.h"
|
|
#include "BKE_material.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_object.h"
|
|
|
|
#include "BLI_edgehash.h"
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_math.h"
|
|
#include "BLI_string.h"
|
|
|
|
#include "ArmatureImporter.h"
|
|
#include "MeshImporter.h"
|
|
#include "collada_utils.h"
|
|
|
|
/* get node name, or fall back to original id if not present (name is optional) */
|
|
template<class T> static std::string bc_get_dae_name(T *node)
|
|
{
|
|
return node->getName().empty() ? node->getOriginalId() : node->getName();
|
|
}
|
|
|
|
static const char *bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type)
|
|
{
|
|
switch (type) {
|
|
case COLLADAFW::MeshPrimitive::LINES:
|
|
return "LINES";
|
|
case COLLADAFW::MeshPrimitive::LINE_STRIPS:
|
|
return "LINESTRIPS";
|
|
case COLLADAFW::MeshPrimitive::POLYGONS:
|
|
return "POLYGONS";
|
|
case COLLADAFW::MeshPrimitive::POLYLIST:
|
|
return "POLYLIST";
|
|
case COLLADAFW::MeshPrimitive::TRIANGLES:
|
|
return "TRIANGLES";
|
|
case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
|
|
return "TRIANGLE_FANS";
|
|
case COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS:
|
|
return "TRIANGLE_STRIPS";
|
|
case COLLADAFW::MeshPrimitive::POINTS:
|
|
return "POINTS";
|
|
case COLLADAFW::MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE:
|
|
return "UNDEFINED_PRIMITIVE_TYPE";
|
|
}
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
static const char *bc_geomTypeToStr(COLLADAFW::Geometry::GeometryType type)
|
|
{
|
|
switch (type) {
|
|
case COLLADAFW::Geometry::GEO_TYPE_MESH:
|
|
return "MESH";
|
|
case COLLADAFW::Geometry::GEO_TYPE_SPLINE:
|
|
return "SPLINE";
|
|
case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH:
|
|
return "CONVEX_MESH";
|
|
case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN:
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
UVDataWrapper::UVDataWrapper(COLLADAFW::MeshVertexData &vdata) : mVData(&vdata)
|
|
{
|
|
}
|
|
|
|
#ifdef COLLADA_DEBUG
|
|
void WVDataWrapper::print()
|
|
{
|
|
fprintf(stderr, "UVs:\n");
|
|
switch (mVData->getType()) {
|
|
case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
|
|
COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
|
|
if (values->getCount()) {
|
|
for (int i = 0; i < values->getCount(); i += 2) {
|
|
fprintf(stderr, "%.1f, %.1f\n", (*values)[i], (*values)[i + 1]);
|
|
}
|
|
}
|
|
} break;
|
|
case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
|
|
COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
|
|
if (values->getCount()) {
|
|
for (int i = 0; i < values->getCount(); i += 2) {
|
|
fprintf(stderr, "%.1f, %.1f\n", (float)(*values)[i], (float)(*values)[i + 1]);
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
#endif
|
|
|
|
void UVDataWrapper::getUV(int uv_index, float *uv)
|
|
{
|
|
int stride = mVData->getStride(0);
|
|
if (stride == 0) {
|
|
stride = 2;
|
|
}
|
|
|
|
switch (mVData->getType()) {
|
|
case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
|
|
COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
|
|
if (values->empty()) {
|
|
return;
|
|
}
|
|
uv[0] = (*values)[uv_index * stride];
|
|
uv[1] = (*values)[uv_index * stride + 1];
|
|
|
|
} break;
|
|
case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
|
|
COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
|
|
if (values->empty()) {
|
|
return;
|
|
}
|
|
uv[0] = (float)(*values)[uv_index * stride];
|
|
uv[1] = (float)(*values)[uv_index * stride + 1];
|
|
|
|
} break;
|
|
case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
|
|
default:
|
|
fprintf(stderr, "MeshImporter.getUV(): unknown data type\n");
|
|
}
|
|
}
|
|
|
|
VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData &vdata) : mVData(&vdata)
|
|
{
|
|
}
|
|
|
|
void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
|
|
{
|
|
int stride = mVData->getStride(0);
|
|
if (stride == 0) {
|
|
stride = 3;
|
|
}
|
|
|
|
switch (mVData->getType()) {
|
|
case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
|
|
COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
|
|
if (values->empty() || values->getCount() <= (v_index * stride + 2)) {
|
|
return; /* xxx need to create an error instead */
|
|
}
|
|
|
|
mloopcol->r = unit_float_to_uchar_clamp((*values)[v_index * stride]);
|
|
mloopcol->g = unit_float_to_uchar_clamp((*values)[v_index * stride + 1]);
|
|
mloopcol->b = unit_float_to_uchar_clamp((*values)[v_index * stride + 2]);
|
|
} break;
|
|
|
|
case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
|
|
COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
|
|
if (values->empty() || values->getCount() <= (v_index * stride + 2)) {
|
|
return; /* xxx need to create an error instead */
|
|
}
|
|
|
|
mloopcol->r = unit_float_to_uchar_clamp((*values)[v_index * stride]);
|
|
mloopcol->g = unit_float_to_uchar_clamp((*values)[v_index * stride + 1]);
|
|
mloopcol->b = unit_float_to_uchar_clamp((*values)[v_index * stride + 2]);
|
|
} break;
|
|
default:
|
|
fprintf(stderr, "VCOLDataWrapper.getvcol(): unknown data type\n");
|
|
}
|
|
}
|
|
|
|
MeshImporter::MeshImporter(
|
|
UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce, ViewLayer *view_layer)
|
|
: unitconverter(unitconv),
|
|
m_bmain(bmain),
|
|
scene(sce),
|
|
view_layer(view_layer),
|
|
armature_importer(arm)
|
|
{
|
|
/* pass */
|
|
}
|
|
|
|
bool MeshImporter::set_poly_indices(
|
|
MPoly *mpoly, MLoop *mloop, int loop_index, const unsigned int *indices, int loop_count)
|
|
{
|
|
mpoly->loopstart = loop_index;
|
|
mpoly->totloop = loop_count;
|
|
bool broken_loop = false;
|
|
for (int index = 0; index < loop_count; index++) {
|
|
|
|
/* Test if loop defines a hole */
|
|
if (!broken_loop) {
|
|
for (int i = 0; i < index; i++) {
|
|
if (indices[i] == indices[index]) {
|
|
/* duplicate index -> not good */
|
|
broken_loop = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
mloop->v = indices[index];
|
|
mloop++;
|
|
}
|
|
return broken_loop;
|
|
}
|
|
|
|
void MeshImporter::set_vcol(MLoopCol *mloopcol,
|
|
VCOLDataWrapper &vob,
|
|
int loop_index,
|
|
COLLADAFW::IndexList &index_list,
|
|
int count)
|
|
{
|
|
int index;
|
|
for (index = 0; index < count; index++, mloopcol++) {
|
|
int v_index = index_list.getIndex(index + loop_index);
|
|
vob.get_vcol(v_index, mloopcol);
|
|
}
|
|
}
|
|
|
|
void MeshImporter::set_face_uv(MLoopUV *mloopuv,
|
|
UVDataWrapper &uvs,
|
|
int start_index,
|
|
COLLADAFW::IndexList &index_list,
|
|
int count)
|
|
{
|
|
/* per face vertex indices, this means for quad we have 4 indices, not 8 */
|
|
COLLADAFW::UIntValuesArray &indices = index_list.getIndices();
|
|
|
|
for (int index = 0; index < count; index++) {
|
|
int uv_index = indices[index + start_index];
|
|
uvs.getUV(uv_index, mloopuv[index].uv);
|
|
}
|
|
}
|
|
|
|
#ifdef COLLADA_DEBUG
|
|
void MeshImporter::print_index_list(COLLADAFW::IndexList &index_list)
|
|
{
|
|
fprintf(stderr, "Index list for \"%s\":\n", index_list.getName().c_str());
|
|
for (int i = 0; i < index_list.getIndicesCount(); i += 2) {
|
|
fprintf(stderr, "%u, %u\n", index_list.getIndex(i), index_list.getIndex(i + 1));
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
#endif
|
|
|
|
/* checks if mesh has supported primitive types: lines, polylist, triangles, triangle_fans */
|
|
bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh)
|
|
{
|
|
COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
|
|
|
|
const std::string &name = bc_get_dae_name(mesh);
|
|
|
|
for (unsigned int i = 0; i < prim_arr.getCount(); i++) {
|
|
|
|
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
|
|
COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType();
|
|
|
|
const char *type_str = bc_primTypeToStr(type);
|
|
|
|
/* OpenCollada passes POLYGONS type for <polylist> */
|
|
if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
|
|
|
|
COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
|
|
COLLADAFW::Polygons::VertexCountArray &vca = mpvc->getGroupedVerticesVertexCountArray();
|
|
|
|
int hole_count = 0;
|
|
int nonface_count = 0;
|
|
|
|
for (unsigned int j = 0; j < vca.getCount(); j++) {
|
|
int count = vca[j];
|
|
if (abs(count) < 3) {
|
|
nonface_count++;
|
|
}
|
|
|
|
if (count < 0) {
|
|
hole_count++;
|
|
}
|
|
}
|
|
|
|
if (hole_count > 0) {
|
|
fprintf(stderr,
|
|
"WARNING: Primitive %s in %s: %d holes not imported (unsupported)\n",
|
|
type_str,
|
|
name.c_str(),
|
|
hole_count);
|
|
}
|
|
|
|
if (nonface_count > 0) {
|
|
fprintf(stderr,
|
|
"WARNING: Primitive %s in %s: %d faces with vertex count < 3 (rejected)\n",
|
|
type_str,
|
|
name.c_str(),
|
|
nonface_count);
|
|
}
|
|
}
|
|
|
|
else if (type == COLLADAFW::MeshPrimitive::LINES) {
|
|
/* TODO: Add Checker for line syntax here */
|
|
}
|
|
|
|
else if (type != COLLADAFW::MeshPrimitive::TRIANGLES &&
|
|
type != COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
|
|
fprintf(stderr, "ERROR: Primitive type %s is not supported.\n", type_str);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
|
|
{
|
|
/* vertices */
|
|
COLLADAFW::MeshVertexData &pos = mesh->getPositions();
|
|
if (pos.empty()) {
|
|
return;
|
|
}
|
|
|
|
int stride = pos.getStride(0);
|
|
if (stride == 0) {
|
|
stride = 3;
|
|
}
|
|
|
|
me->totvert = pos.getFloatValues()->getCount() / stride;
|
|
me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, me->totvert);
|
|
|
|
MVert *mvert;
|
|
int i;
|
|
|
|
for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
|
|
get_vector(mvert->co, pos, i, stride);
|
|
}
|
|
}
|
|
|
|
/* =====================================================================
|
|
* condition 1: The Primitive has normals
|
|
* condition 2: The number of normals equals the number of faces.
|
|
* return true if both conditions apply.
|
|
* return false otherwise.
|
|
* ===================================================================== */
|
|
bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp)
|
|
{
|
|
|
|
bool has_useable_normals = false;
|
|
|
|
int normals_count = mp->getNormalIndices().getCount();
|
|
if (normals_count > 0) {
|
|
int index_count = mp->getPositionIndices().getCount();
|
|
if (index_count == normals_count) {
|
|
has_useable_normals = true;
|
|
}
|
|
else {
|
|
fprintf(stderr,
|
|
"Warning: Number of normals %d is different from the number of vertices %d, "
|
|
"skipping normals\n",
|
|
normals_count,
|
|
index_count);
|
|
}
|
|
}
|
|
|
|
return has_useable_normals;
|
|
}
|
|
|
|
/* =====================================================================
|
|
* Assume that only TRIANGLES, TRIANGLE_FANS, POLYLIST and POLYGONS
|
|
* have faces. (to be verified)
|
|
* ===================================================================== */
|
|
bool MeshImporter::primitive_has_faces(COLLADAFW::MeshPrimitive *mp)
|
|
{
|
|
|
|
bool has_faces = false;
|
|
int type = mp->getPrimitiveType();
|
|
switch (type) {
|
|
case COLLADAFW::MeshPrimitive::TRIANGLES:
|
|
case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
|
|
case COLLADAFW::MeshPrimitive::POLYLIST:
|
|
case COLLADAFW::MeshPrimitive::POLYGONS: {
|
|
has_faces = true;
|
|
break;
|
|
}
|
|
default: {
|
|
has_faces = false;
|
|
break;
|
|
}
|
|
}
|
|
return has_faces;
|
|
}
|
|
|
|
static std::string extract_vcolname(const COLLADAFW::String &collada_id)
|
|
{
|
|
std::string colname = collada_id;
|
|
int spos = colname.find("-mesh-colors-");
|
|
if (spos != std::string::npos) {
|
|
colname = colname.substr(spos + 13);
|
|
}
|
|
return colname;
|
|
}
|
|
|
|
/* =================================================================
|
|
* Return the number of faces by summing up
|
|
* the face-counts of the parts.
|
|
* hint: This is done because `mesh->getFacesCount()` does
|
|
* count loose edges as extra faces, which is not what we want here.
|
|
* ================================================================= */
|
|
void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
|
|
{
|
|
COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
|
|
int total_poly_count = 0;
|
|
int total_loop_count = 0;
|
|
|
|
/* collect edge_count and face_count from all parts */
|
|
for (int i = 0; i < prim_arr.getCount(); i++) {
|
|
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
|
|
int type = mp->getPrimitiveType();
|
|
switch (type) {
|
|
case COLLADAFW::MeshPrimitive::TRIANGLES:
|
|
case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
|
|
case COLLADAFW::MeshPrimitive::POLYLIST:
|
|
case COLLADAFW::MeshPrimitive::POLYGONS: {
|
|
COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
|
|
size_t prim_poly_count = mpvc->getFaceCount();
|
|
|
|
size_t prim_loop_count = 0;
|
|
for (int index = 0; index < prim_poly_count; index++) {
|
|
int vcount = get_vertex_count(mpvc, index);
|
|
if (vcount > 0) {
|
|
prim_loop_count += vcount;
|
|
total_poly_count++;
|
|
}
|
|
else {
|
|
/* TODO: this is a hole and not another polygon! */
|
|
}
|
|
}
|
|
|
|
total_loop_count += prim_loop_count;
|
|
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Add the data containers */
|
|
if (total_poly_count > 0) {
|
|
me->totpoly = total_poly_count;
|
|
me->totloop = total_loop_count;
|
|
me->mpoly = (MPoly *)CustomData_add_layer(
|
|
&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, me->totpoly);
|
|
me->mloop = (MLoop *)CustomData_add_layer(
|
|
&me->ldata, CD_MLOOP, CD_CALLOC, nullptr, me->totloop);
|
|
|
|
unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount();
|
|
for (int i = 0; i < totuvset; i++) {
|
|
if (collada_mesh->getUVCoords().getLength(i) == 0) {
|
|
totuvset = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (totuvset > 0) {
|
|
for (int i = 0; i < totuvset; i++) {
|
|
COLLADAFW::MeshVertexData::InputInfos *info =
|
|
collada_mesh->getUVCoords().getInputInfosArray()[i];
|
|
COLLADAFW::String &uvname = info->mName;
|
|
/* Allocate space for UV_data */
|
|
CustomData_add_layer_named(
|
|
&me->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, me->totloop, uvname.c_str());
|
|
}
|
|
/* activate the first uv map */
|
|
me->mloopuv = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0);
|
|
}
|
|
|
|
int totcolset = collada_mesh->getColors().getInputInfosArray().getCount();
|
|
if (totcolset > 0) {
|
|
for (int i = 0; i < totcolset; i++) {
|
|
COLLADAFW::MeshVertexData::InputInfos *info =
|
|
collada_mesh->getColors().getInputInfosArray()[i];
|
|
COLLADAFW::String colname = extract_vcolname(info->mName);
|
|
CustomData_add_layer_named(
|
|
&me->ldata, CD_MLOOPCOL, CD_DEFAULT, nullptr, me->totloop, colname.c_str());
|
|
}
|
|
me->mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int MeshImporter::get_vertex_count(COLLADAFW::Polygons *mp, int index)
|
|
{
|
|
int type = mp->getPrimitiveType();
|
|
int result;
|
|
switch (type) {
|
|
case COLLADAFW::MeshPrimitive::TRIANGLES:
|
|
case COLLADAFW::MeshPrimitive::TRIANGLE_FANS: {
|
|
result = 3;
|
|
break;
|
|
}
|
|
case COLLADAFW::MeshPrimitive::POLYLIST:
|
|
case COLLADAFW::MeshPrimitive::POLYGONS: {
|
|
result = mp->getGroupedVerticesVertexCountArray()[index];
|
|
break;
|
|
}
|
|
default: {
|
|
result = -1;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh)
|
|
{
|
|
COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
|
|
int loose_edge_count = 0;
|
|
|
|
/* collect edge_count and face_count from all parts */
|
|
for (int i = 0; i < prim_arr.getCount(); i++) {
|
|
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
|
|
int type = mp->getPrimitiveType();
|
|
switch (type) {
|
|
case COLLADAFW::MeshPrimitive::LINES: {
|
|
size_t prim_totface = mp->getFaceCount();
|
|
loose_edge_count += prim_totface;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return loose_edge_count;
|
|
}
|
|
|
|
/* =================================================================
|
|
* This function is copied from source/blender/editors/mesh/mesh_data.c
|
|
*
|
|
* TODO: (As discussed with sergey-) :
|
|
* Maybe move this function to blenderkernel/intern/mesh.c
|
|
* and add definition to BKE_mesh.c
|
|
* ================================================================= */
|
|
void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
|
|
{
|
|
CustomData edata;
|
|
MEdge *medge;
|
|
int totedge;
|
|
|
|
if (len == 0) {
|
|
return;
|
|
}
|
|
|
|
totedge = mesh->totedge + len;
|
|
|
|
/* update customdata */
|
|
CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge);
|
|
CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
|
|
|
|
if (!CustomData_has_layer(&edata, CD_MEDGE)) {
|
|
CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge);
|
|
}
|
|
|
|
CustomData_free(&mesh->edata, mesh->totedge);
|
|
mesh->edata = edata;
|
|
BKE_mesh_update_customdata_pointers(mesh, false); /* new edges don't change tessellation */
|
|
|
|
/* set default flags */
|
|
medge = &mesh->medge[mesh->totedge];
|
|
for (int i = 0; i < len; i++, medge++) {
|
|
medge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT;
|
|
}
|
|
|
|
mesh->totedge = totedge;
|
|
}
|
|
|
|
/* =================================================================
|
|
* Read all loose edges.
|
|
* Important: This function assumes that all edges from existing
|
|
* faces have already been generated and added to me->medge
|
|
* So this function MUST be called after read_faces() (see below)
|
|
* ================================================================= */
|
|
void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
|
|
{
|
|
unsigned int loose_edge_count = get_loose_edge_count(mesh);
|
|
if (loose_edge_count > 0) {
|
|
|
|
unsigned int face_edge_count = me->totedge;
|
|
/* unsigned int total_edge_count = loose_edge_count + face_edge_count; */ /* UNUSED */
|
|
|
|
mesh_add_edges(me, loose_edge_count);
|
|
MEdge *med = me->medge + face_edge_count;
|
|
|
|
COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
|
|
|
|
for (int index = 0; index < prim_arr.getCount(); index++) {
|
|
COLLADAFW::MeshPrimitive *mp = prim_arr[index];
|
|
|
|
int type = mp->getPrimitiveType();
|
|
if (type == COLLADAFW::MeshPrimitive::LINES) {
|
|
unsigned int edge_count = mp->getFaceCount();
|
|
unsigned int *indices = mp->getPositionIndices().getData();
|
|
|
|
for (int j = 0; j < edge_count; j++, med++) {
|
|
med->bweight = 0;
|
|
med->crease = 0;
|
|
med->flag |= ME_LOOSEEDGE;
|
|
med->v1 = indices[2 * j];
|
|
med->v2 = indices[2 * j + 1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* =======================================================================
|
|
* Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
|
|
* Important: This function MUST be called before read_lines()
|
|
* Otherwise we will lose all edges from faces (see read_lines() above)
|
|
*
|
|
* TODO: import uv set names
|
|
* ======================================================================== */
|
|
void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
|
|
{
|
|
unsigned int i;
|
|
|
|
allocate_poly_data(collada_mesh, me);
|
|
|
|
UVDataWrapper uvs(collada_mesh->getUVCoords());
|
|
VCOLDataWrapper vcol(collada_mesh->getColors());
|
|
|
|
MPoly *mpoly = me->mpoly;
|
|
MLoop *mloop = me->mloop;
|
|
int loop_index = 0;
|
|
|
|
MaterialIdPrimitiveArrayMap mat_prim_map;
|
|
|
|
COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
|
|
COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals();
|
|
|
|
for (i = 0; i < prim_arr.getCount(); i++) {
|
|
|
|
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
|
|
|
|
/* faces */
|
|
size_t prim_totpoly = mp->getFaceCount();
|
|
unsigned int *position_indices = mp->getPositionIndices().getData();
|
|
unsigned int *normal_indices = mp->getNormalIndices().getData();
|
|
|
|
bool mp_has_normals = primitive_has_useable_normals(mp);
|
|
bool mp_has_faces = primitive_has_faces(mp);
|
|
|
|
int collada_meshtype = mp->getPrimitiveType();
|
|
|
|
/* since we cannot set mpoly->mat_nr here, we store a portion of me->mpoly in Primitive */
|
|
Primitive prim = {mpoly, 0};
|
|
|
|
/* If MeshPrimitive is TRIANGLE_FANS we split it into triangles
|
|
* The first triangle-fan vertex will be the first vertex in every triangle
|
|
* XXX The proper function of TRIANGLE_FANS is not tested!!!
|
|
* XXX In particular the handling of the normal_indices looks very wrong to me */
|
|
if (collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
|
|
unsigned int grouped_vertex_count = mp->getGroupedVertexElementsCount();
|
|
for (unsigned int group_index = 0; group_index < grouped_vertex_count; group_index++) {
|
|
unsigned int first_vertex = position_indices[0]; /* Store first trifan vertex */
|
|
unsigned int first_normal = normal_indices[0]; /* Store first trifan vertex normal */
|
|
unsigned int vertex_count = mp->getGroupedVerticesVertexCount(group_index);
|
|
|
|
for (unsigned int vertex_index = 0; vertex_index < vertex_count - 2; vertex_index++) {
|
|
/* For each triangle store indices of its 3 vertices */
|
|
unsigned int triangle_vertex_indices[3] = {
|
|
first_vertex, position_indices[1], position_indices[2]};
|
|
set_poly_indices(mpoly, mloop, loop_index, triangle_vertex_indices, 3);
|
|
|
|
if (mp_has_normals) { /* vertex normals, same implementation as for the triangles */
|
|
/* The same for vertices normals. */
|
|
unsigned int vertex_normal_indices[3] = {
|
|
first_normal, normal_indices[1], normal_indices[2]};
|
|
if (!is_flat_face(vertex_normal_indices, nor, 3)) {
|
|
mpoly->flag |= ME_SMOOTH;
|
|
}
|
|
normal_indices++;
|
|
}
|
|
|
|
mpoly++;
|
|
mloop += 3;
|
|
loop_index += 3;
|
|
prim.totpoly++;
|
|
}
|
|
|
|
/* Moving cursor to the next triangle fan. */
|
|
if (mp_has_normals) {
|
|
normal_indices += 2;
|
|
}
|
|
|
|
position_indices += 2;
|
|
}
|
|
}
|
|
|
|
if (collada_meshtype == COLLADAFW::MeshPrimitive::POLYLIST ||
|
|
collada_meshtype == COLLADAFW::MeshPrimitive::POLYGONS ||
|
|
collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLES) {
|
|
COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
|
|
unsigned int start_index = 0;
|
|
|
|
COLLADAFW::IndexListArray &index_list_array_uvcoord = mp->getUVCoordIndicesArray();
|
|
COLLADAFW::IndexListArray &index_list_array_vcolor = mp->getColorIndicesArray();
|
|
|
|
int invalid_loop_holes = 0;
|
|
for (unsigned int j = 0; j < prim_totpoly; j++) {
|
|
|
|
/* Vertices in polygon: */
|
|
int vcount = get_vertex_count(mpvc, j);
|
|
if (vcount < 0) {
|
|
continue; /* TODO: add support for holes */
|
|
}
|
|
|
|
bool broken_loop = set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
|
|
if (broken_loop) {
|
|
invalid_loop_holes += 1;
|
|
}
|
|
|
|
for (unsigned int uvset_index = 0; uvset_index < index_list_array_uvcoord.getCount();
|
|
uvset_index++) {
|
|
/* get mtface by face index and uv set index */
|
|
COLLADAFW::IndexList &index_list = *index_list_array_uvcoord[uvset_index];
|
|
MLoopUV *mloopuv = (MLoopUV *)CustomData_get_layer_named(
|
|
&me->ldata, CD_MLOOPUV, index_list.getName().c_str());
|
|
if (mloopuv == nullptr) {
|
|
fprintf(stderr,
|
|
"Collada import: Mesh [%s] : Unknown reference to TEXCOORD [#%s].\n",
|
|
me->id.name,
|
|
index_list.getName().c_str());
|
|
}
|
|
else {
|
|
set_face_uv(mloopuv + loop_index,
|
|
uvs,
|
|
start_index,
|
|
*index_list_array_uvcoord[uvset_index],
|
|
vcount);
|
|
}
|
|
}
|
|
|
|
if (mp_has_normals) {
|
|
if (!is_flat_face(normal_indices, nor, vcount)) {
|
|
mpoly->flag |= ME_SMOOTH;
|
|
}
|
|
}
|
|
|
|
if (mp->hasColorIndices()) {
|
|
int vcolor_count = index_list_array_vcolor.getCount();
|
|
|
|
for (unsigned int vcolor_index = 0; vcolor_index < vcolor_count; vcolor_index++) {
|
|
|
|
COLLADAFW::IndexList &color_index_list = *mp->getColorIndices(vcolor_index);
|
|
COLLADAFW::String colname = extract_vcolname(color_index_list.getName());
|
|
MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_named(
|
|
&me->ldata, CD_MLOOPCOL, colname.c_str());
|
|
if (mloopcol == nullptr) {
|
|
fprintf(stderr,
|
|
"Collada import: Mesh [%s] : Unknown reference to VCOLOR [#%s].\n",
|
|
me->id.name,
|
|
color_index_list.getName().c_str());
|
|
}
|
|
else {
|
|
set_vcol(mloopcol + loop_index, vcol, start_index, color_index_list, vcount);
|
|
}
|
|
}
|
|
}
|
|
|
|
mpoly++;
|
|
mloop += vcount;
|
|
loop_index += vcount;
|
|
start_index += vcount;
|
|
prim.totpoly++;
|
|
|
|
if (mp_has_normals) {
|
|
normal_indices += vcount;
|
|
}
|
|
|
|
position_indices += vcount;
|
|
}
|
|
|
|
if (invalid_loop_holes > 0) {
|
|
fprintf(stderr,
|
|
"Collada import: Mesh [%s] : contains %d unsupported loops (holes).\n",
|
|
me->id.name,
|
|
invalid_loop_holes);
|
|
}
|
|
}
|
|
|
|
else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) {
|
|
continue; /* read the lines later after all the rest is done */
|
|
}
|
|
|
|
if (mp_has_faces) {
|
|
mat_prim_map[mp->getMaterialId()].push_back(prim);
|
|
}
|
|
}
|
|
|
|
geom_uid_mat_mapping_map[collada_mesh->getUniqueId()] = mat_prim_map;
|
|
}
|
|
|
|
void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData &arr, int i, int stride)
|
|
{
|
|
i *= stride;
|
|
|
|
switch (arr.getType()) {
|
|
case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
|
|
COLLADAFW::ArrayPrimitiveType<float> *values = arr.getFloatValues();
|
|
if (values->empty()) {
|
|
return;
|
|
}
|
|
|
|
v[0] = (*values)[i++];
|
|
v[1] = (*values)[i++];
|
|
if (stride >= 3) {
|
|
v[2] = (*values)[i];
|
|
}
|
|
else {
|
|
v[2] = 0.0f;
|
|
}
|
|
|
|
} break;
|
|
case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
|
|
COLLADAFW::ArrayPrimitiveType<double> *values = arr.getDoubleValues();
|
|
if (values->empty()) {
|
|
return;
|
|
}
|
|
|
|
v[0] = (float)(*values)[i++];
|
|
v[1] = (float)(*values)[i++];
|
|
if (stride >= 3) {
|
|
v[2] = (float)(*values)[i];
|
|
}
|
|
else {
|
|
v[2] = 0.0f;
|
|
}
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool MeshImporter::is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData &nor, int count)
|
|
{
|
|
float a[3], b[3];
|
|
|
|
get_vector(a, nor, *nind, 3);
|
|
normalize_v3(a);
|
|
|
|
nind++;
|
|
|
|
for (int i = 1; i < count; i++, nind++) {
|
|
get_vector(b, nor, *nind, 3);
|
|
normalize_v3(b);
|
|
|
|
float dp = dot_v3v3(a, b);
|
|
|
|
if (dp < 0.99999f || dp > 1.00001f) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Object *MeshImporter::get_object_by_geom_uid(const COLLADAFW::UniqueId &geom_uid)
|
|
{
|
|
if (uid_object_map.find(geom_uid) != uid_object_map.end()) {
|
|
return uid_object_map[geom_uid];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Mesh *MeshImporter::get_mesh_by_geom_uid(const COLLADAFW::UniqueId &geom_uid)
|
|
{
|
|
if (uid_mesh_map.find(geom_uid) != uid_mesh_map.end()) {
|
|
return uid_mesh_map[geom_uid];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::string *MeshImporter::get_geometry_name(const std::string &mesh_name)
|
|
{
|
|
if (this->mesh_geom_map.find(mesh_name) != this->mesh_geom_map.end()) {
|
|
return &this->mesh_geom_map[mesh_name];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/**
|
|
* this function checks if both objects have the same
|
|
* materials assigned to Object (in the same order)
|
|
* returns true if condition matches, otherwise false;
|
|
*/
|
|
static bool bc_has_same_material_configuration(Object *ob1, Object *ob2)
|
|
{
|
|
if (ob1->totcol != ob2->totcol) {
|
|
return false; /* not same number of materials */
|
|
}
|
|
if (ob1->totcol == 0) {
|
|
return false; /* no material at all */
|
|
}
|
|
|
|
for (int index = 0; index < ob1->totcol; index++) {
|
|
if (ob1->matbits[index] != ob2->matbits[index]) {
|
|
return false; /* shouldn't happen */
|
|
}
|
|
if (ob1->matbits[index] == 0) {
|
|
return false; /* shouldn't happen */
|
|
}
|
|
if (ob1->mat[index] != ob2->mat[index]) {
|
|
return false; /* different material assignment */
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Caution here: This code assumes that all materials are assigned to Object
|
|
* and no material is assigned to Data.
|
|
* That is true right after the objects have been imported.
|
|
*
|
|
*/
|
|
static void bc_copy_materials_to_data(Object *ob, Mesh *me)
|
|
{
|
|
for (int index = 0; index < ob->totcol; index++) {
|
|
ob->matbits[index] = 0;
|
|
me->mat[index] = ob->mat[index];
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Remove all references to materials from the object
|
|
*
|
|
*/
|
|
static void bc_remove_materials_from_object(Object *ob, Mesh *me)
|
|
{
|
|
for (int index = 0; index < ob->totcol; index++) {
|
|
ob->matbits[index] = 0;
|
|
ob->mat[index] = nullptr;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the list of Users of the given Mesh object.
|
|
* Note: This function uses the object user flag to control
|
|
* which objects have already been processed.
|
|
*/
|
|
std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh)
|
|
{
|
|
std::vector<Object *> mesh_users;
|
|
for (Object *ob : imported_objects) {
|
|
if (bc_is_marked(ob)) {
|
|
bc_remove_mark(ob);
|
|
Mesh *me = (Mesh *)ob->data;
|
|
if (me == reference_mesh) {
|
|
mesh_users.push_back(ob);
|
|
}
|
|
}
|
|
}
|
|
return mesh_users;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* During import all materials have been assigned to Object.
|
|
* Now we iterate over the imported objects and optimize
|
|
* the assignments as follows:
|
|
*
|
|
* for each imported geometry:
|
|
* if number of users is 1:
|
|
* get the user (object)
|
|
* move the materials from Object to Data
|
|
* else:
|
|
* determine which materials are assigned to the first user
|
|
* check if all other users have the same materials in the same order
|
|
* if the check is positive:
|
|
* Add the materials of the first user to the geometry
|
|
* adjust all other users accordingly.
|
|
*
|
|
*/
|
|
void MeshImporter::optimize_material_assignements()
|
|
{
|
|
for (Object *ob : imported_objects) {
|
|
Mesh *me = (Mesh *)ob->data;
|
|
if (ID_REAL_USERS(&me->id) == 1) {
|
|
bc_copy_materials_to_data(ob, me);
|
|
bc_remove_materials_from_object(ob, me);
|
|
bc_remove_mark(ob);
|
|
}
|
|
else if (ID_REAL_USERS(&me->id) > 1) {
|
|
bool can_move = true;
|
|
std::vector<Object *> mesh_users = get_all_users_of(me);
|
|
if (mesh_users.size() > 1) {
|
|
Object *ref_ob = mesh_users[0];
|
|
for (int index = 1; index < mesh_users.size(); index++) {
|
|
if (!bc_has_same_material_configuration(ref_ob, mesh_users[index])) {
|
|
can_move = false;
|
|
break;
|
|
}
|
|
}
|
|
if (can_move) {
|
|
bc_copy_materials_to_data(ref_ob, me);
|
|
for (Object *object : mesh_users) {
|
|
bc_remove_materials_from_object(object, me);
|
|
bc_remove_mark(object);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* We do not know in advance which objects will share geometries.
|
|
* And we do not know either if the objects which share geometries
|
|
* come along with different materials. So we first create the objects
|
|
* and assign the materials to Object, then in a later cleanup we decide
|
|
* which materials shall be moved to the created geometries. Also see
|
|
* optimize_material_assignements() above.
|
|
*/
|
|
void MeshImporter::assign_material_to_geom(
|
|
COLLADAFW::MaterialBinding cmaterial,
|
|
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
|
|
Object *ob,
|
|
const COLLADAFW::UniqueId *geom_uid,
|
|
short mat_index)
|
|
{
|
|
const COLLADAFW::UniqueId &ma_uid = cmaterial.getReferencedMaterial();
|
|
|
|
/* do we know this material? */
|
|
if (uid_material_map.find(ma_uid) == uid_material_map.end()) {
|
|
|
|
fprintf(stderr, "Cannot find material by UID.\n");
|
|
return;
|
|
}
|
|
|
|
/* first time we get geom_uid, ma_uid pair. Save for later check. */
|
|
materials_mapped_to_geom.insert(
|
|
std::pair<COLLADAFW::UniqueId, COLLADAFW::UniqueId>(*geom_uid, ma_uid));
|
|
|
|
Material *ma = uid_material_map[ma_uid];
|
|
|
|
/* Attention! This temporarily assigns material to object on purpose!
|
|
* See note above. */
|
|
ob->actcol = 0;
|
|
BKE_object_material_assign(m_bmain, ob, ma, mat_index + 1, BKE_MAT_ASSIGN_OBJECT);
|
|
|
|
MaterialIdPrimitiveArrayMap &mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
|
|
COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId();
|
|
|
|
/* assign material indices to mesh faces */
|
|
if (mat_prim_map.find(mat_id) != mat_prim_map.end()) {
|
|
|
|
std::vector<Primitive> &prims = mat_prim_map[mat_id];
|
|
|
|
std::vector<Primitive>::iterator it;
|
|
|
|
for (it = prims.begin(); it != prims.end(); it++) {
|
|
Primitive &prim = *it;
|
|
MPoly *mpoly = prim.mpoly;
|
|
|
|
for (int i = 0; i < prim.totpoly; i++, mpoly++) {
|
|
mpoly->mat_nr = mat_index;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Object *MeshImporter::create_mesh_object(
|
|
COLLADAFW::Node *node,
|
|
COLLADAFW::InstanceGeometry *geom,
|
|
bool isController,
|
|
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map)
|
|
{
|
|
const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId();
|
|
|
|
/* check if node instantiates controller or geometry */
|
|
if (isController) {
|
|
|
|
geom_uid = armature_importer->get_geometry_uid(*geom_uid);
|
|
|
|
if (!geom_uid) {
|
|
fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n");
|
|
return nullptr;
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) {
|
|
/* this could happen if a mesh was not created
|
|
* (e.g. if it contains unsupported geometry) */
|
|
fprintf(stderr, "Couldn't find a mesh by UID.\n");
|
|
return nullptr;
|
|
}
|
|
}
|
|
if (!uid_mesh_map[*geom_uid]) {
|
|
return nullptr;
|
|
}
|
|
|
|
/* name Object */
|
|
const std::string &id = node->getName().empty() ? node->getOriginalId() : node->getName();
|
|
const char *name = (id.length()) ? id.c_str() : nullptr;
|
|
|
|
/* add object */
|
|
Object *ob = bc_add_object(m_bmain, scene, view_layer, OB_MESH, name);
|
|
bc_set_mark(ob); /* used later for material assignment optimization */
|
|
|
|
/* store object pointer for ArmatureImporter */
|
|
uid_object_map[*geom_uid] = ob;
|
|
imported_objects.push_back(ob);
|
|
|
|
/* replace ob->data freeing the old one */
|
|
Mesh *old_mesh = (Mesh *)ob->data;
|
|
Mesh *new_mesh = uid_mesh_map[*geom_uid];
|
|
|
|
BKE_mesh_assign_object(m_bmain, ob, new_mesh);
|
|
BKE_mesh_calc_normals(new_mesh);
|
|
|
|
/* Because BKE_mesh_assign_object would have already decreased it... */
|
|
id_us_plus(&old_mesh->id);
|
|
|
|
BKE_id_free_us(m_bmain, old_mesh);
|
|
|
|
COLLADAFW::MaterialBindingArray &mat_array = geom->getMaterialBindings();
|
|
|
|
/* loop through geom's materials */
|
|
for (unsigned int i = 0; i < mat_array.getCount(); i++) {
|
|
|
|
if (mat_array[i].getReferencedMaterial().isValid()) {
|
|
assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid, i);
|
|
}
|
|
else {
|
|
fprintf(stderr, "invalid referenced material for %s\n", mat_array[i].getName().c_str());
|
|
}
|
|
}
|
|
|
|
/* clean up the mesh */
|
|
BKE_mesh_validate((Mesh *)ob->data, false, false);
|
|
|
|
return ob;
|
|
}
|
|
|
|
/* create a mesh storing a pointer in a map so it can be retrieved later by geometry UID */
|
|
bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
|
|
{
|
|
|
|
if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) {
|
|
/* TODO: report warning */
|
|
fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType()));
|
|
return true;
|
|
}
|
|
|
|
COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh *)geom;
|
|
|
|
if (!is_nice_mesh(mesh)) {
|
|
fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh).c_str());
|
|
return true;
|
|
}
|
|
|
|
const std::string &str_geom_id = mesh->getName().empty() ? mesh->getOriginalId() :
|
|
mesh->getName();
|
|
Mesh *me = BKE_mesh_add(m_bmain, (char *)str_geom_id.c_str());
|
|
id_us_min(&me->id); /* is already 1 here, but will be set later in BKE_mesh_assign_object */
|
|
|
|
/* store the Mesh pointer to link it later with an Object
|
|
* mesh_geom_map needed to map mesh to its geometry name (for shape key naming) */
|
|
this->uid_mesh_map[mesh->getUniqueId()] = me;
|
|
this->mesh_geom_map[std::string(me->id.name)] = str_geom_id;
|
|
|
|
read_vertices(mesh, me);
|
|
read_polys(mesh, me);
|
|
BKE_mesh_calc_edges(me, false, false);
|
|
/* read_lines() must be called after the face edges have been generated.
|
|
* Otherwise the loose edges will be silently deleted again. */
|
|
read_lines(mesh, me);
|
|
|
|
return true;
|
|
}
|