1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-14 13:30:48 +03:00

Compare commits

..

10 Commits

Author SHA1 Message Date
emv
fcfc4713a6 0030794: BRepOffsetAPI_MakePipeShell: shape is produced with artifacts
BRepFill_TrimShellCorner::MakeFacesSec() - When replacing a bound edge with a section wire make sure that edges in a wire are oriented correctly.
Test cases for the issue.
2019-06-24 12:16:12 +03:00
kgv
4151c94d20 0029296: Data Exchange - implement import of mesh data from files in OBJ format
RWObj_Reader and RWObj_CafReader - added new classes reading triangulation from OBJ file.
2019-06-21 18:19:09 +03:00
kgv
0a419c51ed 0030691: Data Exchange - implement import of mesh data from files in glTF format
Added RWGltf_CafReader class implementing glTF reader.
Added readgltf Draw Harness command for reading glTF files.
2019-06-21 18:19:08 +03:00
oan
eec6e810f1 0027685: Visualization of a shape imported from IGES hangs
Adding test case
2019-06-20 15:20:52 +03:00
emv
c2a25d522b 0030785: Mesh - protect BRepMesh_IncrementalMesh::Perform from raising exception
IMeshTools_ModelAlgo and IMeshTools_ModelBuilder have been changed to provide exception protected interfaces for performing the operations.
Protect single Edge/Face discretization methods from raising exceptions to skip broken Edges/Faces and allow mesh construction on the whole model.
2019-06-20 15:20:51 +03:00
kgv
fe525c6f7c 0030777: Visualization - Incorrect selection/highlighting of clipped objects
SelectMgr_ViewerSelector::traverseObject() now handles Object clipping planes in the same way as View clipping planes.
2019-06-20 15:20:51 +03:00
ika
3b739e69c9 0030789: Data Exchange - Some names are lost during STEP import
Add importing name from PRODUCT_DEFINITION_WITH_ASSOCIATED_DOCUMENTS STEP entity.
Update test cases with files contained this entity.
2019-06-20 15:20:50 +03:00
kgv
c9983ee863 0030706: Visualization - fetch font folder list from fontconfig library on Linux
vfont command now prints fonts in alphabetical order.
2019-06-20 15:20:49 +03:00
kgv
912761ea17 0030782: Visualization, Font_FTFont - use predefined fallback fonts for extended Unicode subsets
Font_FTFont now uses fallback fonts for characters from unsupported Unicode subsets,
managed by Font_FTFont::ToUseUnicodeSubsetFallback()
and Font_FontMgr::ToUseUnicodeSubsetFallback() option, enabled by default.
The fallback list includes common font families for Chinese, Korean and Japanese languages.

Font_FTFont::RenderGlyph() now supports FT_PIXEL_MODE_MONO input format used by some CJK fonts.
OpenGl_Font::createTexture() now limits single texture size to circa 4096 glyphs.

test/testgrid now expects test scripts being in UTF-8 encoding in sync with "DRAWEXE -f script.tcl".

AIS::InitFaceLength() - fixed usage of uninitialized result.
2019-06-19 19:42:24 +03:00
emv
1bb67d3844 0030595: Oriented Bounding Box seems not optimal for some shapes
Add possibility of construction of the Optimal Oriented Bounding Box from set of points (the case of shape with triangulation).

