)
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
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}
--- /dev/null
+// 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 <BRep_Builder.hxx>
+#include <BRep_Tool.hxx>
+#include <Graphic3d_ArrayOfTriangles.hxx>
+#include <Prs3d_ShadingAspect.hxx>
+#include <Select3D_SensitiveTriangulation.hxx>
+#include <SelectMgr_EntityOwner.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Face.hxx>
+#include <XCAFDoc_VisMaterial.hxx>
+
+//! 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<Handle(XCAFDoc_VisMaterial), TopoDS_Compound> 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<Handle(XCAFDoc_VisMaterial), TopoDS_Compound>::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);
+ }
+ }
+ }
+}
--- /dev/null
+// 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 <AIS_InteractiveObject.hxx>
+#include <RWMesh_NodeAttributes.hxx>
+#include <TopTools_SequenceOfShape.hxx>
+
+//! 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
: myDevicePixelRatio (1.0f),
myUpdateRequests (0)
{
+ SetLockOrbitZUp (true);
}
// ================================================================
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);
if (aLight->Type() == Graphic3d_TOLS_DIRECTIONAL)
{
aLight->SetCastShadows (true);
+ aLight->SetHeadlight (false);
+ aLight->SetDirection (gp_Dir (0.098f, -0.20f, -0.98f));
}
}
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();
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;
}
else if (dataStartsWithHeader(aBytes, "glTF"))
{
- //return openGltfFromMemory (theName, theBuffer, theDataLen, theToFree);
+ return openGltfFromMemory (theName, theBuffer, theDataLen, theToFree);
}
if (theToFree)
{
return true;
}
+#include <OSD_OpenFile.hxx>
+#include <RWGltf_GltfJsonParser.hxx>
+#include <RWGltf_TriangulationReader.hxx>
+#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<RWGltf_GltfPrimArrayData>::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::kParseStopWhenDoneFlag, rapidjson::UTF8<>, 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<char*>(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<TopoDS_Face>::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 :
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());
}
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.
\r
<h2>OCCT WebGL Viewer Sample</h2>\r
<div>\r
- <canvas id=occViewerCanvas oncontextmenu=event.preventDefault() tabindex=-1 style="border:0 none;background-color:#000" width="409" height="409"></canvas>\r
- <img id=occlogo src="OCC_logo.png" style="position: absolute; left: 20px; top: 0px; z-index: 2;" />\r
+ <canvas id=occViewerCanvas oncontextmenu=event.preventDefault() tabindex=-1 style="border:0 none;background-color:#000" width="409" height="409"></canvas>\r
</div>\r
\r
<div>\r
- <label for="fileInput">Choose BREP file to upload: </label><input type="file" id="fileInput" accept=".brep">\r
+ <label for="fileInput">Choose file to upload: </label><input type="file" id="fileInput" accept=".brep, .gltf, .glb">\r
<input type="button" value="Clear All" onclick="OccViewerModule.removeAllObjects()">\r
<input type="button" value="Fit All" onclick="OccViewerModule.fitAllObjects(true)">\r
</div>\r
var aDevicePixelRatio = window.devicePixelRatio || 1;\r
occViewerCanvas.width = aSizeX * aDevicePixelRatio;\r
occViewerCanvas.height = aSizeY * aDevicePixelRatio;\r
-\r
- occlogo.style.top = (aSizeY - 30) + "px";\r
}\r
window.onresize = updateCanvasSize;\r
updateCanvasSize();\r
var aDataArray = new Uint8Array (aReader.result);\r
const aDataBuffer = OccViewerModule._malloc (aDataArray.length);\r
OccViewerModule.HEAPU8.set (aDataArray, aDataBuffer);\r
- OccViewerModule.openFromMemory (aFile.name, aDataBuffer, aDataArray.length, true);\r
+ //OccViewerModule.openBRepFromMemory (aFile.name, aDataBuffer, aDataArray.length, true);\r
+ OccViewerModule.openGltfFromMemory (aFile.name, aDataBuffer, aDataArray.length, true);\r
//OccViewerModule._free (aDataBuffer); will be freed by called method\r
OccViewerModule.displayGround (true);\r
};\r
\r
const OccViewerModuleInitialized = createOccViewerModule(OccViewerModule);\r
OccViewerModuleInitialized.then(function(Module) {\r
- //OccViewerModule.setCubemapBackground ("cubemap.jpg");\r
- OccViewerModule.openFromUrl ("ball", "samples/Ball.brep");\r
+ //OccViewerModule.setCubemapBackground ("textures/cubemap.jpg");\r
+ //OccViewerModule.setCubemapBackground ("textures/cubemap2.jpg");\r
+ OccViewerModule.setCubemapBackground ("textures/cubemap512.jpg");\r
+ //OccViewerModule.openFromUrl ("ball", "models/Ball.brep");\r
+ OccViewerModule.openFromUrl ("yellow", "models/yellow_up.glb");\r
});\r