diff --git a/examples_tests b/examples_tests index 24e5f12d88..4a01642e0e 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 24e5f12d88d43695eed5b393d0480dc75c951198 +Subproject commit 4a01642e0e1f27519c8861688d39952a2bc612db diff --git a/include/nbl/asset/interchange/IGeometryWriter.h b/include/nbl/asset/interchange/IGeometryWriter.h index d7e7ab964a..3448a031f6 100644 --- a/include/nbl/asset/interchange/IGeometryWriter.h +++ b/include/nbl/asset/interchange/IGeometryWriter.h @@ -26,6 +26,8 @@ class IGeometryWriter : public IAssetWriter private: }; +inline IGeometryWriter::~IGeometryWriter() { } + } #endif diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index e7193e3eaf..93e95a427c 100755 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -52,10 +52,10 @@ include(common) option(_NBL_COMPILE_WITH_MTL_LOADER_ "Compile with MTL Loader" OFF) #default off until Material Compiler 2 option(_NBL_COMPILE_WITH_OBJ_LOADER_ "Compile with OBJ Loader" OFF) #default off until Material Compiler 2 #option(_NBL_COMPILE_WITH_OBJ_WRITER_ "Compile with OBJ Writer" ON) uncomment when writer exists -option(_NBL_COMPILE_WITH_STL_LOADER_ "Compile with STL Loader" OFF) #default off until reimplemented -option(_NBL_COMPILE_WITH_STL_WRITER_ "Compile with STL Writer" OFF) #default off until reimplemented +option(_NBL_COMPILE_WITH_STL_LOADER_ "Compile with STL Loader" ON) +option(_NBL_COMPILE_WITH_STL_WRITER_ "Compile with STL Writer" ON) option(_NBL_COMPILE_WITH_PLY_LOADER_ "Compile with PLY Loader" ON) -option(_NBL_COMPILE_WITH_PLY_WRITER_ "Compile with PLY Writer" OFF) #default off until reimplemented +option(_NBL_COMPILE_WITH_PLY_WRITER_ "Compile with PLY Writer" ON) option(_NBL_COMPILE_WITH_JPG_LOADER_ "Compile with JPG Loader" ON) option(_NBL_COMPILE_WITH_JPG_WRITER_ "Compile with JPG Writer" ON) option(_NBL_COMPILE_WITH_PNG_LOADER_ "Compile with PNG Loader" ON) diff --git a/src/nbl/asset/IAssetManager.cpp b/src/nbl/asset/IAssetManager.cpp index 344429f227..0c1b4493a1 100644 --- a/src/nbl/asset/IAssetManager.cpp +++ b/src/nbl/asset/IAssetManager.cpp @@ -121,7 +121,7 @@ void IAssetManager::initializeMeshTools() void IAssetManager::addLoadersAndWriters() { #ifdef _NBL_COMPILE_WITH_STL_LOADER_ - addAssetLoader(core::make_smart_refctd_ptr(this)); + addAssetLoader(core::make_smart_refctd_ptr()); #endif #ifdef _NBL_COMPILE_WITH_PLY_LOADER_ addAssetLoader(core::make_smart_refctd_ptr()); diff --git a/src/nbl/asset/interchange/CPLYMeshFileLoader.cpp b/src/nbl/asset/interchange/CPLYMeshFileLoader.cpp index 932a04b82c..ffc1aa3eb1 100644 --- a/src/nbl/asset/interchange/CPLYMeshFileLoader.cpp +++ b/src/nbl/asset/interchange/CPLYMeshFileLoader.cpp @@ -63,21 +63,23 @@ struct SContext { static E_FORMAT getType(const char* typeString) { - if (strcmp(typeString, "char")==0 || strcmp(typeString, "int8")==0) + if (strcmp(typeString, "char") == 0 || strcmp(typeString, "int8") == 0) return EF_R8_SINT; - else if (strcmp(typeString, "uchar")==0 || strcmp(typeString, "uint8")==0) + else if (strcmp(typeString, "uchar") == 0 || strcmp(typeString, "uint8") == 0) return EF_R8_UINT; - else if (strcmp(typeString, "short")==0 || strcmp(typeString, "int16")==0) + else if (strcmp(typeString, "short") == 0 || strcmp(typeString, "int16") == 0) return EF_R16_SINT; - else if (strcmp(typeString, "ushort")==0 || strcmp(typeString, "uint16")==0) + else if (strcmp(typeString, "ushort") == 0 || strcmp(typeString, "uint16") == 0) return EF_R16_UINT; - else if (strcmp(typeString, "long")==0 || strcmp(typeString, "int")==0 || strcmp(typeString, "int16")==0) + else if (strcmp(typeString, "long") == 0 || strcmp(typeString, "int") == 0 || strcmp(typeString, "int16") == 0) return EF_R32_SINT; - else if (strcmp(typeString, "ulong")==0 || strcmp(typeString, "uint16")==0) + else if (strcmp(typeString, "ulong") == 0 || strcmp(typeString, "uint16") == 0) return EF_R32_UINT; - else if (strcmp(typeString, "float")==0 || strcmp(typeString, "float32")==0) + else if (strcmp(typeString, "uint") == 0 || strcmp(typeString, "uint32") == 0) + return EF_R32_UINT; + else if (strcmp(typeString, "float") == 0 || strcmp(typeString, "float32") == 0) return EF_R32_SFLOAT; - else if (strcmp(typeString, "double")==0 || strcmp(typeString, "float64")==0) + else if (strcmp(typeString, "double") == 0 || strcmp(typeString, "float64") == 0) return EF_R64_SFLOAT; else return EF_UNKNOWN; diff --git a/src/nbl/asset/interchange/CPLYMeshWriter.cpp b/src/nbl/asset/interchange/CPLYMeshWriter.cpp index fd6fa3ea9e..b4ceae479a 100644 --- a/src/nbl/asset/interchange/CPLYMeshWriter.cpp +++ b/src/nbl/asset/interchange/CPLYMeshWriter.cpp @@ -9,7 +9,6 @@ #include "nbl/system/ISystem.h" #include "nbl/system/IFile.h" -#include "nbl/asset/utils/CMeshManipulator.h" namespace nbl { @@ -57,179 +56,94 @@ CPLYMeshWriter::CPLYMeshWriter() } //! writes a mesh -bool CPLYMeshWriter::writeAsset(system::IFile* _file, const SAssetWriteParams& _params, IAssetWriterOverride* _override) +bool CPLYMeshWriter::writeAsset(system::IFile* _file, const SAssetWriteParams& _params, IAssetWriterOverride* _override) { - if (!_override) - getDefaultOverride(_override); - - SAssetWriteContext inCtx{ _params, _file }; - - const asset::ICPUMesh* mesh = IAsset::castDown(_params.rootAsset); - if (!mesh) - return false; - - system::IFile* file = _override->getOutputFile(_file, inCtx, {mesh, 0u}); - - auto meshbuffers = mesh->getMeshBuffers(); - if (!file || !mesh) - return false; - - SContext context = { SAssetWriteContext{ inCtx.params, file} }; - - if (meshbuffers.size() > 1) - { - #ifdef _NBL_DEBUG - context.writeContext.params.logger.log("PLY WRITER WARNING (" + std::to_string(__LINE__) + " line): Only one meshbuffer input is allowed for writing! Saving first one", system::ILogger::ELL_WARNING, file->getFileName().string().c_str()); - #endif // _NBL_DEBUG - } - - context.writeContext.params.logger.log("Writing PLY mesh", system::ILogger::ELL_INFO, file->getFileName().string().c_str()); - - const asset::E_WRITER_FLAGS flags = _override->getAssetWritingFlags(context.writeContext, mesh, 0u); - - auto getConvertedCpuMeshBufferWithIndexBuffer = [&]() -> core::smart_refctd_ptr - { - auto inputMeshBuffer = *meshbuffers.begin(); - const bool doesItHaveIndexBuffer = inputMeshBuffer->getIndexBufferBinding().buffer.get(); - const bool isItNotTriangleListsPrimitive = inputMeshBuffer->getPipeline()->getCachedCreationParams().primitiveAssembly.primitiveType != asset::EPT_TRIANGLE_LIST; - - if (doesItHaveIndexBuffer && isItNotTriangleListsPrimitive) - { - auto cpuConvertedMeshBuffer = core::smart_refctd_ptr_static_cast(inputMeshBuffer->clone()); - IMeshManipulator::homogenizePrimitiveTypeAndIndices(&cpuConvertedMeshBuffer, &cpuConvertedMeshBuffer + 1, asset::EPT_TRIANGLE_LIST, asset::EIT_32BIT); - return cpuConvertedMeshBuffer; - } - else - return nullptr; - }; - - const auto cpuConvertedMeshBufferWithIndexBuffer = getConvertedCpuMeshBufferWithIndexBuffer(); - const asset::ICPUMeshBuffer* rawCopyMeshBuffer = cpuConvertedMeshBufferWithIndexBuffer.get() ? cpuConvertedMeshBufferWithIndexBuffer.get() : *meshbuffers.begin(); - const bool doesItUseIndexBufferBinding = (rawCopyMeshBuffer->getIndexBufferBinding().buffer.get() && rawCopyMeshBuffer->getIndexType() != asset::EIT_UNKNOWN); - - uint32_t faceCount = {}; - size_t vertexCount = {}; - - void* indices = nullptr; - { - auto indexCount = rawCopyMeshBuffer->getIndexCount(); - - indices = _NBL_ALIGNED_MALLOC(indexCount * sizeof(uint32_t), _NBL_SIMD_ALIGNMENT); - memcpy(indices, rawCopyMeshBuffer->getIndices(), indexCount * sizeof(uint32_t)); - - IMeshManipulator::getPolyCount(faceCount, rawCopyMeshBuffer); - vertexCount = IMeshManipulator::upperBoundVertexID(rawCopyMeshBuffer); - } - - // write PLY header - std::string header = "ply\n"; - header += (flags & asset::EWF_BINARY) ? "format binary_little_endian 1.0" : "format ascii 1.0"; - header += "\ncomment IrrlichtBAW "; - header += NABLA_SDK_VERSION; - - // vertex definition - header += "\nelement vertex "; - header += std::to_string(vertexCount) + '\n'; - - bool vaidToWrite[4]{ 0, 0, 0, 0 }; - - const uint32_t POSITION_ATTRIBUTE = rawCopyMeshBuffer->getPositionAttributeIx(); - constexpr uint32_t COLOR_ATTRIBUTE = 1; - constexpr uint32_t UV_ATTRIBUTE = 2; - const uint32_t NORMAL_ATTRIBUTE = rawCopyMeshBuffer->getNormalAttributeIx(); - - if (rawCopyMeshBuffer->getAttribBoundBuffer(POSITION_ATTRIBUTE).buffer) - { - const asset::E_FORMAT t = rawCopyMeshBuffer->getAttribFormat(POSITION_ATTRIBUTE); - std::string typeStr = getTypeString(t); - vaidToWrite[0] = true; - header += - "property " + typeStr + " x\n" + - "property " + typeStr + " y\n" + - "property " + typeStr + " z\n"; - } - if (rawCopyMeshBuffer->getAttribBoundBuffer(COLOR_ATTRIBUTE).buffer) - { - const asset::E_FORMAT t = rawCopyMeshBuffer->getAttribFormat(COLOR_ATTRIBUTE); - std::string typeStr = getTypeString(t); - vaidToWrite[1] = true; - header += - "property " + typeStr + " red\n" + - "property " + typeStr + " green\n" + - "property " + typeStr + " blue\n"; - if (asset::getFormatChannelCount(t) == 4u) - { - header += "property " + typeStr + " alpha\n"; - } - } - if (rawCopyMeshBuffer->getAttribBoundBuffer(UV_ATTRIBUTE).buffer) - { - const asset::E_FORMAT t = rawCopyMeshBuffer->getAttribFormat(UV_ATTRIBUTE); - std::string typeStr = getTypeString(t); - vaidToWrite[2] = true; - header += - "property " + typeStr + " u\n" + - "property " + typeStr + " v\n"; - } - if (rawCopyMeshBuffer->getAttribBoundBuffer(NORMAL_ATTRIBUTE).buffer) - { - const asset::E_FORMAT t = rawCopyMeshBuffer->getAttribFormat(NORMAL_ATTRIBUTE); - std::string typeStr = getTypeString(t); - vaidToWrite[3] = true; - header += - "property " + typeStr + " nx\n" + - "property " + typeStr + " ny\n" + - "property " + typeStr + " nz\n"; - } - - asset::E_INDEX_TYPE idxT = asset::EIT_UNKNOWN; - bool forceFaces = false; - - const auto primitiveType = rawCopyMeshBuffer->getPipeline()->getCachedCreationParams().primitiveAssembly.primitiveType; - const auto indexType = rawCopyMeshBuffer->getIndexType(); + if (!_override) + getDefaultOverride(_override); + + SAssetWriteContext inCtx{ _params, _file }; + + const asset::ICPUPolygonGeometry* geom = IAsset::castDown(_params.rootAsset); + if (!geom) + return false; + + system::IFile* file = _override->getOutputFile(_file, inCtx, {geom, 0u}); + if (!file || !geom) + return false; + + SContext context = { SAssetWriteContext{ inCtx.params, file} }; + + context.writeContext.params.logger.log("Writing PLY file", system::ILogger::ELL_INFO, file->getFileName().string().c_str()); + + const asset::E_WRITER_FLAGS flags = _override->getAssetWritingFlags(context.writeContext, geom, 0u); + + const auto& idxView = geom->getIndexView(); + const auto& vtxView = geom->getPositionView(); + const auto& normalView = geom->getNormalView(); + const auto& auxAttributes = geom->getAuxAttributeViews(); + + // TODO: quads? + const size_t faceCount = geom->getIndexCount() / 3; + + // indices: + // 0 for vertices (always enabled) + // 1 for normals (optional) + // 2 for vertex colors (optional) + // 3 for texcoords (optional) + bool attrsToWrite[4] = { true, false, false, false }; + + // write PLY header + std::string header = "ply\n"; + header += (flags & asset::EWF_BINARY) ? "format binary_little_endian 1.0" : "format ascii 1.0"; + header += "\ncomment Nabla "; + header += NABLA_SDK_VERSION; + + // vertex definition + header += "\nelement vertex "; + header += std::to_string(vtxView.getElementCount()) + '\n'; + + std::string typeStr = getTypeString(vtxView.composed.format); + header += "property " + typeStr + " x\n" + + "property " + typeStr + " y\n" + + "property " + typeStr + " z\n"; + + if (normalView.getElementCount() > 0) + { + attrsToWrite[1] = true; + std::string typeStr = getTypeString(normalView.composed.format); + header += "property " + typeStr + " nx\n" + + "property " + typeStr + " ny\n" + + "property " + typeStr + " nz\n"; + } + + header += "element face " + std::to_string(faceCount) + '\n'; + header += "property list uchar " + getTypeString(idxView.composed.format) + " vertex_index\n"; + + if (auxAttributes.size() > 0) + for (auto& attr : auxAttributes) + { + // TODO: Texcoords, vertex colors and any additional properties + } - if (primitiveType == asset::EPT_POINT_LIST) - faceCount = 0u; - else if (doesItUseIndexBufferBinding) - { - header += "element face "; - header += std::to_string(faceCount) + '\n'; - idxT = indexType; - const std::string idxTypeStr = idxT == asset::EIT_32BIT ? "uint32" : "uint16"; - header += "property list uchar " + idxTypeStr + " vertex_indices\n"; - } - else if (primitiveType == asset::EPT_TRIANGLE_LIST) - { - forceFaces = true; - - header += "element face "; - header += std::to_string(faceCount) + '\n'; - idxT = vertexCount <= ((1u<<16) - 1) ? asset::EIT_16BIT : asset::EIT_32BIT; - const std::string idxTypeStr = idxT == asset::EIT_32BIT ? "uint32" : "uint16"; - header += "property list uchar " + idxTypeStr + " vertex_indices\n"; - } - else - faceCount = 0u; - header += "end_header\n"; - - { - system::IFile::success_t success; - file->write(success, header.c_str(), context.fileOffset, header.size()); - context.fileOffset += success.getBytesProcessed(); - } - - if (flags & asset::EWF_BINARY) - writeBinary(rawCopyMeshBuffer, vertexCount, faceCount, idxT, indices, forceFaces, vaidToWrite, context); - else - writeText(rawCopyMeshBuffer, vertexCount, faceCount, idxT, indices, forceFaces, vaidToWrite, context); - - _NBL_ALIGNED_FREE(const_cast(indices)); - - return true; + header += "end_header\n"; + + { + system::IFile::success_t success; + context.writeContext.outputFile->write(success, header.data(), context.fileOffset, header.size()); + context.fileOffset += success.getBytesProcessed(); + } + + if (flags & asset::EWF_BINARY) + writeBinary(geom, attrsToWrite, true, context); + else + writeText(geom, attrsToWrite, true, context); + + return true; } -void CPLYMeshWriter::writeBinary(const asset::ICPUMeshBuffer* _mbuf, size_t _vtxCount, size_t _fcCount, asset::E_INDEX_TYPE _idxType, void* const _indices, bool _forceFaces, const bool _vaidToWrite[4], SContext& context) const +void CPLYMeshWriter::writeBinary(const ICPUPolygonGeometry* geom, const bool attrsToWrite[4], bool _forceFaces, SContext& context) const { +#if 0 const size_t colCpa = asset::getFormatChannelCount(_mbuf->getAttribFormat(1)); bool flipVectors = (!(context.writeContext.params.flags & E_WRITER_FLAGS::EWF_MESH_IS_RIGHT_HANDED)) ? true : false; @@ -316,138 +230,43 @@ void CPLYMeshWriter::writeBinary(const asset::ICPUMeshBuffer* _mbuf, size_t _vtx if (_forceFaces) _NBL_ALIGNED_FREE(indices); +#endif } -void CPLYMeshWriter::writeText(const asset::ICPUMeshBuffer* _mbuf, size_t _vtxCount, size_t _fcCount, asset::E_INDEX_TYPE _idxType, void* const _indices, bool _forceFaces, const bool _vaidToWrite[4], SContext& context) const +void CPLYMeshWriter::writeText(const ICPUPolygonGeometry* geom, const bool attrsToWrite[4], bool _forceFaces, SContext& context) const { - auto mbCopy = createCopyMBuffNormalizedReplacedWithTrueInt(_mbuf); - - auto writefunc = [&context, &mbCopy, this](uint32_t _vaid, size_t _ix, size_t _cpa) - { - bool flipVerteciesAndNormals = false; - if (!(context.writeContext.params.flags & E_WRITER_FLAGS::EWF_MESH_IS_RIGHT_HANDED)) - if(_vaid == 0u || _vaid == 3u) - flipVerteciesAndNormals = true; - - uint32_t ui[4]; - core::vectorSIMDf f; - const asset::E_FORMAT t = mbCopy->getAttribFormat(_vaid); - if (asset::isScaledFormat(t) || asset::isIntegerFormat(t)) - { - mbCopy->getAttribute(ui, _vaid, _ix); - if (!asset::isSignedFormat(t)) - writeVectorAsText(context, ui, _cpa, flipVerteciesAndNormals); - else - { - int32_t ii[4]; - memcpy(ii, ui, 4*4); - writeVectorAsText(context, ii, _cpa, flipVerteciesAndNormals); - } - } - else - { - mbCopy->getAttribute(f, _vaid, _ix); - writeVectorAsText(context, f.pointer, _cpa, flipVerteciesAndNormals); - } - }; - - const size_t colCpa = asset::getFormatChannelCount(_mbuf->getAttribFormat(1)); - - for (size_t i = 0u; i < _vtxCount; ++i) - { - core::vectorSIMDf f; - uint32_t ui[4]; - if (_vaidToWrite[0]) - { - writefunc(0, i, 3u); - } - if (_vaidToWrite[1]) - { - writefunc(1, i, colCpa); - } - if (_vaidToWrite[2]) - { - writefunc(2, i, 2u); - } - if (_vaidToWrite[3]) - { - writefunc(3, i, 3u); - } - - { - system::IFile::success_t success; - context.writeContext.outputFile->write(success, "\n", context.fileOffset, 1); - context.fileOffset += success.getBytesProcessed(); - } - } - - const char* listSize = "3 "; - void* indices = _indices; - if (_forceFaces) - { - indices = _NBL_ALIGNED_MALLOC((_idxType == asset::EIT_32BIT ? 4 : 2) * 3 * _fcCount,_NBL_SIMD_ALIGNMENT); - if (_idxType == asset::EIT_16BIT) - { - for (uint16_t i = 0u; i < _fcCount; ++i) - ((uint16_t*)indices)[i] = i; - } - else - { - for (uint32_t i = 0u; i < _fcCount; ++i) - ((uint32_t*)indices)[i] = i; - } - } - if (_idxType == asset::EIT_32BIT) - { - uint32_t* ind = (uint32_t*)indices; - for (size_t i = 0u; i < _fcCount; ++i) - { - { - system::IFile::success_t success; - context.writeContext.outputFile->write(success, listSize, context.fileOffset, 2); - context.fileOffset += success.getBytesProcessed(); - } - - writeVectorAsText(context, ind, 3); - - { - system::IFile::success_t success; - context.writeContext.outputFile->write(success, "\n", context.fileOffset, 1); - context.fileOffset += success.getBytesProcessed(); - } - - ind += 3; - } - } - else - { - uint16_t* ind = (uint16_t*)indices; - for (size_t i = 0u; i < _fcCount; ++i) - { - { - system::IFile::success_t success; - context.writeContext.outputFile->write(success, listSize, context.fileOffset, 2); - context.fileOffset += success.getBytesProcessed(); - } - - writeVectorAsText(context, ind, 3); - - { - system::IFile::success_t success; - context.writeContext.outputFile->write(success, "\n", context.fileOffset, 1); - context.fileOffset += success.getBytesProcessed(); - } - - ind += 3; - } - } - - if (_forceFaces) - _NBL_ALIGNED_FREE(indices); + auto& posView = geom->getPositionView(); + auto& normalView = geom->getNormalView(); + auto& idxView = geom->getIndexView(); + + std::span positions( + reinterpret_cast(posView.getPointer()), + reinterpret_cast(posView.getPointer(posView.getElementCount())) + ); + + const auto* idxBegPtr = reinterpret_cast(idxView.getPointer()); + std::span indices(idxBegPtr, idxBegPtr + idxView.getElementCount()); + + for (size_t i = 0; i < positions.size(); i++) + writeVertexAsText(context, positions[i], (attrsToWrite[1] ? reinterpret_cast(normalView.getPointer(i)) : nullptr)); + + // write indices + for (size_t i = 0; i < indices.size(); i += 3) + { + std::string str = "3 "; + for (size_t j = 0; j < 3; j++) + str += std::to_string(indices[i + j]) + " "; + str += "\n"; + + system::IFile::success_t success; + context.writeContext.outputFile->write(success, str.data(), context.fileOffset, str.size()); + context.fileOffset += success.getBytesProcessed(); + } } -void CPLYMeshWriter::writeAttribBinary(SContext& context, asset::ICPUMeshBuffer* _mbuf, uint32_t _vaid, size_t _ix, size_t _cpa, bool flipAttribute) const +void CPLYMeshWriter::writeAttribBinary(SContext& context, ICPUPolygonGeometry* geom, uint32_t _vaid, size_t _ix, size_t _cpa, bool flipAttribute) const { +#if 0 uint32_t ui[4]; core::vectorSIMDf f; asset::E_FORMAT t = _mbuf->getAttribFormat(_vaid); @@ -504,10 +323,12 @@ void CPLYMeshWriter::writeAttribBinary(SContext& context, asset::ICPUMeshBuffer* context.fileOffset += success.getBytesProcessed(); } } +#endif } -core::smart_refctd_ptr CPLYMeshWriter::createCopyMBuffNormalizedReplacedWithTrueInt(const asset::ICPUMeshBuffer* _mbuf) +core::smart_refctd_ptr CPLYMeshWriter::createCopyNormalizedReplacedWithTrueInt(const ICPUPolygonGeometry* geom) { +#if 0 auto mbCopy = core::smart_refctd_ptr_static_cast(_mbuf->clone(2)); for (size_t i = 0; i < ICPUMeshBuffer::MAX_VERTEX_ATTRIB_COUNT; ++i) @@ -520,6 +341,8 @@ core::smart_refctd_ptr CPLYMeshWriter::createCopyMBuffNor } return mbCopy; +#endif + return nullptr; } std::string CPLYMeshWriter::getTypeString(asset::E_FORMAT _t) diff --git a/src/nbl/asset/interchange/CPLYMeshWriter.h b/src/nbl/asset/interchange/CPLYMeshWriter.h index e709ffa0fe..c099451858 100644 --- a/src/nbl/asset/interchange/CPLYMeshWriter.h +++ b/src/nbl/asset/interchange/CPLYMeshWriter.h @@ -41,8 +41,8 @@ class CPLYMeshWriter : public IGeometryWriter size_t fileOffset = 0; }; - void writeBinary(const ICPUPolygonGeometry* geom, size_t _vtxCount, size_t _fcCount, asset::E_INDEX_TYPE _idxType, void* const _indices, bool _forceFaces, const bool _vaidToWrite[4], SContext& context) const; - void writeText(const ICPUPolygonGeometry* geom, size_t _vtxCount, size_t _fcCount, asset::E_INDEX_TYPE _idxType, void* const _indices, bool _forceFaces, const bool _vaidToWrite[4], SContext& context) const; + void writeBinary(const ICPUPolygonGeometry* geom, const bool attrsToWrite[4], bool _forceFaces, SContext& context) const; + void writeText(const ICPUPolygonGeometry* geom, const bool attrsToWrite[4], bool _forceFaces, SContext& context) const; void writeAttribBinary(SContext& context, ICPUPolygonGeometry* geom, uint32_t _vaid, size_t _ix, size_t _cpa, bool flipAttribute = false) const; @@ -51,27 +51,23 @@ class CPLYMeshWriter : public IGeometryWriter static std::string getTypeString(asset::E_FORMAT _t); - template - void writeVectorAsText(SContext& context, const T* _vec, size_t _elementsToWrite, bool flipVectors = false) const + inline void writeVertexAsText(SContext& context, const hlsl::float32_t3& pos, const hlsl::float32_t3* normal) const { - constexpr size_t xID = 0u; - std::stringstream ss; - ss << std::fixed; - bool currentFlipOnVariable = false; - for (size_t i = 0u; i < _elementsToWrite; ++i) - { - if (flipVectors && i == xID) - currentFlipOnVariable = true; - else - currentFlipOnVariable = false; - - ss << std::setprecision(6) << _vec[i] * (currentFlipOnVariable ? -1 : 1) << " "; - } - auto str = ss.str(); - - system::IFile::success_t succ; - context.writeContext.outputFile->write(succ, str.c_str(), context.fileOffset, str.size()); - context.fileOffset += succ.getBytesProcessed(); + std::stringstream ss; + ss << std::fixed << std::setprecision(6) << pos.x << " " << pos.y << " " << pos.z; + + if (normal) + { + ss << " " << normal->x << " " << normal->y << " " << normal->z << "\n"; + } + else + ss << "\n"; + + const auto& str = ss.str(); + + system::IFile::success_t success; + context.writeContext.outputFile->write(success, str.data(), context.fileOffset, str.size()); + context.fileOffset += success.getBytesProcessed(); } }; diff --git a/src/nbl/asset/interchange/CSTLMeshFileLoader.cpp b/src/nbl/asset/interchange/CSTLMeshFileLoader.cpp index d00c37cf10..444c26bad7 100644 --- a/src/nbl/asset/interchange/CSTLMeshFileLoader.cpp +++ b/src/nbl/asset/interchange/CSTLMeshFileLoader.cpp @@ -22,108 +22,126 @@ constexpr auto COLOR_ATTRIBUTE = 1; constexpr auto UV_ATTRIBUTE = 2; constexpr auto NORMAL_ATTRIBUTE = 3; -CSTLMeshFileLoader::CSTLMeshFileLoader(asset::IAssetManager* _m_assetMgr) - : IRenderpassIndependentPipelineLoader(_m_assetMgr), m_assetMgr(_m_assetMgr) +struct Vec3Hasher { - -} + size_t operator()(const hlsl::float32_t3& v) const + { + return std::hash()(v.x) ^ (std::hash()(v.y) << 1) ^ (std::hash()(v.z) << 2); + } +}; -void CSTLMeshFileLoader::initialize() +struct SContext { - IRenderpassIndependentPipelineLoader::initialize(); + IAssetLoader::SAssetLoadContext inner; + uint32_t topHierarchyLevel; + IAssetLoader::IAssetLoaderOverride* loaderOverride; - auto precomputeAndCachePipeline = [&](bool withColorAttribute) + size_t fileOffset = {}; + + // skips to the first non-space character available + void goNextWord() { - auto getShaderDefaultPaths = [&]() -> std::pair - { - if (withColorAttribute) - return std::make_pair("nbl/builtin/material/debug/vertex_color/specialized_shader.vert", "nbl/builtin/material/debug/vertex_color/specialized_shader.frag"); - else - return std::make_pair("nbl/builtin/material/debug/vertex_normal/specialized_shader.vert", "nbl/builtin/material/debug/vertex_normal/specialized_shader.frag"); - }; - - auto defaultOverride = IAssetLoaderOverride(m_assetMgr); - const std::string pipelineCacheHash = getPipelineCacheKey(withColorAttribute).data(); - const uint32_t _hierarchyLevel = 0; - const IAssetLoader::SAssetLoadContext fakeContext(IAssetLoader::SAssetLoadParams{}, nullptr); - - const asset::IAsset::E_TYPE types[]{ asset::IAsset::ET_RENDERPASS_INDEPENDENT_PIPELINE, (asset::IAsset::E_TYPE)0u }; - auto pipelineBundle = defaultOverride.findCachedAsset(pipelineCacheHash, types, fakeContext, _hierarchyLevel + ICPURenderpassIndependentPipeline::DESC_SET_HIERARCHYLEVELS_BELOW); - if (pipelineBundle.getContents().empty()) + uint8_t c; + while (fileOffset != inner.mainFile->getSize()) // TODO: check it { - auto mbVertexShader = core::smart_refctd_ptr(); - auto mbFragmentShader = core::smart_refctd_ptr(); - { - const IAsset::E_TYPE types[]{ IAsset::E_TYPE::ET_SPECIALIZED_SHADER, static_cast(0u) }; - const auto shaderPaths = getShaderDefaultPaths(); - - auto vertexShaderBundle = m_assetMgr->findAssets(shaderPaths.first.data(), types); - auto fragmentShaderBundle = m_assetMgr->findAssets(shaderPaths.second.data(), types); + system::IFile::success_t success; + inner.mainFile->read(success, &c, fileOffset, sizeof(c)); + fileOffset += success.getBytesProcessed(); - mbVertexShader = core::smart_refctd_ptr_static_cast(vertexShaderBundle->begin()->getContents().begin()[0]); - mbFragmentShader = core::smart_refctd_ptr_static_cast(fragmentShaderBundle->begin()->getContents().begin()[0]); + // found it, so leave + if (!core::isspace(c)) + { + fileOffset -= success.getBytesProcessed(); + break; } + } + } - auto defaultOverride = IAssetLoaderOverride(m_assetMgr); + // returns the next word + const std::string& getNextToken(std::string& token) + { + goNextWord(); + char c; + token = ""; - const IAssetLoader::SAssetLoadContext fakeContext(IAssetLoader::SAssetLoadParams{}, nullptr); - auto mbBundlePipelineLayout = defaultOverride.findDefaultAsset("nbl/builtin/pipeline_layout/loader/STL", fakeContext, _hierarchyLevel + ICPURenderpassIndependentPipeline::PIPELINE_LAYOUT_HIERARCHYLEVELS_BELOW); - auto mbPipelineLayout = mbBundlePipelineLayout.first; + while (fileOffset != inner.mainFile->getSize()) + { + system::IFile::success_t success; + inner.mainFile->read(success, &c, fileOffset, sizeof(c)); + fileOffset += success.getBytesProcessed(); - auto const positionFormatByteSize = getTexelOrBlockBytesize(EF_R32G32B32_SFLOAT); - auto const colorFormatByteSize = withColorAttribute ? getTexelOrBlockBytesize(EF_B8G8R8A8_UNORM) : 0; - auto const normalFormatByteSize = getTexelOrBlockBytesize(EF_A2B10G10R10_SNORM_PACK32); + // found it, so leave + if (core::isspace(c)) + break; + token += c; + } + return token; + } - SVertexInputParams mbInputParams; - const auto stride = positionFormatByteSize + colorFormatByteSize + normalFormatByteSize; - mbInputParams.enabledBindingFlags |= core::createBitmask({ 0 }); - mbInputParams.enabledAttribFlags |= core::createBitmask({ POSITION_ATTRIBUTE, NORMAL_ATTRIBUTE, withColorAttribute ? COLOR_ATTRIBUTE : 0 }); - mbInputParams.bindings[0] = { stride, EVIR_PER_VERTEX }; + // skip to next printable character after the first line break + void goNextLine() + { + uint8_t c; + // look for newline characters + while (fileOffset != inner.mainFile->getSize()) // TODO: check it + { + system::IFile::success_t success; + inner.mainFile->read(success, &c, fileOffset, sizeof(c)); + fileOffset += success.getBytesProcessed(); - mbInputParams.attributes[POSITION_ATTRIBUTE].format = EF_R32G32B32_SFLOAT; - mbInputParams.attributes[POSITION_ATTRIBUTE].relativeOffset = 0; - mbInputParams.attributes[POSITION_ATTRIBUTE].binding = 0; + // found it, so leave + if (c == '\n' || c == '\r') + break; + } + } - if (withColorAttribute) + //! Read 3d vector of floats + void getNextVector(hlsl::float32_t3& vec, bool binary) + { + if (binary) + { { - mbInputParams.attributes[COLOR_ATTRIBUTE].format = EF_R32G32B32_SFLOAT; - mbInputParams.attributes[COLOR_ATTRIBUTE].relativeOffset = positionFormatByteSize; - mbInputParams.attributes[COLOR_ATTRIBUTE].binding = 0; + system::IFile::success_t success; + inner.mainFile->read(success, &vec.x, fileOffset, 4); + fileOffset += success.getBytesProcessed(); } - mbInputParams.attributes[NORMAL_ATTRIBUTE].format = EF_R32G32B32_SFLOAT; - mbInputParams.attributes[NORMAL_ATTRIBUTE].relativeOffset = positionFormatByteSize + colorFormatByteSize; - mbInputParams.attributes[NORMAL_ATTRIBUTE].binding = 0; - - SBlendParams blendParams; - SPrimitiveAssemblyParams primitiveAssemblyParams; - primitiveAssemblyParams.primitiveType = E_PRIMITIVE_TOPOLOGY::EPT_TRIANGLE_LIST; - - SRasterizationParams rastarizationParmas; - - auto mbPipeline = core::make_smart_refctd_ptr(std::move(mbPipelineLayout), nullptr, nullptr, mbInputParams, blendParams, primitiveAssemblyParams, rastarizationParmas); { - mbPipeline->setShaderAtStage(asset::IShader::ESS_VERTEX, mbVertexShader.get()); - mbPipeline->setShaderAtStage(asset::IShader::ESS_FRAGMENT, mbFragmentShader.get()); + system::IFile::success_t success; + inner.mainFile->read(success, &vec.y, fileOffset, 4); + fileOffset += success.getBytesProcessed(); } - asset::SAssetBundle newPipelineBundle(nullptr, {core::smart_refctd_ptr(mbPipeline)}); - defaultOverride.insertAssetIntoCache(newPipelineBundle, pipelineCacheHash, fakeContext, _hierarchyLevel + ICPURenderpassIndependentPipeline::DESC_SET_HIERARCHYLEVELS_BELOW); + { + system::IFile::success_t success; + inner.mainFile->read(success, &vec.z, fileOffset, 4); + fileOffset += success.getBytesProcessed(); + } } else - return; - }; - - /* - Pipeline permutations are cached - */ + { + goNextWord(); + std::string tmp; + + getNextToken(tmp); + sscanf(tmp.c_str(), "%f", &vec.x); + getNextToken(tmp); + sscanf(tmp.c_str(), "%f", &vec.y); + getNextToken(tmp); + sscanf(tmp.c_str(), "%f", &vec.z); + } + vec.x = -vec.x; + } - precomputeAndCachePipeline(true); - precomputeAndCachePipeline(false); -} + core::vector vertices; + core::vector normals; + core::vector colors; + core::vector indices; +}; SAssetBundle CSTLMeshFileLoader::loadAsset(system::IFile* _file, const IAssetLoader::SAssetLoadParams& _params, IAssetLoader::IAssetLoaderOverride* _override, uint32_t _hierarchyLevel) { + using namespace nbl::core; if (!_file) return {}; @@ -136,6 +154,7 @@ SAssetBundle CSTLMeshFileLoader::loadAsset(system::IFile* _file, const IAssetLoa _override }; + auto geometry = make_smart_refctd_ptr(); const size_t filesize = context.inner.mainFile->getSize(); if (filesize < 6ull) // we need a header @@ -143,17 +162,11 @@ SAssetBundle CSTLMeshFileLoader::loadAsset(system::IFile* _file, const IAssetLoa bool hasColor = false; - auto mesh = core::make_smart_refctd_ptr(); - auto meshbuffer = core::make_smart_refctd_ptr(); - meshbuffer->setPositionAttributeIx(POSITION_ATTRIBUTE); - meshbuffer->setNormalAttributeIx(NORMAL_ATTRIBUTE); - bool binary = false; std::string token; - if (getNextToken(&context, token) != "solid") + if (context.getNextToken(token) != "solid") binary = hasColor = true; - core::vector positions, normals; core::vector colors; if (binary) { @@ -171,65 +184,78 @@ SAssetBundle CSTLMeshFileLoader::loadAsset(system::IFile* _file, const IAssetLoa return {}; context.fileOffset += sizeof(vertexCount); - positions.reserve(3 * vertexCount); - normals.reserve(vertexCount); colors.reserve(vertexCount); } else - goNextLine(&context); // skip header + context.goNextLine(); // skip header uint16_t attrib = 0u; token.reserve(32); + + core::unordered_map vertexMap; + while (context.fileOffset < filesize) // TODO: check it { if (!binary) { - if (getNextToken(&context, token) != "facet") + if (context.getNextToken(token) != "facet") { if (token == "endsolid") break; return {}; } - if (getNextToken(&context, token) != "normal") + if (context.getNextToken(token) != "normal") { return {}; } } { - core::vectorSIMDf n; - getNextVector(&context, n, binary); + hlsl::float32_t3 n; + context.getNextVector(n, binary); if(_params.loaderFlags & E_LOADER_PARAMETER_FLAGS::ELPF_RIGHT_HANDED_MESHES) performActionBasedOnOrientationSystem(n.x, [](float& varToFlip) {varToFlip = -varToFlip;}); - normals.push_back(core::normalize(n)); + + context.normals.emplace_back(std::move(n)); } if (!binary) { - if (getNextToken(&context, token) != "outer" || getNextToken(&context, token) != "loop") + if (context.getNextToken(token) != "outer" || context.getNextToken(token) != "loop") return {}; } { - core::vectorSIMDf p[3]; for (uint32_t i = 0u; i < 3u; ++i) { + hlsl::float32_t3 p; if (!binary) { - if (getNextToken(&context, token) != "vertex") + if (context.getNextToken(token) != "vertex") return {}; } - getNextVector(&context, p[i], binary); + context.getNextVector(p, binary); if (_params.loaderFlags & E_LOADER_PARAMETER_FLAGS::ELPF_RIGHT_HANDED_MESHES) - performActionBasedOnOrientationSystem(p[i].x, [](float& varToFlip){varToFlip = -varToFlip; }); + performActionBasedOnOrientationSystem(p.x, [](float& varToFlip){varToFlip = -varToFlip; }); + + auto it = vertexMap.find(p); + if (it == vertexMap.end()) + { + uint32_t newIdx = static_cast(context.vertices.size()); + vertexMap[p] = newIdx; + context.indices.push_back(newIdx); + context.vertices.emplace_back(std::move(p)); + } + else + { + context.indices.push_back(it->second); + } } - for (uint32_t i = 0u; i < 3u; ++i) // seems like in STL format vertices are ordered in clockwise manner... - positions.push_back(p[2u - i]); } if (!binary) { - if (getNextToken(&context, token) != "endloop" || getNextToken(&context, token) != "endfacet") + if (context.getNextToken(token) != "endloop" || context.getNextToken(token) != "endfacet") return {}; } else @@ -246,7 +272,7 @@ SAssetBundle CSTLMeshFileLoader::loadAsset(system::IFile* _file, const IAssetLoa const void* srcColor[1]{ &attrib }; uint32_t color{}; convertColor(srcColor, &color, 0u, 0u); - colors.push_back(color); + context.colors.push_back(color); } else { @@ -254,55 +280,38 @@ SAssetBundle CSTLMeshFileLoader::loadAsset(system::IFile* _file, const IAssetLoa colors.clear(); } - if ((normals.back() == core::vectorSIMDf()).all()) + if (context.normals.back() == hlsl::float32_t3{}) { - normals.back().set( - core::plane3dSIMDf( - *(positions.rbegin() + 2), - *(positions.rbegin() + 1), - *(positions.rbegin() + 0)).getNormal() - ); + auto& p1 = *(context.vertices.rbegin() + 2); + auto& p2 = *(context.vertices.rbegin() + 1); + auto& p3 = *(context.vertices.rbegin() + 0); + + auto u = p2 - p1; + auto v = p3 - p1; + context.normals.emplace_back(hlsl::normalize(hlsl::cross(u, v))); } } // end while (_file->getPos() < filesize) - const size_t vtxSize = hasColor ? (3 * sizeof(float) + 4 + 4) : (3 * sizeof(float) + 4); - auto vertexBuf = asset::ICPUBuffer::create({ vtxSize * positions.size() }); - - quant_normal_t normal; - for (size_t i = 0u; i < positions.size(); ++i) - { - if (i % 3 == 0) - normal = quantNormalCache->quantize(normals[i / 3]); - uint8_t* ptr = (reinterpret_cast(vertexBuf->getPointer())) + i * vtxSize; - memcpy(ptr, positions[i].pointer, 3 * 4); - - *reinterpret_cast(ptr + 12) = normal; - - if (hasColor) - memcpy(ptr + 16, colors.data() + i / 3, 4); - } + geometry->setPositionView(createView(E_FORMAT::EF_R32G32B32_SFLOAT, context.vertices.size(), context.vertices.data())); + geometry->setNormalView(createView(E_FORMAT::EF_R32G32B32_SFLOAT, context.normals.size(), context.normals.data())); - const IAssetLoader::SAssetLoadContext fakeContext(IAssetLoader::SAssetLoadParams{}, nullptr); - const asset::IAsset::E_TYPE types[]{ asset::IAsset::ET_RENDERPASS_INDEPENDENT_PIPELINE, (asset::IAsset::E_TYPE)0u }; - auto pipelineBundle = _override->findCachedAsset(getPipelineCacheKey(hasColor).data(), types, fakeContext, _hierarchyLevel + ICPURenderpassIndependentPipeline::DESC_SET_HIERARCHYLEVELS_BELOW); + if (!context.colors.empty()) { - bool status = !pipelineBundle.getContents().empty(); - assert(status); + // I'm still not sure if this works, probably not + auto colorsView = createView(EF_A1R5G5B5_UNORM_PACK16, context.colors.size(), context.colors.data()); + geometry->getAuxAttributeViews()->push_back(colorsView); } - auto mbPipeline = core::smart_refctd_ptr_static_cast(pipelineBundle.getContents().begin()[0]); + CPolygonGeometryManipulator::recomputeContentHashes(geometry.get()); + CPolygonGeometryManipulator::recomputeRanges(geometry.get()); - auto meta = core::make_smart_refctd_ptr(1u, std::move(m_basicViewParamsSemantics)); - meta->placeMeta(0u, mbPipeline.get()); + geometry->setIndexing(IPolygonGeometryBase::TriangleList()); + geometry->setIndexView(createView(E_FORMAT::EF_R32_UINT, context.indices.size(), context.indices.data())); - meshbuffer->setPipeline(std::move(mbPipeline)); - meshbuffer->setIndexCount(positions.size()); - meshbuffer->setIndexType(asset::EIT_UNKNOWN); + CPolygonGeometryManipulator::recomputeAABB(geometry.get()); - meshbuffer->setVertexBufferBinding({ 0ul, vertexBuf }, 0); - mesh->getMeshBufferVector().emplace_back(std::move(meshbuffer)); - - return SAssetBundle(std::move(meta), { std::move(mesh) }); + auto meta = make_smart_refctd_ptr(); + return SAssetBundle(std::move(meta), { std::move(geometry) }); } bool CSTLMeshFileLoader::isALoadableFileFormat(system::IFile* _file, const system::logger_opt_ptr logger) const @@ -338,100 +347,4 @@ bool CSTLMeshFileLoader::isALoadableFileFormat(system::IFile* _file, const syste } } -//! Read 3d vector of floats -void CSTLMeshFileLoader::getNextVector(SContext* context, core::vectorSIMDf& vec, bool binary) const -{ - if (binary) - { - { - system::IFile::success_t success; - context->inner.mainFile->read(success, &vec.X, context->fileOffset, 4); - context->fileOffset += success.getBytesProcessed(); - } - - { - system::IFile::success_t success; - context->inner.mainFile->read(success, &vec.Y, context->fileOffset, 4); - context->fileOffset += success.getBytesProcessed(); - } - - { - system::IFile::success_t success; - context->inner.mainFile->read(success, &vec.Z, context->fileOffset, 4); - context->fileOffset += success.getBytesProcessed(); - } - } - else - { - goNextWord(context); - std::string tmp; - - getNextToken(context, tmp); - sscanf(tmp.c_str(), "%f", &vec.X); - getNextToken(context, tmp); - sscanf(tmp.c_str(), "%f", &vec.Y); - getNextToken(context, tmp); - sscanf(tmp.c_str(), "%f", &vec.Z); - } - vec.X = -vec.X; -} - -//! Read next word -const std::string& CSTLMeshFileLoader::getNextToken(SContext* context, std::string& token) const -{ - goNextWord(context); - char c; - token = ""; - - while (context->fileOffset != context->inner.mainFile->getSize()) - { - system::IFile::success_t success; - context->inner.mainFile->read(success, &c, context->fileOffset, sizeof(c)); - context->fileOffset += success.getBytesProcessed(); - - // found it, so leave - if (core::isspace(c)) - break; - token += c; - } - return token; -} - -//! skip to next word -void CSTLMeshFileLoader::goNextWord(SContext* context) const -{ - uint8_t c; - while (context->fileOffset != context->inner.mainFile->getSize()) // TODO: check it - { - system::IFile::success_t success; - context->inner.mainFile->read(success, &c, context->fileOffset, sizeof(c)); - context->fileOffset += success.getBytesProcessed(); - - // found it, so leave - if (!core::isspace(c)) - { - context->fileOffset -= success.getBytesProcessed(); - break; - } - } -} - -//! Read until line break is reached and stop at the next non-space character -void CSTLMeshFileLoader::goNextLine(SContext* context) const -{ - uint8_t c; - // look for newline characters - while (context->fileOffset != context->inner.mainFile->getSize()) // TODO: check it - { - system::IFile::success_t success; - context->inner.mainFile->read(success, &c, context->fileOffset, sizeof(c)); - context->fileOffset += success.getBytesProcessed(); - - // found it, so leave - if (c == '\n' || c == '\r') - break; - } -} - - #endif // _NBL_COMPILE_WITH_STL_LOADER_ diff --git a/src/nbl/asset/interchange/CSTLMeshFileLoader.h b/src/nbl/asset/interchange/CSTLMeshFileLoader.h index f7020ab292..7c831f0e3d 100644 --- a/src/nbl/asset/interchange/CSTLMeshFileLoader.h +++ b/src/nbl/asset/interchange/CSTLMeshFileLoader.h @@ -18,45 +18,30 @@ namespace nbl::asset //! Meshloader capable of loading STL meshes. class CSTLMeshFileLoader final : public IGeometryLoader { - public: + public: - CSTLMeshFileLoader(asset::IAssetManager* _m_assetMgr); + inline CSTLMeshFileLoader() = default; - asset::SAssetBundle loadAsset(system::IFile* _file, const IAssetLoader::SAssetLoadParams& _params, IAssetLoader::IAssetLoaderOverride* _override = nullptr, uint32_t _hierarchyLevel = 0u) override; + asset::SAssetBundle loadAsset(system::IFile* _file, const IAssetLoader::SAssetLoadParams& _params, IAssetLoader::IAssetLoaderOverride* _override = nullptr, uint32_t _hierarchyLevel = 0u) override; - bool isALoadableFileFormat(system::IFile* _file, const system::logger_opt_ptr logger) const override; + bool isALoadableFileFormat(system::IFile* _file, const system::logger_opt_ptr logger) const override; - const char** getAssociatedFileExtensions() const override - { - static const char* ext[]{ "stl", nullptr }; - return ext; - } + const char** getAssociatedFileExtensions() const override + { + static const char* ext[]{ "stl", nullptr }; + return ext; + } - private: - struct SContext - { - IAssetLoader::SAssetLoadContext inner; - uint32_t topHierarchyLevel; - IAssetLoader::IAssetLoaderOverride* loaderOverride; + private: + const std::string_view getPipelineCacheKey(bool withColorAttribute) { return withColorAttribute ? "nbl/builtin/pipeline/loader/STL/color_attribute" : "nbl/builtin/pipeline/loader/STL/no_color_attribute"; } - size_t fileOffset = {}; - }; + asset::IAssetManager* m_assetMgr; - virtual void initialize() override; - - const std::string_view getPipelineCacheKey(bool withColorAttribute) { return withColorAttribute ? "nbl/builtin/pipeline/loader/STL/color_attribute" : "nbl/builtin/pipeline/loader/STL/no_color_attribute"; } - - // skips to the first non-space character available - void goNextWord(SContext* context) const; - // returns the next word - - const std::string& getNextToken(SContext* context, std::string& token) const; - // skip to next printable character after the first line break - void goNextLine(SContext* context) const; - //! Read 3d vector of floats - void getNextVector(SContext* context, core::vectorSIMDf& vec, bool binary) const; - - asset::IAssetManager* m_assetMgr; + template + static inline void performActionBasedOnOrientationSystem(aType& varToHandle, void (*performOnCertainOrientation)(aType& varToHandle)) + { + performOnCertainOrientation(varToHandle); + } }; } // end namespace nbl::scene diff --git a/src/nbl/asset/interchange/CSTLMeshWriter.cpp b/src/nbl/asset/interchange/CSTLMeshWriter.cpp index 45c7c1f939..4d925c577e 100644 --- a/src/nbl/asset/interchange/CSTLMeshWriter.cpp +++ b/src/nbl/asset/interchange/CSTLMeshWriter.cpp @@ -5,6 +5,8 @@ #include "nbl/system/ISystem.h" #include "nbl/system/IFile.h" +#include + #include "CSTLMeshWriter.h" #include "SColor.h" @@ -24,9 +26,9 @@ CSTLMeshWriter::CSTLMeshWriter() #endif } - CSTLMeshWriter::~CSTLMeshWriter() { + } //! writes a mesh @@ -37,11 +39,11 @@ bool CSTLMeshWriter::writeAsset(system::IFile* _file, const SAssetWriteParams& _ SAssetWriteContext inCtx{_params, _file}; - const asset::ICPUMesh* mesh = + const asset::ICPUPolygonGeometry* mesh = # ifndef _NBL_DEBUG - static_cast(_params.rootAsset); + static_cast(_params.rootAsset); # else - dynamic_cast(_params.rootAsset); + dynamic_cast(_params.rootAsset); # endif assert(mesh); @@ -61,123 +63,110 @@ bool CSTLMeshWriter::writeAsset(system::IFile* _file, const SAssetWriteParams& _ return writeMeshASCII(mesh, &context); } +inline static hlsl::float32_t3 calculateNormal(const hlsl::float32_t3& p1, const hlsl::float32_t3& p2, const hlsl::float32_t3& p3) +{ + return hlsl::normalize(hlsl::cross(p2 - p1, p3 - p1)); +} + namespace { -template -inline void writeFacesBinary(const asset::ICPUMeshBuffer* buffer, const bool& noIndices, system::IFile* file, uint32_t _colorVaid, IAssetWriter::SAssetWriteContext* context, size_t* fileOffset) +template +inline void writeFacesBinary(const asset::ICPUPolygonGeometry* geom, const bool& noIndices, system::IFile* file, uint32_t _colorVaid, IAssetWriter::SAssetWriteContext* context, size_t* fileOffset) { - auto& inputParams = buffer->getPipeline()->getCachedCreationParams().vertexInput; - bool hasColor = inputParams.enabledAttribFlags & core::createBitmask({ COLOR_ATTRIBUTE }); - const asset::E_FORMAT colorType = static_cast(hasColor ? inputParams.attributes[COLOR_ATTRIBUTE].format : asset::EF_UNKNOWN); - - const uint32_t indexCount = buffer->getIndexCount(); - for (uint32_t j = 0u; j < indexCount; j += 3u) - { - I idx[3]; - for (uint32_t i = 0u; i < 3u; ++i) - { - if (noIndices) - idx[i] = j + i; - else - idx[i] = ((I*)buffer->getIndices())[j + i]; - } - - core::vectorSIMDf v[3]; - for (uint32_t i = 0u; i < 3u; ++i) - v[i] = buffer->getPosition(idx[i]); - - uint16_t color = 0u; - if (hasColor) - { - if (asset::isIntegerFormat(colorType)) - { - uint32_t res[4]; - for (uint32_t i = 0u; i < 3u; ++i) - { - uint32_t d[4]; - buffer->getAttribute(d, _colorVaid, idx[i]); - res[0] += d[0]; res[1] += d[1]; res[2] += d[2]; - } - color = video::RGB16(res[0]/3, res[1]/3, res[2]/3); - } - else - { - core::vectorSIMDf res; - for (uint32_t i = 0u; i < 3u; ++i) - { - core::vectorSIMDf d; - buffer->getAttribute(d, _colorVaid, idx[i]); - res += d; - } - res /= 3.f; - color = video::RGB16(res.X, res.Y, res.Z); - } - } - - core::vectorSIMDf normal = core::plane3dSIMDf(v[0], v[1], v[2]).getNormal(); - core::vectorSIMDf vertex1 = v[2]; - core::vectorSIMDf vertex2 = v[1]; - core::vectorSIMDf vertex3 = v[0]; - - auto flipVectors = [&]() - { - vertex1.X = -vertex1.X; - vertex2.X = -vertex2.X; - vertex3.X = -vertex3.X; - normal = core::plane3dSIMDf(vertex1, vertex2, vertex3).getNormal(); - }; + using pos_t = hlsl::float32_t3; - if (!(context->params.flags & E_WRITER_FLAGS::EWF_MESH_IS_RIGHT_HANDED)) - flipVectors(); + // bool hasColor = inputParams.enabledAttribFlags & core::createBitmask({ COLOR_ATTRIBUTE }); + // const asset::E_FORMAT colorType = static_cast(hasColor ? inputParams.attributes[COLOR_ATTRIBUTE].format : asset::EF_UNKNOWN); - { - system::IFile::success_t success;; - file->write(success, &normal, *fileOffset, 12); + auto& posView = geom->getPositionView(); + auto& normalView = geom->getNormalView(); + auto& idxView = geom->getIndexView(); - *fileOffset += success.getBytesProcessed(); - } + const auto vertexCount = posView.getElementCount(); + const auto idxCount = idxView.getElementCount(); - { - system::IFile::success_t success;; - file->write(success, &vertex1, *fileOffset, 12); - - *fileOffset += success.getBytesProcessed(); - } + assert((idxView.src.buffer->getSize() / idxCount) == sizeof(IndexType)); - { - system::IFile::success_t success;; - file->write(success, &vertex2, *fileOffset, 12); - - *fileOffset += success.getBytesProcessed(); - } + const IndexType* idxBufPtr = reinterpret_cast(idxView.getPointer()); + const pos_t* vtxBufPtr = reinterpret_cast(posView.getPointer()); + for (size_t i = 0; i < idxCount; i+=3) + { + IndexType idx[3] = {}; + for (size_t j = 0; j < 3; j++) + idx[i] = *(idxBufPtr + j + i); + + pos_t pos[3] = {}; + for (size_t j = 0; j < 3; j++) + pos[j] = *(vtxBufPtr + idx[j]); + + // TODO: vertex color + + pos_t normal = calculateNormal(pos[0], pos[1], pos[2]); + + // success variable can be reused, no need to scope it + + // write normal { - system::IFile::success_t success;; - file->write(success, &vertex3, *fileOffset, 12); - + system::IFile::success_t success; + file->write(success, &normal, *fileOffset, 12); *fileOffset += success.getBytesProcessed(); } + // write positions + for (size_t j = 0; j < 3; j++) { - system::IFile::success_t success;; - file->write(success, &color, *fileOffset, 2); // saving color using non-standard VisCAM/SolidView trick - + system::IFile::success_t success; + file->write(success, &pos[i], *fileOffset, 12); *fileOffset += success.getBytesProcessed(); } - } + } + // uint16_t color = 0u; + // if (hasColor) + // { + // if (asset::isIntegerFormat(colorType)) + // { + // uint32_t res[4]; + // for (uint32_t i = 0u; i < 3u; ++i) + // { + // uint32_t d[4]; + // buffer->getAttribute(d, _colorVaid, idx[i]); + // res[0] += d[0]; res[1] += d[1]; res[2] += d[2]; + // } + // color = video::RGB16(res[0]/3, res[1]/3, res[2]/3); + // } + // else + // { + // core::vectorSIMDf res; + // for (uint32_t i = 0u; i < 3u; ++i) + // { + // core::vectorSIMDf d; + // buffer->getAttribute(d, _colorVaid, idx[i]); + // res += d; + // } + // res /= 3.f; + // color = video::RGB16(res.X, res.Y, res.Z); + // } + // } + + //{ + // system::IFile::success_t success;; + // file->write(success, &color, *fileOffset, 2); // saving color using non-standard VisCAM/SolidView trick + + // *fileOffset += success.getBytesProcessed(); + //} } } -bool CSTLMeshWriter::writeMeshBinary(const asset::ICPUMesh* mesh, SContext* context) +bool CSTLMeshWriter::writeMeshBinary(const asset::ICPUPolygonGeometry* geom, SContext* context) { // write STL MESH header - const char headerTxt[] = "Irrlicht-baw Engine"; - constexpr size_t HEADER_SIZE = 80u; + const char headerTxt[] = "Nabla Engine"; + constexpr size_t HEADER_SIZE = 80u; { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, headerTxt, context->fileOffset, sizeof(headerTxt)); - context->fileOffset += success.getBytesProcessed(); } @@ -186,9 +175,8 @@ bool CSTLMeshWriter::writeMeshBinary(const asset::ICPUMesh* mesh, SContext* cont if (sizeleft < 0) { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, name.c_str(), context->fileOffset, HEADER_SIZE - sizeof(headerTxt)); - context->fileOffset += success.getBytesProcessed(); } else @@ -196,277 +184,237 @@ bool CSTLMeshWriter::writeMeshBinary(const asset::ICPUMesh* mesh, SContext* cont const char buf[80] = {0}; { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, name.c_str(), context->fileOffset, name.size()); - context->fileOffset += success.getBytesProcessed(); } { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, buf, context->fileOffset, sizeleft); - context->fileOffset += success.getBytesProcessed(); } } + + size_t idxCount = geom->getIndexCount(); + size_t facesCount = idxCount / 3; - uint32_t facenum = 0; - for (auto& mb : mesh->getMeshBuffers()) - facenum += mb->getIndexCount()/3; + if (idxCount > 0) { - system::IFile::success_t success;; - context->writeContext.outputFile->write(success, &facenum, context->fileOffset, sizeof(facenum)); + auto& idxView = geom->getIndexView(); + size_t idxSize = idxView.src.size / idxCount; - context->fileOffset += success.getBytesProcessed(); + if (idxSize == sizeof(uint16_t)) + writeFacesBinary(geom, false, context->writeContext.outputFile, COLOR_ATTRIBUTE, &context->writeContext, &context->fileOffset); + else + writeFacesBinary(geom, false, context->writeContext.outputFile, COLOR_ATTRIBUTE, &context->writeContext, &context->fileOffset); } - // write mesh buffers - - for (auto& buffer : mesh->getMeshBuffers()) - if (buffer) + else { - asset::E_INDEX_TYPE type = buffer->getIndexType(); - if (!buffer->getIndexBufferBinding().buffer) - type = asset::EIT_UNKNOWN; - - if (type== asset::EIT_16BIT) - writeFacesBinary(buffer, false, context->writeContext.outputFile, COLOR_ATTRIBUTE, &context->writeContext, &context->fileOffset); - else if (type== asset::EIT_32BIT) - writeFacesBinary(buffer, false, context->writeContext.outputFile, COLOR_ATTRIBUTE, &context->writeContext, &context->fileOffset); - else - writeFacesBinary(buffer, true, context->writeContext.outputFile, COLOR_ATTRIBUTE, &context->writeContext, &context->fileOffset); //template param doesn't matter if there's no indices + writeFacesBinary(geom, true, context->writeContext.outputFile, COLOR_ATTRIBUTE, &context->writeContext, &context->fileOffset); } + return true; } -bool CSTLMeshWriter::writeMeshASCII(const asset::ICPUMesh* mesh, SContext* context) +bool CSTLMeshWriter::writeMeshASCII(const asset::ICPUPolygonGeometry* geom, SContext* context) { + using pos_t = hlsl::float32_t3; + // write STL MESH header - const char headerTxt[] = "Irrlicht-baw Engine "; + constexpr char headerTxt[] = "Nabla Engine "; { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, "solid ", context->fileOffset, 6); - context->fileOffset += success.getBytesProcessed(); } - { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, headerTxt, context->fileOffset, sizeof(headerTxt) - 1); - context->fileOffset += success.getBytesProcessed(); } const std::string name = context->writeContext.outputFile->getFileName().filename().replace_extension().string(); - { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, name.c_str(), context->fileOffset, name.size()); - context->fileOffset += success.getBytesProcessed(); } - { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, "\n", context->fileOffset, 1); - context->fileOffset += success.getBytesProcessed(); } - // write mesh buffers - for (auto& buffer : mesh->getMeshBuffers()) - if (buffer) + auto& idxView = geom->getIndexView(); + + const size_t idxCount = geom->getIndexCount(); + const size_t idxSize = idxView.src.buffer->getSize() / idxCount; + const size_t facesCount = idxCount / 3; + + auto& posView = geom->getPositionView(); + const pos_t* posBufPtr = reinterpret_cast(posView.getPointer()); + + uint32_t idx[3]; + pos_t positions[3]; + for (size_t i = 0; i < idxCount; i += 3) { - asset::E_INDEX_TYPE type = buffer->getIndexType(); - if (!buffer->getIndexBufferBinding().buffer) - type = asset::EIT_UNKNOWN; - const uint32_t indexCount = buffer->getIndexCount(); - if (type==asset::EIT_16BIT) + for (size_t j = 0; j < 3; j++) { - //os::Printer::log("Writing mesh with 16bit indices"); - for (uint32_t j=0; jgetPosition(((uint16_t*)buffer->getIndices())[j]), - buffer->getPosition(((uint16_t*)buffer->getIndices())[j+1]), - buffer->getPosition(((uint16_t*)buffer->getIndices())[j+2]), - context - ); - } + if (idxSize == sizeof(uint32_t)) + { + const uint32_t* buf = reinterpret_cast(idxView.getPointer()); + idx[j] = *(buf + i + j); + } + else if (idxSize == sizeof(uint16_t)) + { + const uint16_t* buf = reinterpret_cast(idxView.getPointer()); + idx[j] = *(buf + i + j); + } + else + assert(false); } - else if (type==asset::EIT_32BIT) + + for (size_t j = 0; j < 3; j++) { - //os::Printer::log("Writing mesh with 32bit indices"); - for (uint32_t j=0; jgetPosition(((uint32_t*)buffer->getIndices())[j]), - buffer->getPosition(((uint32_t*)buffer->getIndices())[j+1]), - buffer->getPosition(((uint32_t*)buffer->getIndices())[j+2]), - context - ); - } + positions[j] = *(posBufPtr + idx[j]); } - else - { - //os::Printer::log("Writing mesh with no indices"); - for (uint32_t j=0; jgetPosition(j), - buffer->getPosition(j+1ul), - buffer->getPosition(j+2ul), - context - ); - } - } + + writeFaceText(positions[0], positions[1], positions[2], context); { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, "\n", context->fileOffset, 1); - context->fileOffset += success.getBytesProcessed(); } } { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, "endsolid ", context->fileOffset, 9); - context->fileOffset += success.getBytesProcessed(); } - + { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, headerTxt, context->fileOffset, sizeof(headerTxt) - 1); - context->fileOffset += success.getBytesProcessed(); } { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, name.c_str(), context->fileOffset, name.size()); - context->fileOffset += success.getBytesProcessed(); } return true; } -void CSTLMeshWriter::getVectorAsStringLine(const core::vectorSIMDf& v, std::string& s) const +void CSTLMeshWriter::getVectorAsStringLine(const pos_t& v, std::string& s) const { std::ostringstream tmp; - tmp << v.X << " " << v.Y << " " << v.Z << "\n"; + tmp << std::fixed << std::setprecision(2); + tmp << v.x << " " << v.y << " " << v.z << "\n"; s = std::string(tmp.str().c_str()); } void CSTLMeshWriter::writeFaceText( - const core::vectorSIMDf& v1, - const core::vectorSIMDf& v2, - const core::vectorSIMDf& v3, + const pos_t& v1, + const pos_t& v2, + const pos_t& v3, SContext* context) { - core::vectorSIMDf vertex1 = v3; - core::vectorSIMDf vertex2 = v2; - core::vectorSIMDf vertex3 = v1; - core::vectorSIMDf normal = core::plane3dSIMDf(vertex1, vertex2, vertex3).getNormal(); + pos_t vertex1 = v1; + pos_t vertex2 = v2; + pos_t vertex3 = v3; + normal_t normal = calculateNormal(v1, v2, v3); std::string tmp; auto flipVectors = [&]() { - vertex1.X = -vertex1.X; - vertex2.X = -vertex2.X; - vertex3.X = -vertex3.X; - normal = core::plane3dSIMDf(vertex1, vertex2, vertex3).getNormal(); + vertex1.x = -vertex1.x; + vertex2.x = -vertex2.x; + vertex3.x = -vertex3.x; + normal_t normal = calculateNormal(vertex1, vertex2, vertex3); }; if (!(context->writeContext.params.flags & E_WRITER_FLAGS::EWF_MESH_IS_RIGHT_HANDED)) flipVectors(); - + { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, "facet normal ", context->fileOffset, 13); - context->fileOffset += success.getBytesProcessed(); } getVectorAsStringLine(normal, tmp); { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, tmp.c_str(), context->fileOffset, tmp.size()); - context->fileOffset += success.getBytesProcessed(); } { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, " outer loop\n", context->fileOffset, 13); - context->fileOffset += success.getBytesProcessed(); } { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, " vertex ", context->fileOffset, 11); - context->fileOffset += success.getBytesProcessed(); } getVectorAsStringLine(vertex1, tmp); { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, tmp.c_str(), context->fileOffset, tmp.size()); - context->fileOffset += success.getBytesProcessed(); } { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, " vertex ", context->fileOffset, 11); - context->fileOffset += success.getBytesProcessed(); } getVectorAsStringLine(vertex2, tmp); { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, tmp.c_str(), context->fileOffset, tmp.size()); - context->fileOffset += success.getBytesProcessed(); } { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, " vertex ", context->fileOffset, 11); - context->fileOffset += success.getBytesProcessed(); } getVectorAsStringLine(vertex3, tmp); { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, tmp.c_str(), context->fileOffset, tmp.size()); - context->fileOffset += success.getBytesProcessed(); } { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, " endloop\n", context->fileOffset, 10); - context->fileOffset += success.getBytesProcessed(); } { - system::IFile::success_t success;; + system::IFile::success_t success; context->writeContext.outputFile->write(success, "endfacet\n", context->fileOffset, 9); - context->fileOffset += success.getBytesProcessed(); } } diff --git a/src/nbl/asset/interchange/CSTLMeshWriter.h b/src/nbl/asset/interchange/CSTLMeshWriter.h index a25a84534c..8db79b0d22 100644 --- a/src/nbl/asset/interchange/CSTLMeshWriter.h +++ b/src/nbl/asset/interchange/CSTLMeshWriter.h @@ -17,7 +17,7 @@ namespace nbl::asset class CSTLMeshWriter : public IGeometryWriter { protected: - virtual ~CSTLMeshWriter(); + ~CSTLMeshWriter() override; public: CSTLMeshWriter(); @@ -35,24 +35,26 @@ class CSTLMeshWriter : public IGeometryWriter virtual bool writeAsset(system::IFile* _file, const SAssetWriteParams& _params, IAssetWriterOverride* _override = nullptr) override; private: + using pos_t = hlsl::float32_t3; + using normal_t = hlsl::float32_t3; - struct SContext - { - SAssetWriteContext writeContext; - size_t fileOffset; - }; + struct SContext + { + SAssetWriteContext writeContext; + size_t fileOffset; + }; - // write binary format - bool writeMeshBinary(const ICPUPolygonGeometry* geom, SContext* context); + // write binary format + bool writeMeshBinary(const ICPUPolygonGeometry* geom, SContext* context); - // write text format - bool writeMeshASCII(const ICPUPolygonGeometry* geom, SContext* context); + // write text format + bool writeMeshASCII(const ICPUPolygonGeometry* geom, SContext* context); - // create vector output with line end into string - void getVectorAsStringLine(const core::vectorSIMDf& v, std::string& s) const; + // create vector output with line end into string + void getVectorAsStringLine(const pos_t& v, std::string& s) const; - // write face information to file - void writeFaceText(const core::vectorSIMDf& v1, const core::vectorSIMDf& v2, const core::vectorSIMDf& v3, SContext* context); + // write face information to file + void writeFaceText(const pos_t& v1, const pos_t& v2, const pos_t& v3, SContext* context); }; } // end namespace