The interface of the BRepBndLib::AddOBB method is not changed, but the option <theIsOptimal> now controls also the construction of the OBB from Set of points.
The slightly modified DiTo algorithm will be used, checking all possible axes created by the extreme points.
The performance of the construction of the Optimal OBB is lower but the quality is usually much higher (can't be worse by definition).

Test cases for the issue.
2019-06-17 09:26:54 +03:00
178 changed files with 9204 additions and 1811 deletions

View File

@@ -633,6 +633,26 @@ else()
OCCT_CHECK_AND_UNSET ("INSTALL_TBB")
endif()
# RapidJSON
# search for CSF_RapidJSON variable in EXTERNLIB of each being used toolkit
OCCT_IS_PRODUCT_REQUIRED (CSF_RapidJSON CAN_USE_RAPIDJSON)
if (CAN_USE_RAPIDJSON)
set (USE_RAPIDJSON OFF CACHE BOOL "${USE_RAPIDJSON_DESCR}")
if (USE_RAPIDJSON)
add_definitions (-DHAVE_RAPIDJSON)
OCCT_INCLUDE_CMAKE_FILE ("adm/cmake/rapidjson")
else()
OCCT_CHECK_AND_UNSET_GROUP ("3RDPARTY_RAPIDJSON")
OCCT_CHECK_AND_UNSET ("INSTALL_RAPIDJSON")
endif()
else()
OCCT_CHECK_AND_UNSET ("USE_RAPIDJSON")
OCCT_CHECK_AND_UNSET_GROUP ("3RDPARTY_RAPIDJSON")
OCCT_CHECK_AND_UNSET ("INSTALL_RAPIDJSON")
endif()
# EIGEN
if (CAN_USE_EIGEN)
set (USE_EIGEN OFF CACHE BOOL "${USE_EIGEN_DESCR}")

View File

@@ -440,4 +440,6 @@ t TKVCAF
n XCAFView
n XCAFNoteObjects
t TKRWMesh
n RWGltf
n RWMesh
n RWObj

View File

@@ -73,7 +73,7 @@ if (WIN32)
set (CSF_OpenGlLibs "opengl32.lib")
endif()
else()
else()
if (APPLE)
set (CSF_objc "objc")
@@ -117,5 +117,6 @@ if (WIN32)
endif()
set (CSF_XwLibs "X11 Xext Xmu Xi")
set (CSF_dl "dl")
set (CSF_fontconfig "fontconfig")
endif()
endif()

86
adm/cmake/rapidjson.cmake Normal file
View File

@@ -0,0 +1,86 @@
# RapidJSON
if (NOT DEFINED INSTALL_RAPIDJSON)
set (INSTALL_RAPIDJSON OFF CACHE BOOL "${INSTALL_RAPIDJSON_DESCR}")
endif()
# RapidJSON directory
if (NOT DEFINED 3RDPARTY_RAPIDJSON_DIR)
set (3RDPARTY_RAPIDJSON_DIR "" CACHE PATH "The directory containing RapidJSON")
endif()
# search for RapidJSON in user defined directory
if (3RDPARTY_DIR AND EXISTS "${3RDPARTY_DIR}")
if (NOT 3RDPARTY_RAPIDJSON_DIR OR NOT EXISTS "${3RDPARTY_RAPIDJSON_DIR}")
FIND_PRODUCT_DIR("${3RDPARTY_DIR}" RapidJSON RAPIDJSON_DIR_NAME)
if (RAPIDJSON_DIR_NAME)
set (3RDPARTY_RAPIDJSON_DIR "${3RDPARTY_DIR}/${RAPIDJSON_DIR_NAME}" CACHE PATH "The directory containing RapidJSON" FORCE)
endif()
endif()
endif()
if (NOT DEFINED 3RDPARTY_RAPIDJSON_INCLUDE_DIR)
set (3RDPARTY_RAPIDJSON_INCLUDE_DIR "" CACHE FILEPATH "The directory containing headers of the RAPIDJSON")
endif()
if (NOT 3RDPARTY_RAPIDJSON_INCLUDE_DIR OR NOT EXISTS "${3RDPARTY_RAPIDJSON_INCLUDE_DIR}")
set (HEADER_NAMES rapidjson/rapidjson.h)
set (3RDPARTY_RAPIDJSON_INCLUDE_DIR "3RDPARTY_RAPIDJSON_INCLUDE_DIR-NOTFOUND" CACHE PATH "the path to RapidJSON header file" FORCE)
if (3RDPARTY_RAPIDJSON_DIR AND EXISTS "${3RDPARTY_RAPIDJSON_DIR}")
find_path (3RDPARTY_RAPIDJSON_INCLUDE_DIR NAMES ${HEADER_NAMES}
PATHS ${3RDPARTY_RAPIDJSON_DIR}
PATH_SUFFIXES include rapidjson
CMAKE_FIND_ROOT_PATH_BOTH
NO_DEFAULT_PATH)
else()
find_path (3RDPARTY_RAPIDJSON_INCLUDE_DIR NAMES ${HEADER_NAMES}
PATH_SUFFIXES include rapidjson
CMAKE_FIND_ROOT_PATH_BOTH)
endif()
# use default (CMake) RapidJSON search
if (NOT 3RDPARTY_RAPIDJSON_INCLUDE_DIR OR NOT EXISTS "${3RDPARTY_RAPIDJSON_INCLUDE_DIR}")
if (3RDPARTY_RAPIDJSON_DIR AND EXISTS "${3RDPARTY_RAPIDJSON_DIR}")
set (CACHED_RAPIDJSON_DIR $ENV{RapidJSON_DIR})
set (ENV{RapidJSON_DIR} "${3RDPARTY_RAPIDJSON_DIR}")
endif()
find_package(RapidJSON QUIET)
# restore ENV{RapidJSON_DIR}
if (3RDPARTY_RAPIDJSON_DIR AND EXISTS "${3RDPARTY_RAPIDJSON_DIR}")
set (ENV{RapidJSON_DIR} ${CACHED_RAPIDJSON_DIR})
endif()
if (${RAPIDJSON_FOUND})
set (3RDPARTY_RAPIDJSON_INCLUDE_DIR "${RAPIDJSON_INCLUDE_DIR}" CACHE PATH "the path to RapidJSON header file" FORCE)
set (3RDPARTY_RAPIDJSON_DIR "${RAPIDJSON_ROOT_DIR}" CACHE PATH "The directory containing RapidJSON" FORCE)
endif()
endif()
endif()
if (3RDPARTY_RAPIDJSON_INCLUDE_DIR AND EXISTS "${3RDPARTY_RAPIDJSON_INCLUDE_DIR}")
list (APPEND 3RDPARTY_INCLUDE_DIRS "${3RDPARTY_RAPIDJSON_INCLUDE_DIR}")
# Install header files
if (INSTALL_RAPIDJSON)
file(GLOB RAPIDJSON_SUBDIRS "${3RDPARTY_RAPIDJSON_INCLUDE_DIR}/*")
foreach(SUBDIR ${RAPIDJSON_SUBDIRS})
if(IS_DIRECTORY "${SUBDIR}")
install (DIRECTORY "${SUBDIR}" DESTINATION "${INSTALL_DIR_INCLUDE}")
else()
install (FILES "${SUBDIR}" DESTINATION "${INSTALL_DIR_INCLUDE}")
endif()
endforeach()
endif()
else()
list (APPEND 3RDPARTY_NOT_INCLUDED 3RDPARTY_RAPIDJSON_INCLUDE_DIR)
set (3RDPARTY_RAPIDJSON_INCLUDE_DIR "" CACHE PATH "the path to RapidJSON header file" FORCE)
endif()
# unset all redundant variables
OCCT_CHECK_AND_UNSET(RapidJSON_DIR)

View File

@@ -94,6 +94,7 @@ INSTALL_MESSAGE (INSTALL_EGL "EGL binaries")
INSTALL_MESSAGE (INSTALL_GLES2 "OpenGL ES 2.0 binaries")
INSTALL_MESSAGE (INSTALL_FREETYPE "FreeType binaries")
INSTALL_MESSAGE (INSTALL_TBB "TBB binaries")
INSTALL_MESSAGE (INSTALL_RAPIDJSON "RapidJSON header files")
INSTALL_MESSAGE (INSTALL_TCL "TCL binaries")
INSTALL_MESSAGE (INSTALL_TK "TK binaries")
INSTALL_MESSAGE (INSTALL_VTK "VTK binaries ")
@@ -161,6 +162,10 @@ set (USE_FREEIMAGE_DESCR
"Indicates whether Freeimage product should be used in OCCT visualization
module for support of popular graphics image formats (PNG, BMP etc)")
set (USE_RAPIDJSON_DESCR
"Indicates whether RapidJSON product should be used in OCCT DataExchange
module for support of JSON-based formats like glTF")
set (USE_EGL_DESCR
"Indicates whether EGL should be used in OCCT visualization
module instead of conventional OpenGL context creation APIs")

View File

@@ -189,6 +189,9 @@ proc wokdep:gui:UpdateList {} {
}
wokdep:SearchStandardLibrary anIncErrs anLib32Errs anLib64Errs anBin32Errs anBin64Errs "liblzma" "lzma.h" "$aCheckLib" {"lzma" "xz"}
}
if { "$::HAVE_RAPIDJSON" == "true" } {
wokdep:SearchRapidJson anIncErrs anLib32Errs anLib64Errs anBin32Errs anBin64Errs
}
if { "$::CHECK_QT4" == "true" } {
wokdep:SearchQt4 anIncErrs anLib32Errs anLib64Errs anBin32Errs anBin64Errs
@@ -456,6 +459,9 @@ ttk::label .myFrame.myChecks.myZLibLbl -text "Use zlib"
checkbutton .myFrame.myChecks.myLzmaCheck -offvalue "false" -onvalue "true" -variable HAVE_LIBLZMA -command wokdep:gui:UpdateList
ttk::label .myFrame.myChecks.myLzmaLbl -text "Use liblzma"
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.myQt4Check -offvalue "false" -onvalue "true" -variable CHECK_QT4 -command wokdep:gui:UpdateList
ttk::label .myFrame.myChecks.myQt4Lbl -text "Search Qt4"
checkbutton .myFrame.myChecks.myJDKCheck -offvalue "false" -onvalue "true" -variable CHECK_JDK -command wokdep:gui:UpdateList
@@ -564,8 +570,8 @@ if { "$::tcl_platform(os)" != "Darwin" } {
grid .myFrame.myChecks.myZLibCheck -row $aCheckRowIter -column 6 -sticky e
grid .myFrame.myChecks.myZLibLbl -row $aCheckRowIter -column 7 -sticky w
grid .myFrame.myChecks.myQt4Check -row $aCheckRowIter -column 10 -sticky e
grid .myFrame.myChecks.myQt4Lbl -row $aCheckRowIter -column 11 -sticky w
grid .myFrame.myChecks.myQt4Check -row $aCheckRowIter -column 12 -sticky e
grid .myFrame.myChecks.myQt4Lbl -row $aCheckRowIter -column 13 -sticky w
incr aCheckRowIter
grid .myFrame.myChecks.myFFmpegCheck -row $aCheckRowIter -column 0 -sticky e
@@ -578,8 +584,8 @@ if { "$::tcl_platform(platform)" == "windows" } {
}
grid .myFrame.myChecks.myLzmaCheck -row $aCheckRowIter -column 6 -sticky e
grid .myFrame.myChecks.myLzmaLbl -row $aCheckRowIter -column 7 -sticky w
grid .myFrame.myChecks.myJDKCheck -row $aCheckRowIter -column 10 -sticky e
grid .myFrame.myChecks.myJDKLbl -row $aCheckRowIter -column 11 -sticky w
grid .myFrame.myChecks.myJDKCheck -row $aCheckRowIter -column 12 -sticky e
grid .myFrame.myChecks.myJDKLbl -row $aCheckRowIter -column 13 -sticky w
incr aCheckRowIter
if { "$::tcl_platform(os)" == "Darwin" } {
@@ -588,6 +594,10 @@ if { "$::tcl_platform(os)" == "Darwin" } {
incr aCheckRowIter
}
grid .myFrame.myChecks.myRapidJsonCheck -row $aCheckRowIter -column 6 -sticky e
grid .myFrame.myChecks.myRapidJsonLbl -row $aCheckRowIter -column 7 -sticky w
incr aCheckRowIter
# Additional headers search paths
grid .myFrame.myIncLbl -row $aRowIter -column 0 -columnspan 10 -sticky w
incr aRowIter

View File

@@ -68,7 +68,7 @@ if { [info exists ::env(SHORTCUT_HEADERS)] } {
}
# 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_FREEIMAGE HAVE_FFMPEG HAVE_TBB HAVE_GLES2 HAVE_D3D HAVE_VTK HAVE_ZLIB HAVE_LIBLZMA HAVE_OPENCL CHECK_QT4 CHECK_JDK MACOSX_USE_GLX HAVE_RelWithDebInfo}
set THE_ENV_VARIABLES {HAVE_FREEIMAGE HAVE_FFMPEG HAVE_TBB HAVE_GLES2 HAVE_D3D HAVE_VTK HAVE_ZLIB HAVE_LIBLZMA HAVE_RAPIDJSON HAVE_OPENCL CHECK_QT4 CHECK_JDK MACOSX_USE_GLX HAVE_RelWithDebInfo}
foreach anEnvIter $THE_ENV_VARIABLES {
set ${anEnvIter} "false"
if { [info exists ::env(${anEnvIter})] } {
@@ -858,6 +858,25 @@ proc wokdep:SearchGLES {theErrInc theErrLib32 theErrLib64 theErrBin32 theErrBin6
return "$isFound"
}
# Search RapidJSON headers
proc wokdep:SearchRapidJson {theErrInc theErrLib32 theErrLib64 theErrBin32 theErrBin64} {
upvar $theErrInc anErrInc
set isFound "true"
set aRJHPath [wokdep:SearchHeader "rapidjson/rapidjson.h"]
if { "$aRJHPath" == "" } {
set aPath [wokdep:Preferred [glob -nocomplain -directory "$::PRODUCTS_PATH" -type d *{rapidjson}*] "$::VCVER" "$::ARCH" ]
if { "$aPath" != "" && [file exists "$aPath/include/rapidjson/rapidjson.h"] } {
lappend ::CSF_OPT_INC "$aPath/include"
} else {
lappend anErrInc "Error: 'rapidjson/rapidjson.h' not found (RapidJSON)"
set isFound "false"
}
}
return "$isFound"
}
# Auxiliary function, gets VTK version to set default search directory
proc wokdep:VtkVersion { thePath } {
set aResult "6.1"

View File

@@ -1393,6 +1393,7 @@ proc osutils:csfList { theOS theCsfLibsMap theCsfFrmsMap } {
set aLibsMap(CSF_TclTkLibs) ""
set aLibsMap(CSF_QT) "QtCore QtGui"
} else {
set aLibsMap(CSF_fontconfig) "fontconfig"
if { "$theOS" == "qnx" } {
# CSF_ThreadLibs - pthread API is part of libc on QNX
set aLibsMap(CSF_OpenGlLibs) "EGL GLESv2"

View File

@@ -63,6 +63,7 @@ win32 {
CSF_TclTkLibs = -lX11 -ltk8.6
CSF_XwLibs = -lX11 -lXext -lXmu -lXi
CSF_MotifLibs = -lX11
CSF_fontconfig = -lfontconfig
HAVE_GLES2 { CSF_OpenGlLibs = -lEGL -lGLESv2 }
}

View File

@@ -24,6 +24,7 @@ set "HAVE_GLES2=false"
set "HAVE_D3D=false"
set "HAVE_ZLIB=false"
set "HAVE_LIBLZMA=false"
set "HAVE_RAPIDJSON=false"
set "CSF_OPT_INC="
set "CSF_OPT_LIB32="
set "CSF_OPT_LIB64="
@@ -163,6 +164,7 @@ if ["%HAVE_GLES2%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DH
if ["%HAVE_D3D%"] == ["true"] set "PRODUCTS_DEFINES=%PRODUCTS_DEFINES% -DHAVE_D3D" & set "CSF_DEFINES=HAVE_D3D;%CSF_DEFINES%"
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%"
rem Eliminate VS warning
if ["%CSF_DEFINES%"] == [""] set "CSF_DEFINES=;"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -222,6 +222,7 @@ for which OCCT is certified to work.
| Freetype (for text rendering) | FreeType 2.4.11-2.7.1 https://sourceforge.net/projects/freetype/files/ |
| FreeImage (optional, for support of common 2D graphic formats) | FreeImage 3.17.0+ https://sourceforge.net/projects/freeimage/files |
| FFmpeg (optional, for video recording) | FFmpeg 3.1+ https://www.ffmpeg.org/download.html |
| RapidJSON (optional, for reading glTF) | RapidJSON 1.1+ http://rapidjson.org/ |
| Intel TBB (optional, for multithreaded algorithms) | TBB 4.x or 5.x https://www.threadingbuildingblocks.org/ |
| VTK (for VTK Integration Services | VTK 6.1+ http://www.vtk.org/download/ |
| Doxygen (optional for building documentation) | Doxygen 1.8.5+ https://www.stack.nl/~dimitri/doxygen/download.html |

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1341,7 +1341,26 @@ Further, let us consider the triangle \f$ T_{0}\left \langle p_{0}, p_{1}, p_{2}
<span>10.</span> Compute the center of OBB and its half dimensions.<br>
<span>11.</span> Create OBB using the center, axes and half dimensions.<br>
This algorithm is implemented in the *Bnd_OBB::ReBuild(...)* method.
@subsubsection occt_modat_6_1_1_opt Creation of Optimal OBB from set of points
For creation of the optimal OBB from set of points the same algorithm as described above is used but with some simplifications in logic and increased computation time.
For the optimal OBB it is necessary to check all possible axes which can be created by the extremal points. And since the extremal points are only valid for the initial axes it is necessary to project the whole set of points on each axis.
This approach usually provides much tighter OBB but the performance is lower. The complexity of the algorithm is still linear and with use of BVH for the set of points it is O(N + C*log(N)).
Here is the example of optimal and not optimal OBB for the model using the set of 125K nodes:
<table align="center">
<tr>
<td>@figure{/user_guides/modeling_data/images/modeling_data_obb_125K.png,"Not optimal OBB by DiTo-14",160}</td>
<td>@figure{/user_guides/modeling_data/images/modeling_data_opt_obb_125K.png,"Optimal OBB by DiTo-14",160}</td>
<td>@figure{/user_guides/modeling_data/images/modeling_data_pca_obb_125K.png,"Not optimal OBB by PCA",160}</td>
</tr>
</table>
Computation of the not optimal OBB in this case took 0.007 sec, optimal - 0.1 sec, which is about 14 times slower. Such performance is comparable to creation of the OBB for this shape by PCA approach (see below) which takes about 0.17 sec.
The computation of optimal OBB is controlled by the same *theIsOptimal* flag in the BRepBndLib::AddOBB method as for PCA algorithm.
These algorithms are implemented in the *Bnd_OBB::ReBuild(...)* method.
@subsubsection occt_modat_6_1_2 Creation of OBB based on Axes of inertia

View File

@@ -783,6 +783,7 @@ Standard_Boolean AIS::GetPlaneFromFace(const TopoDS_Face& aFace,
BRepAdaptor_Surface surf1( aFace );
Handle( Adaptor3d_HSurface ) surf2;
Standard_Boolean isOffset = Standard_False;
Offset = 0.0;
if (surf1.GetType() == GeomAbs_OffsetSurface)
{
@@ -801,7 +802,6 @@ Standard_Boolean AIS::GetPlaneFromFace(const TopoDS_Face& aFace,
{
aPlane = surf2->Plane();
aSurfType = AIS_KOS_Plane;
Offset = 0.;
Result = Standard_True;
}
@@ -817,7 +817,6 @@ Standard_Boolean AIS::GetPlaneFromFace(const TopoDS_Face& aFace,
gp_Pln thePlane( LinePos, LineDir ^ ExtrusionDir);
aPlane = thePlane;
aSurfType = AIS_KOS_Plane;
Offset = 0.;
Result = Standard_True;
}
}
@@ -826,7 +825,6 @@ Standard_Boolean AIS::GetPlaneFromFace(const TopoDS_Face& aFace,
{
aSurf = (Handle( Geom_OffsetSurface )::DownCast( aSurf ))->Surface();
aPlane = (Handle( Geom_Plane )::DownCast( aSurf ))->Pln();
Offset = 0.0e0;
}
if (Result == Standard_False)
{
@@ -839,7 +837,6 @@ Standard_Boolean AIS::GetPlaneFromFace(const TopoDS_Face& aFace,
TheType == STANDARD_TYPE(Geom_ToroidalSurface))
{
aSurf = (Handle( Geom_OffsetSurface )::DownCast( aSurf ))->Surface();
Offset = 0.0e0;
}
else
{
@@ -899,20 +896,18 @@ gp_Pnt AIS::ProjectPointOnLine( const gp_Pnt & aPoint, const gp_Lin & aLine )
//function : InitFaceLength
//purpose :
//=======================================================================
void AIS::InitFaceLength (const TopoDS_Face& aFace,
gp_Pln & aPlane,
Handle(Geom_Surface) & aSurface,
AIS_KindOfSurface & aSurfaceType,
Standard_Real & anOffset)
void AIS::InitFaceLength (const TopoDS_Face& theFace,
gp_Pln& thePlane,
Handle(Geom_Surface)& theSurface,
AIS_KindOfSurface& theSurfaceType,
Standard_Real& theOffset)
{
AIS::GetPlaneFromFace( aFace, aPlane, aSurface, aSurfaceType, anOffset );
if (Abs( anOffset ) > Precision::Confusion())
{
aSurface = new Geom_OffsetSurface( aSurface, anOffset );
anOffset = 0.0e0;
}
if (AIS::GetPlaneFromFace (theFace, thePlane, theSurface, theSurfaceType, theOffset)
&& Abs (theOffset) > Precision::Confusion())
{
theSurface = new Geom_OffsetSurface (theSurface, theOffset);
theOffset = 0.0e0;
}
}
//=======================================================================

View File

@@ -633,9 +633,6 @@ void AIS_ColoredShape::addShapesWithCustomProps (const Handle(Prs3d_Presentation
{
aShadedGroup = thePrs->NewGroup();
aShadedGroup->SetClosed (isClosed);
if (isClosed
&& !myCappingStyle.IsNull())
aShadedGroup->SetGroupPrimitivesAspect (myCappingStyle);
}
aShadedGroup->SetPrimitivesAspect (aDrawer->ShadingAspect()->Aspect());
aShadedGroup->AddPrimitiveArray (aTriangles);

View File

@@ -18,7 +18,6 @@
#include <AIS_InteractiveContext.hxx>
#include <Graphic3d_AspectFillArea3d.hxx>
#include <Graphic3d_AspectFillCapping.hxx>
#include <Graphic3d_AspectLine3d.hxx>
#include <Graphic3d_AspectMarker3d.hxx>
#include <Graphic3d_AspectText3d.hxx>
@@ -84,37 +83,6 @@ void AIS_InteractiveObject::SetContext (const Handle(AIS_InteractiveContext)& th
}
}
//=======================================================================
//function : SetCappingStyle
//purpose :
//=======================================================================
void AIS_InteractiveObject::SetCappingStyle (const Handle(Graphic3d_AspectFillCapping)& theStyle)
{
myCappingStyle = theStyle;
// Modify existing presentations
for (Standard_Integer aPrsIter = 1, n = myPresentations.Length(); aPrsIter <= n; ++aPrsIter)
{
const Handle(PrsMgr_Presentation)& aPrs3d = myPresentations (aPrsIter);
if (!aPrs3d.IsNull())
{
const Handle(Graphic3d_Structure)& aStruct = aPrs3d->Presentation();
if (!aStruct.IsNull())
{
const Graphic3d_SequenceOfGroup& aGroups = aStruct->Groups();
for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (aGroups); aGroupIter.More(); aGroupIter.Next())
{
Handle(Graphic3d_Group)& aGrp = aGroupIter.ChangeValue();
if (aGrp.IsNull())
continue;
aGrp->SetGroupPrimitivesAspect (theStyle);
}
}
}
}
}
//=======================================================================
//function : HasPresentation
//purpose :

View File

@@ -104,12 +104,6 @@ public:
void ClearOwner() { myOwner.Nullify(); }
public:
//! Set style of filling capping section created by clipping planes.
Standard_EXPORT virtual void SetCappingStyle (const Handle(Graphic3d_AspectFillCapping)& theStyle);
//! Returns style for filling capping section created by clipping planes.
const Handle(Graphic3d_AspectFillCapping)& CappingStyle() const { return myCappingStyle; }
//! Returns the context pointer to the interactive context.
Standard_EXPORT Handle(AIS_InteractiveContext) GetContext() const;
@@ -134,7 +128,6 @@ protected:
AIS_InteractiveContext* myCTXPtr; //!< pointer to Interactive Context, where object is currently displayed; @sa SetContext()
Handle(Standard_Transient) myOwner; //!< application-specific owner object
Handle(Graphic3d_AspectFillCapping) myCappingStyle;
};

View File

@@ -180,7 +180,10 @@ void AIS_Shape::Compute(const Handle(PrsMgr_PresentationManager3d)& /*aPresentat
try
{
OCC_CATCH_SIGNALS
StdPrs_ShadedShape::Add (aPrs, myshape, myDrawer, myCappingStyle);
StdPrs_ShadedShape::Add (aPrs, myshape, myDrawer,
myDrawer->ShadingAspect()->Aspect()->ToMapTexture()
&& !myDrawer->ShadingAspect()->Aspect()->TextureMap().IsNull(),
myUVOrigin, myUVRepeat, myUVScale);
}
catch (Standard_Failure const& anException)
{

View File

@@ -93,9 +93,8 @@ public:
//! be ignored at all.
//! If theIsShapeToleranceUsed == TRUE then resulting box will be
//! extended on the tolerance of the shape.
//! theIsOptimal flag defines the algorithm for construction of initial
//! Bnd_Box for the second method (if theIsOptimal == TRUE then
//! this box will be created by AddOptimal(...) method).
//! theIsOptimal flag defines whether to look for the more tight
//! OBB for the cost of performance or not.
Standard_EXPORT static
void AddOBB(const TopoDS_Shape& theS,
Bnd_OBB& theOBB,

View File

@@ -293,6 +293,7 @@ static Standard_Integer IsWCS(const gp_Dir& theDir)
//=======================================================================
static Standard_Boolean CheckPoints(const TopoDS_Shape& theS,
const Standard_Boolean theIsTriangulationUsed,
const Standard_Boolean theIsOptimal,
const Standard_Boolean theIsShapeToleranceUsed,
Bnd_OBB& theOBB)
{
@@ -329,7 +330,7 @@ static Standard_Boolean CheckPoints(const TopoDS_Shape& theS,
}
#endif
theOBB.ReBuild(anArrPnts, aPtrArrTol);
theOBB.ReBuild(anArrPnts, aPtrArrTol, theIsOptimal);
return (!theOBB.IsVoid());
}
@@ -498,7 +499,7 @@ void BRepBndLib::AddOBB(const TopoDS_Shape& theS,
const Standard_Boolean theIsOptimal,
const Standard_Boolean theIsShapeToleranceUsed)
{
if(CheckPoints(theS, theIsTriangulationUsed, theIsShapeToleranceUsed, theOBB))
if (CheckPoints(theS, theIsTriangulationUsed, theIsOptimal, theIsShapeToleranceUsed, theOBB))
return;
ComputePCA(theS, theOBB, theIsTriangulationUsed, theIsOptimal, theIsShapeToleranceUsed);

View File

@@ -17,6 +17,7 @@
#include <BOPAlgo_BOP.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPDS_DS.hxx>
#include <BOPTools_AlgoTools.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepAlgoAPI_Section.hxx>
@@ -175,6 +176,7 @@ static void RemoveEdges(const TopoDS_Compound& theSourceComp,
static Standard_Boolean FilterSectionEdges(const BOPDS_VectorOfCurve& theBCurves,
const TopoDS_Face& theSecPlane,
const BOPDS_PDS& theDS,
const Handle (IntTools_Context)& theContext,
TopoDS_Compound& theResult);
static Standard_Boolean GetUEdges(const Standard_Integer theIndex,
@@ -345,7 +347,7 @@ void BRepFill_TrimShellCorner::Perform()
}
}
else {
if(!MakeFacesSec(ii, theDS, anIndex1, anIndex2, i)) {
if(!MakeFacesSec(ii, theDS, aPF.Context(), anIndex1, anIndex2, i)) {
myHistMap.Clear();
return;
}
@@ -658,6 +660,7 @@ BRepFill_TrimShellCorner::MakeFacesNonSec(const Standard_Integer
Standard_Boolean
BRepFill_TrimShellCorner::MakeFacesSec(const Standard_Integer theIndex,
const BOPDS_PDS& theDS,
const Handle (IntTools_Context)& theContext,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2,
const Standard_Integer theSSInterfIndex)
@@ -669,7 +672,7 @@ BRepFill_TrimShellCorner::MakeFacesSec(const Standard_Integer
TopoDS_Compound aSecEdges;
TopoDS_Face aSecPlane;
if(!FilterSectionEdges(aBCurves, aSecPlane, theDS, aSecEdges))
if(!FilterSectionEdges(aBCurves, aSecPlane, theDS, theContext, aSecEdges))
return Standard_False;
//Extract vertices on the intersection of correspondent U-edges
@@ -787,11 +790,18 @@ BRepFill_TrimShellCorner::MakeFacesSec(const Standard_Integer
aBB.MakeWire(aW);
TopTools_ListIteratorOfListOfShape aEIt(aListOfWireEdges);
for(; aEIt.More(); aEIt.Next()) {
if(!aBoundEdge.IsSame(aEIt.Value()))
aBB.Add(aW, aEIt.Value());
TopoDS_Edge aFBE = TopoDS::Edge (aBoundEdge.Oriented (TopAbs_FORWARD));
for (; aEIt.More(); aEIt.Next())
{
if (!aBoundEdge.IsSame(aEIt.Value()))
{
TopoDS_Edge aSplit = TopoDS::Edge (aEIt.Value());
if (BOPTools_AlgoTools::IsSplitToReverse (aSplit, aFBE, theContext))
aSplit.Reverse();
aBB.Add (aW, aSplit);
}
}
aSubstitutor->Replace(aBoundEdge.Oriented(TopAbs_FORWARD), aW);
aSubstitutor->Replace (aFBE, aW);
}
aSubstitutor->Apply(aFace);
@@ -2154,6 +2164,7 @@ void RemoveEdges(const TopoDS_Compound& theSourceComp,
Standard_Boolean FilterSectionEdges(const BOPDS_VectorOfCurve& theBCurves,
const TopoDS_Face& theSecPlane,
const BOPDS_PDS& theDS,
const Handle (IntTools_Context)& theContext,
TopoDS_Compound& theResult) {
theResult.Nullify();
@@ -2181,10 +2192,7 @@ Standard_Boolean FilterSectionEdges(const BOPDS_VectorOfCurve& theBCurves,
Standard_Real f = 0., l = 0.;
BRep_Tool::Range(anEdge, f, l);
anIntersector.SetBeanParameters(f, l);
//
Handle(IntTools_Context) aContext = new IntTools_Context;
anIntersector.SetContext(aContext);
//
anIntersector.SetContext(theContext);
anIntersector.Perform();
if(anIntersector.IsDone()) {

View File

@@ -35,7 +35,7 @@ class gp_Ax2;
class TopoDS_Face;
class TopoDS_Wire;
class TopoDS_Shape;
class IntTools_Context;
//! Trims sets of faces in the corner to make proper parts of pipe
class BRepFill_TrimShellCorner
@@ -80,6 +80,7 @@ private:
Standard_Boolean MakeFacesSec(const Standard_Integer theIndex,
const BOPDS_PDS& theDS,
const Handle (IntTools_Context)& theContext,
const Standard_Integer theFaceIndex1,
const Standard_Integer theFaceIndex2,
const Standard_Integer theSSInterfIndex);

View File

@@ -65,7 +65,7 @@ void BRepMesh_BaseMeshAlgo::Perform(
commitSurfaceTriangulation();
}
}
catch (Standard_Failure& /*theExeption*/)
catch (Standard_Failure const& /*theExeption*/)
{
}

View File

@@ -83,7 +83,7 @@ Handle(IMeshTools_CurveTessellator) BRepMesh_EdgeDiscret::CreateEdgeTessellation
// Function: Perform
// Purpose :
//=======================================================================
Standard_Boolean BRepMesh_EdgeDiscret::Perform (
Standard_Boolean BRepMesh_EdgeDiscret::performInternal (
const Handle (IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters)
{
@@ -108,69 +108,78 @@ Standard_Boolean BRepMesh_EdgeDiscret::Perform (
void BRepMesh_EdgeDiscret::process (const Standard_Integer theEdgeIndex) const
{
const IMeshData::IEdgeHandle& aDEdge = myModel->GetEdge (theEdgeIndex);
BRepMesh_Deflection::ComputeDeflection (aDEdge, myModel->GetMaxSize (), myParameters);
Handle (IMeshTools_CurveTessellator) aEdgeTessellator;
if (!aDEdge->IsFree ())
try
{
// Iterate over pcurves and check deflection on corresponding face.
Standard_Real aMinDeflection = RealLast ();
Standard_Integer aMinPCurveIndex = -1;
for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb (); ++aPCurveIt)
OCC_CATCH_SIGNALS
BRepMesh_Deflection::ComputeDeflection (aDEdge, myModel->GetMaxSize (), myParameters);
Handle (IMeshTools_CurveTessellator) aEdgeTessellator;
if (!aDEdge->IsFree ())
{
const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve (aPCurveIt);
const Standard_Real aTmpDeflection = checkExistingPolygonAndUpdateStatus(aDEdge, aPCurve);
if (aTmpDeflection < aMinDeflection)
// Iterate over pcurves and check deflection on corresponding face.
Standard_Real aMinDeflection = RealLast ();
Standard_Integer aMinPCurveIndex = -1;
for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb (); ++aPCurveIt)
{
// Identify pcurve with the smallest deflection in order to
// retrieve polygon that represents the most smooth discretization.
aMinDeflection = aTmpDeflection;
aMinPCurveIndex = aPCurveIt;
const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve (aPCurveIt);
const Standard_Real aTmpDeflection = checkExistingPolygonAndUpdateStatus(aDEdge, aPCurve);
if (aTmpDeflection < aMinDeflection)
{
// Identify pcurve with the smallest deflection in order to
// retrieve polygon that represents the most smooth discretization.
aMinDeflection = aTmpDeflection;
aMinPCurveIndex = aPCurveIt;
}
BRepMesh_ShapeTool::CheckAndUpdateFlags (aDEdge, aPCurve);
}
BRepMesh_ShapeTool::CheckAndUpdateFlags (aDEdge, aPCurve);
}
if (aMinPCurveIndex != -1)
{
aDEdge->SetDeflection (aMinDeflection);
const IMeshData::IFaceHandle aDFace = aDEdge->GetPCurve(aMinPCurveIndex)->GetFace();
aEdgeTessellator = CreateEdgeTessellationExtractor(aDEdge, aDFace);
}
else
{
const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(0);
const IMeshData::IFaceHandle aDFace = aPCurve->GetFace();
aEdgeTessellator = BRepMesh_EdgeDiscret::CreateEdgeTessellator(
aDEdge, aPCurve->GetOrientation(), aDFace, myParameters);
}
}
else
{
TopLoc_Location aLoc;
const Handle (Poly_Polygon3D)& aPoly3D = BRep_Tool::Polygon3D (aDEdge->GetEdge (), aLoc);
if (!aPoly3D.IsNull ())
{
if (aPoly3D->HasParameters () &&
aPoly3D->Deflection () < 1.1 * aDEdge->GetDeflection ())
if (aMinPCurveIndex != -1)
{
// Edge already has suitable 3d polygon.
aDEdge->SetStatus(IMeshData_Reused);
return;
aDEdge->SetDeflection (aMinDeflection);
const IMeshData::IFaceHandle aDFace = aDEdge->GetPCurve(aMinPCurveIndex)->GetFace();
aEdgeTessellator = CreateEdgeTessellationExtractor(aDEdge, aDFace);
}
else
{
aDEdge->SetStatus(IMeshData_Outdated);
const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(0);
const IMeshData::IFaceHandle aDFace = aPCurve->GetFace();
aEdgeTessellator = BRepMesh_EdgeDiscret::CreateEdgeTessellator(
aDEdge, aPCurve->GetOrientation(), aDFace, myParameters);
}
}
aEdgeTessellator = CreateEdgeTessellator(aDEdge, myParameters);
else
{
TopLoc_Location aLoc;
const Handle (Poly_Polygon3D)& aPoly3D = BRep_Tool::Polygon3D (aDEdge->GetEdge (), aLoc);
if (!aPoly3D.IsNull ())
{
if (aPoly3D->HasParameters () &&
aPoly3D->Deflection () < 1.1 * aDEdge->GetDeflection ())
{
// Edge already has suitable 3d polygon.
aDEdge->SetStatus(IMeshData_Reused);
return;
}
else
{
aDEdge->SetStatus(IMeshData_Outdated);
}
}
aEdgeTessellator = CreateEdgeTessellator(aDEdge, myParameters);
}
Tessellate3d (aDEdge, aEdgeTessellator, Standard_True);
if (!aDEdge->IsFree())
{
Tessellate2d(aDEdge, Standard_True);
}
}
Tessellate3d (aDEdge, aEdgeTessellator, Standard_True);
if (!aDEdge->IsFree())
catch (Standard_Failure const&)
{
Tessellate2d(aDEdge, Standard_True);
aDEdge->SetStatus (IMeshData_Failure);
}
}

View File

@@ -52,11 +52,6 @@ public:
const IMeshData::IEdgeHandle& theDEdge,
const IMeshData::IFaceHandle& theDFace);
//! Performs processing of edges of the given model.
Standard_EXPORT virtual Standard_Boolean Perform (
const Handle (IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) Standard_OVERRIDE;
//! Functor API to discretize the given edge.
inline void operator() (const Standard_Integer theEdgeIndex) const {
process (theEdgeIndex);
@@ -75,6 +70,13 @@ public:
DEFINE_STANDARD_RTTI_INLINE(BRepMesh_EdgeDiscret, IMeshTools_ModelAlgo)
protected:
//! Performs processing of edges of the given model.
Standard_EXPORT virtual Standard_Boolean performInternal (
const Handle (IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) Standard_OVERRIDE;
private:
//! Checks existing discretization of the edge and updates data model.

View File

@@ -43,7 +43,7 @@ BRepMesh_FaceDiscret::~BRepMesh_FaceDiscret()
// Function: Perform
// Purpose :
//=======================================================================
Standard_Boolean BRepMesh_FaceDiscret::Perform(
Standard_Boolean BRepMesh_FaceDiscret::performInternal(
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters)
{
@@ -73,14 +73,23 @@ void BRepMesh_FaceDiscret::process(const Standard_Integer theFaceIndex) const
return;
}
Handle(IMeshTools_MeshAlgo) aMeshingAlgo =
myAlgoFactory->GetAlgo(aDFace->GetSurface()->GetType(), myParameters);
if (aMeshingAlgo.IsNull())
try
{
aDFace->SetStatus(IMeshData_Failure);
return;
}
OCC_CATCH_SIGNALS
aMeshingAlgo->Perform(aDFace, myParameters);
Handle(IMeshTools_MeshAlgo) aMeshingAlgo =
myAlgoFactory->GetAlgo(aDFace->GetSurface()->GetType(), myParameters);
if (aMeshingAlgo.IsNull())
{
aDFace->SetStatus(IMeshData_Failure);
return;
}
aMeshingAlgo->Perform(aDFace, myParameters);
}
catch (Standard_Failure const&)
{
aDFace->SetStatus (IMeshData_Failure);
}
}

View File

@@ -23,7 +23,7 @@
//! Class implements functionality starting triangulation of model's faces.
//! Each face is processed separately and can be executed in parallel mode.
//! Uses mesh algo factory passed as initializer to create instace of triangulation
//! Uses mesh algo factory passed as initializer to create instance of triangulation
//! algorithm according to type of surface of target face.
class BRepMesh_FaceDiscret : public IMeshTools_ModelAlgo
{
@@ -36,11 +36,6 @@ public:
//! Destructor.
Standard_EXPORT virtual ~BRepMesh_FaceDiscret();
//! Performs processing of edges of the given model.
Standard_EXPORT virtual Standard_Boolean Perform(
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) Standard_OVERRIDE;
//! Functor API to discretize the given edge.
inline void operator() (const Standard_Integer theFaceIndex) const {
process(theFaceIndex);
@@ -48,6 +43,13 @@ public:
DEFINE_STANDARD_RTTI_INLINE(BRepMesh_FaceDiscret, IMeshTools_ModelAlgo)
protected:
//! Performs processing of faces of the given model.
Standard_EXPORT virtual Standard_Boolean performInternal (
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) Standard_OVERRIDE;
private:
//! Checks existing discretization of the face and updates data model.

View File

@@ -18,7 +18,6 @@
#include <BRepMesh_ShapeVisitor.hxx>
#include <BRepMesh_ShapeTool.hxx>
#include <IMeshTools_ShapeExplorer.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
@@ -43,52 +42,42 @@ BRepMesh_ModelBuilder::~BRepMesh_ModelBuilder ()
// Function: Perform
// Purpose :
//=======================================================================
Handle (IMeshData_Model) BRepMesh_ModelBuilder::Perform (
Handle (IMeshData_Model) BRepMesh_ModelBuilder::performInternal (
const TopoDS_Shape& theShape,
const IMeshTools_Parameters& theParameters)
{
ClearStatus ();
Handle (BRepMeshData_Model) aModel;
try
Bnd_Box aBox;
BRepBndLib::Add (theShape, aBox, Standard_False);
if (!aBox.IsVoid ())
{
OCC_CATCH_SIGNALS
// Build data model for further processing.
aModel = new BRepMeshData_Model (theShape);
Bnd_Box aBox;
BRepBndLib::Add (theShape, aBox, Standard_False);
if (!aBox.IsVoid ())
if (theParameters.Relative)
{
// Build data model for further processing.
aModel = new BRepMeshData_Model (theShape);
if (theParameters.Relative)
{
Standard_Real aMaxSize;
BRepMesh_ShapeTool::BoxMaxDimension (aBox, aMaxSize);
aModel->SetMaxSize(aMaxSize);
}
else
{
aModel->SetMaxSize(Max(theParameters.Deflection,
theParameters.DeflectionInterior));
}
Handle (IMeshTools_ShapeVisitor) aVisitor =
new BRepMesh_ShapeVisitor (aModel);
IMeshTools_ShapeExplorer aExplorer (theShape);
aExplorer.Accept (aVisitor);
SetStatus (Message_Done1);
Standard_Real aMaxSize;
BRepMesh_ShapeTool::BoxMaxDimension (aBox, aMaxSize);
aModel->SetMaxSize(aMaxSize);
}
else
{
SetStatus(Message_Fail1);
aModel->SetMaxSize(Max(theParameters.Deflection,
theParameters.DeflectionInterior));
}
Handle (IMeshTools_ShapeVisitor) aVisitor =
new BRepMesh_ShapeVisitor (aModel);
IMeshTools_ShapeExplorer aExplorer (theShape);
aExplorer.Accept (aVisitor);
SetStatus (Message_Done1);
}
catch (Standard_Failure&)
else
{
SetStatus (Message_Fail2);
SetStatus (Message_Fail1);
}
return aModel;

View File

@@ -36,13 +36,15 @@ public:
//! Destructor.
Standard_EXPORT virtual ~BRepMesh_ModelBuilder ();
DEFINE_STANDARD_RTTI_INLINE(BRepMesh_ModelBuilder, IMeshTools_ModelBuilder)
protected:
//! Creates discrete model for the given shape.
//! Returns nullptr in case of failure.
Standard_EXPORT virtual Handle (IMeshData_Model) Perform (
Standard_EXPORT virtual Handle (IMeshData_Model) performInternal (
const TopoDS_Shape& theShape,
const IMeshTools_Parameters& theParameters) Standard_OVERRIDE;
DEFINE_STANDARD_RTTI_INLINE(BRepMesh_ModelBuilder, IMeshTools_ModelBuilder)
};
#endif

View File

@@ -115,7 +115,7 @@ BRepMesh_ModelHealer::~BRepMesh_ModelHealer()
// Function: Perform
// Purpose :
//=======================================================================
Standard_Boolean BRepMesh_ModelHealer::Perform(
Standard_Boolean BRepMesh_ModelHealer::performInternal(
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters)
{
@@ -226,22 +226,31 @@ Standard_Boolean BRepMesh_ModelHealer::popEdgesToUpdate(
//=======================================================================
void BRepMesh_ModelHealer::process(const IMeshData::IFaceHandle& theDFace) const
{
Handle(IMeshData::MapOfIEdgePtr)& aIntersections = myFaceIntersectingEdges->ChangeFind(theDFace.get());
aIntersections.Nullify();
fixFaceBoundaries(theDFace);
if (!theDFace->IsSet(IMeshData_Failure))
try
{
BRepMesh_FaceChecker aChecker(theDFace, myParameters);
if (!aChecker.Perform())
OCC_CATCH_SIGNALS
Handle(IMeshData::MapOfIEdgePtr)& aIntersections = myFaceIntersectingEdges->ChangeFind(theDFace.get());
aIntersections.Nullify();
fixFaceBoundaries(theDFace);
if (!theDFace->IsSet(IMeshData_Failure))
{
BRepMesh_FaceChecker aChecker(theDFace, myParameters);
if (!aChecker.Perform())
{
#ifdef DEBUG_HEALER
std::cout << "Failed : #" << aChecker.GetIntersectingEdges()->Size() << std::endl;
std::cout << "Failed : #" << aChecker.GetIntersectingEdges()->Size() << std::endl;
#endif
aIntersections = aChecker.GetIntersectingEdges();
aIntersections = aChecker.GetIntersectingEdges();
}
}
}
catch (Standard_Failure const&)
{
theDFace->SetStatus (IMeshData_Failure);
}
}
//=======================================================================

View File

@@ -44,11 +44,6 @@ public:
//! Destructor.
Standard_EXPORT virtual ~BRepMesh_ModelHealer();
//! Performs processing of edges of the given model.
Standard_EXPORT virtual Standard_Boolean Perform(
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) Standard_OVERRIDE;
//! Functor API to discretize the given edge.
inline void operator() (const Standard_Integer theEdgeIndex) const {
process(theEdgeIndex);
@@ -61,6 +56,13 @@ public:
DEFINE_STANDARD_RTTI_INLINE(BRepMesh_ModelHealer, IMeshTools_ModelAlgo)
protected:
//! Performs processing of edges of the given model.
Standard_EXPORT virtual Standard_Boolean performInternal (
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) Standard_OVERRIDE;
private:
//! Checks existing discretization of the face and updates data model.

View File

@@ -177,7 +177,7 @@ BRepMesh_ModelPostProcessor::~BRepMesh_ModelPostProcessor()
// Function: Perform
// Purpose :
//=======================================================================
Standard_Boolean BRepMesh_ModelPostProcessor::Perform(
Standard_Boolean BRepMesh_ModelPostProcessor::performInternal(
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& /*theParameters*/)
{

View File

@@ -32,12 +32,14 @@ public:
//! Destructor.
Standard_EXPORT virtual ~BRepMesh_ModelPostProcessor();
DEFINE_STANDARD_RTTI_INLINE(BRepMesh_ModelPostProcessor, IMeshTools_ModelAlgo)
protected:
//! Performs processing of edges of the given model.
Standard_EXPORT virtual Standard_Boolean Perform(
Standard_EXPORT virtual Standard_Boolean performInternal (
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) Standard_OVERRIDE;
DEFINE_STANDARD_RTTI_INLINE(BRepMesh_ModelPostProcessor, IMeshTools_ModelAlgo)
};
#endif

View File

@@ -242,7 +242,7 @@ BRepMesh_ModelPreProcessor::~BRepMesh_ModelPreProcessor()
// Function: Perform
// Purpose :
//=======================================================================
Standard_Boolean BRepMesh_ModelPreProcessor::Perform(
Standard_Boolean BRepMesh_ModelPreProcessor::performInternal(
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters)
{

View File

@@ -33,12 +33,14 @@ public:
//! Destructor.
Standard_EXPORT virtual ~BRepMesh_ModelPreProcessor();
DEFINE_STANDARD_RTTI_INLINE(BRepMesh_ModelPreProcessor, IMeshTools_ModelAlgo)
protected:
//! Performs processing of edges of the given model.
Standard_EXPORT virtual Standard_Boolean Perform(
Standard_EXPORT virtual Standard_Boolean performInternal (
const Handle(IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) Standard_OVERRIDE;
DEFINE_STANDARD_RTTI_INLINE(BRepMesh_ModelPreProcessor, IMeshTools_ModelAlgo)
};
#endif

View File

@@ -17,6 +17,7 @@
#include <gp_Pnt2d.hxx>
#include <BRepMesh_OrientedEdge.hxx>
#include <BRepMesh_Vertex.hxx>
#include <Standard_OutOfRange.hxx>
//=======================================================================
// Function: Constructor
@@ -74,6 +75,9 @@ void BRepMeshData_PCurve::AddPoint (
//=======================================================================
gp_Pnt2d& BRepMeshData_PCurve::GetPoint (const Standard_Integer theIndex)
{
Standard_OutOfRange_Raise_if (
theIndex < 0 || theIndex >= static_cast<Standard_Integer>(myPoints2d.size()),
"BRepMeshData_PCurve::GetPoint");
return myPoints2d[theIndex];
}
@@ -83,6 +87,9 @@ gp_Pnt2d& BRepMeshData_PCurve::GetPoint (const Standard_Integer theIndex)
//=======================================================================
Standard_Integer& BRepMeshData_PCurve::GetIndex(const Standard_Integer theIndex)
{
Standard_OutOfRange_Raise_if (
theIndex < 0 || theIndex >= static_cast<Standard_Integer>(myIndices.size()),
"BRepMeshData_PCurve::GetIndex");
return myIndices[theIndex];
}
@@ -92,6 +99,9 @@ Standard_Integer& BRepMeshData_PCurve::GetIndex(const Standard_Integer theIndex)
//=======================================================================
Standard_Real& BRepMeshData_PCurve::GetParameter (const Standard_Integer theIndex)
{
Standard_OutOfRange_Raise_if (
theIndex < 0 || theIndex >= ParametersNb(),
"BRepMeshData_PCurve::GetParameter");
return myParameters[theIndex];
}

View File

@@ -1486,7 +1486,9 @@ void BRepTest::BasicCommands(Draw_Interpretor& theCommands)
"\n\t\t: -noTriangulation Force use of exact geometry for calculation"
"\n\t\t: even if triangulation is present."
"\n\t\t: -optimal Force calculation of optimal (more tight) AABB."
"\n\t\t: In case of OBB, applies to initial AABB used in OBB calculation."
"\n\t\t: In case of OBB:"
"\n\t\t: - for PCA approach applies to initial AABB used in OBB calculation"
"\n\t\t: - for DiTo approach modifies the DiTo algorithm to check more axes."
"\n\t\t: -extToler Include tolerance of the shape in the resulting box."
"\n\t\t:"
"\n\t\t: Output options:"

View File

@@ -14,11 +14,177 @@
#include <Bnd_OBB.hxx>
#include <Bnd_B3d.hxx>
#include <Bnd_Tools.hxx>
#include <Bnd_Range.hxx>
#include <BVH_BoxSet.hxx>
#include <BVH_LinearBuilder.hxx>
#include <BVH_Traverse.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <TColStd_Array1OfReal.hxx>
//! Auxiliary class to select from the points stored in
//! BVH tree the two points giving the extreme projection
//! parameters on the axis
class OBB_ExtremePointsSelector :
public BVH_Traverse <Standard_Real, 3, BVH_BoxSet <Standard_Real, 3, gp_XYZ>, Bnd_Range>
{
public:
//! Constructor
OBB_ExtremePointsSelector() :
BVH_Traverse <Standard_Real, 3, BVH_BoxSet <Standard_Real, 3, gp_XYZ>, Bnd_Range>(),
myPrmMin (RealLast()),
myPrmMax (RealFirst())
{}
public: //! @name Set axis for projection
//! Sets the axis
void SetAxis (const gp_XYZ& theAxis) { myAxis = theAxis; }
public: //! @name Clears the points from previous runs
//! Clear
void Clear()
{
myPrmMin = RealLast();
myPrmMax = RealFirst();
}
public: //! @name Getting the results
//! Returns the minimal projection parameter
Standard_Real MinPrm() const { return myPrmMin; }
//! Returns the maximal projection parameter
Standard_Real MaxPrm() const { return myPrmMax; }
//! Returns the minimal projection point
const gp_XYZ& MinPnt() const { return myPntMin; }
//! Returns the maximal projection point
const gp_XYZ& MaxPnt() const { return myPntMax; }
public: //! @name Definition of rejection/acceptance rules
//! Defines the rules for node rejection
virtual Standard_Boolean RejectNode (const BVH_Vec3d& theCMin,
const BVH_Vec3d& theCMax,
Bnd_Range& theMetric) const Standard_OVERRIDE
{
if (myPrmMin > myPrmMax)
// No parameters computed yet
return Standard_False;
Standard_Real aPrmMin = myPrmMin, aPrmMax = myPrmMax;
Standard_Boolean isToReject = Standard_True;
// Check if the current node is between already found parameters
for (Standard_Integer i = 0; i < 2; ++i)
{
Standard_Real x = !i ? theCMin.x() : theCMax.x();
for (Standard_Integer j = 0; j < 2; ++j)
{
Standard_Real y = !j ? theCMin.y() : theCMax.y();
for (Standard_Integer k = 0; k < 2; ++k)
{
Standard_Real z = !k ? theCMin.z() : theCMax.z();
Standard_Real aPrm = myAxis.Dot (gp_XYZ (x, y, z));
if (aPrm < aPrmMin)
{
aPrmMin = aPrm;
isToReject = Standard_False;
}
else if (aPrm > aPrmMax)
{
aPrmMax = aPrm;
isToReject = Standard_False;
}
}
}
}
theMetric = Bnd_Range (aPrmMin, aPrmMax);
return isToReject;
}
//! Rules for node rejection by the metric
virtual Standard_Boolean RejectMetric (const Bnd_Range& theMetric) const Standard_OVERRIDE
{
if (myPrmMin > myPrmMax)
// no parameters computed
return Standard_False;
Standard_Real aMin, aMax;
if (!theMetric.GetBounds (aMin, aMax))
// void metric
return Standard_False;
// Check if the box of the branch is inside of the already computed parameters
return aMin > myPrmMin && aMax < myPrmMax;
}
//! Defines the rules for leaf acceptance
virtual Standard_Boolean Accept (const Standard_Integer theIndex,
const Bnd_Range&) Standard_OVERRIDE
{
const gp_XYZ& theLeaf = myBVHSet->Element (theIndex);
Standard_Real aPrm = myAxis.Dot (theLeaf);
if (aPrm < myPrmMin)
{
myPrmMin = aPrm;
myPntMin = theLeaf;
}
if (aPrm > myPrmMax)
{
myPrmMax = aPrm;
myPntMax = theLeaf;
}
return Standard_True;
}
public: //! @name Choosing the best branch
//! Returns true if the metric of the left branch is better than the metric of the right
virtual Standard_Boolean IsMetricBetter (const Bnd_Range& theLeft,
const Bnd_Range& theRight) const Standard_OVERRIDE
{
if (myPrmMin > myPrmMax)
// no parameters computed
return Standard_True;
Standard_Real aMin[2], aMax[2];
if (!theLeft.GetBounds (aMin[0], aMax[0]) ||
!theRight.GetBounds (aMin[1], aMax[1]))
// void metrics
return Standard_True;
// Choose branch with larger extension over computed parameters
Standard_Real anExt[2] = {0.0, 0.0};
for (int i = 0; i < 2; ++i)
{
if (aMin[i] < myPrmMin) anExt[i] += myPrmMin - aMin[i];
if (aMax[i] > myPrmMax) anExt[i] += aMax[i] - myPrmMax;
}
return anExt[0] > anExt[1];
}
protected: //! @name Fields
gp_XYZ myAxis; //!< Axis to project the points to
Standard_Real myPrmMin; //!< Minimal projection parameter
Standard_Real myPrmMax; //!< Maximal projection parameter
gp_XYZ myPntMin; //!< Minimal projection point
gp_XYZ myPntMax; //!< Maximal projection point
};
//! Tool for OBB construction
class OBBTool
{
public:
@@ -31,7 +197,8 @@ public:
//! must be available during all time of OBB creation
//! (i.e. while the object of OBBTool exists).
OBBTool(const TColgp_Array1OfPnt& theL,
const TColStd_Array1OfReal *theLT = 0);
const TColStd_Array1OfReal *theLT = 0,
Standard_Boolean theIsOptimal = Standard_False);
//! DiTO algorithm for OBB construction
//! (http://www.idt.mdh.se/~tla/publ/FastOBBs.pdf)
@@ -41,6 +208,10 @@ public:
void BuildBox(Bnd_OBB& theBox);
protected:
// Computes the extreme points on the set of Initial axes
void ComputeExtremePoints ();
//! Works with the triangle set by the points in myTriIdx.
//! If theIsBuiltTrg == TRUE, new set of triangles will be
//! recomputed.
@@ -71,6 +242,106 @@ protected:
OBBTool& operator=(const OBBTool&);
private:
//! Params structure stores the two values meaning
//! min and max parameters on the axis
struct Params
{
Params() :
_ParamMin(RealLast()), _ParamMax(RealFirst())
{}
Params(Standard_Real theMin, Standard_Real theMax)
: _ParamMin(theMin), _ParamMax(theMax)
{}
Standard_Real _ParamMin;
Standard_Real _ParamMax;
};
//! Computes the Minimal and maximal parameters on the vector
//! connecting the points myLExtremalPoints[theId1] and myLExtremalPoints[theId2]
void ComputeParams (const Standard_Integer theId1,
const Standard_Integer theId2,
Standard_Real &theMin,
Standard_Real &theMax)
{
theMin = myParams[theId1][theId2]._ParamMin;
theMax = myParams[theId1][theId2]._ParamMax;
if (theMin > theMax)
{
FindMinMax ((myLExtremalPoints[theId1] - myLExtremalPoints[theId2]).Normalized(), theMin, theMax);
myParams[theId1][theId2]._ParamMin = myParams[theId2][theId1]._ParamMin = theMin;
myParams[theId1][theId2]._ParamMax = myParams[theId2][theId1]._ParamMax = theMax;
}
}
//! Looks for the min-max parameters on the axis.
//! For optimal case projects all the points on the axis,
//! for not optimal - only the set of extreme points.
void FindMinMax (const gp_XYZ& theAxis,
Standard_Real &theMin,
Standard_Real &theMax)
{
theMin = RealLast(), theMax = RealFirst();
if (myOptimal)
Project (theAxis, theMin, theMax);
else
{
for (Standard_Integer i = 0; i < myNbExtremalPoints; ++i)
{
Standard_Real aPrm = theAxis.Dot (myLExtremalPoints[i]);
if (aPrm < theMin) theMin = aPrm;
if (aPrm > theMax) theMax = aPrm;
}
}
}
//! Projects the set of points on the axis
void Project (const gp_XYZ& theAxis,
Standard_Real& theMin, Standard_Real& theMax,
gp_XYZ* thePntMin = 0, gp_XYZ* thePntMax = 0)
{
theMin = RealLast(), theMax = RealFirst();
if (myOptimal)
{
// Project BVH
OBB_ExtremePointsSelector anExtremePointsSelector;
anExtremePointsSelector.SetBVHSet (myPointBoxSet.get());
anExtremePointsSelector.SetAxis (theAxis);
anExtremePointsSelector.Select();
theMin = anExtremePointsSelector.MinPrm();
theMax = anExtremePointsSelector.MaxPrm();
if (thePntMin) *thePntMin = anExtremePointsSelector.MinPnt();
if (thePntMax) *thePntMax = anExtremePointsSelector.MaxPnt();
}
else
{
// Project all points
for (Standard_Integer iP = myPntsList.Lower(); iP <= myPntsList.Upper(); ++iP)
{
const gp_XYZ& aPoint = myPntsList(iP).XYZ();
const Standard_Real aPrm = theAxis.Dot (aPoint);
if (aPrm < theMin)
{
theMin = aPrm;
if (thePntMin)
*thePntMin = aPoint;
}
if (aPrm > theMax)
{
theMax = aPrm;
if (thePntMax)
*thePntMax = aPoint;
}
}
}
}
private:
//! Number of the initial axes.
static const Standard_Integer myNbInitAxes = 7;
@@ -96,6 +367,16 @@ private:
//! The surface area of the OBB
Standard_Real myQualityCriterion;
//! Defines if the OBB should be computed more tight.
//! Takes more time, but the volume is less.
Standard_Boolean myOptimal;
//! Point box set organized with BVH
opencascade::handle<BVH_BoxSet <Standard_Real, 3, gp_XYZ>> myPointBoxSet;
//! Stored min/max parameters for the axes between extremal points
Params myParams[myNbExtremalPoints][myNbExtremalPoints];
};
//=======================================================================
@@ -110,7 +391,7 @@ static inline void SetMinMax(Standard_Real* const thePrmArr,
{
thePrmArr[0] = theNewParam;
}
else if(theNewParam > thePrmArr[1])
if(theNewParam > thePrmArr[1])
{
thePrmArr[1] = theNewParam;
}
@@ -122,76 +403,102 @@ static inline void SetMinMax(Standard_Real* const thePrmArr,
//=======================================================================
OBBTool::
OBBTool(const TColgp_Array1OfPnt& theL,
const TColStd_Array1OfReal *theLT) :myPntsList(theL),
myListOfTolers(theLT),
myQualityCriterion(RealLast())
const TColStd_Array1OfReal *theLT,
const Standard_Boolean theIsOptimal) : myPntsList(theL),
myListOfTolers(theLT),
myQualityCriterion(RealLast()),
myOptimal (theIsOptimal)
{
if (myOptimal)
{
// Use linear builder for BVH construction with 30 elements in the leaf
opencascade::handle<BVH_LinearBuilder<Standard_Real, 3> > aLBuilder =
new BVH_LinearBuilder<Standard_Real, 3> (30);
myPointBoxSet = new BVH_BoxSet <Standard_Real, 3, gp_XYZ> (aLBuilder);
myPointBoxSet->SetSize(myPntsList.Length());
// Add the points into Set
for (Standard_Integer iP = 0; iP < theL.Length(); ++iP)
{
const gp_Pnt& aP = theL (iP);
Standard_Real aTol = theLT ? theLT->Value(iP) : Precision::Confusion();
BVH_Box <Standard_Real, 3> aBox (BVH_Vec3d (aP.X() - aTol, aP.Y() - aTol, aP.Z() - aTol),
BVH_Vec3d (aP.X() + aTol, aP.Y() + aTol, aP.Z() + aTol));
myPointBoxSet->Add (aP.XYZ(), aBox);
}
myPointBoxSet->Build();
}
ComputeExtremePoints();
}
//=======================================================================
// Function : ComputeExtremePoints
// purpose :
//=======================================================================
void OBBTool::ComputeExtremePoints()
{
// Six initial axes show great quality on the Optimal OBB, plus
// the performance is better (due to the less number of operations).
// But they show worse quality for the not optimal approach.
//const Standard_Real a = (sqrt(5) - 1) / 2.;
//const gp_XYZ anInitialAxes6[myNbInitAxes] = { gp_XYZ (0, 1, a),
// gp_XYZ (0, 1, -a),
// gp_XYZ (1, a, 0),
// gp_XYZ (1, -a, 0),
// gp_XYZ (a, 0, 1),
// gp_XYZ (a, 0, -1) };
const Standard_Real aSqrt3 = Sqrt(3);
// Origin of all initial axis is (0,0,0).
// All axes must be normalized.
const gp_XYZ anInitialAxesArray[myNbInitAxes] = {gp_XYZ(1.0, 0.0, 0.0),
gp_XYZ(0.0, 1.0, 0.0),
gp_XYZ(0.0, 0.0, 1.0),
gp_XYZ(1.0, 1.0, 1.0) / aSqrt3,
gp_XYZ(1.0, 1.0, -1.0) / aSqrt3,
gp_XYZ(1.0, -1.0, 1.0) / aSqrt3,
gp_XYZ(1.0, -1.0, -1.0) / aSqrt3};
const gp_XYZ anInitialAxes7[myNbInitAxes] = { gp_XYZ (1.0, 0.0, 0.0),
gp_XYZ (0.0, 1.0, 0.0),
gp_XYZ (0.0, 0.0, 1.0),
gp_XYZ (1.0, 1.0, 1.0) / aSqrt3,
gp_XYZ (1.0, 1.0, -1.0) / aSqrt3,
gp_XYZ (1.0, -1.0, 1.0) / aSqrt3,
gp_XYZ (1.0, -1.0, -1.0) / aSqrt3 };
// Minimal and maximal point on every axis
const Standard_Integer aNbPoints = 2 * myNbInitAxes;
// Set of initial axes
const gp_XYZ *anInitialAxesArray = anInitialAxes7;
for(Standard_Integer i = 0; i < 5; i++)
{
myTriIdx[i] = INT_MAX;
}
// Min and Max parameter
Standard_Real aParams[aNbPoints];
for(Standard_Integer i = 0; i < aNbPoints; i += 2)
{
aParams[i] = RealLast();
aParams[i + 1] = RealFirst();
}
Standard_Real aParams[myNbExtremalPoints];
// Look for the extremal points (myLExtremalPoints)
for(Standard_Integer i = myPntsList.Lower() ; i <= myPntsList.Upper(); i++)
for (Standard_Integer anAxeInd = 0, aPrmInd = -1; anAxeInd < myNbInitAxes; ++anAxeInd)
{
const gp_XYZ &aCurrPoint = myPntsList(i).XYZ();
for(Standard_Integer anAxeInd = 0, aPrmInd = 0; anAxeInd < myNbInitAxes; anAxeInd++, aPrmInd++)
{
const Standard_Real aParam = aCurrPoint.Dot(anInitialAxesArray[anAxeInd]);
if(aParam < aParams[aPrmInd])
{
myLExtremalPoints[aPrmInd] = aCurrPoint;
aParams[aPrmInd] = aParam;
}
aPrmInd++;
if(aParam > aParams[aPrmInd])
{
myLExtremalPoints[aPrmInd] = aCurrPoint;
aParams[aPrmInd] = aParam;
}
}
Standard_Integer aMinInd = ++aPrmInd, aMaxInd = ++aPrmInd;
aParams[aMinInd] = RealLast();
aParams[aMaxInd] = -RealLast();
Project (anInitialAxesArray[anAxeInd],
aParams[aMinInd], aParams[aMaxInd],
&myLExtremalPoints[aMinInd], &myLExtremalPoints[aMaxInd]);
}
// Compute myTriIdx[0] and myTriIdx[1].
Standard_Real aMaxSqDist = -1.0;
for(Standard_Integer aPrmInd = 0; aPrmInd < aNbPoints; aPrmInd += 2)
// For not optimal box it is necessary to compute the max axis
// created by the maximally distant extreme points
if (!myOptimal)
{
const gp_Pnt &aP1 = myLExtremalPoints[aPrmInd],
&aP2 = myLExtremalPoints[aPrmInd + 1];
const Standard_Real aSqDist = aP1.SquareDistance(aP2);
if(aSqDist > aMaxSqDist)
{
aMaxSqDist = aSqDist;
myTriIdx[0] = aPrmInd;
myTriIdx[1] = aPrmInd + 1;
}
}
for(Standard_Integer i = 0; i < 5; i++)
myTriIdx[i] = INT_MAX;
FillToTriangle3();
// Compute myTriIdx[0] and myTriIdx[1].
Standard_Real aMaxSqDist = -1.0;
for (Standard_Integer aPrmInd = 0; aPrmInd < myNbExtremalPoints; aPrmInd += 2)
{
const gp_Pnt &aP1 = myLExtremalPoints[aPrmInd],
&aP2 = myLExtremalPoints[aPrmInd + 1];
const Standard_Real aSqDist = aP1.SquareDistance(aP2);
if (aSqDist > aMaxSqDist)
{
aMaxSqDist = aSqDist;
myTriIdx[0] = aPrmInd;
myTriIdx[1] = aPrmInd + 1;
}
}
// Compute the maximal axis orthogonal to the found one
FillToTriangle3();
}
}
//=======================================================================
@@ -233,6 +540,7 @@ void OBBTool::FillToTriangle5(const gp_XYZ& theNormal,
const gp_XYZ& theBarryCenter)
{
Standard_Real aParams[2] = {0.0, 0.0};
Standard_Integer id3 = -1, id4 = -1;
for(Standard_Integer aPtIdx = 0; aPtIdx < myNbExtremalPoints; aPtIdx++)
{
@@ -242,28 +550,24 @@ void OBBTool::FillToTriangle5(const gp_XYZ& theNormal,
const gp_XYZ &aCurrPoint = myLExtremalPoints[aPtIdx];
const Standard_Real aParam = theNormal.Dot(aCurrPoint - theBarryCenter);
if(aParam < aParams[0])
if (aParam < aParams[0])
{
myTriIdx[3] = aPtIdx;
id3 = aPtIdx;
aParams[0] = aParam;
}
else if(aParam > aParams[1])
else if (aParam > aParams[1])
{
myTriIdx[4] = aPtIdx;
id4 = aPtIdx;
aParams[1] = aParam;
}
}
// The points must be in the different sides of the triangle plane.
if(aParams[0] > -Precision::Confusion())
{
myTriIdx[3] = INT_MAX;
}
if (id3 >= 0 && aParams[0] < -Precision::Confusion())
myTriIdx[3] = id3;
if(aParams[1] < Precision::Confusion())
{
myTriIdx[4] = INT_MAX;
}
if (id4 >= 0 && aParams[1] > Precision::Confusion())
myTriIdx[4] = id4;
}
//=======================================================================
@@ -279,71 +583,60 @@ void OBBTool::ProcessTriangle(const Standard_Integer theIdx1,
{
const Standard_Integer aNbAxes = 3;
//Some vertex of the triangle
const gp_XYZ aP0 = myLExtremalPoints[theIdx1];
// All axes must be normalized in order to provide correct area computation
// (see ComputeQuality(...) method).
gp_XYZ aYAxis[aNbAxes] = {(myLExtremalPoints[theIdx2] - myLExtremalPoints[theIdx1]),
(myLExtremalPoints[theIdx3] - myLExtremalPoints[theIdx2]),
(myLExtremalPoints[theIdx1] - myLExtremalPoints[theIdx3])};
int ID1[3] = { theIdx2, theIdx3, theIdx1 },
ID2[3] = { theIdx1, theIdx2, theIdx3 };
gp_XYZ aYAxis[aNbAxes] = {(myLExtremalPoints[ID1[0]] - myLExtremalPoints[ID2[0]]),
(myLExtremalPoints[ID1[1]] - myLExtremalPoints[ID2[1]]),
(myLExtremalPoints[ID1[2]] - myLExtremalPoints[ID2[2]])};
// Normal to the triangle plane
gp_XYZ aZAxis = aYAxis[0].Crossed(aYAxis[1]);
Standard_Real aSqMod = aZAxis.SquareModulus();
if(aSqMod < Precision::SquareConfusion())
if (aSqMod < Precision::SquareConfusion())
return;
aZAxis /= Sqrt(aSqMod);
gp_XYZ aXAxis[aNbAxes];
for(Standard_Integer i = 0; i < aNbAxes; i++)
{
for (Standard_Integer i = 0; i < aNbAxes; i++)
aXAxis[i] = aYAxis[i].Crossed(aZAxis).Normalized();
aYAxis[i].Normalize();
}
if(theIsBuiltTrg)
FillToTriangle5(aZAxis, aP0);
if (theIsBuiltTrg)
FillToTriangle5 (aZAxis, myLExtremalPoints[theIdx1]);
// Min and Max parameter
const Standard_Integer aNbPoints = 2 * aNbAxes;
// Compute Min/Max params for ZAxis
Standard_Real aParams[aNbPoints];
FindMinMax (aZAxis, aParams[4], aParams[5]); // Compute params on ZAxis once
Standard_Integer aMinIdx = -1;
for(Standard_Integer anAxeInd = 0; anAxeInd < aNbAxes; anAxeInd++)
{
const gp_XYZ &aAX = aXAxis[anAxeInd],
&aAY = aYAxis[anAxeInd];
Standard_Real aParams[aNbPoints] = {0.0, 0.0, 0.0,
0.0, 0.0, 0.0};
for(Standard_Integer aPtIdx = 0; aPtIdx < myNbExtremalPoints; aPtIdx++)
{
if(aPtIdx == theIdx1)
continue;
const gp_XYZ aCurrPoint = myLExtremalPoints[aPtIdx] - aP0;
SetMinMax(&aParams[0], aAX.Dot(aCurrPoint));
SetMinMax(&aParams[2], aAY.Dot(aCurrPoint));
SetMinMax(&aParams[4], aZAxis.Dot(aCurrPoint));
}
const gp_XYZ &aAX = aXAxis[anAxeInd];
// Compute params on XAxis
FindMinMax (aAX, aParams[0], aParams[1]);
// Compute params on YAxis checking for stored values
ComputeParams (ID1[anAxeInd], ID2[anAxeInd], aParams[2], aParams[3]);
const Standard_Real anArea = ComputeQuality(aParams);
if(anArea < myQualityCriterion)
if (anArea < myQualityCriterion)
{
myQualityCriterion = anArea;
aMinIdx = anAxeInd;
}
}
if(aMinIdx < 0)
if (aMinIdx < 0)
return;
myAxes[0] = aXAxis[aMinIdx];
myAxes[1] = aYAxis[aMinIdx];
myAxes[1] = aYAxis[aMinIdx].Normalized();
myAxes[2] = aZAxis;
}
//=======================================================================
@@ -352,20 +645,41 @@ void OBBTool::ProcessTriangle(const Standard_Integer theIdx1,
//=======================================================================
void OBBTool::ProcessDiTetrahedron()
{
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[2], Standard_True);
if(myTriIdx[3] <= myNbExtremalPoints)
// To compute the optimal OBB it is necessary to check all possible
// axes created by the extremal points. It is also necessary to project
// all the points on the axis, as for each different axis there will be
// different extremal points.
if (myOptimal)
{
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[3], Standard_False);
ProcessTriangle(myTriIdx[1], myTriIdx[2], myTriIdx[3], Standard_False);
ProcessTriangle(myTriIdx[0], myTriIdx[2], myTriIdx[3], Standard_False);
for (Standard_Integer i = 0; i < myNbExtremalPoints - 2; i++)
{
for (Standard_Integer j = i + 1; j < myNbExtremalPoints - 1; j++)
{
for (Standard_Integer k = j + 1; k < myNbExtremalPoints; k++)
{
ProcessTriangle (i, j, k, Standard_False);
}
}
}
}
if(myTriIdx[4] <= myNbExtremalPoints)
else
{
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[4], Standard_False);
ProcessTriangle(myTriIdx[1], myTriIdx[2], myTriIdx[4], Standard_False);
ProcessTriangle(myTriIdx[0], myTriIdx[2], myTriIdx[4], Standard_False);
// Use the standard DiTo approach
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[2], Standard_True);
if (myTriIdx[3] <= myNbExtremalPoints)
{
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[3], Standard_False);
ProcessTriangle(myTriIdx[1], myTriIdx[2], myTriIdx[3], Standard_False);
ProcessTriangle(myTriIdx[0], myTriIdx[2], myTriIdx[3], Standard_False);
}
if (myTriIdx[4] <= myNbExtremalPoints)
{
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[4], Standard_False);
ProcessTriangle(myTriIdx[1], myTriIdx[2], myTriIdx[4], Standard_False);
ProcessTriangle(myTriIdx[0], myTriIdx[2], myTriIdx[4], Standard_False);
}
}
}
@@ -452,7 +766,8 @@ void OBBTool::BuildBox(Bnd_OBB& theBox)
// purpose : http://www.idt.mdh.se/~tla/publ/
// =======================================================================
void Bnd_OBB::ReBuild(const TColgp_Array1OfPnt& theListOfPoints,
const TColStd_Array1OfReal *theListOfTolerances)
const TColStd_Array1OfReal *theListOfTolerances,
const Standard_Boolean theIsOptimal)
{
switch(theListOfPoints.Length())
{
@@ -504,7 +819,7 @@ void Bnd_OBB::ReBuild(const TColgp_Array1OfPnt& theListOfPoints,
break;
}
OBBTool aTool(theListOfPoints, theListOfTolerances);
OBBTool aTool(theListOfPoints, theListOfTolerances, theIsOptimal);
aTool.ProcessDiTetrahedron();
aTool.BuildBox(*this);
}

View File

@@ -95,12 +95,17 @@ public:
myCenter.SetCoord(0.5*(aX2 + aX1), 0.5*(aY2 + aY1), 0.5*(aZ2 + aZ1));
}
//! Created new OBB covering every point in theListOfPoints.
//! Creates new OBB covering every point in theListOfPoints.
//! Tolerance of every such point is set by *theListOfTolerances array.
//! If this array is not void (not null-pointer) then the resulted Bnd_OBB
//! will be enlarged using tolerances of points lying on the box surface.
//! <theIsOptimal> flag defines the mode in which the OBB will be built.
//! Constructing Optimal box takes more time, but the resulting box is usually
//! more tight. In case of construction of Optimal OBB more possible
//! axes are checked.
Standard_EXPORT void ReBuild(const TColgp_Array1OfPnt& theListOfPoints,
const TColStd_Array1OfReal *theListOfTolerances = 0);
const TColStd_Array1OfReal *theListOfTolerances = 0,
const Standard_Boolean theIsOptimal = Standard_False);
//! Sets the center of OBB
void SetCenter(const gp_Pnt& theCenter)

View File

@@ -362,6 +362,11 @@ static Standard_Integer dversion(Draw_Interpretor& di, Standard_Integer, const c
#else
di << "OpenGL: desktop\n";
#endif
#ifdef HAVE_RAPIDJSON
di << "RapidJSON enabled (HAVE_RAPIDJSON)\n";
#else
di << "RapidJSON disabled\n";
#endif
#ifdef HAVE_VTK
di << "VTK enabled (HAVE_VTK)\n";
#else

View File

@@ -310,6 +310,23 @@ proc checkreal {name value expected tol_abs tol_rel} {
return
}
# Procedure to check equality of two 3D points with tolerance
help checkpoint {
Compare two 3D points with given tolerance
Use: checkpoint name {valueX valueY valueZ} {expectedX expectedY expectedZ} tolerance
}
proc checkpoint {theName theValue theExpected theTolerance} {
set e 0.0001
foreach i {0 1 2} {
if { [expr abs([lindex $theValue $i] - [lindex $theExpected $i])] > $theTolerance } {
puts "Error: $theName, ($theValue) is not equal to expected ($theExpected)"
return
}
}
puts "Check of $theName OK: value = ($theValue), expected = ($theExpected)"
return
}
help checkfreebounds {
Compare number of free edges with ref_value

View File

@@ -1298,23 +1298,23 @@ proc _run_test {scriptsdir group gridname casefile echo} {
# execute test scripts
if { [file exists $scriptsdir/$group/begin] } {
puts "Executing $scriptsdir/$group/begin..."; flush stdout
uplevel source $scriptsdir/$group/begin
uplevel source -encoding utf-8 $scriptsdir/$group/begin
}
if { [file exists $scriptsdir/$group/$gridname/begin] } {
puts "Executing $scriptsdir/$group/$gridname/begin..."; flush stdout
uplevel source $scriptsdir/$group/$gridname/begin
uplevel source -encoding utf-8 $scriptsdir/$group/$gridname/begin
}
puts "Executing $casefile..."; flush stdout
uplevel source $casefile
uplevel source -encoding utf-8 $casefile
if { [file exists $scriptsdir/$group/$gridname/end] } {
puts "Executing $scriptsdir/$group/$gridname/end..."; flush stdout
uplevel source $scriptsdir/$group/$gridname/end
uplevel source -encoding utf-8 $scriptsdir/$group/$gridname/end
}
if { [file exists $scriptsdir/$group/end] } {
puts "Executing $scriptsdir/$group/end..."; flush stdout
uplevel source $scriptsdir/$group/end
uplevel source -encoding utf-8 $scriptsdir/$group/end
}
} res] {
puts "Tcl Exception: $res"

View File

@@ -17,3 +17,4 @@ Font_SystemFont.cxx
Font_SystemFont.hxx
Font_TextFormatter.hxx
Font_TextFormatter.cxx
Font_UnicodeSubset.hxx

View File

@@ -407,7 +407,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
{
theShape.Nullify();
if (!loadGlyph (theChar)
|| myFTFace->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|| myActiveFTFace->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
{
return Standard_False;
}
@@ -416,8 +416,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
return !theShape.IsNull();
}
FT_Outline& anOutline = myFTFace->glyph->outline;
const FT_Outline& anOutline = myActiveFTFace->glyph->outline;
if (!anOutline.n_contours)
return Standard_False;

View File

@@ -21,6 +21,8 @@
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <algorithm>
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -33,9 +35,12 @@ IMPLEMENT_STANDARD_RTTIEXT(Font_FTFont,Standard_Transient)
Font_FTFont::Font_FTFont (const Handle(Font_FTLibrary)& theFTLib)
: myFTLib (theFTLib),
myFTFace (NULL),
myActiveFTFace(NULL),
myFontAspect (Font_FontAspect_Regular),
myWidthScaling(1.0),
myLoadFlags (FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL),
myUChar (0U)
myUChar (0U),
myToUseUnicodeSubsetFallback (Font_FontMgr::ToUseUnicodeSubsetFallback())
{
if (myFTLib.IsNull())
{
@@ -66,6 +71,7 @@ void Font_FTFont::Release()
FT_Done_Face (myFTFace);
myFTFace = NULL;
}
myActiveFTFace = NULL;
myBuffer.Nullify();
}
@@ -135,6 +141,7 @@ bool Font_FTFont::Init (const Handle(NCollection_Buffer)& theData,
FT_Set_Transform (myFTFace, &aMat, 0);
}
myActiveFTFace = myFTFace;
return true;
}
@@ -161,6 +168,7 @@ Handle(Font_FTFont) Font_FTFont::FindAndCreate (const TCollection_AsciiString& t
Handle(Font_FTFont) aFont = new Font_FTFont();
if (aFont->Init (aPath, aParams))
{
aFont->myFontAspect = aFontAspect;
return aFont;
}
}
@@ -177,22 +185,61 @@ bool Font_FTFont::FindAndInit (const TCollection_AsciiString& theFontName,
Font_StrictLevel theStrictLevel)
{
Font_FTFontParams aParams = theParams;
Font_FontAspect aFontAspect = theFontAspect;
myFontAspect = theFontAspect;
Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName.ToCString(), theStrictLevel, aFontAspect))
if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName.ToCString(), theStrictLevel, myFontAspect))
{
if (aRequestedFont->IsSingleStrokeFont())
{
aParams.IsSingleStrokeFont = true;
}
const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (aFontAspect, aParams.ToSynthesizeItalic);
const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic);
return Init (aPath, aParams);
}
Release();
return false;
}
// =======================================================================
// function : findAndInitFallback
// purpose :
// =======================================================================
bool Font_FTFont::findAndInitFallback (Font_UnicodeSubset theSubset)
{
if (!myFallbackFaces[theSubset].IsNull())
{
return myFallbackFaces[theSubset]->IsValid();
}
myFallbackFaces[theSubset] = new Font_FTFont (myFTLib);
myFallbackFaces[theSubset]->myToUseUnicodeSubsetFallback = false; // no recursion
Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFallbackFont (theSubset, myFontAspect))
{
Font_FTFontParams aParams = myFontParams;
aParams.IsSingleStrokeFont = aRequestedFont->IsSingleStrokeFont();
const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic);
if (myFallbackFaces[theSubset]->Init (aPath, aParams))
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Font_FTFont, using fallback font '") + aRequestedFont->FontName() + "'"
+ " for symbols unsupported by '" + myFTFace->family_name + "'", Message_Trace);
}
}
return myFallbackFaces[theSubset]->IsValid();
}
// =======================================================================
// function : HasSymbol
// purpose :
// =======================================================================
bool Font_FTFont::HasSymbol (Standard_Utf32Char theUChar) const
{
return FT_Get_Char_Index (myFTFace, theUChar) != 0;
}
// =======================================================================
// function : loadGlyph
// purpose :
@@ -206,9 +253,26 @@ bool Font_FTFont::loadGlyph (const Standard_Utf32Char theUChar)
myGlyphImg.Clear();
myUChar = 0;
if (theUChar == 0
|| FT_Load_Char (myFTFace, theUChar, FT_Int32(myLoadFlags)) != 0
|| myFTFace->glyph == NULL)
myActiveFTFace = myFTFace;
if (theUChar == 0)
{
return false;
}
if (myToUseUnicodeSubsetFallback
&& !HasSymbol (theUChar))
{
// try using fallback
const Font_UnicodeSubset aSubset = CharSubset (theUChar);
if (findAndInitFallback (aSubset)
&& myFallbackFaces[aSubset]->HasSymbol (theUChar))
{
myActiveFTFace = myFallbackFaces[aSubset]->myFTFace;
}
}
if (FT_Load_Char (myActiveFTFace, theUChar, FT_Int32(myLoadFlags)) != 0
|| myActiveFTFace->glyph == NULL)
{
return false;
}
@@ -225,26 +289,67 @@ bool Font_FTFont::RenderGlyph (const Standard_Utf32Char theUChar)
{
myGlyphImg.Clear();
myUChar = 0;
myActiveFTFace = myFTFace;
if (theUChar != 0
&& myToUseUnicodeSubsetFallback
&& !HasSymbol (theUChar))
{
// try using fallback
const Font_UnicodeSubset aSubset = CharSubset (theUChar);
if (findAndInitFallback (aSubset)
&& myFallbackFaces[aSubset]->HasSymbol (theUChar))
{
myActiveFTFace = myFallbackFaces[aSubset]->myFTFace;
}
}
if (theUChar == 0
|| FT_Load_Char (myFTFace, theUChar, FT_Int32(myLoadFlags | FT_LOAD_RENDER)) != 0
|| myFTFace->glyph == NULL
|| myFTFace->glyph->format != FT_GLYPH_FORMAT_BITMAP)
|| FT_Load_Char (myActiveFTFace, theUChar, FT_Int32(myLoadFlags | FT_LOAD_RENDER)) != 0
|| myActiveFTFace->glyph == NULL
|| myActiveFTFace->glyph->format != FT_GLYPH_FORMAT_BITMAP)
{
return false;
}
FT_Bitmap aBitmap = myFTFace->glyph->bitmap;
if (aBitmap.pixel_mode != FT_PIXEL_MODE_GRAY
|| aBitmap.buffer == NULL || aBitmap.width == 0 || aBitmap.rows == 0)
FT_Bitmap aBitmap = myActiveFTFace->glyph->bitmap;
if (aBitmap.buffer == NULL || aBitmap.width == 0 || aBitmap.rows == 0)
{
return false;
}
if (!myGlyphImg.InitWrapper (Image_Format_Alpha, aBitmap.buffer,
aBitmap.width, aBitmap.rows, Abs (aBitmap.pitch)))
if (aBitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
{
if (!myGlyphImg.InitWrapper (Image_Format_Alpha, aBitmap.buffer,
aBitmap.width, aBitmap.rows, Abs (aBitmap.pitch)))
{
return false;
}
myGlyphImg.SetTopDown (aBitmap.pitch > 0);
}
else if (aBitmap.pixel_mode == FT_PIXEL_MODE_MONO)
{
if (!myGlyphImg.InitTrash (Image_Format_Gray, aBitmap.width, aBitmap.rows))
{
return false;
}
myGlyphImg.SetTopDown (aBitmap.pitch > 0);
const int aNumOfBytesInRow = aBitmap.width / 8 + (aBitmap.width % 8 ? 1 : 0);
for (int aRow = 0; aRow < (int )aBitmap.rows; ++aRow)
{
for (int aCol = 0; aCol < (int )aBitmap.width; ++aCol)
{
const int aBitOn = aBitmap.buffer[aNumOfBytesInRow * aRow + aCol / 8] & (0x80 >> (aCol % 8));
*myGlyphImg.ChangeRawValue (aRow, aCol) = aBitOn ? 255 : 0;
}
}
}
else
{
return false;
}
myGlyphImg.SetTopDown (aBitmap.pitch > 0);
myUChar = theUChar;
return true;
}
@@ -253,24 +358,58 @@ bool Font_FTFont::RenderGlyph (const Standard_Utf32Char theUChar)
// function : GlyphMaxSizeX
// purpose :
// =======================================================================
unsigned int Font_FTFont::GlyphMaxSizeX() const
unsigned int Font_FTFont::GlyphMaxSizeX (bool theToIncludeFallback) const
{
float aWidth = (FT_IS_SCALABLE(myFTFace) != 0)
? float(myFTFace->bbox.xMax - myFTFace->bbox.xMin) * (float(myFTFace->size->metrics.x_ppem) / float(myFTFace->units_per_EM))
: fromFTPoints<float> (myFTFace->size->metrics.max_advance);
return (unsigned int)(aWidth + 0.5f);
if (!theToIncludeFallback)
{
float aWidth = (FT_IS_SCALABLE(myFTFace) != 0)
? float(myFTFace->bbox.xMax - myFTFace->bbox.xMin) * (float(myFTFace->size->metrics.x_ppem) / float(myFTFace->units_per_EM))
: fromFTPoints<float> (myFTFace->size->metrics.max_advance);
return (unsigned int)(aWidth + 0.5f);
}
unsigned int aWidth = GlyphMaxSizeX (false);
if (theToIncludeFallback)
{
for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter)
{
if (!myFallbackFaces[aFontIter].IsNull()
&& myFallbackFaces[aFontIter]->IsValid())
{
aWidth = std::max (aWidth, myFallbackFaces[aFontIter]->GlyphMaxSizeX (false));
}
}
}
return aWidth;
}
// =======================================================================
// function : GlyphMaxSizeY
// purpose :
// =======================================================================
unsigned int Font_FTFont::GlyphMaxSizeY() const
unsigned int Font_FTFont::GlyphMaxSizeY (bool theToIncludeFallback) const
{
float aHeight = (FT_IS_SCALABLE(myFTFace) != 0)
? float(myFTFace->bbox.yMax - myFTFace->bbox.yMin) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM))
: fromFTPoints<float> (myFTFace->size->metrics.height);
return (unsigned int)(aHeight + 0.5f);
if (!theToIncludeFallback)
{
float aHeight = (FT_IS_SCALABLE(myFTFace) != 0)
? float(myFTFace->bbox.yMax - myFTFace->bbox.yMin) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM))
: fromFTPoints<float> (myFTFace->size->metrics.height);
return (unsigned int)(aHeight + 0.5f);
}
unsigned int aHeight = GlyphMaxSizeY (false);
if (theToIncludeFallback)
{
for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter)
{
if (!myFallbackFaces[aFontIter].IsNull()
&& myFallbackFaces[aFontIter]->IsValid())
{
aHeight = std::max (aHeight, myFallbackFaces[aFontIter]->GlyphMaxSizeY (false));
}
}
}
return aHeight;
}
// =======================================================================
@@ -322,18 +461,22 @@ float Font_FTFont::AdvanceY (Standard_Utf32Char theUChar,
return AdvanceY (theUCharNext);
}
// =======================================================================
// function : getKerning
// purpose :
// =======================================================================
bool Font_FTFont::getKerning (FT_Vector& theKern,
Standard_Utf32Char theUCharCurr,
Standard_Utf32Char theUCharNext) const
{
theKern.x = 0;
theKern.y = 0;
if (theUCharNext != 0 && FT_HAS_KERNING(myFTFace) != 0)
if (theUCharNext != 0 && FT_HAS_KERNING(myActiveFTFace) != 0)
{
const FT_UInt aCharCurr = FT_Get_Char_Index (myFTFace, theUCharCurr);
const FT_UInt aCharNext = FT_Get_Char_Index (myFTFace, theUCharNext);
const FT_UInt aCharCurr = FT_Get_Char_Index (myActiveFTFace, theUCharCurr);
const FT_UInt aCharNext = FT_Get_Char_Index (myActiveFTFace, theUCharNext);
if (aCharCurr == 0 || aCharNext == 0
|| FT_Get_Kerning (myFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, &theKern) != 0)
|| FT_Get_Kerning (myActiveFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, &theKern) != 0)
{
theKern.x = 0;
theKern.y = 0;
@@ -357,7 +500,7 @@ float Font_FTFont::AdvanceX (Standard_Utf32Char theUCharNext) const
FT_Vector aKern;
getKerning (aKern, myUChar, theUCharNext);
return myWidthScaling * fromFTPoints<float> (myFTFace->glyph->advance.x + aKern.x);
return myWidthScaling * fromFTPoints<float> (myActiveFTFace->glyph->advance.x + aKern.x);
}
// =======================================================================
@@ -373,29 +516,41 @@ float Font_FTFont::AdvanceY (Standard_Utf32Char theUCharNext) const
FT_Vector aKern;
getKerning (aKern, myUChar, theUCharNext);
return fromFTPoints<float> (myFTFace->glyph->advance.y + aKern.y);
return fromFTPoints<float> (myActiveFTFace->glyph->advance.y + aKern.y);
}
// =======================================================================
// function : GlyphsNumber
// purpose :
// =======================================================================
Standard_Integer Font_FTFont::GlyphsNumber() const
Standard_Integer Font_FTFont::GlyphsNumber (bool theToIncludeFallback) const
{
return myFTFace->num_glyphs;
Standard_Integer aNbGlyphs = myFTFace->num_glyphs;
if (theToIncludeFallback)
{
for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter)
{
if (!myFallbackFaces[aFontIter].IsNull()
&& myFallbackFaces[aFontIter]->IsValid())
{
aNbGlyphs += myFallbackFaces[aFontIter]->GlyphsNumber (false);
}
}
}
return aNbGlyphs;
}
// =======================================================================
// function : theRect
// function : GlyphRect
// purpose :
// =======================================================================
void Font_FTFont::GlyphRect (Font_Rect& theRect) const
{
const FT_Bitmap& aBitmap = myFTFace->glyph->bitmap;
theRect.Left = float(myFTFace->glyph->bitmap_left);
theRect.Top = float(myFTFace->glyph->bitmap_top);
theRect.Right = float(myFTFace->glyph->bitmap_left + (int )aBitmap.width);
theRect.Bottom = float(myFTFace->glyph->bitmap_top - (int )aBitmap.rows);
const FT_Bitmap& aBitmap = myActiveFTFace->glyph->bitmap;
theRect.Left = float(myActiveFTFace->glyph->bitmap_left);
theRect.Top = float(myActiveFTFace->glyph->bitmap_top);
theRect.Right = float(myActiveFTFace->glyph->bitmap_left + (int )aBitmap.width);
theRect.Bottom = float(myActiveFTFace->glyph->bitmap_top - (int )aBitmap.rows);
}
// =======================================================================

View File

@@ -19,6 +19,7 @@
#include <Font_FontAspect.hxx>
#include <Font_Rect.hxx>
#include <Font_StrictLevel.hxx>
#include <Font_UnicodeSubset.hxx>
#include <Graphic3d_HorizontalTextAlignment.hxx>
#include <Graphic3d_VerticalTextAlignment.hxx>
#include <Image_PixMap.hxx>
@@ -33,10 +34,10 @@ class Font_FTLibrary;
//! Font initialization parameters.
struct Font_FTFontParams
{
unsigned int PointSize; //!< face size in points (1/72 inch)
unsigned int Resolution; //!< resolution of the target device in dpi for FT_Set_Char_Size()
bool ToSynthesizeItalic; //!< generate italic style (e.g. for font family having no italic style); FALSE by default
bool IsSingleStrokeFont; //!< single-stroke (one-line) font, FALSE by default
unsigned int PointSize; //!< face size in points (1/72 inch)
unsigned int Resolution; //!< resolution of the target device in dpi for FT_Set_Char_Size()
bool ToSynthesizeItalic; //!< generate italic style (e.g. for font family having no italic style); FALSE by default
bool IsSingleStrokeFont; //!< single-stroke (one-line) font, FALSE by default
//! Empty constructor.
Font_FTFontParams() : PointSize (0), Resolution (72u), ToSynthesizeItalic (false), IsSingleStrokeFont (false) {}
@@ -68,6 +69,69 @@ public:
const Font_FTFontParams& theParams,
const Font_StrictLevel theStrictLevel = Font_StrictLevel_Any);
//! Return TRUE if specified character is within subset of modern CJK characters.
static bool IsCharFromCJK (Standard_Utf32Char theUChar)
{
return (theUChar >= 0x03400 && theUChar <= 0x04DFF)
|| (theUChar >= 0x04E00 && theUChar <= 0x09FFF)
|| (theUChar >= 0x0F900 && theUChar <= 0x0FAFF)
|| (theUChar >= 0x20000 && theUChar <= 0x2A6DF)
|| (theUChar >= 0x2F800 && theUChar <= 0x2FA1F)
// Hiragana and Katakana (Japanese) are NOT part of CJK, but CJK fonts usually include these symbols
|| IsCharFromHiragana (theUChar)
|| IsCharFromKatakana (theUChar);
}
//! Return TRUE if specified character is within subset of Hiragana (Japanese).
static bool IsCharFromHiragana (Standard_Utf32Char theUChar)
{
return (theUChar >= 0x03040 && theUChar <= 0x0309F);
}
//! Return TRUE if specified character is within subset of Katakana (Japanese).
static bool IsCharFromKatakana (Standard_Utf32Char theUChar)
{
return (theUChar >= 0x030A0 && theUChar <= 0x030FF);
}
//! Return TRUE if specified character is within subset of modern Korean characters (Hangul).
static bool IsCharFromKorean (Standard_Utf32Char theUChar)
{
return (theUChar >= 0x01100 && theUChar <= 0x011FF)
|| (theUChar >= 0x03130 && theUChar <= 0x0318F)
|| (theUChar >= 0x0AC00 && theUChar <= 0x0D7A3);
}
//! Return TRUE if specified character is within subset of Arabic characters.
static bool IsCharFromArabic (Standard_Utf32Char theUChar)
{
return (theUChar >= 0x00600 && theUChar <= 0x006FF);
}
//! Return TRUE if specified character should be displayed in Right-to-Left order.
static bool IsCharRightToLeft (Standard_Utf32Char theUChar)
{
return IsCharFromArabic(theUChar);
}
//! Determine Unicode subset for specified character
static Font_UnicodeSubset CharSubset (Standard_Utf32Char theUChar)
{
if (IsCharFromCJK (theUChar))
{
return Font_UnicodeSubset_CJK;
}
else if (IsCharFromKorean (theUChar))
{
return Font_UnicodeSubset_Korean;
}
else if (IsCharFromArabic (theUChar))
{
return Font_UnicodeSubset_Arabic;
}
return Font_UnicodeSubset_Western;
}
public:
//! Create uninitialized instance.
@@ -119,6 +183,13 @@ public:
const Font_FTFontParams& theParams,
Font_StrictLevel theStrictLevel = Font_StrictLevel_Any);
//! Return flag to use fallback fonts in case if used font does not include symbols from specific Unicode subset; TRUE by default.
//! @sa Font_FontMgr::ToUseUnicodeSubsetFallback()
Standard_Boolean ToUseUnicodeSubsetFallback() const { return myToUseUnicodeSubsetFallback; }
//! Set if fallback fonts should be used in case if used font does not include symbols from specific Unicode subset.
void SetUseUnicodeSubsetFallback (Standard_Boolean theToFallback) { myToUseUnicodeSubsetFallback = theToFallback; }
//! Return TRUE if this is single-stroke (one-line) font, FALSE by default.
//! Such fonts define single-line glyphs instead of closed contours, so that they are rendered incorrectly by normal software.
bool IsSingleStrokeFont() const { return myFontParams.IsSingleStrokeFont; }
@@ -136,10 +207,10 @@ public:
Standard_EXPORT bool RenderGlyph (const Standard_Utf32Char theChar);
//! @return maximal glyph width in pixels (rendered to bitmap).
Standard_EXPORT unsigned int GlyphMaxSizeX() const;
Standard_EXPORT unsigned int GlyphMaxSizeX (bool theToIncludeFallback = false) const;
//! @return maximal glyph height in pixels (rendered to bitmap).
Standard_EXPORT unsigned int GlyphMaxSizeY() const;
Standard_EXPORT unsigned int GlyphMaxSizeY (bool theToIncludeFallback = false) const;
//! @return vertical distance from the horizontal baseline to the highest character coordinate.
Standard_EXPORT float Ascender() const;
@@ -163,6 +234,9 @@ public:
myWidthScaling = theScaleFactor;
}
//! Return TRUE if font contains specified symbol (excluding fallback list).
Standard_EXPORT bool HasSymbol (Standard_Utf32Char theUChar) const;
//! Compute horizontal advance to the next character with kerning applied when applicable.
//! Assuming text rendered horizontally.
//! @param theUCharNext the next character to compute advance from current one
@@ -187,8 +261,9 @@ public:
Standard_EXPORT float AdvanceY (Standard_Utf32Char theUChar,
Standard_Utf32Char theUCharNext);
//! @return glyphs number in this font.
Standard_EXPORT Standard_Integer GlyphsNumber() const;
//! Return glyphs number in this font.
//! @param theToIncludeFallback if TRUE then the number will include fallback list
Standard_EXPORT Standard_Integer GlyphsNumber (bool theToIncludeFallback = false) const;
//! Retrieve glyph bitmap rectangle
Standard_EXPORT void GlyphRect (Font_Rect& theRect) const;
@@ -262,18 +337,25 @@ protected:
Standard_Utf32Char theUCharCurr,
Standard_Utf32Char theUCharNext) const;
//! Initialize fallback font.
Standard_EXPORT bool findAndInitFallback (Font_UnicodeSubset theSubset);
protected:
Handle(Font_FTLibrary) myFTLib; //!< handle to the FT library object
Handle(NCollection_Buffer) myBuffer; //!< memory buffer
Handle(Font_FTFont) myFallbackFaces[Font_UnicodeSubset_NB]; //!< fallback fonts
FT_Face myFTFace; //!< FT face object
FT_Face myActiveFTFace; //!< active FT face object (the main of fallback)
TCollection_AsciiString myFontPath; //!< font path
Font_FTFontParams myFontParams; //!< font initialization parameters
Font_FontAspect myFontAspect; //!< font initialization aspect
float myWidthScaling; //!< scale glyphs along X-axis
int32_t myLoadFlags; //!< default load flags
Image_PixMap myGlyphImg; //!< cached glyph plane
Standard_Utf32Char myUChar; //!< currently loaded unicode character
Standard_Boolean myToUseUnicodeSubsetFallback; //!< use default fallback fonts for extended Unicode sub-sets (Korean, CJK, etc.)
};

View File

@@ -88,6 +88,10 @@ IMPLEMENT_STANDARD_RTTIEXT(Font_FontMgr,Standard_Transient)
"/usr/X11/lib/X11/fs/config",
NULL
};
// Although fontconfig library can be built for various platforms,
// practically it is useful only on desktop Linux distributions, where it is always packaged.
#include <fontconfig/fontconfig.h>
#endif
#ifdef __APPLE__
@@ -193,6 +197,16 @@ Handle(Font_FontMgr) Font_FontMgr::GetInstance()
return _mgr;
}
// =======================================================================
// function : ToUseUnicodeSubsetFallback
// purpose :
// =======================================================================
Standard_Boolean& Font_FontMgr::ToUseUnicodeSubsetFallback()
{
static Standard_Boolean TheToUseUnicodeSubsetFallback = true;
return TheToUseUnicodeSubsetFallback;
}
// =======================================================================
// function : addFontAlias
// purpose :
@@ -239,6 +253,7 @@ Font_FontMgr::Font_FontMgr()
Handle(Font_FontAliasSequence) anIris = new Font_FontAliasSequence();
Handle(Font_FontAliasSequence) aCJK = new Font_FontAliasSequence();
Handle(Font_FontAliasSequence) aKorean = new Font_FontAliasSequence();
Handle(Font_FontAliasSequence) anArab = new Font_FontAliasSequence();
// best matches - pre-installed on Windows, some of them are pre-installed on macOS,
// and sometimes them can be found installed on other systems (by user)
@@ -289,6 +304,15 @@ Font_FontMgr::Font_FontMgr()
aKorean->Append (Font_FontAlias ("noto serif cjk jp")); // Linux
aKorean->Append (Font_FontAlias ("noto sans cjk jp")); // Linux
#if defined(_WIN32)
anArab->Append (Font_FontAlias ("times new roman"));
#elif defined(__APPLE__)
anArab->Append (Font_FontAlias ("decotype naskh"));
#elif defined(__ANDROID__)
anArab->Append (Font_FontAlias ("droid arabic naskh"));
anArab->Append (Font_FontAlias ("noto naskh arabic"));
#endif
addFontAlias ("mono", aMono);
addFontAlias ("courier", aMono); // Font_NOF_ASCII_MONO
addFontAlias ("monospace", aMono); // Font_NOF_MONOSPACE
@@ -308,6 +332,7 @@ Font_FontMgr::Font_FontMgr()
addFontAlias ("korean", aKorean); // Font_NOF_KOREAN
addFontAlias ("cjk", aCJK); // Font_NOF_CJK
addFontAlias ("nsimsun", aCJK);
addFontAlias ("arabic", anArab); // Font_NOF_ARABIC
addFontAlias (Font_NOF_SYMBOL_MONO, aWinDin);
addFontAlias (Font_NOF_ASCII_SCRIPT_SIMPLEX, aScript);
@@ -372,7 +397,7 @@ Standard_Boolean Font_FontMgr::RegisterFont (const Handle(Font_SystemFont)& theF
void Font_FontMgr::InitFontDataBase()
{
myFontMap.Clear();
Handle(Font_FTLibrary) aFtLibrary;
Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
#if defined(OCCT_UWP)
// system font files are not accessible
@@ -407,7 +432,6 @@ void Font_FontMgr::InitFontDataBase()
aSupportedExtensions.Add (TCollection_AsciiString (anExt));
}
aFtLibrary = new Font_FTLibrary();
static const DWORD aBufferSize = 256;
char aNameBuff[aBufferSize];
char aPathBuff[aBufferSize];
@@ -450,61 +474,86 @@ void Font_FontMgr::InitFontDataBase()
NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
#if !defined(__ANDROID__) && !defined(__APPLE__)
const OSD_Protection aProtectRead (OSD_R, OSD_R, OSD_R, OSD_R);
// read fonts directories from font service config file (obsolete)
for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
if (FcConfig* aFcCfg = FcInitLoadConfig())
{
const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
OSD_File aFile (aFileOfFontsPath);
if (!aFile.Exists())
if (FcStrList* aFcFontDir = FcConfigGetFontDirs (aFcCfg))
{
continue;
}
aFile.Open (OSD_ReadOnly, aProtectRead);
if (!aFile.IsOpen())
{
continue;
}
Standard_Integer aNByte = 256;
Standard_Integer aNbyteRead;
TCollection_AsciiString aStr; // read string with information
while (!aFile.IsAtEnd())
{
Standard_Integer aLocation = -1;
Standard_Integer aPathLocation = -1;
aFile.ReadLine (aStr, aNByte, aNbyteRead); // reading 1 line (256 bytes)
aLocation = aStr.Search ("catalogue=");
if (aLocation < 0)
for (;;)
{
aLocation = aStr.Search ("catalogue =");
}
aPathLocation = aStr.Search ("/");
if (aLocation > 0 && aPathLocation > 0)
{
aStr = aStr.Split (aPathLocation - 1);
TCollection_AsciiString aFontPath;
Standard_Integer aPathNumber = 1;
do
FcChar8* aFcFolder = FcStrListNext (aFcFontDir);
if (aFcFolder == NULL)
{
// Getting directory paths, which can be splitted by "," or ":"
aFontPath = aStr.Token (":,", aPathNumber);
aFontPath.RightAdjust();
if (!aFontPath.IsEmpty())
{
OSD_Path aPath(aFontPath);
addDirsRecursively (aPath, aMapOfFontsDirs);
}
aPathNumber++;
break;
}
while (!aFontPath.IsEmpty());
TCollection_AsciiString aPathStr ((const char* )aFcFolder);
OSD_Path aPath (aPathStr);
addDirsRecursively (aPath, aMapOfFontsDirs);
}
FcStrListDone (aFcFontDir);
}
FcConfigDestroy (aFcCfg);
}
const OSD_Protection aProtectRead (OSD_R, OSD_R, OSD_R, OSD_R);
if (aMapOfFontsDirs.IsEmpty())
{
Message::DefaultMessenger()->Send ("Font_FontMgr, fontconfig library returns an empty folder list", Message_Alarm);
// read fonts directories from font service config file (obsolete)
for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
{
const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
OSD_File aFile (aFileOfFontsPath);
if (!aFile.Exists())
{
continue;
}
aFile.Open (OSD_ReadOnly, aProtectRead);
if (!aFile.IsOpen())
{
continue;
}
Standard_Integer aNByte = 256;
Standard_Integer aNbyteRead;
TCollection_AsciiString aStr; // read string with information
while (!aFile.IsAtEnd())
{
Standard_Integer aLocation = -1;
Standard_Integer aPathLocation = -1;
aFile.ReadLine (aStr, aNByte, aNbyteRead); // reading 1 line (256 bytes)
aLocation = aStr.Search ("catalogue=");
if (aLocation < 0)
{
aLocation = aStr.Search ("catalogue =");
}
aPathLocation = aStr.Search ("/");
if (aLocation > 0 && aPathLocation > 0)
{
aStr = aStr.Split (aPathLocation - 1);
TCollection_AsciiString aFontPath;
Standard_Integer aPathNumber = 1;
do
{
// Getting directory paths, which can be splitted by "," or ":"
aFontPath = aStr.Token (":,", aPathNumber);
aFontPath.RightAdjust();
if (!aFontPath.IsEmpty())
{
OSD_Path aPath(aFontPath);
addDirsRecursively (aPath, aMapOfFontsDirs);
}
aPathNumber++;
}
while (!aFontPath.IsEmpty());
}
}
aFile.Close();
}
aFile.Close();
}
#endif
@@ -524,7 +573,6 @@ void Font_FontMgr::InitFontDataBase()
aSupportedExtensions.Add (TCollection_AsciiString (anExt));
}
aFtLibrary = new Font_FTLibrary();
for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
anIter.More(); anIter.Next())
{
@@ -686,6 +734,24 @@ Handle(Font_SystemFont) Font_FontMgr::GetFont (const TCollection_AsciiString& th
return myFontMap.Find (theFontName);
}
// =======================================================================
// function : FindFallbackFont
// purpose :
// =======================================================================
Handle(Font_SystemFont) Font_FontMgr::FindFallbackFont (Font_UnicodeSubset theSubset,
Font_FontAspect theFontAspect) const
{
Font_FontAspect aFontAspect = theFontAspect;
switch (theSubset)
{
case Font_UnicodeSubset_Western: return FindFont (Font_NOF_SANS_SERIF, Font_StrictLevel_Aliases, aFontAspect);
case Font_UnicodeSubset_Korean: return FindFont (Font_NOF_KOREAN, Font_StrictLevel_Aliases, aFontAspect);
case Font_UnicodeSubset_CJK: return FindFont (Font_NOF_CJK, Font_StrictLevel_Aliases, aFontAspect);
case Font_UnicodeSubset_Arabic: return FindFont (Font_NOF_ARABIC, Font_StrictLevel_Aliases, aFontAspect);
}
return Handle(Font_SystemFont)();
}
// =======================================================================
// function : FindFont
// purpose :
@@ -770,7 +836,8 @@ Handle(Font_SystemFont) Font_FontMgr::FindFont (const TCollection_AsciiString& t
}
}
if (aFont.IsNull())
if (aFont.IsNull()
&& theStrictLevel == Font_StrictLevel_Any)
{
// try finding ANY font in case if even default fallback alias myFallbackAlias cannot be found
aFont = myFontMap.Find (TCollection_AsciiString());

View File

@@ -22,6 +22,7 @@
#include <Font_FontAspect.hxx>
#include <Font_NListOfSystemFont.hxx>
#include <Font_StrictLevel.hxx>
#include <Font_UnicodeSubset.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_IndexedMap.hxx>
#include <NCollection_Shared.hxx>
@@ -55,6 +56,9 @@ public:
return "invalid";
}
//! Return flag to use fallback fonts in case if used font does not include symbols from specific Unicode subset; TRUE by default.
Standard_EXPORT static Standard_Boolean& ToUseUnicodeSubsetFallback();
public:
//! Return the list of available fonts.
@@ -106,7 +110,14 @@ public:
{
return FindFont (theFontName, Font_StrictLevel_Any, theFontAspect);
}
//! Tries to find fallback font for specified Unicode subset.
//! Returns NULL in case when fallback font is not found in the system.
//! @param theSubset [in] Unicode subset
//! @param theFontAspect [in] font aspect to find
Standard_EXPORT Handle(Font_SystemFont) FindFallbackFont (Font_UnicodeSubset theSubset,
Font_FontAspect theFontAspect) const;
//! Read font file and retrieve information from it.
Standard_EXPORT Handle(Font_SystemFont) CheckFont (const Standard_CString theFontPath) const;

View File

@@ -16,8 +16,9 @@
#define Font_NOF_MONOSPACE "monospace"
#define Font_NOF_SERIF "serif"
#define Font_NOF_SANS_SERIF "sans-serif"
#define Font_NOF_CJK "cjk"
#define Font_NOF_KOREAN "korean"
#define Font_NOF_CJK "cjk" // Font_UnicodeSubset_CJK
#define Font_NOF_KOREAN "korean" // Font_UnicodeSubset_Korean
#define Font_NOF_ARABIC "arabic" // Font_UnicodeSubset_Arabic
#define Font_NOF_ASCII_MONO "Courier"
#define Font_NOF_ASCII_SIMPLEX "Times-Roman"

View File

@@ -0,0 +1,28 @@
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _Font_UnicodeSubset_HeaderFile
#define _Font_UnicodeSubset_HeaderFile
//! Enumeration defining Unicode subsets.
enum Font_UnicodeSubset
{
Font_UnicodeSubset_Western, //!< western letters
Font_UnicodeSubset_Korean, //!< modern Korean letters
Font_UnicodeSubset_CJK, //!< Chinese characters (Chinese, Japanese, Korean and Vietnam)
Font_UnicodeSubset_Arabic, //!< Arabic characters
};
enum { Font_UnicodeSubset_NB = Font_UnicodeSubset_Arabic };
#endif // _Font_UnicodeSubset_HeaderFile

View File

@@ -15,8 +15,6 @@ Graphic3d_Aspects.cxx
Graphic3d_Aspects.hxx
Graphic3d_AspectFillArea3d.cxx
Graphic3d_AspectFillArea3d.hxx
Graphic3d_AspectFillCapping.cxx
Graphic3d_AspectFillCapping.hxx
Graphic3d_AspectLine3d.cxx
Graphic3d_AspectLine3d.hxx
Graphic3d_AspectMarker3d.cxx

View File

@@ -1,110 +0,0 @@
// Created on: 2017-04-14
// Created by: Anton POLETAEV
// Copyright (c) 2017 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Graphic3d_AspectFillCapping.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_AspectFillCapping, Standard_Transient)
// =======================================================================
// function : Graphic3d_AspectFillCapping
// purpose :
// =======================================================================
Graphic3d_AspectFillCapping::Graphic3d_AspectFillCapping()
: myFlags (Flags_None),
myHatchingState (0)
{
Graphic3d_MaterialAspect aMaterial;
aMaterial.SetColor (Quantity_NOC_BLACK);
aMaterial.SetReflectionModeOff (Graphic3d_TOR_AMBIENT);
aMaterial.SetReflectionModeOff (Graphic3d_TOR_DIFFUSE);
aMaterial.SetReflectionModeOff (Graphic3d_TOR_SPECULAR);
aMaterial.SetReflectionModeOff (Graphic3d_TOR_EMISSION);
aMaterial.SetMaterialType (Graphic3d_MATERIAL_ASPECT);
SetHatchStyle (Aspect_HS_HORIZONTAL);
SetHatchMaterial (aMaterial);
}
// =======================================================================
// function : SetHatchStyle
// purpose :
// =======================================================================
void Graphic3d_AspectFillCapping::SetHatchStyle (const Aspect_HatchStyle theStyle)
{
myStippleHatch = new Graphic3d_HatchStyle (theStyle);
myTextureHatch.Nullify();
myHatchingState++;
}
// =======================================================================
// function : SetHatchStyle
// purpose :
// =======================================================================
void Graphic3d_AspectFillCapping::SetHatchStyle (const Handle(Graphic3d_HatchStyle)& theStyle)
{
myStippleHatch = theStyle;
myTextureHatch.Nullify();
myHatchingState++;
}
// =======================================================================
// function : SetHatchStyle
// purpose :
// =======================================================================
void Graphic3d_AspectFillCapping::SetHatchStyle (const Handle(Graphic3d_TextureMap)& theTexture)
{
myStippleHatch.Nullify();
myTextureHatch = theTexture;
myHatchingState++;
}
// =======================================================================
// function : SetHatchMaterial
// purpose :
// =======================================================================
void Graphic3d_AspectFillCapping::SetHatchMaterial (const Graphic3d_MaterialAspect& theMaterial)
{
myHatchMaterial = theMaterial;
myHatchingState++;
}
// =======================================================================
// function : SetToDrawHatch
// purpose :
// =======================================================================
void Graphic3d_AspectFillCapping::SetToDrawHatch (const Standard_Boolean theToDraw)
{
setFlag (theToDraw, Flags_DrawHatching);
myHatchingState++;
}
// =======================================================================
// function : SetHatchZoomPeristent
// purpose :
// =======================================================================
void Graphic3d_AspectFillCapping::SetHatchZoomPeristent (const Standard_Boolean theToSet)
{
setFlag (theToSet, Flags_HatchZoomPersistent);
myHatchingState++;
}
// =======================================================================
// function : SetHatchRotationPeristent
// purpose :
// =======================================================================
void Graphic3d_AspectFillCapping::SetHatchRotationPeristent (const Standard_Boolean theToSet)
{
setFlag (theToSet, Flags_HatchRotationPersistent);
myHatchingState++;
}

View File

@@ -1,164 +0,0 @@
// Created on: 2017-04-14
// Created by: Anton POLETAEV
// Copyright (c) 2017 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _Graphic3d_AspectFillCapping_HeaderFile
#define _Graphic3d_AspectFillCapping_HeaderFile
#include <Aspect_HatchStyle.hxx>
#include <Graphic3d_Aspects.hxx>
#include <Graphic3d_HatchStyle.hxx>
#include <Graphic3d_MaterialAspect.hxx>
#include <Graphic3d_ShaderProgram.hxx>
#include <Graphic3d_TextureMap.hxx>
#include <Standard_Transient.hxx>
//! Defines graphical attributes for drawing section planes on solids resulted from clipping (cutting) planes.
class Graphic3d_AspectFillCapping : public Graphic3d_Aspects
{
public:
//! Default constructor.
Standard_EXPORT Graphic3d_AspectFillCapping();
public:
//! Sets material for filling section created by clipping.
void SetMaterial (const Graphic3d_MaterialAspect& theMaterial) { myMaterial = theMaterial; }
//! Returns material for filling section created by clipping.
const Graphic3d_MaterialAspect& Material() const { return myMaterial; }
//! Sets flag indicating whether object's material (instead of defined by this aspect) should be used for filling section.
void SetUseObjectMaterial (const Standard_Boolean theToUse) { setFlag (theToUse, Flags_UseObjectMaterial); }
//! Returns flag indicating whether object's material (instead of defined by this aspect) should be used for filling section.
Standard_Boolean ToUseObjectMaterial() const { return (myFlags & Flags_UseObjectMaterial) != 0; }
//! Sets texture for filling section created by clipping.
void SetTexture (const Handle(Graphic3d_TextureMap)& theTexture) { myTexture = theTexture; }
//! Returns texture for filling section created by clipping.
const Handle(Graphic3d_TextureMap)& Texture() const { return myTexture; }
//! Sets flag indicating whether object's texture (instead of defined by this aspect) should be used for filling section.
void SetUseObjectTexture (const Standard_Boolean theToUse) { setFlag (theToUse, Flags_UseObjectTexture); }
//! Returns flag indicating whether object's texture (instead of defined by this aspect) should be used for filling section.
Standard_Boolean ToUseObjectTexture() const { return (myFlags & Flags_UseObjectTexture) != 0; }
//! Sets OpenGL/GLSL shader program.
void SetShader (const Handle(Graphic3d_ShaderProgram)& theShader) { myShader = theShader; }
//! Returns OpenGL/GLSL shader program.
const Handle(Graphic3d_ShaderProgram)& Shader() const { return myShader; }
//! Sets flag indicating whether object's shader (instead of defined by this aspect) should be used for filling section.
void SetUseObjectShader (const Standard_Boolean theToUse) { setFlag (theToUse, Flags_UseObjectShader); }
//! Returns flag indicating whether object's shader (instead of defined by this aspect) should be used for filling section.
Standard_Boolean ToUseObjectShader() const { return (myFlags & Flags_UseObjectShader) != 0; }
public:
//! Sets style of hatch defined by predefined stipple mask.
Standard_EXPORT void SetHatchStyle (const Aspect_HatchStyle theStyle);
//! Sets style of hatch defined by custom stipple mask.
Standard_EXPORT void SetHatchStyle (const Handle(Graphic3d_HatchStyle)& theStyle);
//! Sets style of hatch defined by texture map (decal texture with alpha channel should be used).
Standard_EXPORT void SetHatchStyle (const Handle(Graphic3d_TextureMap)& theTexture);
//! Sets material style for hatch lines (texture).
Standard_EXPORT void SetHatchMaterial (const Graphic3d_MaterialAspect& theMaterial);
//! Returns material style for hatch lines (texture).
const Graphic3d_MaterialAspect& HatchMaterial() const { return myHatchMaterial; }
//! Sets boolean flag indicating whether the hatch layer should be drawn or not.
Standard_EXPORT void SetToDrawHatch (const Standard_Boolean theToDraw);
//! Returns boolean flag indicating whether the hatch layer should be drawn or not.
Standard_Boolean ToDrawHatch() const { return (myFlags & Flags_DrawHatching) != 0; }
//! Sets flag controlling behavior of hatch texture mapping on zooming.
//! @param theToSet [in] if passed TRUE the texture will keep constant screen-scale independent of zooming.
Standard_EXPORT void SetHatchZoomPeristent (const Standard_Boolean theToSet);
//! Returns value of flag controlling behavior of hatch texture mapping on zooming.
Standard_Boolean IsHatchZoomPersistent() { return (myFlags & Flags_HatchZoomPersistent) != 0; }
//! Sets flag controlling behavior of hatch texture mapping on camera rotation around heading vector.
Standard_EXPORT void SetHatchRotationPeristent (const Standard_Boolean theToSet);
//! Returns value of flag controlling behavior of hatch texture mapping on camera rotation around heading vector.
Standard_Boolean IsHatchRotationPersistent() { return (myFlags & Flags_HatchRotationPersistent) != 0; }
//! Returns true if hatch is defined by texture.
Standard_Boolean IsTextureHatch() const { return !myTextureHatch.IsNull(); }
//! Returns texture map defining the hatch.
const Handle(Graphic3d_TextureMap)& TextureHatch() const { return myTextureHatch; }
//! Returns true if hatch is defined by stipple mask.
Standard_Boolean IsStippleHatch() const { return !myStippleHatch.IsNull(); }
//! Returns the stipple mask.
const Handle(Graphic3d_HatchStyle)& StippleHatch() const { return myStippleHatch; }
//! Returns modification counter for hatching state.
Standard_Size HatchingState() const { return myHatchingState; }
private:
enum Flags
{
Flags_None = 0x00, //!< no flags
Flags_UseObjectMaterial = 0x01, //!< use object material
Flags_UseObjectTexture = 0x02, //!< use object texture
Flags_UseObjectShader = 0x04, //!< use object GLSL program
Flags_HatchZoomPersistent = 0x08, //!< zoom-persistent texturing
Flags_HatchRotationPersistent = 0x10, //!< rotation-persistent texturing
Flags_DrawHatching = 0x20, //!< draw hatching
Flags_UseObjectProperties = //!< use entire fill area aspect from object
Flags_UseObjectMaterial
| Flags_UseObjectTexture
| Flags_UseObjectShader
};
void setFlag (const Standard_Boolean theToUse, const unsigned int theFlag)
{
myFlags = theToUse ? myFlags | theFlag : myFlags & ~theFlag;
}
private:
Graphic3d_MaterialAspect myMaterial;
Handle(Graphic3d_TextureMap) myTexture;
Handle(Graphic3d_ShaderProgram) myShader;
Handle(Graphic3d_HatchStyle) myStippleHatch;
Handle(Graphic3d_TextureMap) myTextureHatch;
Graphic3d_MaterialAspect myHatchMaterial;
unsigned int myFlags;
Standard_Size myHatchingState;
public:
DEFINE_STANDARD_RTTIEXT(Graphic3d_AspectFillCapping, Graphic3d_Aspects)
};
DEFINE_STANDARD_HANDLE (Graphic3d_AspectFillCapping, Graphic3d_Aspects)
#endif // _Graphic3d_AspectFillCapping_HeaderFile

View File

@@ -24,6 +24,19 @@ IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ClipPlane,Standard_Transient)
namespace
{
static volatile Standard_Integer THE_CLIP_PLANE_COUNTER = 0;
static Handle(Graphic3d_AspectFillArea3d) defaultAspect()
{
const Graphic3d_MaterialAspect aMaterial (Graphic3d_NOM_DEFAULT);
Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
anAspect->SetDistinguishOff();
anAspect->SetFrontMaterial (aMaterial);
anAspect->SetHatchStyle (Aspect_HS_HORIZONTAL);
anAspect->SetInteriorStyle (Aspect_IS_SOLID);
anAspect->SetInteriorColor (aMaterial.Color());
anAspect->SetSuppressBackFaces (false);
return anAspect;
}
}
// =======================================================================
@@ -31,8 +44,19 @@ namespace
// purpose :
// =======================================================================
Graphic3d_ClipPlane::Graphic3d_ClipPlane()
: myAspect (defaultAspect()),
myPrevInChain(NULL),
myPlane (0.0, 0.0, 1.0, 0.0),
myEquation (0.0, 0.0, 1.0, 0.0),
myEquationRev(0.0, 0.0,-1.0, 0.0),
myChainLenFwd(1),
myFlags (Graphic3d_CappingFlags_None),
myEquationMod(0),
myAspectMod (0),
myIsOn (Standard_True),
myIsCapping (Standard_False)
{
init();
makeId();
}
// =======================================================================
@@ -40,8 +64,19 @@ Graphic3d_ClipPlane::Graphic3d_ClipPlane()
// purpose :
// =======================================================================
Graphic3d_ClipPlane::Graphic3d_ClipPlane (const Graphic3d_Vec4d& theEquation)
: myAspect (defaultAspect()),
myPrevInChain(NULL),
myPlane (theEquation.x(), theEquation.y(), theEquation.z(), theEquation.w()),
myEquation (theEquation),
myEquationRev(0.0, 0.0,-1.0, 0.0),
myChainLenFwd(1),
myFlags (Graphic3d_CappingFlags_None),
myEquationMod(0),
myAspectMod (0),
myIsOn (Standard_True),
myIsCapping (Standard_False)
{
init (gp_Pln (theEquation.x(), theEquation.y(), theEquation.z(), theEquation.a()));
makeId();
updateInversedPlane();
}
@@ -49,27 +84,42 @@ Graphic3d_ClipPlane::Graphic3d_ClipPlane (const Graphic3d_Vec4d& theEquation)
// function : Graphic3d_ClipPlane
// purpose :
// =======================================================================
Graphic3d_ClipPlane::Graphic3d_ClipPlane (const Graphic3d_ClipPlane& theOther)
: Standard_Transient (theOther)
Graphic3d_ClipPlane::Graphic3d_ClipPlane(const Graphic3d_ClipPlane& theOther)
: Standard_Transient(theOther),
myAspect (defaultAspect()),
myPrevInChain(NULL),
myPlane (theOther.myPlane),
myEquation (theOther.myEquation),
myEquationRev(theOther.myEquationRev),
myChainLenFwd(1),
myFlags (theOther.myFlags),
myEquationMod(0),
myAspectMod (0),
myIsOn (theOther.myIsOn),
myIsCapping (theOther.myIsCapping)
{
*mySectionStyle = *theOther.CappingSectionStyle();
init (theOther.myPlane,
theOther.myEquationRev,
theOther.myIsOn,
theOther.myIsCapping,
theOther.ToOverrideCappingAspect(),
theOther.CappingSectionStyle());
updateInversedPlane();
makeId();
*myAspect = *theOther.CappingAspect();
}
// =======================================================================
// function : Graphic3d_ClipPlane
// purpose :
// =======================================================================
Graphic3d_ClipPlane::Graphic3d_ClipPlane (const gp_Pln& thePlane)
Graphic3d_ClipPlane::Graphic3d_ClipPlane(const gp_Pln& thePlane)
: myAspect (defaultAspect()),
myPrevInChain(NULL),
myPlane (thePlane),
myChainLenFwd(1),
myFlags (Graphic3d_CappingFlags_None),
myEquationMod(0),
myAspectMod (0),
myIsOn (Standard_True),
myIsCapping (Standard_False)
{
init (thePlane);
thePlane.Coefficients (myEquation[0], myEquation[1], myEquation[2], myEquation[3]);
updateInversedPlane();
makeId();
}
// =======================================================================
@@ -81,7 +131,7 @@ void Graphic3d_ClipPlane::SetEquation (const Graphic3d_Vec4d& theEquation)
myPlane = gp_Pln (theEquation.x(), theEquation.y(), theEquation.z(), theEquation.w());
myEquation = theEquation;
updateInversedPlane();
myOrientationDirty = Standard_True;
myEquationMod++;
}
// =======================================================================
@@ -93,7 +143,7 @@ void Graphic3d_ClipPlane::SetEquation (const gp_Pln& thePlane)
myPlane = thePlane;
thePlane.Coefficients (myEquation[0], myEquation[1], myEquation[2], myEquation[3]);
updateInversedPlane();
myOrientationDirty = Standard_True;
myEquationMod++;
}
// =======================================================================
@@ -128,106 +178,119 @@ Handle(Graphic3d_ClipPlane) Graphic3d_ClipPlane::Clone() const
}
// =======================================================================
// function : SetCappingSectionStyle
// function : SetCappingMaterial
// purpose :
// =======================================================================
void Graphic3d_ClipPlane::SetCappingSectionStyle (const Handle(Graphic3d_AspectFillCapping)& theStyle)
void Graphic3d_ClipPlane::SetCappingMaterial (const Graphic3d_MaterialAspect& theMat)
{
mySectionStyle = theStyle;
myAspect->SetFrontMaterial (theMat);
myAspect->SetInteriorColor (theMat.Color());
++myAspectMod;
}
// =======================================================================
// function : OrientationMatrix
// function : SetCappingTexture
// purpose :
// =======================================================================
const Graphic3d_Mat4& Graphic3d_ClipPlane::OrientationMatrix() const
void Graphic3d_ClipPlane::SetCappingTexture (const Handle(Graphic3d_TextureMap)& theTexture)
{
if (myOrientationDirty)
if (!theTexture.IsNull())
{
const Standard_ShortReal aDirection[] = {
static_cast<Standard_ShortReal> (myEquation[0]),
static_cast<Standard_ShortReal> (myEquation[1]),
static_cast<Standard_ShortReal> (myEquation[2])
};
const Standard_ShortReal aTranslate[] = {
static_cast<Standard_ShortReal> (myEquation[0] * -myEquation[3]),
static_cast<Standard_ShortReal> (myEquation[1] * -myEquation[3]),
static_cast<Standard_ShortReal> (myEquation[2] * -myEquation[3])
};
Standard_ShortReal aSide1[] = { 0.0f, 0.0f, 0.0f };
Standard_ShortReal aSide2[] = { 0.0f, 0.0f, 0.0f };
const Standard_ShortReal aMagintude = static_cast<Standard_ShortReal> (Sqrt (myEquation[0] * myEquation[0] + myEquation[2] * myEquation[2]));
if (aMagintude < ShortRealSmall())
myAspect->SetTextureMapOn();
Handle(Graphic3d_TextureSet) aTextureSet = myAspect->TextureSet();
if (aTextureSet.IsNull() || aTextureSet->Size() != 1)
{
aSide1[0] = 1.0f;
aTextureSet = new Graphic3d_TextureSet (theTexture);
}
else
{
aSide1[0] = aDirection[2] / aMagintude;
aSide1[2] = -aDirection[0] / aMagintude;
aTextureSet->SetFirst (theTexture);
}
aSide2[0] = (-aSide1[1] * aDirection[2]) - (-aSide1[2] * aDirection[1]);
aSide2[1] = (-aSide1[2] * aDirection[0]) - (-aSide1[0] * aDirection[2]);
aSide2[2] = (-aSide1[0] * aDirection[1]) - (-aSide1[1] * aDirection[0]);
myOrientationMat.SetValue (0, 0, aSide1[0]);
myOrientationMat.SetValue (1, 0, aSide1[1]);
myOrientationMat.SetValue (2, 0, aSide1[2]);
myOrientationMat.SetValue (3, 0, 0.0F);
myOrientationMat.SetValue (0, 1, aDirection[0]);
myOrientationMat.SetValue (1, 1, aDirection[1]);
myOrientationMat.SetValue (2, 1, aDirection[2]);
myOrientationMat.SetValue (3, 1, 0.0F);
myOrientationMat.SetValue (0, 2, aSide2[0]);
myOrientationMat.SetValue (1, 2, aSide2[1]);
myOrientationMat.SetValue (2, 2, aSide2[2]);
myOrientationMat.SetValue (3, 2, 0.0F);
myOrientationMat.SetValue (0, 3, aTranslate[0]);
myOrientationMat.SetValue (1, 3, aTranslate[1]);
myOrientationMat.SetValue (2, 3, aTranslate[2]);
myOrientationMat.SetValue (3, 3, 1.0F);
myOrientationDirty = Standard_False;
myAspect->SetTextureSet (aTextureSet);
}
return myOrientationMat;
else
{
myAspect->SetTextureMapOff();
myAspect->SetTextureSet (Handle(Graphic3d_TextureSet)());
}
++myAspectMod;
}
// =======================================================================
// function : init
// function : SetCappingHatch
// purpose :
// =======================================================================
void Graphic3d_ClipPlane::init (const gp_Pln& thePlane,
const Graphic3d_Vec4d& theEquationRev,
const Standard_Boolean theIsOn,
const Standard_Boolean theIsCapping,
const Standard_Boolean theOverrideStyle,
const Handle(Graphic3d_AspectFillCapping)& theStyle)
void Graphic3d_ClipPlane::SetCappingHatch (const Aspect_HatchStyle theStyle)
{
if (myEntityUID.IsEmpty())
{
myEntityUID = TCollection_AsciiString ("Graphic3d_ClipPlane_") //DynamicType()->Name()
+ TCollection_AsciiString (Standard_Atomic_Increment (&THE_CLIP_PLANE_COUNTER));
}
myAspect->SetHatchStyle (theStyle);
++myAspectMod;
}
myPrevInChain = NULL;
myEquationRev = theEquationRev;
myChainLenFwd = 1;
myPlane = thePlane;
myPlane.Coefficients (myEquation[0], myEquation[1], myEquation[2], myEquation[3]);
myIsOn = theIsOn;
myIsCapping = theIsCapping;
myOverrideObjectStyle = theOverrideStyle;
mySectionStyle = theStyle.IsNull() ? new Graphic3d_AspectFillCapping() : theStyle;
myOrientationDirty = Standard_True;
// =======================================================================
// function : SetCappingCustomHatch
// purpose :
// =======================================================================
void Graphic3d_ClipPlane::SetCappingCustomHatch (const Handle(Graphic3d_HatchStyle)& theStyle)
{
myAspect->SetHatchStyle (theStyle);
++myAspectMod;
}
// =======================================================================
// function : SetCappingHatchOn
// purpose :
// =======================================================================
void Graphic3d_ClipPlane::SetCappingHatchOn()
{
myAspect->SetInteriorStyle (Aspect_IS_HATCH);
++myAspectMod;
}
// =======================================================================
// function : SetCappingHatchOff
// purpose :
// =======================================================================
void Graphic3d_ClipPlane::SetCappingHatchOff()
{
myAspect->SetInteriorStyle (Aspect_IS_SOLID);
++myAspectMod;
}
// =======================================================================
// function : SetCappingAspect
// purpose :
// =======================================================================
void Graphic3d_ClipPlane::SetCappingAspect (const Handle(Graphic3d_AspectFillArea3d)& theAspect)
{
myAspect = theAspect;
++myAspectMod;
}
// =======================================================================
// function : setCappingFlag
// purpose :
// =======================================================================
void Graphic3d_ClipPlane::setCappingFlag (bool theToUse, int theFlag)
{
if (theToUse)
{
myFlags |= theFlag;
}
else
{
myFlags &= ~(theFlag);
}
++myAspectMod;
}
// =======================================================================
// function : makeId
// purpose :
// =======================================================================
void Graphic3d_ClipPlane::makeId()
{
myId = TCollection_AsciiString ("Graphic3d_ClipPlane_") //DynamicType()->Name()
+ TCollection_AsciiString (Standard_Atomic_Increment (&THE_CLIP_PLANE_COUNTER));
}
// =======================================================================
@@ -249,7 +312,7 @@ void Graphic3d_ClipPlane::updateChainLen()
// =======================================================================
void Graphic3d_ClipPlane::SetChainNextPlane (const Handle(Graphic3d_ClipPlane)& thePlane)
{
myOrientationDirty = Standard_True;
++myEquationMod;
if (!myNextInChain.IsNull())
{
myNextInChain->myPrevInChain = NULL;

View File

@@ -19,12 +19,9 @@
#include <Aspect_HatchStyle.hxx>
#include <gp_Pln.hxx>
#include <Graphic3d_AspectFillArea3d.hxx>
#include <Graphic3d_AspectFillCapping.hxx>
#include <Graphic3d_BndBox3d.hxx>
#include <Graphic3d_CappingFlags.hxx>
#include <Graphic3d_Mat4.hxx>
#include <Graphic3d_TextureMap.hxx>
#include <NCollection_Handle.hxx>
#include <NCollection_Vec4.hxx>
#include <Standard_Macro.hxx>
#include <Standard_TypeDef.hxx>
@@ -169,6 +166,44 @@ public:
public: // @name user-defined graphical attributes
//! Set material for rendering capping surface.
//! @param theMat [in] the material.
Standard_EXPORT void SetCappingMaterial (const Graphic3d_MaterialAspect& theMat);
//! @return capping material.
const Graphic3d_MaterialAspect& CappingMaterial() const { return myAspect->FrontMaterial(); }
//! Set texture to be applied on capping surface.
//! @param theTexture [in] the texture.
Standard_EXPORT void SetCappingTexture (const Handle(Graphic3d_TextureMap)& theTexture);
//! @return capping texture map.
Handle(Graphic3d_TextureMap) CappingTexture() const { return !myAspect->TextureSet().IsNull() && !myAspect->TextureSet()->IsEmpty()
? myAspect->TextureSet()->First()
: Handle(Graphic3d_TextureMap)(); }
//! Set hatch style (stipple) and turn hatching on.
//! @param theStyle [in] the hatch style.
Standard_EXPORT void SetCappingHatch (const Aspect_HatchStyle theStyle);
//! @return hatching style.
Aspect_HatchStyle CappingHatch() const { return (Aspect_HatchStyle)myAspect->HatchStyle()->HatchType(); }
//! Set custom hatch style (stipple) and turn hatching on.
//! @param theStyle [in] the hatch pattern.
Standard_EXPORT void SetCappingCustomHatch (const Handle(Graphic3d_HatchStyle)& theStyle);
//! @return hatching style.
const Handle(Graphic3d_HatchStyle)& CappingCustomHatch() const { return myAspect->HatchStyle(); }
//! Turn on hatching.
Standard_EXPORT void SetCappingHatchOn();
//! Turn off hatching.
Standard_EXPORT void SetCappingHatchOff();
//! @return True if hatching mask is turned on.
Standard_Boolean IsHatchOn() const { return myAspect->InteriorStyle() == Aspect_IS_HATCH; }
//! This ID is used for managing associated resources in graphical driver.
//! The clip plane can be assigned within a range of IO which can be
@@ -179,18 +214,41 @@ public: // @name user-defined graphical attributes
//! @return clip plane resource identifier string.
const TCollection_AsciiString& GetId() const
{
return myEntityUID;
return myId;
}
public:
//! Returns style used for drawing capping section.
//! Return capping aspect.
//! @return capping surface rendering aspect.
const Handle(Graphic3d_AspectFillCapping)& CappingSectionStyle() const { return mySectionStyle; }
const Handle(Graphic3d_AspectFillArea3d)& CappingAspect() const { return myAspect; }
//! Sets clipping section filling aspect.
Standard_EXPORT void SetCappingSectionStyle (const Handle(Graphic3d_AspectFillCapping)& theStyle);
//! Assign capping aspect.
Standard_EXPORT void SetCappingAspect (const Handle(Graphic3d_AspectFillArea3d)& theAspect);
//! Flag indicating whether material for capping plane should be taken from object.
//! Default value: FALSE (use dedicated capping plane material).
bool ToUseObjectMaterial() const { return (myFlags & Graphic3d_CappingFlags_ObjectMaterial) != 0; }
//! Set flag for controlling the source of capping plane material.
void SetUseObjectMaterial (bool theToUse) { setCappingFlag (theToUse, Graphic3d_CappingFlags_ObjectMaterial); }
//! Flag indicating whether texture for capping plane should be taken from object.
//! Default value: FALSE.
bool ToUseObjectTexture() const { return (myFlags & Graphic3d_CappingFlags_ObjectTexture) != 0; }
//! Set flag for controlling the source of capping plane texture.
void SetUseObjectTexture (bool theToUse) { setCappingFlag (theToUse, Graphic3d_CappingFlags_ObjectTexture); }
//! Flag indicating whether shader program for capping plane should be taken from object.
//! Default value: FALSE.
bool ToUseObjectShader() const { return (myFlags & Graphic3d_CappingFlags_ObjectShader) != 0; }
//! Set flag for controlling the source of capping plane shader program.
void SetUseObjectShader(bool theToUse) { setCappingFlag (theToUse, Graphic3d_CappingFlags_ObjectShader); }
//! Return true if some fill area aspect properties should be taken from object.
bool ToUseObjectProperties() const { return myFlags != Graphic3d_CappingFlags_None; }
public:
@@ -294,25 +352,14 @@ public: // @name modification counters
{
return myAspectMod;
}
//! Flag indicating whether section style of the plane should overrides similar property of object presentation.
//! Default value: FALSE (use dedicated presentation aspect style).
bool ToOverrideCappingAspect() const { return myOverrideObjectStyle; }
//! Sets flag for controlling the preference of using section style between clip plane and object.
void SetToOverrideCappingAspect (const bool theToOverride) { myOverrideObjectStyle = theToOverride; }
//! Returns plane's orientation matrix.
Standard_EXPORT const Graphic3d_Mat4& OrientationMatrix() const;
private:
//! Initializes plane and makes unique identifier (UID) to differentiate clipping plane entities.
void init (const gp_Pln& thePlane = gp_Pln(),
const Graphic3d_Vec4d& theEquationRev = Graphic3d_Vec4d(0.0, 0.0,-1.0, 0.0),
const Standard_Boolean theIsOn = Standard_True,
const Standard_Boolean theIsCapping = Standard_False,
const Standard_Boolean theOverrideStyle = Standard_False,
const Handle(Graphic3d_AspectFillCapping)& theStyle = Handle(Graphic3d_AspectFillCapping)());
//! Generate unique object id for OpenGL graphic resource manager.
void makeId();
//! Set capping flag.
Standard_EXPORT void setCappingFlag (bool theToUse, int theFlag);
//! Update chain length in backward direction.
void updateChainLen();
@@ -327,10 +374,10 @@ private:
private:
Handle(Graphic3d_AspectFillCapping) mySectionStyle; //!< Style set for drawing capped solid section.
Handle(Graphic3d_AspectFillArea3d) myAspect; //!< fill area aspect
Handle(Graphic3d_ClipPlane) myNextInChain; //!< next plane in a chain of planes defining logical AND operation
Graphic3d_ClipPlane* myPrevInChain; //!< previous plane in a chain of planes defining logical AND operation
TCollection_AsciiString myEntityUID; //!< Unique identifier for the plane
TCollection_AsciiString myId; //!< resource id
gp_Pln myPlane; //!< plane definition
Graphic3d_Vec4d myEquation; //!< plane equation vector
Graphic3d_Vec4d myEquationRev; //!< reversed plane equation
@@ -340,9 +387,6 @@ private:
unsigned int myAspectMod; //!< modification counter of aspect
Standard_Boolean myIsOn; //!< state of the clipping plane
Standard_Boolean myIsCapping; //!< state of graphic driver capping
Standard_Boolean myOverrideObjectStyle; //!< Flag forcing to use plane's section style rather than section style defined for object
mutable Standard_Boolean myOrientationDirty; //!< Boolean flag indicating whether orientation matrix is dirty or not.
mutable Graphic3d_Mat4 myOrientationMat; //!< Plane orientation matrix (for visualization purposes).
};

View File

@@ -37,7 +37,6 @@
class Graphic3d_Structure;
class Graphic3d_ArrayOfPrimitives;
class Graphic3d_AspectFillCapping;
//! This class allows the definition of groups
//! of primitives inside of graphic objects (presentations).
@@ -105,9 +104,6 @@ public:
//! Modifies the current context of the group to give another aspect for all the primitives created after this call in the group.
virtual void SetPrimitivesAspect (const Handle(Graphic3d_Aspects)& theAspect) = 0;
//! Returns style of filling clipping sections on closed shell primitives.
virtual Handle(Graphic3d_AspectFillCapping) FillCappingAspect() const = 0;
//! Update presentation aspects after their modification.
virtual void SynchronizeAspects() = 0;

View File

@@ -21,15 +21,13 @@
//! - ASPECT_LINE: aspect for line primitives;
//! - ASPECT_TEXT: aspect for text primitives;
//! - ASPECT_MARKER: aspect for marker primitives;
//! - ASPECT_FILL_AREA: aspect for face primitives;
//! - Graphic3d_ASPECT_FILL_CAPPING: aspect for filling clipping sections.
//! - ASPECT_FILL_AREA: aspect for face primitives.
enum Graphic3d_GroupAspect
{
Graphic3d_ASPECT_LINE,
Graphic3d_ASPECT_TEXT,
Graphic3d_ASPECT_MARKER,
Graphic3d_ASPECT_FILL_AREA,
Graphic3d_ASPECT_FILL_CAPPING
Graphic3d_ASPECT_FILL_AREA
};
#endif // _Graphic3d_GroupAspect_HeaderFile

View File

@@ -16,6 +16,8 @@
#ifndef _IMeshTools_ModelAlgo_HeaderFile
#define _IMeshTools_ModelAlgo_HeaderFile
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <Standard_Transient.hxx>
#include <Standard_Type.hxx>
@@ -32,10 +34,22 @@ public:
{
}
//! Performs processing of edges of the given model.
Standard_EXPORT virtual Standard_Boolean Perform (
//! Exceptions protected processing of the given model.
Standard_Boolean Perform (
const Handle (IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) = 0;
const IMeshTools_Parameters& theParameters)
{
try
{
OCC_CATCH_SIGNALS
return performInternal (theModel, theParameters);
}
catch (Standard_Failure const&)
{
return Standard_False;
}
}
DEFINE_STANDARD_RTTI_INLINE(IMeshTools_ModelAlgo, Standard_Transient)
@@ -45,6 +59,11 @@ protected:
Standard_EXPORT IMeshTools_ModelAlgo()
{
}
//! Performs processing of the given model.
Standard_EXPORT virtual Standard_Boolean performInternal (
const Handle (IMeshData_Model)& theModel,
const IMeshTools_Parameters& theParameters) = 0;
};
#endif

View File

@@ -17,6 +17,8 @@
#define _IMeshTools_ModelBuilder_HeaderFile
#include <Message_Algorithm.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <Standard_Type.hxx>
#include <TopoDS_Shape.hxx>
@@ -38,11 +40,26 @@ public:
{
}
//! Creates discrete model for the given shape.
//! Exceptions protected method to create discrete model for the given shape.
//! Returns nullptr in case of failure.
Standard_EXPORT virtual Handle (IMeshData_Model) Perform (
Handle (IMeshData_Model) Perform (
const TopoDS_Shape& theShape,
const IMeshTools_Parameters& theParameters) = 0;
const IMeshTools_Parameters& theParameters)
{
ClearStatus ();
try
{
OCC_CATCH_SIGNALS
return performInternal (theShape, theParameters);
}
catch (Standard_Failure const&)
{
SetStatus (Message_Fail2);
return NULL;
}
}
DEFINE_STANDARD_RTTI_INLINE(IMeshTools_ModelBuilder, Message_Algorithm)
@@ -52,6 +69,12 @@ protected:
Standard_EXPORT IMeshTools_ModelBuilder()
{
}
//! Creates discrete model for the given shape.
//! Returns nullptr in case of failure.
Standard_EXPORT virtual Handle (IMeshData_Model) performInternal (
const TopoDS_Shape& theShape,
const IMeshTools_Parameters& theParameters) = 0;
};
#endif

View File

@@ -21,16 +21,11 @@
#include <OpenGl_PrimitiveArray.hxx>
#include <OpenGl_CappingPlaneResource.hxx>
#include <OpenGl_Vec.hxx>
#include <OpenGl_View.hxx>
#include <OpenGl_Structure.hxx>
#include <OpenGl_ShaderManager.hxx>
namespace
{
static const OpenGl_CappingPlaneResource THE_DEFAULT_ASPECT = OpenGl_CappingPlaneResource (new Graphic3d_AspectFillCapping);
static const TCollection_AsciiString THE_QUAD_PARRAY = "OpenGl_CappingAlgo_Quad";
static const TCollection_AsciiString THE_PLANE_STYLE = "OpenGl_CappingAlgo_CappingStyle_";
//! Auxiliary sentry object managing stencil test.
struct StencilTestSentry
{
@@ -63,113 +58,21 @@ namespace
GLint myDepthFuncPrev;
};
class OpenGl_SharedElement : public OpenGl_Resource
{
public:
OpenGl_SharedElement (OpenGl_Element* theGlElement) : myGlElement (theGlElement) {}
virtual void Release (OpenGl_Context* theGlCtx) Standard_OVERRIDE
{
OpenGl_Element::Destroy (theGlCtx, myGlElement);
}
OpenGl_Element* GlElement() const { return myGlElement; }
//! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
Standard_Size EstimatedDataSize() const Standard_OVERRIDE { return 0; }
private:
OpenGl_Element* myGlElement;
public:
DEFINE_STANDARD_RTTI_INLINE (OpenGl_SharedElement, OpenGl_Resource)
};
//! Iitializes and returns vertex buffer for plane section
OpenGl_PrimitiveArray* initQuad (const Handle(OpenGl_Context)& theContext)
{
Handle(OpenGl_SharedElement) aSharedResource;
if (!theContext->GetResource (THE_QUAD_PARRAY, aSharedResource))
{
aSharedResource = new OpenGl_SharedElement (OpenGl_CappingPlaneResource::BuildInfinitPlaneVertices());
theContext->ShareResource (THE_QUAD_PARRAY, aSharedResource);
}
return dynamic_cast<OpenGl_PrimitiveArray*> (aSharedResource->GlElement());
}
//! Render section plane using the given aspects.
void renderSection (const Handle(OpenGl_Workspace)& theWorkspace,
const OpenGl_PrimitiveArray* theQuad,
const OpenGl_Aspects* theCappingAspect,
const OpenGl_Aspects* theHatchAspect,
const OpenGl_Mat4& theCappingMatrix,
const Standard_ShortReal theHatchScale,
const Standard_ShortReal theHatchRotate)
//! Render infinite capping plane.
//! @param theWorkspace [in] the GL workspace, context state.
//! @param thePlane [in] the graphical plane, for which the capping surface is rendered.
static void renderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
const Handle(OpenGl_CappingPlaneResource)& thePlane)
{
const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
const bool wasCullAllowed = theWorkspace->SetAllowFaceCulling (true);
const Standard_Boolean isTextureHatch =
theHatchAspect != NULL
&& theHatchAspect->Aspect()->TextureMapState();
// set identity model matrix
aContext->ModelWorldState.Push();
aContext->ModelWorldState.SetCurrent (theCappingMatrix);
aContext->ModelWorldState.SetCurrent (OpenGl_Mat4::Map (*thePlane->Orientation()->mat));
aContext->ApplyModelViewMatrix();
theWorkspace->SetAspects (theCappingAspect);
theWorkspace->ApplyAspects();
theQuad->Render (theWorkspace);
if (theHatchAspect != NULL)
{
Graphic3d_Vec2 aPrevScale;
Standard_ShortReal aPrevRotate = 0.0;
if (isTextureHatch)
{
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if ((theHatchScale != 1.0 || theHatchRotate != 0.0) && !theHatchAspect->TextureSet(aContext)->IsEmpty())
{
Handle(OpenGl_Texture) aTexture = theHatchAspect->TextureSet(aContext)->First();
const Handle(Graphic3d_TextureParams)& aTexParams = aTexture->Sampler()->Parameters();
aPrevScale = aTexParams->Scale();
aPrevRotate = aTexParams->Rotation();
const Standard_Boolean isMirror = aPrevScale.x() * aPrevScale.y() < 0.0;
aTexParams->SetScale (aPrevScale * theHatchScale);
aTexParams->SetRotation (isMirror ? aPrevRotate - theHatchRotate : aPrevRotate + theHatchRotate);
}
}
theWorkspace->SetAspects (theHatchAspect);
theWorkspace->ApplyAspects();
glDepthFunc (GL_LEQUAL);
theQuad->Render (theWorkspace);
glDepthFunc (GL_LESS);
if (isTextureHatch)
{
glDisable (GL_BLEND);
if (theHatchScale != 1.0 || theHatchRotate != 0.0)
{
Handle(OpenGl_Texture) aTexture = theHatchAspect->TextureSet(aContext)->First();
const Handle(Graphic3d_TextureParams)& aTexParams = aTexture->Sampler()->Parameters();
aTexParams->SetScale (aPrevScale);
aTexParams->SetRotation (aPrevRotate);
}
}
}
thePlane->Primitives().Render (theWorkspace);
aContext->ModelWorldState.Pop();
aContext->ApplyModelViewMatrix();
@@ -183,23 +86,13 @@ namespace
const OpenGl_Structure& theStructure,
const Handle(Graphic3d_ClipPlane)& theClipChain,
const Standard_Integer theSubPlaneIndex,
const Handle(OpenGl_CappingPlaneResource)& thePlane,
const OpenGl_PrimitiveArray* theQuad)
const Handle(OpenGl_CappingPlaneResource)& thePlane)
{
const Standard_Integer aPrevFilter = theWorkspace->RenderFilter();
const Standard_Integer anAnyFilter = aPrevFilter & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly);
const Handle(Graphic3d_ClipPlane)& aPlane = theClipChain;
const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
const Handle(Graphic3d_Camera) aCamera = theWorkspace->View() != NULL
? theWorkspace->View()->Camera()
: Handle(Graphic3d_Camera)();
const OpenGl_Mat4& aPlaneMat = OpenGl_Mat4::Map (aPlane->OrientationMatrix());
Standard_ShortReal aRotateAngle = 0.0;
Standard_ShortReal aViewScale = ShortRealLast();
OpenGl_Mat4 aRotateZoomMat;
const Handle(Graphic3d_ClipPlane)& aRenderPlane = thePlane->Plane();
for (OpenGl_Structure::GroupIterator aGroupIter (theStructure.Groups()); aGroupIter.More(); aGroupIter.Next())
{
if (!aGroupIter.Value()->IsClosed())
@@ -210,6 +103,16 @@ namespace
// clear stencil only if something has been actually drawn
theStencilSentry.Init();
// check if capping plane should be rendered within current pass (only opaque / only transparent)
const OpenGl_Aspects* anObjAspectFace = aRenderPlane->ToUseObjectProperties() ? aGroupIter.Value()->GlAspects() : NULL;
thePlane->Update (aContext, anObjAspectFace != NULL ? anObjAspectFace->Aspect() : Handle(Graphic3d_Aspects)());
theWorkspace->SetAspects (thePlane->AspectFace());
theWorkspace->SetRenderFilter (aPrevFilter);
if (!theWorkspace->ShouldRender (&thePlane->Primitives()))
{
continue;
}
// suppress only opaque/transparent filter since for filling stencil the whole geometry should be drawn
theWorkspace->SetRenderFilter (anAnyFilter);
@@ -218,7 +121,7 @@ namespace
aContext->ShaderManager()->UpdateClippingState();
glClear (GL_STENCIL_BUFFER_BIT);
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
const bool aColorMaskBack = aContext->SetColorMask (false);
// override aspects, disable culling
theWorkspace->SetAspects (&theWorkspace->NoneCulling());
@@ -237,7 +140,20 @@ namespace
glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
// render closed primitives
aGroupIter.Value()->Render (theWorkspace);
if (aRenderPlane->ToUseObjectProperties())
{
aGroupIter.Value()->Render (theWorkspace);
}
else
{
for (; aGroupIter.More(); aGroupIter.Next())
{
if (aGroupIter.Value()->IsClosed())
{
aGroupIter.Value()->Render (theWorkspace);
}
}
}
// override material, cull back faces
theWorkspace->SetAspects (&theWorkspace->FrontCulling());
@@ -248,7 +164,7 @@ namespace
aContext->ShaderManager()->UpdateClippingState();
// render capping plane using the generated stencil mask
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
aContext->SetColorMask (aColorMaskBack);
if (theWorkspace->UseDepthWrite())
{
glDepthMask (GL_TRUE);
@@ -260,66 +176,8 @@ namespace
glEnable (GL_DEPTH_TEST);
}
const OpenGl_Aspects* aGroupAspectFace = aGroupIter.Value()->GlAspects();
const OpenGl_CappingPlaneResource* aGroupAspectCapping = aGroupIter.Value()->AspectFillCapping();
const OpenGl_CappingPlaneResource* anAspectCapping =
thePlane && (!aGroupAspectCapping || aGroupAspectCapping->Aspect().IsNull() || aPlane->ToOverrideCappingAspect())
? thePlane.get()
: aGroupAspectCapping;
if (anAspectCapping == NULL)
{
anAspectCapping = &THE_DEFAULT_ASPECT;
}
const OpenGl_Aspects* anAspectFace = anAspectCapping->CappingFaceAspect (aGroupAspectFace);
const Standard_Boolean hasHatch = anAspectCapping->Aspect()->ToDrawHatch();
const OpenGl_Aspects* anAspectHatching = hasHatch ? anAspectCapping->HatchingFaceAspect() : NULL;
const Standard_Boolean hasTextureHatch = hasHatch && !anAspectCapping->Aspect()->TextureHatch().IsNull();
const Standard_Boolean isRotatePers = hasTextureHatch && !aCamera.IsNull() && anAspectCapping->Aspect()->IsHatchRotationPersistent();
const Standard_Boolean isZoomPers = hasTextureHatch && !aCamera.IsNull() && anAspectCapping->Aspect()->IsHatchZoomPersistent();
Standard_ShortReal aHatchScale = 1.0;
Standard_ShortReal aHatchAngle = 0.0;
if (isRotatePers || isZoomPers)
{
if (isRotatePers)
{
if (aRotateAngle == 0.0)
{
const gp_Dir aPlaneSide (aPlaneMat.GetValue (0, 0), aPlaneMat.GetValue (1, 0), aPlaneMat.GetValue (2, 0));
const gp_Dir aPlaneUp (aPlaneMat.GetValue (0, 2), aPlaneMat.GetValue (1, 2), aPlaneMat.GetValue (2, 2));
const gp_Dir& aCameraUp = aCamera->Up();
const gp_Vec aCameraPln = aPlaneSide.Dot (aCameraUp) * aPlaneSide + aPlaneUp.Dot (aCameraUp) * aPlaneUp;
const gp_Dir& aCameraDir = aCamera->Direction();
aRotateAngle = static_cast<Standard_ShortReal> (aCameraPln.AngleWithRef (aPlaneUp, aCameraDir) / M_PI * 180.0);
}
aHatchAngle = aRotateAngle;
}
if (isZoomPers)
{
if (aViewScale == ShortRealLast())
{
const Standard_Real aFocus = aCamera->IsOrthographic()
? aCamera->Distance()
: (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
? Standard_Real(aCamera->ZFocus() * aCamera->Distance())
: Standard_Real(aCamera->ZFocus()));
const gp_XYZ aViewDim = aCamera->ViewDimensions (aFocus);
aViewScale = static_cast<Standard_ShortReal> (aViewDim.Y() / aContext->Viewport()[3]);
}
if (!anAspectHatching->TextureSet(aContext)->IsEmpty())
aHatchScale = 1.0f / (aViewScale * anAspectHatching->TextureSet(aContext)->First()->SizeY());
}
}
renderSection (theWorkspace, theQuad, anAspectFace, hasHatch ? anAspectCapping->HatchingFaceAspect() : NULL, aPlaneMat, aHatchScale, aHatchAngle);
theWorkspace->SetAspects (thePlane->AspectFace());
renderPlane (theWorkspace, thePlane);
// turn on the current plane to restore initial state
aContext->ChangeClipping().ResetCappingFilter();
@@ -329,7 +187,7 @@ namespace
if (theStructure.InstancedStructure() != NULL)
{
renderCappingForStructure (theStencilSentry, theWorkspace, *theStructure.InstancedStructure(), theClipChain, theSubPlaneIndex, thePlane, theQuad);
renderCappingForStructure (theStencilSentry, theWorkspace, *theStructure.InstancedStructure(), theClipChain, theSubPlaneIndex, thePlane);
}
}
}
@@ -348,12 +206,6 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorks
return;
}
const OpenGl_PrimitiveArray* aCappingQuad = initQuad (aContext);
if (!aCappingQuad)
{
return;
}
// remember current aspect face defined in workspace
const OpenGl_Aspects* aFaceAsp = theWorkspace->Aspects();
@@ -362,16 +214,6 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorks
theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_FillModeOnly);
StencilTestSentry aStencilSentry;
GLboolean aPrevBlend = glIsEnabled (GL_BLEND);
GLint aPrevBlendSrc = GL_ONE;
GLint aPrevBlendDst = GL_ZERO;
if (aPrevBlend == GL_TRUE)
{
glGetIntegerv (GL_BLEND_SRC_ALPHA, &aPrevBlendSrc);
glGetIntegerv (GL_BLEND_DST_ALPHA, &aPrevBlendDst);
glDisable (GL_BLEND);
}
// generate capping for every clip plane
for (OpenGl_ClippingIterator aCappingIt (aContext->Clipping()); aCappingIt.More(); aCappingIt.Next())
{
@@ -387,33 +229,23 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorks
for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
{
// get resource for the plane
const TCollection_AsciiString& aResId = THE_PLANE_STYLE + aSubPlaneIter->GetId();
const TCollection_AsciiString& aResId = aSubPlaneIter->GetId();
Handle(OpenGl_CappingPlaneResource) aPlaneRes;
if (!aContext->GetResource (aResId, aPlaneRes))
{
// share and register for release once the resource is no longer used
aPlaneRes = new OpenGl_CappingPlaneResource (aSubPlaneIter->CappingSectionStyle());
aPlaneRes = new OpenGl_CappingPlaneResource (aSubPlaneIter);
aContext->ShareResource (aResId, aPlaneRes);
}
renderCappingForStructure (aStencilSentry, theWorkspace, theStructure, aClipChain, aSubPlaneIndex, aPlaneRes, aCappingQuad);
renderCappingForStructure (aStencilSentry, theWorkspace, theStructure, aClipChain, aSubPlaneIndex, aPlaneRes);
// set delayed resource release
aPlaneRes.Nullify();
if (!aResId.IsEmpty())
{
// schedule release of resource if not used
aContext->ReleaseResource (aResId, Standard_True);
}
aContext->ReleaseResource (aResId, Standard_True);
}
}
if (aPrevBlend == GL_TRUE)
{
glEnable (GL_BLEND);
glBlendFunc (aPrevBlendSrc, aPrevBlendDst);
}
// restore rendering aspects
theWorkspace->SetAspects (aFaceAsp);
theWorkspace->SetRenderFilter (aPrevFilter);

