Added new optional dependency - Draco library.
RWGltf_GltfJsonParser now detects KHR_draco_mesh_compression extension,
marks accessor being compressed and redirects to compressed buffer view.
RWGltf_TriangulationReader now handles decoding of buffer view compressed using Draco.
env.bat template for genproj has been modified to allow specifying dedicated folders
with debug versions of libraries (CSF_OPT_LIB64D / CSF_OPT_BIN64D) within custom.bat.
Removed unused CSF_FREETYPE from TKOpenGl.
set (USE_FFMPEG OFF CACHE BOOL "${USE_FFMPEG_DESCR}")
set (USE_OPENVR OFF CACHE BOOL "${USE_OPENVR_DESCR}")
set (USE_RAPIDJSON OFF CACHE BOOL "${USE_RAPIDJSON_DESCR}")
+set (USE_DRACO OFF CACHE BOOL "${USE_DRACO_DESCR}")
set (USE_TBB OFF CACHE BOOL "${USE_TBB_DESCR}")
set (USE_EIGEN OFF CACHE BOOL "${USE_EIGEN_DESCR}")
OCCT_CHECK_AND_UNSET ("INSTALL_RAPIDJSON")
endif()
+# Draco library
+# search for CSF_Draco variable in EXTERNLIB of each being used toolkit
+OCCT_IS_PRODUCT_REQUIRED (CSF_Draco CAN_USE_DRACO)
+if (CAN_USE_DRACO)
+ if (USE_DRACO)
+ add_definitions (-DHAVE_DRACO)
+ OCCT_INCLUDE_CMAKE_FILE ("adm/cmake/draco")
+ else()
+ OCCT_CHECK_AND_UNSET_GROUP ("3RDPARTY_DRACO")
+ OCCT_CHECK_AND_UNSET ("INSTALL_DRACO")
+ endif()
+else()
+ OCCT_CHECK_AND_UNSET ("USE_DRACO")
+
+ OCCT_CHECK_AND_UNSET_GROUP ("3RDPARTY_DRACO")
+ OCCT_CHECK_AND_UNSET ("INSTALL_DRACO")
+endif()
+
# EIGEN
if (CAN_USE_EIGEN)
if (USE_EIGEN)
--- /dev/null
+# Draco - a library for a lossy vertex data compression, used as extension to glTF format.
+# https://github.com/google/draco
+
+THIRDPARTY_PRODUCT("DRACO" "draco/compression/decode.h" "CSF_Draco" "")
endif()
endif()
+# Draco
+if (USE_DRACO)
+ set (CSF_Draco "draco")
+else()
+ set (CSF_Draco)
+endif()
+
if (WIN32)
set (CSF_advapi32 "advapi32.lib")
set (CSF_gdi32 "gdi32.lib")
"Indicates whether RapidJSON product should be used in OCCT DataExchange
module for support of JSON-based formats like glTF")
+set (USE_DRACO_DESCR
+"Indicates whether Draco mesh decoding library should be used by glTF reader")
+
set (USE_EGL_DESCR
"Indicates whether EGL should be used in OCCT visualization
module instead of conventional OpenGL context creation APIs")
if { "$::HAVE_RAPIDJSON" == "true" } {
wokdep:SearchRapidJson anIncErrs anLib32Errs anLib64Errs anBin32Errs anBin64Errs
}
+ if { "$::HAVE_DRACO" == "true" } {
+ set aDummy {}
+ wokdep:SearchStandardLibrary anIncErrs anLib32Errs anLib64Errs aDummy aDummy "draco" "draco/compression/decode.h" "draco" {"draco"}
+ }
if {"$::BUILD_Inspector" == "true" } {
set ::CHECK_QT "true"
#ttk::label .myFrame.myChecks.myOpenClLbl -text "Use OpenCL"
checkbutton .myFrame.myChecks.myRapidJsonCheck -offvalue "false" -onvalue "true" -variable HAVE_RAPIDJSON -command wokdep:gui:UpdateList
ttk::label .myFrame.myChecks.myRapidJsonLbl -text "Use RapidJSON"
+checkbutton .myFrame.myChecks.myDracoCheck -offvalue "false" -onvalue "true" -variable HAVE_DRACO -command wokdep:gui:UpdateList
+ttk::label .myFrame.myChecks.myDracoLbl -text "Use Draco"
checkbutton .myFrame.myChecks.myXLibCheck -offvalue "false" -onvalue "true" -variable HAVE_XLIB
ttk::label .myFrame.myChecks.myXLibLbl -text "Use X11 for windows drawing"
incr aCheckRowIter
grid .myFrame.myChecks.myFImageCheck -row $aCheckRowIter -column 0 -sticky e
grid .myFrame.myChecks.myFImageLbl -row $aCheckRowIter -column 1 -sticky w
-grid .myFrame.myChecks.myTbbCheck -row $aCheckRowIter -column 2 -sticky e
-grid .myFrame.myChecks.myTbbLbl -row $aCheckRowIter -column 3 -sticky w
+grid .myFrame.myChecks.myDracoCheck -row $aCheckRowIter -column 2 -sticky e
+grid .myFrame.myChecks.myDracoLbl -row $aCheckRowIter -column 3 -sticky w
+
if { "$::tcl_platform(platform)" == "windows" } {
grid .myFrame.myChecks.myD3dCheck -row $aCheckRowIter -column 4 -sticky e
grid .myFrame.myChecks.myD3dLbl -row $aCheckRowIter -column 5 -sticky w
incr aCheckRowIter
+grid .myFrame.myChecks.myTbbCheck -row $aCheckRowIter -column 12 -sticky e
+grid .myFrame.myChecks.myTbbLbl -row $aCheckRowIter -column 13 -sticky w
+
+incr aCheckRowIter
+
# Additional headers search paths
grid .myFrame.myIncLbl -row $aRowIter -column 0 -columnspan 10 -sticky w
incr aRowIter
}
# fetch environment variables (e.g. set by custom.sh or custom.bat) and set them as tcl variables with the same name
-set THE_ENV_VARIABLES {HAVE_TK HAVE_FREETYPE HAVE_FREEIMAGE HAVE_FFMPEG HAVE_TBB HAVE_GLES2 HAVE_D3D HAVE_VTK HAVE_ZLIB HAVE_LIBLZMA HAVE_E57 HAVE_RAPIDJSON HAVE_OPENVR HAVE_OPENCL CHECK_QT4 CHECK_JDK HAVE_XLIB HAVE_RelWithDebInfo BUILD_Inspector}
+set THE_ENV_VARIABLES { HAVE_TK HAVE_FREETYPE HAVE_FREEIMAGE HAVE_FFMPEG HAVE_TBB HAVE_GLES2 HAVE_D3D HAVE_VTK \
+ HAVE_ZLIB HAVE_LIBLZMA HAVE_E57 HAVE_RAPIDJSON HAVE_DRACO HAVE_OPENVR HAVE_OPENCL \
+ CHECK_QT4 CHECK_JDK HAVE_XLIB \
+ HAVE_RelWithDebInfo BUILD_Inspector }
foreach anEnvIter $THE_ENV_VARIABLES { set ${anEnvIter} "false" }
set HAVE_TK "true"
set HAVE_FREETYPE "true"
if { "$::HAVE_LIBLZMA" == "true" } {
set aLibsMap(CSF_LIBLZMA) "liblzma"
}
+ if { "$::HAVE_DRACO" == "true" } {
+ set aLibsMap(CSF_Draco) "draco"
+ }
if { "$::HAVE_OPENVR" == "true" } {
set aLibsMap(CSF_OpenVR) "openvr_api"
}
set "HAVE_ZLIB=false"
set "HAVE_LIBLZMA=false"
set "HAVE_RAPIDJSON=false"
+set "HAVE_DRACO=false"
set "HAVE_OPENVR=false"
set "HAVE_E57=false"
set "CSF_OPT_INC="
set "CSF_OPT_LIB64="
set "CSF_OPT_BIN32="
set "CSF_OPT_BIN64="
+set "CSF_OPT_LIB32D="
+set "CSF_OPT_LIB64D="
+set "CSF_OPT_BIN32D="
+set "CSF_OPT_BIN64D="
+set "CSF_OPT_LIB32I="
+set "CSF_OPT_LIB64I="
+set "CSF_OPT_BIN32I="
+set "CSF_OPT_BIN64I="
set "CSF_DEFINES=%CSF_DEFINES_EXTRA%"
if not ["%CASROOT%"] == [""] if exist "%SCRIPTROOT%\%CASROOT%" set "CASROOT=%SCRIPTROOT%\%CASROOT%"
exit /B
)
-set "CSF_OPT_LIB32D=%CSF_OPT_LIB32%"
-set "CSF_OPT_LIB64D=%CSF_OPT_LIB64%"
-set "CSF_OPT_BIN32D=%CSF_OPT_BIN32%"
-set "CSF_OPT_BIN64D=%CSF_OPT_BIN64%"
-set "CSF_OPT_LIB32I=%CSF_OPT_LIB32%"
-set "CSF_OPT_LIB64I=%CSF_OPT_LIB64%"
-set "CSF_OPT_BIN32I=%CSF_OPT_BIN32%"
-set "CSF_OPT_BIN64I=%CSF_OPT_BIN64%"
+if ["%CSF_OPT_LIB32D%"] == [""] set "CSF_OPT_LIB32D=%CSF_OPT_LIB32%"
+if ["%CSF_OPT_LIB64D%"] == [""] set "CSF_OPT_LIB64D=%CSF_OPT_LIB64%"
+if ["%CSF_OPT_BIN32D%"] == [""] set "CSF_OPT_BIN32D=%CSF_OPT_BIN32%"
+if ["%CSF_OPT_BIN64D%"] == [""] set "CSF_OPT_BIN64D=%CSF_OPT_BIN64%"
+if ["%CSF_OPT_LIB32I%"] == [""] set "CSF_OPT_LIB32I=%CSF_OPT_LIB32%"
+if ["%CSF_OPT_LIB64I%"] == [""] set "CSF_OPT_LIB64I=%CSF_OPT_LIB64%"
+if ["%CSF_OPT_BIN32I%"] == [""] set "CSF_OPT_BIN32I=%CSF_OPT_BIN32%"
+if ["%CSF_OPT_BIN64I%"] == [""] set "CSF_OPT_BIN64I=%CSF_OPT_BIN64%"
rem ----- Optional 3rd-parties should be enabled by HAVE macros -----
set "CSF_OPT_CMPL="
if ["%HAVE_ZLIB%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_ZLIB" & set "CSF_DEFINES=HAVE_ZLIB;%CSF_DEFINES%"
if ["%HAVE_LIBLZMA%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_LIBLZMA" & set "CSF_DEFINES=HAVE_LIBLZMA;%CSF_DEFINES%"
if ["%HAVE_RAPIDJSON%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_RAPIDJSON" & set "CSF_DEFINES=HAVE_RAPIDJSON;%CSF_DEFINES%"
+if ["%HAVE_DRACO%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_DRACO" & set "CSF_DEFINES=HAVE_DRACO;%CSF_DEFINES%"
if ["%HAVE_OPENVR%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_OPENVR" & set "CSF_DEFINES=HAVE_OPENVR;%CSF_DEFINES%"
if ["%HAVE_E57%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_E57" & set "CSF_DEFINES=HAVE_E57;%CSF_DEFINES%"
export HAVE_ZLIB="false";
export HAVE_LIBLZMA="false";
export HAVE_RAPIDJSON="false";
+export HAVE_DRACO="false";
export HAVE_OPENVR="false";
export HAVE_E57="false";
export HAVE_XLIB="true";
if [ "$HAVE_ZLIB" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_ZLIB"; fi
if [ "$HAVE_LIBLZMA" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_LIBLZMA"; fi
if [ "$HAVE_RAPIDJSON" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_RAPIDJSON"; fi
+if [ "$HAVE_DRACO" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_DRACO"; fi
if [ "$HAVE_OPENVR" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_OPENVR"; fi
if [ "$HAVE_E57" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_E57"; fi
if [ "$HAVE_XLIB" == "true" ]; then export CSF_OPT_CMPL="${CSF_OPT_CMPL} -DHAVE_XLIB"; fi
| VTK 6.1+ | https://www.vtk.org/download/ | Visualization | Optional (VTK integration) |
| Flex 2.6.4+ and Bison 3.7.1+ | https://sourceforge.net/projects/winflexbison/ | Data Exchange | Optional (update of STEP and ExprIntrp parsers) |
| RapidJSON 1.1+ | https://rapidjson.org/ | Data Exchange | Optional (reading glTF files) |
+| Draco 1.4.1+ | https://github.com/google/draco | Data Exchange | Optional (reading compressed glTF files) |
| Tcl/Tk 8.6.3+ <br> or ActiveTcl 8.6 | https://www.tcl.tk/software/tcltk/download.html <br> https://www.activestate.com/activetcl/downloads | DRAW Test Harness | Required |
| Qt Desktop: Qt 4.8.6+ <br> Android: Qt 5.3.2+ | https://www.qt.io/download/ | Samples and demos | Optional (Qt samples) |
| Doxygen 1.8.5+ | https://www.doxygen.nl/download.html | Documentation | Required |
**RapidJSON** is an Open Source JSON parser and generator for C++.
RapidJSON is optionally used by OCCT for reading glTF files (https://rapidjson.org/).
+**Draco** is an Open Source JSON parser and generator for C++.
+Draco is optionally used by OCCT for reading glTF files using KHR_draco_mesh_compression extension (https://github.com/google/draco).
+Draco is available under Apache 2.0 license.
+
**DejaVu** fonts are a font family based on the Vera Fonts under a permissive license (MIT-like, https://dejavu-fonts.github.io/License.html).
DejaVu Sans (basic Latin sub-set) is used by OCCT as fallback font when no system font is available.
#else
di << "RapidJSON disabled\n";
#endif
+#ifdef HAVE_DRACO
+ di << "Draco enabled (HAVE_DRACO)\n";
+#else
+ di << "Draco disabled\n";
+#endif
#ifdef HAVE_VTK
di << "VTK enabled (HAVE_VTK)\n";
#else
RWGltf_GltfAccessorLayout Type; //!< layout type
RWGltf_GltfAccessorCompType ComponentType; //!< component type
Graphic3d_BndBox3d BndBox; //!< bounding box
+ bool IsCompressed; //!< flag indicating KHR_draco_mesh_compression
//! Empty constructor.
RWGltf_GltfAccessor()
Count (0),
ByteStride (0),
Type (RWGltf_GltfAccessorLayout_UNKNOWN),
- ComponentType (RWGltf_GltfAccessorCompType_UNKNOWN) {}
+ ComponentType (RWGltf_GltfAccessorCompType_UNKNOWN),
+ IsCompressed (false) {}
};
namespace
{
//! Material extension.
- const char THE_KHR_materials_common[] = "KHR_materials_common";
- const char THE_KHR_binary_glTF[] = "KHR_binary_glTF";
+ static const char THE_KHR_materials_common[] = "KHR_materials_common";
+ static const char THE_KHR_binary_glTF[] = "KHR_binary_glTF";
+ static const char THE_KHR_draco_mesh_compression[] = "KHR_draco_mesh_compression";
//! Data buffer referring to a portion of another buffer.
class RWGltf_SubBuffer : public NCollection_Buffer
const RWGltf_JsonValue* anIndices = findObjectMember (thePrimArray, "indices");
const RWGltf_JsonValue* aMaterial = findObjectMember (thePrimArray, "material");
const RWGltf_JsonValue* aModeVal = findObjectMember (thePrimArray, "mode");
+ const RWGltf_JsonValue* anExtVal = findObjectMember (thePrimArray, "extensions");
+ const RWGltf_JsonValue* aDracoVal = anExtVal != NULL
+ ? findObjectMember (*anExtVal, THE_KHR_draco_mesh_compression)
+ : NULL;
+ const RWGltf_JsonValue* aDracoBuf = aDracoVal != NULL
+ ? findObjectMember (*aDracoVal, "bufferView")
+ : NULL;
+
RWGltf_GltfPrimitiveMode aMode = RWGltf_GltfPrimitiveMode_Triangles;
if (anAttribs == NULL
|| !anAttribs->IsObject())
reportGltfError ("Primitive array attribute accessor key '" + anAttribId + "' points to non-existing object.");
return false;
}
- else if (!gltfParseAccessor (theMeshData, anAttribId, *anAccessor, aType))
+ else if (!gltfParseAccessor (theMeshData, anAttribId, *anAccessor, aType, aDracoBuf))
{
return false;
}
reportGltfError ("Primitive array indices accessor key '" + anIndicesId + "' points to non-existing object.");
return false;
}
- else if (!gltfParseAccessor (theMeshData, anIndicesId, *anAccessor, RWGltf_GltfArrayType_Indices))
+ else if (!gltfParseAccessor (theMeshData, anIndicesId, *anAccessor, RWGltf_GltfArrayType_Indices, aDracoBuf))
{
return false;
}
bool RWGltf_GltfJsonParser::gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
const TCollection_AsciiString& theName,
const RWGltf_JsonValue& theAccessor,
- const RWGltf_GltfArrayType theType)
+ const RWGltf_GltfArrayType theType,
+ const RWGltf_JsonValue* theCompBuffView)
{
RWGltf_GltfAccessor aStruct;
const RWGltf_JsonValue* aTypeStr = findObjectMember (theAccessor, "type");
- const RWGltf_JsonValue* aBufferViewName = findObjectMember (theAccessor, "bufferView");
- const RWGltf_JsonValue* aByteOffset = findObjectMember (theAccessor, "byteOffset");
+ const RWGltf_JsonValue* aBufferViewName = theCompBuffView == NULL
+ ? findObjectMember (theAccessor, "bufferView")
+ : theCompBuffView;
+ const RWGltf_JsonValue* aByteOffset = theCompBuffView == NULL
+ ? findObjectMember (theAccessor, "byteOffset")
+ : 0;
const RWGltf_JsonValue* aByteStride = findObjectMember (theAccessor, "byteStride"); // byteStride was part of bufferView in glTF 1.0
const RWGltf_JsonValue* aCompType = findObjectMember (theAccessor, "componentType");
const RWGltf_JsonValue* aCount = findObjectMember (theAccessor, "count");
return false;
}
aStruct.Type = RWGltf_GltfParseAccessorType (aTypeStr->GetString());
+ aStruct.IsCompressed = theCompBuffView != NULL;
if (aStruct.Type == RWGltf_GltfAccessorLayout_UNKNOWN)
{
reportGltfError ("Accessor '" + theName + "' has invalid type.");
aData.Accessor = theAccessor;
aData.Accessor.ByteStride = aByteStride;
aData.StreamOffset = anOffset;
+ aData.StreamLength = theView.ByteLength;
aData.StreamUri = myFilePath;
return true;
}
aData.Accessor = theAccessor;
aData.Accessor.ByteStride = aByteStride;
aData.StreamOffset = anOffset;
+ aData.StreamLength = 0;
if (!myDecodedBuffers.Find (theName, aData.StreamData))
{
// it is better decoding in multiple threads
aData.Accessor = theAccessor;
aData.Accessor.ByteStride = aByteStride;
aData.StreamOffset = anOffset;
+ aData.StreamLength = theView.ByteLength;
aData.StreamUri = myFolder + anUri;
if (myExternalFiles != NULL)
{
Standard_EXPORT bool gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
const TCollection_AsciiString& theName,
const RWGltf_JsonValue& theAccessor,
- const RWGltf_GltfArrayType theType);
+ const RWGltf_GltfArrayType theType,
+ const RWGltf_JsonValue* theCompBuffView);
//! Parse buffer view.
Standard_EXPORT bool gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
//! Add primitive array data element.
Standard_EXPORT RWGltf_GltfPrimArrayData& AddPrimArrayData (RWGltf_GltfArrayType theType);
- //! Return TRUE if there is deferred storege and some triangulation data
+ //! Return TRUE if there is deferred storage and some triangulation data
//! that can be loaded using LoadDeferredData().
virtual Standard_Boolean HasDeferredData() const Standard_OVERRIDE
{
Handle(NCollection_Buffer) StreamData;
TCollection_AsciiString StreamUri;
int64_t StreamOffset;
+ int64_t StreamLength;
RWGltf_GltfAccessor Accessor;
RWGltf_GltfArrayType Type;
RWGltf_GltfPrimArrayData()
- : StreamOffset (0), Type (RWGltf_GltfArrayType_UNKNOWN) {}
+ : StreamOffset (0), StreamLength (0), Type (RWGltf_GltfArrayType_UNKNOWN) {}
RWGltf_GltfPrimArrayData (RWGltf_GltfArrayType theType)
- : StreamOffset (0), Type (theType) {}
+ : StreamOffset (0), StreamLength (0), Type (theType) {}
};
#endif // _RWGltf_GltfPrimArrayData_HeaderFile
#include <Standard_ArrayStreamBuffer.hxx>
#include <Standard_ReadBuffer.hxx>
+#ifdef HAVE_DRACO
+ #include <draco/compression/decode.h>
+#endif
+
namespace
{
static const Standard_Integer THE_LOWER_TRI_INDEX = 1;
static const Standard_Integer THE_LOWER_NODE_INDEX = 1;
static const Standard_ShortReal THE_NORMAL_PREC2 = 0.001f;
+
+#ifdef HAVE_DRACO
+ //! Return array type from Draco attribute type.
+ static RWGltf_GltfArrayType arrayTypeFromDraco (draco::GeometryAttribute::Type theType)
+ {
+ switch (theType)
+ {
+ case draco::GeometryAttribute::POSITION: return RWGltf_GltfArrayType_Position;
+ case draco::GeometryAttribute::NORMAL: return RWGltf_GltfArrayType_Normal;
+ case draco::GeometryAttribute::COLOR: return RWGltf_GltfArrayType_Color;
+ case draco::GeometryAttribute::TEX_COORD: return RWGltf_GltfArrayType_TCoord0;
+ default: return RWGltf_GltfArrayType_UNKNOWN;
+ }
+ }
+
+ //! Return layout from Draco number of components.
+ static RWGltf_GltfAccessorLayout layoutFromDraco (int8_t theNbComps)
+ {
+ switch (theNbComps)
+ {
+ case 1: return RWGltf_GltfAccessorLayout_Scalar;
+ case 2: return RWGltf_GltfAccessorLayout_Vec2;
+ case 3: return RWGltf_GltfAccessorLayout_Vec3;
+ case 4: return RWGltf_GltfAccessorLayout_Vec4;
+ }
+ return RWGltf_GltfAccessorLayout_UNKNOWN;
+ }
+
+ //! Return component type from Draco data type.
+ static RWGltf_GltfAccessorCompType compTypeFromDraco (draco::DataType theType)
+ {
+ switch (theType)
+ {
+ case draco::DT_INT8: return RWGltf_GltfAccessorCompType_Int8;
+ case draco::DT_UINT8: return RWGltf_GltfAccessorCompType_UInt8;
+ case draco::DT_INT16: return RWGltf_GltfAccessorCompType_Int16;
+ case draco::DT_UINT16: return RWGltf_GltfAccessorCompType_UInt16;
+ case draco::DT_INT32:
+ case draco::DT_UINT32: return RWGltf_GltfAccessorCompType_UInt32;
+ //case draco::DT_INT64:
+ //case draco::DT_UINT64:
+ case draco::DT_FLOAT32: return RWGltf_GltfAccessorCompType_Float32;
+ //case draco::DT_FLOAT64:
+ //case draco::DT_BOOL:
+ default: return RWGltf_GltfAccessorCompType_UNKNOWN;
+ }
+ }
+#endif
}
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWMesh_TriangulationReader)
(theGltfData.StreamUri, std::ios::in | std::ios::binary, theGltfData.StreamOffset);
if (aSharedStream.get() == NULL)
{
- reportError (TCollection_AsciiString("Buffer '") + theSourceGltfMesh->Id() + "refers to invalid file '" + theGltfData.StreamUri + "'.");
+ reportError (TCollection_AsciiString("Buffer '") + theSourceGltfMesh->Id() + "' refers to invalid file '" + theGltfData.StreamUri + "'.");
return false;
}
+
if (!readBuffer (theSourceGltfMesh, theDestMesh, *aSharedStream.get(), theGltfData.Accessor, theGltfData.Type))
{
return false;
return wasLoaded;
}
+// =======================================================================
+// function : readDracoBuffer
+// purpose :
+// =======================================================================
+bool RWGltf_TriangulationReader::readDracoBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
+ const RWGltf_GltfPrimArrayData& theGltfData,
+ const Handle(Poly_Triangulation)& theDestMesh,
+ const Handle(OSD_FileSystem)& theFileSystem) const
+{
+ const TCollection_AsciiString& aName = theSourceGltfMesh->Id();
+ const Handle(OSD_FileSystem)& aFileSystem = !theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem();
+ opencascade::std::shared_ptr<std::istream> aSharedStream = aFileSystem->OpenIStream (theGltfData.StreamUri, std::ios::in | std::ios::binary, theGltfData.StreamOffset);
+ if (aSharedStream.get() == NULL)
+ {
+ reportError (TCollection_AsciiString("Buffer '") + aName + "' refers to invalid file '" + theGltfData.StreamUri + "'.");
+ return false;
+ }
+
+#ifdef HAVE_DRACO
+ std::vector<char> aReadData;
+ aReadData.resize (theGltfData.StreamLength);
+ aSharedStream->read (aReadData.data(), (std::streamsize )theGltfData.StreamLength);
+ if (!aSharedStream->good())
+ {
+ reportError (TCollection_AsciiString("Buffer '") + aName + "' refers to file that cannot be read '" + theGltfData.StreamUri + "'.");
+ return false;
+ }
+
+ draco::DecoderBuffer aDracoBuf;
+ aDracoBuf.Init (aReadData.data(), aReadData.size());
+
+ draco::Decoder aDracoDecoder;
+ draco::StatusOr<std::unique_ptr<draco::Mesh>> aDracoStat = aDracoDecoder.DecodeMeshFromBuffer (&aDracoBuf);
+ if (!aDracoStat.ok() || aDracoStat.value().get() == NULL)
+ {
+ reportError (TCollection_AsciiString("Buffer '") + aName + "' refers to Draco data that cannot be decoded '" + theGltfData.StreamUri + "'.");
+ return false;
+ }
+
+ const Standard_Integer aNbNodes = (Standard_Integer )aDracoStat.value()->num_points();
+ const Standard_Integer aNbTris = (Standard_Integer )aDracoStat.value()->num_faces();
+ if (aNbNodes < 0)
+ {
+ reportError (TCollection_AsciiString ("Buffer '") + aName + "' defines an empty array.");
+ return false;
+ }
+ if ((int64_t )aDracoStat.value()->num_points() > std::numeric_limits<Standard_Integer>::max())
+ {
+ reportError (TCollection_AsciiString ("Buffer '") + aName + "' defines too big array.");
+ return false;
+ }
+ if (!setNbPositionNodes (theDestMesh, aNbNodes))
+ {
+ return false;
+ }
+
+ if (aNbTris > 0
+ && !setNbTriangles (theDestMesh, aNbTris))
+ {
+ return false;
+ }
+
+ // copy vertex attributes
+ for (int32_t anAttrIter = 0; anAttrIter < aDracoStat.value()->num_attributes(); ++anAttrIter)
+ {
+ const draco::PointAttribute* anAttrib = aDracoStat.value()->attribute (anAttrIter);
+ const RWGltf_GltfArrayType aWrapType = arrayTypeFromDraco(anAttrib->attribute_type());
+ const RWGltf_GltfAccessorLayout aWrapLayout = layoutFromDraco (anAttrib->num_components());
+ const RWGltf_GltfAccessorCompType aWrapCompType = compTypeFromDraco (anAttrib->data_type());
+ switch (aWrapType)
+ {
+ case RWGltf_GltfArrayType_Position:
+ {
+ if (aWrapCompType != RWGltf_GltfAccessorCompType_Float32
+ || aWrapLayout != RWGltf_GltfAccessorLayout_Vec3)
+ {
+ reportError (TCollection_AsciiString ("Buffer '") + aName + "' has unsupported position data type.");
+ return false;
+ }
+
+ for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
+ {
+ const Graphic3d_Vec3* aVec3 = reinterpret_cast<const Graphic3d_Vec3* >(anAttrib->GetAddressOfMappedIndex (draco::PointIndex (aVertIter)));
+ if (aVec3 == NULL)
+ {
+ reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
+ return false;
+ }
+
+ gp_Pnt anXYZ (aVec3->x(), aVec3->y(), aVec3->z());
+ myCoordSysConverter.TransformPosition (anXYZ.ChangeCoord());
+ setNodePosition (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, anXYZ);
+ }
+ }
+ case RWGltf_GltfArrayType_Normal:
+ {
+ if (aWrapCompType != RWGltf_GltfAccessorCompType_Float32
+ || aWrapLayout != RWGltf_GltfAccessorLayout_Vec3)
+ {
+ Message::SendTrace (TCollection_AsciiString() + "Vertex normals in unsupported format have been skipped while reading glTF triangulation '" + aName + "'");
+ break;
+ }
+
+ if (!setNbNormalNodes (theDestMesh, aNbNodes))
+ {
+ return false;
+ }
+
+ for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
+ {
+ const Graphic3d_Vec3* aVec3 = reinterpret_cast<const Graphic3d_Vec3* >(anAttrib->GetAddressOfMappedIndex (draco::PointIndex (aVertIter)));
+ if (aVec3 == NULL)
+ {
+ reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
+ return false;
+ }
+ if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
+ {
+ Graphic3d_Vec3 aVec3Copy = *aVec3;
+ myCoordSysConverter.TransformNormal (aVec3Copy);
+ setNodeNormal (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, aVec3Copy);
+ }
+ else
+ {
+ setNodeNormal (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Vec3f(0.0, 0.0, 1.0));
+ }
+ }
+ break;
+ }
+ case RWGltf_GltfArrayType_TCoord0:
+ {
+ if (aWrapCompType != RWGltf_GltfAccessorCompType_Float32
+ || aWrapLayout != RWGltf_GltfAccessorLayout_Vec2)
+ {
+ Message::SendTrace (TCollection_AsciiString() + "Vertex UV coordinates in unsupported format have been skipped while reading glTF triangulation '" + aName + "'");
+ break;
+ }
+
+ if (!setNbUVNodes (theDestMesh, aNbNodes))
+ {
+ return false;
+ }
+
+ for (int aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
+ {
+ const Graphic3d_Vec2* aVec2 = reinterpret_cast<const Graphic3d_Vec2* >(anAttrib->GetAddressOfMappedIndex (draco::PointIndex (aVertIter)));
+ if (aVec2 == NULL)
+ {
+ reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
+ return false;
+ }
+
+ // Y should be flipped (relative to image layout used by OCCT)
+ float aTexY = 1.0f - aVec2->y();
+ setNodeUV (theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt2d (aVec2->x(), aTexY));
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ // copy triangles
+ Standard_Integer aLastTriIndex = 0;
+ for (Standard_Integer aFaceIter = 0; aFaceIter < aNbTris; ++aFaceIter)
+ {
+ const draco::Mesh::Face& aFace = aDracoStat.value()->face (draco::FaceIndex (aFaceIter));
+ Poly_Triangle aVec3;
+ aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + aFace[0].value();
+ aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + aFace[1].value();
+ aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + aFace[2].value();
+ const Standard_Integer wasSet = setTriangle (theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3);
+ if (!wasSet)
+ {
+ reportError (TCollection_AsciiString ("Buffer '") + aName + "' refers to invalid indices.");
+ }
+ if (wasSet > 0)
+ {
+ ++aLastTriIndex;
+ }
+ }
+
+ const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex;
+ if (aNbDegenerate > 0)
+ {
+ if (aNbDegenerate == aNbTris)
+ {
+ Message::SendWarning (TCollection_AsciiString("Buffer '") + aName + "' has been skipped (all elements are degenerative in)");
+ return false;
+ }
+ theSourceGltfMesh->ChangeDegeneratedTriNb() += aNbDegenerate;
+ if (myLoadingStatistic == NULL && myToPrintDebugMessages)
+ {
+ Message::SendTrace (TCollection_AsciiString() + aNbDegenerate
+ + " degenerate triangles have been skipped while reading glTF triangulation '" + aName + "'");
+ }
+ if (!setNbTriangles (theDestMesh, aLastTriIndex, true))
+ {
+ return false;
+ }
+ }
+ return true;
+#else
+ (void )theDestMesh;
+ reportError (TCollection_AsciiString ("Buffer '") + aName + "' refers to unsupported compressed data.");
+ return false;
+#endif
+}
+
// =======================================================================
// function : load
// purpose :
return false;
}
+ bool hasCompressed = false;
for (NCollection_Sequence<RWGltf_GltfPrimArrayData>::Iterator aDataIter (aSourceGltfMesh->Data()); aDataIter.More(); aDataIter.Next())
{
const RWGltf_GltfPrimArrayData& aData = aDataIter.Value();
+ const TCollection_AsciiString& aName = aSourceGltfMesh->Id();
if (!aData.StreamData.IsNull())
{
- Message::SendWarning (TCollection_AsciiString("Buffer '") + aSourceGltfMesh->Id() +
+ Message::SendWarning (TCollection_AsciiString("Buffer '") + aName +
"' contains stream data that cannot be loaded during deferred data loading.");
continue;
}
else if (aData.StreamUri.IsEmpty())
{
- reportError (TCollection_AsciiString ("Buffer '") + aSourceGltfMesh->Id() + "' does not define uri.");
+ reportError (TCollection_AsciiString ("Buffer '") + aName + "' does not define uri.");
return false;
}
- if (!readFileData (aSourceGltfMesh, aData, theDestMesh, theFileSystem))
+ if (aData.Accessor.IsCompressed)
+ {
+ if (hasCompressed)
+ {
+ // already decoded (compressed stream defines all attributes at once)
+ continue;
+ }
+ if (!readDracoBuffer (aSourceGltfMesh, aData, theDestMesh, theFileSystem))
+ {
+ return false;
+ }
+
+ // keep decoding - there are might be uncompressed attributes in addition to compressed
+ hasCompressed = true;
+ }
+ else if (!readFileData (aSourceGltfMesh, aData, theDestMesh, theFileSystem))
{
return false;
}
const RWGltf_GltfAccessor& theAccessor,
RWGltf_GltfArrayType theType) const;
+ //! Reads primitive array from file data compressed in Draco format.
+ //! @param theSourceGltfMesh source glTF triangulation
+ //! @param theGltfData primitive array element (Uri of file stream should not be empty)
+ //! @param theDestMesh triangulation to be modified
+ //! @param theFileSystem shared file system to read from
+ Standard_EXPORT virtual bool readDracoBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
+ const RWGltf_GltfPrimArrayData& theGltfData,
+ const Handle(Poly_Triangulation)& theDestMesh,
+ const Handle(OSD_FileSystem)& theFileSystem) const;
+
protected:
Handle(Poly_Triangulation) myTriangulation;
TKService
TKMath
CSF_TBB
-CSF_FREETYPE
CSF_OpenGlLibs
CSF_user32
CSF_gdi32
TKG3d
TKService
CSF_RapidJSON
+CSF_Draco