Compare commits

..
Author SHA1 Message Date
Kim Kulling 1a4d4fb545 Enable C++17 and C99
- closes https://github.com/assimp/assimp/issues/4257
2021-12-16 19:41:09 +01:00
Kim Kulling c4d858cf4d Merge pull request #4260 from assimp/kimkulling-patch-1
Fix a typo in the Visual-Studio Dll-Versions
2021-12-16 15:39:01 +01:00
Kim Kulling 7a29147095 Fix a typo 2021-12-16 14:55:23 +01:00
Kim Kulling 46b28a442b Merge pull request #4226 from umlaeute/bugfix/import-crashes
Bugfix/import crashes
2021-12-16 14:51:34 +01:00
Kim Kulling 26dc168449 Merge branch 'master' into bugfix/import-crashes 2021-12-15 07:54:48 +01:00
Kim Kulling 8322e393c5 Merge pull request #4244 from kovacsv/copyscene_fix
Bug: Export crashes when any of the meshes contains texture coordinate names #4243
2021-12-14 00:14:42 +01:00
Kim Kulling 003942aafe Merge branch 'master' into copyscene_fix 2021-12-13 21:19:08 +01:00
Kim Kulling 0491eb3591 Merge pull request #4253 from assimp/kimkulling_fix_double_prec_build_issue4248
Use correct XmlParser-methods and add some missing casts
2021-12-13 21:17:15 +01:00
Viktor Kovacs d619f7015a Merge branch 'master' into copyscene_fix 2021-12-13 20:08:45 +01:00
Kim Kulling 65bc801734 Some fixes for possible divisions by zero 2021-12-13 18:48:58 +01:00
Kim Kulling e4f38810ca Add missing static casts 2021-12-13 18:12:19 +01:00
Kim Kulling cb657e4c13 Use correct XmlParser-methods and add some missing casts 2021-12-13 18:06:23 +01:00
Kim Kulling 052594568a Merge pull request #4247 from inhosens/master
Revert "FBXConverter : Fix timescales of FBX animations"
2021-12-12 21:42:14 +01:00
Kim Kulling 54e60b031e Merge branch 'master' into master 2021-12-12 21:12:37 +01:00
Viktor Kovacs 4959924dab Merge branch 'master' into copyscene_fix 2021-12-10 20:10:25 +01:00
Kim Kulling 819d9f7257 Merge pull request #4250 from assimp/kimkulling-fix_division_by_zero_issue4235-1
Update HMPLoader.cpp
2021-12-10 15:03:01 +01:00
Kim Kulling 33c6762272 Update HMPLoader.cpp
- Fix possible division by zero
- closes https://github.com/assimp/assimp/issues/4235
2021-12-10 14:32:45 +01:00
Kim Kulling 6bb856335f Merge pull request #4249 from assimp/kimkulling-fix_nullptr_dereferencing_issue4237
Fix nullptr dereferencing from std::shared_ptr
2021-12-10 11:02:32 +01:00
Kim Kulling 68682d75b5 Fix nullptr dereferencing from std::shared_ptr
- Finding from fuzzer
- closes https://github.com/assimp/assimp/issues/4237
2021-12-10 08:39:21 +01:00
Inho Lee c2297e9199 Revert "FBXConverter : Fix timescales of FBX animations"
The previous patch was made by misunderstanding about mTime.
It is not real time value, but time ticks.

This reverts commit b8bf1eac04.
2021-12-09 10:57:39 +01:00
Viktor Kovacs d2c8cb755e Merge branch 'master' into copyscene_fix 2021-12-08 14:29:31 +01:00
Kim Kulling ea2e442046 Merge pull request #4245 from assimp/kimkulling-fix-division-by-zero-issue4240
Fix division by zero in PointInTriangle2D
2021-12-07 21:37:50 +01:00
Kim Kulling e51feac2c5 Update PolyTools.h 2021-12-07 21:19:01 +01:00
Kim Kulling 1e4861f86e Fix division by zero in PointInTriangle2D
- closes https://github.com/assimp/assimp/issues/4240
2021-12-07 20:45:21 +01:00
kovacsv 2be6bac4b0 Bug: Export crashes when any of the meshes contains texture coordinate names #4243 2021-12-07 20:42:43 +01:00
IOhannes m zmölnig 9a7ee0ac14 Throw a DeadlyImportError rather than an assertion if all materials are redundant and thus removed
Closes: https://github.com/assimp/assimp/issues/4224
Closes: https://github.com/assimp/assimp/issues/4225
2021-12-07 12:35:15 +01:00
IOhannes m zmölnig 6e090c88b8 fix index variable for surfaces
Closes: https://github.com/assimp/assimp/issues/4209
2021-12-07 12:13:31 +01:00
Kim Kulling 70f5cca9c3 Merge pull request #4219 from assimp/kimkulling-v5.1.3
Update CMakeLists.txt
2021-12-04 21:01:52 +01:00
Kim Kulling 983b20cda6 Update CMakeLists.txt
- tag v5.1.3
2021-12-04 20:26:29 +01:00
Kim Kulling 16149348ed Merge pull request #4217 from umlaeute/bugfix/x3d-extension-check
Fix file-extension check for X3D-files
2021-12-01 16:07:12 +01:00
IOhannes m zmölnig 0e2ac2a91c X3D: simplistic attempt to avoid crashes due to nullptr access
Related: https://github.com/assimp/assimp/issues/4201

while the crashes go away, i'm not sure whether this is the correct fix.
also, afaict the X3D importer produces wrong results anyhow
2021-12-01 12:21:29 +01:00
IOhannes m zmölnig c8cdf3009e X3D: replace 'here' debugging printout by an assertion.
if mNodeElementCur is NULL, we get a crash anyhow...
2021-12-01 12:19:19 +01:00
IOhannes m zmölnig 23d7811276 X3D: consistent initialization with nullptr 2021-12-01 11:35:06 +01:00
IOhannes m zmölnig 836963428e Fix file-extension check for X3D-files
using the pre-existing and well-tested GetExtension() (which happens
to also normalize the extension), rather than attempting our own
buggy one...

Closes: https://github.com/assimp/assimp/issues/4177
2021-12-01 11:17:42 +01:00
Kim Kulling 8c9a148776 Merge pull request #4216 from inhosens/master
Interpolate euler rotations for quaternion animations
2021-12-01 00:24:15 +01:00
Kim Kulling 834ec20008 Merge branch 'master' into master 2021-11-30 23:44:42 +01:00
Kim Kulling cc05b4c8f1 Merge pull request #4211 from ms-maxvollmer/ms-maxvollmer/crashfixes2
Added checks for out of bounds data access/writing
2021-11-30 23:44:00 +01:00
Kim Kulling d6f3f292f2 Merge branch 'master' into ms-maxvollmer/crashfixes2 2021-11-30 23:17:59 +01:00
Inho Lee 4a37aa2ef8 Interpolate euler rotations for quaternion animations
FBX uses euler rotation but assimp library's base type is
quaternion. When assimp convert FBX some animation information
can be lost.
This patch interpolates euler-angle rotations and insert
additional keyframes for the FBX format.
2021-11-30 12:49:59 +01:00
Kim Kulling 745f5e7e65 Merge pull request #4193 from PencilAmazing/BlenderCollections
Update blender importer to work with Blender 2.8+ files
2021-11-28 23:51:06 +01:00
Pencil Amazing 095bd67e10 Fix memory leaks in CollectionObject by making ob a weak pointer and removing prev pointer.
Something was cyclic in CollectionObject and we don't traverse backwards anyways
2021-11-26 22:09:06 -04:00
Pencil Amazing e831ecf3c2 Add a separate test case for Blender 276 and update Box.blend to be 293 2021-11-26 22:09:06 -04:00
Pencil Amazing 44fa1ec6a7 Make Blender importer aware of collections, and use them when available. Also add the default startup file for Blender 2.93 2021-11-26 22:09:06 -04:00
Kim Kulling 70c1aec7c7 Merge pull request #4212 from assimp/kimkulling-remove_deprecated_data
Delete test/models/3DS/UVTransformTest directory
2021-11-26 19:34:02 +01:00
Kim Kulling 34daf87428 Delete test/models/3DS/UVTransformTest directory
- Remove deprecated data
2021-11-26 19:17:42 +01:00
Max Vollmer (Microsoft Havok) 5e1188c44e Check that positions exist before accessing them 2021-11-26 13:01:38 +00:00
Max Vollmer (Microsoft Havok) 0015823bef Reject files with an invalid byteLength value 2021-11-26 13:01:15 +00:00
Max Vollmer (Microsoft Havok) 38382715f7 Ensure we don't access the vector with an out of bounds index 2021-11-26 13:01:00 +00:00
Kim Kulling da8772c57b Merge pull request #4207 from jakrams/msft-jakras-fix-corrupted-accessor
Prevent out-of-range memory writes by sparse accessors
2021-11-26 09:02:17 +01:00
Jan Krassnigg 1a5d66714f Prevent out-of-range memory writes by sparse accessors
This turned up during fuzz testing. Corrupted data would make assimp write to random memory locations, leading to subsequent crashes.
2021-11-25 11:20:26 +01:00
Kim Kulling 889e559696 Merge pull request #4195 from ruyo/fix-gltf2-sparse-indicesType
Fixed an incorrect indeiciesType in the glTF2 sparse accessor.
2021-11-22 22:43:43 +01:00
Kim Kulling b22098c234 Merge branch 'master' into fix-gltf2-sparse-indicesType 2021-11-22 22:02:05 +01:00
Kim Kulling 85ea57dcdb Merge pull request #4196 from Rodousse/fix_mingw_compile_flags
Use adviced c++ flag to supress warning on mingw
2021-11-22 22:01:05 +01:00
Robin Dousse 6819b84b8b Use adviced c++ flag to supress warning on mingw 2021-11-22 09:27:14 +01:00
ruyo 60bfde78eb Fixed an incorrect indeiciesType in the glTF2 sparse accessor. 2021-11-21 23:23:22 +09:00
Kim Kulling aeba7a43a0 Merge pull request #4185 from rhabacker/win_dll_so_version
On Windows/mingw in shared build mode append '-SOVERSION' to DLL base file name
2021-11-20 16:53:21 +01:00
Kim Kulling 9ebd74bd26 Merge branch 'master' into win_dll_so_version 2021-11-20 14:16:32 +01:00
Kim Kulling 9267f4c5b8 Merge pull request #4184 from RichardTea/deprecated_gltfpbr_macros
Redefine deprecated glTF-specific PBR material macros
2021-11-20 14:01:57 +01:00
Kim Kulling 0d857bcf9f Merge branch 'master' into deprecated_gltfpbr_macros 2021-11-20 12:35:56 +01:00
Ralf Habacker 2ceb18746b Append '-SOVERSION' to DLL base file name for mingw builds to match common style 2021-11-18 08:17:31 +01:00
Kim Kulling 3db1592f7e Merge pull request #4187 from RichardTea/collada_value_not_attrib_4179
Collada: Read value, not attribute
2021-11-17 19:16:10 +01:00
RichardTea 74b3be194d Read the Value, not the Attribute
Correct some mistakes made when moving to pugixml from IrrXML
Fixes #4179
2021-11-17 17:10:10 +00:00
RichardTea bab8b8dbab apply clangformat 2021-11-17 17:08:19 +00:00
RichardTea 33845cd019 Only issue compile warning on gcc and msvc
I'm not sure on the proper syntax for clang and mingw
2021-11-17 15:44:16 +00:00
Kim Kulling b1c83f437f Merge pull request #4173 from jdumas/jdumas/ziplib
Do not build ziplib when 3MF exporter is disabled.
2021-11-17 14:09:07 +01:00
Kim Kulling ce3101ea4e Merge branch 'master' into jdumas/ziplib 2021-11-17 13:46:16 +01:00
RichardTea c24f99cd0e Redefine deprecated glTF-specific PBR material macros
Intended to support Qt5 QtQuick3D until it is ported to generic PBR
macros.
2021-11-16 11:42:59 +00:00
Kim Kulling c174575cf8 Merge pull request #4181 from assimp/kimkulling-prepare_installer
Update script_x64.iss
2021-11-15 11:05:34 +01:00
Kim Kulling 1ee8c1b51f Update script_x86.iss
- Update version for 5.1.0 in x86 installer script
2021-11-15 08:41:23 +01:00
Kim Kulling 595799b1bc Update script_x64.iss
- Update to 5.1.0
2021-11-15 08:39:31 +01:00
Kim Kulling a5a091c138 Merge pull request #4180 from assimp/kimkulling-remove_irrxml_notes
Delete irrXML_note.txt
2021-11-15 08:37:49 +01:00
Kim Kulling e8732341f4 Delete irrXML_note.txt
- Remove deprecated notes from irrxml
2021-11-15 08:23:56 +01:00
Jérémie Dumas b0d564467e Merge branch 'master' into jdumas/ziplib 2021-11-14 08:25:59 -08:00
Jérémie Dumas 78d72bff59 Fix 3MF presence test. 2021-11-14 08:24:27 -08:00
Kim Kulling 05115b07b4 Merge pull request #4174 from ifree/master
glTF2 skinning related fixes
2021-11-13 09:30:32 +01:00
Kim Kulling b1c336799c Merge branch 'master' into master 2021-11-13 09:16:27 +01:00
Kim Kulling c3ac5569c5 Merge branch 'master' into jdumas/ziplib 2021-11-13 08:46:46 +01:00
Kim Kulling 4fa3648132 Merge pull request #4172 from assimp/kimkulling-diable_m3m_issue-4126
Disable m3d for 5.1
2021-11-13 08:45:51 +01:00
Kim Kulling f48731622b Disable m3d tesat 2021-11-13 08:30:29 +01:00
Kim Kulling fc0617280e Disable m3d-export 2021-11-13 08:16:34 +01:00
freizhang b9937994ca Fix glTF2 skinning bone weight exporting issue 2021-11-13 12:07:29 +08:00
freizhang 6e6807ee6c Verbose processor bone weight count fix 2021-11-13 11:56:15 +08:00
freizhang 1407491a67 glTF2 exporter buffer overrun issue fix. 2021-11-13 11:52:49 +08:00
Jérémie Dumas 57d22e4dbf Merge branch 'master' into jdumas/ziplib 2021-11-12 10:13:21 -08:00
Kim Kulling 159fadebbf Update M3DExporter.cpp 2021-11-12 17:53:46 +01:00
Kim Kulling 0beacc3854 Merge branch 'master' into kimkulling-diable_m3m_issue-4126 2021-11-12 16:02:51 +01:00
Kim Kulling f03dcc27c0 Update M3DExporter.h 2021-11-12 15:39:21 +01:00
Kim Kulling fe73213420 Merge pull request #4111 from MalcolmTyrrell/MalcolmTyrrell/jsonSchemaSupport
Allow the gltf2 Importer to optionally use glTF 2.0 JSON schemas for initial validation
2021-11-12 13:12:31 +01:00
Kim Kulling e2ccd17494 Fix typo 2021-11-12 11:20:22 +01:00
Kim Kulling 157e032bde Fix small findings
- Merge anonymous functions into one block.
- Some reformattings
2021-11-12 11:08:19 +01:00
Kim Kulling 37c81e7a28 Merge branch 'master' into MalcolmTyrrell/jsonSchemaSupport 2021-11-12 10:37:19 +01:00
Kim Kulling 2e5e176bf3 Merge pull request #4147 from alpire/master
Fix out-of-bounds read in RemoveLineComments
2021-11-12 10:36:44 +01:00
Kim Kulling c22524351a Merge branch 'master' into master 2021-11-12 09:56:56 +01:00
Kim Kulling 97b8e41997 Fix formatting 2021-11-12 09:56:45 +01:00
Kim Kulling a7a6b96ca8 Merge pull request #4150 from kovacsv/readme_add_assimpjs
Add assimpjs link to the ports in the readme file
2021-11-12 09:31:39 +01:00
Kim Kulling 6f853be88c Merge branch 'master' into readme_add_assimpjs 2021-11-12 09:18:22 +01:00
Kim Kulling b43a84a496 Merge pull request #4159 from RichardTea/3ds_export_4157
3DS Export: Add support for aiShadingMode_PBR_BRDF
2021-11-12 09:17:49 +01:00
Kim Kulling ece61c6c68 Update M3DWrapper.cpp 2021-11-12 09:17:32 +01:00
Kim Kulling 608bccd9cf Update M3DWrapper.h 2021-11-12 09:13:48 +01:00
Kim Kulling 13731b37c4 Merge branch 'master' into 3ds_export_4157 2021-11-12 07:06:52 +01:00
Kim Kulling 4abf37ace6 Update CMakeLists.txt 2021-11-11 23:22:06 +01:00
Kim Kulling 4854978108 Disable m3d for 5.1
- closes https://github.com/assimp/assimp/issues/4126
2021-11-11 22:15:56 +01:00
Kim Kulling 1f8edd5959 Merge pull request #4160 from RichardTea/fix_gltf_warning_4126
Check and limit maximum size of glTF
2021-11-11 21:30:07 +01:00
Kim Kulling 43b0ef181a Merge branch 'master' into fix_gltf_warning_4126 2021-11-11 20:30:07 +01:00
Kim Kulling add7f1355e Merge pull request #4163 from RichardTea/fix_aiMesh_abi_4162
Better aiMesh ABI compatibility with 5.0.1, make smaller
2021-11-11 20:27:40 +01:00
Kim Kulling 7120504c46 Merge branch 'master' into fix_aiMesh_abi_4162 2021-11-11 20:02:46 +01:00
Kim Kulling 8a1563d61a Merge pull request #4170 from assimp/Artenuvielle-x3d_pugi_migration_artenuvielle
Artenuvielle x3d pugi migration artenuvielle
2021-11-11 19:19:33 +01:00
Kim Kulling eafb79e7dc Merge branch 'Artenuvielle-x3d_pugi_migration_artenuvielle' of https://github.com/assimp/assimp into Artenuvielle-x3d_pugi_migration_artenuvielle 2021-11-11 19:06:33 +01:00
Kim Kulling 952f0a53c9 Try to fix a leak 2021-11-11 19:06:25 +01:00
Viktor Kovacs b6994c5e1f Merge branch 'master' into readme_add_assimpjs 2021-11-11 07:38:42 +01:00
Kim Kulling 9f28ef4c25 Merge branch 'master' into Artenuvielle-x3d_pugi_migration_artenuvielle 2021-11-10 20:43:39 +01:00
Kim Kulling a31c979abc Use helloworld as X3D-Testcase 2021-11-10 20:40:05 +01:00
Kim Kulling 8ed18621db Fixes 2021-11-10 20:37:27 +01:00
Kim Kulling fe511fddc4 Merge pull request #4165 from irajsb/master
Added UE4 plugin
2021-11-10 11:06:22 +01:00
Kim Kulling 39664d608d Merge branch 'master' into master 2021-11-10 10:51:18 +01:00
Kim Kulling baf3f00644 Merge branch 'master' into master 2021-11-10 10:37:49 +01:00
Kim Kulling d4755648b4 Merge pull request #4167 from assimp/kimkulling-fix_uninitialized_attribs_issue-4158
Update anim.h
2021-11-10 09:34:52 +01:00
Kim Kulling 5fd2a5559c Update mesh.h
- Add initialization for armature attributes.
- closes https://github.com/assimp/assimp/issues/4158
2021-11-10 09:19:29 +01:00
Kim Kulling c01d33a77a Update anim.h
- Add missing whitespaces
2021-11-10 09:12:35 +01:00
Kim Kulling 83950845ee Merge pull request #4166 from assimp/kimkulling-fix_version_issue-4161
Change version to 5.1.0
2021-11-10 09:08:23 +01:00
Kim Kulling 8a613a8655 Fix unittest 2021-11-09 23:27:58 +01:00
Kim Kulling e206d699da Change version to 5.1.0
- Change version for Version 5.1.0-RC1 to 5.1.0
- closes https://github.com/assimp/assimp/issues/4161
2021-11-09 23:26:20 +01:00
iraj mohtasham 7ddd9b2484 Added UE4 plugin 2021-11-10 00:04:12 +03:30
Kim Kulling 50ba15191b Merge pull request #4164 from Skylion007/update-performance-fixes
Remove optimization fence preventing automatic move
2021-11-09 20:09:31 +01:00
Aaron Gokaslan b8a10e62f9 Remove optimization fence 2021-11-09 13:08:13 -05:00
RichardTea 86a25b62e4 Better aiMesh ABI compatibility with 5.0.1, make smaller
Move new mTextureCoordsNames member to end of struct
Convert to pointer-to-array, saving ~8KB per aiMesh in almost all cases
Add C++ accessor functions for simpler usage
2021-11-09 13:03:06 +00:00
Kim Kulling 30143e9626 Merge branch 'master' into MalcolmTyrrell/jsonSchemaSupport 2021-11-09 10:53:58 +01:00
RichardTea aaae3e3a10 size_t is 32bit on some platforms
Also assert if size_t is smaller than uint32_t (probably not necessary)
Note: 32bit builds will crash OOM if a really large model is loaded, as cannot allocate that much in total, let alone contiguously.
2021-11-08 15:05:20 +00:00
RichardTea 9433fc526a Apply clangformat 2021-11-08 14:42:21 +00:00
RichardTea 69cafe64b4 Cap glTFv1 & 2 json size to ~4GB
Ensures size_t cannot overflow
Limits the maximum contiguous memory allocation to something plausible.
2021-11-08 14:41:13 +00:00
RichardTea ee19ce6021 3DS Export: Add support for aiShadingMode_PBR_BRDF
Export as Phong.
If no Diffuse texture, export the PBR base color instead,
2021-11-08 11:06:15 +00:00
Jeremie Dumas cedf1819c3 Do not build ziplib when 3MF exporter is disabled. 2021-11-04 01:14:24 -07:00
Kim Kulling 2b4b3e820b Merge pull request #4154 from assimp/kimkulling-fuzzer-issue-4153
Update D3MFOpcPackage.cpp
2021-11-02 10:51:58 +01:00
Kim Kulling 5a3401b69f Update D3MFOpcPackage.cpp
- Log an error in case of a nullptr-exception in reading out the 3MF-Archive
- closes https://github.com/assimp/assimp/issues/4153
2021-11-02 10:38:38 +01:00
kovacsv 3b2a9d1543 Add assimpjs link. 2021-11-01 08:09:16 +01:00
Alex Rebert 145f972d76 Fix out-of-bounds read in RemoveLineComments
Follow up to 6f07e89fdf, which was not sufficient to fix the bug.

Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24553
2021-10-30 13:43:41 -04:00
Kim Kulling 3664fe20c0 Merge pull request #4146 from alpire/master
Fix fuzzer crashes
2021-10-29 20:20:04 +02:00
Kim Kulling 322de54323 Merge branch 'master' into master 2021-10-29 19:35:27 +02:00
Kim Kulling 7f4839a26c Merge pull request #4145 from Daniel-Genkin/master
Fixed building of Android port
2021-10-29 19:21:27 +02:00
Alex Rebert e900617796 Fix out-of-bounds read in FileSystemFilter::Cleanup
Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=33238
2021-10-29 09:17:40 -04:00
Daniel-Genkin f28500dd0f Fixed building of Android port 2021-10-29 09:03:55 -04:00
Alex Rebert 6f07e89fdf Fix out-of-bounds read in RemoveLineComments
Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24553
2021-10-28 23:50:16 -04:00
Alex Rebert 1909b3e8d2 Fix overflow in IOStreamBuffer
`getNextLine` & `getNextDataLine` now double the buffer size each time
it is needed to avoid writing out of bounds.

Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24465
2021-10-28 23:33:07 -04:00
Alex Rebert 6a3ac623b9 Fix out-of-bounds reads in OpenDDLParser
Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=31795
Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24463
Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=36594
2021-10-28 23:13:29 -04:00
Alex Rebert 107371657b Fix out-of-bounds read in ReadFirstSkin
Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25401
2021-10-28 23:12:54 -04:00
Alex Rebert 1fe9d405f5 Fix out-of-bounds read in MDLImporter
Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24502
2021-10-28 22:38:40 -04:00
Alex Rebert 932dfe0562 Fix overflowing allocations in MDLMaterialLoader
Some allocations might underallocate due to integer overflows. This
commit ensures that we are throwing an exception if the allocation size
does not fit in an unsigned int.

Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25341
2021-10-28 22:27:19 -04:00
Alex Rebert 30f17aa206 Fix heap out-of-bounds write in _m3d_safestr
While there is a 256 character limit when computing the length of the
newly allocated strength, that limit was missing when copying the
string. This commit adds a new length check in the copy loop, preventing
it from writhing out of bounds.

Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=34416
2021-10-28 21:32:38 -04:00
Kim Kulling d273a784d0 Merge pull request #4142 from Daniel-Genkin/master
Added another constructor to avoid requiring a full ANativeActivity
2021-10-28 22:16:07 +02:00
Kim Kulling 5333e41607 Update AndroidJNIIOSystem.h 2021-10-28 17:52:01 +02:00
Kim Kulling e5cd5733e1 Update AndroidJNIIOSystem.cpp 2021-10-28 17:50:25 +02:00
Daniel-Genkin 6e5600a9a5 Added another constructor to avoid requiring a full ANativeActivity 2021-10-28 10:26:14 -04:00
Kim Kulling 8c0b869998 Merge branch 'master' into MalcolmTyrrell/jsonSchemaSupport 2021-10-28 13:38:41 +02:00
Kim Kulling 817fbed8c2 Merge pull request #4130 from MalcolmTyrrell/MalcolmTyrrell/spatialSortImprovements
SpatialSort improvements
2021-10-27 17:46:25 +02:00
Kim Kulling 5af71feef2 Merge branch 'master' into MalcolmTyrrell/spatialSortImprovements 2021-10-27 17:20:47 +02:00
Kim Kulling 0e38cec58c Merge pull request #4140 from assimp/kimkulling-patch-cleanup
Remove dead code.
2021-10-27 00:03:13 +02:00
Kim Kulling e01b488075 Remove dead code. 2021-10-26 22:06:10 +02:00
Malcolm Tyrrell 2239442c64 Merge branch 'master' into MalcolmTyrrell/spatialSortImprovements 2021-10-21 08:55:11 +01:00
Malcolm Tyrrell db0127859a CalculateDistance method 2021-10-21 08:39:44 +01:00
Kim Kulling 791cb195be Merge branch 'master' into x3d_pugi_migration_artenuvielle 2021-10-20 21:14:43 +02:00
Kim Kulling f81d7c0b3e Merge pull request #4112 from diharaw/master
[GLTF2] Add read and write support for KHR_materials_volume and KHR_materials_ior extensions.
2021-10-20 21:14:11 +02:00
Kim Kulling f3baab1153 Merge branch 'master' into master 2021-10-20 20:51:43 +02:00
Malcolm Tyrrell 4ba99c1bb0 Comments 2021-10-20 16:15:00 +01:00
Malcolm Tyrrell c644f9d719 Subtract the centroid 2021-10-20 15:08:08 +01:00
Malcolm Tyrrell 4d10f5d133 Move distance initialization to Finalize. 2021-10-20 12:47:44 +01:00
Malcolm Tyrrell 5b13b97f27 Ensure the usage pattern of SpatialSort. 2021-10-19 14:22:28 +01:00
Kim Kulling a82dc887fc Merge branch 'master' into x3d_pugi_migration_artenuvielle 2021-10-14 09:27:07 +02:00
Malcolm Tyrrell 5a1bcc6aa5 Fix build and test 2021-10-07 10:01:33 +01:00
Malcolm Tyrrell ceddfe19d8 Add comment with link to schema repo. 2021-10-07 10:01:32 +01:00
Malcolm Tyrrell 7788c1a04e Add a unit test for json schemas. 2021-10-07 10:01:32 +01:00
Malcolm Tyrrell a283a255a5 Allow schema checking of glTF2 file. 2021-10-07 10:01:32 +01:00
diharaw 0fb66f8437 Replaced AI_MATKEY_IOR with AI_MATKEY_REFRACTI. 2021-10-07 09:39:08 +01:00
diharaw b01d008bc0 Revert "Removed KHR_materials_ior support."
This reverts commit 0738742611.
2021-10-07 09:36:53 +01:00
diharaw 0738742611 Removed KHR_materials_ior support. 2021-10-07 09:30:22 +01:00
diharaw 46a7de7a0b Moved KHR_material_volume thickness texture under aiTextureType_TRANSMISSION. 2021-09-30 08:56:16 +01:00
diharaw addd541251 Added gltf2 KHR_materials_ior support. 2021-09-30 08:47:53 +01:00
diharaw d3276de47d Added gltf2 KHR_materials_volume write support. 2021-09-30 08:10:02 +01:00
diharaw 200bf8df7a Added gltf2 KHR_materials_volume import support. 2021-09-29 17:05:17 +01:00
Kim Kulling d814e9067a Merge branch 'master' into x3d_pugi_migration_artenuvielle 2021-09-20 21:14:20 +02:00
René Martin e92177cb99 changed use and def attribute check for x3d importer to upper case
This is how it is specified in the standard.
2021-09-17 14:24:57 +02:00
Kim Kulling d0f7200196 Update X3DImporter_Geometry3D.cpp 2021-09-16 21:01:44 +02:00
René Martin 65173df9d9 fixed x3d importer test 2021-09-16 13:45:56 +02:00
Artenuvielle 70dfdb8f9d Merge branch 'master' into x3d_pugi_migration_artenuvielle 2021-09-15 14:51:38 +02:00
René Martin a8a6aa2bd8 fixed some compiling issues 2021-09-15 14:49:46 +02:00
Kim Kulling 8ba4d30d7c Merge branch 'master' into x3d_pugi_migration_artenuvielle 2021-09-14 08:24:44 +02:00
Artenuvielle c7e9c6580a Merge branch 'master' into x3d_pugi_migration_artenuvielle 2021-09-12 11:45:00 +02:00
René Martin dfb0d66437 Merge branch 'master' into x3d_pugi_migration_artenuvielle 2021-09-12 11:44:14 +02:00
René Martin 3f6a371b64 migrated x3d importer to pugixml reader 2021-09-12 11:37:33 +02:00
René Martin 3001d88172 Merge branch 'master' into x3d_pugi_migration 2021-09-07 15:04:08 +02:00
Kim Kulling 6db142ee51 Merge branch 'x3d_pugi_migration' of https://github.com/assimp/assimp into x3d_pugi_migration 2021-06-10 23:36:47 +02:00
Kim Kulling ebb9b1b2af Next iteration 2021-06-10 23:36:07 +02:00
Kim Kulling d33cf1dc0c Merge branch 'master' into x3d_pugi_migration 2021-06-06 16:06:08 +02:00
Kim Kulling d600b45cd2 Merge branch 'x3d_pugi_migration' of https://github.com/assimp/assimp into x3d_pugi_migration 2021-06-03 22:21:10 +02:00
Kim Kulling 3a32612b71 Add skipping of unused nodes. 2021-06-03 20:55:31 +02:00
Kim Kulling 8cae8c5461 Fix static code analysis findings 2021-05-07 11:52:16 +02:00
Kim Kulling 56bfa1ce5c Make constructros with one arg explicit 2021-05-07 11:36:21 +02:00
Kim Kulling 350f2ea1d3 Fix build and merged master. 2021-05-06 21:36:25 +02:00
Kim Kulling 52228a93f8 Fix X3DGeohelper. 2021-05-06 21:07:38 +02:00
125 changed files with 8428 additions and 942 deletions
+10 -6
View File
@@ -40,6 +40,9 @@ SET(CMAKE_POLICY_DEFAULT_CMP0092 NEW)
CMAKE_MINIMUM_REQUIRED( VERSION 3.10 )
# Disabled importers: m3d for 5.1
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_M3D_IMPORTER)
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_M3D_EXPORTER)
# Toggles the use of the hunter package manager
option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
@@ -53,7 +56,7 @@ IF(ASSIMP_HUNTER_ENABLED)
add_definitions(-DASSIMP_USE_HUNTER)
ENDIF()
PROJECT( Assimp VERSION 5.0.1 )
PROJECT(Assimp VERSION 5.1.3)
# All supported options ###############################################
@@ -179,8 +182,10 @@ SET (ASSIMP_SOVERSION 5)
SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
if(NOT ASSIMP_HUNTER_ENABLED)
# Enable C++11 support globally
set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
# Enable C++17 support globally
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 99)
endif()
IF(NOT ASSIMP_IGNORE_GIT_HASH)
@@ -285,12 +290,11 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
message(WARNING "MinGW is old, if you experience errors, update MinGW.")
ENDIF()
IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
SET(CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
ENDIF()
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
ADD_DEFINITIONS( -U__STRICT_ANSI__ )
ENDIF()
IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED)
@@ -760,7 +764,7 @@ if(WIN32)
IF(MSVC_TOOLSET_VERSION)
SET(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
SET(ASSIMP_MSVC_VERSION ${MCVS_PREFIX})
SET(ASSIMP_MSVC_VERSION ${MSVC_PREFIX})
ELSE()
IF(MSVC12)
SET(ASSIMP_MSVC_VERSION "vc120")
+2
View File
@@ -42,7 +42,9 @@ Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file.
* [.NET](https://bitbucket.org/Starnick/assimpnet/src/master/)
* [Pascal](port/AssimpPascal/Readme.md)
* [Javascript (Alpha)](https://github.com/makc/assimp2json)
* [Javascript/Node.js Interface](https://github.com/kovacsv/assimpjs)
* [Unity 3d Plugin](https://ricardoreis.net/trilib-2/)
* [Unreal Engine Plugin](https://github.com/irajsb/UE4_Assimp/)
* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status))
* [HAXE-Port](https://github.com/longde123/assimp-haxe) The Assimp-HAXE-port.
* [Rust](https://github.com/jkvargas/russimp)
+10 -4
View File
@@ -330,6 +330,7 @@ void Discreet3DSExporter::WriteMaterials() {
case aiShadingMode_Blinn:
case aiShadingMode_CookTorrance:
case aiShadingMode_Fresnel:
case aiShadingMode_PBR_BRDF: // Possibly should be Discreet3DS::Metal in some cases but this is undocumented
shading_mode_out = Discreet3DS::Phong;
break;
@@ -356,7 +357,10 @@ void Discreet3DSExporter::WriteMaterials() {
writer.PutI2(1);
}
WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
// Fallback to BASE_COLOR if no DIFFUSE
if (!WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE))
WriteTexture(mat, aiTextureType_BASE_COLOR, Discreet3DS::CHUNK_MAT_TEXTURE);
WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
@@ -367,20 +371,21 @@ void Discreet3DSExporter::WriteMaterials() {
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
// returns true if the texture existed
bool Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
aiString path;
aiTextureMapMode map_mode[2] = {
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
};
ai_real blend = 1.0;
if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) {
return;
return false;
}
// TODO: handle embedded textures properly
if (path.data[0] == '*') {
ASSIMP_LOG_ERROR("Ignoring embedded texture for export: ", path.C_Str());
return;
return false;
}
ChunkWriter chunk(writer, chunk_flags);
@@ -402,6 +407,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type
writer.PutU2(val);
}
// TODO: export texture transformation (i.e. UV offset, scale, rotation)
return true;
}
// ------------------------------------------------------------------------------------------------
+1 -1
View File
@@ -73,7 +73,7 @@ public:
private:
void WriteMeshes();
void WriteMaterials();
void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
bool WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
void WriteFaceMaterialChunk(const aiMesh& mesh);
int WriteHierarchy(const aiNode& node, int level, int sibling_level);
void WriteString(const std::string& s);
+1 -1
View File
@@ -149,7 +149,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
IOStream *fileStream = mZipArchive->Open(file.c_str());
if (nullptr == fileStream) {
ai_assert(fileStream != nullptr);
ASSIMP_LOG_ERROR("Filestream is nullptr.");
continue;
}
-1
View File
@@ -159,7 +159,6 @@ bool parseColor(const char *color, aiColor4D &diffuse) {
return false;
}
//const char *buf(color);
if ('#' != color[0]) {
return false;
}
+1 -1
View File
@@ -601,7 +601,7 @@ static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene,
ioprintf(io, "\t\t<TextureCoords num=\"%u\" set=\"%u\" name=\"%s\" num_components=\"%u\"> \n",
mesh->mNumVertices,
a,
mesh->mTextureCoordsNames[a].C_Str(),
(mesh->HasTextureCoordsName(a) ? mesh->GetTextureCoordsName(a)->C_Str() : ""),
mesh->mNumUVComponents[a]);
if (!shortened) {
+69 -30
View File
@@ -318,42 +318,81 @@ void BlenderImporter::ExtractScene(Scene &out, const FileDatabase &file) {
#endif
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ParseSubCollection(const Blender::Scene &in, aiNode *root, std::shared_ptr<Collection> collection, ConversionData &conv_data) {
std::deque<Object *> root_objects;
// Count number of objects
for (std::shared_ptr<CollectionObject> cur = std::static_pointer_cast<CollectionObject>(collection->gobject.first); cur; cur = cur->next) {
if (cur->ob) {
root_objects.push_back(cur->ob);
}
}
std::deque<Collection *> root_children;
// Count number of child nodes
for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
if (cur->collection) {
root_children.push_back(cur->collection.get());
}
}
root->mNumChildren = static_cast<unsigned int>(root_objects.size() + root_children.size());
root->mChildren = new aiNode *[root->mNumChildren]();
for (unsigned int i = 0; i < static_cast<unsigned int>(root_objects.size()); ++i) {
root->mChildren[i] = ConvertNode(in, root_objects[i], conv_data, aiMatrix4x4());
root->mChildren[i]->mParent = root;
}
// For each subcollection create a new node to represent it
unsigned int iterator = static_cast<unsigned int>(root_objects.size());
for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
if (cur->collection) {
root->mChildren[iterator] = new aiNode(cur->collection->id.name + 2); // skip over the name prefix 'OB'
root->mChildren[iterator]->mParent = root;
ParseSubCollection(in, root->mChildren[iterator], cur->collection, conv_data);
}
iterator += 1;
}
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const FileDatabase &file) {
ConversionData conv(file);
// FIXME it must be possible to take the hierarchy directly from
// the file. This is terrible. Here, we're first looking for
// all objects which don't have parent objects at all -
std::deque<const Object *> no_parents;
for (std::shared_ptr<Base> cur = std::static_pointer_cast<Base>(in.base.first); cur; cur = cur->next) {
if (cur->object) {
if (!cur->object->parent) {
no_parents.push_back(cur->object.get());
} else {
conv.objects.insert(cur->object.get());
}
}
}
for (std::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
if (cur->object) {
if (cur->object->parent) {
conv.objects.insert(cur->object.get());
}
}
}
if (no_parents.empty()) {
ThrowException("Expected at least one object with no parent");
}
aiNode *root = out->mRootNode = new aiNode("<BlenderRoot>");
// Iterate over all objects directly under master_collection,
// If in.master_collection == null, then we're parsing something older.
if (in.master_collection) {
ParseSubCollection(in, root, in.master_collection, conv);
} else {
std::deque<const Object *> no_parents;
for (std::shared_ptr<Base> cur = std::static_pointer_cast<Base>(in.base.first); cur; cur = cur->next) {
if (cur->object) {
if (!cur->object->parent) {
no_parents.push_back(cur->object.get());
} else {
conv.objects.insert(cur->object.get());
}
}
}
for (std::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
if (cur->object) {
if (cur->object->parent) {
conv.objects.insert(cur->object.get());
}
}
}
root->mNumChildren = static_cast<unsigned int>(no_parents.size());
root->mChildren = new aiNode *[root->mNumChildren]();
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
root->mChildren[i]->mParent = root;
if (no_parents.empty()) {
ThrowException("Expected at least one object with no parent");
}
root->mNumChildren = static_cast<unsigned int>(no_parents.size());
root->mChildren = new aiNode *[root->mNumChildren]();
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
root->mChildren[i]->mParent = root;
}
}
BuildMaterials(conv);
+2
View File
@@ -78,6 +78,7 @@ struct ElemBase;
namespace Blender {
struct Scene;
struct Object;
struct Collection;
struct Mesh;
struct Camera;
struct Lamp;
@@ -116,6 +117,7 @@ protected:
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
void ParseBlendFile(Blender::FileDatabase &out, std::shared_ptr<IOStream> stream);
void ExtractScene(Blender::Scene &out, const Blender::FileDatabase &file);
void ParseSubCollection(const Blender::Scene &in, aiNode *root, std::shared_ptr<Blender::Collection> collection, Blender::ConversionData &conv_data);
void ConvertBlendFile(aiScene *out, const Blender::Scene &in, const Blender::FileDatabase &file);
private:
+50
View File
@@ -94,6 +94,52 @@ void Structure ::Convert<Group>(
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CollectionObject>(
CollectionObject &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
{
//std::shared_ptr<CollectionObject> prev;
//ReadFieldPtr<ErrorPolicy_Fail>(prev, "*prev", db);
//dest.prev = prev.get();
std::shared_ptr<Object> ob;
ReadFieldPtr<ErrorPolicy_Igno>(ob, "*ob", db);
dest.ob = ob.get();
}
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CollectionChild>(
CollectionChild &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Fail>(dest.prev, "*prev", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.collection, "*collection", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<Collection>(
Collection &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadField<ErrorPolicy_Fail>(dest.gobject, "gobject", db);
ReadField<ErrorPolicy_Fail>(dest.children, "children", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MTex>(
@@ -660,6 +706,7 @@ void Structure ::Convert<Scene>(
ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.master_collection, "*master_collection", db);
ReadField<ErrorPolicy_Igno>(dest.base, "base", db);
db.reader->IncPtr(size);
@@ -833,6 +880,9 @@ void DNA::RegisterConverters() {
converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>);
converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
converters["Collection"] = DNA::FactoryPair(&Structure::Allocate<Collection>, &Structure::Convert<Collection>);
converters["CollectionChild"] = DNA::FactoryPair(&Structure::Allocate<CollectionChild>, &Structure::Convert<CollectionChild>);
converters["CollectionObject"] = DNA::FactoryPair(&Structure::Allocate<CollectionObject>, &Structure::Convert<CollectionObject>);
}
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
+23 -1
View File
@@ -107,6 +107,7 @@ namespace Blender {
struct Object;
struct MTex;
struct Image;
struct Collection;
#include <memory>
@@ -147,6 +148,26 @@ struct Group : ElemBase {
std::shared_ptr<GroupObject> gobject;
};
// -------------------------------------------------------------------------------
struct CollectionObject : ElemBase {
//CollectionObject* prev;
std::shared_ptr<CollectionObject> next;
Object *ob;
};
// -------------------------------------------------------------------------------
struct CollectionChild : ElemBase {
std::shared_ptr<CollectionChild> next, prev;
std::shared_ptr<Collection> collection;
};
// -------------------------------------------------------------------------------
struct Collection : ElemBase {
ID id FAIL;
ListBase gobject; // CollectionObject
ListBase children; // CollectionChild
};
// -------------------------------------------------------------------------------
struct World : ElemBase {
ID id FAIL;
@@ -729,11 +750,12 @@ struct Scene : ElemBase {
std::shared_ptr<Object> camera WARN;
std::shared_ptr<World> world WARN;
std::shared_ptr<Base> basact WARN;
std::shared_ptr<Collection> master_collection WARN;
ListBase base;
Scene() :
ElemBase(), camera(), world(), basact() {
ElemBase(), camera(), world(), basact(), master_collection() {
// empty
}
};
+6
View File
@@ -62,6 +62,12 @@ template <> void Structure :: Convert<Group> (
) const
;
template <> void Structure::Convert<Collection>(
Collection& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MTex> (
MTex& dest,
const FileDatabase& db
+32 -29
View File
@@ -924,6 +924,8 @@ void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) {
void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
XmlNode currentNode;
// TODO: Check the current technique and skip over unsupported extra techniques
while (xmlIt.getNext(currentNode)) {
const std::string &currentName = currentNode.name();
if (currentName == "spot") {
@@ -949,33 +951,34 @@ void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.b);
SkipSpacesAndLineEnd(&content);
} else if (currentName == "constant_attenuation") {
XmlParser::getRealAttribute(currentNode, "constant_attenuation", pLight.mAttConstant);
XmlParser::getValueAsFloat(currentNode, pLight.mAttConstant);
} else if (currentName == "linear_attenuation") {
XmlParser::getRealAttribute(currentNode, "linear_attenuation", pLight.mAttLinear);
XmlParser::getValueAsFloat(currentNode, pLight.mAttLinear);
} else if (currentName == "quadratic_attenuation") {
XmlParser::getRealAttribute(currentNode, "quadratic_attenuation", pLight.mAttQuadratic);
XmlParser::getValueAsFloat(currentNode, pLight.mAttQuadratic);
} else if (currentName == "falloff_angle") {
XmlParser::getRealAttribute(currentNode, "falloff_angle", pLight.mFalloffAngle);
XmlParser::getValueAsFloat(currentNode, pLight.mFalloffAngle);
} else if (currentName == "falloff_exponent") {
XmlParser::getRealAttribute(currentNode, "falloff_exponent", pLight.mFalloffExponent);
XmlParser::getValueAsFloat(currentNode, pLight.mFalloffExponent);
}
// FCOLLADA extensions
// -------------------------------------------------------
else if (currentName == "outer_cone") {
XmlParser::getRealAttribute(currentNode, "outer_cone", pLight.mOuterAngle);
} else if (currentName == "penumbra_angle") { // ... and this one is even deprecated
XmlParser::getRealAttribute(currentNode, "penumbra_angle", pLight.mPenumbraAngle);
XmlParser::getValueAsFloat(currentNode, pLight.mOuterAngle);
} else if (currentName == "penumbra_angle") { // this one is deprecated, now calculated using outer_cone
XmlParser::getValueAsFloat(currentNode, pLight.mPenumbraAngle);
} else if (currentName == "intensity") {
XmlParser::getRealAttribute(currentNode, "intensity", pLight.mIntensity);
} else if (currentName == "falloff") {
XmlParser::getRealAttribute(currentNode, "falloff", pLight.mOuterAngle);
XmlParser::getValueAsFloat(currentNode, pLight.mIntensity);
}
else if (currentName == "falloff") {
XmlParser::getValueAsFloat(currentNode, pLight.mOuterAngle);
} else if (currentName == "hotspot_beam") {
XmlParser::getRealAttribute(currentNode, "hotspot_beam", pLight.mFalloffAngle);
XmlParser::getValueAsFloat(currentNode, pLight.mFalloffAngle);
}
// OpenCOLLADA extensions
// -------------------------------------------------------
else if (currentName == "decay_falloff") {
XmlParser::getRealAttribute(currentNode, "decay_falloff", pLight.mOuterAngle);
XmlParser::getValueAsFloat(currentNode, pLight.mOuterAngle);
}
}
}
@@ -1109,7 +1112,7 @@ void ColladaParser::ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEff
// GOOGLEEARTH/OKINO extensions
// -------------------------------------------------------
else if (currentName == "double_sided")
XmlParser::getBoolAttribute(currentNode, currentName.c_str(), pEffect.mDoubleSided);
XmlParser::getValueAsBool(currentNode, pEffect.mDoubleSided);
// FCOLLADA extensions
// -------------------------------------------------------
@@ -1121,9 +1124,9 @@ void ColladaParser::ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEff
// MAX3D extensions
// -------------------------------------------------------
else if (currentName == "wireframe") {
XmlParser::getBoolAttribute(currentNode, currentName.c_str(), pEffect.mWireframe);
XmlParser::getValueAsBool(currentNode, pEffect.mWireframe);
} else if (currentName == "faceted") {
XmlParser::getBoolAttribute(currentNode, currentName.c_str(), pEffect.mFaceted);
XmlParser::getValueAsBool(currentNode, pEffect.mFaceted);
}
}
}
@@ -1142,23 +1145,23 @@ void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) {
// MAYA extensions
// -------------------------------------------------------
if (currentName == "wrapU") {
XmlParser::getBoolAttribute(currentNode, currentName.c_str(), out.mWrapU);
XmlParser::getValueAsBool(currentNode, out.mWrapU);
} else if (currentName == "wrapV") {
XmlParser::getBoolAttribute(currentNode, currentName.c_str(), out.mWrapV);
XmlParser::getValueAsBool(currentNode, out.mWrapV);
} else if (currentName == "mirrorU") {
XmlParser::getBoolAttribute(currentNode, currentName.c_str(), out.mMirrorU);
XmlParser::getValueAsBool(currentNode, out.mMirrorU);
} else if (currentName == "mirrorV") {
XmlParser::getBoolAttribute(currentNode, currentName.c_str(), out.mMirrorV);
XmlParser::getValueAsBool(currentNode, out.mMirrorV);
} else if (currentName == "repeatU") {
XmlParser::getRealAttribute(currentNode, currentName.c_str(), out.mTransform.mScaling.x);
XmlParser::getValueAsFloat(currentNode, out.mTransform.mScaling.x);
} else if (currentName == "repeatV") {
XmlParser::getRealAttribute(currentNode, currentName.c_str(), out.mTransform.mScaling.y);
XmlParser::getValueAsFloat(currentNode, out.mTransform.mScaling.y);
} else if (currentName == "offsetU") {
XmlParser::getRealAttribute(currentNode, currentName.c_str(), out.mTransform.mTranslation.x);
XmlParser::getValueAsFloat(currentNode, out.mTransform.mTranslation.x);
} else if (currentName == "offsetV") {
XmlParser::getRealAttribute(currentNode, currentName.c_str(), out.mTransform.mTranslation.y);
XmlParser::getValueAsFloat(currentNode, out.mTransform.mTranslation.y);
} else if (currentName == "rotateUV") {
XmlParser::getRealAttribute(currentNode, currentName.c_str(), out.mTransform.mRotation);
XmlParser::getValueAsFloat(currentNode, out.mTransform.mRotation);
} else if (currentName == "blend_mode") {
std::string v;
XmlParser::getValueAsString(currentNode, v);
@@ -1178,14 +1181,14 @@ void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) {
// OKINO extensions
// -------------------------------------------------------
else if (currentName == "weighting") {
XmlParser::getRealAttribute(currentNode, currentName.c_str(), out.mWeighting);
XmlParser::getValueAsFloat(currentNode, out.mWeighting);
} else if (currentName == "mix_with_previous_layer") {
XmlParser::getRealAttribute(currentNode, currentName.c_str(), out.mMixWithPrevious);
XmlParser::getValueAsFloat(currentNode, out.mMixWithPrevious);
}
// MAX3D extensions
// -------------------------------------------------------
else if (currentName == "amount") {
XmlParser::getRealAttribute(currentNode, currentName.c_str(), out.mWeighting);
XmlParser::getValueAsFloat(currentNode, out.mWeighting);
}
}
}
@@ -2204,7 +2207,7 @@ void ColladaParser::ReadMaterialVertexInputBinding(XmlNode &node, Collada::Seman
void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive) {
// Attempt to load any undefined Collada::Image in ImageLibrary
for (auto & it : mImageLibrary) {
for (auto &it : mImageLibrary) {
Collada::Image &image = it.second;
if (image.mImageData.empty()) {
+5
View File
@@ -378,6 +378,11 @@ void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& bloc
const DXF::Block& bl_src = *(*it).second;
for (std::shared_ptr<const DXF::PolyLine> pl_in : bl_src.lines) {
if (!pl_in) {
ASSIMP_LOG_ERROR("DXF: PolyLine instance is nullptr, skipping.");
continue;
}
std::shared_ptr<DXF::PolyLine> pl_out = std::shared_ptr<DXF::PolyLine>(new DXF::PolyLine(*pl_in));
if (bl_src.base.Length() || insert.scale.x!=1.f || insert.scale.y!=1.f || insert.scale.z!=1.f || insert.angle || insert.pos.Length()) {
+89 -11
View File
@@ -79,7 +79,7 @@ using namespace Util;
#define MAGIC_NODE_TAG "_$AssimpFbx$"
#define CONVERT_FBX_TIME(time) (static_cast<double>(time) * 1000.0 / 46186158000LL)
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBones) :
defaultMaterialIndex(),
@@ -1128,7 +1128,7 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
*out_uv++ = aiVector3D(v.x, v.y, 0.0f);
}
out_mesh->mTextureCoordsNames[i] = mesh.GetTextureCoordChannelName(i);
out_mesh->SetTextureCoordsName(i, aiString(mesh.GetTextureCoordChannelName(i)));
out_mesh->mNumUVComponents[i] = 2;
}
@@ -2618,7 +2618,7 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
meshMorphAnim->mKeys[j].mValues = new unsigned int[numValuesAndWeights];
meshMorphAnim->mKeys[j].mWeights = new double[numValuesAndWeights];
meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first);
meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first) * anim_fps;
for (unsigned int k = 0; k < numValuesAndWeights; k++) {
meshMorphAnim->mKeys[j].mValues[k] = keyData->values.at(k);
meshMorphAnim->mKeys[j].mWeights[k] = keyData->weights.at(k);
@@ -2636,8 +2636,8 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
return;
}
double start_time_fps = has_local_startstop ? CONVERT_FBX_TIME(start_time) : min_time;
double stop_time_fps = has_local_startstop ? CONVERT_FBX_TIME(stop_time) : max_time;
double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time;
double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time;
// adjust relative timing for animation
for (unsigned int c = 0; c < anim->mNumChannels; c++) {
@@ -3127,7 +3127,12 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
if (chain[i] == iterEnd)
continue;
keyframeLists[i] = GetKeyframeList((*chain[i]).second, start, stop);
if (i == TransformationComp_Rotation || i == TransformationComp_PreRotation
|| i == TransformationComp_PostRotation || i == TransformationComp_GeometricRotation) {
keyframeLists[i] = GetRotationKeyframeList((*chain[i]).second, start, stop);
} else {
keyframeLists[i] = GetKeyframeList((*chain[i]).second, start, stop);
}
for (KeyFrameListList::const_iterator it = keyframeLists[i].begin(); it != keyframeLists[i].end(); ++it) {
const KeyTimeList& times = *std::get<0>(*it);
@@ -3157,7 +3162,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
InterpolateKeys(outTranslations, keytimes, keyframeLists[TransformationComp_Translation], defTranslate, maxTime, minTime);
} else {
for (size_t i = 0; i < keyCount; ++i) {
outTranslations[i].mTime = CONVERT_FBX_TIME(keytimes[i]);
outTranslations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
outTranslations[i].mValue = defTranslate;
}
}
@@ -3166,7 +3171,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], defRotation, maxTime, minTime, rotOrder);
} else {
for (size_t i = 0; i < keyCount; ++i) {
outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]);
outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
outRotations[i].mValue = defQuat;
}
}
@@ -3175,7 +3180,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
InterpolateKeys(outScales, keytimes, keyframeLists[TransformationComp_Scaling], defScale, maxTime, minTime);
} else {
for (size_t i = 0; i < keyCount; ++i) {
outScales[i].mTime = CONVERT_FBX_TIME(keytimes[i]);
outScales[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
outScales[i].mValue = defScale;
}
}
@@ -3274,6 +3279,79 @@ FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector<c
return inputs; // pray for NRVO :-)
}
FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std::vector<const AnimationCurveNode *> &nodes,
int64_t start, int64_t stop) {
KeyFrameListList inputs;
inputs.reserve(nodes.size() * 3);
//give some breathing room for rounding errors
const int64_t adj_start = start - 10000;
const int64_t adj_stop = stop + 10000;
for (const AnimationCurveNode *node : nodes) {
ai_assert(node);
const AnimationCurveMap &curves = node->Curves();
for (const AnimationCurveMap::value_type &kv : curves) {
unsigned int mapto;
if (kv.first == "d|X") {
mapto = 0;
} else if (kv.first == "d|Y") {
mapto = 1;
} else if (kv.first == "d|Z") {
mapto = 2;
} else {
FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component");
continue;
}
const AnimationCurve *const curve = kv.second;
ai_assert(curve->GetKeys().size() == curve->GetValues().size());
ai_assert(curve->GetKeys().size());
//get values within the start/stop time window
std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
std::shared_ptr<KeyValueList> Values(new KeyValueList());
const size_t count = curve->GetKeys().size();
int64_t tp = curve->GetKeys().at(0);
float vp = curve->GetValues().at(0);
Keys->push_back(tp);
Values->push_back(vp);
if (count > 1) {
int64_t tc = curve->GetKeys().at(1);
float vc = curve->GetValues().at(1);
for (size_t n = 1; n < count; n++) {
while (std::abs(vc - vp) >= 180.0f) {
float step = std::floor(float(tc - tp) / (vc - vp) * 179.0f);
int64_t tnew = tp + int64_t(step);
float vnew = vp + (vc - vp) * step / float(tc - tp);
if (tnew >= adj_start && tnew <= adj_stop) {
Keys->push_back(tnew);
Values->push_back(vnew);
}
tp = tnew;
vp = vnew;
}
if (tc >= adj_start && tc <= adj_stop) {
Keys->push_back(tc);
Values->push_back(vc);
}
if (n + 1 < count) {
tp = tc;
vp = vc;
tc = curve->GetKeys().at(n + 1);
vc = curve->GetValues().at(n + 1);
}
}
}
inputs.push_back(std::make_tuple(Keys, Values, mapto));
}
}
return inputs;
}
KeyTimeList FBXConverter::GetKeyTimeList(const KeyFrameListList &inputs) {
ai_assert(!inputs.empty());
@@ -3364,7 +3442,7 @@ void FBXConverter::InterpolateKeys(aiVectorKey *valOut, const KeyTimeList &keys,
}
// magic value to convert fbx times to seconds
valOut->mTime = CONVERT_FBX_TIME(time);
valOut->mTime = CONVERT_FBX_TIME(time) * anim_fps;
min_time = std::min(min_time, valOut->mTime);
max_time = std::max(max_time, valOut->mTime);
@@ -3464,7 +3542,7 @@ void FBXConverter::ConvertRotationKeys(aiNodeAnim *na, const std::vector<const A
ai_assert(nodes.size());
// XXX see notes in ConvertScaleKeys()
const std::vector<KeyFrameList> &inputs = GetKeyframeList(nodes, start, stop);
const std::vector<KeyFrameList> &inputs = GetRotationKeyframeList(nodes, start, stop);
const KeyTimeList &keys = GetKeyTimeList(inputs);
na->mNumRotationKeys = static_cast<unsigned int>(keys.size());
+1
View File
@@ -361,6 +361,7 @@ private:
// ------------------------------------------------------------------------------------------------
KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop);
KeyFrameListList GetRotationKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop);
// ------------------------------------------------------------------------------------------------
KeyTimeList GetKeyTimeList(const KeyFrameListList& inputs);
+12 -5
View File
@@ -451,6 +451,7 @@ void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char *szC
// now we need to skip any other skins ...
for (unsigned int i = 1; i < iNumSkins; ++i) {
SizeCheck(szCursor + 3 * sizeof(uint32_t));
iType = *((uint32_t *)szCursor);
szCursor += sizeof(uint32_t);
iWidth = *((uint32_t *)szCursor);
@@ -472,16 +473,22 @@ void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char *szC
// ------------------------------------------------------------------------------------------------
// Generate proepr texture coords
void HMPImporter::GenerateTextureCoords(
const unsigned int width, const unsigned int height) {
void HMPImporter::GenerateTextureCoords(const unsigned int width, const unsigned int height) {
ai_assert(nullptr != pScene->mMeshes);
ai_assert(nullptr != pScene->mMeshes[0]);
ai_assert(nullptr != pScene->mMeshes[0]->mTextureCoords[0]);
aiVector3D *uv = pScene->mMeshes[0]->mTextureCoords[0];
const float fY = (1.0f / height) + (1.0f / height) / (height - 1);
const float fX = (1.0f / width) + (1.0f / width) / (width - 1);
if (uv == nullptr) {
return;
}
if (height == 0.0f || width == 0.0) {
return;
}
const float fY = (1.0f / height) + (1.0f / height) / height;
const float fX = (1.0f / width) + (1.0f / width) / width;
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int x = 0; x < width; ++x, ++uv) {
+1 -1
View File
@@ -393,7 +393,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
// If a RGB color map is explicitly requested delete the
// alpha channel - it could theoretically be != 1.
if (_mSurfaces[i].mVCMapType == AI_LWO_RGB)
if (_mSurfaces[j].mVCMapType == AI_LWO_RGB)
pvVC[w]->a = 1.f;
pvVC[w]++;
+2 -2
View File
@@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define M3D_EXPORTER
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#define M3D_NODUP
#endif
// Header files, standard library.
#include <memory> // shared_ptr
@@ -437,6 +437,6 @@ void M3DExporter::NodeWalk(const M3DWrapper &m3d, const aiNode *pNode, aiMatrix4
}
}
} // namespace Assimp
#endif
#endif // ASSIMP_BUILD_NO_M3D_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT
+4 -5
View File
@@ -46,10 +46,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_M3DEXPORTER_H_INC
#define AI_M3DEXPORTER_H_INC
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
#include <assimp/types.h>
//#include <assimp/material.h>
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
@@ -60,8 +60,7 @@ struct aiNode;
struct aiMaterial;
struct aiFace;
namespace Assimp
{
namespace Assimp {
class IOSystem;
class IOStream;
class ExportProperties;
@@ -71,8 +70,7 @@ namespace Assimp
// ---------------------------------------------------------------------
/** Helper class to export a given scene to an M3D file. */
// ---------------------------------------------------------------------
class M3DExporter
{
class M3DExporter {
public:
/// Constructor for a specific scene to export
M3DExporter(const aiScene* pScene, const ExportProperties* pProperties);
@@ -89,6 +87,7 @@ namespace Assimp
};
}
#endif // #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#endif // ASSIMP_BUILD_NO_M3D_EXPORTER
#endif // AI_M3DEXPORTER_H_INC
+5 -3
View File
@@ -39,8 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER)
#include "M3DWrapper.h"
@@ -141,10 +141,12 @@ unsigned char *M3DWrapper::Save(int quality, int flags, unsigned int &size) {
}
void M3DWrapper::ClearSave() {
if (saved_output_)
if (saved_output_) {
M3D_FREE(saved_output_);
}
saved_output_ = nullptr;
}
} // namespace Assimp
#endif
#endif
+3 -1
View File
@@ -47,7 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_M3DWRAPPER_H_INC
#define AI_M3DWRAPPER_H_INC
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER)
#include <memory>
#include <vector>
@@ -128,5 +129,6 @@ inline m3d_t *M3DWrapper::M3D() const {
} // namespace Assimp
#endif
#endif // ASSIMP_BUILD_NO_M3D_IMPORTER
#endif // AI_M3DWRAPPER_H_INC
+1 -1
View File
@@ -896,7 +896,7 @@ char *_m3d_safestr(char *in, int morelines) {
if (!out) return NULL;
while (*i == ' ' || *i == '\t' || *i == '\r' || (morelines && *i == '\n'))
i++;
for (; *i && (morelines || (*i != '\r' && *i != '\n')); i++) {
for (; *i && (morelines || (*i != '\r' && *i != '\n')) && o - out < l; i++) {
if (*i == '\r') continue;
if (*i == '\n') {
if (morelines >= 3 && o > out && *(o - 1) == '\n') break;
+1 -1
View File
@@ -600,7 +600,7 @@ void MDLImporter::InternReadFile_3DGS_MDL345() {
// need to read all textures
for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins; ++i) {
if (szCurrent >= szEnd) {
if (szCurrent + sizeof(uint32_t) > szEnd) {
throw DeadlyImportError("Texture data past end of file.");
}
BE_NCONST MDL::Skin *pcSkin;
+6
View File
@@ -132,6 +132,9 @@ void MDLImporter::CreateTextureARGB8_3DGS_MDL3(const unsigned char *szData) {
pcNew->mWidth = pcHeader->skinwidth;
pcNew->mHeight = pcHeader->skinheight;
if(pcNew->mWidth != 0 && pcNew->mHeight > UINT_MAX/pcNew->mWidth) {
throw DeadlyImportError("Invalid MDL file. A texture is too big.");
}
pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight];
const unsigned char *szColorMap;
@@ -217,6 +220,9 @@ void MDLImporter::ParseTextureColorData(const unsigned char *szData,
// allocate storage for the texture image
if (do_read) {
if(pcNew->mWidth != 0 && pcNew->mHeight > UINT_MAX/pcNew->mWidth) {
throw DeadlyImportError("Invalid MDL file. A texture is too big.");
}
pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight];
}
+1 -1
View File
@@ -325,7 +325,7 @@ std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& i
std::transform(s.begin(),s.end(),s.begin(),&ai_tolower<char> );
if (schema->IsKnownToken(s)) {
for(cur = t+1;*cur++ != '(';);
const std::shared_ptr<const EXPRESS::DataType> dt = Parse(cur);
std::shared_ptr<const EXPRESS::DataType> dt = Parse(cur);
inout = *cur ? cur+1 : cur;
return dt;
}
+531
View File
@@ -0,0 +1,531 @@
#include "X3DGeoHelper.h"
#include "X3DImporter.hpp"
#include <assimp/vector3.h>
#include <assimp/Exceptional.h>
#include <assimp/StringUtils.h>
#include <vector>
namespace Assimp {
aiVector3D X3DGeoHelper::make_point2D(float angle, float radius) {
return aiVector3D(radius * std::cos(angle), radius * std::sin(angle), 0);
}
void X3DGeoHelper::make_arc2D(float pStartAngle, float pEndAngle, float pRadius, size_t numSegments, std::list<aiVector3D> &pVertices) {
// check argument values ranges.
if ((pStartAngle < -AI_MATH_TWO_PI_F) || (pStartAngle > AI_MATH_TWO_PI_F)) {
throw DeadlyImportError("GeometryHelper_Make_Arc2D.pStartAngle");
}
if ((pEndAngle < -AI_MATH_TWO_PI_F) || (pEndAngle > AI_MATH_TWO_PI_F)) {
throw DeadlyImportError("GeometryHelper_Make_Arc2D.pEndAngle");
}
if (pRadius <= 0) {
throw DeadlyImportError("GeometryHelper_Make_Arc2D.pRadius");
}
// calculate arc angle and check type of arc
float angle_full = std::fabs(pEndAngle - pStartAngle);
if ((angle_full > AI_MATH_TWO_PI_F) || (angle_full == 0.0f)) {
angle_full = AI_MATH_TWO_PI_F;
}
// calculate angle for one step - angle to next point of line.
float angle_step = angle_full / (float)numSegments;
// make points
for (size_t pi = 0; pi <= numSegments; pi++) {
float tangle = pStartAngle + pi * angle_step;
pVertices.emplace_back(make_point2D(tangle, pRadius));
} // for(size_t pi = 0; pi <= pNumSegments; pi++)
// if we making full circle then add last vertex equal to first vertex
if (angle_full == AI_MATH_TWO_PI_F) pVertices.push_back(*pVertices.begin());
}
void X3DGeoHelper::extend_point_to_line(const std::list<aiVector3D> &pPoint, std::list<aiVector3D> &pLine) {
std::list<aiVector3D>::const_iterator pit = pPoint.begin();
std::list<aiVector3D>::const_iterator pit_last = pPoint.end();
--pit_last;
if (pPoint.size() < 2) {
throw DeadlyImportError("GeometryHelper_Extend_PointToLine.pPoint.size() can not be less than 2.");
}
// add first point of first line.
pLine.push_back(*pit++);
// add internal points
while (pit != pit_last) {
pLine.push_back(*pit); // second point of previous line
pLine.push_back(*pit); // first point of next line
++pit;
}
// add last point of last line
pLine.push_back(*pit);
}
void X3DGeoHelper::polylineIdx_to_lineIdx(const std::list<int32_t> &pPolylineCoordIdx, std::list<int32_t> &pLineCoordIdx) {
std::list<int32_t>::const_iterator plit = pPolylineCoordIdx.begin();
while (plit != pPolylineCoordIdx.end()) {
// add first point of polyline
pLineCoordIdx.push_back(*plit++);
while ((*plit != (-1)) && (plit != pPolylineCoordIdx.end())) {
std::list<int32_t>::const_iterator plit_next;
plit_next = plit, ++plit_next;
pLineCoordIdx.push_back(*plit); // second point of previous line.
pLineCoordIdx.push_back(-1); // delimiter
if ((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break; // current polyline is finished
pLineCoordIdx.push_back(*plit); // first point of next line.
plit = plit_next;
} // while((*plit != (-1)) && (plit != pPolylineCoordIdx.end()))
} // while(plit != pPolylineCoordIdx.end())
}
#define MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4) \
do { \
if (pCCW) { \
pOut.push_back(pIn[pP1]); \
pOut.push_back(pIn[pP2]); \
pOut.push_back(pIn[pP3]); \
pOut.push_back(pIn[pP4]); \
} else { \
pOut.push_back(pIn[pP4]); \
pOut.push_back(pIn[pP3]); \
pOut.push_back(pIn[pP2]); \
pOut.push_back(pIn[pP1]); \
} \
} while (false)
#define MESH_RectParallelepiped_CREATE_VERT \
aiVector3D vert_set[8]; \
float x1, x2, y1, y2, z1, z2, hs; \
\
hs = pSize.x / 2, x1 = -hs, x2 = hs; \
hs = pSize.y / 2, y1 = -hs, y2 = hs; \
hs = pSize.z / 2, z1 = -hs, z2 = hs; \
vert_set[0].Set(x2, y1, z2); \
vert_set[1].Set(x2, y2, z2); \
vert_set[2].Set(x2, y2, z1); \
vert_set[3].Set(x2, y1, z1); \
vert_set[4].Set(x1, y1, z2); \
vert_set[5].Set(x1, y2, z2); \
vert_set[6].Set(x1, y2, z1); \
vert_set[7].Set(x1, y1, z1)
void X3DGeoHelper::rect_parallel_epiped(const aiVector3D &pSize, std::list<aiVector3D> &pVertices) {
MESH_RectParallelepiped_CREATE_VERT;
MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 3, 2, 1, 0); // front
MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 6, 7, 4, 5); // back
MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 3, 0, 4); // left
MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 2, 6, 5, 1); // right
MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 0, 1, 5, 4); // top
MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 6, 2, 3); // bottom
}
#undef MESH_RectParallelepiped_CREATE_VERT
void X3DGeoHelper::coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces, unsigned int &pPrimitiveTypes) {
std::vector<int32_t> f_data(pCoordIdx);
std::vector<unsigned int> inds;
unsigned int prim_type = 0;
if (f_data.back() != (-1)) {
f_data.push_back(-1);
}
// reserve average size.
pFaces.reserve(f_data.size() / 3);
inds.reserve(4);
//PrintVectorSet("build. ci", pCoordIdx);
for (std::vector<int32_t>::iterator it = f_data.begin(); it != f_data.end(); ++it) {
// when face is got count how many indices in it.
if (*it == (-1)) {
aiFace tface;
size_t ts;
ts = inds.size();
switch (ts) {
case 0:
goto mg_m_err;
case 1:
prim_type |= aiPrimitiveType_POINT;
break;
case 2:
prim_type |= aiPrimitiveType_LINE;
break;
case 3:
prim_type |= aiPrimitiveType_TRIANGLE;
break;
default:
prim_type |= aiPrimitiveType_POLYGON;
break;
}
tface.mNumIndices = static_cast<unsigned int>(ts);
tface.mIndices = new unsigned int[ts];
memcpy(tface.mIndices, inds.data(), ts * sizeof(unsigned int));
pFaces.push_back(tface);
inds.clear();
} // if(*it == (-1))
else {
inds.push_back(*it);
} // if(*it == (-1)) else
} // for(std::list<int32_t>::iterator it = f_data.begin(); it != f_data.end(); it++)
//PrintVectorSet("build. faces", pCoordIdx);
pPrimitiveTypes = prim_type;
return;
mg_m_err:
for (size_t i = 0, i_e = pFaces.size(); i < i_e; i++)
delete[] pFaces.at(i).mIndices;
pFaces.clear();
}
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
std::list<aiColor4D> tcol;
// create RGBA array from RGB.
for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it)
tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1));
// call existing function for adding RGBA colors
add_color(pMesh, tcol, pColorPerVertex);
}
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor4D> &pColors, const bool pColorPerVertex) {
std::list<aiColor4D>::const_iterator col_it = pColors.begin();
if (pColorPerVertex) {
if (pColors.size() < pMesh.mNumVertices) {
throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Vertices count(" +
ai_to_string(pMesh.mNumVertices) + ").");
}
// copy colors to mesh
pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
for (size_t i = 0; i < pMesh.mNumVertices; i++)
pMesh.mColors[0][i] = *col_it++;
} // if(pColorPerVertex)
else {
if (pColors.size() < pMesh.mNumFaces) {
throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Faces count(" +
ai_to_string(pMesh.mNumFaces) + ").");
}
// copy colors to mesh
pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
// apply color to all vertices of face
for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) {
pMesh.mColors[0][pMesh.mFaces[fi].mIndices[vi]] = *col_it;
}
++col_it;
}
} // if(pColorPerVertex) else
}
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
std::list<aiColor4D> tcol;
// create RGBA array from RGB.
for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it) {
tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1));
}
// call existing function for adding RGBA colors
add_color(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex);
}
void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &coordIdx, const std::vector<int32_t> &colorIdx,
const std::list<aiColor4D> &colors, bool pColorPerVertex) {
std::vector<aiColor4D> col_tgt_arr;
std::list<aiColor4D> col_tgt_list;
std::vector<aiColor4D> col_arr_copy;
if (coordIdx.size() == 0) {
throw DeadlyImportError("MeshGeometry_AddColor2. pCoordIdx can not be empty.");
}
// copy list to array because we are need indexed access to colors.
col_arr_copy.reserve(colors.size());
for (std::list<aiColor4D>::const_iterator it = colors.begin(); it != colors.end(); ++it) {
col_arr_copy.push_back(*it);
}
if (pColorPerVertex) {
if (colorIdx.size() > 0) {
// check indices array count.
if (colorIdx.size() < coordIdx.size()) {
throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
") can not be less than Coords indices count(" + ai_to_string(coordIdx.size()) + ").");
}
// create list with colors for every vertex.
col_tgt_arr.resize(pMesh.mNumVertices);
for (std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin(), coordidx_it = coordIdx.begin(); colidx_it != colorIdx.end(); ++colidx_it, ++coordidx_it) {
if (*colidx_it == (-1)) {
continue; // skip faces delimiter
}
if ((unsigned int)(*coordidx_it) > pMesh.mNumVertices) {
throw DeadlyImportError("MeshGeometry_AddColor2. Coordinate idx is out of range.");
}
if ((unsigned int)*colidx_it > pMesh.mNumVertices) {
throw DeadlyImportError("MeshGeometry_AddColor2. Color idx is out of range.");
}
col_tgt_arr[*coordidx_it] = col_arr_copy[*colidx_it];
}
} // if(pColorIdx.size() > 0)
else {
// when color indices list is absent use CoordIdx.
// check indices array count.
if (colors.size() < pMesh.mNumVertices) {
throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Vertices count(" +
ai_to_string(pMesh.mNumVertices) + ").");
}
// create list with colors for every vertex.
col_tgt_arr.resize(pMesh.mNumVertices);
for (size_t i = 0; i < pMesh.mNumVertices; i++) {
col_tgt_arr[i] = col_arr_copy[i];
}
} // if(pColorIdx.size() > 0) else
} // if(pColorPerVertex)
else {
if (colorIdx.size() > 0) {
// check indices array count.
if (colorIdx.size() < pMesh.mNumFaces) {
throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
") can not be less than Faces count(" + ai_to_string(pMesh.mNumFaces) + ").");
}
// create list with colors for every vertex using faces indices.
col_tgt_arr.resize(pMesh.mNumFaces);
std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin();
for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
if ((unsigned int)*colidx_it > pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddColor2. Face idx is out of range.");
col_tgt_arr[fi] = col_arr_copy[*colidx_it++];
}
} // if(pColorIdx.size() > 0)
else {
// when color indices list is absent use CoordIdx.
// check indices array count.
if (colors.size() < pMesh.mNumFaces) {
throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Faces count(" +
ai_to_string(pMesh.mNumFaces) + ").");
}
// create list with colors for every vertex using faces indices.
col_tgt_arr.resize(pMesh.mNumFaces);
for (size_t fi = 0; fi < pMesh.mNumFaces; fi++)
col_tgt_arr[fi] = col_arr_copy[fi];
} // if(pColorIdx.size() > 0) else
} // if(pColorPerVertex) else
// copy array to list for calling function that add colors.
for (std::vector<aiColor4D>::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); ++it)
col_tgt_list.push_back(*it);
// add prepared colors list to mesh.
add_color(pMesh, col_tgt_list, pColorPerVertex);
}
void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pNormalIdx,
const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
std::vector<size_t> tind;
std::vector<aiVector3D> norm_arr_copy;
// copy list to array because we are need indexed access to normals.
norm_arr_copy.reserve(pNormals.size());
for (std::list<aiVector3D>::const_iterator it = pNormals.begin(); it != pNormals.end(); ++it) {
norm_arr_copy.push_back(*it);
}
if (pNormalPerVertex) {
if (pNormalIdx.size() > 0) {
// check indices array count.
if (pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal.");
tind.reserve(pNormalIdx.size());
for (std::vector<int32_t>::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); ++it) {
if (*it != (-1)) tind.push_back(*it);
}
// copy normals to mesh
pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
for (size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++) {
if (tind[i] >= norm_arr_copy.size())
throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + ai_to_string(tind[i]) +
") is out of range. Normals count: " + ai_to_string(norm_arr_copy.size()) + ".");
pMesh.mNormals[i] = norm_arr_copy[tind[i]];
}
} else {
if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
// copy normals to mesh
pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
for (size_t i = 0; i < pMesh.mNumVertices; i++)
pMesh.mNormals[i] = *norm_it++;
}
} // if(pNormalPerVertex)
else {
if (pNormalIdx.size() > 0) {
if (pMesh.mNumFaces != pNormalIdx.size()) throw DeadlyImportError("Normals faces count must be equal to mesh faces count.");
std::vector<int32_t>::const_iterator normidx_it = pNormalIdx.begin();
tind.reserve(pNormalIdx.size());
for (size_t i = 0, i_e = pNormalIdx.size(); i < i_e; i++)
tind.push_back(*normidx_it++);
} else {
tind.reserve(pMesh.mNumFaces);
for (size_t i = 0; i < pMesh.mNumFaces; i++)
tind.push_back(i);
}
// copy normals to mesh
pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
aiVector3D tnorm;
tnorm = norm_arr_copy[tind[fi]];
for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++)
pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = tnorm;
}
} // if(pNormalPerVertex) else
}
void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
if (pNormalPerVertex) {
if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
// copy normals to mesh
pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
for (size_t i = 0; i < pMesh.mNumVertices; i++)
pMesh.mNormals[i] = *norm_it++;
} // if(pNormalPerVertex)
else {
if (pNormals.size() != pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and faces count must be equal.");
// copy normals to mesh
pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
// apply color to all vertices of face
for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++)
pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = *norm_it;
++norm_it;
}
} // if(pNormalPerVertex) else
}
void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pTexCoordIdx,
const std::list<aiVector2D> &pTexCoords) {
std::vector<aiVector3D> texcoord_arr_copy;
std::vector<aiFace> faces;
unsigned int prim_type;
// copy list to array because we are need indexed access to normals.
texcoord_arr_copy.reserve(pTexCoords.size());
for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) {
texcoord_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0));
}
if (pTexCoordIdx.size() > 0) {
coordIdx_str2faces_arr(pTexCoordIdx, faces, prim_type);
if (faces.empty()) {
throw DeadlyImportError("Failed to add texture coordinates to mesh, faces list is empty.");
}
if (faces.size() != pMesh.mNumFaces) {
throw DeadlyImportError("Texture coordinates faces count must be equal to mesh faces count.");
}
} else {
coordIdx_str2faces_arr(pCoordIdx, faces, prim_type);
}
pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
pMesh.mNumUVComponents[0] = 2;
for (size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++) {
if (pMesh.mFaces[fi].mNumIndices != faces.at(fi).mNumIndices)
throw DeadlyImportError("Number of indices in texture face and mesh face must be equal. Invalid face index: " + ai_to_string(fi) + ".");
for (size_t ii = 0; ii < pMesh.mFaces[fi].mNumIndices; ii++) {
size_t vert_idx = pMesh.mFaces[fi].mIndices[ii];
size_t tc_idx = faces.at(fi).mIndices[ii];
pMesh.mTextureCoords[0][vert_idx] = texcoord_arr_copy.at(tc_idx);
}
} // for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++)
}
void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::list<aiVector2D> &pTexCoords) {
std::vector<aiVector3D> tc_arr_copy;
if (pTexCoords.size() != pMesh.mNumVertices) {
throw DeadlyImportError("MeshGeometry_AddTexCoord. Texture coordinates and vertices count must be equal.");
}
// copy list to array because we are need convert aiVector2D to aiVector3D and also get indexed access as a bonus.
tc_arr_copy.reserve(pTexCoords.size());
for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) {
tc_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0));
}
// copy texture coordinates to mesh
pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
pMesh.mNumUVComponents[0] = 2;
for (size_t i = 0; i < pMesh.mNumVertices; i++) {
pMesh.mTextureCoords[0][i] = tc_arr_copy[i];
}
}
aiMesh *X3DGeoHelper::make_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) {
std::vector<aiFace> faces;
unsigned int prim_type = 0;
// create faces array from input string with vertices indices.
X3DGeoHelper::coordIdx_str2faces_arr(pCoordIdx, faces, prim_type);
if (!faces.size()) {
throw DeadlyImportError("Failed to create mesh, faces list is empty.");
}
//
// Create new mesh and copy geometry data.
//
aiMesh *tmesh = new aiMesh;
size_t ts = faces.size();
// faces
tmesh->mFaces = new aiFace[ts];
tmesh->mNumFaces = static_cast<unsigned int>(ts);
for (size_t i = 0; i < ts; i++)
tmesh->mFaces[i] = faces.at(i);
// vertices
std::list<aiVector3D>::const_iterator vit = pVertices.begin();
ts = pVertices.size();
tmesh->mVertices = new aiVector3D[ts];
tmesh->mNumVertices = static_cast<unsigned int>(ts);
for (size_t i = 0; i < ts; i++) {
tmesh->mVertices[i] = *vit++;
}
// set primitives type and return result.
tmesh->mPrimitiveTypes = prim_type;
return tmesh;
}
} // namespace Assimp
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include <assimp/vector2.h>
#include <assimp/vector3.h>
#include <assimp/color4.h>
#include <assimp/types.h>
#include <list>
#include <vector>
struct aiFace;
struct aiMesh;
namespace Assimp {
class X3DGeoHelper {
public:
static aiVector3D make_point2D(float angle, float radius);
static void make_arc2D(float pStartAngle, float pEndAngle, float pRadius, size_t numSegments, std::list<aiVector3D> &pVertices);
static void extend_point_to_line(const std::list<aiVector3D> &pPoint, std::list<aiVector3D> &pLine);
static void polylineIdx_to_lineIdx(const std::list<int32_t> &pPolylineCoordIdx, std::list<int32_t> &pLineCoordIdx);
static void rect_parallel_epiped(const aiVector3D &pSize, std::list<aiVector3D> &pVertices);
static void coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces, unsigned int &pPrimitiveTypes);
static void add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex);
static void add_color(aiMesh &pMesh, const std::list<aiColor4D> &pColors, const bool pColorPerVertex);
static void add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
const std::list<aiColor3D> &pColors, const bool pColorPerVertex);
static void add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
const std::list<aiColor4D> &pColors, const bool pColorPerVertex);
static void add_normal(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pNormalIdx,
const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex);
static void add_normal(aiMesh &pMesh, const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex);
static void add_tex_coord(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pTexCoordIdx,
const std::list<aiVector2D> &pTexCoords);
static void add_tex_coord(aiMesh &pMesh, const std::list<aiVector2D> &pTexCoords);
static aiMesh *make_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices);
};
} // namespace Assimp
+353 -53
View File
@@ -46,16 +46,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include <assimp/StringUtils.h>
#include "X3DImporter_Macro.hpp"
// Header files, Assimp.
#include <assimp/DefaultIOSystem.h>
#include <assimp/fast_atof.h>
// Header files, stdlib.
#include <iterator>
#include <memory>
#include <string>
namespace Assimp {
@@ -73,60 +70,119 @@ const aiImporterDesc X3DImporter::Description = {
"x3d x3db"
};
struct WordIterator {
using iterator_category = std::input_iterator_tag;
using value_type = const char *;
using difference_type = ptrdiff_t;
using pointer = value_type *;
using reference = value_type &;
bool X3DImporter::isNodeEmpty(XmlNode &node) {
return node.first_child().empty();
}
static const char *whitespace;
const char *mStart, *mEnd;
void X3DImporter::checkNodeMustBeEmpty(XmlNode &node) {
if (!isNodeEmpty(node)) throw DeadlyImportError(std::string("Node <") + node.name() + "> must be empty.");
}
WordIterator(const char *start, const char *end) :
mStart(start),
mEnd(end) {
mStart = start + ::strspn(start, whitespace);
if (mStart >= mEnd) {
mStart = 0;
void X3DImporter::skipUnsupportedNode(const std::string &pParentNodeName, XmlNode &node) {
static const size_t Uns_Skip_Len = 192;
static const char *Uns_Skip[Uns_Skip_Len] = {
// CAD geometry component
"CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet",
// Core
"ROUTE", "ExternProtoDeclare", "ProtoDeclare", "ProtoInstance", "ProtoInterface", "WorldInfo",
// Distributed interactive simulation (DIS) component
"DISEntityManager", "DISEntityTypeMapping", "EspduTransform", "ReceiverPdu", "SignalPdu", "TransmitterPdu",
// Cube map environmental texturing component
"ComposedCubeMapTexture", "GeneratedCubeMapTexture", "ImageCubeMapTexture",
// Environmental effects component
"Background", "Fog", "FogCoordinate", "LocalFog", "TextureBackground",
// Environmental sensor component
"ProximitySensor", "TransformSensor", "VisibilitySensor",
// Followers component
"ColorChaser", "ColorDamper", "CoordinateChaser", "CoordinateDamper", "OrientationChaser", "OrientationDamper", "PositionChaser", "PositionChaser2D",
"PositionDamper", "PositionDamper2D", "ScalarChaser", "ScalarDamper", "TexCoordChaser2D", "TexCoordDamper2D",
// Geospatial component
"GeoCoordinate", "GeoElevationGrid", "GeoLocation", "GeoLOD", "GeoMetadata", "GeoOrigin", "GeoPositionInterpolator", "GeoProximitySensor",
"GeoTouchSensor", "GeoTransform", "GeoViewpoint",
// Humanoid Animation (H-Anim) component
"HAnimDisplacer", "HAnimHumanoid", "HAnimJoint", "HAnimSegment", "HAnimSite",
// Interpolation component
"ColorInterpolator", "CoordinateInterpolator", "CoordinateInterpolator2D", "EaseInEaseOut", "NormalInterpolator", "OrientationInterpolator",
"PositionInterpolator", "PositionInterpolator2D", "ScalarInterpolator", "SplinePositionInterpolator", "SplinePositionInterpolator2D",
"SplineScalarInterpolator", "SquadOrientationInterpolator",
// Key device sensor component
"KeySensor", "StringSensor",
// Layering component
"Layer", "LayerSet", "Viewport",
// Layout component
"Layout", "LayoutGroup", "LayoutLayer", "ScreenFontStyle", "ScreenGroup",
// Navigation component
"Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup",
// Networking component
"EXPORT", "IMPORT", "Anchor", "LoadSensor",
// NURBS component
"Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface",
"NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate",
"NurbsTrimmedSurface",
// Particle systems component
"BoundedPhysicsModel", "ConeEmitter", "ExplosionEmitter", "ForcePhysicsModel", "ParticleSystem", "PointEmitter", "PolylineEmitter", "SurfaceEmitter",
"VolumeEmitter", "WindPhysicsModel",
// Picking component
"LinePickSensor", "PickableGroup", "PointPickSensor", "PrimitivePickSensor", "VolumePickSensor",
// Pointing device sensor component
"CylinderSensor", "PlaneSensor", "SphereSensor", "TouchSensor",
// Rendering component
"ClipPlane",
// Rigid body physics
"BallJoint", "CollidableOffset", "CollidableShape", "CollisionCollection", "CollisionSensor", "CollisionSpace", "Contact", "DoubleAxisHingeJoint",
"MotorJoint", "RigidBody", "RigidBodyCollection", "SingleAxisHingeJoint", "SliderJoint", "UniversalJoint",
// Scripting component
"Script",
// Programmable shaders component
"ComposedShader", "FloatVertexAttribute", "Matrix3VertexAttribute", "Matrix4VertexAttribute", "PackagedShader", "ProgramShader", "ShaderPart",
"ShaderProgram",
// Shape component
"FillProperties", "LineProperties", "TwoSidedMaterial",
// Sound component
"AudioClip", "Sound",
// Text component
"FontStyle", "Text",
// Texturing3D Component
"ComposedTexture3D", "ImageTexture3D", "PixelTexture3D", "TextureCoordinate3D", "TextureCoordinate4D", "TextureTransformMatrix3D", "TextureTransform3D",
// Texturing component
"MovieTexture", "MultiTexture", "MultiTextureCoordinate", "MultiTextureTransform", "PixelTexture", "TextureCoordinateGenerator", "TextureProperties",
// Time component
"TimeSensor",
// Event Utilities component
"BooleanFilter", "BooleanSequencer", "BooleanToggle", "BooleanTrigger", "IntegerSequencer", "IntegerTrigger", "TimeTrigger",
// Volume rendering component
"BlendedVolumeStyle", "BoundaryEnhancementVolumeStyle", "CartoonVolumeStyle", "ComposedVolumeStyle", "EdgeEnhancementVolumeStyle", "IsoSurfaceVolumeData",
"OpacityMapVolumeStyle", "ProjectionVolumeStyle", "SegmentedVolumeData", "ShadedVolumeStyle", "SilhouetteEnhancementVolumeStyle", "ToneMappedVolumeStyle",
"VolumeData"
};
const std::string nn = node.name();
if (nn.empty()) {
const std::string nv = node.value();
if (!nv.empty()) {
LogInfo("Ignoring comment \"" + nv + "\" in " + pParentNodeName + ".");
return;
}
}
WordIterator() :
mStart(0),
mEnd(0) {}
WordIterator(const WordIterator &other) :
mStart(other.mStart),
mEnd(other.mEnd) {}
WordIterator &operator=(const WordIterator &other) {
mStart = other.mStart;
mEnd = other.mEnd;
return *this;
}
bool operator==(const WordIterator &other) const { return mStart == other.mStart; }
bool found = false;
bool operator!=(const WordIterator &other) const { return mStart != other.mStart; }
WordIterator &operator++() {
mStart += strcspn(mStart, whitespace);
mStart += strspn(mStart, whitespace);
if (mStart >= mEnd) {
mStart = 0;
for (size_t i = 0; i < Uns_Skip_Len; i++) {
if (nn == Uns_Skip[i]) {
found = true;
}
return *this;
}
WordIterator operator++(int) {
WordIterator result(*this);
++(*this);
return result;
}
const char *operator*() const { return mStart; }
};
const char *WordIterator::whitespace = ", \t\r\n";
if (!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
LogInfo("Skipping node \"" + nn + "\" in " + pParentNodeName + ".");
}
X3DImporter::X3DImporter() :
mNodeElementCur(nullptr) {
mNodeElementCur(nullptr),
mScene(nullptr),
mpIOHandler(nullptr) {
// empty
}
@@ -153,33 +209,277 @@ void X3DImporter::ParseFile(const std::string &file, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(file, mode));
if (!fileStream.get()) {
throw DeadlyImportError("Failed to open file " + file + ".");
}
}
XmlParser theParser;
if (!theParser.parse(fileStream.get())) {
return;
}
XmlNode *node = theParser.findNode("X3D");
if (nullptr == node) {
return;
}
for (auto &currentNode : node->children()) {
const std::string &currentName = currentNode.name();
if (currentName == "head") {
readHead(currentNode);
} else if (currentName == "Scene") {
readScene(currentNode);
} else {
skipUnsupportedNode("X3D", currentNode);
}
}
}
bool X3DImporter::CanRead( const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig ) const {
bool X3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig) const {
if (checkSig) {
std::string::size_type pos = pFile.find_last_of(".x3d");
if (pos != std::string::npos) {
if (GetExtension(pFile) == "x3d")
return true;
}
}
return false;
}
void X3DImporter::InternReadFile( const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler ) {
void X3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
mpIOHandler = pIOHandler;
Clear();
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
if (!stream) {
throw DeadlyImportError("Could not open file for reading");
}
std::string::size_type slashPos = pFile.find_last_of("\\/");
mScene = pScene;
pScene->mRootNode = new aiNode(pFile);
pScene->mRootNode->mParent = nullptr;
pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
pIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : pFile.substr(0, slashPos + 1));
ParseFile(pFile, pIOHandler);
pIOHandler->PopDirectory();
//search for root node element
mNodeElementCur = NodeElement_List.front();
while (mNodeElementCur->Parent != nullptr) {
mNodeElementCur = mNodeElementCur->Parent;
}
{ // fill aiScene with objects.
std::list<aiMesh *> mesh_list;
std::list<aiMaterial *> mat_list;
std::list<aiLight *> light_list;
// create nodes tree
Postprocess_BuildNode(*mNodeElementCur, *pScene->mRootNode, mesh_list, mat_list, light_list);
// copy needed data to scene
if (!mesh_list.empty()) {
std::list<aiMesh *>::const_iterator it = mesh_list.begin();
pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
for (size_t i = 0; i < pScene->mNumMeshes; i++)
pScene->mMeshes[i] = *it++;
}
if (!mat_list.empty()) {
std::list<aiMaterial *>::const_iterator it = mat_list.begin();
pScene->mNumMaterials = static_cast<unsigned int>(mat_list.size());
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
for (size_t i = 0; i < pScene->mNumMaterials; i++)
pScene->mMaterials[i] = *it++;
}
if (!light_list.empty()) {
std::list<aiLight *>::const_iterator it = light_list.begin();
pScene->mNumLights = static_cast<unsigned int>(light_list.size());
pScene->mLights = new aiLight *[pScene->mNumLights];
for (size_t i = 0; i < pScene->mNumLights; i++)
pScene->mLights[i] = *it++;
}
}
}
const aiImporterDesc *X3DImporter::GetInfo() const {
return &Description;
}
struct meta_entry {
std::string name;
std::string value;
};
void X3DImporter::readHead(XmlNode &node) {
std::vector<meta_entry> metaArray;
for (auto currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == "meta") {
//checkNodeMustBeEmpty(node);
meta_entry entry;
if (XmlParser::getStdStrAttribute(currentNode, "name", entry.name)) {
XmlParser::getStdStrAttribute(currentNode, "content", entry.value);
metaArray.emplace_back(entry);
}
}
// TODO: check if other node types in head should be supported
}
mScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metaArray.size()));
unsigned int i = 0;
for (auto currentMeta : metaArray) {
mScene->mMetaData->Set(i, currentMeta.name, aiString(currentMeta.value));
++i;
}
}
void X3DImporter::readChildNodes(XmlNode &node, const std::string &pParentNodeName) {
if (node.empty()) {
return;
}
for (auto currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == "Shape")
readShape(currentNode);
else if (currentName == "Group") {
startReadGroup(currentNode);
readChildNodes(currentNode, "Group");
endReadGroup();
} else if (currentName == "StaticGroup") {
startReadStaticGroup(currentNode);
readChildNodes(currentNode, "StaticGroup");
endReadStaticGroup();
} else if (currentName == "Transform") {
startReadTransform(currentNode);
readChildNodes(currentNode, "Transform");
endReadTransform();
} else if (currentName == "Switch") {
startReadSwitch(currentNode);
readChildNodes(currentNode, "Switch");
endReadSwitch();
} else if (currentName == "DirectionalLight") {
readDirectionalLight(currentNode);
} else if (currentName == "PointLight") {
readPointLight(currentNode);
} else if (currentName == "SpotLight") {
readSpotLight(currentNode);
} else if (currentName == "Inline") {
readInline(currentNode);
} else if (!checkForMetadataNode(currentNode)) {
skipUnsupportedNode(pParentNodeName, currentNode);
}
}
}
void X3DImporter::readScene(XmlNode &node) {
ParseHelper_Group_Begin(true);
readChildNodes(node, "Scene");
ParseHelper_Node_Exit();
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: find set ************************************************************/
/*********************************************************************************************************************************************/
bool X3DImporter::FindNodeElement_FromRoot(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement) {
for (std::list<X3DNodeElementBase *>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) {
if (((*it)->Type == pType) && ((*it)->ID == pID)) {
if (pElement != nullptr) *pElement = *it;
return true;
}
} // for(std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++)
return false;
}
bool X3DImporter::FindNodeElement_FromNode(X3DNodeElementBase *pStartNode, const std::string &pID,
const X3DElemType pType, X3DNodeElementBase **pElement) {
bool found = false; // flag: true - if requested element is found.
// Check if pStartNode - this is the element, we are looking for.
if ((pStartNode->Type == pType) && (pStartNode->ID == pID)) {
found = true;
if (pElement != nullptr) {
*pElement = pStartNode;
}
goto fne_fn_end;
} // if((pStartNode->Type() == pType) && (pStartNode->ID() == pID))
// Check childs of pStartNode.
for (std::list<X3DNodeElementBase *>::iterator ch_it = pStartNode->Children.begin(); ch_it != pStartNode->Children.end(); ++ch_it) {
found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement);
if (found) {
break;
}
} // for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = it->Children.begin(); ch_it != it->Children.end(); ch_it++)
fne_fn_end:
return found;
}
bool X3DImporter::FindNodeElement(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement) {
X3DNodeElementBase *tnd = mNodeElementCur; // temporary pointer to node.
bool static_search = false; // flag: true if searching in static node.
// At first check if we have deal with static node. Go up through parent nodes and check flag.
while (tnd != nullptr) {
if (tnd->Type == X3DElemType::ENET_Group) {
if (((X3DNodeElementGroup *)tnd)->Static) {
static_search = true; // Flag found, stop walking up. Node with static flag will holded in tnd variable.
break;
}
}
tnd = tnd->Parent; // go up in graph.
} // while (tnd != nullptr)
// at now call appropriate search function.
if (static_search) {
return FindNodeElement_FromNode(tnd, pID, pType, pElement);
} else {
return FindNodeElement_FromRoot(pID, pType, pElement);
}
}
/*********************************************************************************************************************************************/
/************************************************************ Functions: parse set ***********************************************************/
/*********************************************************************************************************************************************/
void X3DImporter::ParseHelper_Group_Begin(const bool pStatic) {
X3DNodeElementGroup *new_group = new X3DNodeElementGroup(mNodeElementCur, pStatic); // create new node with current node as parent.
// if we are adding not the root element then add new element to current element child list.
if (mNodeElementCur != nullptr) {
mNodeElementCur->Children.push_back(new_group);
}
NodeElement_List.push_back(new_group); // it's a new element - add it to list.
mNodeElementCur = new_group; // switch current element to new one.
}
void X3DImporter::ParseHelper_Node_Enter(X3DNodeElementBase *pNode) {
ai_assert(nullptr != pNode);
mNodeElementCur->Children.push_back(pNode); // add new element to current element child list.
mNodeElementCur = pNode; // switch current element to new one.
}
void X3DImporter::ParseHelper_Node_Exit() {
// check if we can walk up.
if (mNodeElementCur != nullptr) {
mNodeElementCur = mNodeElementCur->Parent;
} else {
int i = 0;
++i;
}
}
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
} // namespace Assimp
+124 -62
View File
@@ -38,16 +38,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter.hpp
/// \brief X3D-format files importer for Assimp.
/// \date 2015-2016
/// \author smal.root@gmail.com
// Thanks to acorn89 for support.
#ifndef INCLUDED_AI_X3D_IMPORTER_H
#define INCLUDED_AI_X3D_IMPORTER_H
// Header files, Assimp.
#include "X3DImporter_Node.hpp"
#include <assimp/BaseImporter.h>
#include <assimp/XmlParser.h>
#include <assimp/importerdesc.h>
@@ -57,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/ProgressHandler.hpp>
#include <list>
#include <string>
namespace Assimp {
@@ -73,6 +69,21 @@ inline void Throw_ConvertFail_Str2ArrF(const std::string &nodeName, const std::s
"\" from string to array of floats.");
}
inline void Throw_ConvertFail_Str2ArrD(const std::string &nodeName, const std::string &pAttrValue) {
throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
"\" from string to array of doubles.");
}
inline void Throw_ConvertFail_Str2ArrB(const std::string &nodeName, const std::string &pAttrValue) {
throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
"\" from string to array of booleans.");
}
inline void Throw_ConvertFail_Str2ArrI(const std::string &nodeName, const std::string &pAttrValue) {
throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
"\" from string to array of integers.");
}
inline void Throw_DEF_And_USE(const std::string &nodeName) {
throw DeadlyImportError("\"DEF\" and \"USE\" can not be defined both in <" + nodeName + ">.");
}
@@ -230,61 +241,8 @@ inline void LogInfo(const std::string &message) {
///
/// That's all for now. Enjoy
///
enum class X3DElemType {
ENET_Group, ///< Element has type "Group".
ENET_MetaBoolean, ///< Element has type "Metadata boolean".
ENET_MetaDouble, ///< Element has type "Metadata double".
ENET_MetaFloat, ///< Element has type "Metadata float".
ENET_MetaInteger, ///< Element has type "Metadata integer".
ENET_MetaSet, ///< Element has type "Metadata set".
ENET_MetaString, ///< Element has type "Metadata string".
ENET_Arc2D, ///< Element has type "Arc2D".
ENET_ArcClose2D, ///< Element has type "ArcClose2D".
ENET_Circle2D, ///< Element has type "Circle2D".
ENET_Disk2D, ///< Element has type "Disk2D".
ENET_Polyline2D, ///< Element has type "Polyline2D".
ENET_Polypoint2D, ///< Element has type "Polypoint2D".
ENET_Rectangle2D, ///< Element has type "Rectangle2D".
ENET_TriangleSet2D, ///< Element has type "TriangleSet2D".
ENET_Box, ///< Element has type "Box".
ENET_Cone, ///< Element has type "Cone".
ENET_Cylinder, ///< Element has type "Cylinder".
ENET_Sphere, ///< Element has type "Sphere".
ENET_ElevationGrid, ///< Element has type "ElevationGrid".
ENET_Extrusion, ///< Element has type "Extrusion".
ENET_Coordinate, ///< Element has type "Coordinate".
ENET_Normal, ///< Element has type "Normal".
ENET_TextureCoordinate, ///< Element has type "TextureCoordinate".
ENET_IndexedFaceSet, ///< Element has type "IndexedFaceSet".
ENET_IndexedLineSet, ///< Element has type "IndexedLineSet".
ENET_IndexedTriangleSet, ///< Element has type "IndexedTriangleSet".
ENET_IndexedTriangleFanSet, ///< Element has type "IndexedTriangleFanSet".
ENET_IndexedTriangleStripSet, ///< Element has type "IndexedTriangleStripSet".
ENET_LineSet, ///< Element has type "LineSet".
ENET_PointSet, ///< Element has type "PointSet".
ENET_TriangleSet, ///< Element has type "TriangleSet".
ENET_TriangleFanSet, ///< Element has type "TriangleFanSet".
ENET_TriangleStripSet, ///< Element has type "TriangleStripSet".
ENET_Color, ///< Element has type "Color".
ENET_ColorRGBA, ///< Element has type "ColorRGBA".
ENET_Shape, ///< Element has type "Shape".
ENET_Appearance, ///< Element has type "Appearance".
ENET_Material, ///< Element has type "Material".
ENET_ImageTexture, ///< Element has type "ImageTexture".
ENET_TextureTransform, ///< Element has type "TextureTransform".
ENET_DirectionalLight, ///< Element has type "DirectionalLight".
ENET_PointLight, ///< Element has type "PointLight".
ENET_SpotLight, ///< Element has type "SpotLight".
ENET_Invalid ///< Element has invalid type and possible contain invalid data.
};
struct X3DNodeElementBase {
X3DNodeElementBase *Parent;
std::string ID;
std::list<X3DNodeElementBase *> Child;
X3DElemType Type;
};
using X3DElementList = std::list<X3DNodeElementBase *>;
class X3DImporter : public BaseImporter {
public:
@@ -312,8 +270,112 @@ public:
void Clear();
private:
X3DNodeElementBase *MACRO_USE_CHECKANDAPPLY(XmlNode &node, std::string pDEF, std::string pUSE, X3DElemType pType, X3DNodeElementBase *pNE);
bool isNodeEmpty(XmlNode &node);
void checkNodeMustBeEmpty(XmlNode &node);
void skipUnsupportedNode(const std::string &pParentNodeName, XmlNode &node);
void readHead(XmlNode &node);
void readChildNodes(XmlNode &node, const std::string &pParentNodeName);
void readScene(XmlNode &node);
bool FindNodeElement_FromRoot(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement);
bool FindNodeElement_FromNode(X3DNodeElementBase *pStartNode, const std::string &pID,
const X3DElemType pType, X3DNodeElementBase **pElement);
bool FindNodeElement(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement);
void ParseHelper_Group_Begin(const bool pStatic = false);
void ParseHelper_Node_Enter(X3DNodeElementBase *pNode);
void ParseHelper_Node_Exit();
// 2D geometry
void readArc2D(XmlNode &node);
void readArcClose2D(XmlNode &node);
void readCircle2D(XmlNode &node);
void readDisk2D(XmlNode &node);
void readPolyline2D(XmlNode &node);
void readPolypoint2D(XmlNode &node);
void readRectangle2D(XmlNode &node);
void readTriangleSet2D(XmlNode &node);
// 3D geometry
void readBox(XmlNode &node);
void readCone(XmlNode &node);
void readCylinder(XmlNode &node);
void readElevationGrid(XmlNode &node);
void readExtrusion(XmlNode &node);
void readIndexedFaceSet(XmlNode &node);
void readSphere(XmlNode &node);
// group
void startReadGroup(XmlNode &node);
void endReadGroup();
void startReadStaticGroup(XmlNode &node);
void endReadStaticGroup();
void startReadSwitch(XmlNode &node);
void endReadSwitch();
void startReadTransform(XmlNode &node);
void endReadTransform();
// light
void readDirectionalLight(XmlNode &node);
void readPointLight(XmlNode &node);
void readSpotLight(XmlNode &node);
// metadata
bool checkForMetadataNode(XmlNode &node);
void childrenReadMetadata(XmlNode &node, X3DNodeElementBase *pParentElement, const std::string &pNodeName);
void readMetadataBoolean(XmlNode &node);
void readMetadataDouble(XmlNode &node);
void readMetadataFloat(XmlNode &node);
void readMetadataInteger(XmlNode &node);
void readMetadataSet(XmlNode &node);
void readMetadataString(XmlNode &node);
// networking
void readInline(XmlNode &node);
// postprocessing
aiMatrix4x4 PostprocessHelper_Matrix_GlobalToCurrent() const;
void PostprocessHelper_CollectMetadata(const X3DNodeElementBase &pNodeElement, std::list<X3DNodeElementBase *> &pList) const;
bool PostprocessHelper_ElementIsMetadata(const X3DElemType pType) const;
bool PostprocessHelper_ElementIsMesh(const X3DElemType pType) const;
void Postprocess_BuildLight(const X3DNodeElementBase &pNodeElement, std::list<aiLight *> &pSceneLightList) const;
void Postprocess_BuildMaterial(const X3DNodeElementBase &pNodeElement, aiMaterial **pMaterial) const;
void Postprocess_BuildMesh(const X3DNodeElementBase &pNodeElement, aiMesh **pMesh) const;
void Postprocess_BuildNode(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode, std::list<aiMesh *> &pSceneMeshList,
std::list<aiMaterial *> &pSceneMaterialList, std::list<aiLight *> &pSceneLightList) const;
void Postprocess_BuildShape(const X3DNodeElementShape &pShapeNodeElement, std::list<unsigned int> &pNodeMeshInd,
std::list<aiMesh *> &pSceneMeshList, std::list<aiMaterial *> &pSceneMaterialList) const;
void Postprocess_CollectMetadata(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode) const;
// rendering
void readColor(XmlNode &node);
void readColorRGBA(XmlNode &node);
void readCoordinate(XmlNode &node);
void readIndexedLineSet(XmlNode &node);
void readIndexedTriangleFanSet(XmlNode &node);
void readIndexedTriangleSet(XmlNode &node);
void readIndexedTriangleStripSet(XmlNode &node);
void readLineSet(XmlNode &node);
void readPointSet(XmlNode &node);
void readTriangleFanSet(XmlNode &node);
void readTriangleSet(XmlNode &node);
void readTriangleStripSet(XmlNode &node);
void readNormal(XmlNode &node);
// shape
void readShape(XmlNode &node);
void readAppearance(XmlNode &node);
void readMaterial(XmlNode &node);
// texturing
void readImageTexture(XmlNode &node);
void readTextureCoordinate(XmlNode &node);
void readTextureTransform(XmlNode &node);
static const aiImporterDesc Description;
X3DNodeElementBase *mNodeElementCur; ///< Current element.
X3DNodeElementBase *mNodeElementCur;
aiScene *mScene;
IOSystem *mpIOHandler;
}; // class X3DImporter
} // namespace Assimp
@@ -0,0 +1,467 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Geometry2D.cpp
/// \brief Parsing data from nodes of "Geometry2D" set of X3D.
/// date 2015-2016
/// author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include "X3DXmlHelper.h"
#include "X3DGeoHelper.h"
namespace Assimp {
// <Arc2D
// DEF="" ID
// USE="" IDREF
// endAngle="1.570796" SFFloat [initializeOnly]
// radius="1" SFFloat [initializeOnly]
// startAngle="0" SFFloat [initializeOnly]
// />
// The Arc2D node specifies a linear circular arc whose center is at (0,0) and whose angles are measured starting at the positive x-axis and sweeping
// towards the positive y-axis. The radius field specifies the radius of the circle of which the arc is a portion. The arc extends from the startAngle
// counterclockwise to the endAngle. The values of startAngle and endAngle shall be in the range [-2pi, 2pi] radians (or the equivalent if a different
// angle base unit has been specified). If startAngle and endAngle have the same value, a circle is specified.
void X3DImporter::readArc2D(XmlNode &node) {
std::string def, use;
float endAngle = AI_MATH_HALF_PI_F;
float radius = 1;
float startAngle = 0;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getFloatAttribute(node, "endAngle", endAngle);
XmlParser::getFloatAttribute(node, "radius", radius);
XmlParser::getFloatAttribute(node, "startAngle", startAngle);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Arc2D, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Arc2D, mNodeElementCur);
if (!def.empty()) ne->ID = def;
// create point list of geometry object and convert it to line set.
std::list<aiVector3D> tlist;
X3DGeoHelper::make_arc2D(startAngle, endAngle, radius, 10, tlist); ///TODO: IME - AI_CONFIG for NumSeg
X3DGeoHelper::extend_point_to_line(tlist, ((X3DNodeElementGeometry2D *)ne)->Vertices);
((X3DNodeElementGeometry2D *)ne)->NumIndices = 2;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Arc2D");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <ArcClose2D
// DEF="" ID
// USE="" IDREF
// closureType="PIE" SFString [initializeOnly], {"PIE", "CHORD"}
// endAngle="1.570796" SFFloat [initializeOnly]
// radius="1" SFFloat [initializeOnly]
// solid="false" SFBool [initializeOnly]
// startAngle="0" SFFloat [initializeOnly]
// />
// The ArcClose node specifies a portion of a circle whose center is at (0,0) and whose angles are measured starting at the positive x-axis and sweeping
// towards the positive y-axis. The end points of the arc specified are connected as defined by the closureType field. The radius field specifies the radius
// of the circle of which the arc is a portion. The arc extends from the startAngle counterclockwise to the endAngle. The value of radius shall be greater
// than zero. The values of startAngle and endAngle shall be in the range [-2pi, 2pi] radians (or the equivalent if a different default angle base unit has
// been specified). If startAngle and endAngle have the same value, a circle is specified and closureType is ignored. If the absolute difference between
// startAngle and endAngle is greater than or equal to 2pi, a complete circle is produced with no chord or radial line(s) drawn from the center.
// A closureType of "PIE" connects the end point to the start point by defining two straight line segments first from the end point to the center and then
// the center to the start point. A closureType of "CHORD" connects the end point to the start point by defining a straight line segment from the end point
// to the start point. Textures are applied individually to each face of the ArcClose2D. On the front (+Z) and back (-Z) faces of the ArcClose2D, when
// viewed from the +Z-axis, the texture is mapped onto each face with the same orientation as if the image were displayed normally in 2D.
void X3DImporter::readArcClose2D(XmlNode &node) {
std::string def, use;
std::string closureType("PIE");
float endAngle = AI_MATH_HALF_PI_F;
float radius = 1;
bool solid = false;
float startAngle = 0;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getStdStrAttribute(node, "closureType", closureType);
XmlParser::getFloatAttribute(node, "endAngle", endAngle);
XmlParser::getFloatAttribute(node, "endAngle", endAngle);
XmlParser::getFloatAttribute(node, "radius", radius);
XmlParser::getBoolAttribute(node, "solid", solid);
XmlParser::getFloatAttribute(node, "startAngle", startAngle);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_ArcClose2D, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_ArcClose2D, mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementGeometry2D *)ne)->Solid = solid;
// create point list of geometry object.
X3DGeoHelper::make_arc2D(startAngle, endAngle, radius, 10, ((X3DNodeElementGeometry2D *)ne)->Vertices); ///TODO: IME - AI_CONFIG for NumSeg
// add chord or two radiuses only if not a circle was defined
if (!((std::fabs(endAngle - startAngle) >= AI_MATH_TWO_PI_F) || (endAngle == startAngle))) {
std::list<aiVector3D> &vlist = ((X3DNodeElementGeometry2D *)ne)->Vertices; // just short alias.
if ((closureType == "PIE") || (closureType == "\"PIE\""))
vlist.push_back(aiVector3D(0, 0, 0)); // center point - first radial line
else if ((closureType != "CHORD") && (closureType != "\"CHORD\""))
Throw_IncorrectAttrValue("ArcClose2D", "closureType");
vlist.push_back(*vlist.begin()); // arc first point - chord from first to last point of arc(if CHORD) or second radial line(if PIE).
}
((X3DNodeElementGeometry2D *)ne)->NumIndices = ((X3DNodeElementGeometry2D *)ne)->Vertices.size();
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "ArcClose2D");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Circle2D
// DEF="" ID
// USE="" IDREF
// radius="1" SFFloat [initializeOnly]
// />
void X3DImporter::readCircle2D(XmlNode &node) {
std::string def, use;
float radius = 1;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getFloatAttribute(node, "radius", radius);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Circle2D, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Circle2D, mNodeElementCur);
if (!def.empty()) ne->ID = def;
// create point list of geometry object and convert it to line set.
std::list<aiVector3D> tlist;
X3DGeoHelper::make_arc2D(0, 0, radius, 10, tlist); ///TODO: IME - AI_CONFIG for NumSeg
X3DGeoHelper::extend_point_to_line(tlist, ((X3DNodeElementGeometry2D *)ne)->Vertices);
((X3DNodeElementGeometry2D *)ne)->NumIndices = 2;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Circle2D");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Disk2D
// DEF="" ID
// USE="" IDREF
// innerRadius="0" SFFloat [initializeOnly]
// outerRadius="1" SFFloat [initializeOnly]
// solid="false" SFBool [initializeOnly]
// />
// The Disk2D node specifies a circular disk which is centred at (0, 0) in the local coordinate system. The outerRadius field specifies the radius of the
// outer dimension of the Disk2D. The innerRadius field specifies the inner dimension of the Disk2D. The value of outerRadius shall be greater than zero.
// The value of innerRadius shall be greater than or equal to zero and less than or equal to outerRadius. If innerRadius is zero, the Disk2D is completely
// filled. Otherwise, the area within the innerRadius forms a hole in the Disk2D. If innerRadius is equal to outerRadius, a solid circular line shall
// be drawn using the current line properties. Textures are applied individually to each face of the Disk2D. On the front (+Z) and back (-Z) faces of
// the Disk2D, when viewed from the +Z-axis, the texture is mapped onto each face with the same orientation as if the image were displayed normally in 2D.
void X3DImporter::readDisk2D(XmlNode &node) {
std::string def, use;
float innerRadius = 0;
float outerRadius = 1;
bool solid = false;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getFloatAttribute(node, "innerRadius", innerRadius);
XmlParser::getFloatAttribute(node, "outerRadius", outerRadius);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Disk2D, ne);
} else {
std::list<aiVector3D> tlist_o, tlist_i;
if (innerRadius > outerRadius) Throw_IncorrectAttrValue("Disk2D", "innerRadius");
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Disk2D, mNodeElementCur);
if (!def.empty()) ne->ID = def;
// create point list of geometry object.
///TODO: IME - AI_CONFIG for NumSeg
X3DGeoHelper::make_arc2D(0, 0, outerRadius, 10, tlist_o); // outer circle
if (innerRadius == 0.0f) { // make filled disk
// in tlist_o we already have points of circle. just copy it and sign as polygon.
((X3DNodeElementGeometry2D *)ne)->Vertices = tlist_o;
((X3DNodeElementGeometry2D *)ne)->NumIndices = tlist_o.size();
} else if (innerRadius == outerRadius) { // make circle
// in tlist_o we already have points of circle. convert it to line set.
X3DGeoHelper::extend_point_to_line(tlist_o, ((X3DNodeElementGeometry2D *)ne)->Vertices);
((X3DNodeElementGeometry2D *)ne)->NumIndices = 2;
} else { // make disk
std::list<aiVector3D> &vlist = ((X3DNodeElementGeometry2D *)ne)->Vertices; // just short alias.
X3DGeoHelper::make_arc2D(0, 0, innerRadius, 10, tlist_i); // inner circle
//
// create quad list from two point lists
//
if (tlist_i.size() < 2) throw DeadlyImportError("Disk2D. Not enough points for creating quad list."); // tlist_i and tlist_o has equal size.
// add all quads except last
for (std::list<aiVector3D>::iterator it_i = tlist_i.begin(), it_o = tlist_o.begin(); it_i != tlist_i.end();) {
// do not forget - CCW direction
vlist.push_back(*it_i++); // 1st point
vlist.push_back(*it_o++); // 2nd point
vlist.push_back(*it_o); // 3rd point
vlist.push_back(*it_i); // 4th point
}
// add last quad
vlist.push_back(*tlist_i.end()); // 1st point
vlist.push_back(*tlist_o.end()); // 2nd point
vlist.push_back(*tlist_o.begin()); // 3rd point
vlist.push_back(*tlist_o.begin()); // 4th point
((X3DNodeElementGeometry2D *)ne)->NumIndices = 4;
}
((X3DNodeElementGeometry2D *)ne)->Solid = solid;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Disk2D");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Polyline2D
// DEF="" ID
// USE="" IDREF
// lineSegments="" MFVec2F [intializeOnly]
// />
void X3DImporter::readPolyline2D(XmlNode &node) {
std::string def, use;
std::list<aiVector2D> lineSegments;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector2DListAttribute(node, "lineSegments", lineSegments);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Polyline2D, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Polyline2D, mNodeElementCur);
if (!def.empty()) ne->ID = def;
//
// convert read point list of geometry object to line set.
//
std::list<aiVector3D> tlist;
// convert vec2 to vec3
for (std::list<aiVector2D>::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); ++it2)
tlist.push_back(aiVector3D(it2->x, it2->y, 0));
// convert point set to line set
X3DGeoHelper::extend_point_to_line(tlist, ((X3DNodeElementGeometry2D *)ne)->Vertices);
((X3DNodeElementGeometry2D *)ne)->NumIndices = 2;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Polyline2D");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Polypoint2D
// DEF="" ID
// USE="" IDREF
// point="" MFVec2F [inputOutput]
// />
void X3DImporter::readPolypoint2D(XmlNode &node) {
std::string def, use;
std::list<aiVector2D> point;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector2DListAttribute(node, "point", point);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Polypoint2D, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Polypoint2D, mNodeElementCur);
if (!def.empty()) ne->ID = def;
// convert vec2 to vec3
for (std::list<aiVector2D>::iterator it2 = point.begin(); it2 != point.end(); ++it2) {
((X3DNodeElementGeometry2D *)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
}
((X3DNodeElementGeometry2D *)ne)->NumIndices = 1;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Polypoint2D");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Rectangle2D
// DEF="" ID
// USE="" IDREF
// size="2 2" SFVec2f [initializeOnly]
// solid="false" SFBool [initializeOnly]
// />
void X3DImporter::readRectangle2D(XmlNode &node) {
std::string def, use;
aiVector2D size(2, 2);
bool solid = false;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector2DAttribute(node, "size", size);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Rectangle2D, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Rectangle2D, mNodeElementCur);
if (!def.empty()) ne->ID = def;
float x1 = -size.x / 2.0f;
float x2 = size.x / 2.0f;
float y1 = -size.y / 2.0f;
float y2 = size.y / 2.0f;
std::list<aiVector3D> &vlist = ((X3DNodeElementGeometry2D *)ne)->Vertices; // just short alias.
vlist.push_back(aiVector3D(x2, y1, 0)); // 1st point
vlist.push_back(aiVector3D(x2, y2, 0)); // 2nd point
vlist.push_back(aiVector3D(x1, y2, 0)); // 3rd point
vlist.push_back(aiVector3D(x1, y1, 0)); // 4th point
((X3DNodeElementGeometry2D *)ne)->Solid = solid;
((X3DNodeElementGeometry2D *)ne)->NumIndices = 4;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Rectangle2D");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <TriangleSet2D
// DEF="" ID
// USE="" IDREF
// solid="false" SFBool [initializeOnly]
// vertices="" MFVec2F [inputOutput]
// />
void X3DImporter::readTriangleSet2D(XmlNode &node) {
std::string def, use;
bool solid = false;
std::list<aiVector2D> vertices;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector2DListAttribute(node, "vertices", vertices);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TriangleSet2D, ne);
} else {
if (vertices.size() % 3) throw DeadlyImportError("TriangleSet2D. Not enough points for defining triangle.");
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_TriangleSet2D, mNodeElementCur);
if (!def.empty()) ne->ID = def;
// convert vec2 to vec3
for (std::list<aiVector2D>::iterator it2 = vertices.begin(); it2 != vertices.end(); ++it2) {
((X3DNodeElementGeometry2D *)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
}
((X3DNodeElementGeometry2D *)ne)->Solid = solid;
((X3DNodeElementGeometry2D *)ne)->NumIndices = 3;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "TriangleSet2D");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
@@ -0,0 +1,918 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Geometry3D.cpp
/// \brief Parsing data from nodes of "Geometry3D" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DGeoHelper.h"
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include "X3DXmlHelper.h"
// Header files, Assimp.
#include <assimp/StandardShapes.h>
namespace Assimp {
// <Box
// DEF="" ID
// USE="" IDREF
// size="2 2 2" SFVec3f [initializeOnly]
// solid="true" SFBool [initializeOnly]
// />
// The Box node specifies a rectangular parallelepiped box centred at (0, 0, 0) in the local coordinate system and aligned with the local coordinate axes.
// By default, the box measures 2 units in each dimension, from -1 to +1. The size field specifies the extents of the box along the X-, Y-, and Z-axes
// respectively and each component value shall be greater than zero.
void X3DImporter::readBox(XmlNode &node) {
std::string def, use;
bool solid = true;
aiVector3D size(2, 2, 2);
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector3DAttribute(node, "size", size);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Box, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry3D(X3DElemType::ENET_Box, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DGeoHelper::rect_parallel_epiped(size, ((X3DNodeElementGeometry3D *)ne)->Vertices); // get quad list
((X3DNodeElementGeometry3D *)ne)->Solid = solid;
((X3DNodeElementGeometry3D *)ne)->NumIndices = 4;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Box");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Cone
// DEF="" ID
// USE="" IDREF
// bottom="true" SFBool [initializeOnly]
// bottomRadius="1" SFloat [initializeOnly]
// height="2" SFloat [initializeOnly]
// side="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// />
void X3DImporter::readCone(XmlNode &node) {
std::string use, def;
bool bottom = true;
float bottomRadius = 1;
float height = 2;
bool side = true;
bool solid = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "solid", solid);
XmlParser::getBoolAttribute(node, "side", side);
XmlParser::getBoolAttribute(node, "bottom", bottom);
XmlParser::getFloatAttribute(node, "height", height);
XmlParser::getFloatAttribute(node, "bottomRadius", bottomRadius);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Cone, ne);
} else {
const unsigned int tess = 30; ///TODO: IME tessellation factor through ai_property
std::vector<aiVector3D> tvec; // temp array for vertices.
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry3D(X3DElemType::ENET_Cone, mNodeElementCur);
if (!def.empty()) ne->ID = def;
// make cone or parts according to flags.
if (side) {
StandardShapes::MakeCone(height, 0, bottomRadius, tess, tvec, !bottom);
} else if (bottom) {
StandardShapes::MakeCircle(bottomRadius, tess, tvec);
height = -(height / 2);
for (std::vector<aiVector3D>::iterator it = tvec.begin(); it != tvec.end(); ++it)
it->y = height; // y - because circle made in oXZ.
}
// copy data from temp array
for (std::vector<aiVector3D>::iterator it = tvec.begin(); it != tvec.end(); ++it)
((X3DNodeElementGeometry3D *)ne)->Vertices.push_back(*it);
((X3DNodeElementGeometry3D *)ne)->Solid = solid;
((X3DNodeElementGeometry3D *)ne)->NumIndices = 3;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Cone");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Cylinder
// DEF="" ID
// USE="" IDREF
// bottom="true" SFBool [initializeOnly]
// height="2" SFloat [initializeOnly]
// radius="1" SFloat [initializeOnly]
// side="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// top="true" SFBool [initializeOnly]
// />
void X3DImporter::readCylinder(XmlNode &node) {
std::string use, def;
bool bottom = true;
float height = 2;
float radius = 1;
bool side = true;
bool solid = true;
bool top = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getFloatAttribute(node, "radius", radius);
XmlParser::getBoolAttribute(node, "solid", solid);
XmlParser::getBoolAttribute(node, "bottom", bottom);
XmlParser::getBoolAttribute(node, "top", top);
XmlParser::getBoolAttribute(node, "side", side);
XmlParser::getFloatAttribute(node, "height", height);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Cylinder, ne);
} else {
const unsigned int tess = 30; ///TODO: IME tessellation factor through ai_property
std::vector<aiVector3D> tside; // temp array for vertices of side.
std::vector<aiVector3D> tcir; // temp array for vertices of circle.
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry3D(X3DElemType::ENET_Cylinder, mNodeElementCur);
if (!def.empty()) ne->ID = def;
// make cilynder or parts according to flags.
if (side) StandardShapes::MakeCone(height, radius, radius, tess, tside, true);
height /= 2; // height defined for whole cylinder, when creating top and bottom circle we are using just half of height.
if (top || bottom) StandardShapes::MakeCircle(radius, tess, tcir);
// copy data from temp arrays
std::list<aiVector3D> &vlist = ((X3DNodeElementGeometry3D *)ne)->Vertices; // just short alias.
for (std::vector<aiVector3D>::iterator it = tside.begin(); it != tside.end(); ++it)
vlist.push_back(*it);
if (top) {
for (std::vector<aiVector3D>::iterator it = tcir.begin(); it != tcir.end(); ++it) {
(*it).y = height; // y - because circle made in oXZ.
vlist.push_back(*it);
}
} // if(top)
if (bottom) {
for (std::vector<aiVector3D>::iterator it = tcir.begin(); it != tcir.end(); ++it) {
(*it).y = -height; // y - because circle made in oXZ.
vlist.push_back(*it);
}
} // if(top)
((X3DNodeElementGeometry3D *)ne)->Solid = solid;
((X3DNodeElementGeometry3D *)ne)->NumIndices = 3;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Cylinder");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <ElevationGrid
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// creaseAngle="0" SFloat [initializeOnly]
// height="" MFloat [initializeOnly]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// xDimension="0" SFInt32 [initializeOnly]
// xSpacing="1.0" SFloat [initializeOnly]
// zDimension="0" SFInt32 [initializeOnly]
// zSpacing="1.0" SFloat [initializeOnly]
// >
// <!-- ColorNormalTexCoordContentModel -->
// ColorNormalTexCoordContentModel can contain Color (or ColorRGBA), Normal and TextureCoordinate, in any order. No more than one instance of any single
// node type is allowed. A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </ElevationGrid>
// The ElevationGrid node specifies a uniform rectangular grid of varying height in the Y=0 plane of the local coordinate system. The geometry is described
// by a scalar array of height values that specify the height of a surface above each point of the grid. The xDimension and zDimension fields indicate
// the number of elements of the grid height array in the X and Z directions. Both xDimension and zDimension shall be greater than or equal to zero.
// If either the xDimension or the zDimension is less than two, the ElevationGrid contains no quadrilaterals.
void X3DImporter::readElevationGrid(XmlNode &node) {
std::string use, def;
bool ccw = true;
bool colorPerVertex = true;
float creaseAngle = 0;
std::vector<float> height;
bool normalPerVertex = true;
bool solid = true;
int32_t xDimension = 0;
float xSpacing = 1;
int32_t zDimension = 0;
float zSpacing = 1;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "solid", solid);
XmlParser::getBoolAttribute(node, "ccw", ccw);
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
XmlParser::getFloatAttribute(node, "creaseAngle", creaseAngle);
X3DXmlHelper::getFloatArrayAttribute(node, "height", height);
XmlParser::getIntAttribute(node, "xDimension", xDimension);
XmlParser::getFloatAttribute(node, "xSpacing", xSpacing);
XmlParser::getIntAttribute(node, "zDimension", zDimension);
XmlParser::getFloatAttribute(node, "zSpacing", zSpacing);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_ElevationGrid, ne);
} else {
if ((xSpacing == 0.0f) || (zSpacing == 0.0f)) throw DeadlyImportError("Spacing in <ElevationGrid> must be grater than zero.");
if ((xDimension <= 0) || (zDimension <= 0)) throw DeadlyImportError("Dimension in <ElevationGrid> must be grater than zero.");
if ((size_t)(xDimension * zDimension) != height.size()) DeadlyImportError("Heights count must be equal to \"xDimension * zDimension\" in <ElevationGrid>");
// create and if needed - define new geometry object.
ne = new X3DNodeElementElevationGrid(X3DElemType::ENET_ElevationGrid, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementElevationGrid &grid_alias = *((X3DNodeElementElevationGrid *)ne); // create alias for conveience
{ // create grid vertices list
std::vector<float>::const_iterator he_it = height.begin();
for (int32_t zi = 0; zi < zDimension; zi++) // rows
{
for (int32_t xi = 0; xi < xDimension; xi++) // columns
{
aiVector3D tvec(xSpacing * xi, *he_it, zSpacing * zi);
grid_alias.Vertices.push_back(tvec);
++he_it;
}
}
} // END: create grid vertices list
//
// create faces list. In "coordIdx" format
//
// check if we have quads
if ((xDimension < 2) || (zDimension < 2)) // only one element in dimension is set, create line set.
{
((X3DNodeElementElevationGrid *)ne)->NumIndices = 2; // will be holded as line set.
for (size_t i = 0, i_e = (grid_alias.Vertices.size() - 1); i < i_e; i++) {
grid_alias.CoordIdx.push_back(static_cast<int32_t>(i));
grid_alias.CoordIdx.push_back(static_cast<int32_t>(i + 1));
grid_alias.CoordIdx.push_back(-1);
}
} else // two or more elements in every dimension is set. create quad set.
{
((X3DNodeElementElevationGrid *)ne)->NumIndices = 4;
for (int32_t fzi = 0, fzi_e = (zDimension - 1); fzi < fzi_e; fzi++) // rows
{
for (int32_t fxi = 0, fxi_e = (xDimension - 1); fxi < fxi_e; fxi++) // columns
{
// points direction in face.
if (ccw) {
// CCW:
// 3 2
// 0 1
grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + fxi);
grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + (fxi + 1));
grid_alias.CoordIdx.push_back(fzi * xDimension + (fxi + 1));
grid_alias.CoordIdx.push_back(fzi * xDimension + fxi);
} else {
// CW:
// 0 1
// 3 2
grid_alias.CoordIdx.push_back(fzi * xDimension + fxi);
grid_alias.CoordIdx.push_back(fzi * xDimension + (fxi + 1));
grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + (fxi + 1));
grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + fxi);
} // if(ccw) else
grid_alias.CoordIdx.push_back(-1);
} // for(int32_t fxi = 0, fxi_e = (xDimension - 1); fxi < fxi_e; fxi++)
} // for(int32_t fzi = 0, fzi_e = (zDimension - 1); fzi < fzi_e; fzi++)
} // if((xDimension < 2) || (zDimension < 2)) else
grid_alias.ColorPerVertex = colorPerVertex;
grid_alias.NormalPerVertex = normalPerVertex;
grid_alias.CreaseAngle = creaseAngle;
grid_alias.Solid = solid;
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Normal")
readNormal(currentChildNode);
else if (currentChildName == "TextureCoordinate")
readTextureCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("ElevationGrid", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!mReader->isEmptyElement())
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
} // if(!mReader->isEmptyElement()) else
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
template <typename TVector>
static void GeometryHelper_Extrusion_CurveIsClosed(std::vector<TVector> &pCurve, const bool pDropTail, const bool pRemoveLastPoint, bool &pCurveIsClosed) {
size_t cur_sz = pCurve.size();
pCurveIsClosed = false;
// for curve with less than four points checking is have no sense,
if (cur_sz < 4) return;
for (size_t s = 3, s_e = cur_sz; s < s_e; s++) {
// search for first point of duplicated part.
if (pCurve[0] == pCurve[s]) {
bool found = true;
// check if tail(indexed by b2) is duplicate of head(indexed by b1).
for (size_t b1 = 1, b2 = (s + 1); b2 < cur_sz; b1++, b2++) {
if (pCurve[b1] != pCurve[b2]) { // points not match: clear flag and break loop.
found = false;
break;
}
} // for(size_t b1 = 1, b2 = (s + 1); b2 < cur_sz; b1++, b2++)
// if duplicate tail is found then drop or not it depending on flags.
if (found) {
pCurveIsClosed = true;
if (pDropTail) {
if (!pRemoveLastPoint) s++; // prepare value for iterator's arithmetics.
pCurve.erase(pCurve.begin() + s, pCurve.end()); // remove tail
}
break;
} // if(found)
} // if(pCurve[0] == pCurve[s])
} // for(size_t s = 3, s_e = (cur_sz - 1); s < s_e; s++)
}
static aiVector3D GeometryHelper_Extrusion_GetNextY(const size_t pSpine_PointIdx, const std::vector<aiVector3D> &pSpine, const bool pSpine_Closed) {
const size_t spine_idx_last = pSpine.size() - 1;
aiVector3D tvec;
if ((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last)) // at first special cases
{
if (pSpine_Closed) { // If the spine curve is closed: The SCP for the first and last points is the same and is found using (spine[1] - spine[n - 2]) to compute the Y-axis.
// As we even for closed spine curve last and first point in pSpine are not the same: duplicates(spine[n - 1] which are equivalent to spine[0])
// in tail are removed.
// So, last point in pSpine is a spine[n - 2]
tvec = pSpine[1] - pSpine[spine_idx_last];
} else if (pSpine_PointIdx == 0) { // The Y-axis used for the first point is the vector from spine[0] to spine[1]
tvec = pSpine[1] - pSpine[0];
} else { // The Y-axis used for the last point it is the vector from spine[n-2] to spine[n-1]. In our case(see above about dropping tail) spine[n - 1] is
// the spine[0].
tvec = pSpine[spine_idx_last] - pSpine[spine_idx_last - 1];
}
} // if((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last))
else { // For all points other than the first or last: The Y-axis for spine[i] is found by normalizing the vector defined by (spine[i+1] - spine[i-1]).
tvec = pSpine[pSpine_PointIdx + 1] - pSpine[pSpine_PointIdx - 1];
} // if((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last)) else
return tvec.Normalize();
}
static aiVector3D GeometryHelper_Extrusion_GetNextZ(const size_t pSpine_PointIdx, const std::vector<aiVector3D> &pSpine, const bool pSpine_Closed,
const aiVector3D pVecZ_Prev) {
const aiVector3D zero_vec(0);
const size_t spine_idx_last = pSpine.size() - 1;
aiVector3D tvec;
// at first special cases
if (pSpine.size() < 3) // spine have not enough points for vector calculations.
{
tvec.Set(0, 0, 1);
} else if (pSpine_PointIdx == 0) // special case: first point
{
if (pSpine_Closed) // for calculating use previous point in curve s[n - 2]. In list it's a last point, because point s[n - 1] was removed as duplicate.
{
tvec = (pSpine[1] - pSpine[0]) ^ (pSpine[spine_idx_last] - pSpine[0]);
} else // for not closed curve first and next point(s[0] and s[1]) has the same vector Z.
{
bool found = false;
// As said: "If the Z-axis of the first point is undefined (because the spine is not closed and the first two spine segments are collinear)
// then the Z-axis for the first spine point with a defined Z-axis is used."
// Walk through spine and find Z.
for (size_t next_point = 2; (next_point <= spine_idx_last) && !found; next_point++) {
// (pSpine[2] - pSpine[1]) ^ (pSpine[0] - pSpine[1])
tvec = (pSpine[next_point] - pSpine[next_point - 1]) ^ (pSpine[next_point - 2] - pSpine[next_point - 1]);
found = !tvec.Equal(zero_vec);
}
// if entire spine are collinear then use OZ axis.
if (!found) tvec.Set(0, 0, 1);
} // if(pSpine_Closed) else
} // else if(pSpine_PointIdx == 0)
else if (pSpine_PointIdx == spine_idx_last) // special case: last point
{
if (pSpine_Closed) { // do not forget that real last point s[n - 1] is removed as duplicated. And in this case we are calculating vector Z for point s[n - 2].
tvec = (pSpine[0] - pSpine[pSpine_PointIdx]) ^ (pSpine[pSpine_PointIdx - 1] - pSpine[pSpine_PointIdx]);
// if taken spine vectors are collinear then use previous vector Z.
if (tvec.Equal(zero_vec)) tvec = pVecZ_Prev;
} else { // vector Z for last point of not closed curve is previous vector Z.
tvec = pVecZ_Prev;
}
} else // regular point
{
tvec = (pSpine[pSpine_PointIdx + 1] - pSpine[pSpine_PointIdx]) ^ (pSpine[pSpine_PointIdx - 1] - pSpine[pSpine_PointIdx]);
// if taken spine vectors are collinear then use previous vector Z.
if (tvec.Equal(zero_vec)) tvec = pVecZ_Prev;
}
// After determining the Z-axis, its dot product with the Z-axis of the previous spine point is computed. If this value is negative, the Z-axis
// is flipped (multiplied by -1).
if ((tvec * pVecZ_Prev) < 0) tvec = -tvec;
return tvec.Normalize();
}
// <Extrusion
// DEF="" ID
// USE="" IDREF
// beginCap="true" SFBool [initializeOnly]
// ccw="true" SFBool [initializeOnly]
// convex="true" SFBool [initializeOnly]
// creaseAngle="0.0" SFloat [initializeOnly]
// crossSection="1 1 1 -1 -1 -1 -1 1 1 1" MFVec2f [initializeOnly]
// endCap="true" SFBool [initializeOnly]
// orientation="0 0 1 0" MFRotation [initializeOnly]
// scale="1 1" MFVec2f [initializeOnly]
// solid="true" SFBool [initializeOnly]
// spine="0 0 0 0 1 0" MFVec3f [initializeOnly]
// />
void X3DImporter::readExtrusion(XmlNode &node) {
std::string use, def;
bool beginCap = true;
bool ccw = true;
bool convex = true;
float creaseAngle = 0;
std::vector<aiVector2D> crossSection;
bool endCap = true;
std::vector<float> orientation;
std::vector<aiVector2D> scale;
bool solid = true;
std::vector<aiVector3D> spine;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "beginCap", beginCap);
XmlParser::getBoolAttribute(node, "ccw", ccw);
XmlParser::getBoolAttribute(node, "convex", convex);
XmlParser::getFloatAttribute(node, "creaseAngle", creaseAngle);
X3DXmlHelper::getVector2DArrayAttribute(node, "crossSection", crossSection);
XmlParser::getBoolAttribute(node, "endCap", endCap);
X3DXmlHelper::getFloatArrayAttribute(node, "orientation", orientation);
X3DXmlHelper::getVector2DArrayAttribute(node, "scale", scale);
XmlParser::getBoolAttribute(node, "solid", solid);
X3DXmlHelper::getVector3DArrayAttribute(node, "spine", spine);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Extrusion, ne);
} else {
//
// check if default values must be assigned
//
if (spine.size() == 0) {
spine.resize(2);
spine[0].Set(0, 0, 0), spine[1].Set(0, 1, 0);
} else if (spine.size() == 1) {
throw DeadlyImportError("ParseNode_Geometry3D_Extrusion. Spine must have at least two points.");
}
if (crossSection.size() == 0) {
crossSection.resize(5);
crossSection[0].Set(1, 1), crossSection[1].Set(1, -1), crossSection[2].Set(-1, -1), crossSection[3].Set(-1, 1), crossSection[4].Set(1, 1);
}
{ // orientation
size_t ori_size = orientation.size() / 4;
if (ori_size < spine.size()) {
float add_ori[4]; // values that will be added
if (ori_size == 1) // if "orientation" has one element(means one MFRotation with four components) then use it value for all spine points.
{
add_ori[0] = orientation[0], add_ori[1] = orientation[1], add_ori[2] = orientation[2], add_ori[3] = orientation[3];
} else // else - use default values
{
add_ori[0] = 0, add_ori[1] = 0, add_ori[2] = 1, add_ori[3] = 0;
}
orientation.reserve(spine.size() * 4);
for (size_t i = 0, i_e = (spine.size() - ori_size); i < i_e; i++)
orientation.push_back(add_ori[0]), orientation.push_back(add_ori[1]), orientation.push_back(add_ori[2]), orientation.push_back(add_ori[3]);
}
if (orientation.size() % 4) throw DeadlyImportError("Attribute \"orientation\" in <Extrusion> must has multiple four quantity of numbers.");
} // END: orientation
{ // scale
if (scale.size() < spine.size()) {
aiVector2D add_sc;
if (scale.size() == 1) // if "scale" has one element then use it value for all spine points.
add_sc = scale[0];
else // else - use default values
add_sc.Set(1, 1);
scale.reserve(spine.size());
for (size_t i = 0, i_e = (spine.size() - scale.size()); i < i_e; i++)
scale.push_back(add_sc);
}
} // END: scale
//
// create and if needed - define new geometry object.
//
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_Extrusion, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementIndexedSet &ext_alias = *((X3DNodeElementIndexedSet *)ne); // create alias for conveience
// assign part of input data
ext_alias.CCW = ccw;
ext_alias.Convex = convex;
ext_alias.CreaseAngle = creaseAngle;
ext_alias.Solid = solid;
//
// How we done it at all?
// 1. At first we will calculate array of basises for every point in spine(look SCP in ISO-dic). Also "orientation" vector
// are applied vor every basis.
// 2. After that we can create array of point sets: which are scaled, transferred to basis of relative basis and at final translated to real position
// using relative spine point.
// 3. Next step is creating CoordIdx array(do not forget "-1" delimiter). While creating CoordIdx also created faces for begin and end caps, if
// needed. While createing CootdIdx is taking in account CCW flag.
// 4. The last step: create Vertices list.
//
bool spine_closed; // flag: true if spine curve is closed.
bool cross_closed; // flag: true if cross curve is closed.
std::vector<aiMatrix3x3> basis_arr; // array of basises. ROW_a - X, ROW_b - Y, ROW_c - Z.
std::vector<std::vector<aiVector3D>> pointset_arr; // array of point sets: cross curves.
// detect closed curves
GeometryHelper_Extrusion_CurveIsClosed(crossSection, true, true, cross_closed); // true - drop tail, true - remove duplicate end.
GeometryHelper_Extrusion_CurveIsClosed(spine, true, true, spine_closed); // true - drop tail, true - remove duplicate end.
// If both cap are requested and spine curve is closed then we can make only one cap. Because second cap will be the same surface.
if (spine_closed) {
beginCap |= endCap;
endCap = false;
}
{ // 1. Calculate array of basises.
aiMatrix4x4 rotmat;
aiVector3D vecX(0), vecY(0), vecZ(0);
basis_arr.resize(spine.size());
for (size_t i = 0, i_e = spine.size(); i < i_e; i++) {
aiVector3D tvec;
// get axises of basis.
vecY = GeometryHelper_Extrusion_GetNextY(i, spine, spine_closed);
vecZ = GeometryHelper_Extrusion_GetNextZ(i, spine, spine_closed, vecZ);
vecX = (vecY ^ vecZ).Normalize();
// get rotation matrix and apply "orientation" to basis
aiMatrix4x4::Rotation(orientation[i * 4 + 3], aiVector3D(orientation[i * 4], orientation[i * 4 + 1], orientation[i * 4 + 2]), rotmat);
tvec = vecX, tvec *= rotmat, basis_arr[i].a1 = tvec.x, basis_arr[i].a2 = tvec.y, basis_arr[i].a3 = tvec.z;
tvec = vecY, tvec *= rotmat, basis_arr[i].b1 = tvec.x, basis_arr[i].b2 = tvec.y, basis_arr[i].b3 = tvec.z;
tvec = vecZ, tvec *= rotmat, basis_arr[i].c1 = tvec.x, basis_arr[i].c2 = tvec.y, basis_arr[i].c3 = tvec.z;
} // for(size_t i = 0, i_e = spine.size(); i < i_e; i++)
} // END: 1. Calculate array of basises
{ // 2. Create array of point sets.
aiMatrix4x4 scmat;
std::vector<aiVector3D> tcross(crossSection.size());
pointset_arr.resize(spine.size());
for (size_t spi = 0, spi_e = spine.size(); spi < spi_e; spi++) {
aiVector3D tc23vec;
tc23vec.Set(scale[spi].x, 0, scale[spi].y);
aiMatrix4x4::Scaling(tc23vec, scmat);
for (size_t cri = 0, cri_e = crossSection.size(); cri < cri_e; cri++) {
aiVector3D tvecX, tvecY, tvecZ;
tc23vec.Set(crossSection[cri].x, 0, crossSection[cri].y);
// apply scaling to point
tcross[cri] = scmat * tc23vec;
//
// transfer point to new basis
// calculate coordinate in new basis
tvecX.Set(basis_arr[spi].a1, basis_arr[spi].a2, basis_arr[spi].a3), tvecX *= tcross[cri].x;
tvecY.Set(basis_arr[spi].b1, basis_arr[spi].b2, basis_arr[spi].b3), tvecY *= tcross[cri].y;
tvecZ.Set(basis_arr[spi].c1, basis_arr[spi].c2, basis_arr[spi].c3), tvecZ *= tcross[cri].z;
// apply new coordinates and translate it to spine point.
tcross[cri] = tvecX + tvecY + tvecZ + spine[spi];
} // for(size_t cri = 0, cri_e = crossSection.size(); cri < cri_e; i++)
pointset_arr[spi] = tcross; // store transferred point set
} // for(size_t spi = 0, spi_e = spine.size(); spi < spi_e; i++)
} // END: 2. Create array of point sets.
{ // 3. Create CoordIdx.
// add caps if needed
if (beginCap) {
// add cap as polygon. vertices of cap are places at begin, so just add numbers from zero.
for (size_t i = 0, i_e = crossSection.size(); i < i_e; i++)
ext_alias.CoordIndex.push_back(static_cast<int32_t>(i));
// add delimiter
ext_alias.CoordIndex.push_back(-1);
} // if(beginCap)
if (endCap) {
// add cap as polygon. vertices of cap are places at end, as for beginCap use just sequence of numbers but with offset.
size_t beg = (pointset_arr.size() - 1) * crossSection.size();
for (size_t i = beg, i_e = (beg + crossSection.size()); i < i_e; i++)
ext_alias.CoordIndex.push_back(static_cast<int32_t>(i));
// add delimiter
ext_alias.CoordIndex.push_back(-1);
} // if(beginCap)
// add quads
for (size_t spi = 0, spi_e = (spine.size() - 1); spi <= spi_e; spi++) {
const size_t cr_sz = crossSection.size();
const size_t cr_last = crossSection.size() - 1;
size_t right_col; // hold index basis for points of quad placed in right column;
if (spi != spi_e)
right_col = spi + 1;
else if (spine_closed) // if spine curve is closed then one more quad is needed: between first and last points of curve.
right_col = 0;
else
break; // if spine curve is not closed then break the loop, because spi is out of range for that type of spine.
for (size_t cri = 0; cri < cr_sz; cri++) {
if (cri != cr_last) {
MACRO_FACE_ADD_QUAD(ccw, ext_alias.CoordIndex,
static_cast<int32_t>(spi * cr_sz + cri),
static_cast<int32_t>(right_col * cr_sz + cri),
static_cast<int32_t>(right_col * cr_sz + cri + 1),
static_cast<int32_t>(spi * cr_sz + cri + 1));
// add delimiter
ext_alias.CoordIndex.push_back(-1);
} else if (cross_closed) // if cross curve is closed then one more quad is needed: between first and last points of curve.
{
MACRO_FACE_ADD_QUAD(ccw, ext_alias.CoordIndex,
static_cast<int32_t>(spi * cr_sz + cri),
static_cast<int32_t>(right_col * cr_sz + cri),
static_cast<int32_t>(right_col * cr_sz + 0),
static_cast<int32_t>(spi * cr_sz + 0));
// add delimiter
ext_alias.CoordIndex.push_back(-1);
}
} // for(size_t cri = 0; cri < cr_sz; cri++)
} // for(size_t spi = 0, spi_e = (spine.size() - 2); spi < spi_e; spi++)
} // END: 3. Create CoordIdx.
{ // 4. Create vertices list.
// just copy all vertices
for (size_t spi = 0, spi_e = spine.size(); spi < spi_e; spi++) {
for (size_t cri = 0, cri_e = crossSection.size(); cri < cri_e; cri++) {
ext_alias.Vertices.emplace_back(pointset_arr[spi][cri]);
}
}
} // END: 4. Create vertices list.
//PrintVectorSet("Ext. CoordIdx", ext_alias.CoordIndex);
//PrintVectorSet("Ext. Vertices", ext_alias.Vertices);
// check for child nodes
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Extrusion");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <IndexedFaceSet
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorIndex="" MFInt32 [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// convex="true" SFBool [initializeOnly]
// coordIndex="" MFInt32 [initializeOnly]
// creaseAngle="0" SFFloat [initializeOnly]
// normalIndex="" MFInt32 [initializeOnly]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// texCoordIndex="" MFInt32 [initializeOnly]
// >
// <!-- ComposedGeometryContentModel -->
// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate,
// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute,
// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </IndexedFaceSet>
void X3DImporter::readIndexedFaceSet(XmlNode &node) {
std::string use, def;
bool ccw = true;
std::vector<int32_t> colorIndex;
bool colorPerVertex = true;
bool convex = true;
std::vector<int32_t> coordIndex;
float creaseAngle = 0;
std::vector<int32_t> normalIndex;
bool normalPerVertex = true;
bool solid = true;
std::vector<int32_t> texCoordIndex;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "ccw", ccw);
X3DXmlHelper::getInt32ArrayAttribute(node, "colorIndex", colorIndex);
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
XmlParser::getBoolAttribute(node, "convex", convex);
X3DXmlHelper::getInt32ArrayAttribute(node, "coordIndex", coordIndex);
XmlParser::getFloatAttribute(node, "creaseAngle", creaseAngle);
X3DXmlHelper::getInt32ArrayAttribute(node, "normalIndex", normalIndex);
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
XmlParser::getBoolAttribute(node, "solid", solid);
X3DXmlHelper::getInt32ArrayAttribute(node, "texCoordIndex", texCoordIndex);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_IndexedFaceSet, ne);
} else {
// check data
if (coordIndex.size() == 0) throw DeadlyImportError("IndexedFaceSet must contain not empty \"coordIndex\" attribute.");
// create and if needed - define new geometry object.
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedFaceSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)ne);
ne_alias.CCW = ccw;
ne_alias.ColorIndex = colorIndex;
ne_alias.ColorPerVertex = colorPerVertex;
ne_alias.Convex = convex;
ne_alias.CoordIndex = coordIndex;
ne_alias.CreaseAngle = creaseAngle;
ne_alias.NormalIndex = normalIndex;
ne_alias.NormalPerVertex = normalPerVertex;
ne_alias.Solid = solid;
ne_alias.TexCoordIndex = texCoordIndex;
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
else if (currentChildName == "Normal")
readNormal(currentChildNode);
else if (currentChildName == "TextureCoordinate")
readTextureCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("IndexedFaceSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Sphere
// DEF="" ID
// USE="" IDREF
// radius="1" SFloat [initializeOnly]
// solid="true" SFBool [initializeOnly]
// />
void X3DImporter::readSphere(XmlNode &node) {
std::string use, def;
ai_real radius = 1;
bool solid = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getRealAttribute(node, "radius", radius);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Sphere, ne);
} else {
const unsigned int tess = 3; ///TODO: IME tessellation factor through ai_property
std::vector<aiVector3D> tlist;
// create and if needed - define new geometry object.
ne = new X3DNodeElementGeometry3D(X3DElemType::ENET_Sphere, mNodeElementCur);
if (!def.empty()) ne->ID = def;
StandardShapes::MakeSphere(tess, tlist);
// copy data from temp array and apply scale
for (std::vector<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); ++it) {
aiVector3D v = *it;
((X3DNodeElementGeometry3D *)ne)->Vertices.emplace_back(v * radius);
}
((X3DNodeElementGeometry3D *)ne)->Solid = solid;
((X3DNodeElementGeometry3D *)ne)->NumIndices = 3;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Sphere");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
+277
View File
@@ -0,0 +1,277 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Group.cpp
/// \brief Parsing data from nodes of "Grouping" set of X3D.
/// date 2015-2016
/// author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include "X3DXmlHelper.h"
namespace Assimp {
// <Group
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// >
// <\!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </Group>
// A Group node contains children nodes without introducing a new transformation. It is equivalent to a Transform node containing an identity transform.
void X3DImporter::startReadGroup(XmlNode &node) {
std::string def, use;
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
// if "USE" defined then find already defined element.
if (!use.empty()) {
X3DNodeElementBase *ne(nullptr);
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Group, ne);
} else {
ParseHelper_Group_Begin(); // create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if (!def.empty()) mNodeElementCur->ID = def;
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
if (isNodeEmpty(node)) ParseHelper_Node_Exit();
} // if(!use.empty()) else
}
void X3DImporter::endReadGroup() {
ParseHelper_Node_Exit(); // go up in scene graph
}
// <StaticGroup
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// >
// <\!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </StaticGroup>
// The StaticGroup node contains children nodes which cannot be modified. StaticGroup children are guaranteed to not change, send events, receive events or
// contain any USE references outside the StaticGroup.
void X3DImporter::startReadStaticGroup(XmlNode &node) {
std::string def, use;
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
// if "USE" defined then find already defined element.
if (!use.empty()) {
X3DNodeElementBase *ne(nullptr);
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Group, ne);
} else {
ParseHelper_Group_Begin(true); // create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if (!def.empty()) mNodeElementCur->ID = def;
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
if (isNodeEmpty(node)) ParseHelper_Node_Exit();
} // if(!use.empty()) else
}
void X3DImporter::endReadStaticGroup() {
ParseHelper_Node_Exit(); // go up in scene graph
}
// <Switch
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// whichChoice="-1" SFInt32 [inputOutput]
// >
// <\!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </Switch>
// The Switch grouping node traverses zero or one of the nodes specified in the children field. The whichChoice field specifies the index of the child
// to traverse, with the first child having index 0. If whichChoice is less than zero or greater than the number of nodes in the children field, nothing
// is chosen.
void X3DImporter::startReadSwitch(XmlNode &node) {
std::string def, use;
int32_t whichChoice = -1;
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getIntAttribute(node, "whichChoice", whichChoice);
// if "USE" defined then find already defined element.
if (!use.empty()) {
X3DNodeElementBase *ne(nullptr);
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Group, ne);
} else {
ParseHelper_Group_Begin(); // create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if (!def.empty()) mNodeElementCur->ID = def;
// also set values specific to this type of group
((X3DNodeElementGroup *)mNodeElementCur)->UseChoice = true;
((X3DNodeElementGroup *)mNodeElementCur)->Choice = whichChoice;
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
if (isNodeEmpty(node)) ParseHelper_Node_Exit();
} // if(!use.empty()) else
}
void X3DImporter::endReadSwitch() {
// just exit from node. Defined choice will be accepted at postprocessing stage.
ParseHelper_Node_Exit(); // go up in scene graph
}
// <Transform
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// center="0 0 0" SFVec3f [inputOutput]
// rotation="0 0 1 0" SFRotation [inputOutput]
// scale="1 1 1" SFVec3f [inputOutput]
// scaleOrientation="0 0 1 0" SFRotation [inputOutput]
// translation="0 0 0" SFVec3f [inputOutput]
// >
// <\!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </Transform>
// The Transform node is a grouping node that defines a coordinate system for its children that is relative to the coordinate systems of its ancestors.
// Given a 3-dimensional point P and Transform node, P is transformed into point P' in its parent's coordinate system by a series of intermediate
// transformations. In matrix transformation notation, where C (center), SR (scaleOrientation), T (translation), R (rotation), and S (scale) are the
// equivalent transformation matrices,
// P' = T * C * R * SR * S * -SR * -C * P
void X3DImporter::startReadTransform(XmlNode &node) {
aiVector3D center(0, 0, 0);
float rotation[4] = { 0, 0, 1, 0 };
aiVector3D scale(1, 1, 1); // A value of zero indicates that any child geometry shall not be displayed
float scale_orientation[4] = { 0, 0, 1, 0 };
aiVector3D translation(0, 0, 0);
aiMatrix4x4 matr, tmatr;
std::string use, def;
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector3DAttribute(node, "center", center);
X3DXmlHelper::getVector3DAttribute(node, "scale", scale);
X3DXmlHelper::getVector3DAttribute(node, "translation", translation);
std::vector<float> tvec;
if (X3DXmlHelper::getFloatArrayAttribute(node, "rotation", tvec)) {
if (tvec.size() != 4) throw DeadlyImportError("<Transform>: rotation vector must have 4 elements.");
memcpy(rotation, tvec.data(), sizeof(rotation));
tvec.clear();
}
if (X3DXmlHelper::getFloatArrayAttribute(node, "scaleOrientation", tvec)) {
if (tvec.size() != 4) throw DeadlyImportError("<Transform>: scaleOrientation vector must have 4 elements.");
memcpy(scale_orientation, tvec.data(), sizeof(scale_orientation));
tvec.clear();
}
// if "USE" defined then find already defined element.
if (!use.empty()) {
X3DNodeElementBase *ne(nullptr);
bool newgroup = (nullptr == mNodeElementCur);
if(newgroup)
ParseHelper_Group_Begin();
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Group, ne);
if (newgroup && isNodeEmpty(node)) {
ParseHelper_Node_Exit();
}
} else {
ParseHelper_Group_Begin(); // create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if (!def.empty()) {
mNodeElementCur->ID = def;
}
//
// also set values specific to this type of group
//
// calculate transformation matrix
aiMatrix4x4::Translation(translation, matr); // T
aiMatrix4x4::Translation(center, tmatr); // C
matr *= tmatr;
aiMatrix4x4::Rotation(rotation[3], aiVector3D(rotation[0], rotation[1], rotation[2]), tmatr); // R
matr *= tmatr;
aiMatrix4x4::Rotation(scale_orientation[3], aiVector3D(scale_orientation[0], scale_orientation[1], scale_orientation[2]), tmatr); // SR
matr *= tmatr;
aiMatrix4x4::Scaling(scale, tmatr); // S
matr *= tmatr;
aiMatrix4x4::Rotation(-scale_orientation[3], aiVector3D(scale_orientation[0], scale_orientation[1], scale_orientation[2]), tmatr); // -SR
matr *= tmatr;
aiMatrix4x4::Translation(-center, tmatr); // -C
matr *= tmatr;
// and assign it
((X3DNodeElementGroup *)mNodeElementCur)->Transformation = matr;
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
if (isNodeEmpty(node)) {
ParseHelper_Node_Exit();
}
} // if(!use.empty()) else
}
void X3DImporter::endReadTransform() {
ParseHelper_Node_Exit(); // go up in scene graph
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
+270
View File
@@ -0,0 +1,270 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Light.cpp
/// \brief Parsing data from nodes of "Lighting" set of X3D.
/// date 2015-2016
/// author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include "X3DXmlHelper.h"
#include <assimp/StringUtils.h>
namespace Assimp {
// <DirectionalLight
// DEF="" ID
// USE="" IDREF
// ambientIntensity="0" SFFloat [inputOutput]
// color="1 1 1" SFColor [inputOutput]
// direction="0 0 -1" SFVec3f [inputOutput]
// global="false" SFBool [inputOutput]
// intensity="1" SFFloat [inputOutput]
// on="true" SFBool [inputOutput]
// />
void X3DImporter::readDirectionalLight(XmlNode &node) {
std::string def, use;
float ambientIntensity = 0;
aiColor3D color(1, 1, 1);
aiVector3D direction(0, 0, -1);
bool global = false;
float intensity = 1;
bool on = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getFloatAttribute(node, "ambientIntensity", ambientIntensity);
X3DXmlHelper::getColor3DAttribute(node, "color", color);
X3DXmlHelper::getVector3DAttribute(node, "direction", direction);
XmlParser::getBoolAttribute(node, "global", global);
XmlParser::getFloatAttribute(node, "intensity", intensity);
XmlParser::getBoolAttribute(node, "on", on);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_DirectionalLight, ne);
} else {
if (on) {
// create and if needed - define new geometry object.
ne = new X3DNodeElementLight(X3DElemType::ENET_DirectionalLight, mNodeElementCur);
if (!def.empty())
ne->ID = def;
else
ne->ID = "DirectionalLight_" + ai_to_string((size_t)ne); // make random name
((X3DNodeElementLight *)ne)->AmbientIntensity = ambientIntensity;
((X3DNodeElementLight *)ne)->Color = color;
((X3DNodeElementLight *)ne)->Direction = direction;
((X3DNodeElementLight *)ne)->Global = global;
((X3DNodeElementLight *)ne)->Intensity = intensity;
// Assimp want a node with name similar to a light. "Why? I don't no." )
ParseHelper_Group_Begin(false);
mNodeElementCur->ID = ne->ID; // assign name to node and return to light element.
ParseHelper_Node_Exit();
// check for child nodes
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "DirectionalLight");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(on)
} // if(!use.empty()) else
}
// <PointLight
// DEF="" ID
// USE="" IDREF
// ambientIntensity="0" SFFloat [inputOutput]
// attenuation="1 0 0" SFVec3f [inputOutput]
// color="1 1 1" SFColor [inputOutput]
// global="true" SFBool [inputOutput]
// intensity="1" SFFloat [inputOutput]
// location="0 0 0" SFVec3f [inputOutput]
// on="true" SFBool [inputOutput]
// radius="100" SFFloat [inputOutput]
// />
void X3DImporter::readPointLight(XmlNode &node) {
std::string def, use;
float ambientIntensity = 0;
aiVector3D attenuation(1, 0, 0);
aiColor3D color(1, 1, 1);
bool global = true;
float intensity = 1;
aiVector3D location(0, 0, 0);
bool on = true;
float radius = 100;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getFloatAttribute(node, "ambientIntensity", ambientIntensity);
X3DXmlHelper::getVector3DAttribute(node, "attenuation", attenuation);
X3DXmlHelper::getColor3DAttribute(node, "color", color);
XmlParser::getBoolAttribute(node, "global", global);
XmlParser::getFloatAttribute(node, "intensity", intensity);
X3DXmlHelper::getVector3DAttribute(node, "location", location);
XmlParser::getBoolAttribute(node, "on", on);
XmlParser::getFloatAttribute(node, "radius", radius);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_PointLight, ne);
} else {
if (on) {
// create and if needed - define new geometry object.
ne = new X3DNodeElementLight(X3DElemType::ENET_PointLight, mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementLight *)ne)->AmbientIntensity = ambientIntensity;
((X3DNodeElementLight *)ne)->Attenuation = attenuation;
((X3DNodeElementLight *)ne)->Color = color;
((X3DNodeElementLight *)ne)->Global = global;
((X3DNodeElementLight *)ne)->Intensity = intensity;
((X3DNodeElementLight *)ne)->Location = location;
((X3DNodeElementLight *)ne)->Radius = radius;
// Assimp want a node with name similar to a light. "Why? I don't no." )
ParseHelper_Group_Begin(false);
// make random name
if (ne->ID.empty()) ne->ID = "PointLight_" + ai_to_string((size_t)ne);
mNodeElementCur->ID = ne->ID; // assign name to node and return to light element.
ParseHelper_Node_Exit();
// check for child nodes
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "PointLight");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(on)
} // if(!use.empty()) else
}
// <SpotLight
// DEF="" ID
// USE="" IDREF
// ambientIntensity="0" SFFloat [inputOutput]
// attenuation="1 0 0" SFVec3f [inputOutput]
// beamWidth="0.7854" SFFloat [inputOutput]
// color="1 1 1" SFColor [inputOutput]
// cutOffAngle="1.570796" SFFloat [inputOutput]
// direction="0 0 -1" SFVec3f [inputOutput]
// global="true" SFBool [inputOutput]
// intensity="1" SFFloat [inputOutput]
// location="0 0 0" SFVec3f [inputOutput]
// on="true" SFBool [inputOutput]
// radius="100" SFFloat [inputOutput]
// />
void X3DImporter::readSpotLight(XmlNode &node) {
std::string def, use;
float ambientIntensity = 0;
aiVector3D attenuation(1, 0, 0);
float beamWidth = 0.7854f;
aiColor3D color(1, 1, 1);
float cutOffAngle = 1.570796f;
aiVector3D direction(0, 0, -1);
bool global = true;
float intensity = 1;
aiVector3D location(0, 0, 0);
bool on = true;
float radius = 100;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getFloatAttribute(node, "ambientIntensity", ambientIntensity);
X3DXmlHelper::getVector3DAttribute(node, "attenuation", attenuation);
XmlParser::getFloatAttribute(node, "beamWidth", beamWidth);
X3DXmlHelper::getColor3DAttribute(node, "color", color);
XmlParser::getFloatAttribute(node, "cutOffAngle", cutOffAngle);
X3DXmlHelper::getVector3DAttribute(node, "direction", direction);
XmlParser::getBoolAttribute(node, "global", global);
XmlParser::getFloatAttribute(node, "intensity", intensity);
X3DXmlHelper::getVector3DAttribute(node, "location", location);
XmlParser::getBoolAttribute(node, "on", on);
XmlParser::getFloatAttribute(node, "radius", radius);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_SpotLight, ne);
} else {
if (on) {
// create and if needed - define new geometry object.
ne = new X3DNodeElementLight(X3DElemType::ENET_SpotLight, mNodeElementCur);
if (!def.empty()) ne->ID = def;
if (beamWidth > cutOffAngle) beamWidth = cutOffAngle;
((X3DNodeElementLight *)ne)->AmbientIntensity = ambientIntensity;
((X3DNodeElementLight *)ne)->Attenuation = attenuation;
((X3DNodeElementLight *)ne)->BeamWidth = beamWidth;
((X3DNodeElementLight *)ne)->Color = color;
((X3DNodeElementLight *)ne)->CutOffAngle = cutOffAngle;
((X3DNodeElementLight *)ne)->Direction = direction;
((X3DNodeElementLight *)ne)->Global = global;
((X3DNodeElementLight *)ne)->Intensity = intensity;
((X3DNodeElementLight *)ne)->Location = location;
((X3DNodeElementLight *)ne)->Radius = radius;
// Assimp want a node with name similar to a light. "Why? I don't no." )
ParseHelper_Group_Begin(false);
// make random name
if (ne->ID.empty()) ne->ID = "SpotLight_" + ai_to_string((size_t)ne);
mNodeElementCur->ID = ne->ID; // assign name to node and return to light element.
ParseHelper_Node_Exit();
// check for child nodes
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "SpotLight");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(on)
} // if(!use.empty()) else
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
+121
View File
@@ -0,0 +1,121 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Macro.hpp
/// \brief Useful macrodefines.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef X3DIMPORTER_MACRO_HPP_INCLUDED
#define X3DIMPORTER_MACRO_HPP_INCLUDED
#include <assimp/XmlParser.h>
#include "X3DImporter.hpp"
#include <string>
namespace Assimp {
/// Used for regular checking while attribute "USE" is defined.
/// \param [in] pNode - pugi xml node to read.
/// \param [in] pDEF - string holding "DEF" value.
/// \param [in] pUSE - string holding "USE" value.
/// \param [in] pType - type of element to find.
/// \param [out] pNE - pointer to found node element.
inline X3DNodeElementBase *X3DImporter::MACRO_USE_CHECKANDAPPLY(XmlNode &node, std::string pDEF, std::string pUSE, X3DElemType pType, X3DNodeElementBase *pNE) {
checkNodeMustBeEmpty(node);
if (!pDEF.empty())
Assimp::Throw_DEF_And_USE(node.name());
if (!FindNodeElement(pUSE, pType, &pNE))
Assimp::Throw_USE_NotFound(node.name(), pUSE);
ai_assert(nullptr != mNodeElementCur);
mNodeElementCur->Children.push_back(pNE); /* add found object as child to current element */
return pNE;
}
} // namespace Assimp
/// \def MACRO_ATTRREAD_CHECKUSEDEF_RET
/// Compact variant for checking "USE" and "DEF".
/// \param [in] pNode - pugi xml node to read.
/// \param [out] pDEF_Var - output variable name for "DEF" value.
/// \param [out] pUSE_Var - output variable name for "USE" value.
#define MACRO_ATTRREAD_CHECKUSEDEF_RET(pNode, pDEF_Var, pUSE_Var) \
do { \
XmlParser::getStdStrAttribute(pNode, "DEF", pDEF_Var); \
XmlParser::getStdStrAttribute(pNode, "USE", pUSE_Var); \
} while (false)
/// \def MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4)
/// Add points as quad. Means that pP1..pP4 set in CCW order.
#define MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4) \
do { \
if (pCCW) { \
pOut.push_back(pIn[pP1]); \
pOut.push_back(pIn[pP2]); \
pOut.push_back(pIn[pP3]); \
pOut.push_back(pIn[pP4]); \
} else { \
pOut.push_back(pIn[pP4]); \
pOut.push_back(pIn[pP3]); \
pOut.push_back(pIn[pP2]); \
pOut.push_back(pIn[pP1]); \
} \
} while (false)
/// \def MACRO_FACE_ADD_QUAD(pCCW, pOut, pP1, pP2, pP3, pP4)
/// Add points as quad. Means that pP1..pP4 set in CCW order.
#define MACRO_FACE_ADD_QUAD(pCCW, pOut, pP1, pP2, pP3, pP4) \
do { \
if (pCCW) { \
pOut.push_back(pP1); \
pOut.push_back(pP2); \
pOut.push_back(pP3); \
pOut.push_back(pP4); \
} else { \
pOut.push_back(pP4); \
pOut.push_back(pP3); \
pOut.push_back(pP2); \
pOut.push_back(pP1); \
} \
} while (false)
#endif // X3DIMPORTER_MACRO_HPP_INCLUDED
+255
View File
@@ -0,0 +1,255 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Metadata.cpp
/// \brief Parsing data from nodes of "Metadata" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include "X3DXmlHelper.h"
namespace Assimp {
bool X3DImporter::checkForMetadataNode(XmlNode &node) {
const std::string &name = node.name();
if (name == "MetadataBoolean") {
readMetadataBoolean(node);
} else if (name == "MetadataDouble") {
readMetadataDouble(node);
} else if (name == "MetadataFloat") {
readMetadataFloat(node);
} else if (name == "MetadataInteger") {
readMetadataInteger(node);
} else if (name == "MetadataSet") {
readMetadataSet(node);
} else if (name == "MetadataString") {
readMetadataString(node);
} else
return false;
return true;
}
void X3DImporter::childrenReadMetadata(XmlNode &node, X3DNodeElementBase *pParentElement, const std::string &pNodeName) {
ParseHelper_Node_Enter(pParentElement);
for (auto childNode : node.children()) {
if (!checkForMetadataNode(childNode)) skipUnsupportedNode(pNodeName, childNode);
}
ParseHelper_Node_Exit();
}
/// \def MACRO_METADATA_FINDCREATE(pDEF_Var, pUSE_Var, pReference, pValue, pNE, pMetaName)
/// Find element by "USE" or create new one.
/// \param [in] pNode - pugi xml node to read.
/// \param [in] pDEF_Var - variable name with "DEF" value.
/// \param [in] pUSE_Var - variable name with "USE" value.
/// \param [in] pReference - variable name with "reference" value.
/// \param [in] pValue - variable name with "value" value.
/// \param [in, out] pNE - pointer to node element.
/// \param [in] pMetaClass - Class of node.
/// \param [in] pMetaName - Name of node.
/// \param [in] pType - type of element to find.
#define MACRO_METADATA_FINDCREATE(pNode, pDEF_Var, pUSE_Var, pReference, pValue, pNE, pMetaClass, pMetaName, pType) \
/* if "USE" defined then find already defined element. */ \
if (!pUSE_Var.empty()) { \
ne = MACRO_USE_CHECKANDAPPLY(pNode, pDEF_Var, pUSE_Var, pType, pNE); \
} else { \
pNE = new pMetaClass(mNodeElementCur); \
if (!pDEF_Var.empty()) pNE->ID = pDEF_Var; \
\
((pMetaClass *)pNE)->Reference = pReference; \
((pMetaClass *)pNE)->Value = pValue; \
/* also metadata node can contain childs */ \
if (!isNodeEmpty(pNode)) \
childrenReadMetadata(pNode, pNE, pMetaName); /* in that case node element will be added to child elements list of current node. */ \
else \
mNodeElementCur->Children.push_back(pNE); /* else - add element to child list manually */ \
\
NodeElement_List.push_back(pNE); /* add new element to elements list. */ \
} /* if(!pUSE_Var.empty()) else */ \
\
do { \
} while (false)
// <MetadataBoolean
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFBool [inputOutput]
// />
void X3DImporter::readMetadataBoolean(XmlNode &node) {
std::string def, use;
std::string name, reference;
std::vector<bool> value;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getStdStrAttribute(node, "name", name);
XmlParser::getStdStrAttribute(node, "reference", reference);
X3DXmlHelper::getBooleanArrayAttribute(node, "value", value);
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaBoolean, "MetadataBoolean", ENET_MetaBoolean);
}
// <MetadataDouble
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFDouble [inputOutput]
// />
void X3DImporter::readMetadataDouble(XmlNode &node) {
std::string def, use;
std::string name, reference;
std::vector<double> value;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getStdStrAttribute(node, "name", name);
XmlParser::getStdStrAttribute(node, "reference", reference);
X3DXmlHelper::getDoubleArrayAttribute(node, "value", value);
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaDouble, "MetadataDouble", ENET_MetaDouble);
}
// <MetadataFloat
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFFloat [inputOutput]
// />
void X3DImporter::readMetadataFloat(XmlNode &node) {
std::string def, use;
std::string name, reference;
std::vector<float> value;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getStdStrAttribute(node, "name", name);
XmlParser::getStdStrAttribute(node, "reference", reference);
X3DXmlHelper::getFloatArrayAttribute(node, "value", value);
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaFloat, "MetadataFloat", ENET_MetaFloat);
}
// <MetadataInteger
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFInteger [inputOutput]
// />
void X3DImporter::readMetadataInteger(XmlNode &node) {
std::string def, use;
std::string name, reference;
std::vector<int32_t> value;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getStdStrAttribute(node, "name", name);
XmlParser::getStdStrAttribute(node, "reference", reference);
X3DXmlHelper::getInt32ArrayAttribute(node, "value", value);
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaInt, "MetadataInteger", ENET_MetaInteger);
}
// <MetadataSet
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// />
void X3DImporter::readMetadataSet(XmlNode &node) {
std::string def, use;
std::string name, reference;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getStdStrAttribute(node, "name", name);
XmlParser::getStdStrAttribute(node, "reference", reference);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_MetaSet, ne);
} else {
ne = new X3DNodeElementMetaSet(mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementMetaSet *)ne)->Reference = reference;
// also metadata node can contain children
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "MetadataSet");
else
mNodeElementCur->Children.push_back(ne); // made object as child to current element
NodeElement_List.push_back(ne); // add new element to elements list.
} // if(!use.empty()) else
}
// <MetadataString
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFString [inputOutput]
// />
void X3DImporter::readMetadataString(XmlNode &node) {
std::string def, use;
std::string name, reference;
std::vector<std::string> value;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getStdStrAttribute(node, "name", name);
XmlParser::getStdStrAttribute(node, "reference", reference);
X3DXmlHelper::getStringArrayAttribute(node, "value", value);
MACRO_METADATA_FINDCREATE(node, def, use, reference, value, ne, X3DNodeElementMetaString, "MetadataString", ENET_MetaString);
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
@@ -0,0 +1,124 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Networking.cpp
/// \brief Parsing data from nodes of "Networking" set of X3D.
/// date 2015-2016
/// author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include "X3DXmlHelper.h"
// Header files, Assimp.
#include <assimp/DefaultIOSystem.h>
//#include <regex>
namespace Assimp {
//static std::regex pattern_parentDir(R"((^|/)[^/]+/../)");
static std::string parentDir("/../");
// <Inline
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// load="true" SFBool [inputOutput]
// url="" MFString [inputOutput]
// />
void X3DImporter::readInline(XmlNode &node) {
std::string def, use;
bool load = true;
std::list<std::string> url;
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "load", load);
X3DXmlHelper::getStringListAttribute(node, "url", url);
// if "USE" defined then find already defined element.
X3DNodeElementBase *ne = nullptr;
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Group, ne);
} else {
ParseHelper_Group_Begin(true); // create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if (!def.empty()) mNodeElementCur->ID = def;
if (load && !url.empty()) {
std::string full_path = mpIOHandler->CurrentDirectory() + url.front();
//full_path = std::regex_replace(full_path, pattern_parentDir, "$1");
for (std::string::size_type pos = full_path.find(parentDir); pos != std::string::npos; pos = full_path.find(parentDir, pos)) {
if (pos > 0) {
std::string::size_type pos2 = full_path.rfind('/', pos - 1);
if (pos2 != std::string::npos) {
full_path.erase(pos2, pos - pos2 + 3);
pos = pos2;
} else {
full_path.erase(0, pos + 4);
pos = 0;
}
} else {
pos += 3;
}
}
// Attribute "url" can contain list of strings. But we need only one - first.
std::string::size_type slashPos = full_path.find_last_of("\\/");
mpIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : full_path.substr(0, slashPos + 1));
ParseFile(full_path, mpIOHandler);
mpIOHandler->PopDirectory();
}
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node)) childrenReadMetadata(node, mNodeElementCur, "Inline");
// exit from node in that place
ParseHelper_Node_Exit();
} // if(!use.empty()) else
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
+463
View File
@@ -0,0 +1,463 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Node.hpp
/// \brief Elements of scene graph.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef INCLUDED_AI_X3D_IMPORTER_NODE_H
#define INCLUDED_AI_X3D_IMPORTER_NODE_H
// Header files, Assimp.
#include <assimp/types.h>
#include <list>
#include <vector>
enum X3DElemType {
ENET_Group, ///< Element has type "Group".
ENET_MetaBoolean, ///< Element has type "Metadata boolean".
ENET_MetaDouble, ///< Element has type "Metadata double".
ENET_MetaFloat, ///< Element has type "Metadata float".
ENET_MetaInteger, ///< Element has type "Metadata integer".
ENET_MetaSet, ///< Element has type "Metadata set".
ENET_MetaString, ///< Element has type "Metadata string".
ENET_Arc2D, ///< Element has type "Arc2D".
ENET_ArcClose2D, ///< Element has type "ArcClose2D".
ENET_Circle2D, ///< Element has type "Circle2D".
ENET_Disk2D, ///< Element has type "Disk2D".
ENET_Polyline2D, ///< Element has type "Polyline2D".
ENET_Polypoint2D, ///< Element has type "Polypoint2D".
ENET_Rectangle2D, ///< Element has type "Rectangle2D".
ENET_TriangleSet2D, ///< Element has type "TriangleSet2D".
ENET_Box, ///< Element has type "Box".
ENET_Cone, ///< Element has type "Cone".
ENET_Cylinder, ///< Element has type "Cylinder".
ENET_Sphere, ///< Element has type "Sphere".
ENET_ElevationGrid, ///< Element has type "ElevationGrid".
ENET_Extrusion, ///< Element has type "Extrusion".
ENET_Coordinate, ///< Element has type "Coordinate".
ENET_Normal, ///< Element has type "Normal".
ENET_TextureCoordinate, ///< Element has type "TextureCoordinate".
ENET_IndexedFaceSet, ///< Element has type "IndexedFaceSet".
ENET_IndexedLineSet, ///< Element has type "IndexedLineSet".
ENET_IndexedTriangleSet, ///< Element has type "IndexedTriangleSet".
ENET_IndexedTriangleFanSet, ///< Element has type "IndexedTriangleFanSet".
ENET_IndexedTriangleStripSet, ///< Element has type "IndexedTriangleStripSet".
ENET_LineSet, ///< Element has type "LineSet".
ENET_PointSet, ///< Element has type "PointSet".
ENET_TriangleSet, ///< Element has type "TriangleSet".
ENET_TriangleFanSet, ///< Element has type "TriangleFanSet".
ENET_TriangleStripSet, ///< Element has type "TriangleStripSet".
ENET_Color, ///< Element has type "Color".
ENET_ColorRGBA, ///< Element has type "ColorRGBA".
ENET_Shape, ///< Element has type "Shape".
ENET_Appearance, ///< Element has type "Appearance".
ENET_Material, ///< Element has type "Material".
ENET_ImageTexture, ///< Element has type "ImageTexture".
ENET_TextureTransform, ///< Element has type "TextureTransform".
ENET_DirectionalLight, ///< Element has type "DirectionalLight".
ENET_PointLight, ///< Element has type "PointLight".
ENET_SpotLight, ///< Element has type "SpotLight".
ENET_Invalid ///< Element has invalid type and possible contain invalid data.
};
struct X3DNodeElementBase {
X3DNodeElementBase *Parent;
std::string ID;
std::list<X3DNodeElementBase *> Children;
X3DElemType Type;
virtual ~X3DNodeElementBase() {
// empty
}
protected:
X3DNodeElementBase(X3DElemType type, X3DNodeElementBase *pParent) :
Parent(pParent), Type(type) {
// empty
}
};
/// This struct hold <Color> value.
struct X3DNodeElementColor : X3DNodeElementBase {
std::list<aiColor3D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNodeElementColor(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_Color, pParent) {}
}; // struct X3DNodeElementColor
/// This struct hold <ColorRGBA> value.
struct X3DNodeElementColorRGBA : X3DNodeElementBase {
std::list<aiColor4D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNodeElementColorRGBA(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_ColorRGBA, pParent) {}
}; // struct X3DNodeElementColorRGBA
/// This struct hold <Coordinate> value.
struct X3DNodeElementCoordinate : public X3DNodeElementBase {
std::list<aiVector3D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNodeElementCoordinate(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_Coordinate, pParent) {}
}; // struct X3DNodeElementCoordinate
/// This struct hold <Normal> value.
struct X3DNodeElementNormal : X3DNodeElementBase {
std::list<aiVector3D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNodeElementNormal(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_Normal, pParent) {}
}; // struct X3DNodeElementNormal
/// This struct hold <TextureCoordinate> value.
struct X3DNodeElementTextureCoordinate : X3DNodeElementBase {
std::list<aiVector2D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNodeElementTextureCoordinate(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_TextureCoordinate, pParent) {}
}; // struct X3DNodeElementTextureCoordinate
/// Two-dimensional figure.
struct X3DNodeElementGeometry2D : X3DNodeElementBase {
std::list<aiVector3D> Vertices; ///< Vertices list.
size_t NumIndices; ///< Number of indices in one face.
bool Solid; ///< Flag: if true then render must use back-face culling, else render must draw both sides of object.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DNodeElementGeometry2D(X3DElemType pType, X3DNodeElementBase *pParent) :
X3DNodeElementBase(pType, pParent), Solid(true) {}
}; // class X3DNodeElementGeometry2D
/// Three-dimensional body.
struct X3DNodeElementGeometry3D : X3DNodeElementBase {
std::list<aiVector3D> Vertices; ///< Vertices list.
size_t NumIndices; ///< Number of indices in one face.
bool Solid; ///< Flag: if true then render must use back-face culling, else render must draw both sides of object.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DNodeElementGeometry3D(X3DElemType pType, X3DNodeElementBase *pParent) :
X3DNodeElementBase(pType, pParent), Vertices(), NumIndices(0), Solid(true) {
// empty
}
}; // class X3DNodeElementGeometry3D
/// Uniform rectangular grid of varying height.
struct X3DNodeElementElevationGrid : X3DNodeElementGeometry3D {
bool NormalPerVertex; ///< If true then normals are defined for every vertex, else for every face(line).
bool ColorPerVertex; ///< If true then colors are defined for every vertex, else for every face(line).
/// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are
/// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced.
float CreaseAngle;
std::vector<int32_t> CoordIdx; ///< Coordinates list by faces. In X3D format: "-1" - delimiter for faces.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DNodeElementElevationGrid(X3DElemType pType, X3DNodeElementBase *pParent) :
X3DNodeElementGeometry3D(pType, pParent) {}
}; // class X3DNodeElementIndexedSet
/// Shape with indexed vertices.
struct X3DNodeElementIndexedSet : public X3DNodeElementGeometry3D {
/// The ccw field defines the ordering of the vertex coordinates of the geometry with respect to user-given or automatically generated normal vectors
/// used in the lighting model equations. If ccw is TRUE, the normals shall follow the right hand rule; the orientation of each normal with respect to
/// the vertices (taken in order) shall be such that the vertices appear to be oriented in a counterclockwise order when the vertices are viewed (in the
/// local coordinate system of the Shape) from the opposite direction as the normal. If ccw is FALSE, the normals shall be oriented in the opposite
/// direction. If normals are not generated but are supplied using a Normal node, and the orientation of the normals does not match the setting of the
/// ccw field, results are undefined.
bool CCW;
std::vector<int32_t> ColorIndex; ///< Field to specify the polygonal faces by indexing into the <Color> or <ColorRGBA>.
bool ColorPerVertex; ///< If true then colors are defined for every vertex, else for every face(line).
/// The convex field indicates whether all polygons in the shape are convex (TRUE). A polygon is convex if it is planar, does not intersect itself,
/// and all of the interior angles at its vertices are less than 180 degrees. Non planar and self intersecting polygons may produce undefined results
/// even if the convex field is FALSE.
bool Convex;
std::vector<int32_t> CoordIndex; ///< Field to specify the polygonal faces by indexing into the <Coordinate>.
/// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are
/// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced.
float CreaseAngle;
std::vector<int32_t> NormalIndex; ///< Field to specify the polygonal faces by indexing into the <Normal>.
bool NormalPerVertex; ///< If true then normals are defined for every vertex, else for every face(line).
std::vector<int32_t> TexCoordIndex; ///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DNodeElementIndexedSet(X3DElemType pType, X3DNodeElementBase *pParent) :
X3DNodeElementGeometry3D(pType, pParent) {}
}; // class X3DNodeElementIndexedSet
/// Shape with set of vertices.
struct X3DNodeElementSet : X3DNodeElementGeometry3D {
/// The ccw field defines the ordering of the vertex coordinates of the geometry with respect to user-given or automatically generated normal vectors
/// used in the lighting model equations. If ccw is TRUE, the normals shall follow the right hand rule; the orientation of each normal with respect to
/// the vertices (taken in order) shall be such that the vertices appear to be oriented in a counterclockwise order when the vertices are viewed (in the
/// local coordinate system of the Shape) from the opposite direction as the normal. If ccw is FALSE, the normals shall be oriented in the opposite
/// direction. If normals are not generated but are supplied using a Normal node, and the orientation of the normals does not match the setting of the
/// ccw field, results are undefined.
bool CCW;
bool ColorPerVertex; ///< If true then colors are defined for every vertex, else for every face(line).
bool NormalPerVertex; ///< If true then normals are defined for every vertex, else for every face(line).
std::vector<int32_t> CoordIndex; ///< Field to specify the polygonal faces by indexing into the <Coordinate>.
std::vector<int32_t> NormalIndex; ///< Field to specify the polygonal faces by indexing into the <Normal>.
std::vector<int32_t> TexCoordIndex; ///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
std::vector<int32_t> VertexCount; ///< Field describes how many vertices are to be used in each polyline(polygon) from the <Coordinate> field.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DNodeElementSet(X3DElemType type, X3DNodeElementBase *pParent) :
X3DNodeElementGeometry3D(type, pParent) {}
}; // class X3DNodeElementSet
/// This struct hold <Shape> value.
struct X3DNodeElementShape : X3DNodeElementBase {
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNodeElementShape(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_Shape, pParent) {}
}; // struct X3DNodeElementShape
/// This struct hold <Appearance> value.
struct X3DNodeElementAppearance : public X3DNodeElementBase {
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNodeElementAppearance(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_Appearance, pParent) {}
}; // struct X3DNodeElementAppearance
struct X3DNodeElementMaterial : public X3DNodeElementBase {
float AmbientIntensity; ///< Specifies how much ambient light from light sources this surface shall reflect.
aiColor3D DiffuseColor; ///< Reflects all X3D light sources depending on the angle of the surface with respect to the light source.
aiColor3D EmissiveColor; ///< Models "glowing" objects. This can be useful for displaying pre-lit models.
float Shininess; ///< Lower shininess values produce soft glows, while higher values result in sharper, smaller highlights.
aiColor3D SpecularColor; ///< The specularColor and shininess fields determine the specular highlights.
float Transparency; ///< Specifies how "clear" an object is, with 1.0 being completely transparent, and 0.0 completely opaque.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DNodeElementMaterial(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_Material, pParent),
AmbientIntensity(0.0f),
DiffuseColor(),
EmissiveColor(),
Shininess(0.0f),
SpecularColor(),
Transparency(1.0f) {
// empty
}
}; // class X3DNodeElementMaterial
/// This struct hold <ImageTexture> value.
struct X3DNodeElementImageTexture : X3DNodeElementBase {
/// RepeatS and RepeatT, that specify how the texture wraps in the S and T directions. If repeatS is TRUE (the default), the texture map is repeated
/// outside the [0.0, 1.0] texture coordinate range in the S direction so that it fills the shape. If repeatS is FALSE, the texture coordinates are
/// clamped in the S direction to lie within the [0.0, 1.0] range. The repeatT field is analogous to the repeatS field.
bool RepeatS;
bool RepeatT; ///< See \ref RepeatS.
std::string URL; ///< URL of the texture.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNodeElementImageTexture(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_ImageTexture, pParent) {}
}; // struct X3DNodeElementImageTexture
/// This struct hold <TextureTransform> value.
struct X3DNodeElementTextureTransform : X3DNodeElementBase {
aiVector2D Center; ///< Specifies a translation offset in texture coordinate space about which the rotation and scale fields are applied.
float Rotation; ///< Specifies a rotation in angle base units of the texture coordinates about the center point after the scale has been applied.
aiVector2D Scale; ///< Specifies a scaling factor in S and T of the texture coordinates about the center point.
aiVector2D Translation; ///< Specifies a translation of the texture coordinates.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNodeElementTextureTransform(X3DNodeElementBase *pParent) :
X3DNodeElementBase(X3DElemType::ENET_TextureTransform, pParent) {}
}; // struct X3DNodeElementTextureTransform
struct X3DNodeElementGroup : X3DNodeElementBase {
aiMatrix4x4 Transformation; ///< Transformation matrix.
/// As you know node elements can use already defined node elements when attribute "USE" is defined.
/// Standard search when looking for an element in the whole scene graph, existing at this moment.
/// If a node is marked as static, the children(or lower) can not search for elements in the nodes upper then static.
bool Static;
bool UseChoice; ///< Flag: if true then use number from \ref Choice to choose what the child will be kept.
int32_t Choice; ///< Number of the child which will be kept.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pStatic - static node flag.
X3DNodeElementGroup(X3DNodeElementBase *pParent, const bool pStatic = false) :
X3DNodeElementBase(X3DElemType::ENET_Group, pParent), Static(pStatic), UseChoice(false) {}
};
struct X3DNodeElementMeta : X3DNodeElementBase {
std::string Name; ///< Name of metadata object.
std::string Reference;
virtual ~X3DNodeElementMeta() {
// empty
}
protected:
X3DNodeElementMeta(X3DElemType type, X3DNodeElementBase *parent) :
X3DNodeElementBase(type, parent) {
// empty
}
};
struct X3DNodeElementMetaBoolean : X3DNodeElementMeta {
std::vector<bool> Value; ///< Stored value.
explicit X3DNodeElementMetaBoolean(X3DNodeElementBase *pParent) :
X3DNodeElementMeta(X3DElemType::ENET_MetaBoolean, pParent) {
// empty
}
};
struct X3DNodeElementMetaDouble : X3DNodeElementMeta {
std::vector<double> Value; ///< Stored value.
explicit X3DNodeElementMetaDouble(X3DNodeElementBase *pParent) :
X3DNodeElementMeta(X3DElemType::ENET_MetaDouble, pParent) {
// empty
}
};
struct X3DNodeElementMetaFloat : public X3DNodeElementMeta {
std::vector<float> Value; ///< Stored value.
explicit X3DNodeElementMetaFloat(X3DNodeElementBase *pParent) :
X3DNodeElementMeta(X3DElemType::ENET_MetaFloat, pParent) {
// empty
}
};
struct X3DNodeElementMetaInt : public X3DNodeElementMeta {
std::vector<int32_t> Value; ///< Stored value.
explicit X3DNodeElementMetaInt(X3DNodeElementBase *pParent) :
X3DNodeElementMeta(X3DElemType::ENET_MetaInteger, pParent) {
// empty
}
};
struct X3DNodeElementMetaSet : public X3DNodeElementMeta {
std::list<X3DNodeElementMeta> Value; ///< Stored value.
explicit X3DNodeElementMetaSet(X3DNodeElementBase *pParent) :
X3DNodeElementMeta(X3DElemType::ENET_MetaSet, pParent) {
// empty
}
};
struct X3DNodeElementMetaString : X3DNodeElementMeta {
std::vector<std::string> Value; ///< Stored value.
explicit X3DNodeElementMetaString(X3DNodeElementBase *pParent) :
X3DNodeElementMeta(X3DElemType::ENET_MetaString, pParent) {
// empty
}
};
/// \struct X3DNodeElementLight
/// This struct hold <TextureTransform> value.
struct X3DNodeElementLight : X3DNodeElementBase {
float AmbientIntensity; ///< Specifies the intensity of the ambient emission from the light.
aiColor3D Color; ///< specifies the spectral colour properties of both the direct and ambient light emission as an RGB value.
aiVector3D Direction; ///< Specifies the direction vector of the illumination emanating from the light source in the local coordinate system.
/// \var Global
/// Field that determines whether the light is global or scoped. Global lights illuminate all objects that fall within their volume of lighting influence.
/// Scoped lights only illuminate objects that are in the same transformation hierarchy as the light.
bool Global;
float Intensity; ///< Specifies the brightness of the direct emission from the light.
/// \var Attenuation
/// PointLight node's illumination falls off with distance as specified by three attenuation coefficients. The attenuation factor
/// is: "1 / max(attenuation[0] + attenuation[1] * r + attenuation[2] * r2, 1)", where r is the distance from the light to the surface being illuminated.
aiVector3D Attenuation;
aiVector3D Location; ///< Specifies a translation offset of the centre point of the light source from the light's local coordinate system origin.
float Radius; ///< Specifies the radial extent of the solid angle and the maximum distance from location that may be illuminated by the light source.
float BeamWidth; ///< Specifies an inner solid angle in which the light source emits light at uniform full intensity.
float CutOffAngle; ///< The light source's emission intensity drops off from the inner solid angle (beamWidth) to the outer solid angle (cutOffAngle).
/// Constructor
/// \param [in] pParent - pointer to parent node.
/// \param [in] pLightType - type of the light source.
X3DNodeElementLight(X3DElemType pLightType, X3DNodeElementBase *pParent) :
X3DNodeElementBase(pLightType, pParent) {}
}; // struct X3DNodeElementLight
#endif // INCLUDED_AI_X3D_IMPORTER_NODE_H
@@ -0,0 +1,731 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Postprocess.cpp
/// \brief Convert built scenegraph and objects to Assimp scenegraph.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DGeoHelper.h"
#include "X3DImporter.hpp"
// Header files, Assimp.
#include <assimp/StandardShapes.h>
#include <assimp/StringUtils.h>
#include <assimp/ai_assert.h>
// Header files, stdlib.
#include <algorithm>
#include <iterator>
#include <string>
namespace Assimp {
aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const {
X3DNodeElementBase *cur_node;
std::list<aiMatrix4x4> matr;
aiMatrix4x4 out_matr;
// starting walk from current element to root
cur_node = mNodeElementCur;
if (cur_node != nullptr) {
do {
// if cur_node is group then store group transformation matrix in list.
if (cur_node->Type == X3DElemType::ENET_Group) matr.push_back(((X3DNodeElementGroup *)cur_node)->Transformation);
cur_node = cur_node->Parent;
} while (cur_node != nullptr);
}
// multiplicate all matrices in reverse order
for (std::list<aiMatrix4x4>::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); ++rit)
out_matr = out_matr * (*rit);
return out_matr;
}
void X3DImporter::PostprocessHelper_CollectMetadata(const X3DNodeElementBase &pNodeElement, std::list<X3DNodeElementBase *> &pList) const {
// walk through childs and find for metadata.
for (std::list<X3DNodeElementBase *>::const_iterator el_it = pNodeElement.Children.begin(); el_it != pNodeElement.Children.end(); ++el_it) {
if (((*el_it)->Type == X3DElemType::ENET_MetaBoolean) || ((*el_it)->Type == X3DElemType::ENET_MetaDouble) ||
((*el_it)->Type == X3DElemType::ENET_MetaFloat) || ((*el_it)->Type == X3DElemType::ENET_MetaInteger) ||
((*el_it)->Type == X3DElemType::ENET_MetaString)) {
pList.push_back(*el_it);
} else if ((*el_it)->Type == X3DElemType::ENET_MetaSet) {
PostprocessHelper_CollectMetadata(**el_it, pList);
}
} // for(std::list<X3DNodeElementBase*>::const_iterator el_it = pNodeElement.Children.begin(); el_it != pNodeElement.Children.end(); el_it++)
}
bool X3DImporter::PostprocessHelper_ElementIsMetadata(const X3DElemType pType) const {
if ((pType == X3DElemType::ENET_MetaBoolean) || (pType == X3DElemType::ENET_MetaDouble) ||
(pType == X3DElemType::ENET_MetaFloat) || (pType == X3DElemType::ENET_MetaInteger) ||
(pType == X3DElemType::ENET_MetaString) || (pType == X3DElemType::ENET_MetaSet)) {
return true;
} else {
return false;
}
}
bool X3DImporter::PostprocessHelper_ElementIsMesh(const X3DElemType pType) const {
if ((pType == X3DElemType::ENET_Arc2D) || (pType == X3DElemType::ENET_ArcClose2D) ||
(pType == X3DElemType::ENET_Box) || (pType == X3DElemType::ENET_Circle2D) ||
(pType == X3DElemType::ENET_Cone) || (pType == X3DElemType::ENET_Cylinder) ||
(pType == X3DElemType::ENET_Disk2D) || (pType == X3DElemType::ENET_ElevationGrid) ||
(pType == X3DElemType::ENET_Extrusion) || (pType == X3DElemType::ENET_IndexedFaceSet) ||
(pType == X3DElemType::ENET_IndexedLineSet) || (pType == X3DElemType::ENET_IndexedTriangleFanSet) ||
(pType == X3DElemType::ENET_IndexedTriangleSet) || (pType == X3DElemType::ENET_IndexedTriangleStripSet) ||
(pType == X3DElemType::ENET_PointSet) || (pType == X3DElemType::ENET_LineSet) ||
(pType == X3DElemType::ENET_Polyline2D) || (pType == X3DElemType::ENET_Polypoint2D) ||
(pType == X3DElemType::ENET_Rectangle2D) || (pType == X3DElemType::ENET_Sphere) ||
(pType == X3DElemType::ENET_TriangleFanSet) || (pType == X3DElemType::ENET_TriangleSet) ||
(pType == X3DElemType::ENET_TriangleSet2D) || (pType == X3DElemType::ENET_TriangleStripSet)) {
return true;
} else {
return false;
}
}
void X3DImporter::Postprocess_BuildLight(const X3DNodeElementBase &pNodeElement, std::list<aiLight *> &pSceneLightList) const {
const X3DNodeElementLight &ne = *((X3DNodeElementLight *)&pNodeElement);
aiMatrix4x4 transform_matr = PostprocessHelper_Matrix_GlobalToCurrent();
aiLight *new_light = new aiLight;
new_light->mName = ne.ID;
new_light->mColorAmbient = ne.Color * ne.AmbientIntensity;
new_light->mColorDiffuse = ne.Color * ne.Intensity;
new_light->mColorSpecular = ne.Color * ne.Intensity;
switch (pNodeElement.Type) {
case X3DElemType::ENET_DirectionalLight:
new_light->mType = aiLightSource_DIRECTIONAL;
new_light->mDirection = ne.Direction, new_light->mDirection *= transform_matr;
break;
case X3DElemType::ENET_PointLight:
new_light->mType = aiLightSource_POINT;
new_light->mPosition = ne.Location, new_light->mPosition *= transform_matr;
new_light->mAttenuationConstant = ne.Attenuation.x;
new_light->mAttenuationLinear = ne.Attenuation.y;
new_light->mAttenuationQuadratic = ne.Attenuation.z;
break;
case X3DElemType::ENET_SpotLight:
new_light->mType = aiLightSource_SPOT;
new_light->mPosition = ne.Location, new_light->mPosition *= transform_matr;
new_light->mDirection = ne.Direction, new_light->mDirection *= transform_matr;
new_light->mAttenuationConstant = ne.Attenuation.x;
new_light->mAttenuationLinear = ne.Attenuation.y;
new_light->mAttenuationQuadratic = ne.Attenuation.z;
new_light->mAngleInnerCone = ne.BeamWidth;
new_light->mAngleOuterCone = ne.CutOffAngle;
break;
default:
throw DeadlyImportError("Postprocess_BuildLight. Unknown type of light: " + ai_to_string(pNodeElement.Type) + ".");
}
pSceneLightList.push_back(new_light);
}
void X3DImporter::Postprocess_BuildMaterial(const X3DNodeElementBase &pNodeElement, aiMaterial **pMaterial) const {
// check argument
if (pMaterial == nullptr) throw DeadlyImportError("Postprocess_BuildMaterial. pMaterial is nullptr.");
if (*pMaterial != nullptr) throw DeadlyImportError("Postprocess_BuildMaterial. *pMaterial must be nullptr.");
*pMaterial = new aiMaterial;
aiMaterial &taimat = **pMaterial; // creating alias for convenience.
// at this point pNodeElement point to <Appearance> node. Walk through childs and add all stored data.
for (std::list<X3DNodeElementBase *>::const_iterator el_it = pNodeElement.Children.begin(); el_it != pNodeElement.Children.end(); ++el_it) {
if ((*el_it)->Type == X3DElemType::ENET_Material) {
aiColor3D tcol3;
float tvalf;
X3DNodeElementMaterial &tnemat = *((X3DNodeElementMaterial *)*el_it);
tcol3.r = tnemat.AmbientIntensity, tcol3.g = tnemat.AmbientIntensity, tcol3.b = tnemat.AmbientIntensity;
taimat.AddProperty(&tcol3, 1, AI_MATKEY_COLOR_AMBIENT);
taimat.AddProperty(&tnemat.DiffuseColor, 1, AI_MATKEY_COLOR_DIFFUSE);
taimat.AddProperty(&tnemat.EmissiveColor, 1, AI_MATKEY_COLOR_EMISSIVE);
taimat.AddProperty(&tnemat.SpecularColor, 1, AI_MATKEY_COLOR_SPECULAR);
tvalf = 1;
taimat.AddProperty(&tvalf, 1, AI_MATKEY_SHININESS_STRENGTH);
taimat.AddProperty(&tnemat.Shininess, 1, AI_MATKEY_SHININESS);
tvalf = 1.0f - tnemat.Transparency;
taimat.AddProperty(&tvalf, 1, AI_MATKEY_OPACITY);
} // if((*el_it)->Type == X3DElemType::ENET_Material)
else if ((*el_it)->Type == X3DElemType::ENET_ImageTexture) {
X3DNodeElementImageTexture &tnetex = *((X3DNodeElementImageTexture *)*el_it);
aiString url_str(tnetex.URL.c_str());
int mode = aiTextureOp_Multiply;
taimat.AddProperty(&url_str, AI_MATKEY_TEXTURE_DIFFUSE(0));
taimat.AddProperty(&tnetex.RepeatS, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
taimat.AddProperty(&tnetex.RepeatT, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
taimat.AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0));
} // else if((*el_it)->Type == X3DElemType::ENET_ImageTexture)
else if ((*el_it)->Type == X3DElemType::ENET_TextureTransform) {
aiUVTransform trans;
X3DNodeElementTextureTransform &tnetextr = *((X3DNodeElementTextureTransform *)*el_it);
trans.mTranslation = tnetextr.Translation - tnetextr.Center;
trans.mScaling = tnetextr.Scale;
trans.mRotation = tnetextr.Rotation;
taimat.AddProperty(&trans, 1, AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
} // else if((*el_it)->Type == X3DElemType::ENET_TextureTransform)
} // for(std::list<X3DNodeElementBase*>::const_iterator el_it = pNodeElement.Children.begin(); el_it != pNodeElement.Children.end(); el_it++)
}
void X3DImporter::Postprocess_BuildMesh(const X3DNodeElementBase &pNodeElement, aiMesh **pMesh) const {
// check argument
if (pMesh == nullptr) throw DeadlyImportError("Postprocess_BuildMesh. pMesh is nullptr.");
if (*pMesh != nullptr) throw DeadlyImportError("Postprocess_BuildMesh. *pMesh must be nullptr.");
/************************************************************************************************************************************/
/************************************************************ Geometry2D ************************************************************/
/************************************************************************************************************************************/
if ((pNodeElement.Type == X3DElemType::ENET_Arc2D) || (pNodeElement.Type == X3DElemType::ENET_ArcClose2D) ||
(pNodeElement.Type == X3DElemType::ENET_Circle2D) || (pNodeElement.Type == X3DElemType::ENET_Disk2D) ||
(pNodeElement.Type == X3DElemType::ENET_Polyline2D) || (pNodeElement.Type == X3DElemType::ENET_Polypoint2D) ||
(pNodeElement.Type == X3DElemType::ENET_Rectangle2D) || (pNodeElement.Type == X3DElemType::ENET_TriangleSet2D)) {
X3DNodeElementGeometry2D &tnemesh = *((X3DNodeElementGeometry2D *)&pNodeElement); // create alias for convenience
std::vector<aiVector3D> tarr;
tarr.reserve(tnemesh.Vertices.size());
for (std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it)
tarr.push_back(*it);
*pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices)); // create mesh from vertices using Assimp help.
return; // mesh is build, nothing to do anymore.
}
/************************************************************************************************************************************/
/************************************************************ Geometry3D ************************************************************/
/************************************************************************************************************************************/
//
// Predefined figures
//
if ((pNodeElement.Type == X3DElemType::ENET_Box) || (pNodeElement.Type == X3DElemType::ENET_Cone) ||
(pNodeElement.Type == X3DElemType::ENET_Cylinder) || (pNodeElement.Type == X3DElemType::ENET_Sphere)) {
X3DNodeElementGeometry3D &tnemesh = *((X3DNodeElementGeometry3D *)&pNodeElement); // create alias for convenience
std::vector<aiVector3D> tarr;
tarr.reserve(tnemesh.Vertices.size());
for (std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it)
tarr.push_back(*it);
*pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices)); // create mesh from vertices using Assimp help.
return; // mesh is build, nothing to do anymore.
}
//
// Parametric figures
//
if (pNodeElement.Type == X3DElemType::ENET_ElevationGrid) {
X3DNodeElementElevationGrid &tnemesh = *((X3DNodeElementElevationGrid *)&pNodeElement); // create alias for convenience
// at first create mesh from existing vertices.
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIdx, tnemesh.Vertices);
// copy additional information from children
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Color)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
X3DGeoHelper::add_normal(**pMesh, ((X3DNodeElementNormal *)*ch_it)->Value, tnemesh.NormalPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
X3DGeoHelper::add_tex_coord(**pMesh, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + ai_to_string((*ch_it)->Type) + ".");
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
return; // mesh is build, nothing to do anymore.
} // if(pNodeElement.Type == X3DElemType::ENET_ElevationGrid)
//
// Indexed primitives sets
//
if (pNodeElement.Type == X3DElemType::ENET_IndexedFaceSet) {
X3DNodeElementIndexedSet &tnemesh = *((X3DNodeElementIndexedSet *)&pNodeElement); // create alias for convenience
// at first search for <Coordinate> node and create mesh.
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
}
}
// copy additional information from children
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Color)
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColorRGBA *)*ch_it)->Value,
tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
} // skip because already read when mesh created.
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + ai_to_string((*ch_it)->Type) + ".");
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
return; // mesh is build, nothing to do anymore.
} // if(pNodeElement.Type == X3DElemType::ENET_IndexedFaceSet)
if (pNodeElement.Type == X3DElemType::ENET_IndexedLineSet) {
X3DNodeElementIndexedSet &tnemesh = *((X3DNodeElementIndexedSet *)&pNodeElement); // create alias for convenience
// at first search for <Coordinate> node and create mesh.
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
}
}
// copy additional information from children
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
ai_assert(*pMesh);
if ((*ch_it)->Type == X3DElemType::ENET_Color)
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColorRGBA *)*ch_it)->Value,
tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
} // skip because already read when mesh created.
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + ai_to_string((*ch_it)->Type) + ".");
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
return; // mesh is build, nothing to do anymore.
} // if(pNodeElement.Type == X3DElemType::ENET_IndexedLineSet)
if ((pNodeElement.Type == X3DElemType::ENET_IndexedTriangleSet) ||
(pNodeElement.Type == X3DElemType::ENET_IndexedTriangleFanSet) ||
(pNodeElement.Type == X3DElemType::ENET_IndexedTriangleStripSet)) {
X3DNodeElementIndexedSet &tnemesh = *((X3DNodeElementIndexedSet *)&pNodeElement); // create alias for convenience
// at first search for <Coordinate> node and create mesh.
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
}
}
// copy additional information from children
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
ai_assert(*pMesh);
if ((*ch_it)->Type == X3DElemType::ENET_Color)
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
X3DGeoHelper::add_color(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DNodeElementColorRGBA *)*ch_it)->Value,
tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
} // skip because already read when mesh created.
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \
IndexedTriangleStripSet: " +
ai_to_string((*ch_it)->Type) + ".");
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
return; // mesh is build, nothing to do anymore.
} // if((pNodeElement.Type == X3DElemType::ENET_IndexedTriangleFanSet) || (pNodeElement.Type == X3DElemType::ENET_IndexedTriangleStripSet))
if (pNodeElement.Type == X3DElemType::ENET_Extrusion) {
X3DNodeElementIndexedSet &tnemesh = *((X3DNodeElementIndexedSet *)&pNodeElement); // create alias for convenience
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, tnemesh.Vertices);
return; // mesh is build, nothing to do anymore.
} // if(pNodeElement.Type == X3DElemType::ENET_Extrusion)
//
// Primitives sets
//
if (pNodeElement.Type == X3DElemType::ENET_PointSet) {
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
// at first search for <Coordinate> node and create mesh.
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
std::vector<aiVector3D> vec_copy;
vec_copy.reserve(((X3DNodeElementCoordinate *)*ch_it)->Value.size());
for (std::list<aiVector3D>::const_iterator it = ((X3DNodeElementCoordinate *)*ch_it)->Value.begin();
it != ((X3DNodeElementCoordinate *)*ch_it)->Value.end(); ++it) {
vec_copy.push_back(*it);
}
*pMesh = StandardShapes::MakeMesh(vec_copy, 1);
}
}
// copy additional information from children
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
ai_assert(*pMesh);
if ((*ch_it)->Type == X3DElemType::ENET_Color)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, true);
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, true);
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
} // skip because already read when mesh created.
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + ai_to_string((*ch_it)->Type) + ".");
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
return; // mesh is build, nothing to do anymore.
} // if(pNodeElement.Type == X3DElemType::ENET_PointSet)
if (pNodeElement.Type == X3DElemType::ENET_LineSet) {
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
// at first search for <Coordinate> node and create mesh.
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
}
}
// copy additional information from children
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
ai_assert(*pMesh);
if ((*ch_it)->Type == X3DElemType::ENET_Color)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, true);
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, true);
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
} // skip because already read when mesh created.
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + ai_to_string((*ch_it)->Type) + ".");
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
return; // mesh is build, nothing to do anymore.
} // if(pNodeElement.Type == X3DElemType::ENET_LineSet)
if (pNodeElement.Type == X3DElemType::ENET_TriangleFanSet) {
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
// at first search for <Coordinate> node and create mesh.
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
}
}
// copy additional information from children
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if (nullptr == *pMesh) {
break;
}
if ((*ch_it)->Type == X3DElemType::ENET_Color)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
} // skip because already read when mesh created.
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + ai_to_string((*ch_it)->Type) + ".");
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
return; // mesh is build, nothing to do anymore.
} // if(pNodeElement.Type == X3DElemType::ENET_TriangleFanSet)
if (pNodeElement.Type == X3DElemType::ENET_TriangleSet) {
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
// at first search for <Coordinate> node and create mesh.
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
std::vector<aiVector3D> vec_copy;
vec_copy.reserve(((X3DNodeElementCoordinate *)*ch_it)->Value.size());
for (std::list<aiVector3D>::const_iterator it = ((X3DNodeElementCoordinate *)*ch_it)->Value.begin();
it != ((X3DNodeElementCoordinate *)*ch_it)->Value.end(); ++it) {
vec_copy.push_back(*it);
}
*pMesh = StandardShapes::MakeMesh(vec_copy, 3);
}
}
// copy additional information from children
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
ai_assert(*pMesh);
if ((*ch_it)->Type == X3DElemType::ENET_Color)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
} // skip because already read when mesh created.
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + ai_to_string((*ch_it)->Type) + ".");
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
return; // mesh is build, nothing to do anymore.
} // if(pNodeElement.Type == X3DElemType::ENET_TriangleSet)
if (pNodeElement.Type == X3DElemType::ENET_TriangleStripSet) {
X3DNodeElementSet &tnemesh = *((X3DNodeElementSet *)&pNodeElement); // create alias for convenience
// at first search for <Coordinate> node and create mesh.
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
*pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value);
}
}
// copy additional information from children
for (std::list<X3DNodeElementBase *>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) {
ai_assert(*pMesh);
if ((*ch_it)->Type == X3DElemType::ENET_Color)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColor *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_ColorRGBA)
X3DGeoHelper::add_color(**pMesh, ((X3DNodeElementColorRGBA *)*ch_it)->Value, tnemesh.ColorPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) {
} // skip because already read when mesh created.
else if ((*ch_it)->Type == X3DElemType::ENET_Normal)
X3DGeoHelper::add_normal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNodeElementNormal *)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if ((*ch_it)->Type == X3DElemType::ENET_TextureCoordinate)
X3DGeoHelper::add_tex_coord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DNodeElementTextureCoordinate *)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + ai_to_string((*ch_it)->Type) + ".");
} // for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it)
return; // mesh is build, nothing to do anymore.
} // if(pNodeElement.Type == X3DElemType::ENET_TriangleStripSet)
throw DeadlyImportError("Postprocess_BuildMesh. Unknown mesh type: " + ai_to_string(pNodeElement.Type) + ".");
}
void X3DImporter::Postprocess_BuildNode(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode, std::list<aiMesh *> &pSceneMeshList,
std::list<aiMaterial *> &pSceneMaterialList, std::list<aiLight *> &pSceneLightList) const {
std::list<X3DNodeElementBase *>::const_iterator chit_begin = pNodeElement.Children.begin();
std::list<X3DNodeElementBase *>::const_iterator chit_end = pNodeElement.Children.end();
std::list<aiNode *> SceneNode_Child;
std::list<unsigned int> SceneNode_Mesh;
// At first read all metadata
Postprocess_CollectMetadata(pNodeElement, pSceneNode);
// check if we have deal with grouping node. Which can contain transformation or switch
if (pNodeElement.Type == X3DElemType::ENET_Group) {
const X3DNodeElementGroup &tne_group = *((X3DNodeElementGroup *)&pNodeElement); // create alias for convenience
pSceneNode.mTransformation = tne_group.Transformation;
if (tne_group.UseChoice) {
// If Choice is less than zero or greater than the number of nodes in the children field, nothing is chosen.
if ((tne_group.Choice < 0) || ((size_t)tne_group.Choice >= pNodeElement.Children.size())) {
chit_begin = pNodeElement.Children.end();
chit_end = pNodeElement.Children.end();
} else {
for (size_t i = 0; i < (size_t)tne_group.Choice; i++)
++chit_begin; // forward iterator to chosen node.
chit_end = chit_begin;
++chit_end; // point end iterator to next element after chosen node.
}
} // if(tne_group.UseChoice)
} // if(pNodeElement.Type == X3DElemType::ENET_Group)
// Reserve memory for fast access and check children.
for (std::list<X3DNodeElementBase *>::const_iterator it = chit_begin; it != chit_end; ++it) { // in this loop we do not read metadata because it's already read at begin.
if ((*it)->Type == X3DElemType::ENET_Group) {
// if child is group then create new node and do recursive call.
aiNode *new_node = new aiNode;
new_node->mName = (*it)->ID;
new_node->mParent = &pSceneNode;
SceneNode_Child.push_back(new_node);
Postprocess_BuildNode(**it, *new_node, pSceneMeshList, pSceneMaterialList, pSceneLightList);
} else if ((*it)->Type == X3DElemType::ENET_Shape) {
// shape can contain only one geometry and one appearance nodes.
Postprocess_BuildShape(*((X3DNodeElementShape *)*it), SceneNode_Mesh, pSceneMeshList, pSceneMaterialList);
} else if (((*it)->Type == X3DElemType::ENET_DirectionalLight) || ((*it)->Type == X3DElemType::ENET_PointLight) ||
((*it)->Type == X3DElemType::ENET_SpotLight)) {
Postprocess_BuildLight(*((X3DNodeElementLight *)*it), pSceneLightList);
} else if (!PostprocessHelper_ElementIsMetadata((*it)->Type)) // skip metadata
{
throw DeadlyImportError("Postprocess_BuildNode. Unknown type: " + ai_to_string((*it)->Type) + ".");
}
} // for(std::list<X3DNodeElementBase*>::const_iterator it = chit_begin; it != chit_end; it++)
// copy data about children and meshes to aiNode.
if (!SceneNode_Child.empty()) {
std::list<aiNode *>::const_iterator it = SceneNode_Child.begin();
pSceneNode.mNumChildren = static_cast<unsigned int>(SceneNode_Child.size());
pSceneNode.mChildren = new aiNode *[pSceneNode.mNumChildren];
for (size_t i = 0; i < pSceneNode.mNumChildren; i++)
pSceneNode.mChildren[i] = *it++;
}
if (!SceneNode_Mesh.empty()) {
std::list<unsigned int>::const_iterator it = SceneNode_Mesh.begin();
pSceneNode.mNumMeshes = static_cast<unsigned int>(SceneNode_Mesh.size());
pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes];
for (size_t i = 0; i < pSceneNode.mNumMeshes; i++)
pSceneNode.mMeshes[i] = *it++;
}
// that's all. return to previous deals
}
void X3DImporter::Postprocess_BuildShape(const X3DNodeElementShape &pShapeNodeElement, std::list<unsigned int> &pNodeMeshInd,
std::list<aiMesh *> &pSceneMeshList, std::list<aiMaterial *> &pSceneMaterialList) const {
aiMaterial *tmat = nullptr;
aiMesh *tmesh = nullptr;
X3DElemType mesh_type = X3DElemType::ENET_Invalid;
unsigned int mat_ind = 0;
for (std::list<X3DNodeElementBase *>::const_iterator it = pShapeNodeElement.Children.begin(); it != pShapeNodeElement.Children.end(); ++it) {
if (PostprocessHelper_ElementIsMesh((*it)->Type)) {
Postprocess_BuildMesh(**it, &tmesh);
if (tmesh != nullptr) {
// if mesh successfully built then add data about it to arrays
pNodeMeshInd.push_back(static_cast<unsigned int>(pSceneMeshList.size()));
pSceneMeshList.push_back(tmesh);
// keep mesh type. Need above for texture coordinate generation.
mesh_type = (*it)->Type;
}
} else if ((*it)->Type == X3DElemType::ENET_Appearance) {
Postprocess_BuildMaterial(**it, &tmat);
if (tmat != nullptr) {
// if material successfully built then add data about it to array
mat_ind = static_cast<unsigned int>(pSceneMaterialList.size());
pSceneMaterialList.push_back(tmat);
}
}
} // for(std::list<X3DNodeElementBase*>::const_iterator it = pShapeNodeElement.Children.begin(); it != pShapeNodeElement.Children.end(); it++)
// associate read material with read mesh.
if ((tmesh != nullptr) && (tmat != nullptr)) {
tmesh->mMaterialIndex = mat_ind;
// Check texture mapping. If material has texture but mesh has no texture coordinate then try to ask Assimp to generate texture coordinates.
if ((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0)) {
int32_t tm;
aiVector3D tvec3;
switch (mesh_type) {
case X3DElemType::ENET_Box:
tm = aiTextureMapping_BOX;
break;
case X3DElemType::ENET_Cone:
case X3DElemType::ENET_Cylinder:
tm = aiTextureMapping_CYLINDER;
break;
case X3DElemType::ENET_Sphere:
tm = aiTextureMapping_SPHERE;
break;
default:
tm = aiTextureMapping_PLANE;
break;
} // switch(mesh_type)
tmat->AddProperty(&tm, 1, AI_MATKEY_MAPPING_DIFFUSE(0));
} // if((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0))
} // if((tmesh != nullptr) && (tmat != nullptr))
}
void X3DImporter::Postprocess_CollectMetadata(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode) const {
std::list<X3DNodeElementBase *> meta_list;
size_t meta_idx;
PostprocessHelper_CollectMetadata(pNodeElement, meta_list); // find metadata in current node element.
if (!meta_list.empty()) {
if (pSceneNode.mMetaData != nullptr) {
throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong.");
}
// copy collected metadata to output node.
pSceneNode.mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(meta_list.size()));
meta_idx = 0;
for (std::list<X3DNodeElementBase *>::const_iterator it = meta_list.begin(); it != meta_list.end(); ++it, ++meta_idx) {
X3DNodeElementMeta *cur_meta = (X3DNodeElementMeta *)*it;
// due to limitations we can add only first element of value list.
// Add an element according to its type.
if ((*it)->Type == X3DElemType::ENET_MetaBoolean) {
if (((X3DNodeElementMetaBoolean *)cur_meta)->Value.size() > 0)
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((X3DNodeElementMetaBoolean *)cur_meta)->Value.begin()) == true);
} else if ((*it)->Type == X3DElemType::ENET_MetaDouble) {
if (((X3DNodeElementMetaDouble *)cur_meta)->Value.size() > 0)
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, (float)*(((X3DNodeElementMetaDouble *)cur_meta)->Value.begin()));
} else if ((*it)->Type == X3DElemType::ENET_MetaFloat) {
if (((X3DNodeElementMetaFloat *)cur_meta)->Value.size() > 0)
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((X3DNodeElementMetaFloat *)cur_meta)->Value.begin()));
} else if ((*it)->Type == X3DElemType::ENET_MetaInteger) {
if (((X3DNodeElementMetaInt *)cur_meta)->Value.size() > 0)
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((X3DNodeElementMetaInt *)cur_meta)->Value.begin()));
} else if ((*it)->Type == X3DElemType::ENET_MetaString) {
if (((X3DNodeElementMetaString *)cur_meta)->Value.size() > 0) {
aiString tstr(((X3DNodeElementMetaString *)cur_meta)->Value.begin()->data());
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, tstr);
}
} else {
throw DeadlyImportError("Postprocess. Unknown metadata type.");
} // if((*it)->Type == X3DElemType::ENET_Meta*) else
} // for(std::list<X3DNodeElementBase*>::const_iterator it = meta_list.begin(); it != meta_list.end(); it++)
} // if( !meta_list.empty() )
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
+993
View File
@@ -0,0 +1,993 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Rendering.cpp
/// \brief Parsing data from nodes of "Rendering" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include "X3DXmlHelper.h"
namespace Assimp {
// <Color
// DEF="" ID
// USE="" IDREF
// color="" MFColor [inputOutput]
// />
void X3DImporter::readColor(XmlNode &node) {
std::string use, def;
std::list<aiColor3D> color;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getColor3DListAttribute(node, "color", color);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Color, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementColor(mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementColor *)ne)->Value = color;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Color");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <ColorRGBA
// DEF="" ID
// USE="" IDREF
// color="" MFColorRGBA [inputOutput]
// />
void X3DImporter::readColorRGBA(XmlNode &node) {
std::string use, def;
std::list<aiColor4D> color;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getColor4DListAttribute(node, "color", color);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_ColorRGBA, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementColorRGBA(mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementColorRGBA *)ne)->Value = color;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "ColorRGBA");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Coordinate
// DEF="" ID
// USE="" IDREF
// point="" MFVec3f [inputOutput]
// />
void X3DImporter::readCoordinate(XmlNode &node) {
std::string use, def;
std::list<aiVector3D> point;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector3DListAttribute(node, "point", point);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Coordinate, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementCoordinate(mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementCoordinate *)ne)->Value = point;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Coordinate");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <IndexedLineSet
// DEF="" ID
// USE="" IDREF
// colorIndex="" MFInt32 [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// coordIndex="" MFInt32 [initializeOnly]
// >
// <!-- ColorCoordinateContentModel -->
// ColorCoordinateContentModel is the child-node content model corresponding to IndexedLineSet, LineSet and PointSet. ColorCoordinateContentModel can
// contain any-order Coordinate node with Color (or ColorRGBA) node. No more than one instance of any single node type is allowed.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </IndexedLineSet>
void X3DImporter::readIndexedLineSet(XmlNode &node) {
std::string use, def;
std::vector<int32_t> colorIndex;
bool colorPerVertex = true;
std::vector<int32_t> coordIndex;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getInt32ArrayAttribute(node, "colorIndex", colorIndex);
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
X3DXmlHelper::getInt32ArrayAttribute(node, "coordIndex", coordIndex);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_IndexedLineSet, ne);
} else {
// check data
if ((coordIndex.size() < 2) || ((coordIndex.back() == (-1)) && (coordIndex.size() < 3)))
throw DeadlyImportError("IndexedLineSet must contain not empty \"coordIndex\" attribute.");
// create and if needed - define new geometry object.
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedLineSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)ne);
ne_alias.ColorIndex = colorIndex;
ne_alias.ColorPerVertex = colorPerVertex;
ne_alias.CoordIndex = coordIndex;
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for Color and Coordinate nodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("IndexedLineSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <IndexedTriangleFanSet
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// index="" MFInt32 [initializeOnly]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// >
// <!-- ComposedGeometryContentModel -->
// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate,
// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute,
// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </IndexedTriangleFanSet>
void X3DImporter::readIndexedTriangleFanSet(XmlNode &node) {
std::string use, def;
bool ccw = true;
bool colorPerVertex = true;
std::vector<int32_t> index;
bool normalPerVertex = true;
bool solid = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "ccw", ccw);
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
X3DXmlHelper::getInt32ArrayAttribute(node, "index", index);
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_IndexedTriangleFanSet, ne);
} else {
// check data
if (index.size() == 0) throw DeadlyImportError("IndexedTriangleFanSet must contain not empty \"index\" attribute.");
// create and if needed - define new geometry object.
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedTriangleFanSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)ne);
ne_alias.CCW = ccw;
ne_alias.ColorPerVertex = colorPerVertex;
ne_alias.NormalPerVertex = normalPerVertex;
ne_alias.Solid = solid;
ne_alias.CoordIndex.clear();
int counter = 0;
int32_t idx[3];
for (std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) {
idx[2] = *idx_it;
if (idx[2] < 0) {
counter = 0;
} else {
if (counter >= 2) {
if (ccw) {
ne_alias.CoordIndex.push_back(idx[0]);
ne_alias.CoordIndex.push_back(idx[1]);
ne_alias.CoordIndex.push_back(idx[2]);
} else {
ne_alias.CoordIndex.push_back(idx[0]);
ne_alias.CoordIndex.push_back(idx[2]);
ne_alias.CoordIndex.push_back(idx[1]);
}
ne_alias.CoordIndex.push_back(-1);
idx[1] = idx[2];
} else {
idx[counter] = idx[2];
}
++counter;
}
} // for(std::list<int32_t>::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++)
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
else if (currentChildName == "Normal")
readNormal(currentChildNode);
else if (currentChildName == "TextureCoordinate")
readTextureCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("IndexedTriangleFanSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <IndexedTriangleSet
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// index="" MFInt32 [initializeOnly]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// >
// <!-- ComposedGeometryContentModel -->
// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate,
// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute,
// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </IndexedTriangleSet>
void X3DImporter::readIndexedTriangleSet(XmlNode &node) {
std::string use, def;
bool ccw = true;
bool colorPerVertex = true;
std::vector<int32_t> index;
bool normalPerVertex = true;
bool solid = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "ccw", ccw);
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
X3DXmlHelper::getInt32ArrayAttribute(node, "index", index);
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_IndexedTriangleSet, ne);
} else {
// check data
if (index.size() == 0) throw DeadlyImportError("IndexedTriangleSet must contain not empty \"index\" attribute.");
// create and if needed - define new geometry object.
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedTriangleSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)ne);
ne_alias.CCW = ccw;
ne_alias.ColorPerVertex = colorPerVertex;
ne_alias.NormalPerVertex = normalPerVertex;
ne_alias.Solid = solid;
ne_alias.CoordIndex.clear();
int counter = 0;
int32_t idx[3];
for (std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) {
idx[counter++] = *idx_it;
if (counter > 2) {
counter = 0;
if (ccw) {
ne_alias.CoordIndex.push_back(idx[0]);
ne_alias.CoordIndex.push_back(idx[1]);
ne_alias.CoordIndex.push_back(idx[2]);
} else {
ne_alias.CoordIndex.push_back(idx[0]);
ne_alias.CoordIndex.push_back(idx[2]);
ne_alias.CoordIndex.push_back(idx[1]);
}
ne_alias.CoordIndex.push_back(-1);
}
} // for(std::list<int32_t>::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++)
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
else if (currentChildName == "Normal")
readNormal(currentChildNode);
else if (currentChildName == "TextureCoordinate")
readTextureCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("IndexedTriangleSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <IndexedTriangleStripSet
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// index="" MFInt32 [initializeOnly]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// >
// <!-- ComposedGeometryContentModel -->
// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate,
// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute,
// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </IndexedTriangleStripSet>
void X3DImporter::readIndexedTriangleStripSet(XmlNode &node) {
std::string use, def;
bool ccw = true;
bool colorPerVertex = true;
std::vector<int32_t> index;
bool normalPerVertex = true;
bool solid = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "ccw", ccw);
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
X3DXmlHelper::getInt32ArrayAttribute(node, "index", index);
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_IndexedTriangleStripSet, ne);
} else {
// check data
if (index.empty()) {
throw DeadlyImportError("IndexedTriangleStripSet must contain not empty \"index\" attribute.");
}
// create and if needed - define new geometry object.
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_IndexedTriangleStripSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementIndexedSet &ne_alias = *((X3DNodeElementIndexedSet *)ne);
ne_alias.CCW = ccw;
ne_alias.ColorPerVertex = colorPerVertex;
ne_alias.NormalPerVertex = normalPerVertex;
ne_alias.Solid = solid;
ne_alias.CoordIndex.clear();
int counter = 0;
int32_t idx[3];
for (std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) {
idx[2] = *idx_it;
if (idx[2] < 0) {
counter = 0;
} else {
if (counter >= 2) {
if (ccw) {
ne_alias.CoordIndex.push_back(idx[0]);
ne_alias.CoordIndex.push_back(idx[1]);
ne_alias.CoordIndex.push_back(idx[2]);
} else {
ne_alias.CoordIndex.push_back(idx[0]);
ne_alias.CoordIndex.push_back(idx[2]);
ne_alias.CoordIndex.push_back(idx[1]);
}
ne_alias.CoordIndex.push_back(-1);
}
idx[counter & 1] = idx[2];
++counter;
}
} // for(std::list<int32_t>::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++)
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
else if (currentChildName == "Normal")
readNormal(currentChildNode);
else if (currentChildName == "TextureCoordinate")
readTextureCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("IndexedTriangleStripSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <LineSet
// DEF="" ID
// USE="" IDREF
// vertexCount="" MFInt32 [initializeOnly]
// >
// <!-- ColorCoordinateContentModel -->
// ColorCoordinateContentModel is the child-node content model corresponding to IndexedLineSet, LineSet and PointSet. ColorCoordinateContentModel can
// contain any-order Coordinate node with Color (or ColorRGBA) node. No more than one instance of any single node type is allowed.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </LineSet>
void X3DImporter::readLineSet(XmlNode &node) {
std::string use, def;
std::vector<int32_t> vertexCount;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getInt32ArrayAttribute(node, "vertexCount", vertexCount);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_LineSet, ne);
} else {
// check data
if (vertexCount.empty()) {
throw DeadlyImportError("LineSet must contain not empty \"vertexCount\" attribute.");
}
// create and if needed - define new geometry object.
ne = new X3DNodeElementSet(X3DElemType::ENET_LineSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementSet &ne_alias = *((X3DNodeElementSet *)ne);
ne_alias.VertexCount = vertexCount;
// create CoordIdx
size_t coord_num = 0;
ne_alias.CoordIndex.clear();
for (std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it) {
if (*vc_it < 2) throw DeadlyImportError("LineSet. vertexCount shall be greater than or equal to two.");
for (int32_t i = 0; i < *vc_it; i++)
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num++)); // add vertices indices
ne_alias.CoordIndex.push_back(-1); // add face delimiter.
}
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("LineSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <PointSet
// DEF="" ID
// USE="" IDREF
// >
// <!-- ColorCoordinateContentModel -->
// ColorCoordinateContentModel is the child-node content model corresponding to IndexedLineSet, LineSet and PointSet. ColorCoordinateContentModel can
// contain any-order Coordinate node with Color (or ColorRGBA) node. No more than one instance of any single node type is allowed.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </PointSet>
void X3DImporter::readPointSet(XmlNode &node) {
std::string use, def;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_PointSet, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_PointSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("PointSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <TriangleFanSet
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// fanCount="" MFInt32 [inputOutput]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// >
// <!-- ComposedGeometryContentModel -->
// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate,
// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute,
// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </TriangleFanSet>
void X3DImporter::readTriangleFanSet(XmlNode &node) {
std::string use, def;
bool ccw = true;
bool colorPerVertex = true;
std::vector<int32_t> fanCount;
bool normalPerVertex = true;
bool solid = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "ccw", ccw);
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
X3DXmlHelper::getInt32ArrayAttribute(node, "fanCount", fanCount);
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TriangleFanSet, ne);
} else {
// check data
if (fanCount.empty()) {
throw DeadlyImportError("TriangleFanSet must contain not empty \"fanCount\" attribute.");
}
// create and if needed - define new geometry object.
ne = new X3DNodeElementSet(X3DElemType::ENET_TriangleFanSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementSet &ne_alias = *((X3DNodeElementSet *)ne);
ne_alias.CCW = ccw;
ne_alias.ColorPerVertex = colorPerVertex;
ne_alias.VertexCount = fanCount;
ne_alias.NormalPerVertex = normalPerVertex;
ne_alias.Solid = solid;
// create CoordIdx
size_t coord_num_first, coord_num_prev;
ne_alias.CoordIndex.clear();
// assign indices for first triangle
coord_num_first = 0;
coord_num_prev = 1;
for (std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it) {
if (*vc_it < 3) throw DeadlyImportError("TriangleFanSet. fanCount shall be greater than or equal to three.");
for (int32_t vc = 2; vc < *vc_it; vc++) {
if (ccw) {
// 2 1
// 0
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_first)); // first vertex is a center and always is [0].
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_prev++));
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_prev));
} else {
// 1 2
// 0
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_first)); // first vertex is a center and always is [0].
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_prev + 1));
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num_prev++));
} // if(ccw) else
ne_alias.CoordIndex.push_back(-1); // add face delimiter.
} // for(int32_t vc = 2; vc < *vc_it; vc++)
coord_num_prev++; // that index will be center of next fan
coord_num_first = coord_num_prev++; // forward to next point - second point of fan
} // for(std::list<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
else if (currentChildName == "Normal")
readNormal(currentChildNode);
else if (currentChildName == "TextureCoordinate")
readTextureCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("TriangleFanSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <TriangleSet
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// >
// <!-- ComposedGeometryContentModel -->
// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate,
// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute,
// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </TriangleSet>
void X3DImporter::readTriangleSet(XmlNode &node) {
std::string use, def;
bool ccw = true;
bool colorPerVertex = true;
bool normalPerVertex = true;
bool solid = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "ccw", ccw);
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TriangleSet, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementIndexedSet(X3DElemType::ENET_TriangleSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementSet &ne_alias = *((X3DNodeElementSet *)ne);
ne_alias.CCW = ccw;
ne_alias.ColorPerVertex = colorPerVertex;
ne_alias.NormalPerVertex = normalPerVertex;
ne_alias.Solid = solid;
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
else if (currentChildName == "Normal")
readNormal(currentChildNode);
else if (currentChildName == "TextureCoordinate")
readTextureCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("TriangleSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <TriangleStripSet
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// stripCount="" MFInt32 [inputOutput]
// >
// <!-- ComposedGeometryContentModel -->
// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate,
// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute,
// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </TriangleStripSet>
void X3DImporter::readTriangleStripSet(XmlNode &node) {
std::string use, def;
bool ccw = true;
bool colorPerVertex = true;
std::vector<int32_t> stripCount;
bool normalPerVertex = true;
bool solid = true;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "ccw", ccw);
XmlParser::getBoolAttribute(node, "colorPerVertex", colorPerVertex);
X3DXmlHelper::getInt32ArrayAttribute(node, "stripCount", stripCount);
XmlParser::getBoolAttribute(node, "normalPerVertex", normalPerVertex);
XmlParser::getBoolAttribute(node, "solid", solid);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TriangleStripSet, ne);
} else {
// check data
if (stripCount.size() == 0) throw DeadlyImportError("TriangleStripSet must contain not empty \"stripCount\" attribute.");
// create and if needed - define new geometry object.
ne = new X3DNodeElementSet(X3DElemType::ENET_TriangleStripSet, mNodeElementCur);
if (!def.empty()) ne->ID = def;
X3DNodeElementSet &ne_alias = *((X3DNodeElementSet *)ne);
ne_alias.CCW = ccw;
ne_alias.ColorPerVertex = colorPerVertex;
ne_alias.VertexCount = stripCount;
ne_alias.NormalPerVertex = normalPerVertex;
ne_alias.Solid = solid;
// create CoordIdx
size_t coord_num0, coord_num1, coord_num2; // indices of current triangle
bool odd_tri; // sequence of current triangle
size_t coord_num_sb; // index of first point of strip
ne_alias.CoordIndex.clear();
coord_num_sb = 0;
for (std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it) {
if (*vc_it < 3) throw DeadlyImportError("TriangleStripSet. stripCount shall be greater than or equal to three.");
// set initial values for first triangle
coord_num0 = coord_num_sb;
coord_num1 = coord_num_sb + 1;
coord_num2 = coord_num_sb + 2;
odd_tri = true;
for (int32_t vc = 2; vc < *vc_it; vc++) {
if (ccw) {
// 0 2
// 1
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num0));
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num1));
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num2));
} else {
// 0 1
// 2
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num0));
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num2));
ne_alias.CoordIndex.push_back(static_cast<int32_t>(coord_num1));
} // if(ccw) else
ne_alias.CoordIndex.push_back(-1); // add face delimiter.
// prepare values for next triangle
if (odd_tri) {
coord_num0 = coord_num2;
coord_num2++;
} else {
coord_num1 = coord_num2;
coord_num2 = coord_num1 + 1;
}
odd_tri = !odd_tri;
coord_num_sb = coord_num2; // that index will be start of next strip
} // for(int32_t vc = 2; vc < *vc_it; vc++)
} // for(std::list<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++)
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for X3DComposedGeometryNodes
if (currentChildName == "Color")
readColor(currentChildNode);
else if (currentChildName == "ColorRGBA")
readColorRGBA(currentChildNode);
else if (currentChildName == "Coordinate")
readCoordinate(currentChildNode);
else if (currentChildName == "Normal")
readNormal(currentChildNode);
else if (currentChildName == "TextureCoordinate")
readTextureCoordinate(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("TriangleStripSet", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Normal
// DEF="" ID
// USE="" IDREF
// vector="" MFVec3f [inputOutput]
// />
void X3DImporter::readNormal(XmlNode &node) {
std::string use, def;
std::list<aiVector3D> vector;
X3DNodeElementBase *ne=nullptr;
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector3DListAttribute(node, "vector", vector);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Normal, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementNormal(mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementNormal *)ne)->Value = vector;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Normal");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
+241
View File
@@ -0,0 +1,241 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Shape.cpp
/// \brief Parsing data from nodes of "Shape" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include "X3DXmlHelper.h"
namespace Assimp {
void X3DImporter::readShape(XmlNode &node) {
std::string use, def;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Shape, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementShape(mNodeElementCur);
if (!def.empty()) ne->ID = def;
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
// check for appearance node
if (currentChildName == "Appearance") readAppearance(currentChildNode);
// check for X3DGeometryNodes
else if (currentChildName == "Arc2D")
readArc2D(currentChildNode);
else if (currentChildName == "ArcClose2D")
readArcClose2D(currentChildNode);
else if (currentChildName == "Circle2D")
readCircle2D(currentChildNode);
else if (currentChildName == "Disk2D")
readDisk2D(currentChildNode);
else if (currentChildName == "Polyline2D")
readPolyline2D(currentChildNode);
else if (currentChildName == "Polypoint2D")
readPolypoint2D(currentChildNode);
else if (currentChildName == "Rectangle2D")
readRectangle2D(currentChildNode);
else if (currentChildName == "TriangleSet2D")
readTriangleSet2D(currentChildNode);
else if (currentChildName == "Box")
readBox(currentChildNode);
else if (currentChildName == "Cone")
readCone(currentChildNode);
else if (currentChildName == "Cylinder")
readCylinder(currentChildNode);
else if (currentChildName == "ElevationGrid")
readElevationGrid(currentChildNode);
else if (currentChildName == "Extrusion")
readExtrusion(currentChildNode);
else if (currentChildName == "IndexedFaceSet")
readIndexedFaceSet(currentChildNode);
else if (currentChildName == "Sphere")
readSphere(currentChildNode);
else if (currentChildName == "IndexedLineSet")
readIndexedLineSet(currentChildNode);
else if (currentChildName == "LineSet")
readLineSet(currentChildNode);
else if (currentChildName == "PointSet")
readPointSet(currentChildNode);
else if (currentChildName == "IndexedTriangleFanSet")
readIndexedTriangleFanSet(currentChildNode);
else if (currentChildName == "IndexedTriangleSet")
readIndexedTriangleSet(currentChildNode);
else if (currentChildName == "IndexedTriangleStripSet")
readIndexedTriangleStripSet(currentChildNode);
else if (currentChildName == "TriangleFanSet")
readTriangleFanSet(currentChildNode);
else if (currentChildName == "TriangleSet")
readTriangleSet(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("Shape", currentChildNode);
}
ParseHelper_Node_Exit();
} // if (!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Appearance
// DEF="" ID
// USE="" IDREF
// >
// <!-- AppearanceChildContentModel -->
// "Child-node content model corresponding to X3DAppearanceChildNode. Appearance can contain FillProperties, LineProperties, Material, any Texture node and
// any TextureTransform node, in any order. No more than one instance of these nodes is allowed. Appearance may also contain multiple shaders (ComposedShader,
// PackagedShader, ProgramShader).
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model."
// </Appearance>
void X3DImporter::readAppearance(XmlNode &node) {
std::string use, def;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Appearance, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementAppearance(mNodeElementCur);
if (!def.empty()) ne->ID = def;
// check for child nodes
if (!isNodeEmpty(node)) {
ParseHelper_Node_Enter(ne);
for (auto currentChildNode : node.children()) {
const std::string &currentChildName = currentChildNode.name();
if (currentChildName == "Material")
readMaterial(currentChildNode);
else if (currentChildName == "ImageTexture")
readImageTexture(currentChildNode);
else if (currentChildName == "TextureTransform")
readTextureTransform(currentChildNode);
// check for X3DMetadataObject
else if (!checkForMetadataNode(currentChildNode))
skipUnsupportedNode("Appearance", currentChildNode);
}
ParseHelper_Node_Exit();
} // if(!isNodeEmpty(node))
else {
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
}
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <Material
// DEF="" ID
// USE="" IDREF
// ambientIntensity="0.2" SFFloat [inputOutput]
// diffuseColor="0.8 0.8 0.8" SFColor [inputOutput]
// emissiveColor="0 0 0" SFColor [inputOutput]
// shininess="0.2" SFFloat [inputOutput]
// specularColor="0 0 0" SFColor [inputOutput]
// transparency="0" SFFloat [inputOutput]
// />
void X3DImporter::readMaterial(XmlNode &node) {
std::string use, def;
float ambientIntensity = 0.2f;
float shininess = 0.2f;
float transparency = 0;
aiColor3D diffuseColor(0.8f, 0.8f, 0.8f);
aiColor3D emissiveColor(0, 0, 0);
aiColor3D specularColor(0, 0, 0);
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getFloatAttribute(node, "ambientIntensity", ambientIntensity);
XmlParser::getFloatAttribute(node, "shininess", shininess);
XmlParser::getFloatAttribute(node, "transparency", transparency);
X3DXmlHelper::getColor3DAttribute(node, "diffuseColor", diffuseColor);
X3DXmlHelper::getColor3DAttribute(node, "emissiveColor", emissiveColor);
X3DXmlHelper::getColor3DAttribute(node, "specularColor", specularColor);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Material, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementMaterial(mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementMaterial *)ne)->AmbientIntensity = ambientIntensity;
((X3DNodeElementMaterial *)ne)->Shininess = shininess;
((X3DNodeElementMaterial *)ne)->Transparency = transparency;
((X3DNodeElementMaterial *)ne)->DiffuseColor = diffuseColor;
((X3DNodeElementMaterial *)ne)->EmissiveColor = emissiveColor;
((X3DNodeElementMaterial *)ne)->SpecularColor = specularColor;
// check for child nodes
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "Material");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
+179
View File
@@ -0,0 +1,179 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Texturing.cpp
/// \brief Parsing data from nodes of "Texturing" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include "X3DXmlHelper.h"
namespace Assimp {
// <ImageTexture
// DEF="" ID
// USE="" IDREF
// repeatS="true" SFBool
// repeatT="true" SFBool
// url="" MFString
// />
// When the url field contains no values ([]), texturing is disabled.
void X3DImporter::readImageTexture(XmlNode &node) {
std::string use, def;
bool repeatS = true;
bool repeatT = true;
std::list<std::string> url;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
XmlParser::getBoolAttribute(node, "repeatS", repeatS);
XmlParser::getBoolAttribute(node, "repeatT", repeatT);
X3DXmlHelper::getStringListAttribute(node, "url", url);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_ImageTexture, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementImageTexture(mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementImageTexture *)ne)->RepeatS = repeatS;
((X3DNodeElementImageTexture *)ne)->RepeatT = repeatT;
// Attribute "url" can contain list of strings. But we need only one - first.
if (!url.empty())
((X3DNodeElementImageTexture *)ne)->URL = url.front();
else
((X3DNodeElementImageTexture *)ne)->URL = "";
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "ImageTexture");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <TextureCoordinate
// DEF="" ID
// USE="" IDREF
// point="" MFVec3f [inputOutput]
// />
void X3DImporter::readTextureCoordinate(XmlNode &node) {
std::string use, def;
std::list<aiVector2D> point;
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector2DListAttribute(node, "point", point);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TextureCoordinate, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementTextureCoordinate(mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementTextureCoordinate *)ne)->Value = point;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "TextureCoordinate");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
// <TextureTransform
// DEF="" ID
// USE="" IDREF
// center="0 0" SFVec2f [inputOutput]
// rotation="0" SFFloat [inputOutput]
// scale="1 1" SFVec2f [inputOutput]
// translation="0 0" SFVec2f [inputOutput]
// />
void X3DImporter::readTextureTransform(XmlNode &node) {
std::string use, def;
aiVector2D center(0, 0);
float rotation = 0;
aiVector2D scale(1, 1);
aiVector2D translation(0, 0);
X3DNodeElementBase *ne(nullptr);
MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use);
X3DXmlHelper::getVector2DAttribute(node, "center", center);
XmlParser::getFloatAttribute(node, "rotation", rotation);
X3DXmlHelper::getVector2DAttribute(node, "scale", scale);
X3DXmlHelper::getVector2DAttribute(node, "translation", translation);
// if "USE" defined then find already defined element.
if (!use.empty()) {
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TextureTransform, ne);
} else {
// create and if needed - define new geometry object.
ne = new X3DNodeElementTextureTransform(mNodeElementCur);
if (!def.empty()) ne->ID = def;
((X3DNodeElementTextureTransform *)ne)->Center = center;
((X3DNodeElementTextureTransform *)ne)->Rotation = rotation;
((X3DNodeElementTextureTransform *)ne)->Scale = scale;
((X3DNodeElementTextureTransform *)ne)->Translation = translation;
// check for X3DMetadataObject childs.
if (!isNodeEmpty(node))
childrenReadMetadata(node, ne, "TextureTransform");
else
mNodeElementCur->Children.push_back(ne); // add made object as child to current element
NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph
} // if(!use.empty()) else
}
} // namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
+294
View File
@@ -0,0 +1,294 @@
#include "X3DXmlHelper.h"
#include "X3DImporter.hpp"
#include <assimp/ParsingUtils.h>
namespace Assimp {
bool X3DXmlHelper::getColor3DAttribute(XmlNode &node, const char *attributeName, aiColor3D &color) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
if (values.size() != 3) {
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
return false;
}
auto it = values.begin();
color.r = stof(*it++);
color.g = stof(*it++);
color.b = stof(*it);
return true;
}
return false;
}
bool X3DXmlHelper::getVector2DAttribute(XmlNode &node, const char *attributeName, aiVector2D &color) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
if (values.size() != 2) {
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
return false;
}
auto it = values.begin();
color.x = stof(*it++);
color.y = stof(*it);
return true;
}
return false;
}
bool X3DXmlHelper::getVector3DAttribute(XmlNode &node, const char *attributeName, aiVector3D &color) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
if (values.size() != 3) {
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
return false;
}
auto it = values.begin();
color.x = stof(*it++);
color.y = stof(*it++);
color.z = stof(*it);
return true;
}
return false;
}
bool X3DXmlHelper::getBooleanArrayAttribute(XmlNode &node, const char *attributeName, std::vector<bool> &boolArray) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
auto it = values.begin();
while (it != values.end()) {
auto s = *it++;
if (!s.empty())
boolArray.push_back(s[0] == 't' || s[0] == '1');
else
Throw_ConvertFail_Str2ArrB(node.name(), attributeName);
}
return true;
}
return false;
}
bool X3DXmlHelper::getDoubleArrayAttribute(XmlNode &node, const char *attributeName, std::vector<double> &doubleArray) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
auto it = values.begin();
while (it != values.end()) {
auto s = *it++;
if (!s.empty())
doubleArray.push_back(atof(s.c_str()));
else
Throw_ConvertFail_Str2ArrD(node.name(), attributeName);
}
return true;
}
return false;
}
bool X3DXmlHelper::getFloatArrayAttribute(XmlNode &node, const char *attributeName, std::vector<float> &floatArray) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
auto it = values.begin();
while (it != values.end()) {
auto s = *it++;
if (!s.empty())
floatArray.push_back((float)atof(s.c_str()));
else
Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
}
return true;
}
return false;
}
bool X3DXmlHelper::getInt32ArrayAttribute(XmlNode &node, const char *attributeName, std::vector<int32_t> &intArray) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
auto it = values.begin();
while (it != values.end()) {
auto s = *it++;
if (!s.empty())
intArray.push_back((int32_t)atof(s.c_str()));
else
Throw_ConvertFail_Str2ArrI(node.name(), attributeName);
}
return true;
}
return false;
}
bool X3DXmlHelper::getStringListAttribute(XmlNode &node, const char *attributeName, std::list<std::string> &stringList) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
auto it = values.begin();
std::string currentConcat = "";
bool inQuotes = false;
while (it != values.end()) {
auto s = *it++;
if (!s.empty()) {
if (inQuotes) {
if (*(s.rbegin()) == '"') {
stringList.push_back(currentConcat + s.substr(0, s.length() - 1));
currentConcat = "";
inQuotes = false;
} else {
currentConcat += " " + s;
}
} else {
if (s[0] == '"') {
currentConcat = s.substr(1);
inQuotes = true;
} else {
stringList.push_back(s);
}
}
} else if (!inQuotes)
Throw_ConvertFail_Str2ArrI(node.name(), attributeName);
}
if (inQuotes) Throw_ConvertFail_Str2ArrI(node.name(), attributeName);
return true;
}
return false;
}
bool X3DXmlHelper::getStringArrayAttribute(XmlNode &node, const char *attributeName, std::vector<std::string> &stringArray) {
std::list<std::string> tlist;
if (getStringListAttribute(node, attributeName, tlist)) {
if (!tlist.empty()) {
stringArray.reserve(tlist.size());
for (std::list<std::string>::iterator it = tlist.begin(); it != tlist.end(); ++it) {
stringArray.push_back(*it);
}
return true;
}
}
return false;
}
bool X3DXmlHelper::getVector2DListAttribute(XmlNode &node, const char *attributeName, std::list<aiVector2D> &vectorList) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
if (values.size() % 2) Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
auto it = values.begin();
while (it != values.end()) {
aiVector2D tvec;
tvec.x = (float)atof((*it++).c_str());
tvec.y = (float)atof((*it++).c_str());
vectorList.push_back(tvec);
}
return true;
}
return false;
}
bool X3DXmlHelper::getVector2DArrayAttribute(XmlNode &node, const char *attributeName, std::vector<aiVector2D> &vectorArray) {
std::list<aiVector2D> tlist;
if (getVector2DListAttribute(node, attributeName, tlist)) {
if (!tlist.empty()) {
vectorArray.reserve(tlist.size());
for (std::list<aiVector2D>::iterator it = tlist.begin(); it != tlist.end(); ++it) {
vectorArray.push_back(*it);
}
return true;
}
}
return false;
}
bool X3DXmlHelper::getVector3DListAttribute(XmlNode &node, const char *attributeName, std::list<aiVector3D> &vectorList) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
if (values.size() % 3 != 0) Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
auto it = values.begin();
while (it != values.end()) {
aiVector3D tvec;
tvec.x = (float)atof((*it++).c_str());
tvec.y = (float)atof((*it++).c_str());
tvec.z = (float)atof((*it++).c_str());
vectorList.push_back(tvec);
}
return true;
}
return false;
}
bool X3DXmlHelper::getVector3DArrayAttribute(XmlNode &node, const char *attributeName, std::vector<aiVector3D> &vectorArray) {
std::list<aiVector3D> tlist;
if (getVector3DListAttribute(node, attributeName, tlist)) {
if (!tlist.empty()) {
vectorArray.reserve(tlist.size());
for (std::list<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); ++it) {
vectorArray.push_back(*it);
}
return true;
}
}
return false;
}
bool X3DXmlHelper::getColor3DListAttribute(XmlNode &node, const char *attributeName, std::list<aiColor3D> &colorList) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
if (values.size() % 3 != 0) Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
auto it = values.begin();
while (it != values.end()) {
aiColor3D tvec;
tvec.r = (float)atof((*it++).c_str());
tvec.g = (float)atof((*it++).c_str());
tvec.b = (float)atof((*it++).c_str());
colorList.push_back(tvec);
}
return true;
}
return false;
}
bool X3DXmlHelper::getColor4DListAttribute(XmlNode &node, const char *attributeName, std::list<aiColor4D> &colorList) {
std::string val;
if (XmlParser::getStdStrAttribute(node, attributeName, val)) {
std::vector<std::string> values;
tokenize<std::string>(val, values, " ");
if (values.size() % 4 != 0) Throw_ConvertFail_Str2ArrF(node.name(), attributeName);
auto it = values.begin();
while (it != values.end()) {
aiColor4D tvec;
tvec.r = (float)atof((*it++).c_str());
tvec.g = (float)atof((*it++).c_str());
tvec.b = (float)atof((*it++).c_str());
tvec.a = (float)atof((*it++).c_str());
colorList.push_back(tvec);
}
return true;
}
return false;
}
} // namespace Assimp
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <assimp/XmlParser.h>
#include <assimp/types.h>
#include <list>
namespace Assimp {
class X3DXmlHelper {
public:
static bool getColor3DAttribute(XmlNode &node, const char *attributeName, aiColor3D &color);
static bool getVector2DAttribute(XmlNode &node, const char *attributeName, aiVector2D &vector);
static bool getVector3DAttribute(XmlNode &node, const char *attributeName, aiVector3D &vector);
static bool getBooleanArrayAttribute(XmlNode &node, const char *attributeName, std::vector<bool> &boolArray);
static bool getDoubleArrayAttribute(XmlNode &node, const char *attributeName, std::vector<double> &doubleArray);
static bool getFloatArrayAttribute(XmlNode &node, const char *attributeName, std::vector<float> &floatArray);
static bool getInt32ArrayAttribute(XmlNode &node, const char *attributeName, std::vector<int32_t> &intArray);
static bool getStringListAttribute(XmlNode &node, const char *attributeName, std::list<std::string> &stringArray);
static bool getStringArrayAttribute(XmlNode &node, const char *attributeName, std::vector<std::string> &stringArray);
static bool getVector2DListAttribute(XmlNode &node, const char *attributeName, std::list<aiVector2D> &vectorList);
static bool getVector2DArrayAttribute(XmlNode &node, const char *attributeName, std::vector<aiVector2D> &vectorArray);
static bool getVector3DListAttribute(XmlNode &node, const char *attributeName, std::list<aiVector3D> &vectorList);
static bool getVector3DArrayAttribute(XmlNode &node, const char *attributeName, std::vector<aiVector3D> &vectorArray);
static bool getColor3DListAttribute(XmlNode &node, const char *attributeName, std::list<aiColor3D> &colorList);
static bool getColor4DListAttribute(XmlNode &node, const char *attributeName, std::list<aiColor4D> &colorList);
};
} // namespace Assimp
+61 -52
View File
@@ -39,8 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#include <assimp/StringUtils.h>
#include <assimp/MemoryIOWrapper.h>
#include <assimp/StringUtils.h>
#include <iomanip>
// Header files, Assimp
@@ -57,11 +57,10 @@ using namespace glTFCommon;
namespace glTF {
#if _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4706)
#pragma warning(push)
#pragma warning(disable : 4706)
#endif // _MSC_VER
//
// LazyDict methods
//
@@ -214,9 +213,10 @@ inline void Buffer::Read(Value &obj, Asset &r) {
} else { // Local file
if (byteLength > 0) {
std::string dir = !r.mCurrentAssetDir.empty() ? (
r.mCurrentAssetDir.back() == '/' ?
r.mCurrentAssetDir : r.mCurrentAssetDir + '/'
) : "";
r.mCurrentAssetDir.back() == '/' ?
r.mCurrentAssetDir :
r.mCurrentAssetDir + '/') :
"";
IOStream *file = r.OpenFile(dir + uri, "rb");
if (file) {
@@ -734,8 +734,8 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
ASSIMP_LOG_INFO("GLTF: Decompressing Open3DGC data.");
/************** Read data from JSON-document **************/
#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \
if (!ReadMember(*comp_data, pFieldName, pOut)) { \
#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \
if (!ReadMember(*comp_data, pFieldName, pOut)) { \
throw DeadlyImportError("GLTF: \"compressedData\" must has \"", pFieldName, "\"."); \
}
@@ -771,8 +771,7 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
Decode_O3DGC(*ext_o3dgc, pAsset_Root);
Extension.push_back(ext_o3dgc); // store info in mesh extensions list.
} // if(it_memb->name.GetString() == "Open3DGC-compression")
else
{
else {
throw DeadlyImportError("GLTF: Unknown mesh extension: \"", it_memb->name.GetString(), "\".");
}
} // for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
@@ -842,21 +841,21 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
size_t tval = ifs.GetNFloatAttribute(static_cast<unsigned long>(idx));
switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) {
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
// Check situation when encoded data contain texture coordinates but primitive not.
if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
if (primitives[0].attributes.texcoord[idx]->count != tval)
throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (", ai_to_string(tval),
") not equal to uncompressed (", ai_to_string(primitives[0].attributes.texcoord[idx]->count), ").");
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
// Check situation when encoded data contain texture coordinates but primitive not.
if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
if (primitives[0].attributes.texcoord[idx]->count != tval)
throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (", ai_to_string(tval),
") not equal to uncompressed (", ai_to_string(primitives[0].attributes.texcoord[idx]->count), ").");
idx_texcoord++;
} else {
ifs.SetNFloatAttribute(static_cast<unsigned long>(idx), 0ul); // Disable decoding this attribute.
}
idx_texcoord++;
} else {
ifs.SetNFloatAttribute(static_cast<unsigned long>(idx), 0ul); // Disable decoding this attribute.
}
break;
default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
break;
default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
}
tval *= ifs.GetFloatAttributeDim(static_cast<unsigned long>(idx)) * sizeof(o3dgc::Real); // After checking count of objects we can get size of array.
@@ -868,14 +867,14 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
// size = number_of_elements * components_per_element * size_of_component. See float attributes note.
size_t tval = ifs.GetNIntAttribute(static_cast<unsigned long>(idx));
switch (ifs.GetIntAttributeType(static_cast<unsigned long>(idx))) {
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
break;
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
break;
default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
}
tval *= ifs.GetIntAttributeDim(static_cast<unsigned long>(idx)) * sizeof(long); // See float attributes note.
@@ -901,30 +900,30 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
for (size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) {
switch (ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))) {
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
// See above about absent attributes.
ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real *const)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
idx_texcoord++;
}
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
// See above about absent attributes.
ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real *const)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
idx_texcoord++;
}
break;
default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
break;
default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: ", ai_to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
}
}
for (size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) {
switch (ifs.GetIntAttributeType(static_cast<unsigned int>(idx))) {
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
break;
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
break;
// ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint)));
default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
// ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint)));
default:
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: ", ai_to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
}
}
@@ -1148,7 +1147,8 @@ inline void Asset::ReadBinaryHeader(IOStream &stream) {
AI_SWAP4(header.length);
AI_SWAP4(header.sceneLength);
mSceneLength = static_cast<size_t>(header.sceneLength);
static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits");
mSceneLength = static_cast<size_t>(header.sceneLength); // Can't be larger than 4GB (max. uint32_t)
mBodyOffset = sizeof(header) + mSceneLength;
mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4
@@ -1179,8 +1179,17 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
mBodyLength = 0;
}
// read the scene data
// Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later
if (mSceneLength < 2) {
throw DeadlyImportError("GLTF: No JSON file contents");
}
// Binary format only supports up to 4GB of JSON so limit it there to avoid extreme memory allocation
if (mSceneLength >= std::numeric_limits<uint32_t>::max()) {
throw DeadlyImportError("GLTF: JSON size greater than 4GB");
}
// read the scene data, ensure null termination
std::vector<char> sceneData(mSceneLength + 1);
sceneData[mSceneLength] = '\0';
@@ -1258,7 +1267,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
#undef CHECK_EXT
}
inline IOStream *Asset::OpenFile(const std::string& path, const char *mode, bool absolute) {
inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool absolute) {
#ifdef ASSIMP_API
(void)absolute;
return mIOSystem->Open(path, mode);
@@ -1300,7 +1309,7 @@ inline std::string Asset::FindUniqueID(const std::string &str, const char *suffi
}
#if _MSC_VER
# pragma warning(pop)
#pragma warning(pop)
#endif // _MSC_VER
} // namespace glTF
+1 -1
View File
@@ -300,7 +300,7 @@ public:
inline unsigned int GetIndex() const { return index; }
operator bool() const { return vector != 0; }
operator bool() const { return vector != nullptr && index < vector->size(); }
T *operator->() { return (*vector)[index]; }
+6 -3
View File
@@ -322,8 +322,8 @@ void glTFExporter::GetTexSampler(const aiMaterial* mat, glTF::TexProperty& prop)
prop.texture->sampler->minFilter = SamplerMinFilter_Linear;
}
void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt)
{
void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop,
const char* propName, int type, int idx, aiTextureType tt) {
aiString tex;
aiColor4D col;
if (mat->GetTextureCount(tt) > 0) {
@@ -370,7 +370,10 @@ void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& pr
}
if (mat->Get(propName, type, idx, col) == AI_SUCCESS) {
prop.color[0] = col.r; prop.color[1] = col.g; prop.color[2] = col.b; prop.color[3] = col.a;
prop.color[0] = col.r;
prop.color[1] = col.g;
prop.color[2] = col.b;
prop.color[3] = col.a;
}
}
+42 -2
View File
@@ -49,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* KHR_materials_sheen full
* KHR_materials_clearcoat full
* KHR_materials_transmission full
* KHR_materials_volume full
* KHR_materials_ior full
*/
#ifndef GLTF2ASSET_H_INC
#define GLTF2ASSET_H_INC
@@ -74,6 +76,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rapidjson/document.h>
#include <rapidjson/error/en.h>
#include <rapidjson/rapidjson.h>
#include <rapidjson/schema.h>
#if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0)
# pragma GCC diagnostic pop
@@ -110,6 +113,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// clang-format on
#include <assimp/StringUtils.h>
#include <assimp/material.h>
#include <assimp/GltfMaterial.h>
#include "AssetLib/glTF/glTFCommon.h"
@@ -137,7 +142,6 @@ using glTFCommon::vec4;
//! Magic number for GLB files
#define AI_GLB_MAGIC_NUMBER "glTF"
#include <assimp/pbrmaterial.h>
#ifdef ASSIMP_API
#include <assimp/Compiler/pushpack1.h>
@@ -713,6 +717,7 @@ const vec3 defaultEmissiveFactor = { 0, 0, 0 };
const vec4 defaultDiffuseFactor = { 1, 1, 1, 1 };
const vec3 defaultSpecularFactor = { 1, 1, 1 };
const vec3 defaultSheenFactor = { 0, 0, 0 };
const vec3 defaultAttenuationColor = { 1, 1, 1 };
struct TextureInfo {
Ref<Texture> texture;
@@ -777,6 +782,23 @@ struct MaterialTransmission {
float transmissionFactor = 0.f;
};
struct MaterialVolume {
float thicknessFactor = 0.f;
TextureInfo thicknessTexture;
float attenuationDistance = 0.f;
vec3 attenuationColor;
MaterialVolume() { SetDefaults(); }
void SetDefaults();
};
struct MaterialIOR {
float ior = 0.f;
MaterialIOR() { SetDefaults(); }
void SetDefaults();
};
//! The material appearance of a primitive.
struct Material : public Object {
//PBR metallic roughness properties
@@ -803,6 +825,12 @@ struct Material : public Object {
//extension: KHR_materials_transmission
Nullable<MaterialTransmission> materialTransmission;
//extension: KHR_materials_volume
Nullable<MaterialVolume> materialVolume;
//extension: KHR_materials_ior
Nullable<MaterialIOR> materialIOR;
//extension: KHR_materials_unlit
bool unlit;
@@ -1066,6 +1094,7 @@ class Asset {
private:
IOSystem *mIOSystem;
rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
std::string mCurrentAssetDir;
@@ -1091,6 +1120,8 @@ public:
bool KHR_materials_sheen;
bool KHR_materials_clearcoat;
bool KHR_materials_transmission;
bool KHR_materials_volume;
bool KHR_materials_ior;
bool KHR_draco_mesh_compression;
bool FB_ngon_encoding;
bool KHR_texture_basisu;
@@ -1125,8 +1156,9 @@ public:
Ref<Scene> scene;
public:
Asset(IOSystem *io = nullptr) :
Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) :
mIOSystem(io),
mSchemaDocumentProvider(schemaDocumentProvider),
asset(),
accessors(*this, "accessors"),
animations(*this, "animations"),
@@ -1149,6 +1181,9 @@ public:
//! Main function
void Load(const std::string &file, bool isBinary = false);
//! Parse the AssetMetadata and check that the version is 2.
bool CanRead(const std::string &pFile, bool isBinary = false);
//! Enables binary encoding on the asset
void SetAsBinary();
@@ -1160,6 +1195,11 @@ public:
private:
void ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData);
//! Obtain a JSON document from the stream.
// \param second argument is a buffer used by the document. It must be kept
// alive while the document is in use.
Document ReadDocument(IOStream& stream, bool isBinary, std::vector<char>& sceneData);
void ReadExtensionsUsed(Document &doc);
void ReadExtensionsRequired(Document &doc);
+241 -159
View File
@@ -90,7 +90,6 @@ namespace {
//
// JSON Value reading helpers
//
inline CustomExtension ReadExtensions(const char *name, Value &obj) {
CustomExtension ret;
ret.name = name;
@@ -127,6 +126,81 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) {
return ret;
}
inline void CopyData(size_t count, const uint8_t *src, size_t src_stride,
uint8_t *dst, size_t dst_stride) {
if (src_stride == dst_stride) {
memcpy(dst, src, count * src_stride);
return;
}
size_t sz = std::min(src_stride, dst_stride);
for (size_t i = 0; i < count; ++i) {
memcpy(dst, src, sz);
if (sz < dst_stride) {
memset(dst + sz, 0, dst_stride - sz);
}
src += src_stride;
dst += dst_stride;
}
}
void SetVector(vec4 &v, const float (&in)[4]) {
v[0] = in[0];
v[1] = in[1];
v[2] = in[2];
v[3] = in[3];
}
void SetVector(vec3 &v, const float (&in)[3]) {
v[0] = in[0];
v[1] = in[1];
v[2] = in[2];
}
template <int N>
inline int Compare(const char *attr, const char (&str)[N]) {
return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
}
#if _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4706)
#endif // _MSC_VER
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
if ((pos = Compare(attr, "POSITION"))) {
v = &(p.attributes.position);
} else if ((pos = Compare(attr, "NORMAL"))) {
v = &(p.attributes.normal);
} else if ((pos = Compare(attr, "TANGENT"))) {
v = &(p.attributes.tangent);
} else if ((pos = Compare(attr, "TEXCOORD"))) {
v = &(p.attributes.texcoord);
} else if ((pos = Compare(attr, "COLOR"))) {
v = &(p.attributes.color);
} else if ((pos = Compare(attr, "JOINT"))) {
v = &(p.attributes.joint);
} else if ((pos = Compare(attr, "JOINTMATRIX"))) {
v = &(p.attributes.jointmatrix);
} else if ((pos = Compare(attr, "WEIGHT"))) {
v = &(p.attributes.weight);
} else
return false;
return true;
}
inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, const char *attr, Mesh::AccessorList *&v, int &pos) {
if ((pos = Compare(attr, "POSITION"))) {
v = &(p.targets[targetIndex].position);
} else if ((pos = Compare(attr, "NORMAL"))) {
v = &(p.targets[targetIndex].normal);
} else if ((pos = Compare(attr, "TANGENT"))) {
v = &(p.targets[targetIndex].tangent);
} else
return false;
return true;
}
} // namespace
inline Value *Object::FindString(Value &val, const char *memberId) {
@@ -197,18 +271,18 @@ inline void SetDecodedIndexBuffer_Draco(const draco::Mesh &dracoMesh, Mesh::Prim
// Not same size, convert
switch (componentBytes) {
case sizeof(uint32_t):
CopyFaceIndex_Draco<uint32_t>(*decodedIndexBuffer, dracoMesh);
break;
case sizeof(uint16_t):
CopyFaceIndex_Draco<uint16_t>(*decodedIndexBuffer, dracoMesh);
break;
case sizeof(uint8_t):
CopyFaceIndex_Draco<uint8_t>(*decodedIndexBuffer, dracoMesh);
break;
default:
ai_assert(false);
break;
case sizeof(uint32_t):
CopyFaceIndex_Draco<uint32_t>(*decodedIndexBuffer, dracoMesh);
break;
case sizeof(uint16_t):
CopyFaceIndex_Draco<uint16_t>(*decodedIndexBuffer, dracoMesh);
break;
case sizeof(uint8_t):
CopyFaceIndex_Draco<uint8_t>(*decodedIndexBuffer, dracoMesh);
break;
default:
ai_assert(false);
break;
}
// Assign this alternate data buffer to the accessor
@@ -247,27 +321,27 @@ inline void SetDecodedAttributeBuffer_Draco(const draco::Mesh &dracoMesh, uint32
decodedAttribBuffer->Grow(dracoMesh.num_points() * pDracoAttribute->num_components() * componentBytes);
switch (accessor.componentType) {
case ComponentType_BYTE:
GetAttributeForAllPoints_Draco<int8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_UNSIGNED_BYTE:
GetAttributeForAllPoints_Draco<uint8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_SHORT:
GetAttributeForAllPoints_Draco<int16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_UNSIGNED_SHORT:
GetAttributeForAllPoints_Draco<uint16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_UNSIGNED_INT:
GetAttributeForAllPoints_Draco<uint32_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_FLOAT:
GetAttributeForAllPoints_Draco<float>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
default:
ai_assert(false);
break;
case ComponentType_BYTE:
GetAttributeForAllPoints_Draco<int8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_UNSIGNED_BYTE:
GetAttributeForAllPoints_Draco<uint8_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_SHORT:
GetAttributeForAllPoints_Draco<int16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_UNSIGNED_SHORT:
GetAttributeForAllPoints_Draco<uint16_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_UNSIGNED_INT:
GetAttributeForAllPoints_Draco<uint32_t>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
case ComponentType_FLOAT:
GetAttributeForAllPoints_Draco<float>(dracoMesh, *pDracoAttribute, *decodedAttribBuffer);
break;
default:
ai_assert(false);
break;
}
// Assign this alternate data buffer to the accessor
@@ -299,7 +373,7 @@ inline LazyDict<T>::~LazyDict() {
template <class T>
inline void LazyDict<T>::AttachToDocument(Document &doc) {
Value *container = nullptr;
const char* context = nullptr;
const char *context = nullptr;
if (mExtId) {
if (Value *exts = FindObject(doc, "extensions")) {
@@ -456,7 +530,6 @@ Ref<T> LazyDict<T>::Create(const char *id) {
//
// glTF dictionary objects methods
//
inline Buffer::Buffer() :
byteLength(0),
type(Type_arraybuffer),
@@ -527,6 +600,10 @@ inline void Buffer::Read(Value &obj, Asset &r) {
inline bool Buffer::LoadFromStream(IOStream &stream, size_t length, size_t baseOffset) {
byteLength = length ? length : stream.FileSize();
if (byteLength > stream.FileSize()) {
throw DeadlyImportError("GLTF: Invalid byteLength exceeds size of actual data.");
}
if (baseOffset) {
stream.Seek(baseOffset, aiOrigin_SET);
}
@@ -721,21 +798,26 @@ inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
while (pIndices != indicesEnd) {
size_t offset;
switch (indicesType) {
case ComponentType_UNSIGNED_BYTE:
offset = *pIndices;
break;
case ComponentType_UNSIGNED_SHORT:
offset = *reinterpret_cast<uint16_t *>(pIndices);
break;
case ComponentType_UNSIGNED_INT:
offset = *reinterpret_cast<uint32_t *>(pIndices);
break;
default:
// have fun with float and negative values from signed types as indices.
throw DeadlyImportError("Unsupported component type in index.");
case ComponentType_UNSIGNED_BYTE:
offset = *pIndices;
break;
case ComponentType_UNSIGNED_SHORT:
offset = *reinterpret_cast<uint16_t *>(pIndices);
break;
case ComponentType_UNSIGNED_INT:
offset = *reinterpret_cast<uint32_t *>(pIndices);
break;
default:
// have fun with float and negative values from signed types as indices.
throw DeadlyImportError("Unsupported component type in index.");
}
offset *= elementSize;
if (offset + elementSize > data.size()) {
throw DeadlyImportError("Invalid sparse accessor. Byte offset for patching points outside allocated memory.");
}
std::memcpy(data.data() + offset, pValues, elementSize);
pValues += elementSize;
@@ -751,9 +833,8 @@ inline void Accessor::Read(Value &obj, Asset &r) {
byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
{
const Value* countValue = FindUInt(obj, "count");
if (!countValue)
{
const Value *countValue = FindUInt(obj, "count");
if (!countValue) {
throw DeadlyImportError("A count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
}
count = countValue->GetUint();
@@ -791,6 +872,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
//indices componentType
sparse->indicesType = MemberOrDefault(*indicesValue, "componentType", ComponentType_BYTE);
//sparse->indices->Read(*indicesValue, r);
} else {
// indicesType
sparse->indicesType = MemberOrDefault(*sparseValue, "componentType", ComponentType_UNSIGNED_SHORT);
}
// value
@@ -803,8 +887,6 @@ inline void Accessor::Read(Value &obj, Asset &r) {
//sparse->values->Read(*valuesValue, r);
}
// indicesType
sparse->indicesType = MemberOrDefault(*sparseValue, "componentType", ComponentType_UNSIGNED_SHORT);
const unsigned int elementSize = GetElementSize();
const size_t dataSize = count * elementSize;
@@ -866,27 +948,6 @@ inline size_t Accessor::GetMaxByteSize() {
return (bufferView ? bufferView->byteLength : sparse->data.size());
}
namespace {
inline void CopyData(size_t count,
const uint8_t *src, size_t src_stride,
uint8_t *dst, size_t dst_stride) {
if (src_stride == dst_stride) {
memcpy(dst, src, count * src_stride);
} else {
size_t sz = std::min(src_stride, dst_stride);
for (size_t i = 0; i < count; ++i) {
memcpy(dst, src, sz);
if (sz < dst_stride) {
memset(dst + sz, 0, dst_stride - sz);
}
src += src_stride;
dst += dst_stride;
}
}
}
} // namespace
template <class T>
void Accessor::ExtractData(T *&outData) {
uint8_t *data = GetPointer();
@@ -960,11 +1021,12 @@ inline void Accessor::WriteSparseIndices(size_t _count, const void *src_idx, siz
ai_assert(indices_dst + _count * indices_dst_stride <= indices_buffer_ptr + sparse->indices->buffer->byteLength);
CopyData(_count, indices_src, src_idxStride, indices_dst, indices_dst_stride);
}
inline Accessor::Indexer::Indexer(Accessor &acc) :
accessor(acc),
data(acc.GetPointer()),
elemSize(acc.GetElementSize()),
stride(acc.GetStride()) {
accessor(acc),
data(acc.GetPointer()),
elemSize(acc.GetElementSize()),
stride(acc.GetStride()) {
}
//! Accesses the i-th value as defined by the accessor
@@ -1215,25 +1277,33 @@ inline void Material::Read(Value &material, Asset &r) {
}
}
if (r.extensionsUsed.KHR_materials_volume) {
if (Value *curMaterialVolume = FindObject(*extensions, "KHR_materials_volume")) {
MaterialVolume volume;
ReadMember(*curMaterialVolume, "thicknessFactor", volume.thicknessFactor);
ReadTextureProperty(r, *curMaterialVolume, "thicknessTexture", volume.thicknessTexture);
ReadMember(*curMaterialVolume, "attenuationDistance", volume.attenuationDistance);
ReadMember(*curMaterialVolume, "attenuationColor", volume.attenuationColor);
this->materialVolume = Nullable<MaterialVolume>(volume);
}
}
if (r.extensionsUsed.KHR_materials_ior) {
if (Value *curMaterialIOR = FindObject(*extensions, "KHR_materials_ior")) {
MaterialIOR ior;
ReadMember(*curMaterialIOR, "ior", ior.ior);
this->materialIOR = Nullable<MaterialIOR>(ior);
}
}
unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
}
}
namespace {
void SetVector(vec4 &v, const float (&in)[4]) {
v[0] = in[0];
v[1] = in[1];
v[2] = in[2];
v[3] = in[3];
}
void SetVector(vec3 &v, const float (&in)[3]) {
v[0] = in[0];
v[1] = in[1];
v[2] = in[2];
}
} // namespace
inline void Material::SetDefaults() {
//pbr materials
SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
@@ -1260,53 +1330,18 @@ inline void MaterialSheen::SetDefaults() {
sheenRoughnessFactor = 0.f;
}
namespace {
template <int N>
inline int Compare(const char *attr, const char (&str)[N]) {
return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
inline void MaterialVolume::SetDefaults() {
//KHR_materials_volume properties
thicknessFactor = 0.f;
attenuationDistance = INFINITY;
SetVector(attenuationColor, defaultAttenuationColor);
}
#if _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4706)
#endif // _MSC_VER
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
if ((pos = Compare(attr, "POSITION"))) {
v = &(p.attributes.position);
} else if ((pos = Compare(attr, "NORMAL"))) {
v = &(p.attributes.normal);
} else if ((pos = Compare(attr, "TANGENT"))) {
v = &(p.attributes.tangent);
} else if ((pos = Compare(attr, "TEXCOORD"))) {
v = &(p.attributes.texcoord);
} else if ((pos = Compare(attr, "COLOR"))) {
v = &(p.attributes.color);
} else if ((pos = Compare(attr, "JOINT"))) {
v = &(p.attributes.joint);
} else if ((pos = Compare(attr, "JOINTMATRIX"))) {
v = &(p.attributes.jointmatrix);
} else if ((pos = Compare(attr, "WEIGHT"))) {
v = &(p.attributes.weight);
} else
return false;
return true;
inline void MaterialIOR::SetDefaults() {
//KHR_materials_ior properties
ior = 1.5f;
}
inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, const char *attr, Mesh::AccessorList *&v, int &pos) {
if ((pos = Compare(attr, "POSITION"))) {
v = &(p.targets[targetIndex].position);
} else if ((pos = Compare(attr, "NORMAL"))) {
v = &(p.targets[targetIndex].normal);
} else if ((pos = Compare(attr, "TANGENT"))) {
v = &(p.targets[targetIndex].tangent);
} else
return false;
return true;
}
} // namespace
inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
Value *curName = FindMember(pJSON_Object, "name");
if (nullptr != curName && curName->IsString()) {
@@ -1742,9 +1777,9 @@ inline void Asset::ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneDa
throw DeadlyImportError("GLTF: JSON chunk missing");
}
// read the scene data
mSceneLength = chunk.chunkLength;
// read the scene data, ensure null termination
static_assert(std::numeric_limits<uint32_t>::max() <= std::numeric_limits<size_t>::max(), "size_t must be at least 32bits");
mSceneLength = chunk.chunkLength; // Can't be larger than 4GB (max. uint32_t)
sceneData.resize(mSceneLength + 1);
sceneData[mSceneLength] = '\0';
@@ -1777,40 +1812,36 @@ inline void Asset::ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneDa
}
}
inline void Asset::Load(const std::string &pFile, bool isBinary) {
inline rapidjson::Document Asset::ReadDocument(IOStream &stream, bool isBinary, std::vector<char> &sceneData) {
ASSIMP_LOG_DEBUG("Loading GLTF2 asset");
mCurrentAssetDir.clear();
/*int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
if (pos != int(std::string::npos)) */
if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
mCurrentAssetDir = glTFCommon::getCurrentAssetDir(pFile);
}
shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
if (!stream) {
throw DeadlyImportError("GLTF: Could not open file for reading");
}
// is binary? then read the header
std::vector<char> sceneData;
if (isBinary) {
SetAsBinary(); // also creates the body buffer
ReadBinaryHeader(*stream, sceneData);
ReadBinaryHeader(stream, sceneData);
} else {
mSceneLength = stream->FileSize();
mSceneLength = stream.FileSize();
mBodyLength = 0;
// read the scene data
// Binary format only supports up to 4GB of JSON, use that as a maximum
if (mSceneLength >= std::numeric_limits<uint32_t>::max()) {
throw DeadlyImportError("GLTF: JSON size greater than 4GB");
}
// read the scene data, ensure null termination
sceneData.resize(mSceneLength + 1);
sceneData[mSceneLength] = '\0';
if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
throw DeadlyImportError("GLTF: Could not read the file contents");
}
}
// Smallest legal JSON file is "{}" Smallest loadable glTF file is larger than that but catch it later
if (mSceneLength < 2) {
throw DeadlyImportError("GLTF: No JSON file contents");
}
// parse the JSON document
ASSIMP_LOG_DEBUG("Parsing GLTF2 JSON");
Document doc;
@@ -1826,6 +1857,40 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
}
return doc;
}
inline void Asset::Load(const std::string &pFile, bool isBinary)
{
mCurrentAssetDir.clear();
if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
mCurrentAssetDir = glTFCommon::getCurrentAssetDir(pFile);
}
shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
if (!stream) {
throw DeadlyImportError("GLTF: Could not open file for reading");
}
std::vector<char> sceneData;
rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
// If a schemaDocumentProvider is available, see if the glTF schema is present.
// If so, use it to validate the document.
if (mSchemaDocumentProvider) {
if (const rapidjson::SchemaDocument *gltfSchema = mSchemaDocumentProvider->GetRemoteDocument("glTF.schema.json", 16)) {
// The schemas are found here: https://github.com/KhronosGroup/glTF/tree/main/specification/2.0/schema
rapidjson::SchemaValidator validator(*gltfSchema);
if (!doc.Accept(validator)) {
rapidjson::StringBuffer pathBuffer;
validator.GetInvalidSchemaPointer().StringifyUriFragment(pathBuffer);
rapidjson::StringBuffer argumentBuffer;
validator.GetInvalidDocumentPointer().StringifyUriFragment(argumentBuffer);
throw DeadlyImportError("GLTF: The JSON document did not satisfy the glTF2 schema. Schema keyword: ", validator.GetInvalidSchemaKeyword(), ", document path: ", pathBuffer.GetString(), ", argument: ", argumentBuffer.GetString());
}
}
}
// Fill the buffer instance for the current file embedded contents
if (mBodyLength > 0) {
if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
@@ -1882,6 +1947,21 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
}
}
inline bool Asset::CanRead(const std::string &pFile, bool isBinary) {
try {
shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
if (!stream) {
return false;
}
std::vector<char> sceneData;
rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
asset.Read(doc);
} catch (...) {
return false;
}
return true;
}
inline void Asset::SetAsBinary() {
if (!mBodyBuffer) {
mBodyBuffer = buffers.Create("binary_glTF");
@@ -1931,13 +2011,15 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
CHECK_EXT(KHR_materials_sheen);
CHECK_EXT(KHR_materials_clearcoat);
CHECK_EXT(KHR_materials_transmission);
CHECK_EXT(KHR_materials_volume);
CHECK_EXT(KHR_materials_ior);
CHECK_EXT(KHR_draco_mesh_compression);
CHECK_EXT(KHR_texture_basisu);
#undef CHECK_EXT
}
inline IOStream *Asset::OpenFile(const std::string& path, const char *mode, bool /*absolute*/) {
inline IOStream *Asset::OpenFile(const std::string &path, const char *mode, bool /*absolute*/) {
#ifdef ASSIMP_API
return mIOSystem->Open(path, mode);
#else
@@ -1980,7 +2062,7 @@ inline std::string Asset::FindUniqueID(const std::string &str, const char *suffi
}
#if _MSC_VER
#pragma warning(pop)
# pragma warning(pop)
#endif // _MSC_VER
} // namespace glTF2
+2
View File
@@ -49,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* KHR_materials_sheen: full
* KHR_materials_clearcoat: full
* KHR_materials_transmission: full
* KHR_materials_volume: full
* KHR_materials_ior: full
*/
#ifndef GLTF2ASSETWRITER_H_INC
#define GLTF2ASSETWRITER_H_INC
+44
View File
@@ -474,6 +474,42 @@ namespace glTF2 {
}
}
if (m.materialVolume.isPresent) {
Value materialVolume(rapidjson::Type::kObjectType);
MaterialVolume &volume = m.materialVolume.value;
if (volume.thicknessFactor != 0.f) {
WriteFloat(materialVolume, volume.thicknessFactor, "thicknessFactor", w.mAl);
}
WriteTex(materialVolume, volume.thicknessTexture, "thicknessTexture", w.mAl);
if (volume.attenuationDistance != INFINITY) {
WriteFloat(materialVolume, volume.attenuationDistance, "attenuationDistance", w.mAl);
}
WriteVec(materialVolume, volume.attenuationColor, "attenuationColor", defaultAttenuationColor, w.mAl);
if (!materialVolume.ObjectEmpty()) {
exts.AddMember("KHR_materials_volume", materialVolume, w.mAl);
}
}
if (m.materialIOR.isPresent) {
Value materialIOR(rapidjson::Type::kObjectType);
MaterialIOR &ior = m.materialIOR.value;
if (ior.ior != 1.5f) {
WriteFloat(materialIOR, ior.ior, "ior", w.mAl);
}
if (!materialIOR.ObjectEmpty()) {
exts.AddMember("KHR_materials_ior", materialIOR, w.mAl);
}
}
if (!exts.ObjectEmpty()) {
obj.AddMember("extensions", exts, w.mAl);
}
@@ -890,6 +926,14 @@ namespace glTF2 {
exts.PushBack(StringRef("KHR_materials_transmission"), mAl);
}
if (this->mAsset.extensionsUsed.KHR_materials_volume) {
exts.PushBack(StringRef("KHR_materials_volume"), mAl);
}
if (this->mAsset.extensionsUsed.KHR_materials_ior) {
exts.PushBack(StringRef("KHR_materials_ior"), mAl);
}
if (this->mAsset.extensionsUsed.FB_ngon_encoding) {
exts.PushBack(StringRef("FB_ngon_encoding"), mAl);
}
+75 -25
View File
@@ -174,6 +174,22 @@ static void IdentityMatrix4(mat4 &o) {
o[15] = 1;
}
static bool IsBoneWeightFitted(vec4 &weight) {
return weight[0] + weight[1] + weight[2] + weight[3] >= 1.f;
}
static int FitBoneWeight(vec4 &weight, float value) {
int i = 0;
for (; i < 4; ++i) {
if (weight[i] < value) {
weight[i] = value;
return i;
}
}
return -1;
}
template <typename T>
void SetAccessorRange(Ref<Accessor> acc, void *data, size_t count,
unsigned int numCompsIn, unsigned int numCompsOut) {
@@ -704,6 +720,22 @@ bool glTF2Exporter::GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTra
return result || transmission.transmissionTexture.texture;
}
bool glTF2Exporter::GetMatVolume(const aiMaterial &mat, glTF2::MaterialVolume &volume) {
bool result = mat.Get(AI_MATKEY_VOLUME_THICKNESS_FACTOR, volume.thicknessFactor) != aiReturn_SUCCESS;
GetMatTex(mat, volume.thicknessTexture, AI_MATKEY_VOLUME_THICKNESS_TEXTURE);
result = result || mat.Get(AI_MATKEY_VOLUME_ATTENUATION_DISTANCE, volume.attenuationDistance);
result = result || GetMatColor(mat, volume.attenuationColor, AI_MATKEY_VOLUME_ATTENUATION_COLOR) != aiReturn_SUCCESS;
// Valid if any of these properties are available
return result || volume.thicknessTexture.texture;
}
bool glTF2Exporter::GetMatIOR(const aiMaterial &mat, glTF2::MaterialIOR &ior) {
return mat.Get(AI_MATKEY_REFRACTI, ior.ior) == aiReturn_SUCCESS;
}
void glTF2Exporter::ExportMaterials() {
aiString aiName;
for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
@@ -824,6 +856,18 @@ void glTF2Exporter::ExportMaterials() {
mAsset->extensionsUsed.KHR_materials_transmission = true;
m->materialTransmission = Nullable<MaterialTransmission>(transmission);
}
MaterialVolume volume;
if (GetMatVolume(mat, volume)) {
mAsset->extensionsUsed.KHR_materials_volume = true;
m->materialVolume = Nullable<MaterialVolume>(volume);
}
MaterialIOR ior;
if (GetMatIOR(mat, ior)) {
mAsset->extensionsUsed.KHR_materials_ior = true;
m->materialIOR = Nullable<MaterialIOR>(ior);
}
}
}
}
@@ -922,15 +966,21 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buf
unsigned int vertexId = aib->mWeights[idx_weights].mVertexId;
float vertWeight = aib->mWeights[idx_weights].mWeight;
// A vertex can only have at most four joint weights. Ignore all others.
if (jointsPerVertex[vertexId] > 3) {
// A vertex can only have at most four joint weights, which ideally sum up to 1
if (IsBoneWeightFitted(vertexWeightData[vertexId])) {
continue;
}
if (jointsPerVertex[vertexId] > 3) {
int boneIndexFitted = FitBoneWeight(vertexWeightData[vertexId], vertWeight);
if (boneIndexFitted) {
vertexJointData[vertexId][boneIndexFitted] = static_cast<float>(jointNamesIndex);
}
}else {
vertexJointData[vertexId][jointsPerVertex[vertexId]] = static_cast<float>(jointNamesIndex);
vertexWeightData[vertexId][jointsPerVertex[vertexId]] = vertWeight;
vertexJointData[vertexId][jointsPerVertex[vertexId]] = static_cast<float>(jointNamesIndex);
vertexWeightData[vertexId][jointsPerVertex[vertexId]] = vertWeight;
jointsPerVertex[vertexId] += 1;
jointsPerVertex[vertexId] += 1;
}
}
} // End: for-loop mNumMeshes
@@ -946,7 +996,7 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buf
Ref<Buffer> buf = vertexJointAccessor->bufferView->buffer;
uint8_t *arrys = new uint8_t[bytesLen];
unsigned int i = 0;
for (unsigned int j = 0; j <= bytesLen; j += bytesPerComp) {
for (unsigned int j = 0; j < bytesLen; j += bytesPerComp) {
size_t len_p = offset + j;
float f_value = *(float *)&buf->GetPointer()[len_p];
unsigned short c = static_cast<unsigned short>(f_value);
@@ -1360,22 +1410,22 @@ void glTF2Exporter::ExportMetadata() {
}
}
inline Ref<Accessor> GetSamplerInputRef(Asset &asset, std::string &animId, Ref<Buffer> &buffer, std::vector<float> &times) {
inline Ref<Accessor> GetSamplerInputRef(Asset &asset, std::string &animId, Ref<Buffer> &buffer, std::vector<ai_real> &times) {
return ExportData(asset, animId, buffer, (unsigned int)times.size(), &times[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT);
}
inline void ExtractTranslationSampler(Asset &asset, std::string &animId, Ref<Buffer> &buffer, const aiNodeAnim *nodeChannel, float ticksPerSecond, Animation::Sampler &sampler) {
const unsigned int numKeyframes = nodeChannel->mNumPositionKeys;
std::vector<float> times(numKeyframes);
std::vector<float> values(numKeyframes * 3);
std::vector<ai_real> times(numKeyframes);
std::vector<ai_real> values(numKeyframes * 3);
for (unsigned int i = 0; i < numKeyframes; ++i) {
const aiVectorKey &key = nodeChannel->mPositionKeys[i];
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
values[(i * 3) + 0] = key.mValue.x;
values[(i * 3) + 1] = key.mValue.y;
values[(i * 3) + 2] = key.mValue.z;
values[(i * 3) + 0] = (ai_real) key.mValue.x;
values[(i * 3) + 1] = (ai_real) key.mValue.y;
values[(i * 3) + 2] = (ai_real) key.mValue.z;
}
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
@@ -1386,15 +1436,15 @@ inline void ExtractTranslationSampler(Asset &asset, std::string &animId, Ref<Buf
inline void ExtractScaleSampler(Asset &asset, std::string &animId, Ref<Buffer> &buffer, const aiNodeAnim *nodeChannel, float ticksPerSecond, Animation::Sampler &sampler) {
const unsigned int numKeyframes = nodeChannel->mNumScalingKeys;
std::vector<float> times(numKeyframes);
std::vector<float> values(numKeyframes * 3);
std::vector<ai_real> times(numKeyframes);
std::vector<ai_real> values(numKeyframes * 3);
for (unsigned int i = 0; i < numKeyframes; ++i) {
const aiVectorKey &key = nodeChannel->mScalingKeys[i];
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
values[(i * 3) + 0] = key.mValue.x;
values[(i * 3) + 1] = key.mValue.y;
values[(i * 3) + 2] = key.mValue.z;
values[(i * 3) + 0] = (ai_real) key.mValue.x;
values[(i * 3) + 1] = (ai_real) key.mValue.y;
values[(i * 3) + 2] = (ai_real) key.mValue.z;
}
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
@@ -1405,16 +1455,16 @@ inline void ExtractScaleSampler(Asset &asset, std::string &animId, Ref<Buffer> &
inline void ExtractRotationSampler(Asset &asset, std::string &animId, Ref<Buffer> &buffer, const aiNodeAnim *nodeChannel, float ticksPerSecond, Animation::Sampler &sampler) {
const unsigned int numKeyframes = nodeChannel->mNumRotationKeys;
std::vector<float> times(numKeyframes);
std::vector<float> values(numKeyframes * 4);
std::vector<ai_real> times(numKeyframes);
std::vector<ai_real> values(numKeyframes * 4);
for (unsigned int i = 0; i < numKeyframes; ++i) {
const aiQuatKey &key = nodeChannel->mRotationKeys[i];
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
values[(i * 4) + 0] = key.mValue.x;
values[(i * 4) + 1] = key.mValue.y;
values[(i * 4) + 2] = key.mValue.z;
values[(i * 4) + 3] = key.mValue.w;
values[(i * 4) + 0] = (ai_real) key.mValue.x;
values[(i * 4) + 1] = (ai_real) key.mValue.y;
values[(i * 4) + 2] = (ai_real) key.mValue.z;
values[(i * 4) + 3] = (ai_real) key.mValue.w;
}
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
@@ -1472,7 +1522,7 @@ void glTF2Exporter::ExportAnimations() {
}
}
// Assimp documentation staes this is not used (not implemented)
// Assimp documentation states this is not used (not implemented)
// for (unsigned int channelIndex = 0; channelIndex < anim->mNumMeshChannels; ++channelIndex) {
// const aiMeshAnim* meshChannel = anim->mMeshChannels[channelIndex];
// }
+7
View File
@@ -66,7 +66,9 @@ class Ref;
}
namespace glTF2 {
class Asset;
struct TexProperty;
struct TextureInfo;
struct NormalTextureInfo;
@@ -77,11 +79,14 @@ struct PbrSpecularGlossiness;
struct MaterialSheen;
struct MaterialClearcoat;
struct MaterialTransmission;
struct MaterialVolume;
struct MaterialIOR;
// Vec/matrix types, as raw float arrays
typedef float(vec2)[2];
typedef float(vec3)[3];
typedef float(vec4)[4];
} // namespace glTF2
namespace Assimp {
@@ -114,6 +119,8 @@ protected:
bool GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen);
bool GetMatClearcoat(const aiMaterial &mat, glTF2::MaterialClearcoat &clearcoat);
bool GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTransmission &transmission);
bool GetMatVolume(const aiMaterial &mat, glTF2::MaterialVolume &volume);
bool GetMatIOR(const aiMaterial &mat, glTF2::MaterialIOR &ior);
void ExportMetadata();
void ExportMaterials();
void ExportMeshes();
+31 -12
View File
@@ -111,19 +111,16 @@ const aiImporterDesc *glTF2Importer::GetInfo() const {
return &desc;
}
bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
const std::string &extension = GetExtension(pFile);
bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig ) const {
const std::string &extension = GetExtension(pFile);
if (extension != "gltf" && extension != "glb") {
return false;
}
if (!checkSig && (extension != "gltf") && (extension != "glb"))
return false;
if (pIOHandler) {
glTF2::Asset asset(pIOHandler);
asset.Load(pFile, extension == "glb");
std::string version = asset.asset.version;
return !version.empty() && version[0] == '2';
}
if (pIOHandler) {
glTF2::Asset asset(pIOHandler);
return asset.CanRead(pFile, extension == "glb");
}
return false;
}
@@ -302,6 +299,7 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
// glTFv2 is either PBR or Unlit
aiShadingMode shadingMode = aiShadingMode_PBR_BRDF;
if (mat.unlit) {
aimat->AddProperty(&mat.unlit, 1, "$mat.gltf.unlit", 0, 0); // TODO: Remove this property, it is kept for backwards compatibility with assimp 5.0.1
shadingMode = aiShadingMode_Unlit;
}
@@ -341,6 +339,23 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
SetMaterialTextureProperty(embeddedTexIdxs, r, transmission.transmissionTexture, aimat, AI_MATKEY_TRANSMISSION_TEXTURE);
}
// KHR_materials_volume
if (mat.materialVolume.isPresent) {
MaterialVolume &volume = mat.materialVolume.value;
aimat->AddProperty(&volume.thicknessFactor, 1, AI_MATKEY_VOLUME_THICKNESS_FACTOR);
SetMaterialTextureProperty(embeddedTexIdxs, r, volume.thicknessTexture, aimat, AI_MATKEY_VOLUME_THICKNESS_TEXTURE);
aimat->AddProperty(&volume.attenuationDistance, 1, AI_MATKEY_VOLUME_ATTENUATION_DISTANCE);
SetMaterialColorProperty(r, volume.attenuationColor, aimat, AI_MATKEY_VOLUME_ATTENUATION_COLOR);
}
// KHR_materials_ior
if (mat.materialIOR.isPresent) {
MaterialIOR &ior = mat.materialIOR.value;
aimat->AddProperty(&ior.ior, 1, AI_MATKEY_REFRACTI);
}
return aimat;
} catch (...) {
delete aimat;
@@ -1587,7 +1602,7 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
this->mScene = pScene;
// read the asset file
glTF2::Asset asset(pIOHandler);
glTF2::Asset asset(pIOHandler, static_cast<rapidjson::IRemoteSchemaDocumentProvider*>(mSchemaDocumentProvider));
asset.Load(pFile, GetExtension(pFile) == "glb");
if (asset.scene) {
pScene->mName = asset.scene->name;
@@ -1613,4 +1628,8 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
}
}
void glTF2Importer::SetupProperties(const Importer *pImp) {
mSchemaDocumentProvider = static_cast<rapidjson::IRemoteSchemaDocumentProvider*>(pImp->GetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER));
}
#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
+4
View File
@@ -65,6 +65,7 @@ public:
protected:
const aiImporterDesc *GetInfo() const override;
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
virtual void SetupProperties(const Importer *pImp) override;
private:
void ImportEmbeddedTextures(glTF2::Asset &a);
@@ -80,6 +81,9 @@ private:
std::vector<unsigned int> meshOffsets;
std::vector<int> embeddedTexIdxs;
aiScene *mScene;
/// An instance of rapidjson::IRemoteSchemaDocumentProvider
void *mSchemaDocumentProvider = nullptr;
};
} // namespace Assimp
+45 -17
View File
@@ -79,6 +79,7 @@ SET( PUBLIC_HEADERS
${HEADER_PATH}/matrix4x4.inl
${HEADER_PATH}/mesh.h
${HEADER_PATH}/pbrmaterial.h
${HEADER_PATH}/GltfMaterial.h
${HEADER_PATH}/postprocess.h
${HEADER_PATH}/quaternion.h
${HEADER_PATH}/quaternion.inl
@@ -799,7 +800,23 @@ ADD_ASSIMP_IMPORTER( X
ADD_ASSIMP_IMPORTER( X3D
AssetLib/X3D/X3DImporter.cpp
AssetLib/X3D/X3DImporter_Geometry2D.cpp
AssetLib/X3D/X3DImporter_Geometry3D.cpp
AssetLib/X3D/X3DImporter_Group.cpp
AssetLib/X3D/X3DImporter_Light.cpp
AssetLib/X3D/X3DImporter_Metadata.cpp
AssetLib/X3D/X3DImporter_Networking.cpp
AssetLib/X3D/X3DImporter_Postprocess.cpp
AssetLib/X3D/X3DImporter_Rendering.cpp
AssetLib/X3D/X3DImporter_Shape.cpp
AssetLib/X3D/X3DImporter_Texturing.cpp
AssetLib/X3D/X3DImporter.hpp
AssetLib/X3D/X3DImporter_Macro.hpp
AssetLib/X3D/X3DImporter_Node.hpp
AssetLib/X3D/X3DGeoHelper.cpp
AssetLib/X3D/X3DGeoHelper.h
AssetLib/X3D/X3DXmlHelper.cpp
AssetLib/X3D/X3DXmlHelper.h
)
ADD_ASSIMP_IMPORTER( GLTF
@@ -937,24 +954,27 @@ ELSE()
ENDIF()
# zip (https://github.com/kuba--/zip)
IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(zip)
find_package(zip CONFIG REQUIRED)
ELSE()
SET( ziplib_SRCS
../contrib/zip/src/miniz.h
../contrib/zip/src/zip.c
../contrib/zip/src/zip.h
)
separate_arguments(ASSIMP_EXPORTERS_LIST UNIX_COMMAND ${ASSIMP_EXPORTERS_ENABLED})
IF(3MF IN_LIST ASSIMP_EXPORTERS_LIST)
IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(zip)
find_package(zip CONFIG REQUIRED)
ELSE()
SET( ziplib_SRCS
../contrib/zip/src/miniz.h
../contrib/zip/src/zip.c
../contrib/zip/src/zip.h
)
# TODO if cmake required version has been updated to >3.12.0, collapse this to the second case only
if(${CMAKE_VERSION} VERSION_LESS "3.12.0")
add_definitions(-DMINIZ_USE_UNALIGNED_LOADS_AND_STORES=0)
else()
add_compile_definitions(MINIZ_USE_UNALIGNED_LOADS_AND_STORES=0)
endif()
# TODO if cmake required version has been updated to >3.12.0, collapse this to the second case only
if(${CMAKE_VERSION} VERSION_LESS "3.12.0")
add_definitions(-DMINIZ_USE_UNALIGNED_LOADS_AND_STORES=0)
else()
add_compile_definitions(MINIZ_USE_UNALIGNED_LOADS_AND_STORES=0)
endif()
SOURCE_GROUP( ziplib FILES ${ziplib_SRCS} )
SOURCE_GROUP( ziplib FILES ${ziplib_SRCS} )
ENDIF()
ENDIF()
# openddlparser
@@ -1170,10 +1190,12 @@ IF(ASSIMP_HUNTER_ENABLED)
ZLIB::zlib
RapidJSON::rapidjson
utf8cpp
zip::zip
pugixml
stb::stb
)
if(TARGET zip::zip)
target_link_libraries(assimp PUBLIC zip::zip)
endif()
if (ASSIMP_BUILD_DRACO)
target_link_libraries(assimp PUBLIC ${draco_LIBRARIES})
@@ -1240,6 +1262,12 @@ SET_TARGET_PROPERTIES( assimp PROPERTIES
OUTPUT_NAME assimp${LIBRARY_SUFFIX}
)
if (WIN32 AND CMAKE_COMPILER_IS_GNUCXX AND BUILD_SHARED_LIBS)
set_target_properties(assimp PROPERTIES
SUFFIX "-${ASSIMP_SOVERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}"
)
endif()
if (APPLE)
if (ASSIMP_BUILD_FRAMEWORK)
SET_TARGET_PROPERTIES( assimp PROPERTIES
+3 -2
View File
@@ -300,13 +300,14 @@ private:
const char separator = getOsSeparator();
for (it = in.begin(); it != in.end(); ++it) {
int remaining = std::distance(in.end(), it);
// Exclude :// and \\, which remain untouched.
// https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
if ( !strncmp(&*it, "://", 3 )) {
if (remaining >= 3 && !strncmp(&*it, "://", 3 )) {
it += 3;
continue;
}
if (it == in.begin() && !strncmp(&*it, "\\\\", 2)) {
if (it == in.begin() && remaining >= 2 && !strncmp(&*it, "\\\\", 2)) {
it += 2;
continue;
}
+20
View File
@@ -1072,6 +1072,18 @@ bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
return existing;
}
// ------------------------------------------------------------------------------------------------
// Set a configuration property
bool Importer::SetPropertyPointer(const char* szName, void* value) {
ai_assert(nullptr != pimpl);
bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<void*>(pimpl->mPointerProperties, szName,value);
ASSIMP_END_EXCEPTION_REGION(bool);
return existing;
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
@@ -1104,6 +1116,14 @@ aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& i
return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
void* Importer::GetPropertyPointer(const char* szName, void* iErrorReturn /*= nullptr*/) const {
ai_assert(nullptr != pimpl);
return GetGenericProperty<void*>(pimpl->mPointerProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get the memory requirements of a single node
inline
+6 -2
View File
@@ -73,12 +73,12 @@ public:
// Data type to store the key hash
typedef unsigned int KeyType;
// typedefs for our four configuration maps.
// We don't need more, so there is no need for a generic solution
// typedefs for our configuration maps.
typedef std::map<KeyType, int> IntPropertyMap;
typedef std::map<KeyType, ai_real> FloatPropertyMap;
typedef std::map<KeyType, std::string> StringPropertyMap;
typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
typedef std::map<KeyType, void*> PointerPropertyMap;
/** IO handler to use for all file accesses. */
IOSystem* mIOHandler;
@@ -116,6 +116,9 @@ public:
/** List of Matrix properties */
MatrixPropertyMap mMatrixProperties;
/** List of pointer properties */
PointerPropertyMap mPointerProperties;
/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
* to be executed before and after every single post-process step */
bool bExtraVerbose;
@@ -142,6 +145,7 @@ ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT :
mFloatProperties(),
mStringProperties(),
mMatrixProperties(),
mPointerProperties(),
bExtraVerbose( false ),
mPPShared( nullptr ) {
// empty
+1 -3
View File
@@ -366,9 +366,7 @@ void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
out.push_back(new D3MFImporter());
#endif
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
if (devImportersEnabled) { // https://github.com/assimp/assimp/issues/3647
out.push_back(new X3DImporter());
}
out.push_back(new X3DImporter());
#endif
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
out.push_back(new MMDImporter());
+18 -21
View File
@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -42,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file PolyTools.h, various utilities for our dealings with arbitrary polygons */
#pragma once
#ifndef AI_POLYTOOLS_H_INCLUDED
#define AI_POLYTOOLS_H_INCLUDED
@@ -55,8 +55,7 @@ namespace Assimp {
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline double GetArea2D(const T& v1, const T& v2, const T& v3)
{
inline double GetArea2D(const T& v1, const T& v2, const T& v3) {
return 0.5 * (v1.x * ((double)v3.y - v2.y) + v2.x * ((double)v1.y - v3.y) + v3.x * ((double)v2.y - v1.y));
}
@@ -65,8 +64,7 @@ inline double GetArea2D(const T& v1, const T& v2, const T& v3)
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
{
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) {
return GetArea2D(p0,p2,p1) > 0;
}
@@ -75,20 +73,23 @@ inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
{
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) {
// Point in triangle test using baryzentric coordinates
const aiVector2D v0 = p1 - p0;
const aiVector2D v1 = p2 - p0;
const aiVector2D v2 = pp - p0;
double dot00 = v0 * v0;
double dot01 = v0 * v1;
double dot02 = v0 * v2;
double dot11 = v1 * v1;
double dot12 = v1 * v2;
const double invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
const double dot01 = v0 * v1;
const double dot02 = v0 * v2;
const double dot12 = v1 * v2;
const double denom = dot00 * dot11 - dot01 * dot01;
if (denom == 0.0) {
return false;
}
const double invDenom = 1.0 / denom;
dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom;
dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom;
@@ -133,8 +134,7 @@ inline bool IsCCW(T* in, size_t npoints) {
// in[i+2].x, in[i+2].y)) {
convex_turn = AI_MATH_PI_F - theta;
convex_sum += convex_turn;
}
else {
} else {
convex_sum -= AI_MATH_PI_F - theta;
}
}
@@ -161,15 +161,13 @@ inline bool IsCCW(T* in, size_t npoints) {
if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) {
convex_turn = AI_MATH_PI_F - theta;
convex_sum += convex_turn;
}
else {
} else {
convex_sum -= AI_MATH_PI_F - theta;
}
return convex_sum >= (2 * AI_MATH_PI_F);
}
// -------------------------------------------------------------------------------
/** Compute the normal of an arbitrary polygon in R3.
*
@@ -186,8 +184,7 @@ inline bool IsCCW(T* in, size_t npoints) {
* this method is much faster than the 'other' NewellNormal()
*/
template <int ofs_x, int ofs_y, int ofs_z, typename TReal>
inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z)
{
inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z) {
// Duplicate the first two vertices at the end
x[(num+0)*ofs_x] = x[0];
x[(num+1)*ofs_x] = x[ofs_x];
@@ -224,6 +221,6 @@ inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, T
out = aiVector3t<TReal>(sum_yz,sum_zx,sum_xy);
}
} // ! Assimp
} // ! namespace Assimp
#endif
#endif // AI_POLYTOOLS_H_INCLUDED
+21 -21
View File
@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -40,20 +39,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file RemoveComments.cpp
/**
* @file RemoveComments.cpp
* @brief Defines the CommentRemover utility class
*/
#include <assimp/RemoveComments.h>
#include <assimp/ParsingUtils.h>
namespace Assimp {
namespace Assimp {
// ------------------------------------------------------------------------------------------------
// Remove line comments from a file
void CommentRemover::RemoveLineComments(const char* szComment,
char* szBuffer, char chReplacement /* = ' ' */)
{
void CommentRemover::RemoveLineComments(const char* szComment, char* szBuffer, char chReplacement /* = ' ' */) {
// validate parameters
ai_assert(nullptr != szComment);
ai_assert(nullptr != szBuffer);
@@ -64,29 +62,29 @@ void CommentRemover::RemoveLineComments(const char* szComment,
if (len > lenBuffer) {
len = lenBuffer;
}
while (*szBuffer) {
for(size_t i = 0; i < lenBuffer; i++) {
// skip over quotes
if (*szBuffer == '\"' || *szBuffer == '\'')
while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\'');
if (!strncmp(szBuffer,szComment,len)) {
while (!IsLineEnd(*szBuffer))
*szBuffer++ = chReplacement;
if (szBuffer[i] == '\"' || szBuffer[i] == '\'')
while (++i < lenBuffer && szBuffer[i] != '\"' && szBuffer[i] != '\'');
if (!*szBuffer) {
break;
if(lenBuffer - i < len) {
break;
}
if (!strncmp(szBuffer + i,szComment,len)) {
while (i < lenBuffer && !IsLineEnd(szBuffer[i])) {
szBuffer[i++] = chReplacement;
}
}
++szBuffer;
}
}
// ------------------------------------------------------------------------------------------------
// Remove multi-line comments from a file
void CommentRemover::RemoveMultiLineComments(const char* szCommentStart,
const char* szCommentEnd,char* szBuffer,
char chReplacement)
{
const char* szCommentEnd,char* szBuffer,
char chReplacement) {
// validate parameters
ai_assert(nullptr != szCommentStart);
ai_assert(nullptr != szCommentEnd);
@@ -99,18 +97,20 @@ void CommentRemover::RemoveMultiLineComments(const char* szCommentStart,
while (*szBuffer) {
// skip over quotes
if (*szBuffer == '\"' || *szBuffer == '\'')
if (*szBuffer == '\"' || *szBuffer == '\'') {
while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\'');
}
if (!strncmp(szBuffer,szCommentStart,len2)) {
while (*szBuffer) {
if (!::strncmp(szBuffer,szCommentEnd,len)) {
for (unsigned int i = 0; i < len;++i)
for (unsigned int i = 0; i < len;++i) {
*szBuffer++ = chReplacement;
}
break;
}
*szBuffer++ = chReplacement;
*szBuffer++ = chReplacement;
}
continue;
}
+20
View File
@@ -1101,6 +1101,14 @@ void SceneCombiner::Copy(aiMesh **_dest, const aiMesh *src) {
// make a deep copy of all blend shapes
CopyPtrArray(dest->mAnimMeshes, dest->mAnimMeshes, dest->mNumAnimMeshes);
// make a deep copy of all texture coordinate names
if (src->mTextureCoordsNames != nullptr) {
dest->mTextureCoordsNames = new aiString *[AI_MAX_NUMBER_OF_TEXTURECOORDS] {};
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
Copy(&dest->mTextureCoordsNames[i], src->mTextureCoordsNames[i]);
}
}
}
// ------------------------------------------------------------------------------------------------
@@ -1348,6 +1356,18 @@ void SceneCombiner::Copy(aiMetadata **_dest, const aiMetadata *src) {
}
}
// ------------------------------------------------------------------------------------------------
void SceneCombiner::Copy(aiString **_dest, const aiString *src) {
if (nullptr == _dest || nullptr == src) {
return;
}
aiString *dest = *_dest = new aiString();
// get a flat copy
*dest = *src;
}
#if (__GNUC__ >= 8 && __GNUC_MINOR__ >= 0)
#pragma GCC diagnostic pop
#endif
+28 -10
View File
@@ -58,14 +58,16 @@ const aiVector3D PlaneInit(0.8523f, 0.34321f, 0.5736f);
// define the reference plane. We choose some arbitrary vector away from all basic axes
// in the hope that no model spreads all its vertices along this plane.
SpatialSort::SpatialSort(const aiVector3D *pPositions, unsigned int pNumPositions, unsigned int pElementOffset) :
mPlaneNormal(PlaneInit) {
mPlaneNormal(PlaneInit),
mFinalized(false) {
mPlaneNormal.Normalize();
Fill(pPositions, pNumPositions, pElementOffset);
}
// ------------------------------------------------------------------------------------------------
SpatialSort::SpatialSort() :
mPlaneNormal(PlaneInit) {
mPlaneNormal(PlaneInit),
mFinalized(false) {
mPlaneNormal.Normalize();
}
@@ -80,28 +82,41 @@ void SpatialSort::Fill(const aiVector3D *pPositions, unsigned int pNumPositions,
unsigned int pElementOffset,
bool pFinalize /*= true */) {
mPositions.clear();
mFinalized = false;
Append(pPositions, pNumPositions, pElementOffset, pFinalize);
mFinalized = pFinalize;
}
// ------------------------------------------------------------------------------------------------
ai_real SpatialSort::CalculateDistance(const aiVector3D &pPosition) const {
return (pPosition - mCentroid) * mPlaneNormal;
}
// ------------------------------------------------------------------------------------------------
void SpatialSort::Finalize() {
const ai_real scale = 1.0f / mPositions.size();
for (unsigned int i = 0; i < mPositions.size(); i++) {
mCentroid += scale * mPositions[i].mPosition;
}
for (unsigned int i = 0; i < mPositions.size(); i++) {
mPositions[i].mDistance = CalculateDistance(mPositions[i].mPosition);
}
std::sort(mPositions.begin(), mPositions.end());
mFinalized = true;
}
// ------------------------------------------------------------------------------------------------
void SpatialSort::Append(const aiVector3D *pPositions, unsigned int pNumPositions,
unsigned int pElementOffset,
bool pFinalize /*= true */) {
ai_assert(!mFinalized && "You cannot add positions to the SpatialSort object after it has been finalized.");
// store references to all given positions along with their distance to the reference plane
const size_t initial = mPositions.size();
mPositions.reserve(initial + (pFinalize ? pNumPositions : pNumPositions * 2));
mPositions.reserve(initial + pNumPositions);
for (unsigned int a = 0; a < pNumPositions; a++) {
const char *tempPointer = reinterpret_cast<const char *>(pPositions);
const aiVector3D *vec = reinterpret_cast<const aiVector3D *>(tempPointer + a * pElementOffset);
// store position by index and distance
ai_real distance = *vec * mPlaneNormal;
mPositions.push_back(Entry(static_cast<unsigned int>(a + initial), *vec, distance));
mPositions.push_back(Entry(static_cast<unsigned int>(a + initial), *vec));
}
if (pFinalize) {
@@ -114,7 +129,8 @@ void SpatialSort::Append(const aiVector3D *pPositions, unsigned int pNumPosition
// Returns an iterator for all positions close to the given position.
void SpatialSort::FindPositions(const aiVector3D &pPosition,
ai_real pRadius, std::vector<unsigned int> &poResults) const {
const ai_real dist = pPosition * mPlaneNormal;
ai_assert(mFinalized && "The SpatialSort object must be finalized before FindPositions can be called.");
const ai_real dist = CalculateDistance(pPosition);
const ai_real minDist = dist - pRadius, maxDist = dist + pRadius;
// clear the array
@@ -229,6 +245,7 @@ BinFloat ToBinary(const ai_real &pValue) {
// Fills an array with indices of all positions identical to the given position. In opposite to
// FindPositions(), not an epsilon is used but a (very low) tolerance of four floating-point units.
void SpatialSort::FindIdenticalPositions(const aiVector3D &pPosition, std::vector<unsigned int> &poResults) const {
ai_assert(mFinalized && "The SpatialSort object must be finalized before FindIdenticalPositions can be called.");
// Epsilons have a huge disadvantage: they are of constant precision, while floating-point
// values are of log2 precision. If you apply e=0.01 to 100, the epsilon is rather small, but
// if you apply it to 0.001, it is enormous.
@@ -254,7 +271,7 @@ void SpatialSort::FindIdenticalPositions(const aiVector3D &pPosition, std::vecto
// Convert the plane distance to its signed integer representation so the ULPs tolerance can be
// applied. For some reason, VC won't optimize two calls of the bit pattern conversion.
const BinFloat minDistBinary = ToBinary(pPosition * mPlaneNormal) - distanceToleranceInULPs;
const BinFloat minDistBinary = ToBinary(CalculateDistance(pPosition)) - distanceToleranceInULPs;
const BinFloat maxDistBinary = minDistBinary + 2 * distanceToleranceInULPs;
// clear the array in this strange fashion because a simple clear() would also deallocate
@@ -297,13 +314,14 @@ void SpatialSort::FindIdenticalPositions(const aiVector3D &pPosition, std::vecto
// ------------------------------------------------------------------------------------------------
unsigned int SpatialSort::GenerateMappingTable(std::vector<unsigned int> &fill, ai_real pRadius) const {
ai_assert(mFinalized && "The SpatialSort object must be finalized before GenerateMappingTable can be called.");
fill.resize(mPositions.size(), UINT_MAX);
ai_real dist, maxDist;
unsigned int t = 0;
const ai_real pSquared = pRadius * pRadius;
for (size_t i = 0; i < mPositions.size();) {
dist = mPositions[i].mPosition * mPlaneNormal;
dist = (mPositions[i].mPosition - mCentroid) * mPlaneNormal;
maxDist = dist + pRadius;
fill[mPositions[i].mIndex] = t;
+30 -35
View File
@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -42,25 +40,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <assimp/scene.h>
aiNode::aiNode()
: mName()
, mParent(nullptr)
, mNumChildren(0)
, mChildren(nullptr)
, mNumMeshes(0)
, mMeshes(nullptr)
, mMetaData(nullptr) {
aiNode::aiNode() :
mName(""),
mParent(nullptr),
mNumChildren(0),
mChildren(nullptr),
mNumMeshes(0),
mMeshes(nullptr),
mMetaData(nullptr) {
// empty
}
aiNode::aiNode(const std::string& name)
: mName(name)
, mParent(nullptr)
, mNumChildren(0)
, mChildren(nullptr)
, mNumMeshes(0)
, mMeshes(nullptr)
, mMetaData(nullptr) {
aiNode::aiNode(const std::string &name) :
mName(name),
mParent(nullptr),
mNumChildren(0),
mChildren(nullptr),
mNumMeshes(0),
mMeshes(nullptr),
mMetaData(nullptr) {
// empty
}
@@ -68,8 +66,7 @@ aiNode::aiNode(const std::string& name)
aiNode::~aiNode() {
// delete all children recursively
// to make sure we won't crash if the data is invalid ...
if (mNumChildren && mChildren)
{
if (mNumChildren && mChildren) {
for (unsigned int a = 0; a < mNumChildren; a++)
delete mChildren[a];
}
@@ -78,7 +75,7 @@ aiNode::~aiNode() {
delete mMetaData;
}
const aiNode *aiNode::FindNode(const char* name) const {
const aiNode *aiNode::FindNode(const char *name) const {
if (nullptr == name) {
return nullptr;
}
@@ -86,7 +83,7 @@ const aiNode *aiNode::FindNode(const char* name) const {
return this;
}
for (unsigned int i = 0; i < mNumChildren; ++i) {
const aiNode* const p = mChildren[i]->FindNode(name);
const aiNode *const p = mChildren[i]->FindNode(name);
if (p) {
return p;
}
@@ -95,11 +92,10 @@ const aiNode *aiNode::FindNode(const char* name) const {
return nullptr;
}
aiNode *aiNode::FindNode(const char* name) {
if (!::strcmp(mName.data, name))return this;
for (unsigned int i = 0; i < mNumChildren; ++i)
{
aiNode* const p = mChildren[i]->FindNode(name);
aiNode *aiNode::FindNode(const char *name) {
if (!::strcmp(mName.data, name)) return this;
for (unsigned int i = 0; i < mNumChildren; ++i) {
aiNode *const p = mChildren[i]->FindNode(name);
if (p) {
return p;
}
@@ -121,17 +117,16 @@ void aiNode::addChildren(unsigned int numChildren, aiNode **children) {
}
if (mNumChildren > 0) {
aiNode **tmp = new aiNode*[mNumChildren];
::memcpy(tmp, mChildren, sizeof(aiNode*) * mNumChildren);
aiNode **tmp = new aiNode *[mNumChildren];
::memcpy(tmp, mChildren, sizeof(aiNode *) * mNumChildren);
delete[] mChildren;
mChildren = new aiNode*[mNumChildren + numChildren];
::memcpy(mChildren, tmp, sizeof(aiNode*) * mNumChildren);
::memcpy(&mChildren[mNumChildren], children, sizeof(aiNode*)* numChildren);
mChildren = new aiNode *[mNumChildren + numChildren];
::memcpy(mChildren, tmp, sizeof(aiNode *) * mNumChildren);
::memcpy(&mChildren[mNumChildren], children, sizeof(aiNode *) * numChildren);
mNumChildren += numChildren;
delete[] tmp;
}
else {
mChildren = new aiNode*[numChildren];
} else {
mChildren = new aiNode *[numChildren];
for (unsigned int i = 0; i < numChildren; i++) {
mChildren[i] = children[i];
}
@@ -161,6 +161,7 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh *pcMesh) {
delete[] pcMesh->mBones[i]->mWeights;
if (!newWeights[i].empty()) {
pcMesh->mBones[i]->mWeights = new aiVertexWeight[newWeights[i].size()];
pcMesh->mBones[i]->mNumWeights = static_cast<unsigned int>(newWeights[i].size());
aiVertexWeight *weightToCopy = &(newWeights[i][0]);
memcpy(pcMesh->mBones[i]->mWeights, weightToCopy,
sizeof(aiVertexWeight) * newWeights[i].size());
+7 -6
View File
@@ -133,12 +133,12 @@ inline ::aiQuatKey max(const ::aiQuatKey &a, const ::aiQuatKey &b) {
// std::min for aiVertexWeight
inline ::aiVertexWeight min(const ::aiVertexWeight &a, const ::aiVertexWeight &b) {
return ::aiVertexWeight(min(a.mVertexId, b.mVertexId), min(a.mWeight, b.mWeight));
return ::aiVertexWeight(min(a.mVertexId, b.mVertexId),static_cast<ai_real>(min(a.mWeight, b.mWeight)));
}
// std::max for aiVertexWeight
inline ::aiVertexWeight max(const ::aiVertexWeight &a, const ::aiVertexWeight &b) {
return ::aiVertexWeight(max(a.mVertexId, b.mVertexId), max(a.mWeight, b.mWeight));
return ::aiVertexWeight(max(a.mVertexId, b.mVertexId), static_cast<ai_real>(max(a.mWeight, b.mWeight)));
}
} // end namespace std
@@ -244,7 +244,7 @@ inline void ArrayBounds(const T *in, unsigned int size, T &min, T &max) {
// -------------------------------------------------------------------------------
/** Little helper function to calculate the quadratic difference
* of two colours.
* of two colors.
* @param pColor1 First color
* @param pColor2 second color
* @return Quadratic color difference */
@@ -313,8 +313,8 @@ ai_real ComputePositionEpsilon(const aiMesh *const *pMeshes, size_t num);
unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh);
// defs for ComputeVertexBoneWeightTable()
typedef std::pair<unsigned int, float> PerVertexWeight;
typedef std::vector<PerVertexWeight> VertexWeightTable;
using PerVertexWeight = std::pair<unsigned int, float>;
using VertexWeightTable = std::vector<PerVertexWeight>;
// -------------------------------------------------------------------------------
// Compute a per-vertex bone weight table
@@ -332,7 +332,7 @@ const char *MappingTypeToString(aiTextureMapping in);
aiMesh *MakeSubmesh(const aiMesh *superMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags);
// -------------------------------------------------------------------------------
// Utility postprocess step to share the spatial sort tree between
// Utility post-process step to share the spatial sort tree between
// all steps which use it to speedup its computations.
class ComputeSpatialSortProcess : public BaseProcess {
bool IsActive(unsigned int pFlags) const {
@@ -372,4 +372,5 @@ class DestroySpatialSortProcess : public BaseProcess {
};
} // namespace Assimp
#endif // !! AI_PROCESS_HELPER_H_INCLUDED
@@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/ParsingUtils.h>
#include "ProcessHelper.h"
#include "Material/MaterialSystem.h"
#include <assimp/Exceptional.h>
#include <stdio.h>
using namespace Assimp;
@@ -171,6 +172,8 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
}
// If the new material count differs from the original,
// we need to rebuild the material list and remap mesh material indexes.
if(iNewNum < 1)
throw DeadlyImportError("No materials remaining");
if (iNewNum != pScene->mNumMaterials) {
ai_assert(iNewNum > 0);
aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
-6
View File
@@ -1,6 +0,0 @@
IrrXML
Downloaded September 2008
- fixed a minor compiler warning (vs 2005, shift too large)
- fixed an issue regarding wchar_t/unsigned short
+12 -8
View File
@@ -292,12 +292,15 @@ char *OpenDDLParser::parseHeader(char *in, char *end) {
Property *first(nullptr);
in = lookForNextToken(in, end);
if (*in == Grammar::OpenPropertyToken[0]) {
if (in != end && *in == Grammar::OpenPropertyToken[0]) {
in++;
Property *prop(nullptr), *prev(nullptr);
while (*in != Grammar::ClosePropertyToken[0] && in != end) {
while (in != end && *in != Grammar::ClosePropertyToken[0]) {
in = OpenDDLParser::parseProperty(in, end, &prop);
in = lookForNextToken(in, end);
if(in == end) {
break;
}
if (*in != Grammar::CommaSeparator[0] && *in != Grammar::ClosePropertyToken[0]) {
logInvalidTokenError(in, Grammar::ClosePropertyToken, m_logCallback);
@@ -314,7 +317,9 @@ char *OpenDDLParser::parseHeader(char *in, char *end) {
prev = prop;
}
}
++in;
if(in != end) {
++in;
}
}
// set the properties
@@ -479,7 +484,7 @@ void OpenDDLParser::normalizeBuffer(std::vector<char> &buffer) {
// check for a comment
if (isCommentOpenTag(c, end)) {
++readIdx;
while (!isCommentCloseTag(&buffer[readIdx], end)) {
while (readIdx < len && !isCommentCloseTag(&buffer[readIdx], end)) {
++readIdx;
}
++readIdx;
@@ -489,7 +494,7 @@ void OpenDDLParser::normalizeBuffer(std::vector<char> &buffer) {
if (isComment<char>(c, end)) {
++readIdx;
// skip the comment and the rest of the line
while (!isEndofLine(buffer[readIdx])) {
while (readIdx < len && !isEndofLine(buffer[readIdx])) {
++readIdx;
}
}
@@ -548,8 +553,7 @@ char *OpenDDLParser::parseIdentifier(char *in, char *end, Text **id) {
// get size of id
size_t idLen(0);
char *start(in);
while (!isSeparator(*in) &&
!isNewLine(*in) && (in != end) &&
while ((in != end) && !isSeparator(*in) && !isNewLine(*in) &&
*in != Grammar::OpenPropertyToken[0] &&
*in != Grammar::ClosePropertyToken[0] &&
*in != '$') {
@@ -861,7 +865,7 @@ char *OpenDDLParser::parseProperty(char *in, char *end, Property **prop) {
in = parseIdentifier(in, end, &id);
if (nullptr != id) {
in = lookForNextToken(in, end);
if (*in == '=') {
if (in != end && *in == '=') {
++in;
in = getNextToken(in, end);
Value *primData(nullptr);
@@ -318,7 +318,8 @@ static const unsigned char chartype_table[256] = {
template <class T>
inline bool isNumeric(const T in) {
return (chartype_table[static_cast<size_t>(in)] == 1);
size_t idx = static_cast<size_t>(in);
return idx < sizeof(chartype_table) && (chartype_table[idx] == 1);
}
template <class T>
+74
View File
@@ -0,0 +1,74 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file GltfMaterial.h
* @brief glTF-specific material macros
* These will be made generic at some future date
*/
#ifndef AI_GLTFMATERIAL_H_INC
#define AI_GLTFMATERIAL_H_INC
#ifdef __GNUC__
# pragma GCC system_header
#endif
#include <assimp/material.h>
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0
#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0
#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0
#define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname"
#define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid"
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag"
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin"
#define _AI_MATKEY_GLTF_SCALE_BASE "$tex.scale"
#define _AI_MATKEY_GLTF_STRENGTH_BASE "$tex.strength"
#define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N
#define AI_MATKEY_GLTF_TEXTURE_SCALE(type, N) _AI_MATKEY_GLTF_SCALE_BASE, type, N
#define AI_MATKEY_GLTF_TEXTURE_STRENGTH(type, N) _AI_MATKEY_GLTF_STRENGTH_BASE, type, N
#endif
+10
View File
@@ -261,6 +261,11 @@ AI_FORCE_INLINE bool IOStreamBuffer<T>::getNextDataLine(std::vector<T> &buffer,
buffer[i] = m_cache[m_cachePos];
++m_cachePos;
++i;
if(i == buffer.size()) {
buffer.resize(buffer.size() * 2);
}
if (m_cachePos >= size()) {
break;
}
@@ -308,6 +313,11 @@ AI_FORCE_INLINE bool IOStreamBuffer<T>::getNextLine(std::vector<T> &buffer) {
buffer[i] = m_cache[m_cachePos];
++m_cachePos;
++i;
if(i == buffer.size()) {
buffer.resize(buffer.size() * 2);
}
if (m_cachePos >= m_cacheSize) {
if (!readNextBlock()) {
return false;
+15
View File
@@ -245,6 +245,12 @@ public:
*/
bool SetPropertyMatrix(const char *szName, const aiMatrix4x4 &sValue);
// -------------------------------------------------------------------
/** Set a pointer configuration property.
* @see SetPropertyInteger()
*/
bool SetPropertyPointer(const char *szName, void *sValue);
// -------------------------------------------------------------------
/** Get a configuration property.
* @param szName Name of the property. All supported properties
@@ -297,6 +303,15 @@ public:
aiMatrix4x4 GetPropertyMatrix(const char *szName,
const aiMatrix4x4 &sErrorReturn = aiMatrix4x4()) const;
// -------------------------------------------------------------------
/** Get a pointer configuration property
*
* The return value remains valid until the property is modified.
* @see GetPropertyInteger()
*/
void* GetPropertyPointer(const char *szName,
void *sErrorReturn = nullptr) const;
// -------------------------------------------------------------------
/** Supplies a custom IO handler to the importer to use to open and
* access files. If you need the importer to use custom IO logic to
+1
View File
@@ -361,6 +361,7 @@ public:
static void Copy(aiNodeAnim **dest, const aiNodeAnim *src);
static void Copy(aiMeshMorphAnim **dest, const aiMeshMorphAnim *src);
static void Copy(aiMetadata **dest, const aiMetadata *src);
static void Copy(aiString **dest, const aiString *src);
// recursive, of course
static void Copy(aiNode **dest, const aiNode *src);
+1 -2
View File
@@ -6,7 +6,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -102,7 +101,7 @@ protected:
/** Creates a dummy material and returns it. */
aiMaterial *CreateMaterial();
protected:
private:
/** space to assemble the mesh data: points */
std::vector<aiVector3D> mVertices;
+21 -6
View File
@@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/types.h>
#include <vector>
#include <limits>
namespace Assimp {
@@ -142,24 +143,35 @@ public:
ai_real pRadius) const;
protected:
/** Normal of the sorting plane, normalized. The center is always at (0, 0, 0) */
/** Return the distance to the sorting plane. */
ai_real CalculateDistance(const aiVector3D &pPosition) const;
protected:
/** Normal of the sorting plane, normalized.
*/
aiVector3D mPlaneNormal;
/** The centroid of the positions, which is used as a point on the sorting plane
* when calculating distance. This value is calculated in Finalize.
*/
aiVector3D mCentroid;
/** An entry in a spatially sorted position array. Consists of a vertex index,
* its position and its pre-calculated distance from the reference plane */
struct Entry {
unsigned int mIndex; ///< The vertex referred by this entry
aiVector3D mPosition; ///< Position
ai_real mDistance; ///< Distance of this vertex to the sorting plane
/// Distance of this vertex to the sorting plane. This is set by Finalize.
ai_real mDistance;
Entry() AI_NO_EXCEPT
: mIndex(999999999),
: mIndex(std::numeric_limits<unsigned int>::max()),
mPosition(),
mDistance(99999.) {
mDistance(std::numeric_limits<ai_real>::max()) {
// empty
}
Entry(unsigned int pIndex, const aiVector3D &pPosition, ai_real pDistance) :
mIndex(pIndex), mPosition(pPosition), mDistance(pDistance) {
Entry(unsigned int pIndex, const aiVector3D &pPosition) :
mIndex(pIndex), mPosition(pPosition), mDistance(std::numeric_limits<ai_real>::max()) {
// empty
}
@@ -168,6 +180,9 @@ protected:
// all positions, sorted by distance to the sorting plane
std::vector<Entry> mPositions;
/// false until the Finalize method is called.
bool mFinalized;
};
} // end of namespace Assimp
+3 -1
View File
@@ -135,7 +135,9 @@ public:
/** Extract a particular vertex from a anim mesh and interleave all components */
explicit Vertex(const aiAnimMesh* msh, unsigned int idx) {
ai_assert(idx < msh->mNumVertices);
position = msh->mVertices[idx];
if (msh->HasPositions()) {
position = msh->mVertices[idx];
}
if (msh->HasNormals()) {
normal = msh->mNormals[idx];
+40 -14
View File
@@ -42,8 +42,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef INCLUDED_AI_IRRXML_WRAPPER
#define INCLUDED_AI_IRRXML_WRAPPER
#include <assimp/DefaultLogger.hpp>
#include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp>
#include "BaseImporter.h"
#include "IOStream.hpp"
@@ -112,7 +112,7 @@ public:
/// @brief Will clear the parsed xml-file.
void clear() {
if(mData.empty()) {
if (mData.empty()) {
mDoc = nullptr;
return;
}
@@ -243,7 +243,7 @@ public:
/// @param name [in] The attribute name to look for.
/// @param val [out] The int value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is an int.
static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val ) {
static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
@@ -258,7 +258,7 @@ public:
/// @param name [in] The attribute name to look for.
/// @param val [out] The real value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is a real.
static inline bool getRealAttribute( XmlNode &xmlNode, const char *name, ai_real &val ) {
static inline bool getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
@@ -284,7 +284,6 @@ public:
val = attr.as_float();
return true;
}
/// @brief Will try to get a double attribute value.
@@ -322,7 +321,7 @@ public:
/// @param name [in] The attribute name to look for.
/// @param val [out] The bool value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is a bool.
static inline bool getBoolAttribute( XmlNode &xmlNode, const char *name, bool &val ) {
static inline bool getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
@@ -330,14 +329,13 @@ public:
val = attr.as_bool();
return true;
}
/// @brief Will try to get the value of the node as a string.
/// @param node [in] The node to search in.
/// @param text [out] The value as a text.
/// @return true, if the value can be read out.
static inline bool getValueAsString( XmlNode &node, std::string &text ) {
static inline bool getValueAsString(XmlNode &node, std::string &text) {
text = std::string();
if (node.empty()) {
return false;
@@ -352,7 +350,7 @@ public:
/// @param node [in] The node to search in.
/// @param text [out] The value as a float.
/// @return true, if the value can be read out.
static inline bool getValueAsFloat( XmlNode &node, ai_real &v ) {
static inline bool getValueAsFloat(XmlNode &node, ai_real &v) {
if (node.empty()) {
return false;
}
@@ -360,10 +358,38 @@ public:
v = node.text().as_float();
return true;
}
private:
/// @brief Will try to get the value of the node as an integer.
/// @param node [in] The node to search in.
/// @param text [out] The value as a int.
/// @return true, if the value can be read out.
static inline bool getValueAsInt(XmlNode &node, int &v) {
if (node.empty()) {
return false;
}
v = node.text().as_int();
return true;
}
/// @brief Will try to get the value of the node as an bool.
/// @param node [in] The node to search in.
/// @param text [out] The value as a bool.
/// @return true, if the value can be read out.
static inline bool getValueAsBool(XmlNode& node, bool& v)
{
if (node.empty()) {
return false;
}
v = node.text().as_bool();
return true;
}
private:
pugi::xml_document *mDoc;
TNodeType mCurrent;
std::vector<char> mData;
@@ -376,8 +402,8 @@ class XmlNodeIterator {
public:
/// @brief The iteration mode.
enum IterationMode {
PreOrderMode, ///< Pre-ordering, get the values, continue the iteration.
PostOrderMode ///< Post-ordering, continue the iteration, get the values.
PreOrderMode, ///< Pre-ordering, get the values, continue the iteration.
PostOrderMode ///< Post-ordering, continue the iteration, get the values.
};
/// @brief The class constructor
/// @param parent [in] The xml parent to to iterate through.
@@ -400,7 +426,7 @@ public:
/// @brief Will iterate through all children in pre-order iteration.
/// @param node [in] The nod to iterate through.
void collectChildrenPreOrder( XmlNode &node ) {
void collectChildrenPreOrder(XmlNode &node) {
if (node != mParent && node.type() == pugi::node_element) {
mNodes.push_back(node);
}
+3
View File
@@ -98,6 +98,7 @@ struct aiVectorKey {
bool operator<(const aiVectorKey &rhs) const {
return mTime < rhs.mTime;
}
bool operator>(const aiVectorKey &rhs) const {
return mTime > rhs.mTime;
}
@@ -131,6 +132,7 @@ struct aiQuatKey {
bool operator==(const aiQuatKey &rhs) const {
return rhs.mValue == this->mValue;
}
bool operator!=(const aiQuatKey &rhs) const {
return rhs.mValue != this->mValue;
}
@@ -139,6 +141,7 @@ struct aiQuatKey {
bool operator<(const aiQuatKey &rhs) const {
return mTime < rhs.mTime;
}
bool operator>(const aiQuatKey &rhs) const {
return mTime > rhs.mTime;
}
-2
View File
@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
+9
View File
@@ -547,6 +547,15 @@ enum aiComponent
// Various stuff to fine-tune the behaviour of specific importer plugins.
// ###########################################################################
// ---------------------------------------------------------------------------
/** @brief Importers which parse JSON may use this to obtain a pointer to a
* rapidjson::IRemoteSchemaDocumentProvider.
*
* The default value is nullptr
* Property type: void*
*/
#define AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER \
"IMPORT_SCHEMA_DOCUMENT_PROVIDER"
// ---------------------------------------------------------------------------
/** @brief Set whether the fbx importer will merge all geometry layers present
-1
View File
@@ -255,5 +255,4 @@ struct aiLight {
}
#endif
#endif // !! AI_LIGHT_H_INC
+13
View File
@@ -1028,6 +1028,19 @@ extern "C" {
// Multiplied by AI_MATKEY_TRANSMISSION_FACTOR
#define AI_MATKEY_TRANSMISSION_TEXTURE aiTextureType_TRANSMISSION, 0
// Volume
// ------------
// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_volume
// The thickness of the volume beneath the surface. If the value is 0 the material is thin-walled. Otherwise the material is a volume boundary.
#define AI_MATKEY_VOLUME_THICKNESS_FACTOR "$mat.volume.thicknessFactor", 0, 0
// Texture that defines the thickness.
// Multiplied by AI_MATKEY_THICKNESS_FACTOR
#define AI_MATKEY_VOLUME_THICKNESS_TEXTURE aiTextureType_TRANSMISSION, 1
// Density of the medium given as the average distance that light travels in the medium before interacting with a particle.
#define AI_MATKEY_VOLUME_ATTENUATION_DISTANCE "$mat.volume.attenuationDistance", 0, 0
// The color that white light turns into due to absorption when reaching the attenuation distance.
#define AI_MATKEY_VOLUME_ATTENUATION_COLOR "$mat.volume.attenuationColor", 0, 0
// Emissive
// --------
#define AI_MATKEY_USE_EMISSIVE_MAP "$mat.useEmissiveMap", 0, 0
+29 -61
View File
@@ -44,21 +44,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef AI_MATERIAL_INL_INC
#define AI_MATERIAL_INL_INC
#ifdef __GNUC__
# pragma GCC system_header
#endif
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiPropertyTypeInfo ai_real_to_property_type_info(float) {
AI_FORCE_INLINE aiPropertyTypeInfo ai_real_to_property_type_info(float) {
return aiPTI_Float;
}
AI_FORCE_INLINE
aiPropertyTypeInfo ai_real_to_property_type_info(double) {
AI_FORCE_INLINE aiPropertyTypeInfo ai_real_to_property_type_info(double) {
return aiPTI_Double;
}
// ---------------------------------------------------------------------------
@@ -66,8 +62,7 @@ aiPropertyTypeInfo ai_real_to_property_type_info(double) {
//! @cond never
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::GetTexture( aiTextureType type,
AI_FORCE_INLINE aiReturn aiMaterial::GetTexture( aiTextureType type,
unsigned int index,
C_STRUCT aiString* path,
aiTextureMapping* mapping /*= NULL*/,
@@ -79,15 +74,13 @@ aiReturn aiMaterial::GetTexture( aiTextureType type,
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
unsigned int aiMaterial::GetTextureCount(aiTextureType type) const {
AI_FORCE_INLINE unsigned int aiMaterial::GetTextureCount(aiTextureType type) const {
return ::aiGetMaterialTextureCount(this,type);
}
// ---------------------------------------------------------------------------
template <typename Type>
AI_FORCE_INLINE
aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
unsigned int idx, Type* pOut,
unsigned int* pMax) const {
unsigned int iNum = pMax ? *pMax : 1;
@@ -105,7 +98,7 @@ aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
return AI_FAILURE;
}
iNum = std::min((size_t)iNum,prop->mDataLength / sizeof(Type));
iNum = static_cast<unsigned int>(std::min(static_cast<size_t>(iNum),prop->mDataLength / sizeof(Type)));
::memcpy(pOut,prop->mData,iNum * sizeof(Type));
if (pMax) {
*pMax = iNum;
@@ -116,8 +109,7 @@ aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
// ---------------------------------------------------------------------------
template <typename Type>
AI_FORCE_INLINE
aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
unsigned int idx,Type& pOut) const {
const aiMaterialProperty* prop;
const aiReturn ret = ::aiGetMaterialProperty(this,pKey,type,idx,
@@ -138,34 +130,29 @@ aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
unsigned int idx,ai_real* pOut,
unsigned int* pMax) const {
return ::aiGetMaterialFloatArray(this,pKey,type,idx,pOut,pMax);
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
unsigned int idx,int* pOut,
unsigned int* pMax) const {
return ::aiGetMaterialIntegerArray(this,pKey,type,idx,pOut,pMax);
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
unsigned int idx,ai_real& pOut) const {
return aiGetMaterialFloat(this,pKey,type,idx,&pOut);
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
unsigned int idx,int& pOut) const {
return aiGetMaterialInteger(this,pKey,type,idx,&pOut);
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
unsigned int idx,aiColor4D& pOut) const {
return aiGetMaterialColor(this,pKey,type,idx,&pOut);
}
@@ -190,14 +177,10 @@ AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
// ---------------------------------------------------------------------------
template<class TYPE>
aiReturn aiMaterial::AddProperty (const TYPE* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
unsigned int index)
{
return AddBinaryProperty((const void*)pInput,
pNumValues * sizeof(TYPE),
aiReturn aiMaterial::AddProperty (const TYPE* pInput,
const unsigned int pNumValues, const char* pKey, unsigned int type,
unsigned int index) {
return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(TYPE),
pKey,type,index,aiPTI_Buffer);
}
@@ -213,8 +196,7 @@ AI_FORCE_INLINE aiReturn aiMaterial::AddProperty(const float* pInput,
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty(const double* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty(const double* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -225,8 +207,7 @@ aiReturn aiMaterial::AddProperty(const double* pInput,
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -237,8 +218,7 @@ aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput,
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty(const aiColor4D* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty(const aiColor4D* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -249,8 +229,7 @@ aiReturn aiMaterial::AddProperty(const aiColor4D* pInput,
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty(const aiColor3D* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty(const aiColor3D* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -261,8 +240,7 @@ aiReturn aiMaterial::AddProperty(const aiColor3D* pInput,
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty(const aiVector3D* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty(const aiVector3D* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -273,8 +251,7 @@ aiReturn aiMaterial::AddProperty(const aiVector3D* pInput,
}
// ---------------------------------------------------------------------------
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty(const int* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty(const int* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -293,8 +270,7 @@ aiReturn aiMaterial::AddProperty(const int* pInput,
// ---------------------------------------------------------------------------
template<>
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty<float>(const float* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty<float>(const float* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -306,8 +282,7 @@ aiReturn aiMaterial::AddProperty<float>(const float* pInput,
// ---------------------------------------------------------------------------
template<>
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty<double>(const double* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty<double>(const double* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -319,8 +294,7 @@ aiReturn aiMaterial::AddProperty<double>(const double* pInput,
// ---------------------------------------------------------------------------
template<>
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty<aiUVTransform>(const aiUVTransform* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty<aiUVTransform>(const aiUVTransform* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -332,8 +306,7 @@ aiReturn aiMaterial::AddProperty<aiUVTransform>(const aiUVTransform* pInput,
// ---------------------------------------------------------------------------
template<>
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty<aiColor4D>(const aiColor4D* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty<aiColor4D>(const aiColor4D* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -345,8 +318,7 @@ aiReturn aiMaterial::AddProperty<aiColor4D>(const aiColor4D* pInput,
// ---------------------------------------------------------------------------
template<>
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty<aiColor3D>(const aiColor3D* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty<aiColor3D>(const aiColor3D* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -358,8 +330,7 @@ aiReturn aiMaterial::AddProperty<aiColor3D>(const aiColor3D* pInput,
// ---------------------------------------------------------------------------
template<>
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty<aiVector3D>(const aiVector3D* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty<aiVector3D>(const aiVector3D* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -371,8 +342,7 @@ aiReturn aiMaterial::AddProperty<aiVector3D>(const aiVector3D* pInput,
// ---------------------------------------------------------------------------
template<>
AI_FORCE_INLINE
aiReturn aiMaterial::AddProperty<int>(const int* pInput,
AI_FORCE_INLINE aiReturn aiMaterial::AddProperty<int>(const int* pInput,
const unsigned int pNumValues,
const char* pKey,
unsigned int type,
@@ -383,5 +353,3 @@ aiReturn aiMaterial::AddProperty<int>(const int* pInput,
}
//! @endcond
#endif //! AI_MATERIAL_INL_INC
+68 -5
View File
@@ -300,6 +300,10 @@ struct aiBone {
aiBone() AI_NO_EXCEPT
: mName(),
mNumWeights(0),
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
mArmature(nullptr),
mNode(nullptr),
#endif
mWeights(nullptr),
mOffsetMatrix() {
// empty
@@ -309,6 +313,10 @@ struct aiBone {
aiBone(const aiBone &other) :
mName(other.mName),
mNumWeights(other.mNumWeights),
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
mArmature(nullptr),
mNode(nullptr),
#endif
mWeights(nullptr),
mOffsetMatrix(other.mOffsetMatrix) {
if (other.mWeights && other.mNumWeights) {
@@ -673,10 +681,6 @@ struct aiMesh {
*/
C_STRUCT aiVector3D *mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
/** Vertex stream names.
*/
C_STRUCT aiString mTextureCoordsNames[AI_MAX_NUMBER_OF_TEXTURECOORDS];
/** Specifies the number of components for a given UV channel.
* Up to three channels are supported (UVW, for accessing volume
* or cube maps). If the value is 2 for a given channel n, the
@@ -744,6 +748,10 @@ struct aiMesh {
*/
C_STRUCT aiAABB mAABB;
/** Vertex UV stream names. Pointer to array of size AI_MAX_NUMBER_OF_TEXTURECOORDS
*/
C_STRUCT aiString **mTextureCoordsNames;
#ifdef __cplusplus
//! Default constructor. Initializes all members to 0
@@ -765,7 +773,8 @@ struct aiMesh {
mNumAnimMeshes(0),
mAnimMeshes(nullptr),
mMethod(0),
mAABB() {
mAABB(),
mTextureCoordsNames(nullptr) {
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
mNumUVComponents[a] = 0;
mTextureCoords[a] = nullptr;
@@ -785,6 +794,14 @@ struct aiMesh {
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) {
delete[] mTextureCoords[a];
}
if (mTextureCoordsNames) {
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) {
delete mTextureCoordsNames[a];
}
delete[] mTextureCoordsNames;
}
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) {
delete[] mColors[a];
}
@@ -870,6 +887,52 @@ struct aiMesh {
return mBones != nullptr && mNumBones > 0;
}
//! Check whether the mesh contains a texture coordinate set name
//! \param pIndex Index of the texture coordinates set
bool HasTextureCoordsName(unsigned int pIndex) const {
if (mTextureCoordsNames == nullptr || pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
return false;
}
return mTextureCoordsNames[pIndex] != nullptr;
}
//! Set a texture coordinate set name
//! \param pIndex Index of the texture coordinates set
//! \param texCoordsName name of the texture coordinate set
void SetTextureCoordsName(unsigned int pIndex, const aiString &texCoordsName) {
if (pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
return;
}
if (mTextureCoordsNames == nullptr) {
// Construct and null-init array
mTextureCoordsNames = new aiString *[AI_MAX_NUMBER_OF_TEXTURECOORDS] {};
}
if (texCoordsName.length == 0) {
delete mTextureCoordsNames[pIndex];
mTextureCoordsNames[pIndex] = nullptr;
return;
}
if (mTextureCoordsNames[pIndex] == nullptr) {
mTextureCoordsNames[pIndex] = new aiString(texCoordsName);
return;
}
*mTextureCoordsNames[pIndex] = texCoordsName;
}
//! Get a texture coordinate set name
//! \param pIndex Index of the texture coordinates set
const aiString *GetTextureCoordsName(unsigned int pIndex) const {
if (mTextureCoordsNames == nullptr || pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
return nullptr;
}
return mTextureCoordsNames[pIndex];
}
#endif // __cplusplus
};
+33 -38
View File
@@ -40,7 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @file pbrmaterial.h
* @brief Defines the material system of the library
* @brief Deprecated GLTF_PBR macros
*/
#pragma once
#ifndef AI_PBRMATERIAL_H_INC
@@ -48,47 +48,42 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef __GNUC__
# pragma GCC system_header
# warning pbrmaterial.h is deprecated. Please update to PBR materials in materials.h and glTF-specific items in GltfMaterial.h
#else if defined(_MSC_VER)
# pragma message("pbrmaterial.h is deprecated. Please update to PBR materials in materials.h and glTF-specific items in GltfMaterial.h")
#endif
//#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0
//#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0
//#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0
//#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE aiTextureType_DIFFUSE, 1
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0
#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0
#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0
#include <assimp/material.h>
#include <assimp/GltfMaterial.h>
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR AI_MATKEY_BASE_COLOR
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE AI_MATKEY_BASE_COLOR_TEXTURE
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR AI_MATKEY_METALLIC_FACTOR
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR AI_MATKEY_ROUGHNESS_FACTOR
//#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0
//#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0
//#define AI_MATKEY_GLTF_UNLIT "$mat.gltf.unlit", 0, 0
//#define AI_MATKEY_GLTF_MATERIAL_SHEEN "$mat.gltf.materialSheen", 0, 0
//#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR "$mat.gltf.materialSheen.sheenColorFactor", 0, 0
//#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR "$mat.gltf.materialSheen.sheenRoughnessFactor", 0, 0
//#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE aiTextureType_UNKNOWN, 1
//#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 2
//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT "$mat.gltf.materialClearcoat", 0, 0
//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR "$mat.gltf.materialClearcoat.clearcoatFactor", 0, 0
//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR "$mat.gltf.materialClearcoat.clearcoatRoughnessFactor", 0, 0
//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE aiTextureType_UNKNOWN, 3
//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 4
//#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE aiTextureType_NORMALS, 1
//#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION "$mat.gltf.materialTransmission", 0, 0
//#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR "$mat.gltf.materialTransmission.transmissionFactor", 0, 0
//#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE aiTextureType_UNKNOWN, 5
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR AI_MATKEY_GLOSSINESS_FACTOR
//#define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord"
#define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname"
#define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid"
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag"
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin"
#define _AI_MATKEY_GLTF_SCALE_BASE "$tex.scale"
#define _AI_MATKEY_GLTF_STRENGTH_BASE "$tex.strength"
// Use AI_MATKEY_SHADING_MODEL == aiShadingMode_Unlit instead
#define AI_MATKEY_GLTF_UNLIT "$mat.gltf.unlit", 0, 0
//#define AI_MATKEY_GLTF_TEXTURE_TEXCOORD(type, N) _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N
#define AI_MATKEY_GLTF_TEXTURE_SCALE(type, N) _AI_MATKEY_GLTF_SCALE_BASE, type, N
#define AI_MATKEY_GLTF_TEXTURE_STRENGTH(type, N) _AI_MATKEY_GLTF_STRENGTH_BASE, type, N
//AI_MATKEY_GLTF_MATERIAL_SHEEN
#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR AI_MATKEY_SHEEN_COLOR_FACTOR
#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR AI_MATKEY_SHEEN_ROUGHNESS_FACTOR
#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE AI_MATKEY_SHEEN_COLOR_TEXTURE
#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE AI_MATKEY_SHEEN_ROUGHNESS_TEXTURE
//AI_MATKEY_GLTF_MATERIAL_CLEARCOAT
#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR AI_MATKEY_CLEARCOAT_FACTOR
#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR
#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE AI_MATKEY_CLEARCOAT_TEXTURE
#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE
#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE AI_MATKEY_CLEARCOAT_NORMAL_TEXTURE
//AI_MATKEY_GLTF_MATERIAL_TRANSMISSION
#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR AI_MATKEY_TRANSMISSION_FACTOR
#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE AI_MATKEY_TRANSMISSION_TEXTURE
#define AI_MATKEY_GLTF_TEXTURE_TEXCOORD(type, N) AI_MATKEY_UVWSRC(type, N)
#endif //!!AI_PBRMATERIAL_H_INC
@@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -54,36 +54,32 @@ namespace Assimp {
// ---------------------------------------------------------------------------
/** Android extension to DefaultIOSystem using the standard C file functions */
class ASSIMP_API AndroidJNIIOSystem : public DefaultIOSystem
{
class ASSIMP_API AndroidJNIIOSystem : public DefaultIOSystem {
public:
/** Initialize android activity data */
std::string mApkWorkspacePath;
AAssetManager* mApkAssetManager;
/** Constructor. */
/// Constructor.
AndroidJNIIOSystem(ANativeActivity* activity);
/** Destructor. */
/// Class constructor with past and asset manager.
AndroidJNIIOSystem(const char *internalPath, AAssetManager* assetManager);
/// Destructor.
~AndroidJNIIOSystem();
// -------------------------------------------------------------------
/** Tests for the existence of a file at the given path. */
/// Tests for the existence of a file at the given path.
bool Exists( const char* pFile) const;
// -------------------------------------------------------------------
/** Opens a file at the given path, with given mode */
/// Opens a file at the given path, with given mode
IOStream* Open( const char* strFile, const char* strMode);
// ------------------------------------------------------------------------------------------------
// Inits Android extractor
/// Inits Android extractor
void AndroidActivityInit(ANativeActivity* activity);
// ------------------------------------------------------------------------------------------------
// Extracts android asset
/// Extracts android asset
bool AndroidExtractAsset(std::string name);
};
} //!ns Assimp
+8 -11
View File
@@ -92,22 +92,19 @@ struct aiTexel {
#ifdef __cplusplus
//! Comparison operator
bool operator== (const aiTexel& other) const
{
bool operator== (const aiTexel& other) const {
return b == other.b && r == other.r &&
g == other.g && a == other.a;
}
//! Inverse comparison operator
bool operator!= (const aiTexel& other) const
{
bool operator!= (const aiTexel& other) const {
return b != other.b || r != other.r ||
g != other.g || a != other.a;
}
//! Conversion to a floating-point 4d color
operator aiColor4D() const
{
operator aiColor4D() const {
return aiColor4D(r/255.f,g/255.f,b/255.f,a/255.f);
}
#endif // __cplusplus
@@ -202,11 +199,11 @@ struct aiTexture {
}
// Construction
aiTexture() AI_NO_EXCEPT
: mWidth(0)
, mHeight(0)
, pcData(nullptr)
, mFilename() {
aiTexture() AI_NO_EXCEPT :
mWidth(0),
mHeight(0),
pcData(nullptr),
mFilename() {
memset(achFormatHint, 0, sizeof(achFormatHint));
}
-2
View File
@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
+33 -59
View File
@@ -54,8 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ------------------------------------------------------------------------------------------------
/** Transformation of a vector by a 3x3 matrix */
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator * (const aiMatrix3x3t<TReal>& pMatrix, const aiVector3t<TReal>& pVector) {
AI_FORCE_INLINE aiVector3t<TReal> operator * (const aiMatrix3x3t<TReal>& pMatrix, const aiVector3t<TReal>& pVector) {
aiVector3t<TReal> res;
res.x = pMatrix.a1 * pVector.x + pMatrix.a2 * pVector.y + pMatrix.a3 * pVector.z;
res.y = pMatrix.b1 * pVector.x + pMatrix.b2 * pVector.y + pMatrix.b3 * pVector.z;
@@ -66,8 +65,7 @@ aiVector3t<TReal> operator * (const aiMatrix3x3t<TReal>& pMatrix, const aiVector
// ------------------------------------------------------------------------------------------------
/** Transformation of a vector by a 4x4 matrix */
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator * (const aiMatrix4x4t<TReal>& pMatrix, const aiVector3t<TReal>& pVector) {
AI_FORCE_INLINE aiVector3t<TReal> operator * (const aiMatrix4x4t<TReal>& pMatrix, const aiVector3t<TReal>& pVector) {
aiVector3t<TReal> res;
res.x = pMatrix.a1 * pVector.x + pMatrix.a2 * pVector.y + pMatrix.a3 * pVector.z + pMatrix.a4;
res.y = pMatrix.b1 * pVector.x + pMatrix.b2 * pVector.y + pMatrix.b3 * pVector.z + pMatrix.b4;
@@ -82,36 +80,35 @@ aiVector3t<TReal>::operator aiVector3t<TOther> () const {
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
void aiVector3t<TReal>::Set( TReal pX, TReal pY, TReal pZ) {
AI_FORCE_INLINE void aiVector3t<TReal>::Set( TReal pX, TReal pY, TReal pZ) {
x = pX;
y = pY;
z = pZ;
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
TReal aiVector3t<TReal>::SquareLength() const {
AI_FORCE_INLINE TReal aiVector3t<TReal>::SquareLength() const {
return x*x + y*y + z*z;
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
TReal aiVector3t<TReal>::Length() const {
AI_FORCE_INLINE TReal aiVector3t<TReal>::Length() const {
return std::sqrt( SquareLength());
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal>& aiVector3t<TReal>::Normalize() {
aiVector3t<TReal>& aiVector3t<TReal>::Normalize() {
const TReal l = Length();
if (l == 0) {
return *this;
}
*this /= Length();
return *this;
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal>& aiVector3t<TReal>::NormalizeSafe() {
AI_FORCE_INLINE aiVector3t<TReal>& aiVector3t<TReal>::NormalizeSafe() {
TReal len = Length();
if ( len > static_cast< TReal >( 0 ) ) {
*this /= len;
@@ -120,8 +117,7 @@ aiVector3t<TReal>& aiVector3t<TReal>::NormalizeSafe() {
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
const aiVector3t<TReal>& aiVector3t<TReal>::operator += (const aiVector3t<TReal>& o) {
AI_FORCE_INLINE const aiVector3t<TReal>& aiVector3t<TReal>::operator += (const aiVector3t<TReal>& o) {
x += o.x;
y += o.y;
z += o.z;
@@ -130,8 +126,7 @@ const aiVector3t<TReal>& aiVector3t<TReal>::operator += (const aiVector3t<TReal>
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
const aiVector3t<TReal>& aiVector3t<TReal>::operator -= (const aiVector3t<TReal>& o) {
AI_FORCE_INLINE const aiVector3t<TReal>& aiVector3t<TReal>::operator -= (const aiVector3t<TReal>& o) {
x -= o.x;
y -= o.y;
z -= o.z;
@@ -140,8 +135,7 @@ const aiVector3t<TReal>& aiVector3t<TReal>::operator -= (const aiVector3t<TReal>
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
const aiVector3t<TReal>& aiVector3t<TReal>::operator *= (TReal f) {
AI_FORCE_INLINE const aiVector3t<TReal>& aiVector3t<TReal>::operator *= (TReal f) {
x *= f;
y *= f;
z *= f;
@@ -150,8 +144,7 @@ const aiVector3t<TReal>& aiVector3t<TReal>::operator *= (TReal f) {
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
const aiVector3t<TReal>& aiVector3t<TReal>::operator /= (TReal f) {
AI_FORCE_INLINE const aiVector3t<TReal>& aiVector3t<TReal>::operator /= (TReal f) {
if ( f == static_cast<TReal>(0.0)) {
return *this;
}
@@ -164,20 +157,17 @@ const aiVector3t<TReal>& aiVector3t<TReal>::operator /= (TReal f) {
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal>& aiVector3t<TReal>::operator *= (const aiMatrix3x3t<TReal>& mat){
AI_FORCE_INLINE aiVector3t<TReal>& aiVector3t<TReal>::operator *= (const aiMatrix3x3t<TReal>& mat){
return (*this = mat * (*this));
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal>& aiVector3t<TReal>::operator *= (const aiMatrix4x4t<TReal>& mat){
AI_FORCE_INLINE aiVector3t<TReal>& aiVector3t<TReal>::operator *= (const aiMatrix4x4t<TReal>& mat){
return (*this = mat * (*this));
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
TReal aiVector3t<TReal>::operator[](unsigned int i) const {
AI_FORCE_INLINE TReal aiVector3t<TReal>::operator[](unsigned int i) const {
switch (i) {
case 0:
return x;
@@ -192,9 +182,7 @@ TReal aiVector3t<TReal>::operator[](unsigned int i) const {
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
TReal& aiVector3t<TReal>::operator[](unsigned int i) {
// return *(&x + i);
AI_FORCE_INLINE TReal& aiVector3t<TReal>::operator[](unsigned int i) {
switch (i) {
case 0:
return x;
@@ -209,20 +197,17 @@ TReal& aiVector3t<TReal>::operator[](unsigned int i) {
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
bool aiVector3t<TReal>::operator== (const aiVector3t<TReal>& other) const {
AI_FORCE_INLINE bool aiVector3t<TReal>::operator== (const aiVector3t<TReal>& other) const {
return x == other.x && y == other.y && z == other.z;
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
bool aiVector3t<TReal>::operator!= (const aiVector3t<TReal>& other) const {
AI_FORCE_INLINE bool aiVector3t<TReal>::operator!= (const aiVector3t<TReal>& other) const {
return x != other.x || y != other.y || z != other.z;
}
// ---------------------------------------------------------------------------
template<typename TReal>
AI_FORCE_INLINE
bool aiVector3t<TReal>::Equal(const aiVector3t<TReal>& other, TReal epsilon) const {
AI_FORCE_INLINE bool aiVector3t<TReal>::Equal(const aiVector3t<TReal>& other, TReal epsilon) const {
return
std::abs(x - other.x) <= epsilon &&
std::abs(y - other.y) <= epsilon &&
@@ -230,77 +215,66 @@ bool aiVector3t<TReal>::Equal(const aiVector3t<TReal>& other, TReal epsilon) con
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
bool aiVector3t<TReal>::operator < (const aiVector3t<TReal>& other) const {
AI_FORCE_INLINE bool aiVector3t<TReal>::operator < (const aiVector3t<TReal>& other) const {
return x != other.x ? x < other.x : y != other.y ? y < other.y : z < other.z;
}
// ------------------------------------------------------------------------------------------------
template <typename TReal>
AI_FORCE_INLINE
const aiVector3t<TReal> aiVector3t<TReal>::SymMul(const aiVector3t<TReal>& o) {
AI_FORCE_INLINE const aiVector3t<TReal> aiVector3t<TReal>::SymMul(const aiVector3t<TReal>& o) {
return aiVector3t<TReal>(x*o.x,y*o.y,z*o.z);
}
// ------------------------------------------------------------------------------------------------
// symmetric addition
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator + (const aiVector3t<TReal>& v1, const aiVector3t<TReal>& v2) {
AI_FORCE_INLINE aiVector3t<TReal> operator + (const aiVector3t<TReal>& v1, const aiVector3t<TReal>& v2) {
return aiVector3t<TReal>( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
// ------------------------------------------------------------------------------------------------
// symmetric subtraction
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator - (const aiVector3t<TReal>& v1, const aiVector3t<TReal>& v2) {
AI_FORCE_INLINE aiVector3t<TReal> operator - (const aiVector3t<TReal>& v1, const aiVector3t<TReal>& v2) {
return aiVector3t<TReal>( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
// ------------------------------------------------------------------------------------------------
// scalar product
template <typename TReal>
AI_FORCE_INLINE
TReal operator * (const aiVector3t<TReal>& v1, const aiVector3t<TReal>& v2) {
AI_FORCE_INLINE TReal operator * (const aiVector3t<TReal>& v1, const aiVector3t<TReal>& v2) {
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
}
// ------------------------------------------------------------------------------------------------
// scalar multiplication
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator * ( TReal f, const aiVector3t<TReal>& v) {
AI_FORCE_INLINE aiVector3t<TReal> operator * ( TReal f, const aiVector3t<TReal>& v) {
return aiVector3t<TReal>( f*v.x, f*v.y, f*v.z);
}
// ------------------------------------------------------------------------------------------------
// and the other way around
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator * ( const aiVector3t<TReal>& v, TReal f) {
AI_FORCE_INLINE aiVector3t<TReal> operator * ( const aiVector3t<TReal>& v, TReal f) {
return aiVector3t<TReal>( f*v.x, f*v.y, f*v.z);
}
// ------------------------------------------------------------------------------------------------
// scalar division
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator / ( const aiVector3t<TReal>& v, TReal f) {
AI_FORCE_INLINE aiVector3t<TReal> operator / ( const aiVector3t<TReal>& v, TReal f) {
return v * (1/f);
}
// ------------------------------------------------------------------------------------------------
// vector division
template <typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator / ( const aiVector3t<TReal>& v, const aiVector3t<TReal>& v2) {
AI_FORCE_INLINE aiVector3t<TReal> operator / ( const aiVector3t<TReal>& v, const aiVector3t<TReal>& v2) {
return aiVector3t<TReal>(v.x / v2.x,v.y / v2.y,v.z / v2.z);
}
// ------------------------------------------------------------------------------------------------
// cross product
template<typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator ^ ( const aiVector3t<TReal>& v1, const aiVector3t<TReal>& v2) {
AI_FORCE_INLINE aiVector3t<TReal> operator ^ ( const aiVector3t<TReal>& v1, const aiVector3t<TReal>& v2) {
return aiVector3t<TReal>( v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x);
}
// ------------------------------------------------------------------------------------------------
// vector negation
template<typename TReal>
AI_FORCE_INLINE
aiVector3t<TReal> operator - ( const aiVector3t<TReal>& v) {
AI_FORCE_INLINE aiVector3t<TReal> operator - ( const aiVector3t<TReal>& v) {
return aiVector3t<TReal>( -v.x, -v.y, -v.z);
}
+4 -4
View File
@@ -2,7 +2,7 @@
[Setup]
AppName=Open Asset Import Library - SDK
AppVerName=Open Asset Import Library - SDK (v5.0.1)
AppVerName=Open Asset Import Library - SDK (v5.1.0)
DefaultDirName={pf}\Assimp
DefaultGroupName=Assimp
UninstallDisplayIcon={app}\bin\x64\assimp.exe
@@ -12,9 +12,9 @@ SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico
WizardImageFile=compiler:WizModernImage-IS.BMP
WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP
LicenseFile=License.rtf
OutputBaseFileName=assimp-sdk-5.0.1-setup
VersionInfoVersion=5.0.1.0
VersionInfoTextVersion=5.0.1
OutputBaseFileName=assimp-sdk-5.1.0-setup
VersionInfoVersion=5.1.0.0
VersionInfoTextVersion=5.1.0
VersionInfoCompany=Assimp Development Team
ArchitecturesInstallIn64BitMode=x64
+7 -7
View File
@@ -2,7 +2,7 @@
[Setup]
AppName=Open Asset Import Library - SDK
AppVerName=Open Asset Import Library - SDK (v5.0.1)
AppVerName=Open Asset Import Library - SDK (v5.1.0)
DefaultDirName={pf}\Assimp
DefaultGroupName=Assimp
UninstallDisplayIcon={app}\bin\x86\assimp.exe
@@ -12,9 +12,9 @@ SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico
WizardImageFile=compiler:WizModernImage-IS.BMP
WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP
LicenseFile=License.rtf
OutputBaseFileName=assimp-sdk-5.0.1-setup
VersionInfoVersion=5.0.1.0
VersionInfoTextVersion=5.0.1
OutputBaseFileName=assimp-sdk-5.1.0-setup
VersionInfoVersion=5.1.0.0
VersionInfoTextVersion=5.1.0
VersionInfoCompany=Assimp Development Team
;ArchitecturesInstallIn64BitMode=x64
@@ -49,11 +49,11 @@ Source: "WEB"; DestDir: "{app}"
Source: "..\..\scripts\*"; DestDir: "{app}\scripts"; Flags: recursesubdirs
; x86 binaries
Source: "..\..\bin\release\assimp-vc141-mt.dll"; DestDir: "{app}\bin\x86"
Source: "..\..\bin\release\assimp_viewer.exe"; DestDir: "{app}\bin\x86"; Components: tools
Source: "..\..\bin\release\assimp-vc141-mt.dll"; DestDir: "{app}\bin\x86"
Source: "..\..\bin\release\assimp_viewer.exe"; DestDir: "{app}\bin\x86"; Components: tools
Source: "C:\Windows\SysWOW64\D3DCompiler_42.dll"; DestDir: "{app}\bin\x86"; Components: tools
Source: "C:\Windows\SysWOW64\D3DX9_42.dll"; DestDir: "{app}\bin\x86"; Components: tools
Source: "..\..\bin\release\assimp.exe"; DestDir: "{app}\bin\x86"; Components: tools
Source: "..\..\bin\release\assimp.exe"; DestDir: "{app}\bin\x86"; Components: tools
; Import libraries
+85 -82
View File
@@ -3,7 +3,7 @@
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
Copyright (c) 2006-2021, assimp team
All rights reserved.
@@ -67,45 +67,50 @@ AndroidJNIIOSystem::AndroidJNIIOSystem(ANativeActivity* activity)
AndroidActivityInit(activity);
}
AndroidJNIIOSystem::AndroidJNIIOSystem(const char *internalPath, AAssetManager* assetManager) :
mApkWorkspacePath(internalPath),
mApkAssetManager(assetManager) {
// empty
}
// ------------------------------------------------------------------------------------------------
// Destructor.
AndroidJNIIOSystem::~AndroidJNIIOSystem()
{
// nothing to do here
AndroidJNIIOSystem::~AndroidJNIIOSystem() {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Tests for the existence of a file at the given path.
bool AndroidJNIIOSystem::Exists( const char* pFile) const
{
AAsset* asset = AAssetManager_open(mApkAssetManager, pFile,
AASSET_MODE_UNKNOWN);
FILE* file = ::fopen( (mApkWorkspacePath + getOsSeparator() + std::string(pFile)).c_str(), "rb");
bool AndroidJNIIOSystem::Exists( const char* pFile) const {
AAsset* asset = AAssetManager_open(mApkAssetManager, pFile, AASSET_MODE_UNKNOWN);
FILE* file = ::fopen( (mApkWorkspacePath + getOsSeparator() + std::string(pFile)).c_str(), "rb");
if (!asset && !file) {
__android_log_print(ANDROID_LOG_ERROR, "Assimp", "Asset manager can not find: %s", pFile);
return false;
}
if (!asset && !file)
{
__android_log_print(ANDROID_LOG_ERROR, "Assimp", "Asset manager can not find: %s", pFile);
return false;
}
__android_log_print(ANDROID_LOG_ERROR, "Assimp", "Asset exists");
if (file)
::fclose( file);
return true;
__android_log_print(ANDROID_LOG_ERROR, "Assimp", "Asset exists");
if (file) {
::fclose( file);
}
return true;
}
// ------------------------------------------------------------------------------------------------
// Inits Android extractor
void AndroidJNIIOSystem::AndroidActivityInit(ANativeActivity* activity)
{
mApkWorkspacePath = activity->internalDataPath;
mApkAssetManager = activity->assetManager;
void AndroidJNIIOSystem::AndroidActivityInit(ANativeActivity* activity) {
if (activity == nullptr) {
return;
}
mApkWorkspacePath = activity->internalDataPath;
mApkAssetManager = activity->assetManager;
}
// ------------------------------------------------------------------------------------------------
// Create the directory for the extracted resource
static int mkpath(std::string path, mode_t mode)
{
static int mkpath(std::string path, mode_t mode) {
if (mkdir(path.c_str(), mode) == -1) {
switch(errno) {
case ENOENT:
@@ -125,82 +130,80 @@ static int mkpath(std::string path, mode_t mode)
// ------------------------------------------------------------------------------------------------
// Extracts android asset
bool AndroidJNIIOSystem::AndroidExtractAsset(std::string name)
{
std::string newPath = mApkWorkspacePath + getOsSeparator() + name;
bool AndroidJNIIOSystem::AndroidExtractAsset(std::string name) {
std::string newPath = mApkWorkspacePath + getOsSeparator() + name;
DefaultIOSystem io;
DefaultIOSystem io;
// Do not extract if extracted already
if ( io.Exists(newPath.c_str()) ) {
__android_log_print(ANDROID_LOG_DEFAULT, "Assimp", "Asset already extracted");
return true;
}
// Open file
AAsset* asset = AAssetManager_open(mApkAssetManager, name.c_str(),
// Do not extract if extracted already
if ( io.Exists(newPath.c_str()) ) {
__android_log_print(ANDROID_LOG_DEFAULT, "Assimp", "Asset already extracted");
return true;
}
// Open file
AAsset* asset = AAssetManager_open(mApkAssetManager, name.c_str(),
AASSET_MODE_UNKNOWN);
std::vector<char> assetContent;
std::vector<char> assetContent;
if (asset != NULL) {
// Find size
off_t assetSize = AAsset_getLength(asset);
if (asset != NULL) {
// Find size
off_t assetSize = AAsset_getLength(asset);
// Prepare input buffer
assetContent.resize(assetSize);
// Prepare input buffer
assetContent.resize(assetSize);
// Store input buffer
AAsset_read(asset, &assetContent[0], assetSize);
// Store input buffer
AAsset_read(asset, &assetContent[0], assetSize);
// Close
AAsset_close(asset);
// Close
AAsset_close(asset);
// Prepare directory for output buffer
std::string directoryNewPath = newPath;
directoryNewPath = dirname(&directoryNewPath[0]);
// Prepare directory for output buffer
std::string directoryNewPath = newPath;
directoryNewPath = dirname(&directoryNewPath[0]);
if (mkpath(directoryNewPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
__android_log_print(ANDROID_LOG_ERROR, "assimp",
"Can not create the directory for the output file");
}
if (mkpath(directoryNewPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
__android_log_print(ANDROID_LOG_ERROR, "assimp", "Can not create the directory for the output file");
}
// Prepare output buffer
std::ofstream assetExtracted(newPath.c_str(),
std::ios::out | std::ios::binary);
if (!assetExtracted) {
__android_log_print(ANDROID_LOG_ERROR, "assimp",
"Can not open output file");
}
// Prepare output buffer
std::ofstream assetExtracted(newPath.c_str(), std::ios::out | std::ios::binary);
if (!assetExtracted) {
__android_log_print(ANDROID_LOG_ERROR, "assimp", "Can not open output file");
}
// Write output buffer into a file
assetExtracted.write(&assetContent[0], assetContent.size());
assetExtracted.close();
// Write output buffer into a file
assetExtracted.write(&assetContent[0], assetContent.size());
assetExtracted.close();
__android_log_print(ANDROID_LOG_DEFAULT, "Assimp", "Asset extracted");
} else {
__android_log_print(ANDROID_LOG_ERROR, "assimp", "Asset not found: %s", name.c_str());
return false;
}
return true;
__android_log_print(ANDROID_LOG_DEFAULT, "Assimp", "Asset extracted");
} else {
__android_log_print(ANDROID_LOG_ERROR, "assimp", "Asset not found: %s", name.c_str());
return false;
}
return true;
}
// ------------------------------------------------------------------------------------------------
// Open a new file with a given path.
IOStream* AndroidJNIIOSystem::Open( const char* strFile, const char* strMode)
{
ai_assert(NULL != strFile);
ai_assert(NULL != strMode);
IOStream* AndroidJNIIOSystem::Open( const char* strFile, const char* strMode) {
ai_assert(nullptr != strFile);
ai_assert(nullptr != strMode);
std::string fullPath(mApkWorkspacePath + getOsSeparator() + std::string(strFile));
if (Exists(strFile))
AndroidExtractAsset(std::string(strFile));
std::string fullPath(mApkWorkspacePath + getOsSeparator() + std::string(strFile));
if (Exists(strFile)) {
AndroidExtractAsset(std::string(strFile));
}
FILE* file = ::fopen( fullPath.c_str(), strMode);
FILE* file = ::fopen( fullPath.c_str(), strMode);
if (nullptr == file) {
return nullptr;
}
if( NULL == file)
return NULL;
__android_log_print(ANDROID_LOG_ERROR, "assimp", "AndroidIOSystem: file %s opened", fullPath.c_str());
return new DefaultIOStream(file, fullPath);
__android_log_print(ANDROID_LOG_ERROR, "assimp", "AndroidIOSystem: file %s opened", fullPath.c_str());
return new DefaultIOStream(file, fullPath);
}
#undef PATHLIMIT
+16 -3
View File
@@ -90,6 +90,7 @@ SET( COMMON
unit/utProfiler.cpp
unit/utSharedPPData.cpp
unit/utStringUtils.cpp
unit/Common/utMesh.cpp
unit/Common/utStandardShapes.cpp
unit/Common/uiScene.cpp
unit/Common/utLineSplitter.cpp
@@ -137,7 +138,7 @@ SET( IMPORTERS
unit/utColladaImportExport.cpp
unit/utCSMImportExport.cpp
unit/utB3DImportExport.cpp
unit/utM3DImportExport.cpp
#unit/utM3DImportExport.cpp
unit/utMDCImportExport.cpp
unit/utAssbinImportExport.cpp
unit/ImportExport/utAssjsonImportExport.cpp
@@ -148,14 +149,13 @@ SET( IMPORTERS
unit/ImportExport/utNFFImportExport.cpp
unit/ImportExport/utXGLImportExport.cpp
unit/ImportExport/utMD2Importer.cpp
unit/ImportExport/utMD3Importer.cpp
#unit/ImportExport/utMD3Importer.cpp
unit/ImportExport/utMD5Importer.cpp
unit/ImportExport/utMDLImporter.cpp
unit/ImportExport/MDL/MDLHL1TestFiles.h
unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp
unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp
unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp
#unit/ImportExport/IRR/utIrrImportExport.cpp
unit/ImportExport/RAW/utRAWImportExport.cpp
unit/ImportExport/Terragen/utTerragenImportExport.cpp
)
@@ -223,6 +223,19 @@ else()
target_sources(unit PUBLIC ${Assimp_SOURCE_DIR}/contrib/gtest/src/gtest-all.cc)
endif()
# RapidJSON
IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(RapidJSON)
find_package(RapidJSON CONFIG REQUIRED)
ELSE()
INCLUDE_DIRECTORIES("../contrib/rapidjson/include")
ADD_DEFINITIONS( -DRAPIDJSON_HAS_STDSTRING=1)
option( ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR "Suppress rapidjson warning on MSVC (NOTE: breaks android build)" ON )
if(ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR)
ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS )
endif()
ENDIF()
IF (ASSIMP_BUILD_DRACO)
ADD_DEFINITIONS( -DASSIMP_ENABLE_DRACO )
ENDIF()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

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