View File

@@ -56,28 +56,21 @@ namespace
{ 0.0f, 0.0f, 0.0f, 1.0f } }
};
Handle(Graphic3d_Aspects) defaultMaterial()
{
Handle(Graphic3d_AspectFillArea3d) anAspect;
const Graphic3d_MaterialAspect aMaterial (Graphic3d_NOM_DEFAULT);
anAspect = new Graphic3d_AspectFillArea3d();
anAspect->SetDistinguishOff();
anAspect->SetFrontMaterial (aMaterial);
anAspect->SetInteriorStyle (Aspect_IS_SOLID);
anAspect->SetInteriorColor (aMaterial.Color());
anAspect->SetSuppressBackFaces (false);
return anAspect;
}
}
// =======================================================================
// function : BuildInfinitPlaneVertices
// function : OpenGl_CappingPlaneResource
// purpose :
// =======================================================================
OpenGl_PrimitiveArray* OpenGl_CappingPlaneResource::BuildInfinitPlaneVertices()
OpenGl_CappingPlaneResource::OpenGl_CappingPlaneResource (const Handle(Graphic3d_ClipPlane)& thePlane)
: myPrimitives (NULL),
myOrientation (OpenGl_IdentityMatrix),
myAspect (NULL),
myPlaneRoot (thePlane),
myEquationMod ((unsigned int )-1),
myAspectMod ((unsigned int )-1)
{
OpenGl_PrimitiveArray* aPrimitives = NULL;
// Fill primitive array
Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
Handle(Graphic3d_Buffer) anAttribs = new Graphic3d_Buffer (anAlloc);
@@ -90,26 +83,8 @@ OpenGl_PrimitiveArray* OpenGl_CappingPlaneResource::BuildInfinitPlaneVertices()
if (anAttribs->Init (12, anAttribInfo, 3))
{
memcpy (anAttribs->ChangeData(), THE_CAPPING_PLN_VERTS, sizeof(THE_CAPPING_PLN_VERTS));
aPrimitives = new OpenGl_PrimitiveArray (NULL);
aPrimitives->InitBuffers (NULL, Graphic3d_TOPA_TRIANGLES, NULL, anAttribs, NULL);
myPrimitives.InitBuffers (NULL, Graphic3d_TOPA_TRIANGLES, NULL, anAttribs, NULL);
}
return aPrimitives;
}
// =======================================================================
// function : OpenGl_CappingPlaneResource
// purpose :
// =======================================================================
OpenGl_CappingPlaneResource::OpenGl_CappingPlaneResource (const Handle(Graphic3d_AspectFillCapping)& theAspect)
: myCappingAspect(),//defaultMaterial()),
myHatchingAspect(),//defaultMaterial()),
myHatchingState (0)
{
myCappingAspect.SetAspect (defaultMaterial());
myHatchingAspect.SetAspect (defaultMaterial());
SetAspect (theAspect);
}
// =======================================================================
@@ -118,83 +93,18 @@ OpenGl_CappingPlaneResource::OpenGl_CappingPlaneResource (const Handle(Graphic3d
// =======================================================================
OpenGl_CappingPlaneResource::~OpenGl_CappingPlaneResource()
{
Release (NULL);
}
// =======================================================================
// function : SetAspect
// function : Update
// purpose :
// =======================================================================
void OpenGl_CappingPlaneResource::SetAspect (const Handle(Graphic3d_AspectFillCapping)& theAspect)
void OpenGl_CappingPlaneResource::Update (const Handle(OpenGl_Context)& theCtx,
const Handle(Graphic3d_Aspects)& theObjAspect)
{
myAspect = theAspect;
if (theAspect.IsNull())
{
return;
}
if (!theAspect->ToUseObjectMaterial()
|| !theAspect->ToUseObjectTexture()
|| !theAspect->ToUseObjectShader())
{
Handle(Graphic3d_Aspects) aFillAspect = myCappingAspect.Aspect();
if (!theAspect->ToUseObjectMaterial())
{
aFillAspect->SetFrontMaterial (theAspect->Material());
aFillAspect->SetInteriorColor (theAspect->Material().Color());
}
if (!theAspect->ToUseObjectTexture())
{
aFillAspect->SetTextureMap (theAspect->Texture());
if (!theAspect->Texture().IsNull())
{
aFillAspect->SetTextureMapOn();
}
else
{
aFillAspect->SetTextureMapOff();
}
}
else
{
aFillAspect->SetTextureMap (Handle(Graphic3d_TextureMap)());
aFillAspect->SetTextureMapOff();
}
if (!theAspect->ToUseObjectShader())
{
aFillAspect->SetShaderProgram (theAspect->Shader());
}
myCappingAspect.SetAspect (aFillAspect);
}
if (theAspect->ToDrawHatch()
&& (theAspect->IsTextureHatch()
|| theAspect->IsStippleHatch()))
{
Handle(Graphic3d_Aspects) aFillAspect = myHatchingAspect.Aspect();
aFillAspect->SetInteriorStyle (theAspect->IsStippleHatch() ? Aspect_IS_HATCH : Aspect_IS_SOLID);
aFillAspect->SetHatchStyle (theAspect->IsStippleHatch() ? theAspect->StippleHatch() : Handle(Graphic3d_HatchStyle)());
aFillAspect->SetTextureMap (theAspect->IsTextureHatch() ? theAspect->TextureHatch() : Handle(Graphic3d_TextureMap)());
aFillAspect->SetFrontMaterial (theAspect->HatchMaterial());
aFillAspect->SetInteriorColor (theAspect->HatchMaterial().Color());
if (theAspect->IsTextureHatch())
{
aFillAspect->SetTextureMapOn();
}
else
{
aFillAspect->SetTextureMapOff();
}
myHatchingAspect.SetAspect (aFillAspect);
myHatchingState = theAspect->HatchingState();
}
updateTransform (theCtx);
updateAspect (theObjAspect);
}
// =======================================================================
@@ -203,109 +113,123 @@ void OpenGl_CappingPlaneResource::SetAspect (const Handle(Graphic3d_AspectFillCa
// =======================================================================
void OpenGl_CappingPlaneResource::Release (OpenGl_Context* theContext)
{
myCappingAspect .Release (theContext);
myHatchingAspect.Release (theContext);
OpenGl_Element::Destroy (theContext, myAspect);
myPrimitives.Release (theContext);
myEquationMod = (unsigned int )-1;
myAspectMod = (unsigned int )-1;
}
// =======================================================================
// function : CappingFaceAspect
// function : updateAspect
// purpose :
// =======================================================================
const OpenGl_Aspects* OpenGl_CappingPlaneResource::CappingFaceAspect (const OpenGl_Aspects* theObjectAspect) const
void OpenGl_CappingPlaneResource::updateAspect (const Handle(Graphic3d_Aspects)& theObjAspect)
{
if (myAspect.IsNull())
if (myAspect == NULL)
{
return NULL;
myAspect = new OpenGl_Aspects();
myAspectMod = myPlaneRoot->MCountAspect() - 1; // mark out of sync
}
Handle(Graphic3d_Aspects) aFillAspect = myCappingAspect.Aspect();
if (theObjAspect.IsNull())
{
if (myAspectMod != myPlaneRoot->MCountAspect())
{
myAspect->SetAspect (myPlaneRoot->CappingAspect());
myAspectMod = myPlaneRoot->MCountAspect();
}
return;
}
if (myAspect->ToUseObjectMaterial() && theObjectAspect != NULL)
if (myFillAreaAspect.IsNull())
{
myFillAreaAspect = new Graphic3d_AspectFillArea3d();
}
if (myAspectMod != myPlaneRoot->MCountAspect())
{
*myFillAreaAspect = *myPlaneRoot->CappingAspect();
}
if (myPlaneRoot->ToUseObjectMaterial())
{
// only front material currently supported by capping rendering
aFillAspect->SetFrontMaterial (theObjectAspect->Aspect()->FrontMaterial());
aFillAspect->SetInteriorColor (theObjectAspect->Aspect()->InteriorColor());
myFillAreaAspect->SetFrontMaterial (theObjAspect->FrontMaterial());
myFillAreaAspect->SetInteriorColor (theObjAspect->InteriorColor());
}
else
if (myPlaneRoot->ToUseObjectTexture())
{
aFillAspect->SetFrontMaterial (myAspect->Material());
aFillAspect->SetInteriorColor (myAspect->Material().Color());
}
if (myAspect->ToUseObjectTexture() && theObjectAspect != NULL)
{
if (theObjectAspect->Aspect()->ToMapTexture())
myFillAreaAspect->SetTextureSet (theObjAspect->TextureSet());
if (theObjAspect->ToMapTexture())
{
aFillAspect->SetTextureMap (theObjectAspect->Aspect()->TextureMap());
aFillAspect->SetTextureMapOn();
myFillAreaAspect->SetTextureMapOn();
}
else
{
aFillAspect->SetTextureMapOff();
myFillAreaAspect->SetTextureMapOff();
}
}
else
if (myPlaneRoot->ToUseObjectShader())
{
aFillAspect->SetTextureMap (myAspect->Texture());
if (!myAspect->Texture().IsNull())
{
aFillAspect->SetTextureMapOn();
}
else
{
aFillAspect->SetTextureMapOff();
}
myFillAreaAspect->SetShaderProgram (theObjAspect->ShaderProgram());
}
if (myAspect->ToUseObjectShader() && theObjectAspect != NULL)
{
aFillAspect->SetShaderProgram (theObjectAspect->Aspect()->ShaderProgram());
}
else
{
aFillAspect->SetShaderProgram (myAspect->Shader());
}
myCappingAspect.SetAspect (aFillAspect);
return &myCappingAspect;
myAspect->SetAspect (myFillAreaAspect);
}
// =======================================================================
// function : HatchingFaceAspect
// function : updateTransform
// purpose :
// =======================================================================
const OpenGl_Aspects* OpenGl_CappingPlaneResource::HatchingFaceAspect() const
void OpenGl_CappingPlaneResource::updateTransform (const Handle(OpenGl_Context)& theCtx)
{
if (myAspect.IsNull())
if (myEquationMod == myPlaneRoot->MCountEquation()
&& myLocalOrigin.IsEqual (theCtx->ShaderManager()->LocalOrigin(), gp::Resolution()))
{
return NULL;
return; // nothing to update
}
const Standard_Size aHatchingState = myAspect->HatchingState();
if (myHatchingState != aHatchingState)
{
if (myAspect->ToDrawHatch())
{
Handle(Graphic3d_Aspects) aFillAspect = myHatchingAspect.Aspect();
myEquationMod = myPlaneRoot->MCountEquation();
myLocalOrigin = theCtx->ShaderManager()->LocalOrigin();
aFillAspect->SetInteriorStyle (myAspect->IsStippleHatch() ? Aspect_IS_HATCH : Aspect_IS_SOLID);
aFillAspect->SetHatchStyle (myAspect->IsStippleHatch() ? myAspect->StippleHatch() : Handle(Graphic3d_HatchStyle)());
aFillAspect->SetTextureMap (myAspect->IsTextureHatch() ? myAspect->TextureHatch() : Handle(Graphic3d_TextureMap)());
aFillAspect->SetFrontMaterial (myAspect->HatchMaterial());
aFillAspect->SetInteriorColor (myAspect->HatchMaterial().Color());
if (myAspect->IsTextureHatch())
{
aFillAspect->SetTextureMapOn();
}
else
{
aFillAspect->SetTextureMapOff();
}
myHatchingAspect.SetAspect (aFillAspect);
myHatchingState = aHatchingState;
}
const Graphic3d_ClipPlane::Equation& anEq = myPlaneRoot->GetEquation();
const Standard_Real anEqW = theCtx->ShaderManager()->LocalClippingPlaneW (*myPlaneRoot);
// re-evaluate infinite plane transformation matrix
const Graphic3d_Vec3 aNorm (anEq.xyz());
const Graphic3d_Vec3 T (anEq.xyz() * -anEqW);
// project plane normal onto OX to find left vector
const Standard_ShortReal aProjLen = sqrt ((Standard_ShortReal)anEq.xz().SquareModulus());
Graphic3d_Vec3 aLeft;
if (aProjLen < ShortRealSmall())
{
aLeft[0] = 1.0f;
}
else
{
aLeft[0] = aNorm[2] / aProjLen;
aLeft[2] = -aNorm[0] / aProjLen;
}
return &myHatchingAspect;
const Graphic3d_Vec3 F = Graphic3d_Vec3::Cross (-aLeft, aNorm);
myOrientation.mat[0][0] = aLeft[0];
myOrientation.mat[0][1] = aLeft[1];
myOrientation.mat[0][2] = aLeft[2];
myOrientation.mat[0][3] = 0.0f;
myOrientation.mat[1][0] = aNorm[0];
myOrientation.mat[1][1] = aNorm[1];
myOrientation.mat[1][2] = aNorm[2];
myOrientation.mat[1][3] = 0.0f;
myOrientation.mat[2][0] = F[0];
myOrientation.mat[2][1] = F[1];
myOrientation.mat[2][2] = F[2];
myOrientation.mat[2][3] = 0.0f;
myOrientation.mat[3][0] = T[0];
myOrientation.mat[3][1] = T[1];
myOrientation.mat[3][2] = T[2];
myOrientation.mat[3][3] = 1.0f;
}

View File

@@ -20,7 +20,7 @@
#include <OpenGl_Resource.hxx>
#include <OpenGl_Aspects.hxx>
#include <OpenGl_Matrix.hxx>
#include <Graphic3d_AspectFillCapping.hxx>
#include <Graphic3d_ClipPlane.hxx>
class OpenGl_CappingPlaneResource;
DEFINE_STANDARD_HANDLE (OpenGl_CappingPlaneResource, OpenGl_Resource)
@@ -30,23 +30,25 @@ DEFINE_STANDARD_HANDLE (OpenGl_CappingPlaneResource, OpenGl_Resource)
//! This resource holds data necessary for OpenGl_CappingAlgo.
//! This object is implemented as OpenGl resource for the following reasons:
//! - one instance should be shared between contexts.
//! - instance associated to Graphic3d_AspectFillCapping data.
//! - instance associated to Graphic3d_ClipPlane data by id.
//! - should created and released within context (owns OpenGl elements and resources).
class OpenGl_CappingPlaneResource : public OpenGl_Resource
{
public:
//! Create and assign style.
Standard_EXPORT OpenGl_CappingPlaneResource (const Handle(Graphic3d_AspectFillCapping)& theAspect);
//! Constructor.
//! Create capping plane presentation associated to clipping plane data.
//! @param thePlane [in] the plane data.
Standard_EXPORT OpenGl_CappingPlaneResource (const Handle(Graphic3d_ClipPlane)& thePlane);
//! Destroy object.
Standard_EXPORT virtual ~OpenGl_CappingPlaneResource();
//! Assign section style.
Standard_EXPORT void SetAspect (const Handle(Graphic3d_AspectFillCapping)& theAspect);
//! Returns section style parameters.
const Handle(Graphic3d_AspectFillCapping)& Aspect() const { return myAspect; }
//! Update resource data in the passed context.
//! @param theContext [in] the context
//! @param theObjAspect [in] object aspect
Standard_EXPORT void Update (const Handle(OpenGl_Context)& theContext,
const Handle(Graphic3d_Aspects)& theObjAspect);
//! Release associated OpenGl resources.
//! @param theContext [in] the resource context.
@@ -55,23 +57,17 @@ public:
//! Returns estimated GPU memory usage - not implemented.
virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE { return 0; }
//! Return parent clipping plane structure.
const Handle(Graphic3d_ClipPlane)& Plane() const { return myPlaneRoot; }
//! @return aspect face for rendering capping surface.
inline const OpenGl_Aspects* AspectFace() const { return myAspect; }
//! @return evaluated orientation matrix to transform infinite plane.
inline const OpenGl_Matrix* Orientation() const { return &myOrientation; }
//! @return primitive array of vertices to render infinite plane.
static OpenGl_PrimitiveArray* BuildInfinitPlaneVertices();
//! Returns true if capping should draw hatch layer.
Standard_Boolean ToDrawHatch() const
{
return myAspect->ToDrawHatch()
&& (myAspect->IsStippleHatch()
|| myAspect->IsTextureHatch());
}
//! Returns the shading aspect for drawing face of a clipping section itself.
//! @param theObjectAspect [in] the aspect of an object if it requires combining.
Standard_EXPORT const OpenGl_Aspects* CappingFaceAspect (const OpenGl_Aspects* theObjectAspect) const;
//! Returns the shading aspect for drawing hatch layer of a section.
Standard_EXPORT const OpenGl_Aspects* HatchingFaceAspect() const;
inline const OpenGl_PrimitiveArray& Primitives() const { return myPrimitives; }
private:
@@ -83,11 +79,14 @@ private:
private:
Handle(Graphic3d_AspectFillCapping) myAspect; //!< Section style settings from application's level.
mutable OpenGl_Aspects myCappingAspect; //!< GL aspect for shading base layer of a capping section.
mutable OpenGl_Aspects myHatchingAspect; //!< GL aspect for shading hatching layer (additional to base) of a capping section.
mutable Standard_Size myHatchingState;
gp_XYZ myLocalOrigin; //!< layer origin
OpenGl_PrimitiveArray myPrimitives; //!< vertices and texture coordinates for rendering
OpenGl_Matrix myOrientation; //!< plane transformation matrix.
OpenGl_Aspects* myAspect; //!< capping face aspect.
Handle(Graphic3d_ClipPlane) myPlaneRoot; //!< parent clipping plane structure.
Handle(Graphic3d_Aspects) myFillAreaAspect;//!< own capping aspect
gp_XYZ myLocalOrigin; //!< layer origin
unsigned int myEquationMod; //!< modification counter for plane equation.
unsigned int myAspectMod; //!< modification counter for aspect.
public:

View File

@@ -21,7 +21,6 @@
#include <Standard_Assert.hxx>
#include <TCollection_ExtendedString.hxx>
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Font,OpenGl_Resource)
// =======================================================================
@@ -34,8 +33,6 @@ OpenGl_Font::OpenGl_Font (const Handle(Font_FTFont)& theFont,
myFont (theFont),
myAscender (0.0f),
myDescender (0.0f),
myLineSpacing (0.0f),
myTileSizeX (0),
myTileSizeY (0),
myLastTileId (-1),
myTextureFormat (GL_ALPHA)
@@ -105,11 +102,9 @@ bool OpenGl_Font::Init (const Handle(OpenGl_Context)& theCtx)
return false;
}
myAscender = myFont->Ascender();
myDescender = myFont->Descender();
myLineSpacing = myFont->LineSpacing();
myTileSizeX = myFont->GlyphMaxSizeX();
myTileSizeY = myFont->GlyphMaxSizeY();
myAscender = myFont->Ascender();
myDescender = myFont->Descender();
myTileSizeY = myFont->GlyphMaxSizeY (true);
myLastTileId = -1;
if (!createTexture (theCtx))
@@ -126,12 +121,16 @@ bool OpenGl_Font::Init (const Handle(OpenGl_Context)& theCtx)
// =======================================================================
bool OpenGl_Font::createTexture (const Handle(OpenGl_Context)& theCtx)
{
const Standard_Integer aMaxSize = theCtx->MaxTextureSize();
// Single font might define very wide range of symbols, with very few of them actually used in text.
// Limit single texture with circa 4096 glyphs.
static const Standard_Integer THE_MAX_GLYPHS_PER_TEXTURE = 4096;
Standard_Integer aGlyphsNb = myFont->GlyphsNumber() - myLastTileId + 1;
const Standard_Integer aTextureSizeX = OpenGl_Context::GetPowerOfTwo (aGlyphsNb * myTileSizeX, aMaxSize);
const Standard_Integer aTilesPerRow = aTextureSizeX / myTileSizeX;
myTileSizeY = myFont->GlyphMaxSizeY (true);
const Standard_Integer aGlyphsNb = Min (THE_MAX_GLYPHS_PER_TEXTURE, myFont->GlyphsNumber (true) - myLastTileId + 1);
const Standard_Integer aMaxTileSizeX = myFont->GlyphMaxSizeX (true);
const Standard_Integer aMaxSize = theCtx->MaxTextureSize();
const Standard_Integer aTextureSizeX = OpenGl_Context::GetPowerOfTwo (aGlyphsNb * aMaxTileSizeX, aMaxSize);
const Standard_Integer aTilesPerRow = aTextureSizeX / aMaxTileSizeX;
const Standard_Integer aTextureSizeY = OpenGl_Context::GetPowerOfTwo (GLint((aGlyphsNb / aTilesPerRow) + 1) * myTileSizeY, aMaxSize);
memset (&myLastTilePx, 0, sizeof(myLastTilePx));
@@ -186,14 +185,18 @@ bool OpenGl_Font::renderGlyph (const Handle(OpenGl_Context)& theCtx,
const Standard_Integer aTileId = myLastTileId + 1;
myLastTilePx.Left = myLastTilePx.Right + 3;
myLastTilePx.Right = myLastTilePx.Left + (Standard_Integer )anImg.SizeX();
if (myLastTilePx.Right >= aTexture->SizeX())
if (myLastTilePx.Right > aTexture->SizeX()
|| (Standard_Integer )anImg.SizeY() > myTileSizeY)
{
myTileSizeY = myFont->GlyphMaxSizeY (true);
myLastTilePx.Left = 0;
myLastTilePx.Right = (Standard_Integer )anImg.SizeX();
myLastTilePx.Top += myTileSizeY;
myLastTilePx.Bottom += myTileSizeY;
if (myLastTilePx.Bottom >= aTexture->SizeY())
if (myLastTilePx.Bottom > aTexture->SizeY()
|| myLastTilePx.Right > aTexture->SizeX())
{
if (!createTexture (theCtx))
{

View File

@@ -106,12 +106,6 @@ public:
return myDescender;
}
//! @return default line spacing (the baseline-to-baseline distance)
inline float LineSpacing() const
{
return myLineSpacing;
}
//! Render glyph to texture if not already.
//! @param theCtx active context
//! @param theUChar unicode symbol to render
@@ -135,8 +129,6 @@ protected:
Handle(Font_FTFont) myFont; //!< FreeType font instance
Standard_ShortReal myAscender; //!< ascender provided my FT font
Standard_ShortReal myDescender; //!< descender provided my FT font
Standard_ShortReal myLineSpacing; //!< line spacing provided my FT font
Standard_Integer myTileSizeX; //!< tile width
Standard_Integer myTileSizeY; //!< tile height
Standard_Integer myLastTileId; //!< id of last tile
RectI myLastTilePx;

View File

@@ -25,7 +25,6 @@
#include <OpenGl_Workspace.hxx>
#include <Graphic3d_ArrayOfPrimitives.hxx>
#include <Graphic3d_AspectFillCapping.hxx>
#include <Graphic3d_GroupDefinitionError.hxx>
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Group,Graphic3d_Group)
@@ -91,20 +90,6 @@ void OpenGl_Group::SetGroupPrimitivesAspect (const Handle(Graphic3d_Aspects)& th
return;
}
if (!theAspect.IsNull() && theAspect->IsKind (STANDARD_TYPE(Graphic3d_AspectFillCapping)))
{
Handle(Graphic3d_AspectFillCapping) aFillCappingAspect = Handle(Graphic3d_AspectFillCapping)::DownCast (theAspect);
if (myAspectFillCapping == NULL)
{
myAspectFillCapping = new OpenGl_CappingPlaneResource (aFillCappingAspect);
}
else
{
myAspectFillCapping->SetAspect (aFillCappingAspect);
}
return;
}
if (myAspects == NULL)
{
myAspects = new OpenGl_Aspects (theAspect);

View File

@@ -21,7 +21,6 @@
#include <NCollection_List.hxx>
#include <OpenGl_Aspects.hxx>
#include <OpenGl_CappingPlaneResource.hxx>
#include <OpenGl_Element.hxx>
class OpenGl_Group;
@@ -118,17 +117,6 @@ public:
//! Is the group ray-tracable (contains ray-tracable elements)?
Standard_Boolean IsRaytracable() const { return myIsRaytracable; }
//! Returns section style aspect.
virtual Handle(Graphic3d_AspectFillCapping) FillCappingAspect() const Standard_OVERRIDE
{
return myAspectFillCapping != NULL
? myAspectFillCapping->Aspect()
: Handle(Graphic3d_AspectFillCapping)();
}
//! Returns OpenGL capping filling aspect.
const OpenGl_CappingPlaneResource* AspectFillCapping() const { return myAspectFillCapping; }
protected:
Standard_EXPORT virtual ~OpenGl_Group();
@@ -136,7 +124,6 @@ protected:
protected:
OpenGl_Aspects* myAspects;
OpenGl_CappingPlaneResource* myAspectFillCapping;
OpenGl_ElementNode* myFirst;
OpenGl_ElementNode* myLast;
Standard_Boolean myIsRaytracable;

22
src/RWGltf/FILES Normal file
View File

@@ -0,0 +1,22 @@
RWGltf_GltfAccessor.hxx
RWGltf_GltfAccessorCompType.hxx
RWGltf_GltfAccessorLayout.hxx
RWGltf_GltfArrayType.hxx
RWGltf_GltfBufferView.hxx
RWGltf_GltfBufferViewTarget.hxx
RWGltf_GltfFace.hxx
RWGltf_GltfLatePrimitiveArray.cxx
RWGltf_GltfLatePrimitiveArray.hxx
RWGltf_GltfPrimArrayData.hxx
RWGltf_GltfPrimitiveMode.hxx
RWGltf_GltfRootElement.hxx
RWGltf_MaterialCommon.hxx
RWGltf_MaterialMetallicRoughness.hxx
RWGltf_CafReader.cxx
RWGltf_CafReader.hxx
RWGltf_GltfJsonParser.cxx
RWGltf_GltfJsonParser.pxx
RWGltf_PrimitiveArrayReader.cxx
RWGltf_PrimitiveArrayReader.hxx
RWGltf_TriangulationReader.cxx
RWGltf_TriangulationReader.hxx

View File

@@ -0,0 +1,295 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <RWGltf_CafReader.hxx>
#include "RWGltf_GltfJsonParser.pxx"
#include <RWGltf_TriangulationReader.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <Message_ProgressSentry.hxx>
#include <OSD_OpenFile.hxx>
#include <OSD_ThreadPool.hxx>
#include <fstream>
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_CafReader, RWMesh_CafReader)
//! Functor for parallel execution.
class RWGltf_CafReader::CafReader_GltfReaderFunctor
{
public:
struct GltfReaderTLS
{
Handle(RWGltf_PrimitiveArrayReader) Reader;
};
//! Main constructor.
CafReader_GltfReaderFunctor (RWGltf_CafReader* myCafReader,
NCollection_Vector<TopoDS_Face>& theFaceList,
Message_ProgressSentry& theSentry,
const OSD_ThreadPool::Launcher& theThreadPool,
const TCollection_AsciiString& theErrPrefix)
: myCafReader (myCafReader),
myFaceList (&theFaceList),
mySentry (&theSentry),
myErrPrefix (theErrPrefix),
myThreadPool(theThreadPool),
myTlsData (theThreadPool.LowerThreadIndex(), theThreadPool.UpperThreadIndex())
{
//
}
//! Execute task for a face with specified index.
void operator() (int theThreadIndex,
int theFaceIndex) const
{
GltfReaderTLS& aTlsData = myTlsData.ChangeValue (theThreadIndex);
if (aTlsData.Reader.IsNull())
{
aTlsData.Reader = myCafReader->createMeshReaderContext();
aTlsData.Reader->SetErrorPrefix (myErrPrefix);
aTlsData.Reader->SetCoordinateSystemConverter (myCafReader->myCoordSysConverter);
}
TopLoc_Location aDummyLoc;
TopoDS_Face& aFace = myFaceList->ChangeValue (theFaceIndex);
Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (aFace, aDummyLoc));
Handle(Poly_Triangulation) aPolyData = aTlsData.Reader->Load (aLateData);
BRep_Builder aBuilder;
aBuilder.UpdateFace (aFace, aPolyData);
if (myThreadPool.HasThreads())
{
Standard_Mutex::Sentry aLock (&myMutex);
mySentry->Next();
}
else
{
mySentry->Next();
}
}
private:
RWGltf_CafReader* myCafReader;
NCollection_Vector<TopoDS_Face>* myFaceList;
Message_ProgressSentry* mySentry;
TCollection_AsciiString myErrPrefix;
mutable Standard_Mutex myMutex;
const OSD_ThreadPool::Launcher& myThreadPool;
mutable NCollection_Array1<GltfReaderTLS>
myTlsData;
};
//================================================================
// Function : Constructor
// Purpose :
//================================================================
RWGltf_CafReader::RWGltf_CafReader()
: myToParallel (false)
{
myCoordSysConverter.SetInputLengthUnit (1.0); // glTF defines model in meters
myCoordSysConverter.SetInputCoordinateSystem (RWMesh_CoordinateSystem_glTF);
}
//================================================================
// Function : performMesh
// Purpose :
//================================================================
Standard_Boolean RWGltf_CafReader::performMesh (const TCollection_AsciiString& theFile,
const Handle(Message_ProgressIndicator)& theProgress,
const Standard_Boolean theToProbe)
{
std::ifstream aFile;
OSD_OpenStream (aFile, theFile.ToCString(), std::ios::in | std::ios::binary);
if (!aFile.is_open()
|| !aFile.good())
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFile + "' is not found!", Message_Fail);
return false;
}
bool isBinaryFile = false;
char aGlbHeader[12] = {};
aFile.read (aGlbHeader, sizeof(aGlbHeader));
int64_t aBinBodyOffset = 0;
int64_t aBinBodyLen = 0;
int64_t aJsonBodyOffset = 0;
int64_t 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 == 1)
{
if (*aLen < 20)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFile + "' has broken glTF format!", Message_Fail);
return false;
}
char aHeader1[8] = {};
aFile.read (aHeader1, sizeof(aHeader1));
const uint32_t* aSceneLen = (const uint32_t* )(aHeader1 + 0);
const uint32_t* aSceneFormat = (const uint32_t* )(aHeader1 + 4);
aJsonBodyOffset = 20;
aJsonBodyLen = int64_t(*aSceneLen);
aBinBodyOffset = aJsonBodyOffset + aJsonBodyLen;
aBinBodyLen = int64_t(*aLen) - aBinBodyOffset;
if (*aSceneFormat != 0)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFile + "' is written using unsupported Scene format!", Message_Fail);
return false;
}
}
else //if (*aVer == 2)
{
if (*aVer != 2)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFile + "' is written using unknown version " + int(*aVer) + "!", Message_Warning);
}
for (int aChunkIter = 0; !aFile.eof() && aChunkIter < 2; ++aChunkIter)
{
char aChunkHeader2[8] = {};
if (int64_t(aFile.tellg()) + int64_t(sizeof(aChunkHeader2)) > int64_t(aLen))
{
break;
}
aFile.read (aChunkHeader2, sizeof(aChunkHeader2));
if (!aFile.good())
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFile + "' is written using unsupported format!", Message_Fail);
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(aFile.tellg());
aJsonBodyLen = int64_t(*aChunkLen);
}
else if (*aChunkType == 0x004E4942)
{
aBinBodyOffset = int64_t(aFile.tellg());
aBinBodyLen = int64_t(*aChunkLen);
}
if (*aChunkLen != 0)
{
aFile.seekg (*aChunkLen, std::ios_base::cur);
}
}
aFile.seekg ((std::streamoff )aJsonBodyOffset, std::ios_base::beg);
}
}
else
{
aFile.seekg (0, std::ios_base::beg);
}
TCollection_AsciiString anErrPrefix = TCollection_AsciiString ("File '") + theFile + "' defines invalid glTF!\n";
RWGltf_GltfJsonParser aDoc (myRootShapes);
aDoc.SetFilePath (theFile);
aDoc.SetProbeHeader (theToProbe);
aDoc.SetExternalFiles (myExternalFiles);
aDoc.SetErrorPrefix (anErrPrefix);
aDoc.SetCoordinateSystemConverter (myCoordSysConverter);
if (!theToProbe)
{
aDoc.SetAttributeMap (myAttribMap);
}
if (isBinaryFile)
{
aDoc.SetBinaryFormat (aBinBodyOffset, aBinBodyLen);
}
#ifdef HAVE_RAPIDJSON
rapidjson::ParseResult aRes;
rapidjson::IStreamWrapper aFileStream (aFile);
if (isBinaryFile)
{
aRes = aDoc.ParseStream<rapidjson::kParseStopWhenDoneFlag, rapidjson::UTF8<>, rapidjson::IStreamWrapper> (aFileStream);
}
else
{
aRes = aDoc.ParseStream (aFileStream);
}
if (aRes.IsError())
{
if (aRes.Code() == rapidjson::kParseErrorDocumentEmpty)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFile + "' is empty!", Message_Fail);
return false;
}
TCollection_AsciiString anErrDesc (RWGltf_GltfJsonParser::FormatParseError (aRes.Code()));
Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFile + "' defines invalid JSON document!\n"
+ anErrDesc + ".", Message_Fail);
return false;
}
#endif
if (!aDoc.Parse (theProgress))
{
return false;
}
if (!theToProbe
&& !readLateData (aDoc.FaceList(), theFile, theProgress))
{
return false;
}
return true;
}
//================================================================
// Function : createMeshReaderContext
// Purpose :
//================================================================
Handle(RWGltf_PrimitiveArrayReader) RWGltf_CafReader::createMeshReaderContext()
{
Handle(RWGltf_TriangulationReader) aReader = new RWGltf_TriangulationReader();
return aReader;
}
//================================================================
// Function : readLateData
// Purpose :
//================================================================
Standard_Boolean RWGltf_CafReader::readLateData (NCollection_Vector<TopoDS_Face>& theFaces,
const TCollection_AsciiString& theFile,
const Handle(Message_ProgressIndicator)& theProgress)
{
Message_ProgressSentry aPSentryTris (theProgress, "Loading glTF triangulation", 0, Max (1, theFaces.Size()), 1);
const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
const int aNbThreads = myToParallel ? Min (theFaces.Size(), aThreadPool->NbDefaultThreadsToLaunch()) : 1;
OSD_ThreadPool::Launcher aLauncher (*aThreadPool, aNbThreads);
CafReader_GltfReaderFunctor aFunctor (this, theFaces, aPSentryTris, aLauncher,
TCollection_AsciiString ("File '") + theFile + "' defines invalid glTF!\n");
aLauncher.Perform (theFaces.Lower(), theFaces.Upper() + 1, aFunctor);
return Standard_True;
}

