Implement Q3DO export.
We plan to use flatbuffers in the future for the next generation of the .slvs file format, so flatbuffers are built unconditionally; and the Q3DO exporter itself is tiny.pull/144/head
parent
9d1601eea9
commit
3a3a2755bf
|
@ -20,3 +20,9 @@
|
||||||
[submodule "extlib/angle"]
|
[submodule "extlib/angle"]
|
||||||
path = extlib/angle
|
path = extlib/angle
|
||||||
url = https://github.com/solvespace/angle
|
url = https://github.com/solvespace/angle
|
||||||
|
[submodule "extlib/flatbuffers"]
|
||||||
|
path = extlib/flatbuffers
|
||||||
|
url = https://github.com/google/flatbuffers
|
||||||
|
[submodule "extlib/q3d"]
|
||||||
|
path = extlib/q3d
|
||||||
|
url = https://github.com/q3k/q3d
|
||||||
|
|
|
@ -42,6 +42,10 @@ New export/import features:
|
||||||
* Wavefront OBJ: a material file is exported alongside the model, containing
|
* Wavefront OBJ: a material file is exported alongside the model, containing
|
||||||
mesh color information.
|
mesh color information.
|
||||||
* DXF/DWG: 3D DXF files are imported as construction entities, in 3d.
|
* DXF/DWG: 3D DXF files are imported as construction entities, in 3d.
|
||||||
|
* Q3D: [Q3D](https://github.com/q3k/q3d/) triangle meshes can now be
|
||||||
|
exported. This format allows to easily hack on triangle mesh data created
|
||||||
|
in SolveSpace, supports colour information and is more space efficient than
|
||||||
|
most other formats.
|
||||||
|
|
||||||
New rendering features:
|
New rendering features:
|
||||||
* The "Show/hide hidden lines" button is now a tri-state button that allows
|
* The "Show/hide hidden lines" button is now a tri-state button that allows
|
||||||
|
|
|
@ -103,6 +103,17 @@ endif()
|
||||||
message(STATUS "Using in-tree libdxfrw")
|
message(STATUS "Using in-tree libdxfrw")
|
||||||
add_subdirectory(extlib/libdxfrw)
|
add_subdirectory(extlib/libdxfrw)
|
||||||
|
|
||||||
|
message(STATUS "Using in-tree flatbuffers")
|
||||||
|
set(FLATBUFFERS_BUILD_FLATLIB ON CACHE BOOL "")
|
||||||
|
set(FLATBUFFERS_BUILD_FLATC ON CACHE BOOL "")
|
||||||
|
set(FLATBUFFERS_BUILD_FLATHASH OFF CACHE BOOL "")
|
||||||
|
set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "")
|
||||||
|
add_subdirectory(extlib/flatbuffers EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
message(STATUS "Using in-tree q3d")
|
||||||
|
add_subdirectory(extlib/q3d)
|
||||||
|
set(Q3D_INCLUDE_DIR ${CMAKE_BINARY_DIR}/extlib/q3d)
|
||||||
|
|
||||||
if(WIN32 OR APPLE)
|
if(WIN32 OR APPLE)
|
||||||
# On Win32 and macOS we use vendored packages, since there is little to no benefit
|
# On Win32 and macOS we use vendored packages, since there is little to no benefit
|
||||||
# to trying to find system versions. In particular, trying to link to libraries from
|
# to trying to find system versions. In particular, trying to link to libraries from
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit a1f14005ab823adc1300754fd37c01e9842ed4bc
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit fe71514837af1c627e9e1054d1aa0193a06d3488
|
|
@ -79,7 +79,8 @@ include_directories(
|
||||||
${ZLIB_INCLUDE_DIR}
|
${ZLIB_INCLUDE_DIR}
|
||||||
${PNG_PNG_INCLUDE_DIR}
|
${PNG_PNG_INCLUDE_DIR}
|
||||||
${FREETYPE_INCLUDE_DIRS}
|
${FREETYPE_INCLUDE_DIRS}
|
||||||
${CAIRO_INCLUDE_DIRS})
|
${CAIRO_INCLUDE_DIRS}
|
||||||
|
${Q3D_INCLUDE_DIR})
|
||||||
|
|
||||||
if(Backtrace_FOUND)
|
if(Backtrace_FOUND)
|
||||||
include_directories(
|
include_directories(
|
||||||
|
@ -211,12 +212,16 @@ add_library(solvespace-core STATIC
|
||||||
${solvespace_core_HEADERS}
|
${solvespace_core_HEADERS}
|
||||||
${solvespace_core_SOURCES})
|
${solvespace_core_SOURCES})
|
||||||
|
|
||||||
|
add_dependencies(solvespace-core
|
||||||
|
q3d_header)
|
||||||
|
|
||||||
target_link_libraries(solvespace-core
|
target_link_libraries(solvespace-core
|
||||||
dxfrw
|
dxfrw
|
||||||
${util_LIBRARIES}
|
${util_LIBRARIES}
|
||||||
${ZLIB_LIBRARY}
|
${ZLIB_LIBRARY}
|
||||||
${PNG_LIBRARY}
|
${PNG_LIBRARY}
|
||||||
${FREETYPE_LIBRARY})
|
${FREETYPE_LIBRARY}
|
||||||
|
flatbuffers)
|
||||||
|
|
||||||
if(Backtrace_FOUND)
|
if(Backtrace_FOUND)
|
||||||
target_link_libraries(solvespace-core
|
target_link_libraries(solvespace-core
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
// Copyright 2008-2013 Jonathan Westhues.
|
// Copyright 2008-2013 Jonathan Westhues.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#include "solvespace.h"
|
#include "solvespace.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
void SolveSpaceUI::ExportSectionTo(const Platform::Path &filename) {
|
void SolveSpaceUI::ExportSectionTo(const Platform::Path &filename) {
|
||||||
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
|
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
|
||||||
|
@ -826,6 +827,8 @@ void SolveSpaceUI::ExportMeshTo(const Platform::Path &filename) {
|
||||||
ExportMeshAsObjTo(f, fMtl, m);
|
ExportMeshAsObjTo(f, fMtl, m);
|
||||||
|
|
||||||
fclose(fMtl);
|
fclose(fMtl);
|
||||||
|
} else if(filename.HasExtension("q3do")) {
|
||||||
|
ExportMeshAsQ3doTo(f, m);
|
||||||
} else if(filename.HasExtension("js") ||
|
} else if(filename.HasExtension("js") ||
|
||||||
filename.HasExtension("html")) {
|
filename.HasExtension("html")) {
|
||||||
SOutlineList *e = &(SK.GetGroup(SS.GW.activeGroup)->displayOutlines);
|
SOutlineList *e = &(SK.GetGroup(SS.GW.activeGroup)->displayOutlines);
|
||||||
|
@ -877,6 +880,54 @@ void SolveSpaceUI::ExportMeshAsStlTo(FILE *f, SMesh *sm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Export the mesh as a Q3DO (https://github.com/q3k/q3d) file.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "object_generated.h"
|
||||||
|
void SolveSpaceUI::ExportMeshAsQ3doTo(FILE *f, SMesh *sm) {
|
||||||
|
flatbuffers::FlatBufferBuilder builder(1024);
|
||||||
|
double s = SS.exportScale;
|
||||||
|
|
||||||
|
// Create a material for every colour used, keep note of triangles belonging to color/material.
|
||||||
|
std::map<RgbaColor, flatbuffers::Offset<q3d::Material>, RgbaColorCompare> materials;
|
||||||
|
std::map<RgbaColor, std::vector<flatbuffers::Offset<q3d::Triangle>>, RgbaColorCompare> materialTriangles;
|
||||||
|
for (const STriangle &t : sm->l) {
|
||||||
|
auto color = t.meta.color;
|
||||||
|
if (materials.find(color) == materials.end()) {
|
||||||
|
auto name = builder.CreateString(ssprintf("Color #%02x%02x%02x%02x", color.red, color.green, color.blue, color.alpha));
|
||||||
|
auto co = q3d::CreateColor(builder, color.red, color.green, color.blue, color.alpha);
|
||||||
|
auto mo = q3d::CreateMaterial(builder, name, co);
|
||||||
|
materials.emplace(color, mo);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector faceNormal = t.Normal();
|
||||||
|
auto a = q3d::Vector3(t.a.x/s, t.a.y/s, t.a.z/s);
|
||||||
|
auto b = q3d::Vector3(t.b.x/s, t.b.y/s, t.b.z/s);
|
||||||
|
auto c = q3d::Vector3(t.c.x/s, t.c.y/s, t.c.z/s);
|
||||||
|
auto fn = q3d::Vector3(faceNormal.x, faceNormal.y, faceNormal.x);
|
||||||
|
auto n1 = q3d::Vector3(t.normals[0].x, t.normals[0].y, t.normals[0].z);
|
||||||
|
auto n2 = q3d::Vector3(t.normals[1].x, t.normals[1].y, t.normals[1].z);
|
||||||
|
auto n3 = q3d::Vector3(t.normals[2].x, t.normals[2].y, t.normals[2].z);
|
||||||
|
auto tri = q3d::CreateTriangle(builder, &a, &b, &c, &fn, &n1, &n2, &n3);
|
||||||
|
materialTriangles[color].push_back(tri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build all meshes sorted by material.
|
||||||
|
std::vector<flatbuffers::Offset<q3d::Mesh>> meshes;
|
||||||
|
for (auto &it : materials) {
|
||||||
|
auto &mato = it.second;
|
||||||
|
auto to = builder.CreateVector(materialTriangles[it.first]);
|
||||||
|
auto mo = q3d::CreateMesh(builder, to, mato);
|
||||||
|
meshes.push_back(mo);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mo = builder.CreateVector(meshes);
|
||||||
|
auto o = q3d::CreateObject(builder, mo);
|
||||||
|
q3d::FinishObjectBuffer(builder, o);
|
||||||
|
fwrite(builder.GetBufferPointer(), builder.GetSize(), 1, f);
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Export the mesh as Wavefront OBJ format. This requires us to reduce all the
|
// Export the mesh as Wavefront OBJ format. This requires us to reduce all the
|
||||||
// identical vertices to the same identifier, so do that first.
|
// identical vertices to the same identifier, so do that first.
|
||||||
|
|
|
@ -94,6 +94,7 @@ std::vector<FileFilter> MeshFileFilters = {
|
||||||
{ CN_("file-type", "Wavefront OBJ mesh"), { "obj" } },
|
{ CN_("file-type", "Wavefront OBJ mesh"), { "obj" } },
|
||||||
{ CN_("file-type", "Three.js-compatible mesh, with viewer"), { "html" } },
|
{ CN_("file-type", "Three.js-compatible mesh, with viewer"), { "html" } },
|
||||||
{ CN_("file-type", "Three.js-compatible mesh, mesh only"), { "js" } },
|
{ CN_("file-type", "Three.js-compatible mesh, mesh only"), { "js" } },
|
||||||
|
{ CN_("file-type", "Q3D Object file"), { "q3do" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<FileFilter> SurfaceFileFilters = {
|
std::vector<FileFilter> SurfaceFileFilters = {
|
||||||
|
|
|
@ -693,6 +693,7 @@ public:
|
||||||
void ExportAsPngTo(const Platform::Path &filename);
|
void ExportAsPngTo(const Platform::Path &filename);
|
||||||
void ExportMeshTo(const Platform::Path &filename);
|
void ExportMeshTo(const Platform::Path &filename);
|
||||||
void ExportMeshAsStlTo(FILE *f, SMesh *sm);
|
void ExportMeshAsStlTo(FILE *f, SMesh *sm);
|
||||||
|
void ExportMeshAsQ3doTo(FILE *f, SMesh *sm);
|
||||||
void ExportMeshAsObjTo(FILE *fObj, FILE *fMtl, SMesh *sm);
|
void ExportMeshAsObjTo(FILE *fObj, FILE *fMtl, SMesh *sm);
|
||||||
void ExportMeshAsThreeJsTo(FILE *f, const Platform::Path &filename,
|
void ExportMeshAsThreeJsTo(FILE *f, const Platform::Path &filename,
|
||||||
SMesh *sm, SOutlineList *sol);
|
SMesh *sm, SOutlineList *sol);
|
||||||
|
|
Loading…
Reference in New Issue