@@ -584,190 +584,6 @@ core::smart_refctd_ptr<ICPUMeshBuffer> IMeshManipulator::calculateSmoothNormals(
584584 return outbuffer;
585585}
586586
587- // Used by createMeshBufferWelded only
588- static bool cmpVertices(ICPUMeshBuffer* _inbuf, const void* _va, const void* _vb, size_t _vsize, const IMeshManipulator::SErrorMetric* _errMetrics)
589- {
590- auto cmpInteger = [](uint32_t* _a, uint32_t* _b, size_t _n) -> bool {
591- return !memcmp(_a, _b, _n*4);
592- };
593-
594- constexpr uint32_t MAX_ATTRIBS = ICPUMeshBuffer::MAX_VERTEX_ATTRIB_COUNT;
595-
596- const uint8_t* va = reinterpret_cast<const uint8_t*>(_va), *vb = reinterpret_cast<const uint8_t*>(_vb);
597- for (size_t i = 0u; i < MAX_ATTRIBS; ++i)
598- {
599- if (!_inbuf->isAttributeEnabled(i))
600- continue;
601-
602- const auto atype = _inbuf->getAttribFormat(i);
603- const auto cpa = getFormatChannelCount(atype);
604-
605- if (isIntegerFormat(atype) || isScaledFormat(atype))
606- {
607- uint32_t attr[8];
608- ICPUMeshBuffer::getAttribute(attr, va, atype);
609- ICPUMeshBuffer::getAttribute(attr+4, vb, atype);
610- if (!cmpInteger(attr, attr+4, cpa))
611- return false;
612- }
613- else
614- {
615- core::vectorSIMDf attr[2];
616- ICPUMeshBuffer::getAttribute(attr[0], va, atype);
617- ICPUMeshBuffer::getAttribute(attr[1], vb, atype);
618- if (!IMeshManipulator::compareFloatingPointAttribute(attr[0], attr[1], cpa, _errMetrics[i]))
619- return false;
620- }
621-
622- const uint32_t sz = getTexelOrBlockBytesize(atype);
623- va += sz;
624- vb += sz;
625- }
626-
627- return true;
628- }
629-
630- //! Creates a copy of a mesh, which will have identical vertices welded together
631- core::smart_refctd_ptr<ICPUMeshBuffer> IMeshManipulator::createMeshBufferWelded(ICPUMeshBuffer *inbuffer, const SErrorMetric* _errMetrics, const bool& optimIndexType, const bool& makeNewMesh)
632- {
633- if (!inbuffer || !inbuffer->getPipeline())
634- return nullptr;
635-
636- constexpr uint32_t MAX_ATTRIBS = ICPUMeshBuffer::MAX_VERTEX_ATTRIB_COUNT;
637-
638- bool bufferPresent[MAX_ATTRIBS];
639-
640- size_t vertexAttrSize[MAX_ATTRIBS];
641- size_t vertexSize = 0;
642- for (size_t i=0; i<MAX_ATTRIBS; i++)
643- {
644- const auto& buf = inbuffer->getAttribBoundBuffer(i).buffer;
645- bufferPresent[i] = inbuffer->isAttributeEnabled(i);
646- if (bufferPresent[i] && buf)
647- {
648- const E_FORMAT componentType = inbuffer->getAttribFormat(i);
649- vertexAttrSize[i] = getTexelOrBlockBytesize(componentType);
650- vertexSize += vertexAttrSize[i];
651- }
652- }
653-
654- auto cmpfunc = [&, inbuffer, vertexSize, _errMetrics](const void* _va, const void* _vb) {
655- return cmpVertices(inbuffer, _va, _vb, vertexSize, _errMetrics);
656- };
657-
658- const uint32_t vertexCount = IMeshManipulator::upperBoundVertexID(inbuffer);
659- const E_INDEX_TYPE oldIndexType = inbuffer->getIndexType();
660-
661- if (!vertexCount)
662- return nullptr;
663-
664- // reset redirect list
665- uint32_t* redirects = new uint32_t[vertexCount];
666-
667- uint32_t maxRedirect = 0;
668-
669- uint8_t* epicData = reinterpret_cast<uint8_t*>(_NBL_ALIGNED_MALLOC(vertexSize*vertexCount,_NBL_SIMD_ALIGNMENT));
670- for (auto i=0u; i<vertexCount; i++)
671- {
672- uint8_t* currentVertexPtr = epicData+i*vertexSize;
673- for (size_t k=0; k<MAX_ATTRIBS; k++)
674- {
675- if (!bufferPresent[k])
676- continue;
677-
678- size_t stride = inbuffer->getAttribStride(k);
679- uint8_t* sourcePtr = inbuffer->getAttribPointer(k) + i*stride;
680- memcpy(currentVertexPtr,sourcePtr,vertexAttrSize[k]);
681- currentVertexPtr += vertexAttrSize[k];
682- }
683- }
684-
685- for (auto i=0u; i<vertexCount; i++)
686- {
687- uint32_t redir = i;
688- for (auto j=0u; j<vertexCount; ++j) // TODO: Use spatial hash for this like in the smooth normal computation @Przemog
689- {
690- if (i == j)
691- continue;
692- if (cmpfunc(epicData+vertexSize*i, epicData+vertexSize*j))
693- {
694- redir = j;
695- break;
696- }
697- }
698-
699- redirects[i] = redir;
700- if (redir>maxRedirect)
701- maxRedirect = redir;
702- }
703- _NBL_ALIGNED_FREE(epicData);
704-
705- void* oldIndices = inbuffer->getIndices();
706- core::smart_refctd_ptr<ICPUMeshBuffer> clone;
707- if (makeNewMesh)
708- clone = core::smart_refctd_ptr_static_cast<ICPUMeshBuffer>(inbuffer->clone(0u));
709- else
710- {
711- if (!oldIndices)
712- {
713- inbuffer->setIndexBufferBinding({ 0u, ICPUBuffer::create({ (maxRedirect >= 0x10000u ? sizeof(uint32_t) : sizeof(uint16_t)) * inbuffer->getIndexCount() }) });
714- inbuffer->setIndexType(maxRedirect>=0x10000u ? EIT_32BIT:EIT_16BIT);
715- }
716- }
717-
718- // TODO: reduce the code duplication via the use of a generic lambda (with a `auto*`)
719- if (oldIndexType==EIT_16BIT)
720- {
721- uint16_t* indicesIn = reinterpret_cast<uint16_t*>(oldIndices);
722- if ((makeNewMesh ? clone.get():inbuffer)->getIndexType()==EIT_32BIT)
723- {
724- uint32_t* indicesOut = reinterpret_cast<uint32_t*>((makeNewMesh ? clone.get():inbuffer)->getIndices());
725- for (size_t i=0; i<inbuffer->getIndexCount(); i++)
726- indicesOut[i] = redirects[indicesIn[i]];
727- }
728- else if ((makeNewMesh ? clone.get():inbuffer)->getIndexType()==EIT_16BIT)
729- {
730- uint16_t* indicesOut = reinterpret_cast<uint16_t*>((makeNewMesh ? clone.get():inbuffer)->getIndices());
731- for (size_t i=0; i<inbuffer->getIndexCount(); i++)
732- indicesOut[i] = redirects[indicesIn[i]];
733- }
734- }
735- else if (oldIndexType==EIT_32BIT)
736- {
737- uint32_t* indicesIn = reinterpret_cast<uint32_t*>(oldIndices);
738- if ((makeNewMesh ? clone.get():inbuffer)->getIndexType()==EIT_32BIT)
739- {
740- uint32_t* indicesOut = reinterpret_cast<uint32_t*>((makeNewMesh ? clone.get():inbuffer)->getIndices());
741- for (size_t i=0; i<inbuffer->getIndexCount(); i++)
742- indicesOut[i] = redirects[indicesIn[i]];
743- }
744- else if ((makeNewMesh ? clone.get():inbuffer)->getIndexType()==EIT_16BIT)
745- {
746- uint16_t* indicesOut = reinterpret_cast<uint16_t*>((makeNewMesh ? clone.get():inbuffer)->getIndices());
747- for (size_t i=0; i<inbuffer->getIndexCount(); i++)
748- indicesOut[i] = redirects[indicesIn[i]];
749- }
750- }
751- else if ((makeNewMesh ? clone.get():inbuffer)->getIndexType()==EIT_32BIT)
752- {
753- uint32_t* indicesOut = reinterpret_cast<uint32_t*>((makeNewMesh ? clone.get():inbuffer)->getIndices());
754- for (size_t i=0; i<inbuffer->getIndexCount(); i++)
755- indicesOut[i] = redirects[i];
756- }
757- else if ((makeNewMesh ? clone.get():inbuffer)->getIndexType()==EIT_16BIT)
758- {
759- uint16_t* indicesOut = reinterpret_cast<uint16_t*>((makeNewMesh ? clone.get():inbuffer)->getIndices());
760- for (size_t i=0; i<inbuffer->getIndexCount(); i++)
761- indicesOut[i] = redirects[i];
762- }
763- delete [] redirects;
764-
765- if (makeNewMesh)
766- return clone;
767- else
768- return core::smart_refctd_ptr<ICPUMeshBuffer>(inbuffer);
769- }
770-
771587core::smart_refctd_ptr<ICPUMeshBuffer> IMeshManipulator::createOptimizedMeshBuffer(const ICPUMeshBuffer* _inbuffer, const SErrorMetric* _errMetric)
772588{
773589 if (!_inbuffer)
0 commit comments