View File

@@ -0,0 +1,65 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_CafReader_HeaderFile
#define _RWGltf_CafReader_HeaderFile
#include <NCollection_Vector.hxx>
#include <RWMesh_CafReader.hxx>
#include <TopoDS_Face.hxx>
class RWGltf_PrimitiveArrayReader;
//! The glTF (GL Transmission Format) mesh reader into XDE document.
class RWGltf_CafReader : public RWMesh_CafReader
{
DEFINE_STANDARD_RTTIEXT(RWGltf_CafReader, RWMesh_CafReader)
public:
//! Empty constructor.
Standard_EXPORT RWGltf_CafReader();
//! Return TRUE if multithreaded optimizations are allowed; FALSE by default.
bool ToParallel() const { return myToParallel; }
//! Setup multithreaded execution.
void SetParallel (bool theToParallel) { myToParallel = theToParallel; }
protected:
//! Read the mesh from specified file.
Standard_EXPORT virtual Standard_Boolean performMesh (const TCollection_AsciiString& theFile,
const Handle(Message_ProgressIndicator)& theProgress,
const Standard_Boolean theToProbe) Standard_OVERRIDE;
//! Create primitive array reader context.
//! Can be overridden by sub-class to read triangulation into application-specific data structures instead of Poly_Triangulation.
//! Default implementation creates RWGltf_TriangulationReader.
Standard_EXPORT virtual Handle(RWGltf_PrimitiveArrayReader) createMeshReaderContext();
//! Read late data from RWGltf_GltfLatePrimitiveArray stored as Poly_Triangulation within faces.
Standard_EXPORT virtual Standard_Boolean readLateData (NCollection_Vector<TopoDS_Face>& theFaces,
const TCollection_AsciiString& theFile,
const Handle(Message_ProgressIndicator)& theProgress);
protected:
class CafReader_GltfReaderFunctor;
protected:
Standard_Boolean myToParallel; //!< flag to use multithreading; FALSE by default
};
#endif // _RWGltf_CafReader_HeaderFile

