diff --git a/appveyor.yml b/appveyor.yml index ac5f0483..5375bbfa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -51,11 +51,21 @@ build: false test_script: - set PATH=%PATH%;%QTDIR%\bin + - if "%PLATFORM%" == "x64" qmake "BOOST_INCLUDEDIR=C:\Libraries\boost_1_66_0" "CGAL_DIR=%APPVEYOR_BUILD_FOLDER%\thirdparty\cgal\CGAL-4.13" - if "%PLATFORM%" == "x86" qmake "BOOST_INCLUDEDIR=C:\Libraries\boost_1_66_0" "CGAL_DIR=%APPVEYOR_BUILD_FOLDER%\CGAL-4.13" - nmake -f Makefile.Release + + - cd lib + - if "%PLATFORM%" == "x64" + qmake "BOOST_INCLUDEDIR=C:\Libraries\boost_1_66_0" "CGAL_DIR=%APPVEYOR_BUILD_FOLDER%\thirdparty\cgal\CGAL-4.13" + - if "%PLATFORM%" == "x86" + qmake "BOOST_INCLUDEDIR=C:\Libraries\boost_1_66_0" "CGAL_DIR=%APPVEYOR_BUILD_FOLDER%\CGAL-4.13" + - nmake -f Makefile.Release + + - cd %APPVEYOR_BUILD_FOLDER% after_test: # Check deps by Dependency Walker @@ -73,6 +83,8 @@ after_test: - if "%TAG%" == "unstable" 7z a %RELEASE_FILENAME% %APPVEYOR_BUILD_FOLDER%\release\dust3d.pdb - 7z a %RELEASE_FILENAME% %APPVEYOR_BUILD_FOLDER%\release\dust3d.exe + - 7z a %RELEASE_FILENAME% %APPVEYOR_BUILD_FOLDER%\lib\release\libdust3d.dll + - 7z a %RELEASE_FILENAME% %APPVEYOR_BUILD_FOLDER%\lib\release\libdust3d.lib - if "%TAG%" == "unstable" 7z a %RELEASE_FILENAME% %APPVEYOR_BUILD_FOLDER%\thirdparty\instant-meshes\build\RelWithDebInfo\instant-meshes.pdb - 7z a %RELEASE_FILENAME% %APPVEYOR_BUILD_FOLDER%\thirdparty\instant-meshes\build\RelWithDebInfo\instant-meshes.dll diff --git a/dust3d.pro b/dust3d.pro index f60d87d2..579ea2e3 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -54,11 +54,11 @@ win32 { } win32 { - RC_FILE = dust3d.rc + RC_FILE = $${SOURCE_ROOT}dust3d.rc } macx { - ICON = dust3d.icns + ICON = $${SOURCE_ROOT}dust3d.icns RESOURCE_FILES.files = $$ICON RESOURCE_FILES.path = Contents/Resources @@ -551,16 +551,16 @@ INCLUDEPATH += thirdparty/instant-meshes/instant-meshes-dust3d/ext/rply INCLUDEPATH += thirdparty/instant-meshes/instant-meshes-dust3d/ext/half unix { SOURCES += thirdparty/instant-meshes/instant-meshes-api.cpp - LIBS += -Lthirdparty/instant-meshes/build -linstant-meshes - LIBS += -Lthirdparty/instant-meshes/build/ext_build/tbb -ltbb_static + LIBS += -L$${SOURCE_ROOT}thirdparty/instant-meshes/build -linstant-meshes + LIBS += -L$${SOURCE_ROOT}thirdparty/instant-meshes/build/ext_build/tbb -ltbb_static unix:!macx { LIBS += -ldl } } win32 { DEFINES += _USE_MATH_DEFINES - LIBS += -Lthirdparty/instant-meshes/build/RelWithDebInfo -linstant-meshes - LIBS += -Lthirdparty/instant-meshes/build/ext_build/tbb/RelWithDebInfo -ltbb + LIBS += -L$${SOURCE_ROOT}thirdparty/instant-meshes/build/RelWithDebInfo -linstant-meshes + LIBS += -L$${SOURCE_ROOT}thirdparty/instant-meshes/build/ext_build/tbb/RelWithDebInfo -ltbb } INCLUDEPATH += thirdparty/bullet3/src @@ -913,4 +913,4 @@ INCLUDEPATH += $$CGAL_BUILDINCLUDEDIR LIBS += -L$$CGAL_LIBDIR -l$$CGAL_LIBNAME target.path = ./ -INSTALLS += target +INSTALLS += target \ No newline at end of file diff --git a/include/dust3d.h b/include/dust3d.h new file mode 100644 index 00000000..aa7c519d --- /dev/null +++ b/include/dust3d.h @@ -0,0 +1,48 @@ +#ifndef DUST3D_H +#define DUST3D_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +# ifdef DUST3D_EXPORTING +# define DUST3D_DLL __declspec(dllexport) +# else +# define DUST3D_DLL __declspec(dllimport) +# endif +#else +# define DUST3D_DLL +#endif + +# define DUST3D_API __stdcall + +#define DUST3D_OK 0 +#define DUST3D_ERROR 1 +#define DUST3D_UNSUPPORTED 2 + +typedef struct _dust3d dust3d; + +DUST3D_DLL void DUST3D_API dust3dInitialize(int argc, char *argv[]); +DUST3D_DLL dust3d * DUST3D_API dust3dOpenFromMemory(const char *documentType, const char *buffer, int size); +DUST3D_DLL dust3d * DUST3D_API dust3dOpen(const char *fileName); +DUST3D_DLL void DUST3D_API dust3dSetUserData(dust3d *ds3, void *userData); +DUST3D_DLL void * DUST3D_API dust3dGetUserData(dust3d *ds3); +DUST3D_DLL int DUST3D_API dust3dGenerateMesh(dust3d *ds3); +DUST3D_DLL int DUST3D_API dust3dGetMeshVertexCount(dust3d *ds3); +DUST3D_DLL int DUST3D_API dust3dGetMeshTriangleCount(dust3d *ds3); +DUST3D_DLL void DUST3D_API dust3dGetMeshTriangleIndices(dust3d *ds3, int *indices); +DUST3D_DLL void DUST3D_API dust3dGetMeshTriangleColors(dust3d *ds3, unsigned int *colors); +DUST3D_DLL void DUST3D_API dust3dGetMeshVertexPosition(dust3d *ds3, int vertexIndex, float *x, float *y, float *z); +DUST3D_DLL void DUST3D_API dust3dGetMeshVertexSource(dust3d *ds3, int vertexIndex, unsigned char partId[16], unsigned char nodeId[16]); +DUST3D_DLL int DUST3D_API dust3dGetMeshTriangleAndQuadCount(dust3d *ds3); +DUST3D_DLL void DUST3D_API dust3dGetMeshTriangleAndQuadIndices(dust3d *ds3, int *indices); +DUST3D_DLL void DUST3D_API dust3dClose(dust3d *ds3); +DUST3D_DLL int DUST3D_API dust3dError(dust3d *ds3); +DUST3D_DLL const char * DUST3D_API dust3dVersion(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/examples/nodes2mesh/CMakeLists.txt b/lib/examples/nodes2mesh/CMakeLists.txt new file mode 100644 index 00000000..52182b4f --- /dev/null +++ b/lib/examples/nodes2mesh/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.10) + +project(nodes2mesh) + +link_directories( + ../../release +) + +add_executable(nodes2mesh + nodes2mesh.cpp +) + +target_include_directories(nodes2mesh PUBLIC + ../../../include +) + +target_link_libraries(nodes2mesh PUBLIC + libdust3d +) diff --git a/lib/examples/nodes2mesh/nodes2mesh.cpp b/lib/examples/nodes2mesh/nodes2mesh.cpp new file mode 100644 index 00000000..429e7681 --- /dev/null +++ b/lib/examples/nodes2mesh/nodes2mesh.cpp @@ -0,0 +1,71 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + dust3dInitialize(argc, argv); + + printf("dust3d version:%s\n", dust3dVersion()); + + dust3d *ds3 = dust3dOpen("screwdriver.xml"); + if (ds3) { + int error = dust3dGenerateMesh(ds3); + printf("error: %d\n", error); + { + FILE *fp = nullptr; + fopen_s(&fp, "test-triangles.obj", "wb"); + int vertexCount = dust3dGetMeshVertexCount(ds3); + for (int i = 0; i < vertexCount; ++i) { + float x, y, z; + dust3dGetMeshVertexPosition(ds3, i, &x, &y, &z); + fprintf(fp, "v %f %f %f\n", x, y, z); + } + int triangleCount = dust3dGetMeshTriangleCount(ds3); + if (triangleCount > 0) { + int *triangleIndices = new int[triangleCount * 3]; + dust3dGetMeshTriangleIndices(ds3, triangleIndices); + for (int i = 0, offset = 0; i < triangleCount; ++i, offset += 3) { + fprintf(fp, "f %d %d %d\n", + 1 + triangleIndices[offset], + 1 + triangleIndices[offset + 1], + 1 + triangleIndices[offset + 2]); + } + delete[] triangleIndices; + } + fclose(fp); + } + { + FILE *fp = nullptr; + fopen_s(&fp, "test-triangleandquads.obj", "wb"); + int vertexCount = dust3dGetMeshVertexCount(ds3); + for (int i = 0; i < vertexCount; ++i) { + float x, y, z; + dust3dGetMeshVertexPosition(ds3, i, &x, &y, &z); + fprintf(fp, "v %f %f %f\n", x, y, z); + } + int triangleAndQuadCount = dust3dGetMeshTriangleAndQuadCount(ds3); + if (triangleAndQuadCount > 0) { + int *faceIndices = new int[triangleAndQuadCount * 4]; + dust3dGetMeshTriangleAndQuadIndices(ds3, faceIndices); + for (int i = 0, offset = 0; i < triangleAndQuadCount; ++i, offset += 4) { + if (-1 == faceIndices[offset + 3]) { + fprintf(fp, "f %d %d %d\n", + 1 + faceIndices[offset], + 1 + faceIndices[offset + 1], + 1 + faceIndices[offset + 2]); + } else { + fprintf(fp, "f %d %d %d %d\n", + 1 + faceIndices[offset], + 1 + faceIndices[offset + 1], + 1 + faceIndices[offset + 2], + 1 + faceIndices[offset + 3]); + } + } + delete[] faceIndices; + } + fclose(fp); + } + dust3dClose(ds3); + } +} diff --git a/lib/examples/nodes2mesh/screwdriver.xml b/lib/examples/nodes2mesh/screwdriver.xml new file mode 100644 index 00000000..76e26e9d --- /dev/null +++ b/lib/examples/nodes2mesh/screwdriver.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/libdust3d.pro b/lib/libdust3d.pro new file mode 100644 index 00000000..59ba8115 --- /dev/null +++ b/lib/libdust3d.pro @@ -0,0 +1,22 @@ +TEMPLATE = lib + +VPATH += ../ + +SOURCE_ROOT = ../ + +CONFIG += skip_target_version_ext + +include(../dust3d.pro) + +DEFINES += DUST3D_EXPORTING + +INCLUDEPATH += include + +SOURCES += src/libdust3d.cpp +HEADERS += include/dust3d.h + +for(path, INCLUDEPATH) { + PREFIXED_INCLUDEPATH += "../$$path" +} + +INCLUDEPATH += $$PREFIXED_INCLUDEPATH \ No newline at end of file diff --git a/src/libdust3d.cpp b/src/libdust3d.cpp new file mode 100644 index 00000000..7248f96d --- /dev/null +++ b/src/libdust3d.cpp @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include +#include +#include +#include "dust3d.h" +#include "meshgenerator.h" +#include "snapshot.h" +#include "snapshotxml.h" +#include "model.h" +#include "version.h" + +struct _dust3d +{ + void *userData = nullptr; + GeneratedCacheContext *cacheContext = nullptr; + Model *resultMesh = nullptr; + Snapshot *snapshot = nullptr; + Outcome *outcome = nullptr; + int error = DUST3D_ERROR; +}; + +DUST3D_DLL int DUST3D_API dust3dError(dust3d *ds3) +{ + return ds3->error; +} + +DUST3D_DLL void DUST3D_API dust3dClose(dust3d *ds3) +{ + delete ds3->resultMesh; + ds3->resultMesh = nullptr; + + delete ds3->cacheContext; + ds3->cacheContext = nullptr; + + delete ds3->snapshot; + ds3->snapshot = nullptr; + + delete ds3->outcome; + ds3->outcome = nullptr; + + delete ds3; +} + +DUST3D_DLL void DUST3D_API dust3dInitialize(int argc, char *argv[]) +{ + if (nullptr == QCoreApplication::instance()) + new QCoreApplication(argc, argv); +} + +DUST3D_DLL dust3d * DUST3D_API dust3dOpenFromMemory(const char *documentType, const char *buffer, int size) +{ + dust3d *ds3 = new dust3d; + + ds3->error = DUST3D_ERROR; + + delete ds3->outcome; + ds3->outcome = new Outcome; + + if (0 == strcmp(documentType, "xml")) { + QByteArray data(buffer, size); + + QXmlStreamReader stream(data); + + delete ds3->snapshot; + ds3->snapshot = new Snapshot; + + loadSkeletonFromXmlStream(ds3->snapshot, stream); + + ds3->error = DUST3D_OK; + } else { + ds3->error = DUST3D_UNSUPPORTED; + } + + return ds3; +} + +DUST3D_DLL dust3d * DUST3D_API dust3dOpen(const char *fileName) +{ + std::string name = fileName; + auto dotIndex = name.rfind('.'); + if (std::string::npos == dotIndex) + return nullptr; + + std::string extension = name.substr(dotIndex + 1); + + std::ifstream is(name, std::ifstream::binary); + if (!is) + return nullptr; + + is.seekg (0, is.end); + int length = is.tellg(); + is.seekg (0, is.beg); + + char *buffer = new char[length + 1]; + is.read(buffer, length); + is.close(); + buffer[length] = '\0'; + + dust3d *ds3 = dust3dOpenFromMemory(extension.c_str(), buffer, length); + + delete[] buffer; + + return ds3; +} + +DUST3D_DLL void DUST3D_API dust3dSetUserData(dust3d *ds3, void *userData) +{ + ds3->userData = userData; +} + +DUST3D_DLL void * DUST3D_API dust3dGetUserData(dust3d *ds3) +{ + return ds3->userData; +} + +DUST3D_DLL const char * DUST3D_API dust3dVersion(void) +{ + return APP_NAME " " APP_HUMAN_VER; +} + +DUST3D_DLL int DUST3D_API dust3dGenerateMesh(dust3d *ds3) +{ + ds3->error = DUST3D_ERROR; + + if (nullptr == ds3->snapshot) + return ds3->error; + + if (nullptr == ds3->cacheContext) + ds3->cacheContext = new GeneratedCacheContext(); + + Snapshot *snapshot = ds3->snapshot; + ds3->snapshot = nullptr; + + MeshGenerator *meshGenerator = new MeshGenerator(snapshot); + meshGenerator->setGeneratedCacheContext(ds3->cacheContext); + meshGenerator->generate(); + + delete ds3->outcome; + ds3->outcome = meshGenerator->takeOutcome(); + if (nullptr == ds3->outcome) + ds3->outcome = new Outcome; + + if (meshGenerator->isSuccessful()) + ds3->error = DUST3D_OK; + + delete meshGenerator; + + return ds3->error; +} + +DUST3D_DLL int DUST3D_API dust3dGetMeshVertexCount(dust3d *ds3) +{ + return (int)ds3->outcome->vertices.size(); +} + +DUST3D_DLL int DUST3D_API dust3dGetMeshTriangleCount(dust3d *ds3) +{ + return (int)ds3->outcome->triangles.size(); +} + +DUST3D_DLL void DUST3D_API dust3dGetMeshTriangleIndices(dust3d *ds3, int *indices) +{ + for (const auto &it: ds3->outcome->triangles) { + *(indices++) = (int)it[0]; + *(indices++) = (int)it[1]; + *(indices++) = (int)it[2]; + } +} + +DUST3D_DLL void DUST3D_API dust3dGetMeshTriangleColors(dust3d *ds3, unsigned int *colors) +{ + for (const auto &it: ds3->outcome->triangleColors) { + *(colors++) = ((unsigned int)it.red() << 16) | ((unsigned int)it.green() << 8) | ((unsigned int)it.blue() << 0); + } +} + +DUST3D_DLL void DUST3D_API dust3dGetMeshVertexPosition(dust3d *ds3, int vertexIndex, float *x, float *y, float *z) +{ + if (vertexIndex >= 0 && vertexIndex < ds3->outcome->vertices.size()) { + const auto &v = ds3->outcome->vertices[vertexIndex]; + *x = v.x(); + *y = v.y(); + *z = v.z(); + } +} + +DUST3D_DLL void DUST3D_API dust3dGetMeshVertexSource(dust3d *ds3, int vertexIndex, unsigned char partId[16], unsigned char nodeId[16]) +{ + if (vertexIndex >= 0 && vertexIndex < ds3->outcome->vertices.size()) { + const auto &source = ds3->outcome->vertexSourceNodes[vertexIndex]; + + auto sourcePartUuid = source.first.toByteArray(QUuid::Id128); + memcpy(partId, sourcePartUuid.constData(), sizeof(partId)); + + auto sourceNodeUuid = source.second.toByteArray(QUuid::Id128); + memcpy(partId, sourceNodeUuid.constData(), sizeof(nodeId)); + } +} + +DUST3D_DLL int DUST3D_API dust3dGetMeshTriangleAndQuadCount(dust3d *ds3) +{ + return (int)ds3->outcome->triangleAndQuads.size(); +} + +DUST3D_DLL void DUST3D_API dust3dGetMeshTriangleAndQuadIndices(dust3d *ds3, int *indices) +{ + for (const auto &it: ds3->outcome->triangleAndQuads) { + *(indices++) = (int)it[0]; + *(indices++) = (int)it[1]; + *(indices++) = (int)it[2]; + if (it.size() > 3) + *(indices++) = (int)it[3]; + else + *(indices++) = (int)-1; + } +} +