From: kgv Date: Wed, 20 Jan 2021 11:30:04 +0000 (+0300) Subject: gltf reader X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=0a9811c9cf7ffebb786663b8f2abab09ef3a474f;p=occt-copy.git gltf reader --- diff --git a/samples/webgl/CMakeLists.txt b/samples/webgl/CMakeLists.txt index bdcb29aa7b..3a32e698da 100644 --- a/samples/webgl/CMakeLists.txt +++ b/samples/webgl/CMakeLists.txt @@ -38,10 +38,12 @@ file(GLOB SOURCES ) source_group ("Headers" FILES WasmOcctView.h - WasmOcctPixMap.h) + WasmOcctPixMap.h + WasmOcctObject.h) source_group ("Sources" FILES WasmOcctView.cpp WasmOcctPixMap.cpp + WasmOcctObject.cpp main.cpp) # FreeType @@ -66,6 +68,9 @@ endif() set(OpenCASCADE_LIBS TKRWMesh TKBinXCAF TKBin TKBinL TKOpenGl TKXCAF TKVCAF TKCAF TKV3d TKHLR TKMesh TKService TKShHealing TKPrim TKTopAlgo TKGeomAlgo TKBRep TKGeomBase TKG3d TKG2d TKMath TKLCAF TKCDF TKernel) +INCLUDE_DIRECTORIES("c:/workssd/Develop/3rdparty/android/rapidjson-1.1.0/include") +add_definitions (-DHAVE_RAPIDJSON) + add_executable(${APP_TARGET} ${SOURCES}) target_link_libraries( ${APP_TARGET} diff --git a/samples/webgl/WasmOcctObject.cpp b/samples/webgl/WasmOcctObject.cpp new file mode 100644 index 0000000000..d6459c7323 --- /dev/null +++ b/samples/webgl/WasmOcctObject.cpp @@ -0,0 +1,243 @@ +// Copyright (c) 2021 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#include "WasmOcctObject.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//! Gets triangulation of every face of shape and fills output array of triangles +static Handle(Graphic3d_ArrayOfTriangles) fillTriangles (const TopoDS_Shape& theShape, + const bool theHasTexels, + const gp_Pnt2d& theUVOrigin, + const gp_Pnt2d& theUVRepeat, + const gp_Pnt2d& theUVScale) +{ + TopLoc_Location aLoc; + Standard_Integer aNbTriangles = 0, aNbVertices = 0; + bool hasNormals = true; + for (TopExp_Explorer aFaceIt (theShape, TopAbs_FACE); aFaceIt.More(); aFaceIt.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (aFaceIt.Current()); + if (const Handle(Poly_Triangulation)& aT = BRep_Tool::Triangulation (aFace, aLoc)) + { + aNbTriangles += aT->NbTriangles(); + aNbVertices += aT->NbNodes(); + hasNormals = hasNormals && aT->HasNormals(); + } + } + if (aNbVertices < 3 || aNbTriangles < 1) + { + return Handle(Graphic3d_ArrayOfTriangles)(); + } + + const Graphic3d_ArrayFlags aFlags = (hasNormals ? Graphic3d_ArrayFlags_VertexNormal : Graphic3d_ArrayFlags_None) + | (theHasTexels ? Graphic3d_ArrayFlags_VertexTexel : Graphic3d_ArrayFlags_None); + Handle(Graphic3d_ArrayOfTriangles) anArray = new Graphic3d_ArrayOfTriangles (aNbVertices, 3 * aNbTriangles, aFlags); + Standard_Real aUmin (0.0), aUmax (1.0), aVmin (0.0), aVmax (1.0), dUmax (1.0), dVmax (1.0); + for (TopExp_Explorer aFaceIt(theShape, TopAbs_FACE); aFaceIt.More(); aFaceIt.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (aFaceIt.Current()); + const Handle(Poly_Triangulation)& aT = BRep_Tool::Triangulation (aFace, aLoc); + if (aT.IsNull()) + { + continue; + } + + // Determinant of transform matrix less then 0 means that mirror transform applied. + const gp_Trsf& aTrsf = aLoc.Transformation(); + const bool isMirrored = aTrsf.VectorialPart().Determinant() < 0; + + // Extracts vertices & normals from nodes + const TColgp_Array1OfPnt& aNodes = aT->Nodes(); + const TColgp_Array1OfPnt2d* aUVNodes = theHasTexels && aT->HasUVNodes() && aT->UVNodes().Upper() == aNodes.Upper() + ? &aT->UVNodes() + : NULL; + + const TShort_Array1OfShortReal* aNormals = aT->HasNormals() ? &aT->Normals() : NULL; + const Standard_ShortReal* aNormArr = aNormals != NULL ? &aNormals->First() : NULL; + + const Standard_Integer aVertFrom = anArray->VertexNumber(); + for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter) + { + gp_Pnt aPoint = aNodes (aNodeIter); + const Standard_Integer anId = 3 * (aNodeIter - aNodes.Lower()); + gp_Dir aNorm = aNormArr != NULL ? gp_Dir (aNormArr[anId + 0], aNormArr[anId + 1], aNormArr[anId + 2]) : gp::DZ(); + if ((aFace.Orientation() == TopAbs_REVERSED) ^ isMirrored) + { + aNorm.Reverse(); + } + if (!aLoc.IsIdentity()) + { + aPoint.Transform (aTrsf); + aNorm .Transform (aTrsf); + } + + if (aUVNodes != NULL) + { + const gp_Pnt2d aTexel = (dUmax == 0.0 || dVmax == 0.0) + ? aUVNodes->Value (aNodeIter) + : gp_Pnt2d ((-theUVOrigin.X() + (theUVRepeat.X() * (aUVNodes->Value (aNodeIter).X() - aUmin)) / dUmax) / theUVScale.X(), + (-theUVOrigin.Y() + (theUVRepeat.Y() * (aUVNodes->Value (aNodeIter).Y() - aVmin)) / dVmax) / theUVScale.Y()); + anArray->AddVertex (aPoint, aNorm, aTexel); + } + else + { + anArray->AddVertex (aPoint, aNorm); + } + } + + // Fill array with vertex and edge visibility info + const Poly_Array1OfTriangle& aTriangles = aT->Triangles(); + Standard_Integer anIndex[3] = {}; + for (Standard_Integer aTriIter = 1; aTriIter <= aT->NbTriangles(); ++aTriIter) + { + aTriangles (aTriIter).Get (anIndex[0], anIndex[1], anIndex[2]); + if (aFace.Orientation() == TopAbs_REVERSED) { std::swap (anIndex[1], anIndex[2]); } + anArray->AddEdges (anIndex[0] + aVertFrom, anIndex[1] + aVertFrom, anIndex[2] + aVertFrom); + } + } + return anArray; +} + +// ================================================================ +// Function : WasmOcctObject +// Purpose : +// ================================================================ +WasmOcctObject::WasmOcctObject() +{ +} + +// ================================================================ +// Function : ~WasmOcctObject +// Purpose : +// ================================================================ +WasmOcctObject::~WasmOcctObject() +{ +} + +// ================================================================ +// Function : Compute +// Purpose : +// ================================================================ +void WasmOcctObject::Compute (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr, + const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) +{ + if (theMode != 0) + { + return; + } + + gp_Pnt2d anUVOrigin, anUVRepeat, anUVScale; + bool hasTexCoords = false; + + NCollection_DataMap aMatMap; + + RWMesh_NodeAttributes aDefAttribs; + for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next()) + { + const TopoDS_Shape& aShape = aRootIter.Value(); + /*if (Handle(Graphic3d_ArrayOfTriangles) aPArray = fillTriangles (aShape, hasTexCoords, anUVOrigin, anUVRepeat, anUVScale)) + { + Handle(Graphic3d_Group) aGroup = thePrs->NewGroup(); + aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect()); + aGroup->AddPrimitiveArray (aPArray); + }*/ + + for (TopExp_Explorer aFaceIter (aShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Value()); + const RWMesh_NodeAttributes* anAttribs = myAttribMap.Seek (aFace); + if (anAttribs == NULL) + { + anAttribs = myAttribMap.Seek (aFace.Located (TopLoc_Location())); + if (anAttribs == NULL) + { + anAttribs = &aDefAttribs; + } + } + if (Handle(XCAFDoc_VisMaterial) aVisMat = anAttribs->Style.Material()) + { + TopoDS_Compound* aComp = aMatMap.ChangeSeek (aVisMat); + if (aComp == NULL) + { + aComp = aMatMap.Bound (aVisMat, TopoDS_Compound()); + BRep_Builder().MakeCompound (*aComp); + } + BRep_Builder().Add (*aComp, aFace); + } + } + } + + for (NCollection_DataMap::Iterator aMatIter (aMatMap); aMatIter.More(); aMatIter.Next()) + { + const Handle(XCAFDoc_VisMaterial)& aVisMat = aMatIter.Key(); + const TopoDS_Compound& aShape = aMatIter.Value(); + if (Handle(Graphic3d_ArrayOfTriangles) aPArray = fillTriangles (aShape, hasTexCoords, anUVOrigin, anUVRepeat, anUVScale)) + { + Handle(Graphic3d_AspectFillArea3d) anAspects = new Graphic3d_AspectFillArea3d(); + *anAspects = *myDrawer->ShadingAspect()->Aspect(); + aVisMat->FillAspect (anAspects); + + Handle(Graphic3d_Group) aGroup = thePrs->NewGroup(); + aGroup->SetGroupPrimitivesAspect (anAspects); + aGroup->AddPrimitiveArray (aPArray); + } + } +} + +// ================================================================ +// Function : ComputeSelection +// Purpose : +// ================================================================ +void WasmOcctObject::ComputeSelection (const Handle(SelectMgr_Selection)& theSel, + const Standard_Integer theMode) +{ + if (theMode != 0) + { + return; + } + + Handle(SelectMgr_EntityOwner) anOwner = new SelectMgr_EntityOwner (this, 5); + for (TopTools_SequenceOfShape::Iterator aRootIter (myRootShapes); aRootIter.More(); aRootIter.Next()) + { + const TopoDS_Shape& aShape = aRootIter.Value(); + for (TopExp_Explorer aFaceIter (aShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Value()); + TopLoc_Location aLoc; + if (Handle(Poly_Triangulation) aPolyTri = BRep_Tool::Triangulation (aFace, aLoc)) + { + Handle(Select3D_SensitiveTriangulation) aSensTris = new Select3D_SensitiveTriangulation (anOwner, aPolyTri, aLoc); + theSel->Add (aSensTris); + } + } + } +} diff --git a/samples/webgl/WasmOcctObject.h b/samples/webgl/WasmOcctObject.h new file mode 100644 index 0000000000..a6b8ba6dc1 --- /dev/null +++ b/samples/webgl/WasmOcctObject.h @@ -0,0 +1,73 @@ +// Copyright (c) 2021 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef _WasmOcctObject_HeaderFile +#define _WasmOcctObject_HeaderFile + +#include +#include +#include + +//! Sample presentation. +class WasmOcctObject : public AIS_InteractiveObject +{ +public: + //! Default constructor. + Standard_EXPORT WasmOcctObject(); + + //! Destructor. + Standard_EXPORT virtual ~WasmOcctObject(); + + //! Return sequence of root shapes. + TopTools_SequenceOfShape& ChangeShapes() { return myRootShapes; } + + //! Return shape attributes. + RWMesh_NodeAttributeMap& ChangeAttributes() { return myAttribMap; } + +protected: + + //! Return TRUE for supported display mode. + virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0; } + + //! Compute 3D part of View Cube. + //! @param thePrsMgr [in] presentation manager. + //! @param thePrs [in] input presentation that is to be filled with flat presentation primitives. + //! @param theMode [in] display mode. + //! @warning this object accept only 0 display mode. + Standard_EXPORT virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr, + const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) Standard_OVERRIDE; + + //! Redefine computing of sensitive entities for View Cube. + //! @param theSelection [in] input selection object that is to be filled with sensitive entities. + //! @param theMode [in] selection mode. + //! @warning object accepts only 0 selection mode. + Standard_EXPORT virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, + const Standard_Integer theMode) Standard_OVERRIDE; + +private: + + TopTools_SequenceOfShape myRootShapes; //!< sequence of result root shapes + RWMesh_NodeAttributeMap myAttribMap; //!< shape attributes + +}; + +#endif // _WasmOcctObject_HeaderFile diff --git a/samples/webgl/WasmOcctView.cpp b/samples/webgl/WasmOcctView.cpp index ec33303300..92a484ce42 100644 --- a/samples/webgl/WasmOcctView.cpp +++ b/samples/webgl/WasmOcctView.cpp @@ -137,6 +137,7 @@ WasmOcctView::WasmOcctView() : myDevicePixelRatio (1.0f), myUpdateRequests (0) { + SetLockOrbitZUp (true); } // ================================================================ @@ -294,10 +295,14 @@ bool WasmOcctView::initViewer() Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: font '") + aFontPath + "' is not found", Message_Fail); }*/ + const bool toAntialias = myDevicePixelRatio <= 1.25f; + Handle(Aspect_DisplayConnection) aDisp; Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (aDisp, false); aDriver->ChangeOptions().buffersNoSwap = true; // swap has no effect in WebGL aDriver->ChangeOptions().buffersOpaqueAlpha = true; // avoid unexpected blending of canvas with page background + ///aDriver->ChangeOptions().useSystemBuffer = false; /// + aDriver->ChangeOptions().useSystemBuffer = true; /// if (!aDriver->InitContext()) { Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: EGL initialization failed"), Message_Fail); @@ -315,6 +320,8 @@ bool WasmOcctView::initViewer() if (aLight->Type() == Graphic3d_TOLS_DIRECTIONAL) { aLight->SetCastShadows (true); + aLight->SetHeadlight (false); + aLight->SetDirection (gp_Dir (0.098f, -0.20f, -0.98f)); } } @@ -340,7 +347,8 @@ bool WasmOcctView::initViewer() myView = new V3d_View (aViewer); myView->Camera()->SetProjectionType (Graphic3d_Camera::Projection_Perspective); myView->SetImmediateUpdate (false); - myView->ChangeRenderingParams().IsShadowEnabled = false; + //myView->ChangeRenderingParams().NbMsaaSamples = toAntialias ? 4 : 0; + myView->ChangeRenderingParams().RenderResolutionScale = toAntialias ? 2.0f : 1.0f; myView->ChangeRenderingParams().Resolution = (unsigned int )(96.0 * myDevicePixelRatio + 0.5); myView->ChangeRenderingParams().ToShowStats = true; myView->ChangeRenderingParams().StatsTextAspect = myTextStyle->Aspect(); @@ -348,6 +356,10 @@ bool WasmOcctView::initViewer() myView->SetWindow (aWindow); dumpGlInfo (false); + ///myView->SetShadingModel (aDriver->InquireLimit (Graphic3d_TypeOfLimit_HasPBR) == 1 ? Graphic3d_TOSM_PBR : Graphic3d_TOSM_FRAGMENT); + ///myView->ChangeRenderingParams().IsShadowEnabled = aDriver->InquireLimit (Graphic3d_TypeOfLimit_HasPBR) == 1; /// TODO + myView->ChangeRenderingParams().IsShadowEnabled = true; /// + myContext = new AIS_InteractiveContext (aViewer); initPixelScaleRatio(); return true; @@ -915,7 +927,7 @@ bool WasmOcctView::openFromMemory (const std::string& theName, } else if (dataStartsWithHeader(aBytes, "glTF")) { - //return openGltfFromMemory (theName, theBuffer, theDataLen, theToFree); + return openGltfFromMemory (theName, theBuffer, theDataLen, theToFree); } if (theToFree) { @@ -971,6 +983,265 @@ bool WasmOcctView::openBRepFromMemory (const std::string& theName, return true; } +#include +#include +#include +#include "WasmOcctObject.h" + +class WasmTriangulationReader : public RWGltf_TriangulationReader +{ +public: + + WasmTriangulationReader (std::istream& theStream, + const TCollection_AsciiString& theFile) + : myRootStream (&theStream), myRootPath (theFile) + { + // + } + + virtual bool load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh) override + { + reset(); + if (theMesh.IsNull() + || theMesh->PrimitiveMode() == RWGltf_GltfPrimitiveMode_UNKNOWN) + { + return false; + } + + for (NCollection_Sequence::Iterator aDataIter (theMesh->Data()); aDataIter.More(); aDataIter.Next()) + { + const RWGltf_GltfPrimArrayData& aData = aDataIter.Value(); + if (!aData.StreamData.IsNull()) + { + Standard_ArrayStreamBuffer aStreamBuffer ((const char* )aData.StreamData->Data(), aData.StreamData->Size()); + std::istream aStream (&aStreamBuffer); + aStream.seekg ((std::streamoff )aData.StreamOffset, std::ios_base::beg); + if (!readBuffer (aStream, theMesh->Id(), aData.Accessor, aData.Type, theMesh->PrimitiveMode())) + { + return false; + } + continue; + } + else if (aData.StreamUri.IsEmpty()) + { + reportError (TCollection_AsciiString ("Buffer '") + theMesh->Id() + "' does not define uri."); + return false; + } + + std::istream* aStream = &mySharedStream.Stream; + if (aData.StreamUri == myRootPath + && myRootStream != NULL) + { + aStream = myRootStream; + } + else if (mySharedStream.Path != aData.StreamUri) + { + mySharedStream.Stream.close(); + mySharedStream.Path = aData.StreamUri; + } + if (aStream == &mySharedStream.Stream + && !mySharedStream.Stream.is_open()) + { + OSD_OpenStream (mySharedStream.Stream, aData.StreamUri.ToCString(), std::ios::in | std::ios::binary); + if (!mySharedStream.Stream.is_open()) + { + mySharedStream.Stream.close(); + reportError (TCollection_AsciiString ("Buffer '") + theMesh->Id() + "refers to non-existing file '" + aData.StreamUri + "'."); + return false; + } + } + + aStream->seekg ((std::streamoff )aData.StreamOffset, std::ios_base::beg); + if (!aStream->good()) + { + mySharedStream.Stream.close(); + reportError (TCollection_AsciiString ("Buffer '") + theMesh->Id() + "refers to invalid location."); + return false; + } + + if (!readBuffer (*aStream, theMesh->Id(), aData.Accessor, aData.Type, theMesh->PrimitiveMode())) + { + return false; + } + } + return true; + } + +private: + + std::istream* myRootStream; + TCollection_AsciiString myRootPath; + +}; + +//! Parse glTF data. +static bool parseGltfFromMemory (RWGltf_GltfJsonParser& theParser, + std::istream& theStream, + const TCollection_AsciiString& theFile) +{ + bool isBinaryFile = false; + char aGlbHeader[12] = {}; + theStream.read (aGlbHeader, sizeof(aGlbHeader)); + int64_t aBinBodyOffset = 0, aBinBodyLen = 0, aJsonBodyOffset = 0, aJsonBodyLen = 0; + if (::strncmp (aGlbHeader, "glTF", 4) == 0) + { + isBinaryFile = true; + const uint32_t* aVer = (const uint32_t* )(aGlbHeader + 4); + const uint32_t* aLen = (const uint32_t* )(aGlbHeader + 8); + if (*aVer != 2) + { + Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' is written using unknown version " + int(*aVer)); + return false; + } + + for (int aChunkIter = 0; !theStream.eof() && aChunkIter < 2; ++aChunkIter) + { + char aChunkHeader2[8] = {}; + if (int64_t(theStream.tellg()) + int64_t(sizeof(aChunkHeader2)) > int64_t(*aLen)) + { + break; + } + + theStream.read (aChunkHeader2, sizeof(aChunkHeader2)); + if (!theStream.good()) + { + Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' is written using unsupported format"); + return false; + } + + const uint32_t* aChunkLen = (const uint32_t* )(aChunkHeader2 + 0); + const uint32_t* aChunkType = (const uint32_t* )(aChunkHeader2 + 4); + if (*aChunkType == 0x4E4F534A) + { + aJsonBodyOffset = int64_t(theStream.tellg()); + aJsonBodyLen = int64_t(*aChunkLen); + } + else if (*aChunkType == 0x004E4942) + { + aBinBodyOffset = int64_t(theStream.tellg()); + aBinBodyLen = int64_t(*aChunkLen); + } + if (*aChunkLen != 0) + { + theStream.seekg (*aChunkLen, std::ios_base::cur); + } + } + + theStream.seekg ((std::streamoff )aJsonBodyOffset, std::ios_base::beg); + } + else + { + theStream.seekg (0, std::ios_base::beg); + } + if (isBinaryFile) + { + theParser.SetBinaryFormat (aBinBodyOffset, aBinBodyLen); + } + + rapidjson::ParseResult aRes; + rapidjson::IStreamWrapper aFileStream (theStream); + if (isBinaryFile) + { + aRes = theParser.ParseStream, rapidjson::IStreamWrapper> (aFileStream); + } + else + { + aRes = theParser.ParseStream (aFileStream); + } + if (aRes.IsError()) + { + if (aRes.Code() == rapidjson::kParseErrorDocumentEmpty) + { + Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' is empty"); + return false; + } + TCollection_AsciiString anErrDesc (RWGltf_GltfJsonParser::FormatParseError (aRes.Code())); + Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' defines invalid JSON document!\n" + + anErrDesc + " [at offset " + (int )aRes.Offset() + "]."); + return false; + } + + if (!theParser.Parse (Message_ProgressRange())) + { + return false; + } + + return true; +} + +// ================================================================ +// Function : openGltfFromMemory +// Purpose : +// ================================================================ +bool WasmOcctView::openGltfFromMemory (const std::string& theName, + uintptr_t theBuffer, int theDataLen, + bool theToFree) +{ + removeObject (theName); + + WasmOcctView& aViewer = Instance(); + + char* aRawData = reinterpret_cast(theBuffer); + Standard_ArrayStreamBuffer aStreamBuffer (aRawData, theDataLen); + std::istream aStream (&aStreamBuffer); + + Handle(WasmOcctObject) aShapePrs = new WasmOcctObject(); + + RWMesh_CoordinateSystemConverter aTrsf; + aTrsf.SetInputLengthUnit (1.0); // meters + aTrsf.SetInputCoordinateSystem (RWMesh_CoordinateSystem_glTF); + aTrsf.SetOutputLengthUnit (1.0); // meters + aTrsf.SetOutputCoordinateSystem(RWMesh_CoordinateSystem_Zup); + + RWGltf_GltfJsonParser aParser (aShapePrs->ChangeShapes()); + aParser.SetFilePath (theName.c_str()); + aParser.SetErrorPrefix (TCollection_AsciiString ("File '") + theName.c_str() + "' defines invalid glTF!\n"); + aParser.SetAttributeMap (aShapePrs->ChangeAttributes()); + aParser.SetCoordinateSystemConverter (aTrsf); + //aParser.SetSkipEmptyNodes (myToSkipEmptyNodes); + //aParser.SetMeshNameAsFallback (myUseMeshNameAsFallback); + bool isParsed = parseGltfFromMemory (aParser, aStream, theName.c_str()); + if (isParsed) + { + Handle(RWGltf_PrimitiveArrayReader) aReader = new WasmTriangulationReader (aStream, theName.c_str()); + aReader->SetCoordinateSystemConverter (aTrsf); + for (NCollection_Vector::Iterator aFaceIter (aParser.FaceList()); aFaceIter.More(); aFaceIter.Next()) + { + TopoDS_Face& aFace = aFaceIter.ChangeValue(); + TopLoc_Location aDummyLoc; + Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (aFace, aDummyLoc)); + Handle(Poly_Triangulation) aPolyData = aReader->Load (aLateData); + BRep_Builder aBuilder; + aBuilder.UpdateFace (aFace, aPolyData); + } + } + if (theToFree) + { + free (aRawData); + } + + if (!isParsed) + { + return false; + } + + if (!theName.empty()) + { + aViewer.myObjects.Add (theName.c_str(), aShapePrs); + } + + aViewer.Context()->Display (aShapePrs, 0, 0, false); + aViewer.View()->FitAll (0.01, false); + aViewer.View()->Invalidate(); + aViewer.updateView(); + +displayGround (true); /// + + Message::DefaultMessenger()->Send (TCollection_AsciiString("Loaded file ") + theName.c_str(), Message_Info); + Message::DefaultMessenger()->Send (OSD_MemInfo::PrintInfo(), Message_Trace); + return true; +} + // ================================================================ // Function : displayGround // Purpose : @@ -1043,4 +1314,5 @@ EMSCRIPTEN_BINDINGS(OccViewerModule) { emscripten::function("openFromUrl", &WasmOcctView::openFromUrl); emscripten::function("openFromMemory", &WasmOcctView::openFromMemory, emscripten::allow_raw_pointers()); emscripten::function("openBRepFromMemory", &WasmOcctView::openBRepFromMemory, emscripten::allow_raw_pointers()); + emscripten::function("openGltfFromMemory", &WasmOcctView::openGltfFromMemory, emscripten::allow_raw_pointers()); } diff --git a/samples/webgl/WasmOcctView.h b/samples/webgl/WasmOcctView.h index c05ce179a3..8a0c42775f 100644 --- a/samples/webgl/WasmOcctView.h +++ b/samples/webgl/WasmOcctView.h @@ -99,6 +99,16 @@ public: //! @name methods exported by Module uintptr_t theBuffer, int theDataLen, bool theToFree); + //! Open glTF object from memory. + //! @param theName [in] object name + //! @param theBuffer [in] pointer to data + //! @param theDataLen [in] data length + //! @param theToFree [in] free theBuffer if set to TRUE + //! @return FALSE on reading error + static bool openGltfFromMemory (const std::string& theName, + uintptr_t theBuffer, int theDataLen, + bool theToFree); + public: //! Default constructor. diff --git a/samples/webgl/occt-webgl-sample.html b/samples/webgl/occt-webgl-sample.html index c04add8b47..3e1c633613 100644 --- a/samples/webgl/occt-webgl-sample.html +++ b/samples/webgl/occt-webgl-sample.html @@ -9,12 +9,11 @@