View File

@@ -0,0 +1,48 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfAccessor_HeaderFile
#define _RWGltf_GltfAccessor_HeaderFile
#include <Graphic3d_BndBox3d.hxx>
#include <RWGltf_GltfAccessorCompType.hxx>
#include <RWGltf_GltfAccessorLayout.hxx>
#include <Standard_TypeDef.hxx>
//! Low-level glTF data structure defining Accessor.
struct RWGltf_GltfAccessor
{
static const int INVALID_ID = -1;
public:
int Id; //!< identifier
int64_t ByteOffset; //!< byte offset
int64_t Count; //!< size
int32_t ByteStride; //!< [0, 255] for glTF 1.0
RWGltf_GltfAccessorLayout Type; //!< layout type
RWGltf_GltfAccessorCompType ComponentType; //!< component type
Graphic3d_BndBox3d BndBox; //!< bounding box
//! Empty constructor.
RWGltf_GltfAccessor()
: Id (INVALID_ID),
ByteOffset (0),
Count (0),
ByteStride (0),
Type (RWGltf_GltfAccessorLayout_UNKNOWN),
ComponentType (RWGltf_GltfAccessorCompType_UNKNOWN) {}
};
#endif // _RWGltf_GltfAccessor_HeaderFile

View File

@@ -0,0 +1,30 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfAccessorCompType_HeaderFile
#define _RWGltf_GltfAccessorCompType_HeaderFile
//! Low-level glTF enumeration defining Accessor component type.
enum RWGltf_GltfAccessorCompType
{
RWGltf_GltfAccessorCompType_UNKNOWN, //!< unknown or invalid type
RWGltf_GltfAccessorCompType_Int8 = 5120, //!< GL_BYTE
RWGltf_GltfAccessorCompType_UInt8 = 5121, //!< GL_UNSIGNED_BYTE
RWGltf_GltfAccessorCompType_Int16 = 5122, //!< GL_SHORT
RWGltf_GltfAccessorCompType_UInt16 = 5123, //!< GL_UNSIGNED_SHORT
RWGltf_GltfAccessorCompType_UInt32 = 5125, //!< GL_UNSIGNED_INT
RWGltf_GltfAccessorCompType_Float32 = 5126, //!< GL_FLOAT
};
#endif // _RWGltf_GltfAccessorCompType_HeaderFile

