diff --git a/Plugin/abci/Importer/AlembicImporter.cpp b/Plugin/abci/Importer/AlembicImporter.cpp index 7fb25bd91..412012dd2 100644 --- a/Plugin/abci/Importer/AlembicImporter.cpp +++ b/Plugin/abci/Importer/AlembicImporter.cpp @@ -257,7 +257,7 @@ abciAPI void aiPolyMeshGetSampleSummary(aiPolyMeshSample* sample, aiMeshSampleSu { if (sample) { - sample->getSummary(forceRefresh, *summary); + sample->getSummary(forceRefresh, *summary, sample); } } @@ -298,7 +298,7 @@ abciAPI void aiPolyMeshFillVertexBuffer(aiPolyMeshSample* sample, int splitIndex abciAPI int aiPolyMeshPrepareSubmeshes(aiPolyMeshSample* sample, const aiFacesets* facesets) { - return (sample ? sample->prepareSubmeshes(*facesets) : 0); + return (sample ? sample->prepareSubmeshes(sample, *facesets) : 0); } abciAPI int aiPolyMeshGetSplitSubmeshCount(aiPolyMeshSample* sample, int splitIndex) diff --git a/Plugin/abci/Importer/AlembicImporter.h b/Plugin/abci/Importer/AlembicImporter.h index b87f5440a..e8a8d9945 100644 --- a/Plugin/abci/Importer/AlembicImporter.h +++ b/Plugin/abci/Importer/AlembicImporter.h @@ -113,6 +113,7 @@ struct aiConfig bool useThreads = true; int32_t cacheSamples = 0; bool submeshPerUVTile = true; + bool shareVertices = false; }; struct aiTimeSamplingData diff --git a/Plugin/abci/Importer/aiPolyMesh.cpp b/Plugin/abci/Importer/aiPolyMesh.cpp index 95e71893a..c82596ebf 100644 --- a/Plugin/abci/Importer/aiPolyMesh.cpp +++ b/Plugin/abci/Importer/aiPolyMesh.cpp @@ -1,1807 +1,2135 @@ -#include "pch.h" -#include "aiInternal.h" -#include "aiContext.h" -#include "aiObject.h" -#include "aiSchema.h" -#include "aiPolyMesh.h" - -// --- - -static inline int CalculateTriangulatedIndexCount(Abc::Int32ArraySample &counts) -{ - int r = 0; - size_t n = counts.size(); - for (size_t fi = 0; fi < n; ++fi) - { - int ngon = counts[fi]; - r += (ngon - 2) * 3; - } - return r; -} - -// --- - -Topology::Topology() - : m_triangulatedIndexCount(0) - , m_tangentsCount(0) -{ - m_indices.reset(); - m_counts.reset(); -} - -Topology::~Topology() -{ -} - -void Topology::clear() -{ - aiLogger::Info("Topology::clear()"); - m_indices.reset(); - m_counts.reset(); - - m_tangentIndices.clear(); - m_tangentsCount = 0; - - m_submeshes.clear(); - m_faceSplitIndices.clear(); - m_splits.clear(); -} - -int Topology::getTriangulatedIndexCount() const -{ - return m_triangulatedIndexCount; -} - -int Topology::getSplitCount() const -{ - return (int) m_splits.size(); -} - -int Topology::getSplitCount(bool forceRefresh) -{ - if (m_counts && m_indices) - { - if (m_faceSplitIndices.size() != m_counts->size() || forceRefresh) - { - updateSplits(); - } - } - else - { - m_splits.clear(); - m_faceSplitIndices.clear(); - } - - return (int) m_splits.size(); -} - -void Topology::updateSplits() -{ - DebugLog("Topology::updateSplits()"); - - int splitIndex = 0; - size_t indexOffset = 0; - size_t ncounts = m_counts->size(); - - m_faceSplitIndices.resize(ncounts); - - m_splits.clear(); - m_splits.reserve(1 + m_indices->size() / 65000); - m_splits.push_back(SplitInfo()); - - SplitInfo *curSplit = &(m_splits.back()); - - for (size_t i=0; iget()[i]; - - if (curSplit->vertexCount + nv > 65000) - { - m_splits.push_back(SplitInfo(i, indexOffset)); - - ++splitIndex; - - curSplit = &(m_splits.back()); - } - - m_faceSplitIndices[i] = splitIndex; - - curSplit->lastFace = i; - curSplit->vertexCount += nv; - - indexOffset += nv; - } -} - -int Topology::getVertexBufferLength(int splitIndex) const -{ - if (splitIndex < 0 || size_t(splitIndex) >= m_splits.size()) - { - return 0; - } - else - { - return (int) m_splits[splitIndex].vertexCount; - } -} - -int Topology::prepareSubmeshes(const AbcGeom::IV2fGeomParam::Sample &uvs, - const aiFacesets &inFacesets, - bool submeshPerUVTile) -{ - DebugLog("Topology::prepareSubmeshes()"); - - Facesets facesets; - std::vector facesetIndices; // index -> face table - - - m_submeshes.clear(); - - if (inFacesets.count > 0) - { - int index_count = 0; - int max_index = 0; - { - int n = inFacesets.count; - for (int i = 0; i < n; ++i) - { - int ngon = inFacesets.faceCounts[i]; - for (int j = 0; j < ngon; ++j) - { - max_index = std::max(max_index, inFacesets.faceIndices[index_count++]); - } - } - } - facesetIndices.resize(max_index, -1); - - - size_t index = 0; - int defaultFacesetIndex = -1; - - facesets.resize(inFacesets.count); - - for (int i=0; isize(), -1); - for (size_t i=0; isize(); ++i) - { - if (facesetIndices[i] == -1) { - facesetIndices[i] = defaultFacesetIndex; - } - } - } - } - else - { - facesetIndices.resize(m_counts->size(), -1); - - // don't even fill faceset if we have no UVs to tile split the mesh - if (uvs.valid() && submeshPerUVTile) - { - facesets.resize(1); - Faceset &faceset = facesets.front(); - - for (size_t i=0; isize(); ++i) - { - faceset.push_back(i); - } - } - } - - int nsplits = getSplitCount(false); - - if (facesets.empty() && nsplits == 1) - { - // no facesets, no uvs, no splits - m_submeshes.push_back(Submesh()); - - Submesh &submesh = m_submeshes.back(); - - for (size_t i=0; isize(); ++i) - { - submesh.triangleCount += (m_counts->get()[i] - 2); - } - - m_splits[0].submeshCount = 1; - } - else - { - int vertexIndex = 0; - Submesh *curMesh = 0; - const Util::uint32_t *uvIndices = 0; - const abcV2 *uvValues = 0; - - if (uvs.valid() && submeshPerUVTile) - { - uvValues = uvs.getVals()->get(); - uvIndices = uvs.getIndices()->get(); - } - - std::map submeshIndices; - - std::vector splitSubmeshIndices(nsplits, 0); - - for (size_t i=0; isize(); ++i) - { - int nv = m_counts->get()[i]; - - if (nv == 0) - { - continue; - } - - int facesetIndex = facesetIndices[i]; - int splitIndex = m_faceSplitIndices[i]; - - SplitInfo &split = m_splits[splitIndex]; - - // Compute submesh ID based on face's average UV coordinate and it faceset index - float uAcc = 0.0f; - float vAcc = 0.0f; - float invNv = 1.0f / float(nv); - - if (uvValues) - { - for (int j=0; jindex = splitSubmeshIndices[splitIndex]++; - curMesh->vertexIndices.reserve(m_indices->size()); - - split.submeshCount = splitSubmeshIndices[splitIndex]; - } - else - { - curMesh = &(m_submeshes[submeshIndexIt->second]); - } - - curMesh->faces.push_back(i); - curMesh->triangleCount += (nv - 2); - - for (int j=0; jvertexIndices.push_back(vertexIndex - int(split.indexOffset)); - } - } - - for (size_t i=0; i= m_splits.size()) - { - return 0; - } - else - { - return (int) m_splits[splitIndex].submeshCount; - } -} - -// --- - -aiPolyMeshSample::aiPolyMeshSample(aiPolyMesh *schema, Topology *topo, bool ownTopo) - : super(schema) - , m_topology(topo) - , m_ownTopology(ownTopo) -{ -} - -aiPolyMeshSample::~aiPolyMeshSample() -{ - if (m_topology && m_ownTopology) - { - delete m_topology; - } -} - -bool aiPolyMeshSample::hasNormals() const -{ - switch (m_config.normalsMode) - { - case aiNormalsMode::ReadFromFile: - return m_normals.valid(); - break; - case aiNormalsMode::Ignore: - return false; - break; - default: - return (m_normals.valid() || !m_smoothNormals.empty()); - } -} - -bool aiPolyMeshSample::hasUVs() const -{ - return m_uvs.valid(); -} - -bool aiPolyMeshSample::hasTangents() const -{ - return (m_config.tangentsMode != aiTangentsMode::None && hasUVs() && !m_tangents.empty() && !m_topology->m_tangentIndices.empty()); -} - -bool aiPolyMeshSample::smoothNormalsRequired() const -{ - return (m_config.normalsMode == aiNormalsMode::AlwaysCompute || - m_config.tangentsMode == aiTangentsMode::Smooth || - (!m_normals.valid() && m_config.normalsMode == aiNormalsMode::ComputeIfMissing)); -} - -bool aiPolyMeshSample::tangentsRequired() const -{ - return (m_config.tangentsMode != aiTangentsMode::None); -} - -void aiPolyMeshSample::computeSmoothNormals(const aiConfig &config) -{ - aiLogger::Info("%s: Compute smooth normals", getSchema()->getObject()->getFullName()); - - size_t smoothNormalsCount = m_positions->size(); - m_smoothNormals.resize(smoothNormalsCount); - // sadly, memset() is way faster than std::fill() on VC - memset(&m_smoothNormals[0], 0, sizeof(m_smoothNormals[0])*m_smoothNormals.size()); - - - const auto &counts = *(m_topology->m_counts); - const auto &indices = *(m_topology->m_indices); - const auto &positions = *m_positions; - - size_t nf = counts.size(); - size_t off = 0; - bool ccw = config.swapFaceWinding; - int ti1 = ccw ? 2 : 1; - int ti2 = ccw ? 1 : 2; - abcV3 N, dP1, dP2; - - for (size_t f=0; f= 3) - { - // Compute average normal for current face - N.setValue(0.0f, 0.0f, 0.0f); - - const abcV3 &P0 = positions[indices[off]]; - - for (int fv=0; fv 3) - { - N.normalize(); - } - - // Accumulate for all vertices participating to this face - for (int fv=0; fvgetObject()->getFullName()); - - const auto &counts = *(m_topology->m_counts); - const auto &indices = *(m_topology->m_indices); - const auto &uvVals = *(m_uvs.getVals()); - const auto &uvIdxs = *(m_uvs.getIndices()); - const Util::uint32_t *Nidxs = (indexedNormals ? m_normals.getIndices()->get() : 0); - - size_t tangentIndicesCount = indices.size(); - m_topology->m_tangentIndices.resize(tangentIndicesCount); - - if (config.tangentsMode == aiTangentsMode::Smooth) - { - for (size_t i=0; im_tangentIndices[i] = indices[i]; - } - - m_topology->m_tangentsCount = m_positions->size(); - } - else - { - TangentIndexMap uniqueIndices; - TangentIndexMap::iterator it; - - size_t nf = counts.size(); - - for (size_t f=0, v=0; fm_tangentIndices[v] = idx; - uniqueIndices[key] = idx; - } - else - { - m_topology->m_tangentIndices[v] = it->second; - } - } - } - - m_topology->m_tangentsCount = uniqueIndices.size(); - } - - aiLogger::Info("%lu unique tangent(s)", m_topology->m_tangentsCount); -} - -void aiPolyMeshSample::computeTangents(const aiConfig &config, const abcV3 *inN, bool indexedNormals) -{ - aiLogger::Info("%s: Compute %stangents", getSchema()->getObject()->getFullName(), (config.tangentsMode == aiTangentsMode::Smooth ? "smooth " : "")); - - const auto &counts = *(m_topology->m_counts); - const auto &indices = *(m_topology->m_indices); - const auto &positions = *m_positions; - const auto &uvVals = *(m_uvs.getVals()); - const auto &uvIdxs = *(m_uvs.getIndices()); - const Util::uint32_t *Nidxs = (indexedNormals ? m_normals.getIndices()->get() : 0); - - size_t nf = counts.size(); - size_t off = 0; - bool ccw = config.swapFaceWinding; - int ti1 = (ccw ? 2 : 1); - int ti2 = (ccw ? 1 : 2); - - size_t tangentsCount = m_topology->m_tangentsCount; - m_tangents.resize(tangentsCount); - memset(&m_tangents[0], 0, sizeof(m_tangents[0])*m_tangents.size()); - - - abcV3 *tan1 = new Abc::V3f[2 * tangentsCount]; - abcV3 *tan2 = tan1 + tangentsCount; - int *tanNidxs = new int[tangentsCount]; - abcV3 T, B, dP1, dP2, tmp; - abcV2 dUV1, dUV2; - - for (size_t f=0; f= 3) - { - // reset face tangent and bitangent - T.setValue(0.0f, 0.0f, 0.0f); - B.setValue(0.0f, 0.0f, 0.0f); - - const abcV3 &P0 = positions[indices[off]]; - const abcV2 &UV0 = uvVals[uvIdxs[off]]; - - // for each triangle making up current polygon - for (int fv=0; fv 3) - { - T.normalize(); - B.normalize(); - } - - // accumulate normals, tangent and bitangent for each vertex - for (int fv=0; fvm_tangentIndices[off + fv]; - tan1[v] += T; - tan2[v] += B; - tanNidxs[v] = (Nidxs ? Nidxs[off + fv] : indices[off + fv]); - } - } - - off += nfv; - } - - // compute final tangent space for each point - for (size_t i=0; igetObject()->getFullName()); - m_smoothNormals.clear(); - dataChanged = true; - } - } - - bool tangentsRequired = (m_uvs.valid() && config.tangentsMode != aiTangentsMode::None); - - if (tangentsRequired) - { - bool tangentsModeChanged = (config.tangentsMode != m_config.tangentsMode); - - const abcV3 *N = 0; - bool Nindexed = false; - - if (smoothNormalsRequired) - { - N = &m_smoothNormals[0]; - } - else if (m_normals.valid()) - { - N = m_normals.getVals()->get(); - Nindexed = (m_normals.getScope() == AbcGeom::kFacevaryingScope); - } - - if (N) - { - // do not compute indices if they are cached, constant topology and valid - if (m_topology->m_tangentIndices.empty() || - !config.cacheTangentsSplits || - tangentsModeChanged) - { - computeTangentIndices(config, N, Nindexed); - } - if (m_tangents.empty() || - tangentsModeChanged || - topoChanged) - { - computeTangents(config, N, Nindexed); - dataChanged = true; - } - } - else - { - tangentsRequired = false; - } - } - - if (!tangentsRequired) - { - if (!m_tangents.empty()) - { - aiLogger::Info("%s: Clear tangents", getSchema()->getObject()->getFullName()); - - m_tangents.clear(); - dataChanged = true; - } - - if (!m_topology->m_tangentIndices.empty() && (m_ownTopology || !config.cacheTangentsSplits)) - { - aiLogger::Info("%s: Clear tangent indices", getSchema()->getObject()->getFullName()); - - m_topology->m_tangentIndices.clear(); - m_topology->m_tangentsCount = 0; - } - } - - if (topoChanged) - { - dataChanged = true; - } - - m_config = config; -} - -void aiPolyMeshSample::getSummary(bool forceRefresh, aiMeshSampleSummary &summary) const -{ - DebugLog("aiPolyMeshSample::getSummary(forceRefresh=%s)", forceRefresh ? "true" : "false"); - - summary.splitCount = m_topology->getSplitCount(forceRefresh); - - summary.hasNormals = hasNormals(); - - summary.hasUVs = hasUVs(); - - summary.hasTangents = hasTangents(); -} - - -void aiPolyMeshSample::getDataPointer(aiPolyMeshData &dst) -{ - if (m_positions) { - dst.positionCount = m_positions->valid() ? (int)m_positions->size() : 0; - dst.positions = (abcV3*)(m_positions->get()); - } - - if (m_velocities) { - dst.velocities = m_velocities->valid() ? (abcV3*)m_velocities->get() : nullptr; - } - - if (m_normals) { - dst.normalCount = (int)m_normals.getVals()->size(); - dst.normals = (abcV3*)m_normals.getVals()->get(); - dst.normalIndexCount = m_normals.isIndexed() ? (int)m_normals.getIndices()->size() : 0; - if (dst.normalIndexCount) { - dst.normalIndices = (int*)m_normals.getIndices()->get(); - } - } - - if (m_uvs) { - dst.uvCount = (int)m_uvs.getVals()->size(); - dst.uvs = (abcV2*)m_uvs.getVals()->get(); - dst.uvIndexCount = m_uvs.isIndexed() ? (int)m_uvs.getIndices()->size() : 0; - if (dst.uvIndexCount) { - dst.uvIndices = (int*)m_uvs.getIndices()->get(); - } - } - - if (m_topology) { - if (m_topology->m_indices) { - dst.indexCount = (int)m_topology->m_indices->size(); - dst.indices = (int*)m_topology->m_indices->get(); - } - if (m_topology->m_counts) { - dst.faceCount = (int)m_topology->m_counts->size(); - dst.faces = (int*)m_topology->m_counts->get(); - dst.triangulatedIndexCount = m_topology->m_triangulatedIndexCount; - } - } - - dst.center = m_bounds.center(); - dst.size = m_bounds.size(); -} - - -static inline void SwapHandedness(aiPolyMeshData &dst) -{ - auto body = [&](abcV3 *v, int n) { - if (v) { - for (int i = 0; i < n; ++i) { v[i].x *= -1.0f; } - } - }; - body(dst.positions, dst.positionCount); - body(dst.velocities, dst.positionCount); - body(dst.normals, dst.normalCount); -} - -// return true if position and uv / normal indices are deferent -static inline bool IsIndicesDivergent(const aiPolyMeshData &dst) -{ - if ((dst.normalCount != 0 && dst.positionCount != dst.normalCount) || - (dst.uvCount != 0 && dst.positionCount != dst.uvCount)) - { - return true; - } - - // maybe more detailed (=very slow) comparison is needed.. - return false; -} - -static inline void TriangulateIndices(aiPolyMeshData& src, int *dv, const int *indices, bool swap_face) -{ - if (!dv) { return; } - - const int i1 = swap_face ? 2 : 1; - const int i2 = swap_face ? 1 : 2; - - int n = 0; - int i = 0; - if (indices) { - for (int fi = 0; fi < src.faceCount; ++fi) { - int ngon = src.faces[fi]; - for (int ni = 0; ni < ngon - 2; ++ni) { - dv[i + 0] = indices[n + 0]; - dv[i + 1] = indices[n + ni + i1]; - dv[i + 2] = indices[n + ni + i2]; - i += 3; - } - n += ngon; - } - } - else { - for (int fi = 0; fi < src.faceCount; ++fi) { - int ngon = src.faces[fi]; - for (int ni = 0; ni < ngon - 2; ++ni) { - dv[i + 0] = n + 0; - dv[i + 1] = n + ni + i1; - dv[i + 2] = n + ni + i2; - i += 3; - } - n += ngon; - } - } -} - -template -static inline void ExpandWithTriangulation(aiPolyMeshData& src, T *dv, const T *sv, const int *indices, bool swap_face) -{ - if (!dv || !sv) { return; } - - const int i1 = swap_face ? 2 : 1; - const int i2 = swap_face ? 1 : 2; - - int n = 0; - int i = 0; - if (indices) { - for (int fi = 0; fi < src.faceCount; ++fi) { - int ngon = src.faces[fi]; - for (int ni = 0; ni < ngon - 2; ++ni) { - dv[i + 0] = sv[indices[n + 0]]; - dv[i + 1] = sv[indices[n + ni + i1]]; - dv[i + 2] = sv[indices[n + ni + i2]]; - i += 3; - } - n += ngon; - } - } - else { - for (int fi = 0; fi < src.faceCount; ++fi) { - int ngon = src.faces[fi]; - for (int ni = 0; ni < ngon - 2; ++ni) { - dv[i + 0] = sv[n + 0]; - dv[i + 1] = sv[n + ni + i1]; - dv[i + 2] = sv[n + ni + i2]; - i += 3; - } - n += ngon; - } - } -} - -void aiPolyMeshSample::copyData(aiPolyMeshData &dst) -{ - aiPolyMeshData src; - getDataPointer(src); - - // sadly, memcpy() is way faster than std::copy() on VC - - if (src.faces && dst.faces && dst.faceCount >= src.faceCount) { - memcpy(dst.faces, src.faces, src.faceCount * sizeof(*dst.faces)); - dst.faceCount = src.faceCount; - } - else { - dst.faceCount = 0; - } - - if (src.positions && dst.positions && dst.positionCount >= src.positionCount) { - memcpy(dst.positions, src.positions, src.positionCount * sizeof(*dst.positions)); - dst.positionCount = src.positionCount; - } - else { - dst.positionCount = 0; - } - - if (src.velocities && dst.velocities && dst.positionCount >= src.positionCount) { - memcpy(dst.velocities, src.velocities, src.positionCount * sizeof(*dst.velocities)); - } - - if (src.normals && dst.normals && dst.normalCount >= src.normalCount) { - memcpy(dst.normals, src.normals, src.normalCount * sizeof(*dst.normals)); - dst.normalCount = src.normalCount; - } - else { - dst.normalCount = 0; - } - - if (src.uvs && dst.uvs && dst.uvCount >= src.uvCount) { - memcpy(dst.uvs, src.uvs, src.uvCount * sizeof(*dst.uvs)); - dst.uvCount = src.uvCount; - } - else { - dst.uvCount = 0; - } - - if (m_config.swapHandedness) { - SwapHandedness(dst); - } - - - auto copy_indices = [&](int *d, const int *s, int n) { - // swap faces if needed - if (m_config.swapFaceWinding) { - int i = 0; - for (int fi = 0; fi < src.faceCount; ++fi) { - int ngon = src.faces[i]; - for (int ni = 0; ni < ngon; ++ni) { - int ini = ngon - ni - 1; - d[i + ni] = s[i + ini]; - } - i += ngon; - } - } - else { - memcpy(d, s, n * sizeof(int)); - } - }; - - if (src.indices && dst.indices && dst.indexCount >= src.indexCount) { - copy_indices(dst.indices, src.indices, src.indexCount); - dst.indexCount = src.indexCount; - } - if (src.normalIndices && dst.normalIndices && dst.normalIndexCount >= src.normalIndexCount) { - copy_indices(dst.normalIndices, src.normalIndices, src.normalIndexCount); - dst.normalIndexCount = src.normalIndexCount; - } - if (src.uvIndices && dst.uvIndices && dst.uvIndexCount >= src.uvIndexCount) { - copy_indices(dst.uvIndices, src.uvIndices, src.uvIndexCount); - dst.uvIndexCount = src.uvIndexCount; - } - - dst.center = dst.center; - dst.size = dst.size; -} - - -void aiPolyMeshSample::copyDataWithTriangulation(aiPolyMeshData &dst, bool always_expand_indices) -{ - aiPolyMeshData src; - getDataPointer(src); - - bool needs_expand = IsIndicesDivergent(src) || always_expand_indices; - - // triangulated mesh has one index buffer - dst.normalIndices = nullptr; - dst.normalIndexCount = 0; - dst.uvIndices = nullptr; - dst.uvIndexCount = 0; - - // todo: generate normals and tangents if required - - if (needs_expand) { - if (src.positions && dst.positions && dst.positionCount >= src.triangulatedIndexCount) { - ExpandWithTriangulation(src, dst.positions, src.positions, src.indices, m_config.swapFaceWinding); - dst.positionCount = src.triangulatedIndexCount; - } - else { - dst.positionCount = 0; - } - - if (src.velocities && dst.velocities && dst.positionCount >= src.triangulatedIndexCount) { - ExpandWithTriangulation(src, dst.velocities, src.velocities, src.indices, m_config.swapFaceWinding); - } - - if (src.normals && dst.normals && dst.normalCount >= src.triangulatedIndexCount) { - ExpandWithTriangulation(src, dst.normals, src.normals, src.normalIndices, m_config.swapFaceWinding); - dst.normalCount = src.triangulatedIndexCount; - } - else { - dst.normalCount = 0; - } - - if (src.uvs && dst.uvs && dst.uvCount >= src.triangulatedIndexCount) { - ExpandWithTriangulation(src, dst.uvs, src.uvs, src.uvIndices, m_config.swapFaceWinding); - dst.uvCount = src.triangulatedIndexCount; - } - else { - dst.uvCount = 0; - } - - if (dst.indices && dst.indexCount >= src.triangulatedIndexCount) { - for (int i = 0; i < src.triangulatedIndexCount; ++i) { - dst.indices[i] = i; - } - } - } - else { - int *indices = dst.indices; - dst.indices = nullptr; // skip needless copy - copyData(dst); - dst.indices = indices; - TriangulateIndices(src, dst.indices, src.indices, m_config.swapFaceWinding); - } - - { - dst.triangulatedIndexCount = src.triangulatedIndexCount; - int num_triangles = src.triangulatedIndexCount / 3; - if (dst.faces && dst.faceCount >= num_triangles) { - std::fill(dst.faces, dst.faces + num_triangles, 3); - dst.faceCount = num_triangles; - } - else { - dst.faceCount = 0; - } - } - - dst.center = dst.center; - dst.size = dst.size; -} - - -int aiPolyMeshSample::getVertexBufferLength(int splitIndex) const -{ - DebugLog("aiPolyMeshSample::getVertexBufferLength(splitIndex=%d)", splitIndex); - - return m_topology->getVertexBufferLength(splitIndex); -} - -void aiPolyMeshSample::fillVertexBuffer(int splitIndex, aiPolyMeshData &data) -{ - DebugLog("aiPolyMeshSample::fillVertexBuffer(splitIndex=%d)", splitIndex); - - if (splitIndex < 0 || size_t(splitIndex) >= m_topology->m_splits.size() || m_topology->m_splits[splitIndex].vertexCount == 0) - { - return; - } - - bool copyNormals = (hasNormals() && data.normals); - bool copyUvs = (hasUVs() && data.uvs); - bool copyTangents = (hasTangents() && data.tangents); - - bool useAbcNormals = (m_normals.valid() && (m_config.normalsMode == aiNormalsMode::ReadFromFile || m_config.normalsMode == aiNormalsMode::ComputeIfMissing)); - float xScale = (m_config.swapHandedness ? -1.0f : 1.0f); - - const SplitInfo &split = m_topology->m_splits[splitIndex]; - const auto &counts = *(m_topology->m_counts); - const auto &indices = *(m_topology->m_indices); - const auto &positions = *m_positions; - - size_t k = 0; - size_t o = split.indexOffset; - - // reset unused data arrays - - if (data.normals && !copyNormals) - { - aiLogger::Info("%s: Reset normals", getSchema()->getObject()->getFullName()); - memset(data.normals, 0, split.vertexCount * sizeof(abcV3)); - } - - if (data.uvs && !copyUvs) - { - aiLogger::Info("%s: Reset UVs", getSchema()->getObject()->getFullName()); - memset(data.uvs, 0, split.vertexCount * sizeof(abcV2)); - } - - if (data.tangents && !copyTangents) - { - aiLogger::Info("%s: Reset tangents", getSchema()->getObject()->getFullName()); - memset(data.tangents, 0, split.vertexCount * sizeof(abcV4)); - } - - abcV3 bbmin = positions[indices[o]]; - abcV3 bbmax = bbmin; - -#define UPDATE_POSITIONS_AND_BOUNDS(srcIdx, dstIdx) \ - abcV3 &cP = data.positions[dstIdx]; \ - cP = positions[srcIdx]; \ - cP.x *= xScale; \ - if (cP.x < bbmin.x) bbmin.x = cP.x; \ - else if (cP.x > bbmax.x) bbmax.x = cP.x; \ - if (cP.y < bbmin.y) bbmin.y = cP.y; \ - else if (cP.y > bbmax.y) bbmax.y = cP.y; \ - if (cP.z < bbmin.z) bbmin.z = cP.z; \ - else if (cP.z > bbmax.z) bbmax.z = cP.z - - - // fill data arrays - - if (copyNormals) - { - if (useAbcNormals) - { - const auto &normals = *(m_normals.getVals()); - - if (m_normals.getScope() == AbcGeom::kFacevaryingScope) - { - const auto &nIndices = *(m_normals.getIndices()); - - if (copyUvs) - { - const auto &uvs = *(m_uvs.getVals()); - const auto &uvIndices = *(m_uvs.getIndices()); - - if (copyTangents) - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); - data.normals[k] = normals[nIndices[o]]; - data.normals[k].x *= xScale; - data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; - data.tangents[k].x *= xScale; - data.uvs[k] = uvs[uvIndices[o]]; - } - } - } - else - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); - data.normals[k] = normals[nIndices[o]]; - data.normals[k].x *= xScale; - data.uvs[k] = uvs[uvIndices[o]]; - } - } - } - } - else if (copyTangents) - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); - data.normals[k] = normals[nIndices[o]]; - data.normals[k].x *= xScale; - data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; - data.tangents[k].x *= xScale; - } - } - } - else - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); - data.normals[k] = normals[nIndices[o]]; - data.normals[k].x *= xScale; - } - } - } - } - else - { - if (copyUvs) - { - const auto &uvs = *(m_uvs.getVals()); - const auto &uvIndices = *(m_uvs.getIndices()); - - if (copyTangents) - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - int v = indices[o]; - UPDATE_POSITIONS_AND_BOUNDS(v, k); - data.normals[k] = normals[v]; - data.normals[k].x *= xScale; - data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; - data.tangents[k].x *= xScale; - data.uvs[k] = uvs[uvIndices[o]]; - } - } - } - else - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - int v = indices[o]; - UPDATE_POSITIONS_AND_BOUNDS(v, k); - data.normals[k] = normals[v]; - data.normals[k].x *= xScale; - data.uvs[k] = uvs[uvIndices[o]]; - } - } - } - } - else if (copyTangents) - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - int v = indices[o]; - UPDATE_POSITIONS_AND_BOUNDS(v, k); - data.normals[k] = normals[v]; - data.normals[k].x *= xScale; - data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; - data.tangents[k].x *= xScale; - } - } - } - else - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - int v = indices[o]; - UPDATE_POSITIONS_AND_BOUNDS(v, k); - data.normals[k] = normals[v]; - data.normals[k].x *= xScale; - } - } - } - } - } - else - { - if (copyUvs) - { - const auto &uvs = *(m_uvs.getVals()); - const auto &uvIndices = *(m_uvs.getIndices()); - - if (copyTangents) - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - int v = indices[o]; - UPDATE_POSITIONS_AND_BOUNDS(v, k); - data.normals[k] = m_smoothNormals[v]; - data.normals[k].x *= xScale; - data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; - data.tangents[k].x *= xScale; - data.uvs[k] = uvs[uvIndices[o]]; - } - } - } - else - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - int v = indices[o]; - UPDATE_POSITIONS_AND_BOUNDS(v, k); - data.normals[k] = m_smoothNormals[v]; - data.normals[k].x *= xScale; - data.uvs[k] = uvs[uvIndices[o]]; - } - } - } - } - else if (copyTangents) - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - int v = indices[o]; - UPDATE_POSITIONS_AND_BOUNDS(v, k); - data.normals[k] = m_smoothNormals[v]; - data.normals[k].x *= xScale; - data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; - data.tangents[k].x *= xScale; - } - } - } - else - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - int v = indices[o]; - UPDATE_POSITIONS_AND_BOUNDS(v, k); - data.normals[k] = m_smoothNormals[v]; - data.normals[k].x *= xScale; - } - } - } - } - } - else - { - if (copyUvs) - { - const auto &uvs = *(m_uvs.getVals()); - const auto &uvIndices = *(m_uvs.getIndices()); - - if (copyTangents) - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); - data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; - data.tangents[k].x *= xScale; - data.uvs[k] = uvs[uvIndices[o]]; - } - } - } - else - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); - data.uvs[k] = uvs[uvIndices[o]]; - } - } - } - } - else if (copyTangents) - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); - data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; - data.tangents[k].x *= xScale; - } - } - } - else - { - for (size_t i=split.firstFace; i<=split.lastFace; ++i) - { - int nv = counts[i]; - for (int j = 0; j < nv; ++j, ++o, ++k) - { - UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); - } - } - } - } - -#undef UPDATE_POSITIONS_AND_BOUNDS - - data.center = 0.5f * (bbmin + bbmax); - data.size = bbmax - bbmin; -} - -int aiPolyMeshSample::prepareSubmeshes(const aiFacesets &inFacesets) -{ - DebugLog("aiPolyMeshSample::prepateSubmeshes()"); - - int rv = m_topology->prepareSubmeshes(m_uvs, inFacesets, m_config.submeshPerUVTile); - - m_curSubmesh = m_topology->submeshBegin(); - - return rv; -} - -int aiPolyMeshSample::getSplitSubmeshCount(int splitIndex) const -{ - DebugLog("aiPolyMeshSample::getSplitSubmeshCount()"); - - return m_topology->getSplitSubmeshCount(splitIndex); -} - -bool aiPolyMeshSample::getNextSubmesh(aiSubmeshSummary &summary) -{ - DebugLog("aiPolyMeshSample::getNextSubmesh()"); - - if (m_curSubmesh == m_topology->submeshEnd()) - { - return false; - } - else - { - Submesh &submesh = *m_curSubmesh; - - summary.index = int(m_curSubmesh - m_topology->submeshBegin()); - summary.splitIndex = submesh.splitIndex; - summary.splitSubmeshIndex = submesh.index; - summary.facesetIndex = submesh.facesetIndex; - summary.triangleCount = int(submesh.triangleCount); - - ++m_curSubmesh; - - return true; - } -} - -void aiPolyMeshSample::fillSubmeshIndices(const aiSubmeshSummary &summary, aiSubmeshData &data) const -{ - DebugLog("aiPolyMeshSample::fillSubmeshIndices()"); - - Submeshes::const_iterator it = m_topology->submeshBegin() + summary.index; - - if (it != m_topology->submeshEnd()) - { - bool ccw = m_config.swapFaceWinding; - const auto &counts = *(m_topology->m_counts); - const Submesh &submesh = *it; - - int index = 0; - int i1 = (ccw ? 2 : 1); - int i2 = (ccw ? 1 : 2); - int offset = 0; - - if (submesh.faces.empty() && submesh.vertexIndices.empty()) - { - // single submesh case, faces and vertexIndices not populated - - for (size_t i=0; im_topology->clear(); - } - } - - return sample; -} - -aiPolyMesh::Sample* aiPolyMesh::readSample(const abcSampleSelector& ss, bool &topologyChanged) -{ - DebugLog("aiPolyMesh::readSample(t=%f)", (float)ss.getRequestedTime()); - - Sample *ret = newSample(); - - topologyChanged = m_varyingTopology; - - if (!ret->m_topology->m_counts || m_varyingTopology) - { - DebugLog(" Read face counts"); - m_schema.getFaceCountsProperty().get(ret->m_topology->m_counts, ss); - ret->m_topology->m_triangulatedIndexCount = CalculateTriangulatedIndexCount(*ret->m_topology->m_counts); - topologyChanged = true; - } - - if (!ret->m_topology->m_indices || m_varyingTopology) - { - DebugLog(" Read face indices"); - m_schema.getFaceIndicesProperty().get(ret->m_topology->m_indices, ss); - topologyChanged = true; - } - - DebugLog(" Read positions"); - m_schema.getPositionsProperty().get(ret->m_positions, ss); - - ret->m_velocities.reset(); - auto velocitiesProp = m_schema.getVelocitiesProperty(); - if (velocitiesProp.valid()) - { - DebugLog(" Read velocities"); - velocitiesProp.get(ret->m_velocities, ss); - } - - ret->m_normals.reset(); - auto normalsParam = m_schema.getNormalsParam(); - if (!m_ignoreNormals && normalsParam.valid()) - { - if (normalsParam.isConstant()) - { - if (!m_sharedNormals.valid()) - { - DebugLog(" Read normals (constant)"); - normalsParam.getIndexed(m_sharedNormals, ss); - } - - ret->m_normals = m_sharedNormals; - } - else - { - DebugLog(" Read normals"); - normalsParam.getIndexed(ret->m_normals, ss); - } - } - - ret->m_uvs.reset(); - auto uvsParam = m_schema.getUVsParam(); - if (!m_ignoreUVs && uvsParam.valid()) - { - if (uvsParam.isConstant()) - { - if (!m_sharedUVs.valid()) - { - DebugLog(" Read uvs (constant)"); - uvsParam.getIndexed(m_sharedUVs, ss); - } - - ret->m_uvs = m_sharedUVs; - } - else - { - DebugLog(" Read uvs"); - uvsParam.getIndexed(ret->m_uvs, ss); - } - } - - auto boundsParam = m_schema.getSelfBoundsProperty(); - if (boundsParam) { - boundsParam.get(ret->m_bounds, ss); - } - - bool smoothNormalsRequired = ret->smoothNormalsRequired(); - - if (smoothNormalsRequired) - { - ret->computeSmoothNormals(m_config); - } - - if (ret->tangentsRequired()) - { - const abcV3 *normals = 0; - bool indexedNormals = false; - - if (smoothNormalsRequired) - { - normals = &ret->m_smoothNormals[0]; - } - else if (ret->m_normals.valid()) - { - normals = ret->m_normals.getVals()->get(); - indexedNormals = (ret->m_normals.getScope() == AbcGeom::kFacevaryingScope); - } - - if (normals && ret->m_uvs.valid()) - { - // topology may be shared, check tangent indices - if (ret->m_topology->m_tangentIndices.empty() || !m_config.cacheTangentsSplits) - { - ret->computeTangentIndices(m_config, normals, indexedNormals); - } - - ret->computeTangents(m_config, normals, indexedNormals); - } - } - - return ret; -} - -int aiPolyMesh::getTopologyVariance() const -{ - return (int) m_schema.getTopologyVariance(); -} - - -void aiPolyMesh::updatePeakIndexCount() const -{ - if (m_peakIndexCount != 0) { return; } - - DebugLog("aiPolyMesh::updateMaxIndex()"); - - Util::Dimensions dim; - Abc::Int32ArraySamplePtr counts; - - auto indicesProp = m_schema.getFaceIndicesProperty(); - auto countsProp = m_schema.getFaceCountsProperty(); - - int numSamples = (int)indicesProp.getNumSamples(); - if (numSamples == 0) { return; } - - size_t cMax = 0; - if (indicesProp.isConstant()) - { - auto ss = Abc::ISampleSelector(int64_t(0)); - countsProp.get(counts, ss); - indicesProp.getDimensions(dim, ss); - cMax = dim.numPoints(); - } - else - { - aiLogger::Info("Checking %d sample(s)", numSamples); - - int iMax = 0; - - for (int i = 0; i < numSamples; ++i) - { - indicesProp.getDimensions(dim, Abc::ISampleSelector(int64_t(i))); - - size_t numIndices = dim.numPoints(); - - if (numIndices > cMax) - { - cMax = numIndices; - iMax = i; - } - } - - countsProp.get(counts, Abc::ISampleSelector(int64_t(iMax))); - } - - m_peakIndexCount = (int)cMax; - m_peakTriangulatedIndexCount = CalculateTriangulatedIndexCount(*counts); -} - -int aiPolyMesh::getPeakIndexCount() const -{ - updatePeakIndexCount(); - return m_peakTriangulatedIndexCount; -} - -int aiPolyMesh::getPeakTriangulatedIndexCount() const -{ - updatePeakIndexCount(); - return m_peakTriangulatedIndexCount; -} - -int aiPolyMesh::getPeakVertexCount() const -{ - if (m_peakVertexCount == 0) - { - DebugLog("aiPolyMesh::getPeakVertexCount()"); - - Util::Dimensions dim; - - auto positionsProp = m_schema.getPositionsProperty(); - - int numSamples = (int)positionsProp.getNumSamples(); - - if (numSamples == 0) - { - return 0; - } - else if (positionsProp.isConstant()) - { - positionsProp.getDimensions(dim, Abc::ISampleSelector(int64_t(0))); - - m_peakVertexCount = (int)dim.numPoints(); - } - else - { - m_peakVertexCount = 0; - - for (int i = 0; i < numSamples; ++i) - { - positionsProp.getDimensions(dim, Abc::ISampleSelector(int64_t(i))); - - size_t numVertices = dim.numPoints(); - - if (numVertices > size_t(m_peakVertexCount)) - { - m_peakVertexCount = int(numVertices); - } - } - } - } - - return m_peakVertexCount; -} - -void aiPolyMesh::getSummary(aiMeshSummary &summary) const -{ - DebugLog("aiPolyMesh::getSummary()"); - - summary.topologyVariance = getTopologyVariance(); - summary.peakVertexCount = getPeakVertexCount(); - summary.peakIndexCount = getPeakIndexCount(); - summary.peakTriangulatedIndexCount = getPeakTriangulatedIndexCount(); - summary.peakSubmeshCount = ceildiv(summary.peakIndexCount, 64998); -} - +#include "pch.h" +#include "aiInternal.h" +#include "aiContext.h" +#include "aiObject.h" +#include "aiSchema.h" +#include "aiPolyMesh.h" +#include + +// --- + +static inline int CalculateTriangulatedIndexCount(Abc::Int32ArraySample &counts) +{ + int r = 0; + size_t n = counts.size(); + for (size_t fi = 0; fi < n; ++fi) + { + int ngon = counts[fi]; + r += (ngon - 2) * 3; + } + return r; +} + +// --- + +Topology::Topology() + : m_triangulatedIndexCount(0) + , m_tangentsCount(0) +{ + m_indices.reset(); + m_counts.reset(); +} + +Topology::~Topology() +{ +} + +void Topology::clear() +{ + aiLogger::Info("Topology::clear()"); + m_indices.reset(); + m_counts.reset(); + + m_tangentIndices.clear(); + m_tangentsCount = 0; + + m_submeshes.clear(); + m_faceSplitIndices.clear(); + m_splits.clear(); +} + +int Topology::getTriangulatedIndexCount() const +{ + return m_triangulatedIndexCount; +} + +int Topology::getSplitCount() const +{ + return (int) m_splits.size(); +} + +int Topology::getSplitCount(aiPolyMeshSample * meshSample, bool forceRefresh) +{ + if (m_counts && m_indices) + { + if (m_faceSplitIndices.size() != m_counts->size() || forceRefresh) + { + updateSplits(meshSample); + } + } + else + { + m_splits.clear(); + m_faceSplitIndices.clear(); + } + + return (int) m_splits.size(); +} + +void Topology::updateSplits(aiPolyMeshSample * meshSample) +{ + DebugLog("Topology::updateSplits()"); + + int splitIndex = 0; + size_t indexOffset = 0; + size_t ncounts = m_counts->size(); + + m_faceSplitIndices.resize(ncounts); // number of faces + + m_splits.clear(); + + if (m_vertexSharingEnabled && meshSample != NULL && !meshSample->m_ownTopology) // only fixed topologies get this execution path + { + m_splits.push_back(SplitInfo()); + + SplitInfo *curSplit = &(m_splits.back()); + + for (size_t i = 0; ilastFace = ncounts-1; + curSplit->vertexCount = m_FixedTopoPositionsIndexes.size(); + } + else + { + m_splits.reserve(1 + m_indices->size() / 65000); + m_splits.push_back(SplitInfo()); + + SplitInfo *curSplit = &(m_splits.back()); + + for (size_t i = 0; iget()[i]; + + if (curSplit->vertexCount + nv > 65000) + { + m_splits.push_back(SplitInfo(i, indexOffset)); + + ++splitIndex; + + curSplit = &(m_splits.back()); + } + + m_faceSplitIndices[i] = splitIndex; // assign a split ID/index to each face + + curSplit->lastFace = i; + curSplit->vertexCount += nv; + + indexOffset += nv; + } + } +} + +int Topology::getVertexBufferLength(int splitIndex) const +{ + if (splitIndex < 0 || size_t(splitIndex) >= m_splits.size()) + { + return 0; + } + else + { + return (int) m_splits[splitIndex].vertexCount; + } +} + +int Topology::prepareSubmeshes(const AbcGeom::IV2fGeomParam::Sample &uvs, + const aiFacesets &inFacesets, + bool submeshPerUVTile, + aiPolyMeshSample* sample) +{ + DebugLog("Topology::prepareSubmeshes()"); + + Facesets facesets; + std::vector facesetIndices; // index -> face table + + + m_submeshes.clear(); + + if (inFacesets.count > 0) + { + int index_count = 0; + int max_index = 0; + { + int n = inFacesets.count; + for (int i = 0; i < n; ++i) + { + int ngon = inFacesets.faceCounts[i]; + for (int j = 0; j < ngon; ++j) + { + max_index = std::max(max_index, inFacesets.faceIndices[index_count++]); + } + } + } + facesetIndices.resize(max_index, -1); + + + size_t index = 0; + int defaultFacesetIndex = -1; + + facesets.resize(inFacesets.count); + + for (int i=0; isize(), -1); + for (size_t i=0; isize(); ++i) + { + if (facesetIndices[i] == -1) { + facesetIndices[i] = defaultFacesetIndex; + } + } + } + } + else + { + facesetIndices.resize(m_counts->size(), -1); + + // don't even fill faceset if we have no UVs to tile split the mesh + if (uvs.valid() && submeshPerUVTile) + { + facesets.resize(1); + Faceset &faceset = facesets.front(); + + for (size_t i=0; isize(); ++i) + { + faceset.push_back(i); + } + } + } + + int nsplits = getSplitCount(sample, false); + + if (facesets.empty() && nsplits == 1) + { + // no facesets, no uvs, no splits + m_submeshes.push_back(Submesh()); + + Submesh &submesh = m_submeshes.back(); + + for (size_t i=0; isize(); ++i) + { + submesh.triangleCount += (m_counts->get()[i] - 2); + } + + m_splits[0].submeshCount = 1; + } + else + { + int vertexIndex = 0; + Submesh *curMesh = 0; + const Util::uint32_t *uvIndices = 0; + const abcV2 *uvValues = 0; + + if (uvs.valid() && submeshPerUVTile) + { + uvValues = uvs.getVals()->get(); + uvIndices = uvs.getIndices()->get(); + } + + std::map submeshIndices; + + std::vector splitSubmeshIndices(nsplits, 0); + + for (size_t i=0; isize(); ++i) + { + int nv = m_counts->get()[i]; + + if (nv == 0) + { + continue; + } + + int facesetIndex = facesetIndices[i]; + int splitIndex = m_faceSplitIndices[i]; + + SplitInfo &split = m_splits[splitIndex]; + + // Compute submesh ID based on face's average UV coordinate and it faceset index + float uAcc = 0.0f; + float vAcc = 0.0f; + float invNv = 1.0f / float(nv); + + if (uvValues) + { + for (int j=0; jindex = splitSubmeshIndices[splitIndex]++; + + if(m_vertexSharingEnabled) + curMesh->vertexIndices.reserve(m_FixedTopoPositionsIndexes.size()); + else + curMesh->vertexIndices.reserve(m_indices->size()); + + split.submeshCount = splitSubmeshIndices[splitIndex]; + } + else + { + curMesh = &(m_submeshes[submeshIndexIt->second]); + } + + curMesh->faces.push_back(i); + curMesh->triangleCount += (nv - 2); + + if (m_vertexSharingEnabled) + { + for (int j = 0; jvertexIndices.push_back( (int)( m_FaceIndexingReindexed[vertexIndex] - split.indexOffset) ); + } + } + else + { + for (int j=0; jvertexIndices.push_back(vertexIndex - int(split.indexOffset)); + } + } + } + + for (size_t i=0; i= m_splits.size()) + { + return 0; + } + else + { + return (int) m_splits[splitIndex].submeshCount; + } +} + +// --- + +aiPolyMeshSample::aiPolyMeshSample(aiPolyMesh *schema, Topology *topo, bool ownTopo, bool vertexSharingEnabled) + : super(schema) + , m_topology(topo) + , m_ownTopology(ownTopo) + , m_vertexSharingEnabled(vertexSharingEnabled) +{ +} + +aiPolyMeshSample::~aiPolyMeshSample() +{ + if (m_topology && m_ownTopology) + { + delete m_topology; + } +} + +bool aiPolyMeshSample::hasNormals() const +{ + switch (m_config.normalsMode) + { + case aiNormalsMode::ReadFromFile: + return m_normals.valid(); + break; + case aiNormalsMode::Ignore: + return false; + break; + default: + return (m_normals.valid() || !m_smoothNormals.empty()); + } +} + +bool aiPolyMeshSample::hasUVs() const +{ + return m_uvs.valid(); +} + +bool aiPolyMeshSample::hasTangents() const +{ + return (m_config.tangentsMode != aiTangentsMode::None && hasUVs() && !m_tangents.empty() && !m_topology->m_tangentIndices.empty()); +} + +bool aiPolyMeshSample::smoothNormalsRequired() const +{ + return (m_config.normalsMode == aiNormalsMode::AlwaysCompute || + m_config.tangentsMode == aiTangentsMode::Smooth || + (!m_normals.valid() && m_config.normalsMode == aiNormalsMode::ComputeIfMissing)); +} + +bool aiPolyMeshSample::tangentsRequired() const +{ + return (m_config.tangentsMode != aiTangentsMode::None); +} + +void aiPolyMeshSample::computeSmoothNormals(const aiConfig &config) +{ + aiLogger::Info("%s: Compute smooth normals", getSchema()->getObject()->getFullName()); + + size_t smoothNormalsCount = m_positions->size(); + m_smoothNormals.resize(smoothNormalsCount); + // sadly, memset() is way faster than std::fill() on VC + memset(&m_smoothNormals[0], 0, sizeof(m_smoothNormals[0])*m_smoothNormals.size()); + + + const auto &counts = *(m_topology->m_counts); + const auto &indices = *(m_topology->m_indices); + const auto &positions = *m_positions; + + size_t nf = counts.size(); + size_t off = 0; + bool ccw = config.swapFaceWinding; + int ti1 = ccw ? 2 : 1; + int ti2 = ccw ? 1 : 2; + abcV3 N, dP1, dP2; + + for (size_t f=0; f= 3) + { + // Compute average normal for current face + N.setValue(0.0f, 0.0f, 0.0f); + + const abcV3 &P0 = positions[indices[off]]; + + for (int fv=0; fv 3) + { + N.normalize(); + } + + // Accumulate for all vertices participating to this face + for (int fv=0; fvgetObject()->getFullName()); + + const auto &counts = *(m_topology->m_counts); + const auto &indices = *(m_topology->m_indices); + const auto &uvVals = *(m_uvs.getVals()); + const auto &uvIdxs = *(m_uvs.getIndices()); + const Util::uint32_t *Nidxs = (indexedNormals ? m_normals.getIndices()->get() : 0); + + size_t tangentIndicesCount = indices.size(); + m_topology->m_tangentIndices.resize(tangentIndicesCount); + + if (config.tangentsMode == aiTangentsMode::Smooth) + { + for (size_t i=0; im_tangentIndices[i] = indices[i]; + } + + m_topology->m_tangentsCount = m_positions->size(); + } + else + { + TangentIndexMap uniqueIndices; + TangentIndexMap::iterator it; + + size_t nf = counts.size(); + + for (size_t f=0, v=0; fm_tangentIndices[v] = idx; + uniqueIndices[key] = idx; + } + else + { + m_topology->m_tangentIndices[v] = it->second; + } + } + } + + m_topology->m_tangentsCount = uniqueIndices.size(); + } + + aiLogger::Info("%lu unique tangent(s)", m_topology->m_tangentsCount); +} + +void aiPolyMeshSample::computeTangents(const aiConfig &config, const abcV3 *inN, bool indexedNormals) +{ + aiLogger::Info("%s: Compute %stangents", getSchema()->getObject()->getFullName(), (config.tangentsMode == aiTangentsMode::Smooth ? "smooth " : "")); + + const auto &counts = *(m_topology->m_counts); + const auto &indices = *(m_topology->m_indices); + const auto &positions = *m_positions; + const auto &uvVals = *(m_uvs.getVals()); + const auto &uvIdxs = *(m_uvs.getIndices()); + const Util::uint32_t *Nidxs = (indexedNormals ? m_normals.getIndices()->get() : 0); + + size_t nf = counts.size(); + size_t off = 0; + bool ccw = config.swapFaceWinding; + int ti1 = (ccw ? 2 : 1); + int ti2 = (ccw ? 1 : 2); + + size_t tangentsCount = m_topology->m_tangentsCount; + m_tangents.resize(tangentsCount); + memset(&m_tangents[0], 0, sizeof(m_tangents[0])*m_tangents.size()); + + + abcV3 *tan1 = new Abc::V3f[2 * tangentsCount]; + abcV3 *tan2 = tan1 + tangentsCount; + int *tanNidxs = new int[tangentsCount]; + abcV3 T, B, dP1, dP2, tmp; + abcV2 dUV1, dUV2; + + for (size_t f=0; f= 3) + { + // reset face tangent and bitangent + T.setValue(0.0f, 0.0f, 0.0f); + B.setValue(0.0f, 0.0f, 0.0f); + + const abcV3 &P0 = positions[indices[off]]; + const abcV2 &UV0 = uvVals[uvIdxs[off]]; + + // for each triangle making up current polygon + for (int fv=0; fv 3) + { + T.normalize(); + B.normalize(); + } + + // accumulate normals, tangent and bitangent for each vertex + for (int fv=0; fvm_tangentIndices[off + fv]; + tan1[v] += T; + tan2[v] += B; + tanNidxs[v] = (Nidxs ? Nidxs[off + fv] : indices[off + fv]); + } + } + + off += nfv; + } + + // compute final tangent space for each point + for (size_t i=0; igetObject()->getFullName()); + m_smoothNormals.clear(); + dataChanged = true; + } + } + + bool tangentsRequired = (m_uvs.valid() && config.tangentsMode != aiTangentsMode::None); + + if (tangentsRequired) + { + bool tangentsModeChanged = (config.tangentsMode != m_config.tangentsMode); + + const abcV3 *N = 0; + bool Nindexed = false; + + if (smoothNormalsRequired) + { + N = &m_smoothNormals[0]; + } + else if (m_normals.valid()) + { + N = m_normals.getVals()->get(); + Nindexed = (m_normals.getScope() == AbcGeom::kFacevaryingScope); + } + + if (N) + { + // do not compute indices if they are cached, constant topology and valid + if (m_topology->m_tangentIndices.empty() || + !config.cacheTangentsSplits || + tangentsModeChanged) + { + computeTangentIndices(config, N, Nindexed); + } + if (m_tangents.empty() || + tangentsModeChanged || + topoChanged) + { + computeTangents(config, N, Nindexed); + dataChanged = true; + } + } + else + { + tangentsRequired = false; + } + } + + if (!tangentsRequired) + { + if (!m_tangents.empty()) + { + aiLogger::Info("%s: Clear tangents", getSchema()->getObject()->getFullName()); + + m_tangents.clear(); + dataChanged = true; + } + + if (!m_topology->m_tangentIndices.empty() && (m_ownTopology || !config.cacheTangentsSplits)) + { + aiLogger::Info("%s: Clear tangent indices", getSchema()->getObject()->getFullName()); + + m_topology->m_tangentIndices.clear(); + m_topology->m_tangentsCount = 0; + } + } + + if (topoChanged) + { + dataChanged = true; + } + + m_config = config; +} + +void aiPolyMeshSample::getSummary(bool forceRefresh, aiMeshSampleSummary &summary, aiPolyMeshSample* sample) const +{ + DebugLog("aiPolyMeshSample::getSummary(forceRefresh=%s)", forceRefresh ? "true" : "false"); + + summary.splitCount = m_topology->getSplitCount(sample, forceRefresh); + + summary.hasNormals = hasNormals(); + + summary.hasUVs = hasUVs(); + + summary.hasTangents = hasTangents(); +} + + +void aiPolyMeshSample::getDataPointer(aiPolyMeshData &dst) +{ + if (m_positions) { + dst.positionCount = m_positions->valid() ? (int)m_positions->size() : 0; + dst.positions = (abcV3*)(m_positions->get()); + } + + if (m_velocities) { + dst.velocities = m_velocities->valid() ? (abcV3*)m_velocities->get() : nullptr; + } + + if (m_normals) { + dst.normalCount = (int)m_normals.getVals()->size(); + dst.normals = (abcV3*)m_normals.getVals()->get(); + dst.normalIndexCount = m_normals.isIndexed() ? (int)m_normals.getIndices()->size() : 0; + if (dst.normalIndexCount) { + dst.normalIndices = (int*)m_normals.getIndices()->get(); + } + } + + if (m_uvs) { + dst.uvCount = (int)m_uvs.getVals()->size(); + dst.uvs = (abcV2*)m_uvs.getVals()->get(); + dst.uvIndexCount = m_uvs.isIndexed() ? (int)m_uvs.getIndices()->size() : 0; + if (dst.uvIndexCount) { + dst.uvIndices = (int*)m_uvs.getIndices()->get(); + } + } + + if (m_topology) { + if (m_topology->m_indices) { + dst.indexCount = (int)m_topology->m_indices->size(); + dst.indices = (int*)m_topology->m_indices->get(); + } + if (m_topology->m_counts) { + dst.faceCount = (int)m_topology->m_counts->size(); + dst.faces = (int*)m_topology->m_counts->get(); + dst.triangulatedIndexCount = m_topology->m_triangulatedIndexCount; + } + } + + dst.center = m_bounds.center(); + dst.size = m_bounds.size(); +} + + +static inline void SwapHandedness(aiPolyMeshData &dst) +{ + auto body = [&](abcV3 *v, int n) { + if (v) { + for (int i = 0; i < n; ++i) { v[i].x *= -1.0f; } + } + }; + body(dst.positions, dst.positionCount); + body(dst.velocities, dst.positionCount); + body(dst.normals, dst.normalCount); +} + +// return true if position and uv / normal indices are deferent +static inline bool IsIndicesDivergent(const aiPolyMeshData &dst) +{ + if ((dst.normalCount != 0 && dst.positionCount != dst.normalCount) || + (dst.uvCount != 0 && dst.positionCount != dst.uvCount)) + { + return true; + } + + // maybe more detailed (=very slow) comparison is needed.. + return false; +} + +static inline void TriangulateIndices(aiPolyMeshData& src, int *dv, const int *indices, bool swap_face) +{ + if (!dv) { return; } + + const int i1 = swap_face ? 2 : 1; + const int i2 = swap_face ? 1 : 2; + + int n = 0; + int i = 0; + if (indices) { + for (int fi = 0; fi < src.faceCount; ++fi) { + int ngon = src.faces[fi]; + for (int ni = 0; ni < ngon - 2; ++ni) { + dv[i + 0] = indices[n + 0]; + dv[i + 1] = indices[n + ni + i1]; + dv[i + 2] = indices[n + ni + i2]; + i += 3; + } + n += ngon; + } + } + else { + for (int fi = 0; fi < src.faceCount; ++fi) { + int ngon = src.faces[fi]; + for (int ni = 0; ni < ngon - 2; ++ni) { + dv[i + 0] = n + 0; + dv[i + 1] = n + ni + i1; + dv[i + 2] = n + ni + i2; + i += 3; + } + n += ngon; + } + } +} + +template +static inline void ExpandWithTriangulation(aiPolyMeshData& src, T *dv, const T *sv, const int *indices, bool swap_face) +{ + if (!dv || !sv) { return; } + + const int i1 = swap_face ? 2 : 1; + const int i2 = swap_face ? 1 : 2; + + int n = 0; + int i = 0; + if (indices) { + for (int fi = 0; fi < src.faceCount; ++fi) { + int ngon = src.faces[fi]; + for (int ni = 0; ni < ngon - 2; ++ni) { + dv[i + 0] = sv[indices[n + 0]]; + dv[i + 1] = sv[indices[n + ni + i1]]; + dv[i + 2] = sv[indices[n + ni + i2]]; + i += 3; + } + n += ngon; + } + } + else { + for (int fi = 0; fi < src.faceCount; ++fi) { + int ngon = src.faces[fi]; + for (int ni = 0; ni < ngon - 2; ++ni) { + dv[i + 0] = sv[n + 0]; + dv[i + 1] = sv[n + ni + i1]; + dv[i + 2] = sv[n + ni + i2]; + i += 3; + } + n += ngon; + } + } +} + +void aiPolyMeshSample::copyData(aiPolyMeshData &dst) +{ + aiPolyMeshData src; + getDataPointer(src); + + // sadly, memcpy() is way faster than std::copy() on VC + + if (src.faces && dst.faces && dst.faceCount >= src.faceCount) { + memcpy(dst.faces, src.faces, src.faceCount * sizeof(*dst.faces)); + dst.faceCount = src.faceCount; + } + else { + dst.faceCount = 0; + } + + if (src.positions && dst.positions && dst.positionCount >= src.positionCount) { + memcpy(dst.positions, src.positions, src.positionCount * sizeof(*dst.positions)); + dst.positionCount = src.positionCount; + } + else { + dst.positionCount = 0; + } + + if (src.velocities && dst.velocities && dst.positionCount >= src.positionCount) { + memcpy(dst.velocities, src.velocities, src.positionCount * sizeof(*dst.velocities)); + } + + if (src.normals && dst.normals && dst.normalCount >= src.normalCount) { + memcpy(dst.normals, src.normals, src.normalCount * sizeof(*dst.normals)); + dst.normalCount = src.normalCount; + } + else { + dst.normalCount = 0; + } + + if (src.uvs && dst.uvs && dst.uvCount >= src.uvCount) { + memcpy(dst.uvs, src.uvs, src.uvCount * sizeof(*dst.uvs)); + dst.uvCount = src.uvCount; + } + else { + dst.uvCount = 0; + } + + if (m_config.swapHandedness) { + SwapHandedness(dst); + } + + + auto copy_indices = [&](int *d, const int *s, int n) { + // swap faces if needed + if (m_config.swapFaceWinding) { + int i = 0; + for (int fi = 0; fi < src.faceCount; ++fi) { + int ngon = src.faces[i]; + for (int ni = 0; ni < ngon; ++ni) { + int ini = ngon - ni - 1; + d[i + ni] = s[i + ini]; + } + i += ngon; + } + } + else { + memcpy(d, s, n * sizeof(int)); + } + }; + + if (src.indices && dst.indices && dst.indexCount >= src.indexCount) { + copy_indices(dst.indices, src.indices, src.indexCount); + dst.indexCount = src.indexCount; + } + if (src.normalIndices && dst.normalIndices && dst.normalIndexCount >= src.normalIndexCount) { + copy_indices(dst.normalIndices, src.normalIndices, src.normalIndexCount); + dst.normalIndexCount = src.normalIndexCount; + } + if (src.uvIndices && dst.uvIndices && dst.uvIndexCount >= src.uvIndexCount) { + copy_indices(dst.uvIndices, src.uvIndices, src.uvIndexCount); + dst.uvIndexCount = src.uvIndexCount; + } + + dst.center = dst.center; + dst.size = dst.size; +} + + +void aiPolyMeshSample::copyDataWithTriangulation(aiPolyMeshData &dst, bool always_expand_indices) +{ + aiPolyMeshData src; + getDataPointer(src); + + bool needs_expand = IsIndicesDivergent(src) || always_expand_indices; + + // triangulated mesh has one index buffer + dst.normalIndices = nullptr; + dst.normalIndexCount = 0; + dst.uvIndices = nullptr; + dst.uvIndexCount = 0; + + // todo: generate normals and tangents if required + + if (needs_expand) { + if (src.positions && dst.positions && dst.positionCount >= src.triangulatedIndexCount) { + ExpandWithTriangulation(src, dst.positions, src.positions, src.indices, m_config.swapFaceWinding); + dst.positionCount = src.triangulatedIndexCount; + } + else { + dst.positionCount = 0; + } + + if (src.velocities && dst.velocities && dst.positionCount >= src.triangulatedIndexCount) { + ExpandWithTriangulation(src, dst.velocities, src.velocities, src.indices, m_config.swapFaceWinding); + } + + if (src.normals && dst.normals && dst.normalCount >= src.triangulatedIndexCount) { + ExpandWithTriangulation(src, dst.normals, src.normals, src.normalIndices, m_config.swapFaceWinding); + dst.normalCount = src.triangulatedIndexCount; + } + else { + dst.normalCount = 0; + } + + if (src.uvs && dst.uvs && dst.uvCount >= src.triangulatedIndexCount) { + ExpandWithTriangulation(src, dst.uvs, src.uvs, src.uvIndices, m_config.swapFaceWinding); + dst.uvCount = src.triangulatedIndexCount; + } + else { + dst.uvCount = 0; + } + + if (dst.indices && dst.indexCount >= src.triangulatedIndexCount) { + for (int i = 0; i < src.triangulatedIndexCount; ++i) { + dst.indices[i] = i; + } + } + } + else { + int *indices = dst.indices; + dst.indices = nullptr; // skip needless copy + copyData(dst); + dst.indices = indices; + TriangulateIndices(src, dst.indices, src.indices, m_config.swapFaceWinding); + } + + { + dst.triangulatedIndexCount = src.triangulatedIndexCount; + int num_triangles = src.triangulatedIndexCount / 3; + if (dst.faces && dst.faceCount >= num_triangles) { + std::fill(dst.faces, dst.faces + num_triangles, 3); + dst.faceCount = num_triangles; + } + else { + dst.faceCount = 0; + } + } + + dst.center = dst.center; + dst.size = dst.size; +} + + +int aiPolyMeshSample::getVertexBufferLength(int splitIndex) const +{ + DebugLog("aiPolyMeshSample::getVertexBufferLength(splitIndex=%d)", splitIndex); + + return m_topology->getVertexBufferLength(splitIndex); +} + +void aiPolyMeshSample::fillVertexBuffer(int splitIndex, aiPolyMeshData &data) +{ + DebugLog("aiPolyMeshSample::fillVertexBuffer(splitIndex=%d)", splitIndex); + + if (splitIndex < 0 || size_t(splitIndex) >= m_topology->m_splits.size() || m_topology->m_splits[splitIndex].vertexCount == 0) + { + return; + } + + bool copyNormals = (hasNormals() && data.normals); + bool copyUvs = (hasUVs() && data.uvs); + bool copyTangents = (hasTangents() && data.tangents); + + bool useAbcNormals = (m_normals.valid() && (m_config.normalsMode == aiNormalsMode::ReadFromFile || m_config.normalsMode == aiNormalsMode::ComputeIfMissing)); + float xScale = (m_config.swapHandedness ? -1.0f : 1.0f); + + const SplitInfo &split = m_topology->m_splits[splitIndex]; + const auto &counts = *(m_topology->m_counts); + const auto &indices = *(m_topology->m_indices); + const auto &positions = *m_positions; + + size_t k = 0; + size_t o = split.indexOffset; + + // reset unused data arrays + + if (data.normals && !copyNormals) + { + aiLogger::Info("%s: Reset normals", getSchema()->getObject()->getFullName()); + memset(data.normals, 0, split.vertexCount * sizeof(abcV3)); + } + + if (data.uvs && !copyUvs) + { + aiLogger::Info("%s: Reset UVs", getSchema()->getObject()->getFullName()); + memset(data.uvs, 0, split.vertexCount * sizeof(abcV2)); + } + + if (data.tangents && !copyTangents) + { + aiLogger::Info("%s: Reset tangents", getSchema()->getObject()->getFullName()); + memset(data.tangents, 0, split.vertexCount * sizeof(abcV4)); + } + + abcV3 bbmin = positions[indices[o]]; + abcV3 bbmax = bbmin; + +#define UPDATE_POSITIONS_AND_BOUNDS(srcIdx, dstIdx) \ + abcV3 &cP = data.positions[dstIdx]; \ + cP = positions[srcIdx]; \ + cP.x *= xScale; \ + if (cP.x < bbmin.x) bbmin.x = cP.x; \ + else if (cP.x > bbmax.x) bbmax.x = cP.x; \ + if (cP.y < bbmin.y) bbmin.y = cP.y; \ + else if (cP.y > bbmax.y) bbmax.y = cP.y; \ + if (cP.z < bbmin.z) bbmin.z = cP.z; \ + else if (cP.z > bbmax.z) bbmax.z = cP.z + + + // fill data arrays + + if (copyNormals) + { + if (useAbcNormals) + { + const auto &normals = *(m_normals.getVals()); + + if (m_normals.getScope() == AbcGeom::kFacevaryingScope) + { + const auto &nIndices = *(m_normals.getIndices()); + + if (copyUvs) + { + const auto &uvs = *(m_uvs.getVals()); + const auto &uvIndices = *(m_uvs.getIndices()); + + if (copyTangents) + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = normals[nIndices[o]]; + data.normals[dstNdx].x *= xScale; + data.tangents[dstNdx] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[dstNdx].x *= xScale; + data.uvs[dstNdx] = uvs[uvIndices[o]]; + } + else + { + UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); + data.normals[k] = normals[nIndices[o]]; + data.normals[k].x *= xScale; + data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[k].x *= xScale; + data.uvs[k] = uvs[uvIndices[o]]; + } + } + } + } + else + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = normals[nIndices[o]]; + data.normals[dstNdx].x *= xScale; + data.uvs[dstNdx] = uvs[uvIndices[o]]; + } + else + { + UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); + data.normals[k] = normals[nIndices[o]]; + data.normals[k].x *= xScale; + data.uvs[k] = uvs[uvIndices[o]]; + } + } + } + } + } + else if (copyTangents) + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = normals[nIndices[o]]; + data.normals[dstNdx].x *= xScale; + data.tangents[dstNdx] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[dstNdx].x *= xScale; + } + else + { + UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); + data.normals[k] = normals[nIndices[o]]; + data.normals[k].x *= xScale; + data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[k].x *= xScale; + } + } + } + } + else + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = normals[nIndices[o]]; + data.normals[dstNdx].x *= xScale; + } + else + { + UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); + data.normals[k] = normals[nIndices[o]]; + data.normals[k].x *= xScale; + } + } + } + } + } + else + { + if (copyUvs) + { + const auto &uvs = *(m_uvs.getVals()); + const auto &uvIndices = *(m_uvs.getIndices()); + + if (copyTangents) + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if (m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = normals[indices[o]]; + data.normals[dstNdx].x *= xScale; + data.tangents[dstNdx] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[dstNdx].x *= xScale; + data.uvs[dstNdx] = uvs[uvIndices[o]]; + } + else + { + int v = indices[o]; + UPDATE_POSITIONS_AND_BOUNDS(v, k); + data.normals[k] = normals[v]; + data.normals[k].x *= xScale; + data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[k].x *= xScale; + data.uvs[k] = uvs[uvIndices[o]]; + } + } + } + } + else + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = normals[indices[o]]; + data.normals[dstNdx].x *= xScale; + data.uvs[dstNdx] = uvs[uvIndices[o]]; + } + else + { + int v = indices[o]; + UPDATE_POSITIONS_AND_BOUNDS(v, k); + data.normals[k] = normals[v]; + data.normals[k].x *= xScale; + data.uvs[k] = uvs[uvIndices[o]]; + } + } + } + } + } + else if (copyTangents) + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = normals[indices[o]]; + data.normals[dstNdx].x *= xScale; + data.tangents[dstNdx] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[dstNdx].x *= xScale; + } + else + { + int v = indices[o]; + UPDATE_POSITIONS_AND_BOUNDS(v, k); + data.normals[k] = normals[v]; + data.normals[k].x *= xScale; + data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[k].x *= xScale; + } + } + } + } + else + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = normals[indices[o]]; + data.normals[dstNdx].x *= xScale; + } + else + { + int v = indices[o]; + UPDATE_POSITIONS_AND_BOUNDS(v, k); + data.normals[k] = normals[v]; + data.normals[k].x *= xScale; + } + } + } + } + } + } + else + { + if (copyUvs) + { + const auto &uvs = *(m_uvs.getVals()); + const auto &uvIndices = *(m_uvs.getIndices()); + + if (copyTangents) + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = m_smoothNormals[indices[o]]; + data.normals[dstNdx].x *= xScale; + data.tangents[dstNdx] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[dstNdx].x *= xScale; + data.uvs[dstNdx] = uvs[uvIndices[o]]; + } + else + { + int v = indices[o]; + + UPDATE_POSITIONS_AND_BOUNDS(v, k); + data.normals[k] = m_smoothNormals[v]; + data.normals[k].x *= xScale; + data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[k].x *= xScale; + data.uvs[k] = uvs[uvIndices[o]]; + } + } + } + } + else + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = m_smoothNormals[indices[o]]; + data.normals[dstNdx].x *= xScale; + data.uvs[dstNdx] = uvs[uvIndices[o]]; + } + else + { + int v = indices[o]; + UPDATE_POSITIONS_AND_BOUNDS(v, k); + data.normals[k] = m_smoothNormals[v]; + data.normals[k].x *= xScale; + data.uvs[k] = uvs[uvIndices[o]]; + } + } + } + } + } + else if (copyTangents) + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = m_smoothNormals[indices[o]]; + data.normals[dstNdx].x *= xScale; + data.tangents[dstNdx] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[dstNdx].x *= xScale; + } + else + { + int v = indices[o]; + UPDATE_POSITIONS_AND_BOUNDS(v, k); + data.normals[k] = m_smoothNormals[v]; + data.normals[k].x *= xScale; + data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[k].x *= xScale; + } + } + } + } + else + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if ( m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.normals[dstNdx] = m_smoothNormals[indices[o]]; + data.normals[dstNdx].x *= xScale; + } + else + { + int v = indices[o]; + UPDATE_POSITIONS_AND_BOUNDS(v, k); + data.normals[k] = m_smoothNormals[v]; + data.normals[k].x *= xScale; + } + } + } + } + } + } + else + { + if (copyUvs) + { + const auto &uvs = *(m_uvs.getVals()); + const auto &uvIndices = *(m_uvs.getIndices()); + + if (copyTangents) + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if (m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.tangents[dstNdx] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[dstNdx].x *= xScale; + data.uvs[dstNdx] = uvs[uvIndices[o]]; + } + else + { + UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); + data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[k].x *= xScale; + data.uvs[k] = uvs[uvIndices[o]]; + } + } + } + } + else + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if (m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.uvs[dstNdx] = uvs[uvIndices[o]]; + } + else + { + UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); + data.uvs[k] = uvs[uvIndices[o]]; + } + } + } + } + } + else if (copyTangents) + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if (m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + data.tangents[dstNdx] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[dstNdx].x *= xScale; + } + else + { + UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); + data.tangents[k] = m_tangents[m_topology->m_tangentIndices[o]]; + data.tangents[k].x *= xScale; + } + } + } + } + else + { + for (size_t i=split.firstFace; i<=split.lastFace; ++i) + { + int nv = counts[i]; + for (int j = 0; j < nv; ++j, ++o, ++k) + { + if (m_topology->m_FixedTopoPositionsIndexes.size()) + { + size_t dstNdx = m_topology->m_FaceIndexingReindexed[o]; + size_t srcNdx = m_topology->m_FixedTopoPositionsIndexes[dstNdx]; + + UPDATE_POSITIONS_AND_BOUNDS(srcNdx, dstNdx); + } + else + { + UPDATE_POSITIONS_AND_BOUNDS(indices[o], k); + } + } + } + } + } + +#undef UPDATE_POSITIONS_AND_BOUNDS + + data.center = 0.5f * (bbmin + bbmax); + data.size = bbmax - bbmin; +} + +int aiPolyMeshSample::prepareSubmeshes(aiPolyMeshSample* sample, const aiFacesets &inFacesets) +{ + DebugLog("aiPolyMeshSample::prepateSubmeshes()"); + + int rv = m_topology->prepareSubmeshes(m_uvs, inFacesets, m_config.submeshPerUVTile, sample); + + m_curSubmesh = m_topology->submeshBegin(); + + return rv; +} + +int aiPolyMeshSample::getSplitSubmeshCount(int splitIndex) const +{ + DebugLog("aiPolyMeshSample::getSplitSubmeshCount()"); + + return m_topology->getSplitSubmeshCount(splitIndex); +} + +bool aiPolyMeshSample::getNextSubmesh(aiSubmeshSummary &summary) +{ + DebugLog("aiPolyMeshSample::getNextSubmesh()"); + + if (m_curSubmesh == m_topology->submeshEnd()) + { + return false; + } + else + { + Submesh &submesh = *m_curSubmesh; + + summary.index = int(m_curSubmesh - m_topology->submeshBegin()); + summary.splitIndex = submesh.splitIndex; + summary.splitSubmeshIndex = submesh.index; + summary.facesetIndex = submesh.facesetIndex; + summary.triangleCount = int(submesh.triangleCount); + + ++m_curSubmesh; + + return true; + } +} + +void aiPolyMeshSample::fillSubmeshIndices(const aiSubmeshSummary &summary, aiSubmeshData &data) const +{ + DebugLog("aiPolyMeshSample::fillSubmeshIndices()"); + + Submeshes::const_iterator it = m_topology->submeshBegin() + summary.index; + + if (it != m_topology->submeshEnd()) + { + bool ccw = m_config.swapFaceWinding; + const auto &counts = *(m_topology->m_counts); + const Submesh &submesh = *it; + + int index = 0; + int i1 = (ccw ? 2 : 1); + int i2 = (ccw ? 1 : 2); + int offset = 0; + + if (submesh.faces.empty() && submesh.vertexIndices.empty()) + { + // single submesh case, faces and vertexIndices not populated + + for (size_t i=0; im_topology->clear(); + } + } + + return sample; +} + +aiPolyMesh::Sample* aiPolyMesh::readSample(const abcSampleSelector& ss, bool &topologyChanged) +{ + DebugLog("aiPolyMesh::readSample(t=%f)", (float)ss.getRequestedTime()); + + Sample *ret = newSample(); + + topologyChanged = m_varyingTopology; + ret->m_topology->EnableVertexSharing(m_config.shareVertices && !m_varyingTopology); + + if (!ret->m_topology->m_counts || m_varyingTopology) + { + DebugLog(" Read face counts"); + m_schema.getFaceCountsProperty().get(ret->m_topology->m_counts, ss); + ret->m_topology->m_triangulatedIndexCount = CalculateTriangulatedIndexCount(*ret->m_topology->m_counts); + topologyChanged = true; + } + + if (!ret->m_topology->m_indices || m_varyingTopology) + { + DebugLog(" Read face indices"); + m_schema.getFaceIndicesProperty().get(ret->m_topology->m_indices, ss); + topologyChanged = true; + } + + DebugLog(" Read positions"); + m_schema.getPositionsProperty().get(ret->m_positions, ss); + + ret->m_velocities.reset(); + auto velocitiesProp = m_schema.getVelocitiesProperty(); + if (velocitiesProp.valid()) + { + DebugLog(" Read velocities"); + velocitiesProp.get(ret->m_velocities, ss); + } + + ret->m_normals.reset(); + auto normalsParam = m_schema.getNormalsParam(); + if (!m_ignoreNormals && normalsParam.valid()) + { + if (normalsParam.isConstant()) + { + if (!m_sharedNormals.valid()) + { + DebugLog(" Read normals (constant)"); + normalsParam.getIndexed(m_sharedNormals, ss); + } + + ret->m_normals = m_sharedNormals; + } + else + { + DebugLog(" Read normals"); + normalsParam.getIndexed(ret->m_normals, ss); + } + } + + ret->m_uvs.reset(); + auto uvsParam = m_schema.getUVsParam(); + if (!m_ignoreUVs && uvsParam.valid()) + { + if (uvsParam.isConstant()) + { + if (!m_sharedUVs.valid()) + { + DebugLog(" Read uvs (constant)"); + uvsParam.getIndexed(m_sharedUVs, ss); + } + + ret->m_uvs = m_sharedUVs; + } + else + { + DebugLog(" Read uvs"); + uvsParam.getIndexed(ret->m_uvs, ss); + } + } + + auto boundsParam = m_schema.getSelfBoundsProperty(); + if (boundsParam) { + boundsParam.get(ret->m_bounds, ss); + } + + bool smoothNormalsRequired = ret->smoothNormalsRequired(); + + if (smoothNormalsRequired) + { + ret->computeSmoothNormals(m_config); + } + + if (ret->tangentsRequired()) + { + const abcV3 *normals = 0; + bool indexedNormals = false; + + if (smoothNormalsRequired) + { + normals = &ret->m_smoothNormals[0]; + } + else if (ret->m_normals.valid()) + { + normals = ret->m_normals.getVals()->get(); + indexedNormals = (ret->m_normals.getScope() == AbcGeom::kFacevaryingScope); + } + + if (normals && ret->m_uvs.valid()) + { + // topology may be shared, check tangent indices + if (ret->m_topology->m_tangentIndices.empty() || !m_config.cacheTangentsSplits) + { + ret->computeTangentIndices(m_config, normals, indexedNormals); + } + + ret->computeTangents(m_config, normals, indexedNormals); + } + } + + + if (m_config.shareVertices && ret != NULL && !ret->m_ownTopology && topologyChanged) + GenerateVerticesToFacesLookup(ret); + + return ret; +} + +// generates two lookup tables: +// m_FaceIndexingReindexed : for each face in the abc sample, hold an index value to lookup in m_FixedTopoPositionsIndexes, that will give final position index. +// m_FixedTopoPositionsIndexes : list of resulting positions. value is index into the abc "position" vector. size is greter than or equal to "position" array. +void aiPolyMesh::GenerateVerticesToFacesLookup(aiPolyMeshSample *sample) +{ + auto faces = sample->m_topology->m_counts; + auto * facesIndices = sample->m_topology->m_indices->get(); + size_t totalFaces = faces->size(); + + // 1st, figure out which face uses wich vertices (for sharing identification) + std::unordered_map< size_t, std::vector> indexesOfFacesValues; + size_t facesIndicesCursor = 0; + for (size_t faceIndex = 0; faceIndex < totalFaces; faceIndex++) + { + size_t faceSize = (size_t)(faces->get()[faceIndex]); + for (size_t i = 0; i < faceSize; ++i, ++facesIndicesCursor) + indexesOfFacesValues[ facesIndices[facesIndicesCursor] ].push_back(facesIndicesCursor); + } + + // 2nd, figure out which vertex can be merged, which cannot. + // If all faces targetting a vertex give it the same normal and UV, then it can be shared. + std::unordered_map< size_t, std::vector>::iterator itr = indexesOfFacesValues.begin(); + + const abcV3 * normals = sample->m_normals.getVals()->get(); + bool normalsIndexed = (sample->m_normals.getScope() == AbcGeom::kFacevaryingScope); + const Util::uint32_t *Nidxs = normalsIndexed ? sample->m_normals.getIndices()->get() : NULL; + + const auto &uvVals = *(sample->m_uvs.getVals()); + const auto &uvIdxs = *(sample->m_uvs.getIndices()); + + sample->m_topology->m_FixedTopoPositionsIndexes.clear(); + sample->m_topology->m_FaceIndexingReindexed.clear(); + sample->m_topology->m_FaceIndexingReindexed.resize( sample->m_topology->m_indices->size() ); + sample->m_topology->m_FixedTopoPositionsIndexes.reserve(sample->m_positions->size()); + + while (itr != indexesOfFacesValues.end()) + { + size_t faceValueIndex = itr->first; + std::vector::iterator indexItr = itr->second.begin(); + const Abc::V2f * prevUV = NULL; + const abcV3 * prevN = NULL; + bool share = true; + do + { + size_t index = facesIndices[faceValueIndex]; + // same Normal? + const abcV3 & N = normals[Nidxs ? Nidxs[index] : index]; + if (prevN == NULL) + prevN = &N; + else + share = N == *prevN; + + // Same UV? + const Abc::V2f & uv = uvVals[uvIdxs[index]]; + if (prevUV == NULL) + prevUV = &uv; + else + share = uv == *prevUV; + } + while (share && ++indexItr != itr->second.end()); + + // Verdict is in for this vertex. + if (share) + sample->m_topology->m_FixedTopoPositionsIndexes.push_back(itr->first); + + indexItr = itr->second.begin(); + while( indexItr != itr->second.end() ) + { + if (!share) + sample->m_topology->m_FixedTopoPositionsIndexes.push_back(itr->first); + + sample->m_topology->m_FaceIndexingReindexed[*indexItr] = sample->m_topology->m_FixedTopoPositionsIndexes.size() - 1; + + ++indexItr; + } + ++itr; + } + + // We now have a lookup for face value indexes that re-routes to shared indexes when possible! +} + +int aiPolyMesh::getTopologyVariance() const +{ + return (int) m_schema.getTopologyVariance(); +} + + +void aiPolyMesh::updatePeakIndexCount() const +{ + if (m_peakIndexCount != 0) { return; } + + DebugLog("aiPolyMesh::updateMaxIndex()"); + + Util::Dimensions dim; + Abc::Int32ArraySamplePtr counts; + + auto indicesProp = m_schema.getFaceIndicesProperty(); + auto countsProp = m_schema.getFaceCountsProperty(); + + int numSamples = (int)indicesProp.getNumSamples(); + if (numSamples == 0) { return; } + + size_t cMax = 0; + if (indicesProp.isConstant()) + { + auto ss = Abc::ISampleSelector(int64_t(0)); + countsProp.get(counts, ss); + indicesProp.getDimensions(dim, ss); + cMax = dim.numPoints(); + } + else + { + aiLogger::Info("Checking %d sample(s)", numSamples); + + int iMax = 0; + + for (int i = 0; i < numSamples; ++i) + { + indicesProp.getDimensions(dim, Abc::ISampleSelector(int64_t(i))); + + size_t numIndices = dim.numPoints(); + + if (numIndices > cMax) + { + cMax = numIndices; + iMax = i; + } + } + + countsProp.get(counts, Abc::ISampleSelector(int64_t(iMax))); + } + + m_peakIndexCount = (int)cMax; + m_peakTriangulatedIndexCount = CalculateTriangulatedIndexCount(*counts); +} + +int aiPolyMesh::getPeakIndexCount() const +{ + updatePeakIndexCount(); + return m_peakTriangulatedIndexCount; +} + +int aiPolyMesh::getPeakTriangulatedIndexCount() const +{ + updatePeakIndexCount(); + return m_peakTriangulatedIndexCount; +} + +int aiPolyMesh::getPeakVertexCount() const +{ + if (m_peakVertexCount == 0) + { + DebugLog("aiPolyMesh::getPeakVertexCount()"); + + Util::Dimensions dim; + + auto positionsProp = m_schema.getPositionsProperty(); + + int numSamples = (int)positionsProp.getNumSamples(); + + if (numSamples == 0) + { + return 0; + } + else if (positionsProp.isConstant()) + { + positionsProp.getDimensions(dim, Abc::ISampleSelector(int64_t(0))); + + m_peakVertexCount = (int)dim.numPoints(); + } + else + { + m_peakVertexCount = 0; + + for (int i = 0; i < numSamples; ++i) + { + positionsProp.getDimensions(dim, Abc::ISampleSelector(int64_t(i))); + + size_t numVertices = dim.numPoints(); + + if (numVertices > size_t(m_peakVertexCount)) + { + m_peakVertexCount = int(numVertices); + } + } + } + } + + return m_peakVertexCount; +} + +void aiPolyMesh::getSummary(aiMeshSummary &summary) const +{ + DebugLog("aiPolyMesh::getSummary()"); + + summary.topologyVariance = getTopologyVariance(); + summary.peakVertexCount = getPeakVertexCount(); + summary.peakIndexCount = getPeakIndexCount(); + summary.peakTriangulatedIndexCount = getPeakTriangulatedIndexCount(); + summary.peakSubmeshCount = ceildiv(summary.peakIndexCount, 64998); +} + diff --git a/Plugin/abci/Importer/aiPolyMesh.h b/Plugin/abci/Importer/aiPolyMesh.h index 37efe8bcf..ac20b9cf8 100644 --- a/Plugin/abci/Importer/aiPolyMesh.h +++ b/Plugin/abci/Importer/aiPolyMesh.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once typedef std::vector Faceset; typedef std::vector Facesets; @@ -43,6 +43,8 @@ struct SplitInfo size_t indexOffset; size_t vertexCount; size_t submeshCount; + std::unordered_map verticiesXRefs; // org face index (not it's refred value), index in position vector + size_t uniqueValues; inline SplitInfo(size_t ff=0, size_t io=0) : firstFace(ff) @@ -136,13 +138,13 @@ class Topology int getTriangulatedIndexCount() const; int getSplitCount() const; - int getSplitCount(bool forceRefresh); + int getSplitCount(aiPolyMeshSample * meshSample, bool forceRefresh); - void updateSplits(); + void updateSplits(aiPolyMeshSample * meshSample); int getVertexBufferLength(int splitIndex) const; - int prepareSubmeshes(const AbcGeom::IV2fGeomParam::Sample &uvs, const aiFacesets &inFacesets, bool submeshPerUVTile); + int prepareSubmeshes(const AbcGeom::IV2fGeomParam::Sample &uvs, const aiFacesets &inFacesets, bool submeshPerUVTile, aiPolyMeshSample* sample); int getSplitSubmeshCount(int splitIndex) const; inline Submeshes::iterator submeshBegin() { return m_submeshes.begin(); } @@ -151,6 +153,8 @@ class Topology inline Submeshes::const_iterator submeshBegin() const { return m_submeshes.begin(); } inline Submeshes::const_iterator submeshEnd() const { return m_submeshes.end(); } + inline void EnableVertexSharing(bool value) { m_vertexSharingEnabled = value; } + public: Abc::Int32ArraySamplePtr m_indices; Abc::Int32ArraySamplePtr m_counts; @@ -162,6 +166,11 @@ class Topology std::vector m_tangentIndices; size_t m_tangentsCount; + + std::vector m_FixedTopoPositionsIndexes; + std::vector m_FaceIndexingReindexed; + + bool m_vertexSharingEnabled; }; // --- @@ -170,7 +179,7 @@ class aiPolyMeshSample : public aiSampleBase { typedef aiSampleBase super; public: - aiPolyMeshSample(aiPolyMesh *schema, Topology *topo, bool ownTopo); + aiPolyMeshSample(aiPolyMesh *schema, Topology *topo, bool ownTopo, bool vertexSharingEnabled ); virtual ~aiPolyMeshSample(); void updateConfig(const aiConfig &config, bool &topoChanged, bool &dataChanged) override; @@ -181,7 +190,7 @@ typedef aiSampleBase super; bool smoothNormalsRequired() const; bool tangentsRequired() const; - void getSummary(bool forceRefresh, aiMeshSampleSummary &summary) const; + void getSummary(bool forceRefresh, aiMeshSampleSummary &summary, aiPolyMeshSample* sample) const; void getDataPointer(aiPolyMeshData &data); void copyData(aiPolyMeshData &data); void copyDataWithTriangulation(aiPolyMeshData &data, bool always_expand_indices); @@ -193,7 +202,7 @@ typedef aiSampleBase super; int getVertexBufferLength(int splitIndex) const; void fillVertexBuffer(int splitIndex, aiPolyMeshData &data); - int prepareSubmeshes(const aiFacesets &inFacesets); + int prepareSubmeshes(aiPolyMeshSample* sample, const aiFacesets &inFacesets); int getSplitSubmeshCount(int splitIndex) const; bool getNextSubmesh(aiSubmeshSummary &summary); void fillSubmeshIndices(const aiSubmeshSummary &summary, aiSubmeshData &data) const; @@ -212,6 +221,7 @@ typedef aiSampleBase super; std::vector m_tangents; Submeshes::iterator m_curSubmesh; + bool m_vertexSharingEnabled; }; @@ -239,6 +249,7 @@ typedef aiTSchema super; private: void updatePeakIndexCount() const; + void GenerateVerticesToFacesLookup(aiPolyMeshSample *sample); private: mutable int m_peakIndexCount;