OCCT WebGL Viewer Sample

- - +
- +
@@ -36,8 +35,6 @@ function updateCanvasSize() var aDevicePixelRatio = window.devicePixelRatio || 1; occViewerCanvas.width = aSizeX * aDevicePixelRatio; occViewerCanvas.height = aSizeY * aDevicePixelRatio; - - occlogo.style.top = (aSizeY - 30) + "px"; } window.onresize = updateCanvasSize; updateCanvasSize(); @@ -75,7 +72,8 @@ fileInput.onchange = function() var aDataArray = new Uint8Array (aReader.result); const aDataBuffer = OccViewerModule._malloc (aDataArray.length); OccViewerModule.HEAPU8.set (aDataArray, aDataBuffer); - OccViewerModule.openFromMemory (aFile.name, aDataBuffer, aDataArray.length, true); + //OccViewerModule.openBRepFromMemory (aFile.name, aDataBuffer, aDataArray.length, true); + OccViewerModule.openGltfFromMemory (aFile.name, aDataBuffer, aDataArray.length, true); //OccViewerModule._free (aDataBuffer); will be freed by called method OccViewerModule.displayGround (true); }; diff --git a/samples/webgl/occt-webgl-viewer.js b/samples/webgl/occt-webgl-viewer.js index 484b519231..0c3f01c546 100644 --- a/samples/webgl/occt-webgl-viewer.js +++ b/samples/webgl/occt-webgl-viewer.js @@ -23,6 +23,9 @@ var OccViewerModule = const OccViewerModuleInitialized = createOccViewerModule(OccViewerModule); OccViewerModuleInitialized.then(function(Module) { - //OccViewerModule.setCubemapBackground ("cubemap.jpg"); - OccViewerModule.openFromUrl ("ball", "samples/Ball.brep"); + //OccViewerModule.setCubemapBackground ("textures/cubemap.jpg"); + //OccViewerModule.setCubemapBackground ("textures/cubemap2.jpg"); + OccViewerModule.setCubemapBackground ("textures/cubemap512.jpg"); + //OccViewerModule.openFromUrl ("ball", "models/Ball.brep"); + OccViewerModule.openFromUrl ("yellow", "models/yellow_up.glb"); });