View File

@@ -0,0 +1,68 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfAccessorLayout_HeaderFile
#define _RWGltf_GltfAccessorLayout_HeaderFile
#include <Standard_CString.hxx>
//! Low-level glTF enumeration defining Accessor layout.
//! Similar to Graphic3d_TypeOfData but does not define actual type and includes matrices.
enum RWGltf_GltfAccessorLayout
{
RWGltf_GltfAccessorLayout_UNKNOWN, //!< unknown or invalid type
RWGltf_GltfAccessorLayout_Scalar, //!< "SCALAR"
RWGltf_GltfAccessorLayout_Vec2, //!< "VEC2"
RWGltf_GltfAccessorLayout_Vec3, //!< "VEC3"
RWGltf_GltfAccessorLayout_Vec4, //!< "VEC4"
RWGltf_GltfAccessorLayout_Mat2, //!< "MAT2"
RWGltf_GltfAccessorLayout_Mat3, //!< "MAT3"
RWGltf_GltfAccessorLayout_Mat4, //!< "MAT4"
};
//! Parse GltfAccessorLayout from string.
inline RWGltf_GltfAccessorLayout RWGltf_GltfParseAccessorType (const char* theType)
{
if (IsEqual ("SCALAR", theType))
{
return RWGltf_GltfAccessorLayout_Scalar;
}
else if (IsEqual ("VEC2", theType))
{
return RWGltf_GltfAccessorLayout_Vec2;
}
else if (IsEqual ("VEC3", theType))
{
return RWGltf_GltfAccessorLayout_Vec3;
}
else if (IsEqual ("VEC4", theType))
{
return RWGltf_GltfAccessorLayout_Vec4;
}
else if (IsEqual ("MAT2", theType))
{
return RWGltf_GltfAccessorLayout_Mat2;
}
else if (IsEqual ("MAT3", theType))
{
return RWGltf_GltfAccessorLayout_Mat3;
}
else if (IsEqual ("MAT4", theType))
{
return RWGltf_GltfAccessorLayout_Mat4;
}
return RWGltf_GltfAccessorLayout_UNKNOWN;
}
#endif // _RWGltf_GltfAccessorLayout_HeaderFile

View File

@@ -0,0 +1,68 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfArrayType_HeaderFile
#define _RWGltf_GltfArrayType_HeaderFile
#include <Standard_CString.hxx>
//! Low-level glTF enumeration defining Array type.
enum RWGltf_GltfArrayType
{
RWGltf_GltfArrayType_UNKNOWN, //!< unknown or invalid type
RWGltf_GltfArrayType_Indices, //!< "indices" within "primitive" element
RWGltf_GltfArrayType_Position, //!< "POSITION" within "attributes" element
RWGltf_GltfArrayType_Normal, //!< "NORMAL" within "attributes" element
RWGltf_GltfArrayType_Color, //!< "COLOR" within "attributes" element
RWGltf_GltfArrayType_TCoord0, //!< "TEXCOORD_0" within "attributes" element
RWGltf_GltfArrayType_TCoord1, //!< "TEXCOORD_1" within "attributes" element
RWGltf_GltfArrayType_Joint, //!< "JOINT" within "attributes" element
RWGltf_GltfArrayType_Weight, //!< "WEIGHT" within "attributes" element
};
//! Parse GltfArrayType from string.
inline RWGltf_GltfArrayType RWGltf_GltfParseAttribType (const char* theType)
{
if (IsEqual ("POSITION", theType))
{
return RWGltf_GltfArrayType_Position;
}
else if (IsEqual ("NORMAL", theType))
{
return RWGltf_GltfArrayType_Normal;
}
else if (IsEqual ("COLOR", theType))
{
return RWGltf_GltfArrayType_Color;
}
else if (IsEqual ("TEXCOORD_0", theType))
{
return RWGltf_GltfArrayType_TCoord0;
}
else if (IsEqual ("TEXCOORD_1", theType))
{
return RWGltf_GltfArrayType_TCoord1;
}
else if (IsEqual ("JOINT", theType))
{
return RWGltf_GltfArrayType_Joint;
}
else if (IsEqual ("WEIGHT", theType))
{
return RWGltf_GltfArrayType_Weight;
}
return RWGltf_GltfArrayType_UNKNOWN;
}
#endif // _RWGltf_GltfArrayType_HeaderFile

View File

@@ -0,0 +1,38 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfBufferView_HeaderFile
#define _RWGltf_GltfBufferView_HeaderFile
#include <RWGltf_GltfBufferViewTarget.hxx>
#include <Standard_TypeDef.hxx>
//! Low-level glTF data structure defining BufferView.
struct RWGltf_GltfBufferView
{
static const int INVALID_ID = -1;
public:
int Id;
int64_t ByteOffset;
int64_t ByteLength;
int32_t ByteStride; //!< [0, 255]
RWGltf_GltfBufferViewTarget Target;
RWGltf_GltfBufferView()
: Id (INVALID_ID), ByteOffset (0), ByteLength (0), ByteStride (0), Target (RWGltf_GltfBufferViewTarget_UNKNOWN) {}
};
#endif // _RWGltf_GltfBufferView_HeaderFile

View File

@@ -0,0 +1,26 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfBufferViewTarget_HeaderFile
#define _RWGltf_GltfBufferViewTarget_HeaderFile
//! Low-level glTF enumeration defining BufferView target.
enum RWGltf_GltfBufferViewTarget
{
RWGltf_GltfBufferViewTarget_UNKNOWN, //!< unknown or invalid type
RWGltf_GltfBufferViewTarget_ARRAY_BUFFER = 34962, //!< GL_ARRAY_BUFFER
RWGltf_GltfBufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963, //!< GL_ELEMENT_ARRAY_BUFFER
};
#endif // _RWGltf_GltfBufferViewTarget_HeaderFile

View File

@@ -0,0 +1,29 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfFace_HeaderFile
#define _RWGltf_GltfFace_HeaderFile
#include <RWGltf_GltfAccessor.hxx>
//! Low-level glTF data structure holding single Face (one primitive array) definition.
struct RWGltf_GltfFace
{
RWGltf_GltfAccessor NodePos; //!< accessor for nodal positions
RWGltf_GltfAccessor NodeNorm; //!< accessor for nodal normals
RWGltf_GltfAccessor NodeUV; //!< accessor for nodal UV texture coordinates
RWGltf_GltfAccessor Indices; //!< accessor for indexes
};
#endif // _RWGltf_GltfFace_HeaderFile

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,416 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfJsonParser_HeaderFile
#define _RWGltf_GltfJsonParser_HeaderFile
#include <Graphic3d_Vec.hxx>
#include <Message_Gravity.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_IndexedMap.hxx>
#include <RWGltf_GltfLatePrimitiveArray.hxx>
#include <RWGltf_GltfBufferView.hxx>
#include <RWGltf_GltfRootElement.hxx>
#include <RWGltf_MaterialCommon.hxx>
#include <RWGltf_MaterialMetallicRoughness.hxx>
#include <RWMesh_CoordinateSystemConverter.hxx>
#include <RWMesh_NodeAttributes.hxx>
#include <TColStd_IndexedDataMapOfStringString.hxx>
#include <TopoDS_Face.hxx>
#include <TopTools_SequenceOfShape.hxx>
// workaround name collisions with XLib
#ifdef None
#undef None
#endif
#ifdef Bool
#undef Bool
#endif
#ifdef HAVE_RAPIDJSON
//#define RAPIDJSON_ASSERT
#include <rapidjson/document.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/istreamwrapper.h>
#include <rapidjson/ostreamwrapper.h>
typedef rapidjson::Document::ValueType RWGltf_JsonValue;
#endif
class Message_ProgressIndicator;
//! INTERNAL tool for parsing glTF document (JSON structure).
class RWGltf_GltfJsonParser
#ifdef HAVE_RAPIDJSON
: public rapidjson::Document
#endif
{
public:
#ifdef HAVE_RAPIDJSON
//! Auxiliary method for formatting error code.
Standard_EXPORT static const char* FormatParseError (rapidjson::ParseErrorCode theCode);
#endif
public:
//! Empty constructor.
Standard_EXPORT RWGltf_GltfJsonParser (TopTools_SequenceOfShape& theRootShapes);
//! Set file path.
Standard_EXPORT void SetFilePath (const TCollection_AsciiString& theFilePath);
//! Set flag for probing file without complete reading.
void SetProbeHeader (bool theToProbe) { myToProbeHeader = theToProbe; }
//! Return prefix for reporting issues.
const TCollection_AsciiString& ErrorPrefix() const { return myErrorPrefix; }
//! Set prefix for reporting issues.
void SetErrorPrefix (const TCollection_AsciiString& theErrPrefix) { myErrorPrefix = theErrPrefix; }
//! Set map for storing node attributes.
void SetAttributeMap (RWMesh_NodeAttributeMap& theAttribMap) { myAttribMap = &theAttribMap; }
//! Set list for storing external files.
void SetExternalFiles (NCollection_IndexedMap<TCollection_AsciiString>& theExternalFiles) { myExternalFiles = &theExternalFiles; }
//! Return transformation from glTF to OCCT coordinate system.
const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCSTrsf; }
//! Set transformation from glTF to OCCT coordinate system.
void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCSTrsf = theConverter; }
//! Initialize binary format.
void SetBinaryFormat (int64_t theBinBodyOffset,
int64_t theBinBodyLen)
{
myIsBinary = true;
myBinBodyOffset = theBinBodyOffset;
myBinBodyLen = theBinBodyLen;
}
//! Parse glTF document.
Standard_EXPORT bool Parse (const Handle(Message_ProgressIndicator)& theProgress);
//! Return metadata map.
const TColStd_IndexedDataMapOfStringString& Metadata() const { return myMetadata; }
//! Return face list for loading triangulation.
NCollection_Vector<TopoDS_Face>& FaceList() { return myFaceList; }
protected:
#ifdef HAVE_RAPIDJSON
//! Search mandatory root elements in the document.
//! Return FALSE if some mandatory element is missing.
Standard_EXPORT bool gltfParseRoots();
//! Parse default scene.
Standard_EXPORT bool gltfParseScene (const Handle(Message_ProgressIndicator)& theProgress);
//! Parse document metadata.
Standard_EXPORT void gltfParseAsset();
protected:
//! Parse materials defined in the document.
Standard_EXPORT void gltfParseMaterials();
//! Parse standard material.
Standard_EXPORT bool gltfParseStdMaterial (Handle(RWGltf_MaterialCommon)& theMat,
const RWGltf_JsonValue& theMatNode);
//! Parse pbrMetallicRoughness material.
Standard_EXPORT bool gltfParsePbrMaterial (Handle(RWGltf_MaterialMetallicRoughness)& theMat,
const RWGltf_JsonValue& theMatNode);
//! Parse common material (KHR_materials_common extension).
Standard_EXPORT bool gltfParseCommonMaterial (Handle(RWGltf_MaterialCommon)& theMat,
const RWGltf_JsonValue& theMatNode);
//! Parse texture definition.
Standard_EXPORT bool gltfParseTexture (Handle(Image_Texture)& theTexture,
const RWGltf_JsonValue* theTextureId);
protected:
//! Parse scene array of nodes recursively.
Standard_EXPORT bool gltfParseSceneNodes (TopTools_SequenceOfShape& theShapeSeq,
const RWGltf_JsonValue& theSceneNodes,
const Handle(Message_ProgressIndicator)& theProgress);
//! Parse scene node recursively.
Standard_EXPORT bool gltfParseSceneNode (TopoDS_Shape& theNodeShape,
const TCollection_AsciiString& theSceneNodeId,
const RWGltf_JsonValue& theSceneNode,
const Handle(Message_ProgressIndicator)& theProgress);
//! Parse mesh element.
Standard_EXPORT bool gltfParseMesh (TopoDS_Shape& theMeshShape,
const TCollection_AsciiString& theMeshId,
const RWGltf_JsonValue& theMesh,
const Handle(Message_ProgressIndicator)& theProgress);
//! Parse primitive array.
Standard_EXPORT bool gltfParsePrimArray (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
const TCollection_AsciiString& theMeshName,
const RWGltf_JsonValue& thePrimArray,
const Handle(Message_ProgressIndicator)& theProgress);
//! Parse accessor.
Standard_EXPORT bool gltfParseAccessor (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
const TCollection_AsciiString& theName,
const RWGltf_JsonValue& theAccessor,
const RWGltf_GltfArrayType theType);
//! Parse buffer view.
Standard_EXPORT bool gltfParseBufferView (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
const TCollection_AsciiString& theName,
const RWGltf_JsonValue& theBufferView,
const RWGltf_GltfAccessor& theAccessor,
const RWGltf_GltfArrayType theType);
//! Parse buffer.
Standard_EXPORT bool gltfParseBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theMeshData,
const TCollection_AsciiString& theName,
const RWGltf_JsonValue& theBuffer,
const RWGltf_GltfAccessor& theAccessor,
const RWGltf_GltfBufferView& theView,
const RWGltf_GltfArrayType theType);
protected:
//! Read vec4 from specified item.
static bool gltfReadVec4 (Graphic3d_Vec4d& theVec4,
const RWGltf_JsonValue* theVal)
{
if (theVal == NULL
|| !theVal->IsArray()
|| theVal->Size() != 4)
{
return false;
}
for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
{
const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
if (!aGenVal.IsNumber())
{
return false;
}
theVec4[aCompIter] = aGenVal.GetDouble();
}
return true;
}
//! Validate color
static bool validateColor4 (const Graphic3d_Vec4d& theVec)
{
return theVec.r() >= 0.0 && theVec.r() <= 1.0
&& theVec.g() >= 0.0 && theVec.g() <= 1.0
&& theVec.b() >= 0.0 && theVec.b() <= 1.0
&& theVec.a() >= 0.0 && theVec.a() <= 1.0;
}
//! Read vec3 from specified item.
static bool gltfReadVec3 (Graphic3d_Vec3d& theVec3,
const RWGltf_JsonValue* theVal)
{
if (theVal == NULL
|| !theVal->IsArray()
|| theVal->Size() != 3)
{
return false;
}
for (int aCompIter = 0; aCompIter < 3; ++aCompIter)
{
const RWGltf_JsonValue& aGenVal = (*theVal)[aCompIter];
if (!aGenVal.IsNumber())
{
return false;
}
theVec3[aCompIter] = aGenVal.GetDouble();
}
return true;
}
//! Validate color
static bool validateColor3 (const Graphic3d_Vec3d& theVec)
{
return theVec.r() >= 0.0 && theVec.r() <= 1.0
&& theVec.g() >= 0.0 && theVec.g() <= 1.0
&& theVec.b() >= 0.0 && theVec.b() <= 1.0;
}
protected:
//! Groups for re-using shapes.
enum ShapeMapGroup
{
ShapeMapGroup_Nodes, //!< nodes
ShapeMapGroup_Meshes, //!< meshes
};
//! Bind name attribute.
void bindNodeShape (TopoDS_Shape& theShape,
const TopLoc_Location& theLoc,
const TCollection_AsciiString& theNodeId,
const RWGltf_JsonValue* theUserName)
{
bindNamedShape (theShape, ShapeMapGroup_Nodes, theLoc, theNodeId, theUserName);
}
//! Bind name attribute.
void bindMeshShape (TopoDS_Shape& theShape,
const TCollection_AsciiString& theMeshId,
const RWGltf_JsonValue* theUserName)
{
bindNamedShape (theShape, ShapeMapGroup_Meshes, TopLoc_Location(), theMeshId, theUserName);
}
//! Find named shape.
bool findNodeShape (TopoDS_Shape& theShape,
const TCollection_AsciiString& theNodeId) const
{
return findNamedShape (theShape, ShapeMapGroup_Nodes, theNodeId);
}
//! Find named shape.
bool findMeshShape (TopoDS_Shape& theShape,
const TCollection_AsciiString& theMeshId) const
{
return findNamedShape (theShape, ShapeMapGroup_Meshes, theMeshId);
}
//! Bind name attribute.
Standard_EXPORT void bindNamedShape (TopoDS_Shape& theShape,
ShapeMapGroup theGroup,
const TopLoc_Location& theLoc,
const TCollection_AsciiString& theId,
const RWGltf_JsonValue* theUserName);
//! Find named shape.
bool findNamedShape (TopoDS_Shape& theShape,
ShapeMapGroup theGroup,
const TCollection_AsciiString& theId) const
{
return myShapeMap[theGroup].Find (theId, theShape);
}
//! Return the string representation of the key.
static TCollection_AsciiString getKeyString (const RWGltf_JsonValue& theValue)
{
if (theValue.IsString())
{
return TCollection_AsciiString (theValue.GetString());
}
else if (theValue.IsInt())
{
return TCollection_AsciiString (theValue.GetInt());
}
return TCollection_AsciiString();
}
protected:
//! Auxiliary structure for fast look-up of document sub-nodes of specified node.
class GltfElementMap
{
public:
//! Empty constructor.
GltfElementMap() : myRoot (NULL) {}
//! Return TRUE if this element is NULL.
bool IsNull() const { return myRoot == NULL; }
//! Access this node.
const RWGltf_JsonValue* Root() const { return myRoot; }
//! Find the child node with specified key.
const RWGltf_JsonValue* FindChild (const TCollection_AsciiString& theKey)
{
const RWGltf_JsonValue* aNode = NULL;
return myChildren.Find (theKey, aNode)
? aNode
: NULL;
}
//! Find the child node with specified key.
const RWGltf_JsonValue* FindChild (const RWGltf_JsonValue& theKey)
{
const TCollection_AsciiString aKey = getKeyString (theKey);
if (aKey.IsEmpty())
{
return NULL;
}
const RWGltf_JsonValue* aNode = NULL;
return myChildren.Find (aKey, aNode)
? aNode
: NULL;
}
//! Initialize the element.
void Init (const TCollection_AsciiString& theRootName,
const RWGltf_JsonValue* theRoot);
private:
NCollection_DataMap<TCollection_AsciiString, const RWGltf_JsonValue*, TCollection_AsciiString> myChildren;
const RWGltf_JsonValue* myRoot;
};
#endif
protected:
//! Print message about invalid glTF syntax.
void reportGltfSyntaxProblem (const TCollection_AsciiString& theMsg, Message_Gravity theGravity);
protected:
TopTools_SequenceOfShape* myRootShapes; //!< sequence of result root shapes
RWMesh_NodeAttributeMap* myAttribMap; //!< shape attributes
NCollection_IndexedMap<TCollection_AsciiString>*
myExternalFiles; //!< list of external file references
RWMesh_CoordinateSystemConverter myCSTrsf; //!< transformation from glTF to OCCT coordinate system
TColStd_IndexedDataMapOfStringString myMetadata; //!< file metadata
NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialMetallicRoughness)> myMaterialsPbr;
NCollection_DataMap<TCollection_AsciiString, Handle(RWGltf_MaterialCommon)> myMaterialsCommon;
NCollection_DataMap<TCollection_AsciiString, TopoDS_Shape> myShapeMap[2];
NCollection_DataMap<TCollection_AsciiString, bool> myProbedFiles;
NCollection_DataMap<TCollection_AsciiString, Handle(NCollection_Buffer)> myDecodedBuffers;
NCollection_Vector<TopoDS_Face> myFaceList; //!< face list for loading triangulation
TCollection_AsciiString myFilePath; //!< file path
TCollection_AsciiString myFolder; //!< folder
TCollection_AsciiString myErrorPrefix; //!< invalid syntax error prefix
int64_t myBinBodyOffset; //!< offset to binary body
int64_t myBinBodyLen; //!< binary body length
bool myIsBinary; //!< binary document
bool myIsGltf1; //!< obsolete glTF 1.0 version format
bool myToSkipEmptyNodes; //!< ignore nodes without Geometry
bool myToProbeHeader; //!< flag to probe header without full reading, FALSE by default
#ifdef HAVE_RAPIDJSON
GltfElementMap myGltfRoots[RWGltf_GltfRootElement_NB]; //!< glTF format root elements
#endif
};
#endif // _RWGltf_GltfJsonParser_HeaderFile

View File

@@ -0,0 +1,133 @@
// Author: Kirill Gavrilov
// Copyright (c) 2018-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <RWGltf_GltfLatePrimitiveArray.hxx>
#include <RWGltf_MaterialMetallicRoughness.hxx>
#include <RWGltf_MaterialCommon.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <OSD_OpenFile.hxx>
#include <Standard_ArrayStreamBuffer.hxx>
#include <fstream>
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_GltfLatePrimitiveArray, Poly_Triangulation)
// =======================================================================
// function : RWGltf_GltfLatePrimitiveArray
// purpose :
// =======================================================================
RWGltf_GltfLatePrimitiveArray::RWGltf_GltfLatePrimitiveArray (const TCollection_AsciiString& theId,
const TCollection_AsciiString& theName)
: Poly_Triangulation (3, 1, false),
myId (theId),
myName (theName),
myPrimMode (RWGltf_GltfPrimitiveMode_UNKNOWN)
{
SetBoundingBox (Bnd_Box());
}
// =======================================================================
// function : ~RWGltf_GltfLatePrimitiveArray
// purpose :
// =======================================================================
RWGltf_GltfLatePrimitiveArray::~RWGltf_GltfLatePrimitiveArray()
{
//
}
// =======================================================================
// function : BaseColor
// purpose :
// =======================================================================
Quantity_ColorRGBA RWGltf_GltfLatePrimitiveArray::BaseColor() const
{
if (!myMaterialPbr.IsNull())
{
return myMaterialPbr->BaseColor;
}
else if (!myMaterialCommon.IsNull())
{
return Quantity_ColorRGBA (myMaterialCommon->DiffuseColor, 1.0f - myMaterialCommon->Transparency);
}
return Quantity_ColorRGBA();
}
// =======================================================================
// function : AddPrimArrayData
// purpose :
// =======================================================================
RWGltf_GltfPrimArrayData& RWGltf_GltfLatePrimitiveArray::AddPrimArrayData (RWGltf_GltfArrayType theType)
{
if (theType == RWGltf_GltfArrayType_Position)
{
// make sure positions go first
myData.Prepend (RWGltf_GltfPrimArrayData (theType));
return myData.ChangeFirst();
}
else if (theType == RWGltf_GltfArrayType_Indices)
{
// make sure indexes go after vertex positions but before any other vertex attributes
if (myData.First().Type == RWGltf_GltfArrayType_Position)
{
myData.InsertAfter (myData.Lower(), RWGltf_GltfPrimArrayData (theType));
return myData.ChangeValue (myData.Lower() + 1);
}
else
{
myData.Prepend (RWGltf_GltfPrimArrayData (theType));
return myData.ChangeFirst();
}
}
else
{
myData.Append (RWGltf_GltfPrimArrayData (theType));
return myData.ChangeLast();
}
}
// =======================================================================
// function : SetBoundingBox
// purpose :
// =======================================================================
void RWGltf_GltfLatePrimitiveArray::SetBoundingBox (const Bnd_Box& theBox)
{
myBox = theBox;
if (theBox.IsVoid())
{
Poly_Triangulation::myNodes = TColgp_Array1OfPnt();
Poly_Triangulation::myTriangles = Poly_Array1OfTriangle();
return;
}
// define 8 nodes so that AABB will be huge enough to include mesh even with transformation applied
Poly_Triangulation::myNodes.Resize (1, 8, false);
const gp_Pnt aMin = theBox.CornerMin();
const gp_Pnt aMax = theBox.CornerMax();
Poly_Triangulation::ChangeNode(1).SetCoord(aMin.X(), aMin.Y(), aMin.Z());
Poly_Triangulation::ChangeNode(2).SetCoord(aMax.X(), aMax.Y(), aMax.Z());
Poly_Triangulation::ChangeNode(3).SetCoord(aMin.X(), aMin.Y(), aMax.Z());
Poly_Triangulation::ChangeNode(4).SetCoord(aMin.X(), aMax.Y(), aMax.Z());
Poly_Triangulation::ChangeNode(5).SetCoord(aMax.X(), aMax.Y(), aMin.Z());
Poly_Triangulation::ChangeNode(6).SetCoord(aMax.X(), aMin.Y(), aMin.Z());
Poly_Triangulation::ChangeNode(7).SetCoord(aMin.X(), aMax.Y(), aMin.Z());
Poly_Triangulation::ChangeNode(8).SetCoord(aMax.X(), aMin.Y(), aMax.Z());
Poly_Triangulation::myTriangles.Resize (1, 1, false);
Poly_Triangulation::ChangeTriangle (1).Set (1, 2, 1);
//Poly_Triangulation::myTriangles = Poly_Array1OfTriangle();
}

View File

@@ -0,0 +1,99 @@
// Author: Kirill Gavrilov
// Copyright (c) 2018-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfLatePrimitiveArray_HeaderFile
#define _RWGltf_GltfLatePrimitiveArray_HeaderFile
#include <Bnd_Box.hxx>
#include <NCollection_Sequence.hxx>
#include <Poly_Triangulation.hxx>
#include <RWGltf_GltfPrimArrayData.hxx>
#include <RWGltf_GltfPrimitiveMode.hxx>
#include <Quantity_ColorRGBA.hxx>
class RWGltf_MaterialMetallicRoughness;
class RWGltf_MaterialCommon;
//! Mesh data wrapper for delayed primitive array loading from glTF file.
//! Class inherits Poly_Triangulation so that it can be put temporarily into TopoDS_Face within assembly structure,
//! to be replaced with proper Poly_Triangulation loaded later on.
class RWGltf_GltfLatePrimitiveArray : public Poly_Triangulation
{
DEFINE_STANDARD_RTTIEXT(RWGltf_GltfLatePrimitiveArray, Poly_Triangulation)
public:
//! Constructor.
Standard_EXPORT RWGltf_GltfLatePrimitiveArray (const TCollection_AsciiString& theId,
const TCollection_AsciiString& theName);
//! Destructor.
Standard_EXPORT virtual ~RWGltf_GltfLatePrimitiveArray();
//! Entity id.
const TCollection_AsciiString& Id() const { return myId; }
//! Entity name.
const TCollection_AsciiString& Name() const { return myName; }
//! Assign entity name.
void SetName (const TCollection_AsciiString& theName) { myName = theName; }
//! Return type of primitive array.
RWGltf_GltfPrimitiveMode PrimitiveMode() const { return myPrimMode; }
//! Set type of primitive array.
void SetPrimitiveMode (RWGltf_GltfPrimitiveMode theMode) { myPrimMode = theMode; }
//! Return true if primitive array has assigned material
bool HasStyle() const { return !myMaterialPbr.IsNull() || !myMaterialCommon.IsNull(); }
//! Return base color.
Standard_EXPORT Quantity_ColorRGBA BaseColor() const;
//! Return PBR material definition.
const Handle(RWGltf_MaterialMetallicRoughness)& MaterialPbr() const { return myMaterialPbr; }
//! Set PBR material definition.
void SetMaterialPbr (const Handle(RWGltf_MaterialMetallicRoughness)& theMat) { myMaterialPbr = theMat; }
//! Return common (obsolete) material definition.
const Handle(RWGltf_MaterialCommon)& MaterialCommon() const { return myMaterialCommon; }
//! Set common (obsolete) material definition.
void SetMaterialCommon (const Handle(RWGltf_MaterialCommon)& theMat) { myMaterialCommon = theMat; }
//! Return primitive array data elements.
const NCollection_Sequence<RWGltf_GltfPrimArrayData>& Data() const { return myData; }
//! Add primitive array data element.
Standard_EXPORT RWGltf_GltfPrimArrayData& AddPrimArrayData (RWGltf_GltfArrayType theType);
//! This method sets input bounding box and assigns a FAKE data to underlying Poly_Triangulation
//! as Min/Max corners of bounding box, so that standard tools like BRepBndLib::Add()
//! can be used transparently for computing bounding box of this face.
Standard_EXPORT void SetBoundingBox (const Bnd_Box& theBox);
private:
NCollection_Sequence<RWGltf_GltfPrimArrayData> myData;
Handle(RWGltf_MaterialMetallicRoughness) myMaterialPbr; //!< PBR material
Handle(RWGltf_MaterialCommon) myMaterialCommon; //!< common (obsolete) material
Bnd_Box myBox; //!< bounding box
TCollection_AsciiString myId; //!< entity id
TCollection_AsciiString myName; //!< entity name
RWGltf_GltfPrimitiveMode myPrimMode; //!< type of primitive array
};
#endif // _RWGltf_GltfLatePrimitiveArray_HeaderFile

View File

@@ -0,0 +1,41 @@
// Author: Kirill Gavrilov
// Copyright (c) 2018-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfPrimArrayData_HeaderFile
#define _RWGltf_GltfPrimArrayData_HeaderFile
#include <NCollection_Buffer.hxx>
#include <RWGltf_GltfAccessor.hxx>
#include <RWGltf_GltfArrayType.hxx>
#include <TCollection_AsciiString.hxx>
//! An element within primitive array - vertex attribute or element indexes.
class RWGltf_GltfPrimArrayData
{
public:
Handle(NCollection_Buffer) StreamData;
TCollection_AsciiString StreamUri;
int64_t StreamOffset;
RWGltf_GltfAccessor Accessor;
RWGltf_GltfArrayType Type;
RWGltf_GltfPrimArrayData()
: StreamOffset (0), Type (RWGltf_GltfArrayType_UNKNOWN) {}
RWGltf_GltfPrimArrayData (RWGltf_GltfArrayType theType)
: StreamOffset (0), Type (theType) {}
};
#endif // _RWGltf_GltfPrimArrayData_HeaderFile

View File

@@ -0,0 +1,32 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfPrimitiveMode_HeaderFile
#define _RWGltf_GltfPrimitiveMode_HeaderFile
//! Low-level glTF enumeration defining Primitive type.
//! Similar to Graphic3d_TypeOfData but does not define actual type and includes matrices.
enum RWGltf_GltfPrimitiveMode
{
RWGltf_GltfPrimitiveMode_UNKNOWN = -1, //!< unknown or invalid type
RWGltf_GltfPrimitiveMode_Points = 0, //!< GL_POINTS
RWGltf_GltfPrimitiveMode_Lines = 1, //!< GL_LINES
RWGltf_GltfPrimitiveMode_LineLoop = 2, //!< GL_LINE_LOOP
RWGltf_GltfPrimitiveMode_LineStrip = 3, //!< GL_LINE_STRIP
RWGltf_GltfPrimitiveMode_Triangles = 4, //!< GL_TRIANGLES
RWGltf_GltfPrimitiveMode_TriangleStrip = 5, //!< GL_TRIANGLE_STRIP
RWGltf_GltfPrimitiveMode_TriangleFan = 6, //!< GL_TRIANGLE_FAN
};
#endif // _RWGltf_GltfPrimitiveMode_HeaderFile

View File

@@ -0,0 +1,73 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_GltfRootElement_HeaderFile
#define _RWGltf_GltfRootElement_HeaderFile
//! Root elements within glTF JSON document.
enum RWGltf_GltfRootElement
{
RWGltf_GltfRootElement_Asset, //!< "asset" element, mandatory
RWGltf_GltfRootElement_Scenes, //!< "scenes" element, mandatory
RWGltf_GltfRootElement_Scene, //!< "scene" element, mandatory
RWGltf_GltfRootElement_Nodes, //!< "nodes" element, mandatory
RWGltf_GltfRootElement_Meshes, //!< "meshes" element, mandatory
RWGltf_GltfRootElement_Accessors, //!< "accessors" element, mandatory
RWGltf_GltfRootElement_BufferViews, //!< "bufferViews" element, mandatory
RWGltf_GltfRootElement_Buffers, //!< "buffers" element, mandatory
RWGltf_GltfRootElement_NB_MANDATORY, //!< number of mandatory elements
// optional elements
RWGltf_GltfRootElement_Animations = RWGltf_GltfRootElement_NB_MANDATORY, //!< "animations" element
RWGltf_GltfRootElement_Materials, //!< "materials" element,
RWGltf_GltfRootElement_Programs, //!< "programs" element,
RWGltf_GltfRootElement_Samplers, //!< "samplers" element,
RWGltf_GltfRootElement_Shaders, //!< "shaders" element,
RWGltf_GltfRootElement_Skins, //!< "skins" element,
RWGltf_GltfRootElement_Techniques, //!< "techniques" element,
RWGltf_GltfRootElement_Textures, //!< "textures" element,
RWGltf_GltfRootElement_Images, //!< "images" element,
RWGltf_GltfRootElement_ExtensionsUsed, //!< "extensionsUsed" element,
RWGltf_GltfRootElement_ExtensionsRequired, //!< "extensionsRequired" element,
RWGltf_GltfRootElement_NB //!< overall number of elements
};
//! Root elements within glTF JSON document - names array.
inline const char* RWGltf_GltfRootElementName (RWGltf_GltfRootElement theElem)
{
static const char* THE_ROOT_NAMES[RWGltf_GltfRootElement_NB] =
{
"asset",
"scenes",
"scene",
"nodes",
"meshes",
"accessors",
"bufferViews",
"buffers",
"animations",
"materials",
"programs",
"samplers",
"shaders",
"skins",
"techniques",
"textures",
"images",
"extensionsUsed",
"extensionsRequired"
};
return THE_ROOT_NAMES[theElem];
}
#endif // _RWGltf_GltfRootElement_HeaderFile

View File

@@ -0,0 +1,48 @@
// Author: Kirill Gavrilov
// Copyright (c) 2016-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_MaterialCommon_HeaderFile
#define _RWGltf_MaterialCommon_HeaderFile
#include <Image_Texture.hxx>
#include <Quantity_ColorRGBA.hxx>
//! glTF 1.0 format common (obsolete) material definition.
class RWGltf_MaterialCommon : public Standard_Transient
{
public:
Handle(Image_Texture) AmbientTexture; //!< image defining ambient color
Handle(Image_Texture) DiffuseTexture; //!< image defining diffuse color
Handle(Image_Texture) SpecularTexture; //!< image defining specular color
TCollection_AsciiString Id; //!< material identifier
TCollection_AsciiString Name; //!< material name
Quantity_Color AmbientColor;
Quantity_Color DiffuseColor;
Quantity_Color SpecularColor;
Quantity_Color EmissiveColor;
Standard_ShortReal Shininess;
Standard_ShortReal Transparency;
RWGltf_MaterialCommon()
: AmbientColor (0.1, 0.1, 0.1, Quantity_TOC_RGB),
DiffuseColor (0.8, 0.8, 0.8, Quantity_TOC_RGB),
SpecularColor(0.2, 0.2, 0.2, Quantity_TOC_RGB),
EmissiveColor(0.0, 0.0, 0.0, Quantity_TOC_RGB),
Shininess (1.0f),
Transparency (0.0f) {}
};
#endif // _RWGltf_MaterialCommon_HeaderFile

View File

@@ -0,0 +1,50 @@
// Author: Kirill Gavrilov
// Copyright (c) 2015-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_MaterialMetallicRoughness_HeaderFile
#define _RWGltf_MaterialMetallicRoughness_HeaderFile
#include <Graphic3d_Vec.hxx>
#include <Quantity_ColorRGBA.hxx>
#include <Standard_Transient.hxx>
#include <TCollection_AsciiString.hxx>
class Image_Texture;
//! glTF 2.0 format PBR material definition.
class RWGltf_MaterialMetallicRoughness : public Standard_Transient
{
public:
Handle(Image_Texture) BaseColorTexture; //!< RGB texture for the base color
Handle(Image_Texture) MetallicRoughnessTexture; //!< RG texture packing the metallic and roughness properties together
Handle(Image_Texture) EmissiveTexture; //!< RGB emissive map controls the color and intensity of the light being emitted by the material
Handle(Image_Texture) OcclusionTexture; //!< R occlusion map indicating areas of indirect lighting
Handle(Image_Texture) NormalTexture; //!< normal map
TCollection_AsciiString Id; //!< material identifier
TCollection_AsciiString Name; //!< material name
Quantity_ColorRGBA BaseColor; //!< base color (or scale factor to the texture); [1.0, 1.0, 1.0, 1.0] by default
Graphic3d_Vec3 EmissiveFactor; //!< emissive color; [0.0, 0.0, 0.0] by default
Standard_ShortReal Metallic; //!< metalness (or scale factor to the texture) within range [0.0, 1.0]; 1.0 by default
Standard_ShortReal Roughness; //!< roughness (or scale factor to the texture) within range [0.0, 1.0]; 1.0 by default
RWGltf_MaterialMetallicRoughness()
: BaseColor (1.0f, 1.0f, 1.0f, 1.0f),
EmissiveFactor (0.0f, 0.0f, 0.0f),
Metallic (0.0f),
Roughness (0.0f) {}
};
#endif // _RWGltf_MaterialMetallicRoughness_HeaderFile

View File

@@ -0,0 +1,101 @@
// Author: Kirill Gavrilov
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <RWGltf_PrimitiveArrayReader.hxx>
#include <RWGltf_GltfLatePrimitiveArray.hxx>
#include <BRep_Builder.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <OSD_OpenFile.hxx>
#include <Standard_ArrayStreamBuffer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Iterator.hxx>
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_PrimitiveArrayReader, Standard_Transient)
// =======================================================================
// function : reportError
// purpose :
// =======================================================================
void RWGltf_PrimitiveArrayReader::reportError (const TCollection_AsciiString& theText)
{
Message::DefaultMessenger()->Send (myErrorPrefix + theText, Message_Fail);
}
// =======================================================================
// function : load
// purpose :
// =======================================================================
bool RWGltf_PrimitiveArrayReader::load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh)
{
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;
}
if (mySharedStream.Path != aData.StreamUri)
{
mySharedStream.Stream.close();
mySharedStream.Path = aData.StreamUri;
}
if (!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;
}
}
mySharedStream.Stream.seekg ((std::streamoff )aData.StreamOffset, std::ios_base::beg);
if (!mySharedStream.Stream.good())
{
mySharedStream.Stream.close();
reportError (TCollection_AsciiString ("Buffer '") + theMesh->Id() + "refers to invalid location.");
return false;
}
if (!readBuffer (mySharedStream.Stream, theMesh->Id(), aData.Accessor, aData.Type, theMesh->PrimitiveMode()))
{
return false;
}
}
return true;
}

View File

@@ -0,0 +1,100 @@
// Author: Kirill Gavrilov
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_PrimitiveArrayReader_HeaderFile
#define _RWGltf_PrimitiveArrayReader_HeaderFile
#include <Poly_Triangulation.hxx>
#include <RWMesh_CoordinateSystemConverter.hxx>
#include <RWGltf_GltfAccessor.hxx>
#include <RWGltf_GltfArrayType.hxx>
#include <RWGltf_GltfPrimitiveMode.hxx>
#include <TCollection_AsciiString.hxx>
class RWGltf_GltfLatePrimitiveArray;
//! The interface for shared file.
struct RWGltf_GltfSharedIStream
{
std::ifstream Stream; //!< shared file
TCollection_AsciiString Path; //!< path to currently opened stream
};
//! Interface for reading primitive array from glTF buffer.
class RWGltf_PrimitiveArrayReader : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(RWGltf_PrimitiveArrayReader, Standard_Transient)
public:
//! Constructor.
RWGltf_PrimitiveArrayReader() {}
//! Return prefix for reporting issues.
const TCollection_AsciiString& ErrorPrefix() const { return myErrorPrefix; }
//! Set prefix for reporting issues.
void SetErrorPrefix (const TCollection_AsciiString& theErrPrefix) { myErrorPrefix = theErrPrefix; }
//! Return transformation from glTF to OCCT coordinate system.
const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCoordSysConverter; }
//! Set transformation from glTF to OCCT coordinate system.
void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCoordSysConverter = theConverter; }
//! Load primitive array.
Handle(Poly_Triangulation) Load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh)
{
if (load (theMesh))
{
return result();
}
return Handle(Poly_Triangulation)();
}
protected:
//! Reset cache before loading primitive array.
Standard_EXPORT virtual void reset() = 0;
//! Load primitive array.
Standard_EXPORT virtual bool load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh);
//! Return result primitive array.
Standard_EXPORT virtual Handle(Poly_Triangulation) result() = 0;
//! Read primitive array data.
//! @param theStream input stream to read from
//! @param theName entity name for logging errors
//! @param theAccessor buffer accessor
//! @param theType array type
//! @param theMode primitive mode
//! @return FALSE on error
Standard_EXPORT virtual bool readBuffer (std::istream& theStream,
const TCollection_AsciiString& theName,
const RWGltf_GltfAccessor& theAccessor,
RWGltf_GltfArrayType theType,
RWGltf_GltfPrimitiveMode theMode) = 0;
//! Report error.
Standard_EXPORT virtual void reportError (const TCollection_AsciiString& theText);
protected:
TCollection_AsciiString myErrorPrefix;
RWGltf_GltfSharedIStream mySharedStream;
RWMesh_CoordinateSystemConverter myCoordSysConverter;
};
#endif // _RWGltf_PrimitiveArrayReader_HeaderFile

View File

@@ -0,0 +1,434 @@
// Author: Kirill Gavrilov
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <RWGltf_TriangulationReader.hxx>
#include <RWMesh_CoordinateSystemConverter.hxx>
#include <Standard_ReadBuffer.hxx>
#include <BRep_Builder.hxx>
#include <Graphic3d_Vec.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Iterator.hxx>
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;
}
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWGltf_PrimitiveArrayReader)
// =======================================================================
// function : RWGltf_TriangulationReader
// purpose :
// =======================================================================
RWGltf_TriangulationReader::RWGltf_TriangulationReader()
{
//
}
// =======================================================================
// function : reset
// purpose :
// =======================================================================
void RWGltf_TriangulationReader::reset()
{
myTriangulation = new Poly_Triangulation (1, 1, true);
{
TColgp_Array1OfPnt anEmpty;
myTriangulation->ChangeNodes().Move (anEmpty);
}
{
TColgp_Array1OfPnt2d anEmpty;
myTriangulation->ChangeUVNodes().Move (anEmpty);
}
{
Poly_Array1OfTriangle anEmpty;
myTriangulation->ChangeTriangles().Move (anEmpty);
}
}
// =======================================================================
// function : result
// purpose :
// =======================================================================
Handle(Poly_Triangulation) RWGltf_TriangulationReader::result()
{
if (myTriangulation->NbNodes() < 1)
{
return Handle(Poly_Triangulation)();
}
if (myTriangulation->UVNodes().Size() != myTriangulation->NbNodes())
{
myTriangulation->RemoveUVNodes();
}
if (myTriangulation->NbTriangles() < 1)
{
// reconstruct indexes
const Standard_Integer aNbTris = myTriangulation->NbNodes() / 3;
if (!setNbTriangles (aNbTris))
{
return Handle(Poly_Triangulation)();
}
for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
{
setTriangle (THE_LOWER_TRI_INDEX + aTriIter,
Poly_Triangle (THE_LOWER_NODE_INDEX + aTriIter * 3 + 0,
THE_LOWER_NODE_INDEX + aTriIter * 3 + 1,
THE_LOWER_NODE_INDEX + aTriIter * 3 + 2));
}
}
return myTriangulation;
}
// =======================================================================
// function : readBuffer
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
const TCollection_AsciiString& theName,
const RWGltf_GltfAccessor& theAccessor,
RWGltf_GltfArrayType theType,
RWGltf_GltfPrimitiveMode theMode)
{
if (theMode != RWGltf_GltfPrimitiveMode_Triangles)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString("Buffer '") + theName + "' skipped unsupported primitive array.", Message_Warning);
return true;
}
switch (theType)
{
case RWGltf_GltfArrayType_Indices:
{
if (theAccessor.Type != RWGltf_GltfAccessorLayout_Scalar)
{
break;
}
Poly_Triangle aVec3;
if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt16)
{
if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
return false;
}
const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3);
if (!setNbTriangles (aNbTris))
{
return false;
}
const size_t aStride = theAccessor.ByteStride != 0
? theAccessor.ByteStride
: sizeof(uint16_t);
Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
{
if (const uint16_t* anIndex0 = aBuffer.ReadChunk<uint16_t> (theStream))
{
aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + *anIndex0;
}
if (const uint16_t* anIndex1 = aBuffer.ReadChunk<uint16_t> (theStream))
{
aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + *anIndex1;
}
if (const uint16_t* anIndex2 = aBuffer.ReadChunk<uint16_t> (theStream))
{
aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + *anIndex2;
}
else
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
return false;
}
if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
}
}
}
else if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt32)
{
if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
return false;
}
const int aNbTris = (Standard_Integer )(theAccessor.Count / 3);
if (!setNbTriangles (aNbTris))
{
return false;
}
const size_t aStride = theAccessor.ByteStride != 0
? theAccessor.ByteStride
: sizeof(uint32_t);
Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
{
if (const uint32_t* anIndex0 = aBuffer.ReadChunk<uint32_t> (theStream))
{
aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + *anIndex0;
}
if (const uint32_t* anIndex1 = aBuffer.ReadChunk<uint32_t> (theStream))
{
aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + *anIndex1;
}
if (const uint32_t* anIndex2 = aBuffer.ReadChunk<uint32_t> (theStream))
{
aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + *anIndex2;
}
else
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
return false;
}
if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
}
}
}
else if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt8)
{
if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
return false;
}
const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3);
if (!setNbTriangles (aNbTris))
{
return false;
}
const size_t aStride = theAccessor.ByteStride != 0
? theAccessor.ByteStride
: sizeof(uint8_t);
Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
{
if (const uint8_t* anIndex0 = aBuffer.ReadChunk<uint8_t> (theStream))
{
aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + (Standard_Integer )*anIndex0;
}
if (const uint8_t* anIndex1 = aBuffer.ReadChunk<uint8_t> (theStream))
{
aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + (Standard_Integer )*anIndex1;
}
if (const uint8_t* anIndex2 = aBuffer.ReadChunk<uint8_t> (theStream))
{
aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + (Standard_Integer )*anIndex2;
}
else
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
return false;
}
if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
}
}
}
else
{
break;
}
break;
}
case RWGltf_GltfArrayType_Position:
{
if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
|| theAccessor.Type != RWGltf_GltfAccessorLayout_Vec3)
{
break;
}
else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
return false;
}
const size_t aStride = theAccessor.ByteStride != 0
? theAccessor.ByteStride
: sizeof(Graphic3d_Vec3);
const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
if (!setNbPositionNodes (aNbNodes))
{
return false;
}
Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
if (!myCoordSysConverter.IsEmpty())
{
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
if (aVec3 == NULL)
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
return false;
}
gp_Pnt anXYZ (aVec3->x(), aVec3->y(), aVec3->z());
myCoordSysConverter.TransformPosition (anXYZ.ChangeCoord());
setNodePosition (THE_LOWER_NODE_INDEX + aVertIter, anXYZ);
}
}
else
{
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
if (aVec3 == NULL)
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
return false;
}
setNodePosition (THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt (aVec3->x(), aVec3->y(), aVec3->z()));
}
}
break;
}
case RWGltf_GltfArrayType_Normal:
{
if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
|| theAccessor.Type != RWGltf_GltfAccessorLayout_Vec3)
{
break;
}
else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
return false;
}
const size_t aStride = theAccessor.ByteStride != 0
? theAccessor.ByteStride
: sizeof(Graphic3d_Vec3);
const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
if (!setNbNormalNodes (aNbNodes))
{
return false;
}
Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
if (!myCoordSysConverter.IsEmpty())
{
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
if (aVec3 == NULL)
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
return false;
}
if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
{
myCoordSysConverter.TransformNormal (*aVec3);
setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (aVec3->x(), aVec3->y(), aVec3->z()));
}
else
{
setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (0.0, 0.0, 1.0));
}
}
}
else
{
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
if (aVec3 == NULL)
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
return false;
}
if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
{
setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (aVec3->x(), aVec3->y(), aVec3->z()));
}
else
{
setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (0.0, 0.0, 1.0));
}
}
}
break;
}
case RWGltf_GltfArrayType_TCoord0:
{
if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
|| theAccessor.Type != RWGltf_GltfAccessorLayout_Vec2)
{
break;
}
else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
return false;
}
const size_t aStride = theAccessor.ByteStride != 0
? theAccessor.ByteStride
: sizeof(Graphic3d_Vec2);
const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
if (!setNbUVNodes (aNbNodes))
{
return false;
}
Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
for (int aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
Graphic3d_Vec2* aVec2 = aBuffer.ReadChunk<Graphic3d_Vec2> (theStream);
if (aVec2 == NULL)
{
reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
return false;
}
// Y should be flipped (relative to image layout used by OCCT)
aVec2->y() = 1.0f - aVec2->y();
setNodeUV (THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt2d (aVec2->x(), aVec2->y()));
}
break;
}
case RWGltf_GltfArrayType_Color:
case RWGltf_GltfArrayType_TCoord1:
case RWGltf_GltfArrayType_Joint:
case RWGltf_GltfArrayType_Weight:
{
return true;
}
case RWGltf_GltfArrayType_UNKNOWN:
{
return false;
}
}
return true;
}

View File

@@ -0,0 +1,148 @@
// Author: Kirill Gavrilov
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWGltf_TriangulationReader_HeaderFile
#define _RWGltf_TriangulationReader_HeaderFile
#include <RWGltf_PrimitiveArrayReader.hxx>
//! RWGltf_PrimitiveArrayReader implementation creating Poly_Triangulation.
class RWGltf_TriangulationReader : public RWGltf_PrimitiveArrayReader
{
DEFINE_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWGltf_PrimitiveArrayReader)
public:
//! Empty constructor.
Standard_EXPORT RWGltf_TriangulationReader();
protected:
//! Create Poly_Triangulation from collected data
Standard_EXPORT virtual Handle(Poly_Triangulation) result() Standard_OVERRIDE;
//! Reset cache before loading primitive array.
Standard_EXPORT virtual void reset() Standard_OVERRIDE;
//! Fill triangulation data and ignore non-triangulation primitives.
//! @param theStream input stream to read from
//! @param theName entity name for logging errors
//! @param theAccessor buffer accessor
//! @param theType array type
//! @param theMode primitive mode
//! @return FALSE on error
Standard_EXPORT virtual bool readBuffer (std::istream& theStream,
const TCollection_AsciiString& theName,
const RWGltf_GltfAccessor& theAccessor,
RWGltf_GltfArrayType theType,
RWGltf_GltfPrimitiveMode theMode) Standard_OVERRIDE;
protected: //! @name interface for filling triangulation data
//! Resize array of position nodes to specified size.
virtual bool setNbPositionNodes (Standard_Integer theNbNodes)
{
if (theNbNodes <= 0)
{
return false;
}
myTriangulation->ChangeNodes().Resize (1, theNbNodes, false);
return true;
}
//! Set node position.
//! @param theIndex node index starting from 1
//! @param thePnt node position
virtual void setNodePosition (Standard_Integer theIndex,
const gp_Pnt& thePnt)
{
myTriangulation->ChangeNode (theIndex) = thePnt;
}
//! Resize array of UV nodes to specified size.
virtual bool setNbUVNodes (Standard_Integer theNbNodes)
{
if (theNbNodes <= 0
|| myTriangulation->NbNodes() != theNbNodes)
{
return false;
}
myTriangulation->ChangeUVNodes().Resize (1, theNbNodes, false);
return true;
}
//! Set node UV texture coordinates.
//! @param theIndex node index starting from 1
//! @param theUV node UV coordinates
virtual void setNodeUV (Standard_Integer theIndex,
const gp_Pnt2d& theUV)
{
myTriangulation->ChangeUVNode (theIndex) = theUV;
}
//! Resize array of nodes normals to specified size.
virtual bool setNbNormalNodes (Standard_Integer theNbNodes)
{
if (theNbNodes <= 0
|| myTriangulation->NbNodes() != theNbNodes)
{
return false;
}
myTriangulation->SetNormals (new TShort_HArray1OfShortReal (1, theNbNodes * 3));
return true;
}
//! Set node normal.
//! @param theIndex node index starting from 1
//! @param theNormal node normal
virtual void setNodeNormal (Standard_Integer theIndex,
const gp_Dir& theNormal)
{
myTriangulation->SetNormal (theIndex, theNormal);
}
//! Resize array of triangles to specified size.
virtual bool setNbTriangles (Standard_Integer theNbTris)
{
if (theNbTris >= 1)
{
myTriangulation->ChangeTriangles().Resize (1, theNbTris, false);
return true;
}
return false;
}
//! Add triangle element.
//! @param theIndex triangle index starting from 1
//! @param theTriangle triangle nodes starting from 1
//! @return FALSE if node indexes are out of range
virtual bool setTriangle (Standard_Integer theIndex,
const Poly_Triangle& theTriangle)
{
if (theTriangle.Value (1) < myTriangulation->Nodes().Lower() || theTriangle.Value (1) > myTriangulation->Nodes().Upper()
|| theTriangle.Value (2) < myTriangulation->Nodes().Lower() || theTriangle.Value (2) > myTriangulation->Nodes().Upper()
|| theTriangle.Value (3) < myTriangulation->Nodes().Lower() || theTriangle.Value (3) > myTriangulation->Nodes().Upper())
{
return false;
}
myTriangulation->ChangeTriangle (theIndex) = theTriangle;
return true;
}
protected:
Handle(Poly_Triangulation) myTriangulation;
};
#endif // _RWGltf_TriangulationReader_HeaderFile

14
src/RWObj/FILES Normal file
View File

@@ -0,0 +1,14 @@
RWObj.cxx
RWObj.hxx
RWObj_CafReader.cxx
RWObj_CafReader.hxx
RWObj_Material.hxx
RWObj_MtlReader.cxx
RWObj_MtlReader.hxx
RWObj_Reader.cxx
RWObj_Reader.hxx
RWObj_SubMesh.hxx
RWObj_SubMeshReason.hxx
RWObj_Tools.hxx
RWObj_TriangulationReader.cxx
RWObj_TriangulationReader.hxx

32
src/RWObj/RWObj.cxx Normal file
View File

@@ -0,0 +1,32 @@
// Author: Kirill Gavrilov
// Copyright (c) 2017-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <RWObj.hxx>
#include <RWObj_TriangulationReader.hxx>
//=============================================================================
//function : Read
//purpose :
//=============================================================================
Handle(Poly_Triangulation) RWObj::ReadFile (const Standard_CString theFile,
const Handle(Message_ProgressIndicator)& theProgress)
{
RWObj_TriangulationReader aReader;
aReader.SetCreateShapes (Standard_False);
aReader.Read (theFile, theProgress);
// note that returned bool value is ignored intentionally -- even if something went wrong,
// but some data have been read, we at least will return these data
return aReader.GetTriangulation();
}

35
src/RWObj/RWObj.hxx Normal file
View File

@@ -0,0 +1,35 @@
// Author: Kirill Gavrilov
// Copyright (c) 2017-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWObj_HeaderFile
#define _RWObj_HeaderFile
#include <Message_ProgressIndicator.hxx>
#include <OSD_Path.hxx>
#include <Poly_Triangulation.hxx>
#include <Standard_Macro.hxx>
//! This class provides methods to read and write triangulation from / to the OBJ files.
class RWObj
{
public:
//! Read specified OBJ file and returns its content as triangulation.
//! In case of error, returns Null handle.
Standard_EXPORT static Handle(Poly_Triangulation) ReadFile (const Standard_CString theFile,
const Handle(Message_ProgressIndicator)& aProgInd = NULL);
};
#endif // _RWObj_HeaderFile

View File

@@ -0,0 +1,104 @@
// Author: Kirill Gavrilov
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <RWObj_CafReader.hxx>
#include <Message_ProgressSentry.hxx>
IMPLEMENT_STANDARD_RTTIEXT(RWObj_CafReader, RWMesh_CafReader)
//================================================================
// Function : Constructor
// Purpose :
//================================================================
RWObj_CafReader::RWObj_CafReader()
: myIsSinglePrecision (Standard_False)
{
//myCoordSysConverter.SetInputLengthUnit (-1.0); // length units are undefined within OBJ file
// OBJ format does not define coordinate system (apart from mentioning that it is right-handed),
// however most files are stored Y-up
myCoordSysConverter.SetInputCoordinateSystem (RWMesh_CoordinateSystem_glTF);
}
//================================================================
// Function : BindNamedShape
// Purpose :
//================================================================
void RWObj_CafReader::BindNamedShape (const TopoDS_Shape& theShape,
const TCollection_AsciiString& theName,
const RWObj_Material* theMaterial,
const Standard_Boolean theIsRootShape)
{
if (theShape.IsNull())
{
return;
}
RWMesh_NodeAttributes aShapeAttribs;
aShapeAttribs.Name = theName;
if (theMaterial != NULL)
{
aShapeAttribs.Style.SetColorSurf (Quantity_ColorRGBA (theMaterial->DiffuseColor, 1.0f - theMaterial->Transparency));
}
myAttribMap.Bind (theShape, aShapeAttribs);
if (theIsRootShape)
{
myRootShapes.Append (theShape);
}
}
//================================================================
// Function : createReaderContext
// Purpose :
//================================================================
Handle(RWObj_TriangulationReader) RWObj_CafReader::createReaderContext()
{
Handle(RWObj_TriangulationReader) aReader = new RWObj_TriangulationReader();
return aReader;
}
//================================================================
// Function : performMesh
// Purpose :
//================================================================
Standard_Boolean RWObj_CafReader::performMesh (const TCollection_AsciiString& theFile,
const Handle(Message_ProgressIndicator)& theProgress,
const Standard_Boolean theToProbe)
{
Handle(RWObj_TriangulationReader) aCtx = createReaderContext();
aCtx->SetSinglePrecision (myIsSinglePrecision);
aCtx->SetCreateShapes (Standard_True);
aCtx->SetShapeReceiver (this);
aCtx->SetTransformation (myCoordSysConverter);
aCtx->SetMemoryLimit (myMemoryLimitMiB == -1 ? Standard_Size(-1) : Standard_Size(myMemoryLimitMiB * 1024 * 1024));
Standard_Boolean isDone = Standard_False;
if (theToProbe)
{
isDone = aCtx->Probe (theFile.ToCString(), theProgress);
}
else
{
isDone = aCtx->Read (theFile.ToCString(), theProgress);
}
if (!aCtx->FileComments().IsEmpty())
{
myMetadata.Add ("Comments", aCtx->FileComments());
}
for (NCollection_IndexedMap<TCollection_AsciiString>::Iterator aFileIter (aCtx->ExternalFiles()); aFileIter.More(); aFileIter.Next())
{
myExternalFiles.Add (aFileIter.Value());
}
return isDone;
}

View File

@@ -0,0 +1,63 @@
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWObj_CafReader_HeaderFile
#define _RWObj_CafReader_HeaderFile
#include <RWMesh_CafReader.hxx>
#include <RWObj_TriangulationReader.hxx>
//! The OBJ mesh reader into XDE document.
class RWObj_CafReader : public RWMesh_CafReader, protected RWObj_IShapeReceiver
{
DEFINE_STANDARD_RTTIEXT(RWObj_CafReader, RWMesh_CafReader)
public:
//! Empty constructor.
Standard_EXPORT RWObj_CafReader();
//! Return single precision flag for reading vertex data (coordinates); FALSE by default.
Standard_Boolean IsSinglePrecision() const { return myIsSinglePrecision; }
//! Setup single/double precision flag for reading vertex data (coordinates).
void SetSinglePrecision (Standard_Boolean theIsSinglePrecision) { myIsSinglePrecision = theIsSinglePrecision; }
protected:
//! Read the mesh from specified file.
Standard_EXPORT virtual Standard_Boolean performMesh (const TCollection_AsciiString& theFile,
const Handle(Message_ProgressIndicator)& theProgress,
const Standard_Boolean theToProbe) Standard_OVERRIDE;
protected:
//! Create reader context.
//! Can be overridden by sub-class to read triangulation into application-specific data structures instead of Poly_Triangulation.
virtual Handle(RWObj_TriangulationReader) createReaderContext();
//! @param theShape shape to register
//! @param theName shape name
//! @param theMaterial shape material
//! @param theIsRootShape indicates that this is a root object (free shape)
virtual void BindNamedShape (const TopoDS_Shape& theShape,
const TCollection_AsciiString& theName,
const RWObj_Material* theMaterial,
const Standard_Boolean theIsRootShape) Standard_OVERRIDE;
protected:
Standard_Boolean myIsSinglePrecision; //!< flag for reading vertex data with single or double floating point precision
};
#endif // _RWObj_CafReader_HeaderFile

View File

@@ -0,0 +1,43 @@
// Author: Kirill Gavrilov
// Copyright (c) 2015-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWObj_Material_HeaderFile
#define _RWObj_Material_HeaderFile
#include <Quantity_Color.hxx>
#include <TCollection_AsciiString.hxx>
//! Material definition for OBJ file format.
struct RWObj_Material
{
TCollection_AsciiString Name; //!< material name (identifier) as defined in MTL file
TCollection_AsciiString DiffuseTexture; //!< path to the texture image file defining diffuse color
TCollection_AsciiString SpecularTexture; //!< path to the texture image file defining specular color
TCollection_AsciiString BumpTexture; //!< path to the texture image file defining normal map
Quantity_Color AmbientColor;
Quantity_Color DiffuseColor;
Quantity_Color SpecularColor;
Standard_ShortReal Shininess;
Standard_ShortReal Transparency;
RWObj_Material()
: AmbientColor (0.1, 0.1, 0.1, Quantity_TOC_RGB),
DiffuseColor (0.8, 0.8, 0.8, Quantity_TOC_RGB),
SpecularColor(0.2, 0.2, 0.2, Quantity_TOC_RGB),
Shininess (1.0f),
Transparency (0.0f) {}
};
#endif // _RWObj_Material_HeaderFile

View File

@@ -0,0 +1,351 @@
// Author: Kirill Gavrilov
// Copyright (c) 2017-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <RWObj_MtlReader.hxx>
#include <RWObj_Tools.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <OSD_File.hxx>
#include <OSD_OpenFile.hxx>
#include <OSD_Path.hxx>
namespace
{
//! Try to find a new location of the file relative to specified folder from absolute path.
//! @param theAbsolutePath original absolute file path
//! @param theNewFoler the new folder to look for the file
//! @param theRelativePath result file path relative to theNewFoler
//! @return true if relative file has been found
static bool findRelativePath (const TCollection_AsciiString& theAbsolutePath,
const TCollection_AsciiString& theNewFoler,
TCollection_AsciiString& theRelativePath)
{
TCollection_AsciiString aNewFoler = (theNewFoler.EndsWith ("\\") || theNewFoler.EndsWith ("/"))
? theNewFoler
: (theNewFoler + "/");
TCollection_AsciiString aRelPath;
TCollection_AsciiString aPath = theAbsolutePath;
for (;;)
{
TCollection_AsciiString aFolder, aFileName;
OSD_Path::FolderAndFileFromPath (aPath, aFolder, aFileName);
if (aFolder.IsEmpty()
|| aFileName.IsEmpty())
{
return false;
}
if (aRelPath.IsEmpty())
{
aRelPath = aFileName;
}
else
{
aRelPath = aFileName + "/" + aRelPath;
}
if (OSD_File (aNewFoler + aRelPath).Exists())
{
theRelativePath = aRelPath;
return true;
}
aPath = aFolder;
}
}
}
// =======================================================================
// function : RWObj_MtlReader
// purpose :
// =======================================================================
RWObj_MtlReader::RWObj_MtlReader (NCollection_DataMap<TCollection_AsciiString, RWObj_Material>& theMaterials)
: myFile (NULL),
myMaterials (&theMaterials),
myNbLines (0)
{
//
}
// =======================================================================
// function : ~RWObj_MtlReader
// purpose :
// =======================================================================
RWObj_MtlReader::~RWObj_MtlReader()
{
if (myFile != NULL)
{
::fclose (myFile);
}
}
// =======================================================================
// function : Read
// purpose :
// =======================================================================
bool RWObj_MtlReader::Read (const TCollection_AsciiString& theFolder,
const TCollection_AsciiString& theFile)
{
myPath = theFolder + theFile;
myFile = OSD_OpenFile (myPath.ToCString(), "rb");
if (myFile == NULL)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("OBJ material file '") + myPath + "' is not found!", Message_Warning);
return Standard_False;
}
char aLine[256] = {};
TCollection_AsciiString aMatName;
RWObj_Material aMat;
const Standard_Integer aNbMatOld = myMaterials->Extent();
bool hasAspect = false;
for (; ::feof (myFile) == 0 && ::fgets (aLine, 255, myFile) != NULL; )
{
++myNbLines;
const char* aPos = aLine;
// skip spaces
for (; IsSpace(*aPos);)
{
++aPos;
}
if (*aPos == '#'
|| *aPos == '\n'
|| *aPos == '\0')
{
continue;
}
if (::memcmp (aPos, "newmtl", 6) == 0)
{
aPos += 7;
if (!aMatName.IsEmpty())
{
if (hasAspect)
{
aMat.Name = aMatName;
}
else
{
// reset incomplete material definition
aMat = RWObj_Material();
}
myMaterials->Bind (aMatName, aMat);
hasAspect = false;
}
aMatName = TCollection_AsciiString(aPos);
aMat = RWObj_Material();
if (!RWObj_Tools::ReadName (aPos, aMatName))
{
Message::DefaultMessenger()->Send (TCollection_AsciiString("Empty OBJ material at line ") + myNbLines + " in file " + myPath, Message_Warning);
}
}
else if (::memcmp (aPos, "Ka", 2) == 0
&& IsSpace (aPos[2]))
{
aPos += 3;
char* aNext = NULL;
Graphic3d_Vec3 aColor;
RWObj_Tools::ReadVec3 (aPos, aNext, aColor);
aPos = aNext;
if (validateColor (aColor))
{
aMat.AmbientColor = Quantity_Color (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB);
hasAspect = true;
}
}
else if (::memcmp (aPos, "Kd", 2) == 0
&& IsSpace (aPos[2]))
{
aPos += 3;
char* aNext = NULL;
Graphic3d_Vec3 aColor;
RWObj_Tools::ReadVec3 (aPos, aNext, aColor);
aPos = aNext;
if (validateColor (aColor))
{
aMat.DiffuseColor = Quantity_Color (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB);
hasAspect = true;
}
}
else if (::memcmp (aPos, "Ks", 2) == 0
&& IsSpace (aPos[2]))
{
aPos += 3;
char* aNext = NULL;
Graphic3d_Vec3 aColor;
RWObj_Tools::ReadVec3 (aPos, aNext, aColor);
aPos = aNext;
if (validateColor (aColor))
{
aMat.SpecularColor = Quantity_Color (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB);
}
}
else if (::memcmp (aPos, "Ns", 2) == 0
&& IsSpace (aPos[2]))
{
aPos += 3;
char* aNext = NULL;
double aSpecular = Strtod (aPos, &aNext);
aPos = aNext;
if (aSpecular >= 0.0)
{
aMat.Shininess = (float )Min (aSpecular / 1000.0, 1.0);
}
}
else if (::memcmp (aPos, "Tr", 2) == 0
&& IsSpace (aPos[2]))
{
aPos += 3;
char* aNext = NULL;
double aTransp = Strtod (aPos, &aNext);
aPos = aNext;
if (validateScalar (aTransp)
&& aTransp <= 0.99)
{
aMat.Transparency = (float )aTransp;
}
}
else if (*aPos == 'd' && IsSpace (aPos[1]))
{
// dissolve
aPos += 2;
char* aNext = NULL;
double anAlpha = Strtod (aPos, &aNext);
aPos = aNext;
if (validateScalar (anAlpha)
&& anAlpha >= 0.01)
{
aMat.Transparency = float(1.0 - anAlpha);
}
}
else if (::memcmp (aPos, "map_Kd", 6) == 0
&& IsSpace (aPos[6]))
{
aPos += 7;
if (RWObj_Tools::ReadName (aPos, aMat.DiffuseTexture))
{
processTexturePath (aMat.DiffuseTexture, theFolder);
}
}
else if (::memcmp (aPos, "map_Ks", 6) == 0
&& IsSpace (aPos[6]))
{
aPos += 7;
if (RWObj_Tools::ReadName (aPos, aMat.SpecularTexture))
{
processTexturePath (aMat.SpecularTexture, theFolder);
}
}
else if (::memcmp (aPos, "map_Bump", 8) == 0
&& IsSpace (aPos[8]))
{
aPos += 9;
if (RWObj_Tools::ReadName (aPos, aMat.BumpTexture))
{
processTexturePath (aMat.BumpTexture, theFolder);
}
}
/*else if (::memcmp (aPos, "illum", 5) == 0)
{
aPos += 6;
char* aNext = NULL;
const int aModel = strtol (aPos, &aNext, 10);
aPos = aNext;
if (aModel < 0 || aModel > 10)
{
// unknown model
}
}*/
}
if (!aMatName.IsEmpty())
{
if (hasAspect)
{
aMat.Name = aMatName;
}
else
{
// reset incomplete material definition
aMat = RWObj_Material();
}
myMaterials->Bind (aMatName, aMat);
}
return myMaterials->Extent() != aNbMatOld;
}
// =======================================================================
// function : processTexturePath
// purpose :
// =======================================================================
void RWObj_MtlReader::processTexturePath (TCollection_AsciiString& theTexturePath,
const TCollection_AsciiString& theFolder)
{
if (OSD_Path::IsAbsolutePath (theTexturePath.ToCString()))
{
Message::DefaultMessenger()->Send (TCollection_AsciiString("OBJ file specifies absolute path to the texture image file which may be inaccessible on another device\n")
+ theTexturePath, Message_Warning);
if (!OSD_File (theTexturePath).Exists())
{
// workaround absolute filenames - try to find the same file at the OBJ file location
TCollection_AsciiString aRelativePath;
if (findRelativePath (theTexturePath, theFolder, aRelativePath))
{
theTexturePath = theFolder + aRelativePath;
}
}
}
else
{
theTexturePath = theFolder + theTexturePath;
}
}
// =======================================================================
// function : validateScalar
// purpose :
// =======================================================================
bool RWObj_MtlReader::validateScalar (const Standard_Real theValue)
{
if (theValue < 0.0
|| theValue > 1.0)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid scalar in OBJ material at line ") + myNbLines + " in file " + myPath, Message_Warning);
return false;
}
return true;
}
// =======================================================================
// function : validateColor
// purpose :
// =======================================================================
bool RWObj_MtlReader::validateColor (const Graphic3d_Vec3& theVec)
{
if (theVec.r() < 0.0f || theVec.r() > 1.0f
|| theVec.g() < 0.0f || theVec.g() > 1.0f
|| theVec.b() < 0.0f || theVec.b() > 1.0f)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString("Invalid color in OBJ material at line ") + myNbLines + " in file " + myPath, Message_Warning);
return false;
}
return true;
}

View File

@@ -0,0 +1,58 @@
// Author: Kirill Gavrilov
// Copyright (c) 2015-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _RWObj_MtlReader_HeaderFile
#define _RWObj_MtlReader_HeaderFile
#include <Graphic3d_Vec3.hxx>
#include <RWObj_Material.hxx>
#include <NCollection_DataMap.hxx>
//! Reader of mtl files.
class RWObj_MtlReader
{
public:
//! Main constructor.
RWObj_MtlReader (NCollection_DataMap<TCollection_AsciiString, RWObj_Material>& theMaterials);
//! Destructor.
~RWObj_MtlReader();
//! Read the file.
bool Read (const TCollection_AsciiString& theFolder,
const TCollection_AsciiString& theFile);
private:
//! Validate scalar value
bool validateScalar (const Standard_Real theValue);
//! Validate RGB color
bool validateColor (const Graphic3d_Vec3& theVec);
//! Process texture path.
void processTexturePath (TCollection_AsciiString& theTexturePath,
const TCollection_AsciiString& theFolder);
private:
FILE* myFile;
TCollection_AsciiString myPath;
NCollection_DataMap<TCollection_AsciiString, RWObj_Material>* myMaterials;
int myNbLines;
};
#endif // _RWObj_MtlReader_HeaderFile

Some files were not shown because too many files have changed in this diff Show More