Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e73a537081 | ||
|
|
9c10e7d2b5 | ||
|
|
048becec92 | ||
|
|
8ff005570a | ||
|
|
fcb1702162 | ||
|
|
b5f567bd3a | ||
|
|
1569f6a9e0 | ||
|
|
29df28d7d3 | ||
|
|
b10b8ab99a | ||
|
|
b2852bc49b | ||
|
|
e70199446d | ||
|
|
dc54c9fdea | ||
|
|
38f3e8d98b | ||
|
|
8a073f7cb4 | ||
|
|
553fbc1fdb | ||
|
|
e13e0b5b7d | ||
|
|
929bff1830 | ||
|
|
48515a4aa1 | ||
|
|
8ef1461cb8 | ||
|
|
1ed019b869 | ||
|
|
7c7a1233f5 | ||
|
|
10be273aea | ||
|
|
3e6482bca0 | ||
|
|
c0d273cb3b | ||
|
|
3e672ff856 | ||
|
|
e730b7803c | ||
|
|
3e188e6768 | ||
|
|
21607dfb75 | ||
|
|
970f8691dd | ||
|
|
8acd2c964e | ||
|
|
b4c7912d21 | ||
|
|
e38451ff6c | ||
|
|
36c3a19aa8 | ||
|
|
cedc5a8d10 | ||
|
|
4d3a694807 | ||
|
|
5c5ae38934 | ||
|
|
18798f150d | ||
|
|
ae6633ef8a | ||
|
|
517fb1b242 |
@@ -109,7 +109,7 @@ jobs:
|
|||||||
run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }}
|
run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v6
|
- uses: actions/upload-artifact@v7
|
||||||
if: matrix.name == 'windows-msvc'
|
if: matrix.name == 'windows-msvc'
|
||||||
with:
|
with:
|
||||||
name: 'assimp-bins-${{ matrix.name }}'
|
name: 'assimp-bins-${{ matrix.name }}'
|
||||||
@@ -141,7 +141,7 @@ jobs:
|
|||||||
prerelease: true
|
prerelease: true
|
||||||
- run: |
|
- run: |
|
||||||
echo '${{steps.create-release.outputs.upload_url}}' > release_upload_url.txt
|
echo '${{steps.create-release.outputs.upload_url}}' > release_upload_url.txt
|
||||||
- uses: actions/upload-artifact@v6
|
- uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: create-release
|
name: create-release
|
||||||
path: release_upload_url.txt
|
path: release_upload_url.txt
|
||||||
@@ -188,7 +188,7 @@ jobs:
|
|||||||
- id: upload-url
|
- id: upload-url
|
||||||
run: |
|
run: |
|
||||||
echo "url=$(cat create-release/release_upload_url.txt)" >> $GITHUB_OUTPUT
|
echo "url=$(cat create-release/release_upload_url.txt)" >> $GITHUB_OUTPUT
|
||||||
- uses: actions/download-artifact@v7
|
- uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}'
|
name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}'
|
||||||
- uses: actions/upload-release-asset@v1
|
- uses: actions/upload-release-asset@v1
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
dry-run: false
|
dry-run: false
|
||||||
language: c++
|
language: c++
|
||||||
- name: Upload Crash
|
- name: Upload Crash
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
if: failure() && steps.build.outcome == 'success'
|
if: failure() && steps.build.outcome == 'success'
|
||||||
with:
|
with:
|
||||||
name: artifacts
|
name: artifacts
|
||||||
|
|||||||
@@ -0,0 +1,207 @@
|
|||||||
|
# AGENTS.md - Agent Guidelines for Assimp
|
||||||
|
|
||||||
|
This document provides guidelines for AI agents working on the Assimp codebase.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
Assimp (Open Asset Import Library) is a C++ library that loads various 3D file formats into a shared, in-memory format. It supports 40+ import formats and several export formats.
|
||||||
|
|
||||||
|
## Build Commands
|
||||||
|
|
||||||
|
### Basic Build (CMake + Ninja recommended)
|
||||||
|
```bash
|
||||||
|
# Configure with CMake
|
||||||
|
cmake -G Ninja -DASSIMP_BUILD_TESTS=ON -DASSIMP_WARNINGS_AS_ERRORS=ON -S . -B build
|
||||||
|
|
||||||
|
# Build
|
||||||
|
cmake --build build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key CMake Options
|
||||||
|
- `-DASSIMP_BUILD_TESTS=ON` - Build unit tests (default ON)
|
||||||
|
- `-DASSIMP_WARNINGS_AS_ERRORS=ON` - Treat warnings as errors (default ON)
|
||||||
|
- `-DASSIMP_BUILD_ASSIMP_TOOLS=ON` - Build command-line tools
|
||||||
|
- `-DASSIMP_BUILD_SAMPLES=ON` - Build sample applications
|
||||||
|
- `-DASSIMP_DOUBLE_PRECISION=ON` - Use double precision for calculations
|
||||||
|
- `-DASSIMP_NO_EXPORT=ON` - Disable export functionality
|
||||||
|
- `-DBUILD_SHARED_LIBS=OFF` - Build static library
|
||||||
|
|
||||||
|
### Running Tests
|
||||||
|
|
||||||
|
#### Run All Tests
|
||||||
|
```bash
|
||||||
|
# Using ctest
|
||||||
|
cd build && ctest
|
||||||
|
|
||||||
|
# Or run unit directly
|
||||||
|
./build/unit
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Run Single Test
|
||||||
|
```bash
|
||||||
|
# Using ctest with filter
|
||||||
|
cd build && ctest -R "TestName"
|
||||||
|
|
||||||
|
# Or run unit with filter
|
||||||
|
./build/unit --gtest_filter="TestSuiteName.TestName"
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
```bash
|
||||||
|
./build/unit --gtest_filter="utObjImportExport.*"
|
||||||
|
./build/unit --gtest_filter="utMaterialSystem.*"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Test Directory
|
||||||
|
Tests are located in `test/unit/` and use Google Test. Test files are named `ut<Feature>.cpp`.
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
### Formatting
|
||||||
|
- **Use clang-format** before committing. Run: `clang-format -i <file>`
|
||||||
|
- The project uses a `.clang-format` file at the root with LLVM-based style
|
||||||
|
- Key settings:
|
||||||
|
- Indent width: 4 spaces
|
||||||
|
- Tab width: 4, UseTab: Never
|
||||||
|
- ColumnLimit: 0 (no line length limit)
|
||||||
|
- BreakConstructorInitializers: AfterColon
|
||||||
|
- AccessModifierOffset: -4
|
||||||
|
|
||||||
|
### Header File Organization
|
||||||
|
```cpp
|
||||||
|
// Order of includes (use clang-format to enforce):
|
||||||
|
// 1. Module's own header
|
||||||
|
// 2. Other assimp headers (assimp/*)
|
||||||
|
// 3. External headers (contrib/*)
|
||||||
|
// 4. Standard library headers
|
||||||
|
// 5. System headers
|
||||||
|
|
||||||
|
#include "Common/Importer.h"
|
||||||
|
#include <assimp/version.h>
|
||||||
|
#include <assimp/config.h>
|
||||||
|
#include "../contrib/some_lib/some.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Naming Conventions
|
||||||
|
- **Classes/Types**: PascalCase (e.g., `Importer`, `aiScene`)
|
||||||
|
- **Functions**: PascalCase (e.g., `ReadFile`, `GetExtension`)
|
||||||
|
- **Variables**: camelCase (e.g., `scene`, `importStep`)
|
||||||
|
- **Constants**: kCamelCase or UPPER_SNAKE_CASE (e.g., `kMaxVertices`)
|
||||||
|
- **Member variables**: Often prefixed with `m_` (e.g., `mScene`)
|
||||||
|
- **Static variables**: Often prefixed with `s_`
|
||||||
|
|
||||||
|
### File Naming
|
||||||
|
- **Header files**: PascalCase (e.g., `Importer.h`, `ScenePrivate.h`)
|
||||||
|
- **Source files**: PascalCase (e.g., `Importer.cpp`)
|
||||||
|
- **Test files**: Prefixed with `ut` (e.g., `utObjImportExport.cpp`)
|
||||||
|
|
||||||
|
### C++ Guidelines
|
||||||
|
|
||||||
|
#### Language Standard
|
||||||
|
- Minimum: C++17
|
||||||
|
- Use modern C++ features (smart pointers, constexpr, etc.)
|
||||||
|
|
||||||
|
#### Error Handling
|
||||||
|
- Use exceptions for recoverable errors (derived from `std::exception`)
|
||||||
|
- Use `ai_assert` for debugging assertions in code
|
||||||
|
- Return error codes from C API functions
|
||||||
|
|
||||||
|
#### Classes
|
||||||
|
- Use `ai_enable_erasing` pattern for optional features
|
||||||
|
- Use PImpl idiom for ABI stability where appropriate
|
||||||
|
|
||||||
|
#### Memory Management
|
||||||
|
- Use smart pointers (`std::unique_ptr`, `std::shared_ptr`)
|
||||||
|
- Prefer RAII patterns
|
||||||
|
- Document ownership semantics in function comments
|
||||||
|
|
||||||
|
### Importers/Exporters
|
||||||
|
|
||||||
|
#### Structure
|
||||||
|
Each importer typically has:
|
||||||
|
1. Header in `code/AssetLib/<Format>/`
|
||||||
|
2. Implementation in `code/AssetLib/<Format>/`
|
||||||
|
3. Registration in `code/Common/ImporterRegistry.cpp`
|
||||||
|
4. Unit tests in `test/unit/ImportExport/`
|
||||||
|
|
||||||
|
#### Registration
|
||||||
|
```cpp
|
||||||
|
void GetImporterInstanceList(std::vector<BaseImporter*>& out);
|
||||||
|
// Add to registry
|
||||||
|
out.push_back(new MyFormatImporter());
|
||||||
|
```
|
||||||
|
|
||||||
|
### Post-Processing
|
||||||
|
|
||||||
|
- Located in `code/PostProcessing/`
|
||||||
|
- Each process inherits from `BaseProcess`
|
||||||
|
- Implement `ExecuteOnScene` method
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Use Doxygen-style comments for public APIs
|
||||||
|
- Example:
|
||||||
|
```cpp
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a file from disk.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pFile">Path to the file.</param>
|
||||||
|
/// <returns>Pointer to the imported scene.</returns>
|
||||||
|
aiScene* Importer::ReadFile(const char* pFile);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Contributing
|
||||||
|
|
||||||
|
1. Create a fork of assimp
|
||||||
|
2. Create a branch for your feature/fix
|
||||||
|
3. Run `clang-format` on modified files
|
||||||
|
4. Ensure tests pass
|
||||||
|
5. Open a PR against `master` branch
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
code/
|
||||||
|
AssetLib/ - Importers and exporters
|
||||||
|
CApi/ - C API wrapper
|
||||||
|
Common/ - Shared utilities
|
||||||
|
Geometry/ - Geometry processing
|
||||||
|
Material/ - Material handling
|
||||||
|
PostProcessing/ - Mesh post-processing
|
||||||
|
include/ - Public headers (assimp/)
|
||||||
|
test/
|
||||||
|
unit/ - Unit tests
|
||||||
|
models/ - Test 3D models
|
||||||
|
test/ - Test data (non-BSD licensed)
|
||||||
|
contrib/ - Third-party libraries
|
||||||
|
```
|
||||||
|
|
||||||
|
## CI/CD
|
||||||
|
|
||||||
|
The project runs CI on GitHub Actions:
|
||||||
|
- Builds on Linux and Windows
|
||||||
|
- Runs tests including memory leak detection
|
||||||
|
- Checks compiler warnings
|
||||||
|
|
||||||
|
## Common Tasks
|
||||||
|
|
||||||
|
### Adding a New Importer
|
||||||
|
1. Create `code/AssetLib/<Format>/<Format>Importer.h`
|
||||||
|
2. Create `code/AssetLib/<Format>/<Format>Importer.cpp`
|
||||||
|
3. Register in `code/Common/ImporterRegistry.cpp`
|
||||||
|
4. Add tests in `test/unit/ImportExport/`
|
||||||
|
5. Add to CMakeLists.txt if needed
|
||||||
|
|
||||||
|
### Running Specific Test Suite
|
||||||
|
```bash
|
||||||
|
# Test specific importer
|
||||||
|
./build/unit --gtest_filter="utglTF2ImportExport.*"
|
||||||
|
|
||||||
|
# Test post-processing
|
||||||
|
./build/unit --gtest_filter="utTriangulate.*"
|
||||||
|
|
||||||
|
# Test math operations
|
||||||
|
./build/unit --gtest_filter="utMatrix4x4.*"
|
||||||
|
```
|
||||||
+172
@@ -0,0 +1,172 @@
|
|||||||
|
# Asset-Importer-Lib AI Tool Use Policy
|
||||||
|
|
||||||
|
## Policy
|
||||||
|
|
||||||
|
Assimp's policy is that contributors can use whatever tools they would like to
|
||||||
|
craft their contributions, but there must be a **human in the loop**.
|
||||||
|
**Contributors must read and review all LLM-generated code or text before they
|
||||||
|
ask other project members to review it.** The contributor is always the author
|
||||||
|
and is fully accountable for their contributions. Contributors should be
|
||||||
|
sufficiently confident that the contribution is high enough quality that asking
|
||||||
|
for a review is a good use of scarce maintainer time, and they should be **able
|
||||||
|
to answer questions about their work** during review.
|
||||||
|
|
||||||
|
We expect that new contributors will be less confident in their contributions,
|
||||||
|
and our guidance to them is to **start with small contributions** that they can
|
||||||
|
fully understand to build confidence. We aspire to be a welcoming community
|
||||||
|
that helps new contributors grow their expertise, but learning involves taking
|
||||||
|
small steps, getting feedback, and iterating. Passing maintainer feedback to an
|
||||||
|
LLM doesn't help anyone grow, and does not sustain our community.
|
||||||
|
|
||||||
|
Contributors are expected to **be transparent and label contributions that
|
||||||
|
contain substantial amounts of tool-generated content**. Our policy on
|
||||||
|
labelling is intended to facilitate reviews, and not to track which parts of
|
||||||
|
Assimp are generated. Contributors should note tool usage in their pull request
|
||||||
|
description, commit message, or wherever authorship is normally indicated for
|
||||||
|
the work. For instance, use a commit message trailer like Assisted-by: <name of
|
||||||
|
code assistant>. This transparency helps the community develop best practices
|
||||||
|
and understand the role of these new tools.
|
||||||
|
|
||||||
|
This policy includes, but is not limited to, the following kinds of
|
||||||
|
contributions:
|
||||||
|
|
||||||
|
- Code, usually in the form of a pull request
|
||||||
|
- RFCs or design proposals
|
||||||
|
- Issues or security vulnerabilities
|
||||||
|
- Comments and feedback on pull requests
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
To ensure sufficient self review and understanding of the work, it is strongly
|
||||||
|
recommended that contributors write PR descriptions themselves (if needed,
|
||||||
|
using tools for translation or copy-editing). The description should explain
|
||||||
|
the motivation, implementation approach, expected impact, and any open
|
||||||
|
questions or uncertainties to the same extent as a contribution made without
|
||||||
|
tool assistance.
|
||||||
|
|
||||||
|
AI tools must not be used to fix GitHub issues labelled [`good first
|
||||||
|
issue`][good-first-issue]. These issues are generally not urgent, and are
|
||||||
|
intended to be learning opportunities for new contributors to get familiar with
|
||||||
|
the codebase. Whether you are a newcomer or not, fully automating the process
|
||||||
|
of fixing this issue squanders the learning opportunity and doesn't add much
|
||||||
|
value to the project. **Using AI tools to fix issues labelled as "good first
|
||||||
|
issues" is forbidden**.
|
||||||
|
|
||||||
|
[good-first-issue]: https://github.com/llvm/llvm-project/issues/?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22
|
||||||
|
|
||||||
|
## Extractive Contributions
|
||||||
|
|
||||||
|
The reason for our "human-in-the-loop" contribution policy is that processing
|
||||||
|
patches, PRs, RFCs, and comments to Assimp is not free -- it takes a lot of
|
||||||
|
maintainer time and energy to review those contributions! Sending the
|
||||||
|
unreviewed output of an Assimp to open source project maintainers *extracts* work
|
||||||
|
from them in the form of design and code review, so we call this kind of
|
||||||
|
contribution an "extractive contribution".
|
||||||
|
|
||||||
|
Our **golden rule** is that a contribution should be worth more to the project
|
||||||
|
than the time it takes to review it. These ideas are captured by this quote
|
||||||
|
from the book [Working in Public][public] by Nadia Eghbal:
|
||||||
|
|
||||||
|
[public]: https://press.stripe.com/working-in-public
|
||||||
|
|
||||||
|
> \"When attention is being appropriated, producers need to weigh the costs and
|
||||||
|
> benefits of the transaction. To assess whether the appropriation of attention
|
||||||
|
> is net-positive, it's useful to distinguish between *extractive* and
|
||||||
|
> *non-extractive* contributions. Extractive contributions are those where the
|
||||||
|
> marginal cost of reviewing and merging that contribution is greater than the
|
||||||
|
> marginal benefit to the project's producers. In the case of a code
|
||||||
|
> contribution, it might be a pull request that's too complex or unwieldy to
|
||||||
|
> review, given the potential upside.\" \-- Nadia Eghbal
|
||||||
|
|
||||||
|
Prior to the advent of LLMs, open source project maintainers would often review
|
||||||
|
any and all changes sent to the project simply because posting a change for
|
||||||
|
review was a sign of interest from a potential long-term contributor. While new
|
||||||
|
tools enable more development, it shifts effort from the implementor to the
|
||||||
|
reviewer, and our policy exists to ensure that we value and do not squander
|
||||||
|
maintainer time.
|
||||||
|
|
||||||
|
Reviewing changes from new contributors is part of growing the next generation
|
||||||
|
of contributors and sustaining the project. We want the LLVM project to be
|
||||||
|
welcoming and open to aspiring compiler engineers who are willing to invest
|
||||||
|
time and effort to learn and grow, because growing our contributor base and
|
||||||
|
recruiting new maintainers helps sustain the project over the long term. Being
|
||||||
|
open to contributions and [liberally granting commit access][commit-access]
|
||||||
|
is a big part of how LLVM has grown and successfully been adopted all across
|
||||||
|
the industry. We therefore automatically post a greeting comment to pull
|
||||||
|
requests from new contributors and encourage maintainers to spend their time to
|
||||||
|
help new contributors learn.
|
||||||
|
|
||||||
|
[commit-access]: https://llvm.org/docs/DeveloperPolicy.html#obtaining-commit-access
|
||||||
|
|
||||||
|
## Handling Violations
|
||||||
|
|
||||||
|
If a maintainer judges that a contribution doesn't comply with this policy,
|
||||||
|
they should paste the following response to request changes:
|
||||||
|
|
||||||
|
This PR doesn't appear to comply with our policy on tool-generated content,
|
||||||
|
and requires additional justification for why it is valuable enough to the
|
||||||
|
project for us to review it. Please see our developer policy on
|
||||||
|
AI-generated contributions: http://llvm.org/docs/AIToolPolicy.html
|
||||||
|
|
||||||
|
The best ways to make a change less extractive and more valuable are to reduce
|
||||||
|
its size or complexity or to increase its usefulness to the community. These
|
||||||
|
factors are impossible to weigh objectively, and our project policy leaves this
|
||||||
|
determination up to the maintainers of the project, i.e. those who are doing
|
||||||
|
the work of sustaining the project.
|
||||||
|
|
||||||
|
If or when it becomes clear that a GitHub issue or PR is off-track and not
|
||||||
|
moving in the right direction, maintainers should apply the `extractive` label
|
||||||
|
to help other reviewers prioritize their review time.
|
||||||
|
|
||||||
|
If a contributor fails to make their change meaningfully less extractive,
|
||||||
|
maintainers should escalate to the relevant moderation or admin team for the
|
||||||
|
space (GitHub, Discourse, Discord, etc) to lock the conversation.
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
Artificial intelligence systems raise many questions around copyright that have
|
||||||
|
yet to be answered. Our policy on AI tools is similar to our copyright policy:
|
||||||
|
Contributors are responsible for ensuring that they have the right to
|
||||||
|
contribute code under the terms of our license, typically meaning that either
|
||||||
|
they, their employer, or their collaborators hold the copyright. Using AI tools
|
||||||
|
to regenerate copyrighted material does not remove the copyright, and
|
||||||
|
contributors are responsible for ensuring that such material does not appear in
|
||||||
|
their contributions. Contributions found to violate this policy will be removed
|
||||||
|
just like any other offending contribution.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Here are some examples of contributions that demonstrate how to apply
|
||||||
|
the principles of this policy:
|
||||||
|
|
||||||
|
- [This PR][alive-pr] contains a proof from Alive2, which is a strong signal of
|
||||||
|
value and correctness.
|
||||||
|
- This [generated documentation][gsym-docs] was reviewed for correctness by a
|
||||||
|
human before being posted.
|
||||||
|
|
||||||
|
[alive-pr]: https://github.com/llvm/llvm-project/pull/142869
|
||||||
|
[gsym-docs]: https://discourse.llvm.org/t/searching-for-gsym-documentation/85185/2
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
Our policy was informed by experiences in other communities:
|
||||||
|
|
||||||
|
- [Fedora Council Policy Proposal: Policy on AI-Assisted Contributions (fetched
|
||||||
|
2025-10-01)][fedora]: Some of the text above was copied from the Fedora
|
||||||
|
project policy proposal, which is licensed under the [Creative Commons
|
||||||
|
Attribution 4.0 International License][cca]. This link serves as attribution.
|
||||||
|
- [Rust draft policy on burdensome PRs][rust-burdensome]
|
||||||
|
- [Seth Larson's post][security-slop]
|
||||||
|
on slop security reports in the Python ecosystem
|
||||||
|
- The METR paper [Measuring the Impact of Early-2025 AI on Experienced
|
||||||
|
Open-Source Developer Productivity][metr-paper].
|
||||||
|
- [QEMU bans use of AI content generators][qemu-ban]
|
||||||
|
- [Slop is the new name for unwanted AI-generated content][ai-slop]
|
||||||
|
|
||||||
|
[fedora]: https://communityblog.fedoraproject.org/council-policy-proposal-policy-on-ai-assisted-contributions/
|
||||||
|
[cca]: https://creativecommons.org/licenses/by/4.0/
|
||||||
|
[rust-burdensome]: https://github.com/rust-lang/compiler-team/issues/893
|
||||||
|
[security-slop]: https://sethmlarson.dev/slop-security-reports
|
||||||
|
[metr-paper]: https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/
|
||||||
|
[qemu-ban]: https://www.qemu.org/docs/master/devel/code-provenance.html#use-of-ai-content-generators
|
||||||
|
[ai-slop]: https://simonwillison.net/2024/May/8/slop/
|
||||||
+1
-1
@@ -104,7 +104,7 @@ IF(ASSIMP_HUNTER_ENABLED)
|
|||||||
ADD_DEFINITIONS(-DASSIMP_USE_HUNTER)
|
ADD_DEFINITIONS(-DASSIMP_USE_HUNTER)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
PROJECT(Assimp VERSION 6.0.4
|
PROJECT(Assimp VERSION 6.0.5
|
||||||
LANGUAGES C CXX
|
LANGUAGES C CXX
|
||||||
DESCRIPTION "Open Asset Import Library (Assimp) is a library to import various well-known 3D model formats in a uniform manner."
|
DESCRIPTION "Open Asset Import Library (Assimp) is a library to import various well-known 3D model formats in a uniform manner."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Open Asset Import Library (assimp)
|
|||||||
|
|
||||||
Open Asset Import Library is a library that loads various 3D file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
|
Open Asset Import Library is a library that loads various 3D file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
|
||||||
|
|
||||||
### Current project status
|
## Current project status
|
||||||

|

|
||||||
[](https://www.codacy.com/gh/assimp/assimp/dashboard?utm_source=github.com&utm_medium=referral&utm_content=assimp/assimp&utm_campaign=Badge_Grade)
|
[](https://www.codacy.com/gh/assimp/assimp/dashboard?utm_source=github.com&utm_medium=referral&utm_content=assimp/assimp&utm_campaign=Badge_Grade)
|
||||||
[](https://sonarcloud.io/summary/new_code?id=assimp_assimp)
|
[](https://sonarcloud.io/summary/new_code?id=assimp_assimp)
|
||||||
@@ -19,29 +19,38 @@ Additionally, assimp features various __mesh post-processing tools__: normals an
|
|||||||
## Project activity
|
## Project activity
|
||||||

|

|
||||||
|
|
||||||
### Documentation
|
## Developer quickstart
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/assimp/assimp
|
||||||
|
cd assimp
|
||||||
|
cmake -G Ninja -DASSIMP_BUILD_TESTS=off -DASSIMP_INSTALL=off -S . -B build
|
||||||
|
cd build
|
||||||
|
ninja
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
Read [our latest documentation](https://the-asset-importer-lib-documentation.readthedocs.io/en/latest/).
|
Read [our latest documentation](https://the-asset-importer-lib-documentation.readthedocs.io/en/latest/).
|
||||||
|
|
||||||
### Pre-built binaries
|
## Pre-built binaries
|
||||||
Download binaries from [our Itch Projectspace](https://kimkulling.itch.io/the-asset-importer-lib).
|
Download binaries from [our Itch Projectspace](https://kimkulling.itch.io/the-asset-importer-lib).
|
||||||
|
|
||||||
### Test data
|
## Test data
|
||||||
Clone [our model database for testing purposes](https://github.com/assimp/assimp-mdb).
|
Clone [our model database for testing purposes](https://github.com/assimp/assimp-mdb).
|
||||||
|
|
||||||
### Communities
|
## Communities
|
||||||
- Ask questions at [the Assimp Discussion Board](https://github.com/assimp/assimp/discussions).
|
- Ask questions at [the Assimp Discussion Board](https://github.com/assimp/assimp/discussions).
|
||||||
- Find us on [discord](https://discord.gg/kKazXMXDy2)
|
- Find us on [discord](https://discord.gg/kKazXMXDy2)
|
||||||
- Ask [the Assimp community on Reddit](https://www.reddit.com/r/Assimp/).
|
- Ask [the Assimp community on Reddit](https://www.reddit.com/r/Assimp/).
|
||||||
- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest).
|
- Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest).
|
||||||
- Nothing has worked? File a question or an issue report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues)
|
- Nothing has worked? File a question or an issue report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues)
|
||||||
|
|
||||||
#### Supported file formats
|
## Supported file formats
|
||||||
See [the complete list of supported formats](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md).
|
See [the complete list of supported formats](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md).
|
||||||
|
|
||||||
### Building
|
## Building
|
||||||
Start by reading [our build instructions](https://github.com/assimp/assimp/blob/master/Build.md). We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do.
|
Start by reading [our build instructions](https://github.com/assimp/assimp/blob/master/Build.md). We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do.
|
||||||
|
|
||||||
### Ports
|
## Ports
|
||||||
* [Android](port/AndroidJNI/README.md)
|
* [Android](port/AndroidJNI/README.md)
|
||||||
* [Python](port/PyAssimp/README.md)
|
* [Python](port/PyAssimp/README.md)
|
||||||
* [.NET](https://github.com/Saalvage/AssimpNetter)
|
* [.NET](https://github.com/Saalvage/AssimpNetter)
|
||||||
@@ -54,11 +63,11 @@ Start by reading [our build instructions](https://github.com/assimp/assimp/blob/
|
|||||||
* [HAXE-Port](https://github.com/longde123/assimp-haxe) The Assimp-HAXE-port.
|
* [HAXE-Port](https://github.com/longde123/assimp-haxe) The Assimp-HAXE-port.
|
||||||
* [Rust](https://github.com/jkvargas/russimp)
|
* [Rust](https://github.com/jkvargas/russimp)
|
||||||
|
|
||||||
### Other tools
|
## Other tools
|
||||||
[Qt5-ModelViewer](https://github.com/sharjith/ModelViewer-Qt5) is a powerful viewer based on Qt5 and Assimp's import and export abilities.<br>
|
[Qt5-ModelViewer](https://github.com/sharjith/ModelViewer-Qt5) is a powerful viewer based on Qt5 and Assimp's import and export abilities.<br>
|
||||||
[Assimp-Viewer](https://github.com/assimp/assimp_view) is an experimental implementation for an Asset-Viewer based on ImGUI and Assimp (experimental).
|
[Assimp-Viewer](https://github.com/assimp/assimp_view) is an experimental implementation for an Asset-Viewer based on ImGUI and Assimp (experimental).
|
||||||
|
|
||||||
#### Repository structure ####
|
### Repository structure
|
||||||
Open Asset Import Library is implemented in C++. The directory structure looks like this:
|
Open Asset Import Library is implemented in C++. The directory structure looks like this:
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
@@ -85,7 +94,7 @@ test Unit- and regression tests, test suite of models
|
|||||||
tools Tools (old assimp viewer, command line `assimp`)
|
tools Tools (old assimp viewer, command line `assimp`)
|
||||||
samples Small number of samples to illustrate possible use cases for Assimp
|
samples Small number of samples to illustrate possible use cases for Assimp
|
||||||
```
|
```
|
||||||
### Contributing
|
## Contributing
|
||||||
|
|
||||||
We would greatly appreciate for you to contribute to assimp. The easiest way to get involved is to submit
|
We would greatly appreciate for you to contribute to assimp. The easiest way to get involved is to submit
|
||||||
a pull request with your changes against the main repository's `master` branch.
|
a pull request with your changes against the main repository's `master` branch.
|
||||||
@@ -113,7 +122,7 @@ You can support the project with your organization. Your logo will show up here
|
|||||||
|
|
||||||
<a href="https://opencollective.com/assimp/organization/0/website"><img src="https://opencollective.com/assimp/organization/0/avatar.svg"></a>
|
<a href="https://opencollective.com/assimp/organization/0/website"><img src="https://opencollective.com/assimp/organization/0/avatar.svg"></a>
|
||||||
|
|
||||||
### License ###
|
## License ###
|
||||||
Our license is based on the modified, __3-clause BSD__-License.
|
Our license is based on the modified, __3-clause BSD__-License.
|
||||||
|
|
||||||
An _informal_ summary is: do whatever you want, but include Assimp's license text with your product -
|
An _informal_ summary is: do whatever you want, but include Assimp's license text with your product -
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ The current version of Assimp that's being supported with security updates:
|
|||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| ------- | ------------------ |
|
| ------- | ------------------ |
|
||||||
| 6.0.2 | :white_check_mark: |
|
| 6.0.5 | :white_check_mark: |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
|||||||
@@ -607,6 +607,10 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
|
|||||||
const Surface::SurfaceEntry &entry1 = src.entries[i];
|
const Surface::SurfaceEntry &entry1 = src.entries[i];
|
||||||
const Surface::SurfaceEntry &entry2 = src.entries[i + 1];
|
const Surface::SurfaceEntry &entry2 = src.entries[i + 1];
|
||||||
const Surface::SurfaceEntry &entry3 = src.entries[i + 2];
|
const Surface::SurfaceEntry &entry3 = src.entries[i + 2];
|
||||||
|
const unsigned int verticesNeeded = isDoubleSided ? 6 : 3;
|
||||||
|
if (static_cast<unsigned>(vertices - mesh->mVertices) + verticesNeeded > mesh->mNumVertices) {
|
||||||
|
throw DeadlyImportError("AC3D: Invalid number of vertices");
|
||||||
|
}
|
||||||
|
|
||||||
aiFace &face = *faces++;
|
aiFace &face = *faces++;
|
||||||
face.mNumIndices = 3;
|
face.mNumIndices = 3;
|
||||||
@@ -661,6 +665,10 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
|
|||||||
unsigned int tmp = (unsigned int)(*it).entries.size();
|
unsigned int tmp = (unsigned int)(*it).entries.size();
|
||||||
if (Surface::OpenLine == type) --tmp;
|
if (Surface::OpenLine == type) --tmp;
|
||||||
for (unsigned int m = 0; m < tmp; ++m) {
|
for (unsigned int m = 0; m < tmp; ++m) {
|
||||||
|
if (static_cast<unsigned>(vertices - mesh->mVertices) + 2 > mesh->mNumVertices) {
|
||||||
|
throw DeadlyImportError("AC3D: Invalid number of vertices");
|
||||||
|
}
|
||||||
|
|
||||||
aiFace &face = *faces++;
|
aiFace &face = *faces++;
|
||||||
|
|
||||||
face.mNumIndices = 2;
|
face.mNumIndices = 2;
|
||||||
|
|||||||
@@ -469,9 +469,11 @@ void B3DImporter::ReadBONE(int id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void B3DImporter::ReadKEYS(aiNodeAnim *nodeAnim) {
|
void B3DImporter::ReadKEYS(AnimKeys& keys) {
|
||||||
vector<aiVectorKey> trans, scale;
|
vector<aiVectorKey>& trans = keys.positionKeys;
|
||||||
vector<aiQuatKey> rot;
|
vector<aiVectorKey>& scale = keys.scalingKeys;
|
||||||
|
vector<aiQuatKey>& rot = keys.rotationKeys;
|
||||||
|
|
||||||
int flags = ReadInt();
|
int flags = ReadInt();
|
||||||
while (ChunkSize()) {
|
while (ChunkSize()) {
|
||||||
int frame = ReadInt();
|
int frame = ReadInt();
|
||||||
@@ -485,21 +487,6 @@ void B3DImporter::ReadKEYS(aiNodeAnim *nodeAnim) {
|
|||||||
rot.emplace_back(frame, ReadQuat());
|
rot.emplace_back(frame, ReadQuat());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & 1) {
|
|
||||||
nodeAnim->mNumPositionKeys = static_cast<unsigned int>(trans.size());
|
|
||||||
nodeAnim->mPositionKeys = to_array(trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & 2) {
|
|
||||||
nodeAnim->mNumScalingKeys = static_cast<unsigned int>(scale.size());
|
|
||||||
nodeAnim->mScalingKeys = to_array(scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & 4) {
|
|
||||||
nodeAnim->mNumRotationKeys = static_cast<unsigned int>(rot.size());
|
|
||||||
nodeAnim->mRotationKeys = to_array(rot);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -542,6 +529,7 @@ aiNode *B3DImporter::ReadNODE(aiNode *parent) {
|
|||||||
std::unique_ptr<aiNodeAnim> nodeAnim;
|
std::unique_ptr<aiNodeAnim> nodeAnim;
|
||||||
vector<unsigned> meshes;
|
vector<unsigned> meshes;
|
||||||
vector<aiNode *> children;
|
vector<aiNode *> children;
|
||||||
|
AnimKeys keys;
|
||||||
|
|
||||||
while (ChunkSize()) {
|
while (ChunkSize()) {
|
||||||
const string chunk = ReadChunk();
|
const string chunk = ReadChunk();
|
||||||
@@ -560,7 +548,7 @@ aiNode *B3DImporter::ReadNODE(aiNode *parent) {
|
|||||||
nodeAnim.reset(new aiNodeAnim);
|
nodeAnim.reset(new aiNodeAnim);
|
||||||
nodeAnim->mNodeName = node->mName;
|
nodeAnim->mNodeName = node->mName;
|
||||||
}
|
}
|
||||||
ReadKEYS(nodeAnim.get());
|
ReadKEYS(keys);
|
||||||
} else if (chunk == "NODE") {
|
} else if (chunk == "NODE") {
|
||||||
aiNode *child = ReadNODE(node);
|
aiNode *child = ReadNODE(node);
|
||||||
children.push_back(child);
|
children.push_back(child);
|
||||||
@@ -569,6 +557,21 @@ aiNode *B3DImporter::ReadNODE(aiNode *parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nodeAnim) {
|
if (nodeAnim) {
|
||||||
|
if (!keys.positionKeys.empty()) {
|
||||||
|
nodeAnim->mNumPositionKeys = static_cast<unsigned int>(keys.positionKeys.size());
|
||||||
|
nodeAnim->mPositionKeys = to_array(keys.positionKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keys.scalingKeys.empty()) {
|
||||||
|
nodeAnim->mNumScalingKeys = static_cast<unsigned int>(keys.scalingKeys.size());
|
||||||
|
nodeAnim->mScalingKeys = to_array(keys.scalingKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keys.rotationKeys.empty()) {
|
||||||
|
nodeAnim->mNumRotationKeys = static_cast<unsigned int>(keys.rotationKeys.size());
|
||||||
|
nodeAnim->mRotationKeys = to_array(keys.rotationKeys);
|
||||||
|
}
|
||||||
|
|
||||||
_nodeAnims.emplace_back(std::move(nodeAnim));
|
_nodeAnims.emplace_back(std::move(nodeAnim));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include <assimp/types.h>
|
#include <assimp/types.h>
|
||||||
#include <assimp/mesh.h>
|
#include <assimp/mesh.h>
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/anim.h>
|
||||||
#include <assimp/BaseImporter.h>
|
#include <assimp/BaseImporter.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -94,6 +95,12 @@ private:
|
|||||||
float weights[4];
|
float weights[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AnimKeys {
|
||||||
|
std::vector<aiVectorKey> positionKeys;
|
||||||
|
std::vector<aiVectorKey> scalingKeys;
|
||||||
|
std::vector<aiQuatKey> rotationKeys;
|
||||||
|
};
|
||||||
|
|
||||||
AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
|
AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
|
||||||
AI_WONT_RETURN void Fail(const std::string &str) AI_WONT_RETURN_SUFFIX;
|
AI_WONT_RETURN void Fail(const std::string &str) AI_WONT_RETURN_SUFFIX;
|
||||||
|
|
||||||
@@ -104,7 +111,7 @@ private:
|
|||||||
void ReadTRIS( int v0 );
|
void ReadTRIS( int v0 );
|
||||||
void ReadMESH();
|
void ReadMESH();
|
||||||
void ReadBONE( int id );
|
void ReadBONE( int id );
|
||||||
void ReadKEYS( aiNodeAnim *nodeAnim );
|
void ReadKEYS( AnimKeys& keys );
|
||||||
void ReadANIM();
|
void ReadANIM();
|
||||||
|
|
||||||
aiNode *ReadNODE( aiNode *parent );
|
aiNode *ReadNODE( aiNode *parent );
|
||||||
|
|||||||
@@ -1766,8 +1766,8 @@ void FBXExporter::WriteObjects () {
|
|||||||
// can't easily determine which texture path will be correct,
|
// can't easily determine which texture path will be correct,
|
||||||
// so just store what we have in every field.
|
// so just store what we have in every field.
|
||||||
// these being incorrect is a common problem with FBX anyway.
|
// these being incorrect is a common problem with FBX anyway.
|
||||||
tnode.AddChild("FileName", tp_elem->second);
|
tnode.AddChild("FileName", tfile_path);
|
||||||
tnode.AddChild("RelativeFilename", tp_elem->second);
|
tnode.AddChild("RelativeFilename", tfile_path);
|
||||||
tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0));
|
tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0));
|
||||||
tnode.AddChild("ModelUVScaling", double(1.0), double(1.0));
|
tnode.AddChild("ModelUVScaling", double(1.0), double(1.0));
|
||||||
tnode.AddChild("Texture_Alpha_Source", "None");
|
tnode.AddChild("Texture_Alpha_Source", "None");
|
||||||
|
|||||||
@@ -179,7 +179,8 @@ void AnimResolver::UpdateAnimRangeSetup() {
|
|||||||
case LWO::PrePostBehaviour_Oscillate: {
|
case LWO::PrePostBehaviour_Oscillate: {
|
||||||
const double start_time = delta - std::fmod(my_first - first, delta);
|
const double start_time = delta - std::fmod(my_first - first, delta);
|
||||||
std::vector<LWO::Key>::iterator n = std::find_if((*it).keys.begin(), (*it).keys.end(),
|
std::vector<LWO::Key>::iterator n = std::find_if((*it).keys.begin(), (*it).keys.end(),
|
||||||
[start_time](double t) { return start_time > t; }), m;
|
[start_time](double t) { return start_time > t; });
|
||||||
|
std::vector<LWO::Key>::iterator m;
|
||||||
|
|
||||||
size_t ofs = 0;
|
size_t ofs = 0;
|
||||||
if (n != (*it).keys.end()) {
|
if (n != (*it).keys.end()) {
|
||||||
@@ -211,13 +212,21 @@ void AnimResolver::UpdateAnimRangeSetup() {
|
|||||||
double cur_minus = delta;
|
double cur_minus = delta;
|
||||||
unsigned int tt = 1;
|
unsigned int tt = 1;
|
||||||
for (const double tmp = delta * (num + 1); cur_minus <= tmp; cur_minus += delta, ++tt) {
|
for (const double tmp = delta * (num + 1); cur_minus <= tmp; cur_minus += delta, ++tt) {
|
||||||
m = (delta == tmp ? (*it).keys.begin() : n - (old_size + 1));
|
if (delta == tmp) {
|
||||||
for (; m < n; --n) {
|
m = it->keys.begin();
|
||||||
(*n).time -= cur_minus;
|
} else {
|
||||||
|
ptrdiff_t dist = std::distance((*it).keys.begin(), n);
|
||||||
// offset repeat? add delta offset to key value
|
if (dist <= static_cast<ptrdiff_t>(old_size)) {
|
||||||
|
// clamp to begin to avoid seeking before begin
|
||||||
|
m = (*it).keys.begin();
|
||||||
|
} else {
|
||||||
|
m = n - (old_size + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto it2 = m; it2 != n; ++it2) {
|
||||||
|
it2->time -= cur_minus;
|
||||||
if ((*it).pre == LWO::PrePostBehaviour_OffsetRepeat) {
|
if ((*it).pre == LWO::PrePostBehaviour_OffsetRepeat) {
|
||||||
(*n).value += tt * value_delta;
|
it2->value += tt * value_delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
static const aiImporterDesc desc = {
|
static constexpr aiImporterDesc desc = {
|
||||||
"LightWave/Modo Object Importer",
|
"LightWave/Modo Object Importer",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
@@ -77,30 +77,6 @@ static const aiImporterDesc desc = {
|
|||||||
"lwo lxo"
|
"lwo lxo"
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Constructor to be privately used by Importer
|
|
||||||
LWOImporter::LWOImporter() :
|
|
||||||
mIsLWO2(),
|
|
||||||
mIsLXOB(),
|
|
||||||
mIsLWO3(),
|
|
||||||
mLayers(),
|
|
||||||
mCurLayer(),
|
|
||||||
mTags(),
|
|
||||||
mMapping(),
|
|
||||||
mSurfaces(),
|
|
||||||
mFileBuffer(),
|
|
||||||
fileSize(),
|
|
||||||
mScene(nullptr),
|
|
||||||
configSpeedFlag(),
|
|
||||||
configLayerIndex(),
|
|
||||||
hasNamedLayer() {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Destructor, private as well
|
|
||||||
LWOImporter::~LWOImporter() = default;
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
||||||
@@ -155,6 +131,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mFileBuffer = &mBuffer[0] + 12;
|
mFileBuffer = &mBuffer[0] + 12;
|
||||||
|
mFileBufferEnd = &mBuffer[0] + fileSize;
|
||||||
fileSize -= 12;
|
fileSize -= 12;
|
||||||
|
|
||||||
// Initialize some members with their default values
|
// Initialize some members with their default values
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ struct aiNode;
|
|||||||
struct aiMaterial;
|
struct aiMaterial;
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
using namespace LWO;
|
using namespace LWO;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -68,10 +69,17 @@ using namespace LWO;
|
|||||||
* they aren't specific to one format version
|
* they aren't specific to one format version
|
||||||
*/
|
*/
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
class LWOImporter : public BaseImporter {
|
class LWOImporter final : public BaseImporter {
|
||||||
public:
|
public:
|
||||||
LWOImporter();
|
/**
|
||||||
~LWOImporter() override;
|
* @brief The class constructor.
|
||||||
|
*/
|
||||||
|
LWOImporter() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The class destructor.
|
||||||
|
*/
|
||||||
|
~LWOImporter() override = default;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/** Returns whether the class can handle the format of the given file.
|
||||||
@@ -113,13 +121,13 @@ private:
|
|||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parsing functions used for all file format versions
|
/** Parsing functions used for all file format versions
|
||||||
*/
|
*/
|
||||||
inline void GetS0(std::string &out, unsigned int max);
|
void GetS0(std::string &out, unsigned int max);
|
||||||
inline float GetF4();
|
float GetF4();
|
||||||
inline float GetF8();
|
float GetF8();
|
||||||
inline uint64_t GetU8();
|
uint64_t GetU8();
|
||||||
inline uint32_t GetU4();
|
uint32_t GetU4();
|
||||||
inline uint16_t GetU2();
|
uint16_t GetU2();
|
||||||
inline uint8_t GetU1();
|
uint8_t GetU1();
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Loads a surface chunk from an LWOB file
|
/** Loads a surface chunk from an LWOB file
|
||||||
@@ -353,57 +361,44 @@ private:
|
|||||||
LWO::Texture *SetupNewTextureLWOB(LWO::TextureList &list,
|
LWO::Texture *SetupNewTextureLWOB(LWO::TextureList &list,
|
||||||
unsigned int size);
|
unsigned int size);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
/** true if the file is a LWO2 file*/
|
/// true if the file is a LWO2 file
|
||||||
bool mIsLWO2;
|
bool mIsLWO2{false};
|
||||||
|
/// true if the file is a LXOB file
|
||||||
/** true if the file is a LXOB file*/
|
bool mIsLXOB{false};
|
||||||
bool mIsLXOB;
|
/// true if the file is a LWO3 file
|
||||||
|
bool mIsLWO3{false};
|
||||||
bool mIsLWO3;
|
/// Temporary list of layers from the file
|
||||||
|
LayerList *mLayers{nullptr};
|
||||||
/** Temporary list of layers from the file */
|
/// Pointer to the current layer
|
||||||
LayerList *mLayers;
|
LWO::Layer *mCurLayer{nullptr};
|
||||||
|
/// Temporary tag list from the file
|
||||||
/** Pointer to the current layer */
|
TagList *mTags{nullptr};
|
||||||
LWO::Layer *mCurLayer;
|
/// Mapping table to convert from tag to surface indices.
|
||||||
|
// UINT_MAX indicates that a no corresponding surface is available
|
||||||
/** Temporary tag list from the file */
|
TagMappingTable *mMapping{nullptr};
|
||||||
TagList *mTags;
|
/// Temporary surface list from the file
|
||||||
|
SurfaceList *mSurfaces{nullptr};
|
||||||
/** Mapping table to convert from tag to surface indices.
|
/// Temporary clip list from the file
|
||||||
UINT_MAX indicates that a no corresponding surface is available */
|
ClipList mClips{};
|
||||||
TagMappingTable *mMapping;
|
/// Temporary envelope list from the file
|
||||||
|
EnvelopeList mEnvelopes{};
|
||||||
/** Temporary surface list from the file */
|
/// Pointer to the file buffer
|
||||||
SurfaceList *mSurfaces;
|
uint8_t *mFileBuffer{nullptr};
|
||||||
|
/// Size of the file, in bytes
|
||||||
/** Temporary clip list from the file */
|
unsigned int fileSize{0u};
|
||||||
ClipList mClips;
|
/// End of the file buffer (for bounds checking)
|
||||||
|
uint8_t *mFileBufferEnd{nullptr};
|
||||||
/** Temporary envelope list from the file */
|
/// Output scene
|
||||||
EnvelopeList mEnvelopes;
|
aiScene *mScene{nullptr};
|
||||||
|
/// Configuration option: speed flag set?
|
||||||
/** file buffer */
|
bool configSpeedFlag{false};
|
||||||
uint8_t *mFileBuffer;
|
/// Configuration option: index of layer to be loaded
|
||||||
|
unsigned int configLayerIndex{0};
|
||||||
/** Size of the file, in bytes */
|
/// Configuration option: name of layer to be loaded */
|
||||||
unsigned int fileSize;
|
std::string configLayerName{};
|
||||||
|
/// True if we have a named layer
|
||||||
/** Output scene */
|
bool hasNamedLayer{false};
|
||||||
aiScene *mScene;
|
|
||||||
|
|
||||||
/** Configuration option: speed flag set? */
|
|
||||||
bool configSpeedFlag;
|
|
||||||
|
|
||||||
/** Configuration option: index of layer to be loaded */
|
|
||||||
unsigned int configLayerIndex;
|
|
||||||
|
|
||||||
/** Configuration option: name of layer to be loaded */
|
|
||||||
std::string configLayerName;
|
|
||||||
|
|
||||||
/** True if we have a named layer */
|
|
||||||
bool hasNamedLayer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -415,6 +410,7 @@ inline float LWOImporter::GetF4() {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
inline float LWOImporter::GetF8() {
|
inline float LWOImporter::GetF8() {
|
||||||
double f;
|
double f;
|
||||||
::memcpy(&f, mFileBuffer, 8);
|
::memcpy(&f, mFileBuffer, 8);
|
||||||
@@ -423,6 +419,7 @@ inline float LWOImporter::GetF8() {
|
|||||||
return (float)f;
|
return (float)f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
inline uint64_t LWOImporter::GetU8() {
|
inline uint64_t LWOImporter::GetU8() {
|
||||||
uint64_t f;
|
uint64_t f;
|
||||||
::memcpy(&f, mFileBuffer, 8);
|
::memcpy(&f, mFileBuffer, 8);
|
||||||
@@ -482,16 +479,23 @@ inline int LWOImporter::ReadVSizedIntLWO2(uint8_t *&inout) {
|
|||||||
inline void LWOImporter::GetS0(std::string &out, unsigned int max) {
|
inline void LWOImporter::GetS0(std::string &out, unsigned int max) {
|
||||||
unsigned int iCursor = 0;
|
unsigned int iCursor = 0;
|
||||||
const char *sz = (const char *)mFileBuffer;
|
const char *sz = (const char *)mFileBuffer;
|
||||||
while (*mFileBuffer) {
|
while (mFileBuffer < mFileBufferEnd && *mFileBuffer) {
|
||||||
if (++iCursor > max) {
|
if (++iCursor > max) {
|
||||||
ASSIMP_LOG_WARN("LWO: Invalid file, string is is too long");
|
ASSIMP_LOG_WARN("LWO: Invalid file, string is too long");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++mFileBuffer;
|
++mFileBuffer;
|
||||||
}
|
}
|
||||||
size_t len = (size_t)((const char *)mFileBuffer - sz);
|
size_t len = (size_t)((const char *)mFileBuffer - sz);
|
||||||
out = std::string(sz, len);
|
out = std::string(sz, len);
|
||||||
mFileBuffer += (len & 0x1 ? 1 : 2);
|
|
||||||
|
const size_t skip = (len & 0x1 ? 1u : 2u);
|
||||||
|
const size_t remaining = static_cast<size_t>(mFileBufferEnd - mFileBuffer);
|
||||||
|
if (remaining < skip) {
|
||||||
|
mFileBuffer = mFileBufferEnd;
|
||||||
|
} else {
|
||||||
|
mFileBuffer += skip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|||||||
@@ -971,7 +971,7 @@ void HL1MDLLoader::read_animations() {
|
|||||||
|
|
||||||
pseqdesc = get_buffer_data<SequenceDesc_HL1>(header_->seqindex, header_->numseq);
|
pseqdesc = get_buffer_data<SequenceDesc_HL1>(header_->seqindex, header_->numseq);
|
||||||
|
|
||||||
aiAnimation **scene_animations_ptr = scene_->mAnimations = new aiAnimation *[scene_->mNumAnimations];
|
aiAnimation **scene_animations_ptr = scene_->mAnimations = new aiAnimation *[scene_->mNumAnimations]();
|
||||||
|
|
||||||
for (int sequence = 0; sequence < header_->numseq; ++sequence, ++pseqdesc) {
|
for (int sequence = 0; sequence < header_->numseq; ++sequence, ++pseqdesc) {
|
||||||
pseqgroup = get_buffer_data<SequenceGroup_HL1>(header_->seqgroupindex + pseqdesc->seqgroup * sizeof(SequenceGroup_HL1), 1);
|
pseqgroup = get_buffer_data<SequenceGroup_HL1>(header_->seqgroupindex + pseqdesc->seqgroup * sizeof(SequenceGroup_HL1), 1);
|
||||||
@@ -992,7 +992,7 @@ void HL1MDLLoader::read_animations() {
|
|||||||
scene_animation->mTicksPerSecond = pseqdesc->fps;
|
scene_animation->mTicksPerSecond = pseqdesc->fps;
|
||||||
scene_animation->mDuration = static_cast<double>(pseqdesc->fps) * pseqdesc->numframes;
|
scene_animation->mDuration = static_cast<double>(pseqdesc->fps) * pseqdesc->numframes;
|
||||||
scene_animation->mNumChannels = static_cast<unsigned int>(header_->numbones);
|
scene_animation->mNumChannels = static_cast<unsigned int>(header_->numbones);
|
||||||
scene_animation->mChannels = new aiNodeAnim *[scene_animation->mNumChannels];
|
scene_animation->mChannels = new aiNodeAnim *[scene_animation->mNumChannels]();
|
||||||
|
|
||||||
for (int bone = 0; bone < header_->numbones; bone++, ++pbone, ++panim) {
|
for (int bone = 0; bone < header_->numbones; bone++, ++pbone, ++panim) {
|
||||||
aiNodeAnim *node_anim = scene_animation->mChannels[bone] = new aiNodeAnim();
|
aiNodeAnim *node_anim = scene_animation->mChannels[bone] = new aiNodeAnim();
|
||||||
|
|||||||
@@ -450,12 +450,14 @@ void MDLImporter::InternReadFile_Quake1() {
|
|||||||
BE_NCONST MDL::Frame *pcFrames = (BE_NCONST MDL::Frame *)szCurrent;
|
BE_NCONST MDL::Frame *pcFrames = (BE_NCONST MDL::Frame *)szCurrent;
|
||||||
MDL::SimpleFrame *pcFirstFrame;
|
MDL::SimpleFrame *pcFirstFrame;
|
||||||
|
|
||||||
|
VALIDATE_FILE_SIZE((const unsigned char *)(pcFrames + 1));
|
||||||
if (0 == pcFrames->type) {
|
if (0 == pcFrames->type) {
|
||||||
// get address of single frame
|
// get address of single frame
|
||||||
pcFirstFrame = (MDL::SimpleFrame *)&pcFrames->frame;
|
pcFirstFrame = (MDL::SimpleFrame *)&pcFrames->frame;
|
||||||
} else {
|
} else {
|
||||||
// get the first frame in the group
|
// get the first frame in the group
|
||||||
BE_NCONST MDL::GroupFrame *pcFrames2 = (BE_NCONST MDL::GroupFrame *)szCurrent;
|
BE_NCONST MDL::GroupFrame *pcFrames2 = (BE_NCONST MDL::GroupFrame *)szCurrent;
|
||||||
|
VALIDATE_FILE_SIZE((const unsigned char *)(pcFrames2 + 1));
|
||||||
pcFirstFrame = (MDL::SimpleFrame *)( szCurrent + sizeof(MDL::GroupFrame::type) + sizeof(MDL::GroupFrame::numframes)
|
pcFirstFrame = (MDL::SimpleFrame *)( szCurrent + sizeof(MDL::GroupFrame::type) + sizeof(MDL::GroupFrame::numframes)
|
||||||
+ sizeof(MDL::GroupFrame::min) + sizeof(MDL::GroupFrame::max) + sizeof(*MDL::GroupFrame::times) * pcFrames2->numframes );
|
+ sizeof(MDL::GroupFrame::min) + sizeof(MDL::GroupFrame::max) + sizeof(*MDL::GroupFrame::times) * pcFrames2->numframes );
|
||||||
}
|
}
|
||||||
@@ -703,6 +705,7 @@ void MDLImporter::InternReadFile_3DGS_MDL345() {
|
|||||||
|
|
||||||
// now get a pointer to the first frame in the file
|
// now get a pointer to the first frame in the file
|
||||||
BE_NCONST MDL::Frame *pcFrames = (BE_NCONST MDL::Frame *)szCurrent;
|
BE_NCONST MDL::Frame *pcFrames = (BE_NCONST MDL::Frame *)szCurrent;
|
||||||
|
VALIDATE_FILE_SIZE((const unsigned char *)(pcFrames + 1));
|
||||||
AI_SWAP4(pcFrames->type);
|
AI_SWAP4(pcFrames->type);
|
||||||
|
|
||||||
// byte packed vertices
|
// byte packed vertices
|
||||||
@@ -1173,6 +1176,7 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7 &groupInf
|
|||||||
for (unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes; ++iFrame) {
|
for (unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes; ++iFrame) {
|
||||||
MDL::IntFrameInfo_MDL7 frame((BE_NCONST MDL::Frame_MDL7 *)szCurrent, iFrame);
|
MDL::IntFrameInfo_MDL7 frame((BE_NCONST MDL::Frame_MDL7 *)szCurrent, iFrame);
|
||||||
|
|
||||||
|
VALIDATE_FILE_SIZE((const unsigned char *)(frame.pcFrame + 1));
|
||||||
AI_SWAP4(frame.pcFrame->vertices_count);
|
AI_SWAP4(frame.pcFrame->vertices_count);
|
||||||
AI_SWAP4(frame.pcFrame->transmatrix_count);
|
AI_SWAP4(frame.pcFrame->transmatrix_count);
|
||||||
|
|
||||||
|
|||||||
+274
-266
@@ -57,58 +57,73 @@ namespace Assimp {
|
|||||||
|
|
||||||
constexpr const char ObjFileParser::DEFAULT_MATERIAL[];
|
constexpr const char ObjFileParser::DEFAULT_MATERIAL[];
|
||||||
|
|
||||||
ObjFileParser::ObjFileParser() :
|
// -------------------------------------------------------------------
|
||||||
m_DataIt(),
|
static bool isDataDefinitionEnd(const char *tmp) {
|
||||||
m_DataItEnd(),
|
ai_assert(tmp != nullptr);
|
||||||
m_pModel(nullptr),
|
|
||||||
m_uiLine(0),
|
if (*tmp == '\\') {
|
||||||
m_buffer(),
|
++tmp;
|
||||||
mEnd(&m_buffer[Buffersize]),
|
if (IsLineEnd(*tmp)) {
|
||||||
m_pIO(nullptr),
|
return true;
|
||||||
m_progress(nullptr),
|
}
|
||||||
m_originalObjFileName() {
|
}
|
||||||
std::fill_n(m_buffer, Buffersize, '\0');
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
static bool isNanOrInf(const char *in) {
|
||||||
|
ai_assert(in != nullptr);
|
||||||
|
|
||||||
|
// Look for "nan" or "inf", case insensitive
|
||||||
|
return ((in[0] == 'N' || in[0] == 'n') && ASSIMP_strincmp(in, "nan", 3) == 0) ||
|
||||||
|
((in[0] == 'I' || in[0] == 'i') && ASSIMP_strincmp(in, "inf", 3) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
ObjFileParser::ObjFileParser() : mEnd(&mBuffer[Buffersize-1]+1) {
|
||||||
|
std::fill_n(mBuffer, Buffersize, '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
ObjFileParser::ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::string &modelName,
|
ObjFileParser::ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::string &modelName,
|
||||||
IOSystem *io, ProgressHandler *progress,
|
IOSystem *io, ProgressHandler *progress, const std::string &originalObjFileName) :
|
||||||
const std::string &originalObjFileName) :
|
mIO(io),
|
||||||
m_DataIt(),
|
mProgress(progress),
|
||||||
m_DataItEnd(),
|
mOriginalObjFileName(originalObjFileName) {
|
||||||
m_pModel(nullptr),
|
std::fill_n(mBuffer, Buffersize, '\0');
|
||||||
m_uiLine(0),
|
|
||||||
m_buffer(),
|
|
||||||
m_pIO(io),
|
|
||||||
m_progress(progress),
|
|
||||||
m_originalObjFileName(originalObjFileName) {
|
|
||||||
std::fill_n(m_buffer, Buffersize, '\0');
|
|
||||||
|
|
||||||
// Create the model instance to store all the data
|
// Create the model instance to store all the data
|
||||||
m_pModel.reset(new ObjFile::Model());
|
mModel.reset(new ObjFile::Model());
|
||||||
m_pModel->mModelName = modelName;
|
mModel->mModelName = modelName;
|
||||||
|
|
||||||
// create default material and store it
|
// create default material and store it
|
||||||
m_pModel->mDefaultMaterial = new ObjFile::Material;
|
mModel->mDefaultMaterial = new ObjFile::Material;
|
||||||
m_pModel->mDefaultMaterial->MaterialName.Set(DEFAULT_MATERIAL);
|
mModel->mDefaultMaterial->MaterialName.Set(DEFAULT_MATERIAL);
|
||||||
m_pModel->mMaterialLib.emplace_back(DEFAULT_MATERIAL);
|
mModel->mMaterialLib.emplace_back(DEFAULT_MATERIAL);
|
||||||
m_pModel->mMaterialMap[DEFAULT_MATERIAL] = m_pModel->mDefaultMaterial;
|
mModel->mMaterialMap[DEFAULT_MATERIAL] = mModel->mDefaultMaterial;
|
||||||
|
|
||||||
// Start parsing the file
|
// Start parsing the file
|
||||||
parseFile(streamBuffer);
|
parseFile(streamBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjFileParser::setBuffer(std::vector<char> &buffer) {
|
void ObjFileParser::setBuffer(std::vector<char> &buffer) {
|
||||||
m_DataIt = buffer.begin();
|
mDataIt = buffer.begin();
|
||||||
m_DataItEnd = buffer.end();
|
mDataItEnd = buffer.end();
|
||||||
|
ai_assert(mDataIt < mDataItEnd);
|
||||||
|
if (!buffer.empty()) {
|
||||||
|
mEnd = &buffer[buffer.size() - 1] + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
ObjFile::Model *ObjFileParser::GetModel() const {
|
ObjFile::Model *ObjFileParser::GetModel() const {
|
||||||
return m_pModel.get();
|
return mModel.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
||||||
// only update every 100KB or it'll be too slow
|
// only update every 100KB or it'll be too slow
|
||||||
//const unsigned int updateProgressEveryBytes = 100 * 1024;
|
// const unsigned int updateProgressEveryBytes = 100 * 1024;
|
||||||
const unsigned int bytesToProcess = static_cast<unsigned int>(streamBuffer.size());
|
const unsigned int bytesToProcess = static_cast<unsigned int>(streamBuffer.size());
|
||||||
const unsigned int progressTotal = bytesToProcess;
|
const unsigned int progressTotal = bytesToProcess;
|
||||||
unsigned int processed = 0u;
|
unsigned int processed = 0u;
|
||||||
@@ -117,90 +132,93 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
|||||||
bool insideCstype = false;
|
bool insideCstype = false;
|
||||||
std::vector<char> buffer;
|
std::vector<char> buffer;
|
||||||
while (streamBuffer.getNextDataLine(buffer, '\\')) {
|
while (streamBuffer.getNextDataLine(buffer, '\\')) {
|
||||||
m_DataIt = buffer.begin();
|
mDataIt = buffer.begin();
|
||||||
m_DataItEnd = buffer.end();
|
mDataItEnd = buffer.end();
|
||||||
mEnd = &buffer[buffer.size() - 1] + 1;
|
mEnd = &buffer[buffer.size() - 1] + 1;
|
||||||
|
|
||||||
if (processed == 0 && std::distance(m_DataIt, m_DataItEnd) >= 3 &&
|
if (processed == 0 && std::distance(mDataIt, mDataItEnd) >= 3 &&
|
||||||
static_cast<unsigned char>(*m_DataIt) == 0xEF &&
|
static_cast<unsigned char>(*mDataIt) == 0xEF &&
|
||||||
static_cast<unsigned char>(*(m_DataIt + 1)) == 0xBB &&
|
static_cast<unsigned char>(*(mDataIt + 1)) == 0xBB &&
|
||||||
static_cast<unsigned char>(*(m_DataIt + 2)) == 0xBF) {
|
static_cast<unsigned char>(*(mDataIt + 2)) == 0xBF) {
|
||||||
m_DataIt += 3; // skip BOM
|
mDataIt += 3; // skip BOM
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle progress reporting
|
// Handle progress reporting
|
||||||
const size_t filePos(streamBuffer.getFilePos());
|
const size_t filePos = streamBuffer.getFilePos();
|
||||||
if (lastFilePos < filePos) {
|
if (lastFilePos < filePos) {
|
||||||
processed = static_cast<unsigned int>(filePos);
|
processed = static_cast<unsigned int>(filePos);
|
||||||
lastFilePos = filePos;
|
lastFilePos = filePos;
|
||||||
m_progress->UpdateFileRead(processed, progressTotal);
|
if (mProgress != nullptr) {
|
||||||
|
mProgress->UpdateFileRead(processed, progressTotal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle c-stype section end (http://paulbourke.net/dataformats/obj/)
|
// handle c-stype section end (http://paulbourke.net/dataformats/obj/)
|
||||||
if (insideCstype) {
|
if (insideCstype) {
|
||||||
switch (*m_DataIt) {
|
switch (*mDataIt) {
|
||||||
case 'e': {
|
case 'e': {
|
||||||
std::string name;
|
std::string name;
|
||||||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
getNameNoSpace(mDataIt, mDataItEnd, name);
|
||||||
insideCstype = name != "end";
|
insideCstype = name != "end";
|
||||||
} break;
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
goto pf_skip_line;
|
goto pf_skip_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse line
|
// parse line
|
||||||
switch (*m_DataIt) {
|
switch (*mDataIt) {
|
||||||
case 'v': // Parse a vertex texture coordinate
|
case 'v': // Parse a vertex texture coordinate
|
||||||
{
|
{
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
if (*m_DataIt == ' ' || *m_DataIt == '\t') {
|
if (*mDataIt == ' ' || *mDataIt == '\t') {
|
||||||
size_t numComponents = getNumComponentsInDataDefinition();
|
size_t numComponents = getNumComponentsInDataDefinition();
|
||||||
if (numComponents == 3) {
|
if (numComponents == 3) {
|
||||||
// read in vertex definition
|
// read in vertex definition
|
||||||
getVector3(m_pModel->mVertices);
|
getVector3(mModel->mVertices);
|
||||||
} else if (numComponents == 4) {
|
} else if (numComponents == 4) {
|
||||||
// read in vertex definition (homogeneous coords)
|
// read in vertex definition (homogeneous coords)
|
||||||
getHomogeneousVector3(m_pModel->mVertices);
|
getHomogeneousVector3(mModel->mVertices);
|
||||||
} else if (numComponents == 6) {
|
} else if (numComponents == 6) {
|
||||||
// fill previous omitted vertex-colors by default
|
// fill previous omitted vertex-colors by default
|
||||||
if (m_pModel->mVertexColors.size() < m_pModel->mVertices.size()) {
|
if (mModel->mVertexColors.size() < mModel->mVertices.size()) {
|
||||||
m_pModel->mVertexColors.resize(m_pModel->mVertices.size(), aiVector3D(0, 0, 0));
|
mModel->mVertexColors.resize(mModel->mVertices.size(), aiVector3D(0, 0, 0));
|
||||||
}
|
}
|
||||||
// read vertex and vertex-color
|
// read vertex and vertex-color
|
||||||
getTwoVectors3(m_pModel->mVertices, m_pModel->mVertexColors);
|
getTwoVectors3(mModel->mVertices, mModel->mVertexColors);
|
||||||
}
|
}
|
||||||
// append omitted vertex-colors as default for the end if any vertex-color exists
|
// append omitted vertex-colors as default for the end if any vertex-color exists
|
||||||
if (!m_pModel->mVertexColors.empty() && m_pModel->mVertexColors.size() < m_pModel->mVertices.size()) {
|
if (!mModel->mVertexColors.empty() && mModel->mVertexColors.size() < mModel->mVertices.size()) {
|
||||||
m_pModel->mVertexColors.resize(m_pModel->mVertices.size(), aiVector3D(0, 0, 0));
|
mModel->mVertexColors.resize(mModel->mVertices.size(), aiVector3D(0, 0, 0));
|
||||||
}
|
}
|
||||||
} else if (*m_DataIt == 't') {
|
} else if (*mDataIt == 't') {
|
||||||
// read in texture coordinate ( 2D or 3D )
|
// read in texture coordinate ( 2D or 3D )
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
size_t dim = getTexCoordVector(m_pModel->mTextureCoord);
|
size_t dim = getTexCoordVector(mModel->mTextureCoord);
|
||||||
m_pModel->mTextureCoordDim = std::max(m_pModel->mTextureCoordDim, (unsigned int)dim);
|
mModel->mTextureCoordDim = std::max(mModel->mTextureCoordDim, (unsigned int)dim);
|
||||||
} else if (*m_DataIt == 'n') {
|
} else if (*mDataIt == 'n') {
|
||||||
// Read in normal vector definition
|
// Read in normal vector definition
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
getVector3(m_pModel->mNormals);
|
getVector3(mModel->mNormals);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 'p': // Parse a face, line or point statement
|
case 'p': // Parse a face, line or point statement
|
||||||
case 'l':
|
case 'l':
|
||||||
case 'f': {
|
case 'f': {
|
||||||
getFace(*m_DataIt == 'f' ? aiPrimitiveType_POLYGON : (*m_DataIt == 'l' ? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
|
getFace(*mDataIt == 'f' ? aiPrimitiveType_POLYGON : (*mDataIt == 'l' ? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case '#': // Parse a comment
|
case '#': // Parse a comment
|
||||||
{
|
{
|
||||||
getComment();
|
skipComment();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 'u': // Parse a material desc. setter
|
case 'u': // Parse a material desc. setter
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
|
getNameNoSpace(mDataIt, mDataItEnd, name);
|
||||||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
|
||||||
|
|
||||||
size_t nextSpace = name.find(' ');
|
size_t nextSpace = name.find(' ');
|
||||||
if (nextSpace != std::string::npos)
|
if (nextSpace != std::string::npos)
|
||||||
@@ -215,14 +233,14 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
|||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
getNameNoSpace(mDataIt, mDataItEnd, name);
|
||||||
|
|
||||||
size_t nextSpace = name.find(' ');
|
size_t nextSpace = name.find(' ');
|
||||||
if (nextSpace != std::string::npos)
|
if (nextSpace != std::string::npos)
|
||||||
name = name.substr(0, nextSpace);
|
name = name.substr(0, nextSpace);
|
||||||
|
|
||||||
if (name == "mg")
|
if (name == "mg")
|
||||||
getGroupNumberAndResolution();
|
skipGroupNumberAndResolution();
|
||||||
else if (name == "mtllib")
|
else if (name == "mtllib")
|
||||||
getMaterialLib();
|
getMaterialLib();
|
||||||
else
|
else
|
||||||
@@ -236,7 +254,7 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
|||||||
|
|
||||||
case 's': // Parse group number
|
case 's': // Parse group number
|
||||||
{
|
{
|
||||||
getGroupNumber();
|
skipGroupNumber();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 'o': // Parse object name
|
case 'o': // Parse object name
|
||||||
@@ -247,59 +265,45 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
|||||||
case 'c': // handle cstype section start
|
case 'c': // handle cstype section start
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
getNameNoSpace(mDataIt, mDataItEnd, name);
|
||||||
insideCstype = name == "cstype";
|
insideCstype = name == "cstype";
|
||||||
goto pf_skip_line;
|
goto pf_skip_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
pf_skip_line:
|
pf_skip_line:
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
|
void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
|
mDataIt = getNextWord<DataArrayIt>(mDataIt, mDataItEnd);
|
||||||
if (*m_DataIt == '\\') {
|
if (*mDataIt == '\\') {
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
|
mDataIt = getNextWord<DataArrayIt>(mDataIt, mDataItEnd);
|
||||||
}
|
}
|
||||||
while (m_DataIt != m_DataItEnd && !IsSpaceOrNewLine(*m_DataIt)) {
|
while (mDataIt != mDataItEnd && !IsSpaceOrNewLine(*mDataIt)) {
|
||||||
pBuffer[index] = *m_DataIt;
|
pBuffer[index] = *mDataIt;
|
||||||
index++;
|
index++;
|
||||||
if (index == length - 1) {
|
if (index == length - 1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
}
|
}
|
||||||
|
|
||||||
ai_assert(index < length);
|
ai_assert(index < length);
|
||||||
pBuffer[index] = '\0';
|
pBuffer[index] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isDataDefinitionEnd(const char *tmp) {
|
// -------------------------------------------------------------------
|
||||||
if (*tmp == '\\') {
|
|
||||||
tmp++;
|
|
||||||
if (IsLineEnd(*tmp)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isNanOrInf(const char *in) {
|
|
||||||
// Look for "nan" or "inf", case insensitive
|
|
||||||
return ((in[0] == 'N' || in[0] == 'n') && ASSIMP_strincmp(in, "nan", 3) == 0) ||
|
|
||||||
((in[0] == 'I' || in[0] == 'i') && ASSIMP_strincmp(in, "inf", 3) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ObjFileParser::getNumComponentsInDataDefinition() {
|
size_t ObjFileParser::getNumComponentsInDataDefinition() {
|
||||||
size_t numComponents(0);
|
size_t numComponents(0);
|
||||||
const char *tmp(&m_DataIt[0]);
|
const char *tmp = &mDataIt[0];
|
||||||
bool end_of_definition = false;
|
bool end_of_definition = false;
|
||||||
while (!end_of_definition) {
|
while (!end_of_definition) {
|
||||||
if (isDataDefinitionEnd(tmp)) {
|
if (isDataDefinitionEnd(tmp)) {
|
||||||
@@ -323,25 +327,26 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() {
|
|||||||
return numComponents;
|
return numComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
size_t ObjFileParser::getTexCoordVector(std::vector<aiVector3D> &point3d_array) {
|
size_t ObjFileParser::getTexCoordVector(std::vector<aiVector3D> &point3d_array) {
|
||||||
size_t numComponents = getNumComponentsInDataDefinition();
|
size_t numComponents = getNumComponentsInDataDefinition();
|
||||||
ai_real x, y, z;
|
ai_real x, y, z;
|
||||||
if (2 == numComponents) {
|
if (2 == numComponents) {
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
x = (ai_real)fast_atof(m_buffer);
|
x = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
y = (ai_real)fast_atof(m_buffer);
|
y = fast_atof(mBuffer);
|
||||||
z = 0.0;
|
z = 0.0;
|
||||||
} else if (3 == numComponents) {
|
} else if (3 == numComponents) {
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
x = (ai_real)fast_atof(m_buffer);
|
x = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
y = (ai_real)fast_atof(m_buffer);
|
y = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
z = (ai_real)fast_atof(m_buffer);
|
z = fast_atof(mBuffer);
|
||||||
} else {
|
} else {
|
||||||
throw DeadlyImportError("OBJ: Invalid number of components");
|
throw DeadlyImportError("OBJ: Invalid number of components");
|
||||||
}
|
}
|
||||||
@@ -357,121 +362,126 @@ size_t ObjFileParser::getTexCoordVector(std::vector<aiVector3D> &point3d_array)
|
|||||||
z = 0;
|
z = 0;
|
||||||
|
|
||||||
point3d_array.emplace_back(x, y, z);
|
point3d_array.emplace_back(x, y, z);
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
return numComponents;
|
return numComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
|
void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
|
||||||
ai_real x, y, z;
|
ai_real x, y, z;
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
x = (ai_real)fast_atof(m_buffer);
|
x = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
y = (ai_real)fast_atof(m_buffer);
|
y = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
z = (ai_real)fast_atof(m_buffer);
|
z = fast_atof(mBuffer);
|
||||||
|
|
||||||
point3d_array.emplace_back(x, y, z);
|
point3d_array.emplace_back(x, y, z);
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
void ObjFileParser::getHomogeneousVector3(std::vector<aiVector3D> &point3d_array) {
|
void ObjFileParser::getHomogeneousVector3(std::vector<aiVector3D> &point3d_array) {
|
||||||
ai_real x, y, z, w;
|
ai_real x, y, z, w;
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
x = (ai_real)fast_atof(m_buffer);
|
x = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
y = (ai_real)fast_atof(m_buffer);
|
y = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
z = (ai_real)fast_atof(m_buffer);
|
z = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
w = (ai_real)fast_atof(m_buffer);
|
w = fast_atof(mBuffer);
|
||||||
|
|
||||||
if (w == 0)
|
if (w == 0)
|
||||||
throw DeadlyImportError("OBJ: Invalid component in homogeneous vector (Division by zero)");
|
throw DeadlyImportError("OBJ: Invalid component in homogeneous vector (Division by zero)");
|
||||||
|
|
||||||
point3d_array.emplace_back(x / w, y / w, z / w);
|
point3d_array.emplace_back(x / w, y / w, z / w);
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
void ObjFileParser::getTwoVectors3(std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b) {
|
void ObjFileParser::getTwoVectors3(std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b) {
|
||||||
ai_real x, y, z;
|
ai_real x, y, z;
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
x = (ai_real)fast_atof(m_buffer);
|
x = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
y = (ai_real)fast_atof(m_buffer);
|
y = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
z = (ai_real)fast_atof(m_buffer);
|
z = fast_atof(mBuffer);
|
||||||
|
|
||||||
point3d_array_a.emplace_back(x, y, z);
|
point3d_array_a.emplace_back(x, y, z);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
x = (ai_real)fast_atof(m_buffer);
|
x = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
y = (ai_real)fast_atof(m_buffer);
|
y = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
z = (ai_real)fast_atof(m_buffer);
|
z = fast_atof(mBuffer);
|
||||||
|
|
||||||
point3d_array_b.emplace_back(x, y, z);
|
point3d_array_b.emplace_back(x, y, z);
|
||||||
|
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
void ObjFileParser::getVector2(std::vector<aiVector2D> &point2d_array) {
|
void ObjFileParser::getVector2(std::vector<aiVector2D> &point2d_array) {
|
||||||
ai_real x, y;
|
ai_real x, y;
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
x = (ai_real)fast_atof(m_buffer);
|
x = fast_atof(mBuffer);
|
||||||
|
|
||||||
copyNextWord(m_buffer, Buffersize);
|
copyNextWord(mBuffer, Buffersize);
|
||||||
y = (ai_real)fast_atof(m_buffer);
|
y = fast_atof(mBuffer);
|
||||||
|
|
||||||
point2d_array.emplace_back(x, y);
|
point2d_array.emplace_back(x, y);
|
||||||
|
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr char DefaultObjName[] = "defaultobject";
|
static constexpr char DefaultObjName[] = "defaultobject";
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
void ObjFileParser::getFace(aiPrimitiveType type) {
|
void ObjFileParser::getFace(aiPrimitiveType type) {
|
||||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
|
||||||
if (m_DataIt == m_DataItEnd || *m_DataIt == '\0') {
|
if (mDataIt == mDataItEnd || *mDataIt == '\0') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjFile::Face *face = new ObjFile::Face(type);
|
ObjFile::Face *face = new ObjFile::Face(type);
|
||||||
bool hasNormal = false;
|
bool hasNormal = false;
|
||||||
|
|
||||||
const int vSize = static_cast<unsigned int>(m_pModel->mVertices.size());
|
const int vSize = static_cast<unsigned int>(mModel->mVertices.size());
|
||||||
const int vtSize = static_cast<unsigned int>(m_pModel->mTextureCoord.size());
|
const int vtSize = static_cast<unsigned int>(mModel->mTextureCoord.size());
|
||||||
const int vnSize = static_cast<unsigned int>(m_pModel->mNormals.size());
|
const int vnSize = static_cast<unsigned int>(mModel->mNormals.size());
|
||||||
|
|
||||||
const bool vt = (!m_pModel->mTextureCoord.empty());
|
const bool vt = (!mModel->mTextureCoord.empty());
|
||||||
const bool vn = (!m_pModel->mNormals.empty());
|
const bool vn = (!mModel->mNormals.empty());
|
||||||
int iPos = 0;
|
int iPos = 0;
|
||||||
while (m_DataIt < m_DataItEnd) {
|
while (mDataIt < mDataItEnd) {
|
||||||
int iStep = 1;
|
int iStep = 1;
|
||||||
|
|
||||||
if (IsLineEnd(*m_DataIt) || *m_DataIt == '#') {
|
if (IsLineEnd(*mDataIt) || *mDataIt == '#') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*m_DataIt == '/') {
|
if (*mDataIt == '/') {
|
||||||
if (type == aiPrimitiveType_POINT) {
|
if (type == aiPrimitiveType_POINT) {
|
||||||
ASSIMP_LOG_ERROR("Obj: Separator unexpected in point statement");
|
ASSIMP_LOG_ERROR("Obj: Separator unexpected in point statement");
|
||||||
}
|
}
|
||||||
iPos++;
|
++iPos;
|
||||||
} else if (IsSpaceOrNewLine(*m_DataIt)) {
|
} else if (IsSpaceOrNewLine(*mDataIt) || *mDataIt == '\v') {
|
||||||
iPos = 0;
|
iPos = 0;
|
||||||
} else {
|
} else {
|
||||||
//OBJ USES 1 Base ARRAYS!!!!
|
//OBJ USES 1 Base ARRAYS!!!!
|
||||||
const int iVal = ::atoi(&(*m_DataIt));
|
const int iVal = ::atoi(&(*mDataIt));
|
||||||
|
|
||||||
// increment iStep position based off of the sign and # of digits
|
// increment iStep position based off of the sign and # of digits
|
||||||
int tmp = iVal;
|
int tmp = iVal;
|
||||||
@@ -516,62 +526,63 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
|
|||||||
throw DeadlyImportError("OBJ: Invalid face index.");
|
throw DeadlyImportError("OBJ: Invalid face index.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_DataIt += iStep;
|
mDataIt += iStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (face->m_vertices.empty()) {
|
if (face->m_vertices.empty()) {
|
||||||
ASSIMP_LOG_ERROR("Obj: Ignoring empty face");
|
ASSIMP_LOG_ERROR("Obj: Ignoring empty face");
|
||||||
// skip line and clean up
|
// skip line and clean up
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
delete face;
|
delete face;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set active material, if one set
|
// Set active material, if one set
|
||||||
if (nullptr != m_pModel->mCurrentMaterial) {
|
if (nullptr != mModel->mCurrentMaterial) {
|
||||||
face->m_pMaterial = m_pModel->mCurrentMaterial;
|
face->m_pMaterial = mModel->mCurrentMaterial;
|
||||||
} else {
|
} else {
|
||||||
face->m_pMaterial = m_pModel->mDefaultMaterial;
|
face->m_pMaterial = mModel->mDefaultMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a default object, if nothing is there
|
// Create a default object, if nothing is there
|
||||||
if (nullptr == m_pModel->mCurrentObject) {
|
if (nullptr == mModel->mCurrentObject) {
|
||||||
createObject(DefaultObjName);
|
createObject(DefaultObjName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign face to mesh
|
// Assign face to mesh
|
||||||
if (nullptr == m_pModel->mCurrentMesh) {
|
if (nullptr == mModel->mCurrentMesh) {
|
||||||
createMesh(DefaultObjName);
|
createMesh(DefaultObjName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the face
|
// Store the face
|
||||||
m_pModel->mCurrentMesh->m_Faces.emplace_back(face);
|
mModel->mCurrentMesh->m_Faces.emplace_back(face);
|
||||||
m_pModel->mCurrentMesh->m_uiNumIndices += static_cast<unsigned int>(face->m_vertices.size());
|
mModel->mCurrentMesh->m_uiNumIndices += static_cast<unsigned int>(face->m_vertices.size());
|
||||||
m_pModel->mCurrentMesh->m_uiUVCoordinates[0] += static_cast<unsigned int>(face->m_texturCoords.size());
|
mModel->mCurrentMesh->m_uiUVCoordinates[0] += static_cast<unsigned int>(face->m_texturCoords.size());
|
||||||
if (!m_pModel->mCurrentMesh->m_hasNormals && hasNormal) {
|
if (!mModel->mCurrentMesh->m_hasNormals && hasNormal) {
|
||||||
m_pModel->mCurrentMesh->m_hasNormals = true;
|
mModel->mCurrentMesh->m_hasNormals = true;
|
||||||
}
|
}
|
||||||
// Skip the rest of the line
|
// Skip the rest of the line
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
void ObjFileParser::getMaterialDesc() {
|
void ObjFileParser::getMaterialDesc() {
|
||||||
// Get next data for material data
|
// Get next data for material data
|
||||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
|
||||||
if (m_DataIt == m_DataItEnd) {
|
if (mDataIt == mDataItEnd) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pStart = &(*m_DataIt);
|
char *pStart = &(*mDataIt);
|
||||||
while (m_DataIt != m_DataItEnd && !IsLineEnd(*m_DataIt)) {
|
while (mDataIt != mDataItEnd && !IsLineEnd(*mDataIt)) {
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In some cases we should ignore this 'usemtl' command, this variable helps us to do so
|
// In some cases we should ignore this 'usemtl' command, this variable helps us to do so
|
||||||
bool skip = false;
|
bool skip = false;
|
||||||
|
|
||||||
// Get name
|
// Get name
|
||||||
std::string strName(pStart, &(*m_DataIt));
|
std::string strName(pStart, &(*mDataIt));
|
||||||
strName = ai_trim(strName);
|
strName = ai_trim(strName);
|
||||||
if (strName.empty()) {
|
if (strName.empty()) {
|
||||||
skip = true;
|
skip = true;
|
||||||
@@ -580,63 +591,62 @@ void ObjFileParser::getMaterialDesc() {
|
|||||||
// If the current mesh has the same material, we will ignore that 'usemtl' command
|
// If the current mesh has the same material, we will ignore that 'usemtl' command
|
||||||
// There is no need to create another object or even mesh here
|
// There is no need to create another object or even mesh here
|
||||||
if (!skip) {
|
if (!skip) {
|
||||||
if (m_pModel->mCurrentMaterial && m_pModel->mCurrentMaterial->MaterialName == aiString(strName)) {
|
if (mModel->mCurrentMaterial && mModel->mCurrentMaterial->MaterialName == aiString(strName)) {
|
||||||
skip = true;
|
skip = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip) {
|
if (!skip) {
|
||||||
// Search for material
|
// Search for material
|
||||||
std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->mMaterialMap.find(strName);
|
std::map<std::string, ObjFile::Material *>::iterator it = mModel->mMaterialMap.find(strName);
|
||||||
if (it == m_pModel->mMaterialMap.end()) {
|
if (it == mModel->mMaterialMap.end()) {
|
||||||
// Not found, so we don't know anything about the material except for its name.
|
// Not found, so we don't know anything about the material except for its name.
|
||||||
// This may be the case if the material library is missing. We don't want to lose all
|
// This may be the case if the material library is missing. We don't want to lose all
|
||||||
// materials if that happens, so create a new named material instead of discarding it
|
// materials if that happens, so create a new named material instead of discarding it
|
||||||
// completely.
|
// completely.
|
||||||
ASSIMP_LOG_ERROR("OBJ: failed to locate material ", strName, ", creating new material");
|
ASSIMP_LOG_ERROR("OBJ: failed to locate material ", strName, ", creating new material");
|
||||||
m_pModel->mCurrentMaterial = new ObjFile::Material();
|
mModel->mCurrentMaterial = new ObjFile::Material();
|
||||||
m_pModel->mCurrentMaterial->MaterialName.Set(strName);
|
mModel->mCurrentMaterial->MaterialName.Set(strName);
|
||||||
m_pModel->mMaterialLib.push_back(strName);
|
mModel->mMaterialLib.push_back(strName);
|
||||||
m_pModel->mMaterialMap[strName] = m_pModel->mCurrentMaterial;
|
mModel->mMaterialMap[strName] = mModel->mCurrentMaterial;
|
||||||
} else {
|
} else {
|
||||||
// Found, using detected material
|
// Found, using detected material
|
||||||
m_pModel->mCurrentMaterial = (*it).second;
|
mModel->mCurrentMaterial = it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsNewMesh(strName)) {
|
if (needsNewMesh(strName)) {
|
||||||
auto newMeshName = m_pModel->mActiveGroup.empty() ? strName : m_pModel->mActiveGroup;
|
auto newMeshName = mModel->mActiveGroup.empty() ? strName : mModel->mActiveGroup;
|
||||||
createMesh(newMeshName);
|
createMesh(newMeshName);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pModel->mCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
|
mModel->mCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip rest of line
|
// Skip rest of line
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Get a comment, values will be skipped
|
// Get a comment, values will be skipped
|
||||||
void ObjFileParser::getComment() {
|
void ObjFileParser::skipComment() {
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Get material library from file.
|
|
||||||
void ObjFileParser::getMaterialLib() {
|
void ObjFileParser::getMaterialLib() {
|
||||||
// Translate tuple
|
// Translate tuple
|
||||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
|
||||||
if (m_DataIt == m_DataItEnd) {
|
if (mDataIt == mDataItEnd) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pStart = &(*m_DataIt);
|
char *pStart = &(*mDataIt);
|
||||||
while (m_DataIt != m_DataItEnd && !IsLineEnd(*m_DataIt)) {
|
while (mDataIt != mDataItEnd && !IsLineEnd(*mDataIt)) {
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for existence
|
// Check for existence
|
||||||
const std::string strMatName(pStart, &(*m_DataIt));
|
const std::string strMatName(pStart, &(*mDataIt));
|
||||||
std::string absName;
|
std::string absName;
|
||||||
|
|
||||||
// Check if directive is valid.
|
// Check if directive is valid.
|
||||||
@@ -645,8 +655,8 @@ void ObjFileParser::getMaterialLib() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pIO->StackSize() > 0) {
|
if (mIO->StackSize() > 0) {
|
||||||
std::string path = m_pIO->CurrentDirectory();
|
std::string path = mIO->CurrentDirectory();
|
||||||
if ('/' != *path.rbegin()) {
|
if ('/' != *path.rbegin()) {
|
||||||
path += '/';
|
path += '/';
|
||||||
}
|
}
|
||||||
@@ -656,15 +666,15 @@ void ObjFileParser::getMaterialLib() {
|
|||||||
absName = strMatName;
|
absName = strMatName;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IOStream> pFile(m_pIO->Open(absName));
|
std::unique_ptr<IOStream> pFile(mIO->Open(absName));
|
||||||
if (nullptr == pFile) {
|
if (nullptr == pFile) {
|
||||||
ASSIMP_LOG_ERROR("OBJ: Unable to locate material file ", strMatName);
|
ASSIMP_LOG_ERROR("OBJ: Unable to locate material file ", strMatName);
|
||||||
std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl";
|
std::string strMatFallbackName = mOriginalObjFileName.substr(0, mOriginalObjFileName.length() - 3) + "mtl";
|
||||||
ASSIMP_LOG_INFO("OBJ: Opening fallback material file ", strMatFallbackName);
|
ASSIMP_LOG_INFO("OBJ: Opening fallback material file ", strMatFallbackName);
|
||||||
pFile.reset(m_pIO->Open(strMatFallbackName));
|
pFile.reset(mIO->Open(strMatFallbackName));
|
||||||
if (!pFile) {
|
if (!pFile) {
|
||||||
ASSIMP_LOG_ERROR("OBJ: Unable to locate fallback material file ", strMatFallbackName);
|
ASSIMP_LOG_ERROR("OBJ: Unable to locate fallback material file ", strMatFallbackName);
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -678,47 +688,48 @@ void ObjFileParser::getMaterialLib() {
|
|||||||
//m_pIO->Close(pFile);
|
//m_pIO->Close(pFile);
|
||||||
|
|
||||||
// Importing the material library
|
// Importing the material library
|
||||||
ObjFileMtlImporter mtlImporter(buffer, strMatName, m_pModel.get());
|
ObjFileMtlImporter mtlImporter(buffer, strMatName, mModel.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Set a new material definition as the current material.
|
|
||||||
void ObjFileParser::getNewMaterial() {
|
void ObjFileParser::getNewMaterial() {
|
||||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
|
||||||
m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
|
mDataIt = getNextWord<DataArrayIt>(mDataIt, mDataItEnd);
|
||||||
if (m_DataIt == m_DataItEnd) {
|
if (mDataIt == mDataItEnd) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pStart = &(*m_DataIt);
|
char *pStart = &(*mDataIt);
|
||||||
std::string strMat(pStart, *m_DataIt);
|
std::string strMat(pStart, *mDataIt);
|
||||||
while (m_DataIt != m_DataItEnd && IsSpaceOrNewLine(*m_DataIt)) {
|
while (mDataIt != mDataItEnd && IsSpaceOrNewLine(*mDataIt)) {
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
}
|
}
|
||||||
std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->mMaterialMap.find(strMat);
|
auto it = mModel->mMaterialMap.find(strMat);
|
||||||
if (it == m_pModel->mMaterialMap.end()) {
|
if (it == mModel->mMaterialMap.end()) {
|
||||||
// Show a warning, if material was not found
|
// Show a warning, if material was not found
|
||||||
ASSIMP_LOG_WARN("OBJ: Unsupported material requested: ", strMat);
|
ASSIMP_LOG_WARN("OBJ: Unsupported material requested: ", strMat);
|
||||||
m_pModel->mCurrentMaterial = m_pModel->mDefaultMaterial;
|
mModel->mCurrentMaterial = mModel->mDefaultMaterial;
|
||||||
} else {
|
} else {
|
||||||
// Set new material
|
// Set new material
|
||||||
if (needsNewMesh(strMat)) {
|
if (needsNewMesh(strMat)) {
|
||||||
createMesh(strMat);
|
createMesh(strMat);
|
||||||
}
|
}
|
||||||
m_pModel->mCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strMat);
|
mModel->mCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strMat);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr int InvalidMaterialIndex = -1;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
int ObjFileParser::getMaterialIndex(const std::string &strMaterialName) {
|
int ObjFileParser::getMaterialIndex(const std::string &strMaterialName) {
|
||||||
int mat_index = -1;
|
int mat_index = InvalidMaterialIndex;
|
||||||
if (strMaterialName.empty()) {
|
if (strMaterialName.empty()) {
|
||||||
return mat_index;
|
return mat_index;
|
||||||
}
|
}
|
||||||
for (size_t index = 0; index < m_pModel->mMaterialLib.size(); ++index) {
|
for (size_t index = 0; index < mModel->mMaterialLib.size(); ++index) {
|
||||||
if (strMaterialName == m_pModel->mMaterialLib[index]) {
|
if (strMaterialName == mModel->mMaterialLib[index]) {
|
||||||
mat_index = (int)index;
|
mat_index = (int)index;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -732,111 +743,108 @@ void ObjFileParser::getGroupName() {
|
|||||||
std::string groupName;
|
std::string groupName;
|
||||||
|
|
||||||
// here we skip 'g ' from line
|
// here we skip 'g ' from line
|
||||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
|
||||||
m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, groupName);
|
mDataIt = getName<DataArrayIt>(mDataIt, mDataItEnd, groupName);
|
||||||
if (isEndOfBuffer(m_DataIt, m_DataItEnd)) {
|
if (isEndOfBuffer(mDataIt, mDataItEnd)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change active group, if necessary
|
// Change active group, if necessary
|
||||||
if (m_pModel->mActiveGroup != groupName) {
|
if (mModel->mActiveGroup != groupName) {
|
||||||
// Search for already existing entry
|
// Search for already existing entry
|
||||||
ObjFile::Model::ConstGroupMapIt it = m_pModel->mGroups.find(groupName);
|
ObjFile::Model::ConstGroupMapIt it = mModel->mGroups.find(groupName);
|
||||||
|
|
||||||
// We are mapping groups into the object structure
|
// We are mapping groups into the object structure
|
||||||
createObject(groupName);
|
createObject(groupName);
|
||||||
|
|
||||||
// New group name, creating a new entry
|
// New group name, creating a new entry
|
||||||
if (it == m_pModel->mGroups.end()) {
|
if (it == mModel->mGroups.end()) {
|
||||||
std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
|
std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
|
||||||
m_pModel->mGroups[groupName] = pFaceIDArray;
|
mModel->mGroups[groupName] = pFaceIDArray;
|
||||||
m_pModel->mGroupFaceIDs = (pFaceIDArray);
|
mModel->mGroupFaceIDs = (pFaceIDArray);
|
||||||
} else {
|
} else {
|
||||||
m_pModel->mGroupFaceIDs = (*it).second;
|
mModel->mGroupFaceIDs = (*it).second;
|
||||||
}
|
}
|
||||||
m_pModel->mActiveGroup = groupName;
|
mModel->mActiveGroup = groupName;
|
||||||
}
|
}
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Not supported
|
void ObjFileParser::skipGroupNumber() {
|
||||||
void ObjFileParser::getGroupNumber() {
|
|
||||||
// Not used
|
// Not used
|
||||||
|
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Not supported
|
void ObjFileParser::skipGroupNumberAndResolution() {
|
||||||
void ObjFileParser::getGroupNumberAndResolution() {
|
|
||||||
// Not used
|
// Not used
|
||||||
|
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Stores values for a new object instance, name will be used to
|
// Stores values for a new object instance, name will be used to
|
||||||
// identify it.
|
// identify it.
|
||||||
void ObjFileParser::getObjectName() {
|
void ObjFileParser::getObjectName() {
|
||||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
|
||||||
if (m_DataIt == m_DataItEnd) {
|
if (mDataIt == mDataItEnd) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char *pStart = &(*m_DataIt);
|
char *pStart = &(*mDataIt);
|
||||||
while (m_DataIt != m_DataItEnd && !IsSpaceOrNewLine(*m_DataIt)) {
|
while (mDataIt != mDataItEnd && !IsSpaceOrNewLine(*mDataIt)) {
|
||||||
++m_DataIt;
|
++mDataIt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string strObjectName(pStart, &(*m_DataIt));
|
std::string strObjectName(pStart, &(*mDataIt));
|
||||||
if (!strObjectName.empty()) {
|
if (!strObjectName.empty()) {
|
||||||
// Reset current object
|
// Reset current object
|
||||||
m_pModel->mCurrentObject = nullptr;
|
mModel->mCurrentObject = nullptr;
|
||||||
|
|
||||||
// Search for actual object
|
// Search for actual object
|
||||||
for (std::vector<ObjFile::Object *>::const_iterator it = m_pModel->mObjects.begin();
|
for (auto it = mModel->mObjects.begin(); it != mModel->mObjects.end(); ++it) {
|
||||||
it != m_pModel->mObjects.end();
|
|
||||||
++it) {
|
|
||||||
if ((*it)->m_strObjName == strObjectName) {
|
if ((*it)->m_strObjName == strObjectName) {
|
||||||
m_pModel->mCurrentObject = *it;
|
mModel->mCurrentObject = *it;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a new object, if current one was not found before
|
// Allocate a new object, if current one was not found before
|
||||||
if (nullptr == m_pModel->mCurrentObject) {
|
if (mModel->mCurrentObject == nullptr) {
|
||||||
createObject(strObjectName);
|
createObject(strObjectName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Creates a new object instance
|
// Creates a new object instance
|
||||||
void ObjFileParser::createObject(const std::string &objName) {
|
void ObjFileParser::createObject(const std::string &objName) {
|
||||||
ai_assert(nullptr != m_pModel);
|
ai_assert(nullptr != mModel);
|
||||||
|
|
||||||
m_pModel->mCurrentObject = new ObjFile::Object;
|
mModel->mCurrentObject = new ObjFile::Object;
|
||||||
m_pModel->mCurrentObject->m_strObjName = objName;
|
mModel->mCurrentObject->m_strObjName = objName;
|
||||||
m_pModel->mObjects.push_back(m_pModel->mCurrentObject);
|
mModel->mObjects.push_back(mModel->mCurrentObject);
|
||||||
|
|
||||||
createMesh(objName);
|
createMesh(objName);
|
||||||
|
|
||||||
if (m_pModel->mCurrentMaterial) {
|
if (mModel->mCurrentMaterial) {
|
||||||
m_pModel->mCurrentMesh->m_uiMaterialIndex =
|
mModel->mCurrentMesh->m_uiMaterialIndex =
|
||||||
getMaterialIndex(m_pModel->mCurrentMaterial->MaterialName.data);
|
getMaterialIndex(mModel->mCurrentMaterial->MaterialName.data);
|
||||||
m_pModel->mCurrentMesh->m_pMaterial = m_pModel->mCurrentMaterial;
|
mModel->mCurrentMesh->m_pMaterial = mModel->mCurrentMaterial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Creates a new mesh
|
// Creates a new mesh
|
||||||
void ObjFileParser::createMesh(const std::string &meshName) {
|
void ObjFileParser::createMesh(const std::string &meshName) {
|
||||||
ai_assert(nullptr != m_pModel);
|
ai_assert(nullptr != mModel);
|
||||||
|
|
||||||
m_pModel->mCurrentMesh = new ObjFile::Mesh(meshName);
|
mModel->mCurrentMesh = new ObjFile::Mesh(meshName);
|
||||||
m_pModel->mMeshes.push_back(m_pModel->mCurrentMesh);
|
mModel->mMeshes.push_back(mModel->mCurrentMesh);
|
||||||
unsigned int meshId = static_cast<unsigned int>(m_pModel->mMeshes.size() - 1);
|
auto meshId = static_cast<unsigned int>(mModel->mMeshes.size() - 1);
|
||||||
if (nullptr != m_pModel->mCurrentObject) {
|
if (mModel->mCurrentObject != nullptr) {
|
||||||
m_pModel->mCurrentObject->m_Meshes.push_back(meshId);
|
mModel->mCurrentObject->m_Meshes.push_back(meshId);
|
||||||
} else {
|
} else {
|
||||||
ASSIMP_LOG_ERROR("OBJ: No object detected to attach a new mesh instance.");
|
ASSIMP_LOG_ERROR("OBJ: No object detected to attach a new mesh instance.");
|
||||||
}
|
}
|
||||||
@@ -846,16 +854,16 @@ void ObjFileParser::createMesh(const std::string &meshName) {
|
|||||||
// Returns true, if a new mesh must be created.
|
// Returns true, if a new mesh must be created.
|
||||||
bool ObjFileParser::needsNewMesh(const std::string &materialName) {
|
bool ObjFileParser::needsNewMesh(const std::string &materialName) {
|
||||||
// If no mesh data yet
|
// If no mesh data yet
|
||||||
if (m_pModel->mCurrentMesh == nullptr) {
|
if (mModel->mCurrentMesh == nullptr) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool newMat = false;
|
bool newMat = false;
|
||||||
int matIdx = getMaterialIndex(materialName);
|
int matIdx = getMaterialIndex(materialName);
|
||||||
int curMatIdx = m_pModel->mCurrentMesh->m_uiMaterialIndex;
|
int curMatIdx = mModel->mCurrentMesh->m_uiMaterialIndex;
|
||||||
if (curMatIdx != int(ObjFile::Mesh::NoMaterial) && curMatIdx != matIdx
|
if (curMatIdx != int(ObjFile::Mesh::NoMaterial) && curMatIdx != matIdx
|
||||||
// no need create a new mesh if no faces in current
|
// no need create a new mesh if no faces in current
|
||||||
// lets say 'usemtl' goes straight after 'g'
|
// lets say 'usemtl' goes straight after 'g'
|
||||||
&& !m_pModel->mCurrentMesh->m_Faces.empty()) {
|
&& !mModel->mCurrentMesh->m_Faces.empty()) {
|
||||||
// New material -> only one material per mesh, so we need to create a new
|
// New material -> only one material per mesh, so we need to create a new
|
||||||
// material
|
// material
|
||||||
newMat = true;
|
newMat = true;
|
||||||
@@ -866,7 +874,7 @@ bool ObjFileParser::needsNewMesh(const std::string &materialName) {
|
|||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Shows an error in parsing process.
|
// Shows an error in parsing process.
|
||||||
void ObjFileParser::reportErrorTokenInFace() {
|
void ObjFileParser::reportErrorTokenInFace() {
|
||||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
|
||||||
ASSIMP_LOG_ERROR("OBJ: Not supported token in face description detected");
|
ASSIMP_LOG_ERROR("OBJ: Not supported token in face description detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,8 +106,8 @@ protected:
|
|||||||
void getFace(aiPrimitiveType type);
|
void getFace(aiPrimitiveType type);
|
||||||
/// Reads the material description.
|
/// Reads the material description.
|
||||||
void getMaterialDesc();
|
void getMaterialDesc();
|
||||||
/// Gets a comment.
|
/// Skip a comment.
|
||||||
void getComment();
|
void skipComment();
|
||||||
/// Gets a a material library.
|
/// Gets a a material library.
|
||||||
void getMaterialLib();
|
void getMaterialLib();
|
||||||
/// Creates a new material.
|
/// Creates a new material.
|
||||||
@@ -115,9 +115,9 @@ protected:
|
|||||||
/// Gets the group name from file.
|
/// Gets the group name from file.
|
||||||
void getGroupName();
|
void getGroupName();
|
||||||
/// Gets the group number from file.
|
/// Gets the group number from file.
|
||||||
void getGroupNumber();
|
void skipGroupNumber();
|
||||||
/// Gets the group number and resolution from file.
|
/// Gets the group number and resolution from file.
|
||||||
void getGroupNumberAndResolution();
|
void skipGroupNumberAndResolution();
|
||||||
/// Returns the index of the material. Is -1 if not material was found.
|
/// Returns the index of the material. Is -1 if not material was found.
|
||||||
int getMaterialIndex(const std::string &strMaterialName);
|
int getMaterialIndex(const std::string &strMaterialName);
|
||||||
/// Parse object name
|
/// Parse object name
|
||||||
@@ -135,23 +135,23 @@ private:
|
|||||||
/// Default material name
|
/// Default material name
|
||||||
static constexpr const char DEFAULT_MATERIAL[] = AI_DEFAULT_MATERIAL_NAME;
|
static constexpr const char DEFAULT_MATERIAL[] = AI_DEFAULT_MATERIAL_NAME;
|
||||||
//! Iterator to current position in buffer
|
//! Iterator to current position in buffer
|
||||||
DataArrayIt m_DataIt;
|
DataArrayIt mDataIt{};
|
||||||
//! Iterator to end position of buffer
|
//! Iterator to end position of buffer
|
||||||
DataArrayIt m_DataItEnd;
|
DataArrayIt mDataItEnd{};
|
||||||
//! Pointer to model instance
|
//! Pointer to model instance
|
||||||
std::unique_ptr<ObjFile::Model> m_pModel;
|
std::unique_ptr<ObjFile::Model> mModel{};
|
||||||
//! Current line (for debugging)
|
//! Current line (for debugging)
|
||||||
unsigned int m_uiLine;
|
unsigned int mLine{ 0 };
|
||||||
//! Helper buffer
|
//! Helper buffer
|
||||||
char m_buffer[Buffersize];
|
char mBuffer[Buffersize];
|
||||||
/// End of buffer
|
/// End of buffer
|
||||||
const char *mEnd;
|
const char *mEnd{ nullptr };
|
||||||
/// Pointer to IO system instance.
|
/// Pointer to IO system instance.
|
||||||
IOSystem *m_pIO;
|
IOSystem *mIO{ nullptr };
|
||||||
//! Pointer to progress handler
|
//! Pointer to progress handler
|
||||||
ProgressHandler *m_progress;
|
ProgressHandler *mProgress{ nullptr };
|
||||||
/// Path to the current model, name of the obj file where the buffer comes from
|
/// Path to the current model, name of the obj file where the buffer comes from
|
||||||
const std::string m_originalObjFileName;
|
const std::string mOriginalObjFileName{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace Assimp
|
} // Namespace Assimp
|
||||||
|
|||||||
@@ -892,7 +892,7 @@ void OpenGEXImporter::handleIndexArrayNode(ODDLParser::DDLNode *node, aiScene *
|
|||||||
m_currentMesh->mVertices = new aiVector3D[m_currentMesh->mNumVertices];
|
m_currentMesh->mVertices = new aiVector3D[m_currentMesh->mNumVertices];
|
||||||
bool hasColors(false);
|
bool hasColors(false);
|
||||||
if (m_currentVertices.m_numColors > 0) {
|
if (m_currentVertices.m_numColors > 0) {
|
||||||
m_currentMesh->mColors[0] = new aiColor4D[m_currentVertices.m_numColors];
|
m_currentMesh->mColors[0] = new aiColor4D[m_currentMesh->mNumVertices];
|
||||||
hasColors = true;
|
hasColors = true;
|
||||||
}
|
}
|
||||||
bool hasNormalCoords(false);
|
bool hasNormalCoords(false);
|
||||||
@@ -924,7 +924,7 @@ void OpenGEXImporter::handleIndexArrayNode(ODDLParser::DDLNode *node, aiScene *
|
|||||||
ai_assert(index < m_currentMesh->mNumVertices);
|
ai_assert(index < m_currentMesh->mNumVertices);
|
||||||
aiVector3D &pos = (m_currentVertices.m_vertices[idx]);
|
aiVector3D &pos = (m_currentVertices.m_vertices[idx]);
|
||||||
m_currentMesh->mVertices[index].Set(pos.x, pos.y, pos.z);
|
m_currentMesh->mVertices[index].Set(pos.x, pos.y, pos.z);
|
||||||
if (hasColors) {
|
if (hasColors && static_cast<size_t>(idx) < m_currentVertices.m_numColors) {
|
||||||
aiColor4D &col = m_currentVertices.m_colors[idx];
|
aiColor4D &col = m_currentVertices.m_colors[idx];
|
||||||
m_currentMesh->mColors[0][index] = col;
|
m_currentMesh->mColors[0][index] = col;
|
||||||
}
|
}
|
||||||
|
|||||||
+755
-762
File diff suppressed because it is too large
Load Diff
@@ -60,70 +60,60 @@ namespace Assimp {
|
|||||||
using namespace PLY;
|
using namespace PLY;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Importer class to load the stanford PLY file format
|
/// @brief Importer class to load the stanford PLY file format
|
||||||
*/
|
// ---------------------------------------------------------------------------
|
||||||
class PLYImporter final : public BaseImporter {
|
class PLYImporter final : public BaseImporter {
|
||||||
public:
|
public:
|
||||||
PLYImporter();
|
/// @brief Default constructor
|
||||||
|
PLYImporter() = default;
|
||||||
|
|
||||||
|
/// @brief Destructor
|
||||||
~PLYImporter() override;
|
~PLYImporter() override;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/// Returns whether the class can handle the format of the given file.
|
||||||
* See BaseImporter::CanRead() for details.
|
/// @see BaseImporter::CanRead() for details.
|
||||||
*/
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
|
||||||
bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
|
|
||||||
bool checkSig) const override;
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Extract a vertex from the DOM
|
/// Extract a vertex from the DOM
|
||||||
*/
|
|
||||||
void LoadVertex(const PLY::Element *pcElement, const PLY::ElementInstance *instElement, unsigned int pos);
|
void LoadVertex(const PLY::Element *pcElement, const PLY::ElementInstance *instElement, unsigned int pos);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Extract a face from the DOM
|
/// @brief Extract a face from the DOM
|
||||||
*/
|
/// The function will also take care of the correct winding order of the triangles.
|
||||||
|
/// @param pcElement The element containing the face data
|
||||||
|
/// @param instElement The element instance containing the face data
|
||||||
|
/// @param pos The position of the face in the element instance. This is needed to correctly assign the face to the mesh.
|
||||||
void LoadFace(const PLY::Element *pcElement, const PLY::ElementInstance *instElement, unsigned int pos);
|
void LoadFace(const PLY::Element *pcElement, const PLY::ElementInstance *instElement, unsigned int pos);
|
||||||
|
|
||||||
|
/// @brief Will create a triangle from a triangle strip.
|
||||||
|
/// The function will use the first three vertices of the strip to create the first triangle, then the second,
|
||||||
|
/// third and fourth vertex to create the second triangle and so on. The function will also take care of the correct
|
||||||
|
/// winding order of the triangles.
|
||||||
|
/// @param instElement The element instance containing the triangle strip data
|
||||||
|
/// @param iProperty The index of the property containing the triangle strip data
|
||||||
|
/// @param eType The data type of the triangle strip data
|
||||||
|
void createFromeTriStrip(const Assimp::PLY::ElementInstance *instElement, unsigned int iProperty, Assimp::PLY::EDataType eType);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Return importer meta information.
|
|
||||||
* See #BaseImporter::GetInfo for the details
|
|
||||||
*/
|
|
||||||
const aiImporterDesc *GetInfo() const override;
|
const aiImporterDesc *GetInfo() const override;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Imports the given file into the given scene structure.
|
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
||||||
* See BaseImporter::InternReadFile() for details
|
|
||||||
*/
|
|
||||||
void InternReadFile(const std::string &pFile, aiScene *pScene,
|
|
||||||
IOSystem *pIOHandler) override;
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Extract a material list from the DOM
|
/// @brief Extract a material list from the DOM
|
||||||
*/
|
/// @param pvOut The output material list. The function will fill the list with the extracted materials.
|
||||||
|
/// @param defaultTexture The default texture to use for the materials. This is needed to correctly assign the texture to the materials.
|
||||||
|
/// @param pointsOnly Whether the file contains only points. This is needed to correctly assign the material properties.
|
||||||
void LoadMaterial(std::vector<aiMaterial *> *pvOut, std::string &defaultTexture, const bool pointsOnly);
|
void LoadMaterial(std::vector<aiMaterial *> *pvOut, std::string &defaultTexture, const bool pointsOnly);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Static helper to parse a color from four single channels in
|
|
||||||
*/
|
|
||||||
static void GetMaterialColor(
|
|
||||||
const std::vector<PLY::PropertyInstance> &avList,
|
|
||||||
unsigned int aiPositions[4],
|
|
||||||
PLY::EDataType aiTypes[4],
|
|
||||||
aiColor4D *clrOut);
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Static helper to parse a color channel value. The input value
|
|
||||||
* is normalized to 0-1.
|
|
||||||
*/
|
|
||||||
static ai_real NormalizeColorValue(
|
|
||||||
PLY::PropertyInstance::ValueUnion val,
|
|
||||||
PLY::EDataType eType);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned char *mBuffer;
|
unsigned char *mBuffer{nullptr};
|
||||||
PLY::DOM *pcDOM;
|
PLY::DOM *pcDOM{nullptr};
|
||||||
aiMesh *mGeneratedMesh;
|
aiMesh *mGeneratedMesh{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|||||||
+118
-111
@@ -52,53 +52,53 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
std::string to_string(EElementSemantic e) {
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
static std::string to_string(EElementSemantic e) {
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case EEST_Vertex:
|
case EEST_Vertex:
|
||||||
return std::string{ "vertex" };
|
return std::string{ "vertex" };
|
||||||
case EEST_TriStrip:
|
case EEST_TriStrip:
|
||||||
return std::string{ "tristrips" };
|
return std::string{ "tristrips" };
|
||||||
case EEST_Edge:
|
case EEST_Edge:
|
||||||
return std::string{ "edge" };
|
return std::string{ "edge" };
|
||||||
case EEST_Material:
|
case EEST_Material:
|
||||||
return std::string{ "material" };
|
return std::string{ "material" };
|
||||||
case EEST_TextureFile:
|
case EEST_TextureFile:
|
||||||
return std::string{ "TextureFile" };
|
return std::string{ "TextureFile" };
|
||||||
default:
|
default:
|
||||||
return std::string{ "invalid" };
|
return std::string{ "invalid" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
PLY::EDataType PLY::Property::ParseDataType(std::vector<char> &buffer) {
|
EDataType Property::ParseDataType(std::vector<char> &buffer) {
|
||||||
ai_assert(!buffer.empty());
|
ai_assert(!buffer.empty());
|
||||||
|
|
||||||
PLY::EDataType eOut = PLY::EDT_INVALID;
|
EDataType eOut = EDT_INVALID;
|
||||||
|
|
||||||
if (PLY::DOM::TokenMatch(buffer, "char", 4) ||
|
if (DOM::TokenMatch(buffer, "char", 4) ||
|
||||||
PLY::DOM::TokenMatch(buffer, "int8", 4)) {
|
DOM::TokenMatch(buffer, "int8", 4)) {
|
||||||
eOut = PLY::EDT_Char;
|
eOut = EDT_Char;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "uchar", 5) ||
|
} else if (DOM::TokenMatch(buffer, "uchar", 5) ||
|
||||||
PLY::DOM::TokenMatch(buffer, "uint8", 5)) {
|
DOM::TokenMatch(buffer, "uint8", 5)) {
|
||||||
eOut = PLY::EDT_UChar;
|
eOut = EDT_UChar;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "short", 5) ||
|
} else if (DOM::TokenMatch(buffer, "short", 5) ||
|
||||||
PLY::DOM::TokenMatch(buffer, "int16", 5)) {
|
DOM::TokenMatch(buffer, "int16", 5)) {
|
||||||
eOut = PLY::EDT_Short;
|
eOut = EDT_Short;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "ushort", 6) ||
|
} else if (DOM::TokenMatch(buffer, "ushort", 6) ||
|
||||||
PLY::DOM::TokenMatch(buffer, "uint16", 6)) {
|
DOM::TokenMatch(buffer, "uint16", 6)) {
|
||||||
eOut = PLY::EDT_UShort;
|
eOut = EDT_UShort;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "int32", 5) || PLY::DOM::TokenMatch(buffer, "int", 3)) {
|
} else if (DOM::TokenMatch(buffer, "int32", 5) || DOM::TokenMatch(buffer, "int", 3)) {
|
||||||
eOut = PLY::EDT_Int;
|
eOut = EDT_Int;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "uint32", 6) || PLY::DOM::TokenMatch(buffer, "uint", 4)) {
|
} else if (DOM::TokenMatch(buffer, "uint32", 6) || DOM::TokenMatch(buffer, "uint", 4)) {
|
||||||
eOut = PLY::EDT_UInt;
|
eOut = EDT_UInt;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "float", 5) || PLY::DOM::TokenMatch(buffer, "float32", 7)) {
|
} else if (DOM::TokenMatch(buffer, "float", 5) || DOM::TokenMatch(buffer, "float32", 7)) {
|
||||||
eOut = PLY::EDT_Float;
|
eOut = EDT_Float;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "double64", 8) || PLY::DOM::TokenMatch(buffer, "double", 6) ||
|
} else if (DOM::TokenMatch(buffer, "double64", 8) || DOM::TokenMatch(buffer, "double", 6) ||
|
||||||
PLY::DOM::TokenMatch(buffer, "float64", 7)) {
|
DOM::TokenMatch(buffer, "float64", 7)) {
|
||||||
eOut = PLY::EDT_Double;
|
eOut = EDT_Double;
|
||||||
}
|
}
|
||||||
if (PLY::EDT_INVALID == eOut) {
|
if (EDT_INVALID == eOut) {
|
||||||
ASSIMP_LOG_INFO("Found unknown data type in PLY file. This is OK");
|
ASSIMP_LOG_INFO("Found unknown data type in PLY file. This is OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,81 +106,81 @@ PLY::EDataType PLY::Property::ParseDataType(std::vector<char> &buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
PLY::ESemantic PLY::Property::ParseSemantic(std::vector<char> &buffer) {
|
ESemantic Property::ParseSemantic(std::vector<char> &buffer) {
|
||||||
ai_assert(!buffer.empty());
|
ai_assert(!buffer.empty());
|
||||||
|
|
||||||
PLY::ESemantic eOut = PLY::EST_INVALID;
|
ESemantic eOut = PLY::EST_INVALID;
|
||||||
if (PLY::DOM::TokenMatch(buffer, "red", 3)) {
|
if (DOM::TokenMatch(buffer, "red", 3)) {
|
||||||
eOut = PLY::EST_Red;
|
eOut = EST_Red;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "green", 5)) {
|
} else if (DOM::TokenMatch(buffer, "green", 5)) {
|
||||||
eOut = PLY::EST_Green;
|
eOut = EST_Green;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "blue", 4)) {
|
} else if (DOM::TokenMatch(buffer, "blue", 4)) {
|
||||||
eOut = PLY::EST_Blue;
|
eOut = EST_Blue;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "alpha", 5)) {
|
} else if (DOM::TokenMatch(buffer, "alpha", 5)) {
|
||||||
eOut = PLY::EST_Alpha;
|
eOut = EST_Alpha;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "vertex_index", 12) || PLY::DOM::TokenMatch(buffer, "vertex_indices", 14)) {
|
} else if (DOM::TokenMatch(buffer, "vertex_index", 12) || PLY::DOM::TokenMatch(buffer, "vertex_indices", 14)) {
|
||||||
eOut = PLY::EST_VertexIndex;
|
eOut = EST_VertexIndex;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "texcoord", 8)) // Manage uv coords on faces
|
} else if (DOM::TokenMatch(buffer, "texcoord", 8)) // Manage uv coords on faces
|
||||||
{
|
{
|
||||||
eOut = PLY::EST_TextureCoordinates;
|
eOut = EST_TextureCoordinates;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "material_index", 14)) {
|
} else if (DOM::TokenMatch(buffer, "material_index", 14)) {
|
||||||
eOut = PLY::EST_MaterialIndex;
|
eOut = EST_MaterialIndex;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "ambient_red", 11)) {
|
} else if (DOM::TokenMatch(buffer, "ambient_red", 11)) {
|
||||||
eOut = PLY::EST_AmbientRed;
|
eOut = EST_AmbientRed;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "ambient_green", 13)) {
|
} else if (DOM::TokenMatch(buffer, "ambient_green", 13)) {
|
||||||
eOut = PLY::EST_AmbientGreen;
|
eOut = EST_AmbientGreen;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "ambient_blue", 12)) {
|
} else if (DOM::TokenMatch(buffer, "ambient_blue", 12)) {
|
||||||
eOut = PLY::EST_AmbientBlue;
|
eOut = EST_AmbientBlue;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "ambient_alpha", 13)) {
|
} else if (DOM::TokenMatch(buffer, "ambient_alpha", 13)) {
|
||||||
eOut = PLY::EST_AmbientAlpha;
|
eOut = EST_AmbientAlpha;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "diffuse_red", 11)) {
|
} else if (DOM::TokenMatch(buffer, "diffuse_red", 11)) {
|
||||||
eOut = PLY::EST_DiffuseRed;
|
eOut = EST_DiffuseRed;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "diffuse_green", 13)) {
|
} else if (DOM::TokenMatch(buffer, "diffuse_green", 13)) {
|
||||||
eOut = PLY::EST_DiffuseGreen;
|
eOut = EST_DiffuseGreen;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "diffuse_blue", 12)) {
|
} else if (DOM::TokenMatch(buffer, "diffuse_blue", 12)) {
|
||||||
eOut = PLY::EST_DiffuseBlue;
|
eOut = EST_DiffuseBlue;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "diffuse_alpha", 13)) {
|
} else if (DOM::TokenMatch(buffer, "diffuse_alpha", 13)) {
|
||||||
eOut = PLY::EST_DiffuseAlpha;
|
eOut = EST_DiffuseAlpha;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "specular_red", 12)) {
|
} else if (DOM::TokenMatch(buffer, "specular_red", 12)) {
|
||||||
eOut = PLY::EST_SpecularRed;
|
eOut = EST_SpecularRed;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "specular_green", 14)) {
|
} else if (DOM::TokenMatch(buffer, "specular_green", 14)) {
|
||||||
eOut = PLY::EST_SpecularGreen;
|
eOut = EST_SpecularGreen;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "specular_blue", 13)) {
|
} else if (DOM::TokenMatch(buffer, "specular_blue", 13)) {
|
||||||
eOut = PLY::EST_SpecularBlue;
|
eOut = EST_SpecularBlue;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "specular_alpha", 14)) {
|
} else if (DOM::TokenMatch(buffer, "specular_alpha", 14)) {
|
||||||
eOut = PLY::EST_SpecularAlpha;
|
eOut = EST_SpecularAlpha;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "opacity", 7)) {
|
} else if (DOM::TokenMatch(buffer, "opacity", 7)) {
|
||||||
eOut = PLY::EST_Opacity;
|
eOut = EST_Opacity;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "specular_power", 14)) {
|
} else if (DOM::TokenMatch(buffer, "specular_power", 14)) {
|
||||||
eOut = PLY::EST_PhongPower;
|
eOut = EST_PhongPower;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "r", 1)) {
|
} else if (DOM::TokenMatch(buffer, "r", 1)) {
|
||||||
eOut = PLY::EST_Red;
|
eOut = EST_Red;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "g", 1)) {
|
} else if (DOM::TokenMatch(buffer, "g", 1)) {
|
||||||
eOut = PLY::EST_Green;
|
eOut = EST_Green;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "b", 1)) {
|
} else if (DOM::TokenMatch(buffer, "b", 1)) {
|
||||||
eOut = PLY::EST_Blue;
|
eOut = EST_Blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Blender3D exports texture coordinates as s,t tuples
|
// NOTE: Blender3D exports texture coordinates as s,t tuples
|
||||||
else if (PLY::DOM::TokenMatch(buffer, "u", 1) || PLY::DOM::TokenMatch(buffer, "s", 1) || PLY::DOM::TokenMatch(buffer, "tx", 2) || PLY::DOM::TokenMatch(buffer, "texture_u", 9)) {
|
else if (DOM::TokenMatch(buffer, "u", 1) || PLY::DOM::TokenMatch(buffer, "s", 1) || PLY::DOM::TokenMatch(buffer, "tx", 2) || PLY::DOM::TokenMatch(buffer, "texture_u", 9)) {
|
||||||
eOut = PLY::EST_UTextureCoord;
|
eOut = EST_UTextureCoord;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "v", 1) || PLY::DOM::TokenMatch(buffer, "t", 1) || PLY::DOM::TokenMatch(buffer, "ty", 2) || PLY::DOM::TokenMatch(buffer, "texture_v", 9)) {
|
} else if (DOM::TokenMatch(buffer, "v", 1) || PLY::DOM::TokenMatch(buffer, "t", 1) || PLY::DOM::TokenMatch(buffer, "ty", 2) || PLY::DOM::TokenMatch(buffer, "texture_v", 9)) {
|
||||||
eOut = PLY::EST_VTextureCoord;
|
eOut = EST_VTextureCoord;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "x", 1)) {
|
} else if (DOM::TokenMatch(buffer, "x", 1)) {
|
||||||
eOut = PLY::EST_XCoord;
|
eOut = EST_XCoord;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "y", 1)) {
|
} else if (DOM::TokenMatch(buffer, "y", 1)) {
|
||||||
eOut = PLY::EST_YCoord;
|
eOut = EST_YCoord;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "z", 1)) {
|
} else if (DOM::TokenMatch(buffer, "z", 1)) {
|
||||||
eOut = PLY::EST_ZCoord;
|
eOut = EST_ZCoord;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "nx", 2)) {
|
} else if (DOM::TokenMatch(buffer, "nx", 2)) {
|
||||||
eOut = PLY::EST_XNormal;
|
eOut = EST_XNormal;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "ny", 2)) {
|
} else if (DOM::TokenMatch(buffer, "ny", 2)) {
|
||||||
eOut = PLY::EST_YNormal;
|
eOut = EST_YNormal;
|
||||||
} else if (PLY::DOM::TokenMatch(buffer, "nz", 2)) {
|
} else if (DOM::TokenMatch(buffer, "nz", 2)) {
|
||||||
eOut = PLY::EST_ZNormal;
|
eOut = EST_ZNormal;
|
||||||
} else {
|
} else {
|
||||||
ASSIMP_LOG_INFO("Found unknown property semantic in file. This is ok");
|
ASSIMP_LOG_INFO("Found unknown property semantic in file. This is ok");
|
||||||
PLY::DOM::SkipLine(buffer);
|
DOM::SkipLine(buffer);
|
||||||
}
|
}
|
||||||
return eOut;
|
return eOut;
|
||||||
}
|
}
|
||||||
@@ -194,12 +194,12 @@ bool PLY::Property::ParseProperty(std::vector<char> &buffer, PLY::Property *pOut
|
|||||||
// "property list uchar int vertex_index"
|
// "property list uchar int vertex_index"
|
||||||
|
|
||||||
// skip leading spaces
|
// skip leading spaces
|
||||||
if (!PLY::DOM::SkipSpaces(buffer)) {
|
if (!DOM::SkipSpaces(buffer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip the "property" string at the beginning
|
// skip the "property" string at the beginning
|
||||||
if (!PLY::DOM::TokenMatch(buffer, "property", 8)) {
|
if (!DOM::TokenMatch(buffer, "property", 8)) {
|
||||||
// seems not to be a valid property entry
|
// seems not to be a valid property entry
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -343,6 +343,7 @@ bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool PLY::DOM::SkipSpaces(std::vector<char> &buffer) {
|
bool PLY::DOM::SkipSpaces(std::vector<char> &buffer) {
|
||||||
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
||||||
const char *end = pCur + buffer.size();
|
const char *end = pCur + buffer.size();
|
||||||
@@ -359,6 +360,7 @@ bool PLY::DOM::SkipSpaces(std::vector<char> &buffer) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool PLY::DOM::SkipLine(std::vector<char> &buffer) {
|
bool PLY::DOM::SkipLine(std::vector<char> &buffer) {
|
||||||
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
||||||
const char *end = pCur + buffer.size();
|
const char *end = pCur + buffer.size();
|
||||||
@@ -375,6 +377,7 @@ bool PLY::DOM::SkipLine(std::vector<char> &buffer) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool PLY::DOM::TokenMatch(std::vector<char> &buffer, const char *token, unsigned int len) {
|
bool PLY::DOM::TokenMatch(std::vector<char> &buffer, const char *token, unsigned int len) {
|
||||||
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
@@ -390,6 +393,7 @@ bool PLY::DOM::TokenMatch(std::vector<char> &buffer, const char *token, unsigned
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer) {
|
bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer) {
|
||||||
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
|
||||||
const char *end = pCur + buffer.size();
|
const char *end = pCur + buffer.size();
|
||||||
@@ -406,6 +410,7 @@ bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool PLY::DOM::SkipComments(std::vector<char> buffer) {
|
bool PLY::DOM::SkipComments(std::vector<char> buffer) {
|
||||||
ai_assert(!buffer.empty());
|
ai_assert(!buffer.empty());
|
||||||
|
|
||||||
@@ -835,7 +840,7 @@ bool PLY::PropertyInstance::ParseValue(const char *&pCur,
|
|||||||
case EDT_Double:
|
case EDT_Double:
|
||||||
double d;
|
double d;
|
||||||
pCur = fast_atoreal_move(pCur, d);
|
pCur = fast_atoreal_move(pCur, d);
|
||||||
out->fDouble = (double)d;
|
out->fDouble = d;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EDT_INVALID:
|
case EDT_INVALID:
|
||||||
@@ -848,12 +853,12 @@ bool PLY::PropertyInstance::ParseValue(const char *&pCur,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
|
bool PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
|
||||||
std::vector<char> &buffer,
|
std::vector<char> &buffer,
|
||||||
const char *&pCur,
|
const char *&pCur,
|
||||||
unsigned int &bufferSize,
|
unsigned int &bufferSize,
|
||||||
PLY::EDataType eType,
|
EDataType eType,
|
||||||
PLY::PropertyInstance::ValueUnion *out,
|
PropertyInstance::ValueUnion *out,
|
||||||
bool p_bBE) {
|
bool p_bBE) {
|
||||||
ai_assert(nullptr != out);
|
ai_assert(nullptr != out);
|
||||||
|
|
||||||
@@ -991,6 +996,8 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
} // namespace Assimp
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER
|
#endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER
|
||||||
|
|||||||
@@ -291,16 +291,13 @@ public:
|
|||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
/** \brief Instance of a property in a PLY file
|
/** \brief Instance of a property in a PLY file
|
||||||
*/
|
*/
|
||||||
class PropertyInstance
|
class PropertyInstance {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Default constructor
|
//! Default constructor
|
||||||
PropertyInstance() AI_NO_EXCEPT = default;
|
PropertyInstance() AI_NO_EXCEPT = default;
|
||||||
|
|
||||||
union ValueUnion
|
union ValueUnion
|
||||||
{
|
{
|
||||||
|
|
||||||
//! uInt32 representation of the property. All
|
//! uInt32 representation of the property. All
|
||||||
// uint types are automatically converted to uint32
|
// uint types are automatically converted to uint32
|
||||||
uint32_t iUInt;
|
uint32_t iUInt;
|
||||||
@@ -351,9 +348,11 @@ public:
|
|||||||
static TYPE ConvertTo(ValueUnion v, EDataType eType);
|
static TYPE ConvertTo(ValueUnion v, EDataType eType);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using PropertyInstVec = std::vector<PropertyInstance::ValueUnion>;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------
|
||||||
|
/// @brief Class for an element instance in a PLY file
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
/** \brief Class for an element instance in a PLY file
|
|
||||||
*/
|
|
||||||
class ElementInstance {
|
class ElementInstance {
|
||||||
public:
|
public:
|
||||||
//! Default constructor
|
//! Default constructor
|
||||||
@@ -374,20 +373,18 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
/** \brief Class for an element instance list in a PLY file
|
/// @brief Class for an element instance list in a PLY file
|
||||||
*/
|
// ---------------------------------------------------------------------------------
|
||||||
class ElementInstanceList
|
class ElementInstanceList {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
/// Default constructor
|
||||||
//! Default constructor
|
|
||||||
ElementInstanceList() AI_NO_EXCEPT = default;
|
ElementInstanceList() AI_NO_EXCEPT = default;
|
||||||
|
|
||||||
//! List of all element instances
|
/// List of all element instances
|
||||||
std::vector< ElementInstance > alInstances;
|
std::vector< ElementInstance > alInstances;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
//! Parse an element instance list
|
/// Parse an element instance list
|
||||||
static bool ParseInstanceList(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
|
static bool ParseInstanceList(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
|
||||||
const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader);
|
const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader);
|
||||||
|
|
||||||
@@ -400,17 +397,15 @@ public:
|
|||||||
/** \brief Class to represent the document object model of an ASCII or binary
|
/** \brief Class to represent the document object model of an ASCII or binary
|
||||||
* (both little and big-endian) PLY file
|
* (both little and big-endian) PLY file
|
||||||
*/
|
*/
|
||||||
class DOM
|
class DOM {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
/// Default constructor
|
||||||
//! Default constructor
|
|
||||||
DOM() AI_NO_EXCEPT = default;
|
DOM() AI_NO_EXCEPT = default;
|
||||||
|
|
||||||
|
|
||||||
//! Contains all elements of the file format
|
/// Contains all elements of the file format
|
||||||
std::vector<Element> alElements;
|
std::vector<Element> alElements;
|
||||||
//! Contains the real data of each element's instance list
|
/// Contains the real data of each element's instance list
|
||||||
std::vector<ElementInstanceList> alElementData;
|
std::vector<ElementInstanceList> alElementData;
|
||||||
|
|
||||||
//! Parse the DOM for a PLY file. The input string is assumed
|
//! Parse the DOM for a PLY file. The input string is assumed
|
||||||
@@ -446,11 +441,8 @@ private:
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
template <typename TYPE>
|
template <typename TYPE>
|
||||||
inline TYPE PLY::PropertyInstance::ConvertTo(
|
inline TYPE PLY::PropertyInstance::ConvertTo(PLY::PropertyInstance::ValueUnion v, PLY::EDataType eType) {
|
||||||
PLY::PropertyInstance::ValueUnion v, PLY::EDataType eType)
|
switch (eType) {
|
||||||
{
|
|
||||||
switch (eType)
|
|
||||||
{
|
|
||||||
case EDT_Float:
|
case EDT_Float:
|
||||||
return (TYPE)v.fFloat;
|
return (TYPE)v.fFloat;
|
||||||
case EDT_Double:
|
case EDT_Double:
|
||||||
|
|||||||
@@ -511,14 +511,6 @@ void USDImporterImplTinyusdz::uvsForMesh(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static aiColor3D *ownedColorPtrFor(const std::array<float, 3> &color) {
|
|
||||||
aiColor3D *colorPtr = new aiColor3D();
|
|
||||||
colorPtr->r = color[0];
|
|
||||||
colorPtr->g = color[1];
|
|
||||||
colorPtr->b = color[2];
|
|
||||||
return colorPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string nameForTextureWithId(const RenderScene &render_scene, const int targetId) {
|
static std::string nameForTextureWithId(const RenderScene &render_scene, const int targetId) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
std::string texName;
|
std::string texName;
|
||||||
@@ -544,14 +536,14 @@ static void assignTexture(
|
|||||||
const int textureId,
|
const int textureId,
|
||||||
const int aiTextureType) {
|
const int aiTextureType) {
|
||||||
std::string name = nameForTextureWithId(render_scene, textureId);
|
std::string name = nameForTextureWithId(render_scene, textureId);
|
||||||
aiString *texName = new aiString();
|
aiString texName;
|
||||||
texName->Set(name);
|
texName.Set(name);
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss.str("");
|
ss.str("");
|
||||||
ss << "assignTexture(): name: " << name;
|
ss << "assignTexture(): name: " << name;
|
||||||
TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
|
TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
|
||||||
// TODO: verify hard-coded '0' index is correct
|
// TODO: verify hard-coded '0' index is correct
|
||||||
mat->AddProperty(texName, _AI_MATKEY_TEXTURE_BASE, aiTextureType, 0);
|
mat->AddProperty(&texName, _AI_MATKEY_TEXTURE_BASE, aiTextureType, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void USDImporterImplTinyusdz::materials(
|
void USDImporterImplTinyusdz::materials(
|
||||||
@@ -575,18 +567,18 @@ void USDImporterImplTinyusdz::materials(
|
|||||||
TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
|
TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
|
||||||
aiMaterial *mat = new aiMaterial;
|
aiMaterial *mat = new aiMaterial;
|
||||||
|
|
||||||
aiString *materialName = new aiString();
|
aiString materialName;
|
||||||
materialName->Set(material.name);
|
materialName.Set(material.name);
|
||||||
mat->AddProperty(materialName, AI_MATKEY_NAME);
|
mat->AddProperty(materialName, AI_MATKEY_NAME);
|
||||||
|
|
||||||
mat->AddProperty(
|
mat->AddProperty(
|
||||||
ownedColorPtrFor(material.surfaceShader.diffuseColor.value),
|
reinterpret_cast<const aiColor3D *>(material.surfaceShader.diffuseColor.value.data()),
|
||||||
1, AI_MATKEY_COLOR_DIFFUSE);
|
1, AI_MATKEY_COLOR_DIFFUSE);
|
||||||
mat->AddProperty(
|
mat->AddProperty(
|
||||||
ownedColorPtrFor(material.surfaceShader.specularColor.value),
|
reinterpret_cast<const aiColor3D *>(material.surfaceShader.specularColor.value.data()),
|
||||||
1, AI_MATKEY_COLOR_SPECULAR);
|
1, AI_MATKEY_COLOR_SPECULAR);
|
||||||
mat->AddProperty(
|
mat->AddProperty(
|
||||||
ownedColorPtrFor(material.surfaceShader.emissiveColor.value),
|
reinterpret_cast<const aiColor3D *>(material.surfaceShader.emissiveColor.value.data()),
|
||||||
1, AI_MATKEY_COLOR_EMISSIVE);
|
1, AI_MATKEY_COLOR_EMISSIVE);
|
||||||
|
|
||||||
ss.str("");
|
ss.str("");
|
||||||
|
|||||||
@@ -888,7 +888,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
|
|||||||
|
|
||||||
if (bufferView) {
|
if (bufferView) {
|
||||||
// Check length
|
// Check length
|
||||||
unsigned long long byteLength = (unsigned long long)GetBytesPerComponent() * (unsigned long long)count;
|
unsigned long long byteLength = count > 0
|
||||||
|
? (unsigned long long)GetStride() * (unsigned long long)(count - 1) + (unsigned long long)GetElementSize()
|
||||||
|
: 0;
|
||||||
|
|
||||||
// handle integer overflow
|
// handle integer overflow
|
||||||
if (byteLength < count) {
|
if (byteLength < count) {
|
||||||
@@ -1004,7 +1006,15 @@ inline size_t Accessor::GetMaxByteSize() {
|
|||||||
if (decodedBuffer)
|
if (decodedBuffer)
|
||||||
return decodedBuffer->byteLength;
|
return decodedBuffer->byteLength;
|
||||||
|
|
||||||
return (bufferView ? bufferView->byteLength : sparse->data.size());
|
if (sparse) {
|
||||||
|
return sparse->data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferView) {
|
||||||
|
return byteOffset <= bufferView->byteLength ? bufferView->byteLength - byteOffset : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ void SetAccessorRange(Ref<Accessor> acc, void *data, size_t count,
|
|||||||
|
|
||||||
// Allocate and initialize with large values.
|
// Allocate and initialize with large values.
|
||||||
for (unsigned int i = 0; i < numCompsOut; i++) {
|
for (unsigned int i = 0; i < numCompsOut; i++) {
|
||||||
acc->min.push_back(std::numeric_limits<double>::min());
|
acc->min.push_back(std::numeric_limits<double>::max());
|
||||||
acc->max.push_back(-std::numeric_limits<double>::max());
|
acc->max.push_back(-std::numeric_limits<double>::max());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -462,9 +462,9 @@ template <typename T>
|
|||||||
aiColor4D *GetVertexColorsForType(Ref<Accessor> input, std::vector<unsigned int> *vertexRemappingTable) {
|
aiColor4D *GetVertexColorsForType(Ref<Accessor> input, std::vector<unsigned int> *vertexRemappingTable) {
|
||||||
constexpr float max = std::numeric_limits<T>::max();
|
constexpr float max = std::numeric_limits<T>::max();
|
||||||
aiColor4t<T> *colors;
|
aiColor4t<T> *colors;
|
||||||
input->ExtractData(colors, vertexRemappingTable);
|
size_t count = input->ExtractData(colors, vertexRemappingTable);
|
||||||
auto output = new aiColor4D[input->count];
|
auto output = new aiColor4D[count];
|
||||||
for (size_t i = 0; i < input->count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
output[i] = aiColor4D(
|
output[i] = aiColor4D(
|
||||||
colors[i].r / max, colors[i].g / max,
|
colors[i].r / max, colors[i].g / max,
|
||||||
colors[i].b / max, colors[i].a / max);
|
colors[i].b / max, colors[i].a / max);
|
||||||
@@ -766,9 +766,12 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||||||
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
|
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
|
||||||
count = nFaces * 3;
|
count = nFaces * 3;
|
||||||
}
|
}
|
||||||
facePtr = faces = new aiFace[nFaces];
|
// copycd:: than > 0
|
||||||
for (unsigned int i = 0; i < count; i += 3) {
|
if (nFaces > 0) {
|
||||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[i], indexBuffer[i + 1], indexBuffer[i + 2]);
|
facePtr = faces = new aiFace[nFaces];
|
||||||
|
for (unsigned int i = 0; i < count; i += 3) {
|
||||||
|
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[i], indexBuffer[i + 1], indexBuffer[i + 2]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1316,6 +1319,15 @@ struct AnimationSamplers {
|
|||||||
struct vec4f {
|
struct vec4f {
|
||||||
float x, y, z, w;
|
float x, y, z, w;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static aiAnimInterpolation MapInterpolation(Interpolation interp) {
|
||||||
|
switch (interp) {
|
||||||
|
case Interpolation_STEP: return aiAnimInterpolation_Step;
|
||||||
|
case Interpolation_CUBICSPLINE: return aiAnimInterpolation_Cubic_Spline;
|
||||||
|
default: return aiAnimInterpolation_Linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
aiNodeAnim *CreateNodeAnim(glTF2::Asset &, Node &node, AnimationSamplers &samplers) {
|
aiNodeAnim *CreateNodeAnim(glTF2::Asset &, Node &node, AnimationSamplers &samplers) {
|
||||||
aiNodeAnim *anim = new aiNodeAnim();
|
aiNodeAnim *anim = new aiNodeAnim();
|
||||||
|
|
||||||
@@ -1327,7 +1339,6 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset &, Node &node, AnimationSamplers &sample
|
|||||||
if (samplers.translation && samplers.translation->input && samplers.translation->output) {
|
if (samplers.translation && samplers.translation->input && samplers.translation->output) {
|
||||||
float *times = nullptr;
|
float *times = nullptr;
|
||||||
samplers.translation->input->ExtractData(times);
|
samplers.translation->input->ExtractData(times);
|
||||||
//aiVector3D *values = nullptr;
|
|
||||||
vec4f *tmp_values = nullptr;
|
vec4f *tmp_values = nullptr;
|
||||||
size_t numItems = samplers.translation->output->ExtractData(tmp_values);
|
size_t numItems = samplers.translation->output->ExtractData(tmp_values);
|
||||||
aiVector3D *values = new aiVector3D[numItems];
|
aiVector3D *values = new aiVector3D[numItems];
|
||||||
@@ -1338,13 +1349,31 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset &, Node &node, AnimationSamplers &sample
|
|||||||
}
|
}
|
||||||
delete[] tmp_values;
|
delete[] tmp_values;
|
||||||
|
|
||||||
anim->mNumPositionKeys = static_cast<unsigned int>(samplers.translation->input->count);
|
const bool isCubic = (samplers.translation->interpolation == Interpolation_CUBICSPLINE);
|
||||||
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
const aiAnimInterpolation interpType = MapInterpolation(samplers.translation->interpolation);
|
||||||
unsigned int ii = (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
|
const unsigned int numLogicalKeys = static_cast<unsigned int>(samplers.translation->input->count);
|
||||||
for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
|
|
||||||
anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
if (isCubic) {
|
||||||
anim->mPositionKeys[i].mValue = values[ii];
|
// Store as triplets: in-tangent, value, out-tangent per logical key
|
||||||
ii += (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1;
|
anim->mNumPositionKeys = numLogicalKeys * 3;
|
||||||
|
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
||||||
|
for (unsigned int i = 0; i < numLogicalKeys; ++i) {
|
||||||
|
unsigned int srcBase = i * 3;
|
||||||
|
unsigned int dstBase = i * 3;
|
||||||
|
for (unsigned int t = 0; t < 3; ++t) {
|
||||||
|
anim->mPositionKeys[dstBase + t].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
|
anim->mPositionKeys[dstBase + t].mValue = values[srcBase + t];
|
||||||
|
anim->mPositionKeys[dstBase + t].mInterpolation = interpType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
anim->mNumPositionKeys = numLogicalKeys;
|
||||||
|
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
||||||
|
for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
|
||||||
|
anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
|
anim->mPositionKeys[i].mValue = values[i];
|
||||||
|
anim->mPositionKeys[i].mInterpolation = interpType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete[] times;
|
delete[] times;
|
||||||
delete[] values;
|
delete[] values;
|
||||||
@@ -1362,16 +1391,36 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset &, Node &node, AnimationSamplers &sample
|
|||||||
samplers.rotation->input->ExtractData(times);
|
samplers.rotation->input->ExtractData(times);
|
||||||
aiQuaternion *values = nullptr;
|
aiQuaternion *values = nullptr;
|
||||||
samplers.rotation->output->ExtractData(values);
|
samplers.rotation->output->ExtractData(values);
|
||||||
anim->mNumRotationKeys = static_cast<unsigned int>(samplers.rotation->input->count);
|
const bool isCubic = (samplers.rotation->interpolation == Interpolation_CUBICSPLINE);
|
||||||
anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
|
const aiAnimInterpolation interpType = MapInterpolation(samplers.rotation->interpolation);
|
||||||
unsigned int ii = (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
|
const unsigned int numLogicalKeys = static_cast<unsigned int>(samplers.rotation->input->count);
|
||||||
for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
|
|
||||||
anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
if (isCubic) {
|
||||||
anim->mRotationKeys[i].mValue.x = values[ii].w;
|
anim->mNumRotationKeys = numLogicalKeys * 3;
|
||||||
anim->mRotationKeys[i].mValue.y = values[ii].x;
|
anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
|
||||||
anim->mRotationKeys[i].mValue.z = values[ii].y;
|
for (unsigned int i = 0; i < numLogicalKeys; ++i) {
|
||||||
anim->mRotationKeys[i].mValue.w = values[ii].z;
|
unsigned int srcBase = i * 3;
|
||||||
ii += (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1;
|
unsigned int dstBase = i * 3;
|
||||||
|
for (unsigned int t = 0; t < 3; ++t) {
|
||||||
|
anim->mRotationKeys[dstBase + t].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
|
anim->mRotationKeys[dstBase + t].mValue.x = values[srcBase + t].w;
|
||||||
|
anim->mRotationKeys[dstBase + t].mValue.y = values[srcBase + t].x;
|
||||||
|
anim->mRotationKeys[dstBase + t].mValue.z = values[srcBase + t].y;
|
||||||
|
anim->mRotationKeys[dstBase + t].mValue.w = values[srcBase + t].z;
|
||||||
|
anim->mRotationKeys[dstBase + t].mInterpolation = interpType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
anim->mNumRotationKeys = numLogicalKeys;
|
||||||
|
anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
|
||||||
|
for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
|
||||||
|
anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
|
anim->mRotationKeys[i].mValue.x = values[i].w;
|
||||||
|
anim->mRotationKeys[i].mValue.y = values[i].x;
|
||||||
|
anim->mRotationKeys[i].mValue.z = values[i].y;
|
||||||
|
anim->mRotationKeys[i].mValue.w = values[i].z;
|
||||||
|
anim->mRotationKeys[i].mInterpolation = interpType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete[] times;
|
delete[] times;
|
||||||
delete[] values;
|
delete[] values;
|
||||||
@@ -1390,13 +1439,30 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset &, Node &node, AnimationSamplers &sample
|
|||||||
samplers.scale->input->ExtractData(times);
|
samplers.scale->input->ExtractData(times);
|
||||||
aiVector3D *values = nullptr;
|
aiVector3D *values = nullptr;
|
||||||
samplers.scale->output->ExtractData(values);
|
samplers.scale->output->ExtractData(values);
|
||||||
anim->mNumScalingKeys = static_cast<unsigned int>(samplers.scale->input->count);
|
const bool isCubic = (samplers.scale->interpolation == Interpolation_CUBICSPLINE);
|
||||||
anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
|
const aiAnimInterpolation interpType = MapInterpolation(samplers.scale->interpolation);
|
||||||
unsigned int ii = (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
|
const unsigned int numLogicalKeys = static_cast<unsigned int>(samplers.scale->input->count);
|
||||||
for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) {
|
|
||||||
anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
if (isCubic) {
|
||||||
anim->mScalingKeys[i].mValue = values[ii];
|
anim->mNumScalingKeys = numLogicalKeys * 3;
|
||||||
ii += (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1;
|
anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
|
||||||
|
for (unsigned int i = 0; i < numLogicalKeys; ++i) {
|
||||||
|
unsigned int srcBase = i * 3;
|
||||||
|
unsigned int dstBase = i * 3;
|
||||||
|
for (unsigned int t = 0; t < 3; ++t) {
|
||||||
|
anim->mScalingKeys[dstBase + t].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
|
anim->mScalingKeys[dstBase + t].mValue = values[srcBase + t];
|
||||||
|
anim->mScalingKeys[dstBase + t].mInterpolation = interpType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
anim->mNumScalingKeys = numLogicalKeys;
|
||||||
|
anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
|
||||||
|
for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) {
|
||||||
|
anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
|
anim->mScalingKeys[i].mValue = values[i];
|
||||||
|
anim->mScalingKeys[i].mInterpolation = interpType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete[] times;
|
delete[] times;
|
||||||
delete[] values;
|
delete[] values;
|
||||||
|
|||||||
@@ -80,11 +80,11 @@ aiReturn aiGetMaterialProperty(const aiMaterial *pMat,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*pPropOut = nullptr;
|
*pPropOut = nullptr;
|
||||||
|
|
||||||
return AI_FAILURE;
|
return AI_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace {
|
||||||
{
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Implementation of functions "aiGetMaterialFloatArray" and "aiGetMaterialFloatFloatArray".
|
// Implementation of functions "aiGetMaterialFloatArray" and "aiGetMaterialFloatFloatArray".
|
||||||
@@ -98,8 +98,8 @@ aiReturn GetMaterialFloatArray(const aiMaterial *pMat,
|
|||||||
ai_assert(pOut != nullptr);
|
ai_assert(pOut != nullptr);
|
||||||
ai_assert(pMat != nullptr);
|
ai_assert(pMat != nullptr);
|
||||||
|
|
||||||
const aiMaterialProperty *prop;
|
const aiMaterialProperty *prop{nullptr};
|
||||||
aiGetMaterialProperty(pMat, pKey, type, index, (const aiMaterialProperty **)&prop);
|
aiGetMaterialProperty(pMat, pKey, type, index, &prop);
|
||||||
if (nullptr == prop) {
|
if (nullptr == prop) {
|
||||||
return AI_FAILURE;
|
return AI_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,6 @@ aiReturn GetMaterialFloatArray(const aiMaterial *pMat,
|
|||||||
iWrite = prop->mDataLength / sizeof(float);
|
iWrite = prop->mDataLength / sizeof(float);
|
||||||
if (pMax) {
|
if (pMax) {
|
||||||
iWrite = std::min(*pMax, iWrite);
|
iWrite = std::min(*pMax, iWrite);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int a = 0; a < iWrite; ++a) {
|
for (unsigned int a = 0; a < iWrite; ++a) {
|
||||||
@@ -120,9 +119,7 @@ aiReturn GetMaterialFloatArray(const aiMaterial *pMat,
|
|||||||
if (pMax) {
|
if (pMax) {
|
||||||
*pMax = iWrite;
|
*pMax = iWrite;
|
||||||
}
|
}
|
||||||
}
|
} else if (aiPTI_Double == prop->mType) { // data is given in doubles, convert to TReal
|
||||||
// data is given in doubles, convert to TReal
|
|
||||||
else if (aiPTI_Double == prop->mType) {
|
|
||||||
iWrite = prop->mDataLength / sizeof(double);
|
iWrite = prop->mDataLength / sizeof(double);
|
||||||
if (pMax) {
|
if (pMax) {
|
||||||
iWrite = std::min(*pMax, iWrite);
|
iWrite = std::min(*pMax, iWrite);
|
||||||
@@ -134,9 +131,7 @@ aiReturn GetMaterialFloatArray(const aiMaterial *pMat,
|
|||||||
if (pMax) {
|
if (pMax) {
|
||||||
*pMax = iWrite;
|
*pMax = iWrite;
|
||||||
}
|
}
|
||||||
}
|
} else if (aiPTI_Integer == prop->mType) { // data is given in ints, convert to TReal
|
||||||
// data is given in ints, convert to TReal
|
|
||||||
else if (aiPTI_Integer == prop->mType) {
|
|
||||||
iWrite = prop->mDataLength / sizeof(int32_t);
|
iWrite = prop->mDataLength / sizeof(int32_t);
|
||||||
if (pMax) {
|
if (pMax) {
|
||||||
iWrite = std::min(*pMax, iWrite);
|
iWrite = std::min(*pMax, iWrite);
|
||||||
@@ -148,9 +143,7 @@ aiReturn GetMaterialFloatArray(const aiMaterial *pMat,
|
|||||||
if (pMax) {
|
if (pMax) {
|
||||||
*pMax = iWrite;
|
*pMax = iWrite;
|
||||||
}
|
}
|
||||||
}
|
} else { // a string ... read floats separated by spaces
|
||||||
// a string ... read floats separated by spaces
|
|
||||||
else {
|
|
||||||
if (pMax) {
|
if (pMax) {
|
||||||
iWrite = *pMax;
|
iWrite = *pMax;
|
||||||
}
|
}
|
||||||
@@ -174,6 +167,7 @@ aiReturn GetMaterialFloatArray(const aiMaterial *pMat,
|
|||||||
*pMax = iWrite;
|
*pMax = iWrite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return AI_SUCCESS;
|
return AI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +179,7 @@ aiReturn aiGetMaterialFloatFloatArray(const aiMaterial *pMat,
|
|||||||
unsigned int index,
|
unsigned int index,
|
||||||
float *pOut,
|
float *pOut,
|
||||||
unsigned int *pMax) {
|
unsigned int *pMax) {
|
||||||
return ::GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
|
return GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -198,7 +192,7 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat,
|
|||||||
unsigned int index,
|
unsigned int index,
|
||||||
ai_real *pOut,
|
ai_real *pOut,
|
||||||
unsigned int *pMax) {
|
unsigned int *pMax) {
|
||||||
return ::GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
|
return GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -213,7 +207,7 @@ aiReturn aiGetMaterialIntegerArray(const aiMaterial *pMat,
|
|||||||
ai_assert(pMat != nullptr);
|
ai_assert(pMat != nullptr);
|
||||||
|
|
||||||
const aiMaterialProperty *prop;
|
const aiMaterialProperty *prop;
|
||||||
aiGetMaterialProperty(pMat, pKey, type, index, (const aiMaterialProperty **)&prop);
|
aiGetMaterialProperty(pMat, pKey, type, index, &prop);
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
return AI_FAILURE;
|
return AI_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -305,7 +299,7 @@ aiReturn aiGetMaterialUVTransform(const aiMaterial *pMat,
|
|||||||
unsigned int index,
|
unsigned int index,
|
||||||
aiUVTransform *pOut) {
|
aiUVTransform *pOut) {
|
||||||
unsigned int iMax = 5;
|
unsigned int iMax = 5;
|
||||||
return aiGetMaterialFloatArray(pMat, pKey, type, index, (ai_real *)pOut, &iMax);
|
return aiGetMaterialFloatArray(pMat, pKey, type, index, reinterpret_cast<ai_real *>(pOut), &iMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -317,8 +311,8 @@ aiReturn aiGetMaterialString(const aiMaterial *pMat,
|
|||||||
aiString *pOut) {
|
aiString *pOut) {
|
||||||
ai_assert(pOut != nullptr);
|
ai_assert(pOut != nullptr);
|
||||||
|
|
||||||
const aiMaterialProperty *prop;
|
const aiMaterialProperty *prop{nullptr};
|
||||||
aiGetMaterialProperty(pMat, pKey, type, index, (const aiMaterialProperty **)&prop);
|
aiGetMaterialProperty(pMat, pKey, type, index, &prop);
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
return AI_FAILURE;
|
return AI_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -386,7 +380,7 @@ aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial *mat,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine mapping type
|
// Determine mapping type
|
||||||
int mapping_ = static_cast<int>(aiTextureMapping_UV);
|
int mapping_ = aiTextureMapping_UV;
|
||||||
aiGetMaterialInteger(mat, AI_MATKEY_MAPPING(type, index), &mapping_);
|
aiGetMaterialInteger(mat, AI_MATKEY_MAPPING(type, index), &mapping_);
|
||||||
aiTextureMapping mapping = static_cast<aiTextureMapping>(mapping_);
|
aiTextureMapping mapping = static_cast<aiTextureMapping>(mapping_);
|
||||||
if (_mapping)
|
if (_mapping)
|
||||||
@@ -417,12 +411,11 @@ aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial *mat,
|
|||||||
return AI_SUCCESS;
|
return AI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned int DefaultNumAllocated = 5;
|
static constexpr unsigned int DefaultNumAllocated = 5;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Construction. Actually the one and only way to get an aiMaterial instance
|
// Construction. Actually the one and only way to get an aiMaterial instance
|
||||||
aiMaterial::aiMaterial() :
|
aiMaterial::aiMaterial() : mProperties(nullptr), mNumProperties(0), mNumAllocated(DefaultNumAllocated) {
|
||||||
mProperties(nullptr), mNumProperties(0), mNumAllocated(DefaultNumAllocated) {
|
|
||||||
// Allocate 5 entries by default
|
// Allocate 5 entries by default
|
||||||
mProperties = new aiMaterialProperty *[DefaultNumAllocated];
|
mProperties = new aiMaterialProperty *[DefaultNumAllocated];
|
||||||
}
|
}
|
||||||
@@ -436,7 +429,7 @@ aiMaterial::~aiMaterial() {
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
aiString aiMaterial::GetName() const {
|
aiString aiMaterial::GetName() const {
|
||||||
aiString name;
|
aiString name{};
|
||||||
Get(AI_MATKEY_NAME, name);
|
Get(AI_MATKEY_NAME, name);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
@@ -507,7 +500,7 @@ aiReturn aiMaterial::AddBinaryProperty(const void *pInput,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a new material property
|
// Allocate a new material property
|
||||||
std::unique_ptr<aiMaterialProperty> pcNew(new aiMaterialProperty());
|
auto pcNew = std::make_unique<aiMaterialProperty>();
|
||||||
|
|
||||||
// .. and fill it
|
// .. and fill it
|
||||||
pcNew->mType = pType;
|
pcNew->mType = pType;
|
||||||
@@ -569,11 +562,9 @@ aiReturn aiMaterial::AddProperty(const aiString *pInput,
|
|||||||
uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName /*= false*/) {
|
uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName /*= false*/) {
|
||||||
uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
|
uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
|
||||||
for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
|
for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
|
||||||
aiMaterialProperty *prop;
|
|
||||||
|
|
||||||
// Exclude all properties whose first character is '?' from the hash
|
// Exclude all properties whose first character is '?' from the hash
|
||||||
// See doc for aiMaterialProperty.
|
// See doc for aiMaterialProperty.
|
||||||
prop = mat->mProperties[i];
|
const aiMaterialProperty *prop = mat->mProperties[i];
|
||||||
if (nullptr != prop && (includeMatName || prop->mKey.data[0] != '?')) {
|
if (nullptr != prop && (includeMatName || prop->mKey.data[0] != '?')) {
|
||||||
|
|
||||||
hash = SuperFastHash(prop->mKey.data, (unsigned int)prop->mKey.length, hash);
|
hash = SuperFastHash(prop->mKey.data, (unsigned int)prop->mKey.length, hash);
|
||||||
@@ -617,7 +608,7 @@ void aiMaterial::CopyPropertyList(aiMaterial *const pcDest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = iOldNum; i < pcDest->mNumProperties; ++i) {
|
for (unsigned int i = iOldNum; i < pcDest->mNumProperties; ++i) {
|
||||||
aiMaterialProperty *propSrc = pcSrc->mProperties[i];
|
const aiMaterialProperty *propSrc = pcSrc->mProperties[i];
|
||||||
|
|
||||||
// search whether we have already a property with this name -> if yes, overwrite it
|
// search whether we have already a property with this name -> if yes, overwrite it
|
||||||
aiMaterialProperty *prop;
|
aiMaterialProperty *prop;
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) {
|
|||||||
++numOut;
|
++numOut;
|
||||||
} else {
|
} else {
|
||||||
numOut += face.mNumIndices-2;
|
numOut += face.mNumIndices-2;
|
||||||
max_out = std::max(max_out,face.mNumIndices);
|
max_out = std::max<uint32_t>(max_out,face.mNumIndices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -796,10 +796,13 @@ char *OpenDDLParser::parseStringLiteral(char *in, char *end, Value **stringData)
|
|||||||
if (*start == '\"') {
|
if (*start == '\"') {
|
||||||
++start;
|
++start;
|
||||||
++in;
|
++in;
|
||||||
while (*in != '\"' && in != end) {
|
while (in != end && *in != '\"') {
|
||||||
++in;
|
++in;
|
||||||
++len;
|
++len;
|
||||||
}
|
}
|
||||||
|
if (in == end) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
*stringData = ValueAllocator::allocPrimData(Value::ValueType::ddl_string, len);
|
*stringData = ValueAllocator::allocPrimData(Value::ValueType::ddl_string, len);
|
||||||
::strncpy((char *)(*stringData)->m_data, start, len);
|
::strncpy((char *)(*stringData)->m_data, start, len);
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_emp
|
|||||||
mSkip_empty_lines(skip_empty_lines),
|
mSkip_empty_lines(skip_empty_lines),
|
||||||
mTrim(trim) {
|
mTrim(trim) {
|
||||||
mCur.reserve(1024);
|
mCur.reserve(1024);
|
||||||
mEnd = mCur.c_str() + 1024;
|
mEnd = mCur.c_str() + mCur.capacity();
|
||||||
operator++();
|
operator++();
|
||||||
mIdx = 0;
|
mIdx = 0;
|
||||||
}
|
}
|
||||||
@@ -183,6 +183,7 @@ AI_FORCE_INLINE LineSplitter& LineSplitter::operator++() {
|
|||||||
|
|
||||||
char s;
|
char s;
|
||||||
mCur.clear();
|
mCur.clear();
|
||||||
|
mEnd = mCur.c_str() + mCur.capacity();
|
||||||
while (mStream.GetRemainingSize() && (s = mStream.GetI1(), 1)) {
|
while (mStream.GetRemainingSize() && (s = mStream.GetI1(), 1)) {
|
||||||
if (s == '\n' || s == '\r') {
|
if (s == '\n' || s == '\r') {
|
||||||
if (mSkip_empty_lines) {
|
if (mSkip_empty_lines) {
|
||||||
@@ -205,6 +206,7 @@ AI_FORCE_INLINE LineSplitter& LineSplitter::operator++() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mCur += s;
|
mCur += s;
|
||||||
|
mEnd = mCur.c_str() + mCur.capacity();
|
||||||
}
|
}
|
||||||
++mIdx;
|
++mIdx;
|
||||||
|
|
||||||
|
|||||||
@@ -124,11 +124,11 @@ AI_FORCE_INLINE bool IsSpaceOrNewLine(char_t in) {
|
|||||||
/// @return true if valid.
|
/// @return true if valid.
|
||||||
template <class char_t>
|
template <class char_t>
|
||||||
AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out, const char_t *end) {
|
AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out, const char_t *end) {
|
||||||
while ((*in == (char_t)' ' || *in == (char_t)'\t') && in != end) {
|
while (in < end && (*in == (char_t)' ' || *in == (char_t)'\t')) {
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
*out = in;
|
*out = in;
|
||||||
return !IsLineEnd<char_t>(*in);
|
return ((in < end) && !IsLineEnd<char_t>(*in));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
@@ -154,11 +154,11 @@ AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out, const char_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
// files are opened in binary mode. Ergo there are both NL and CR
|
// files are opened in binary mode. Ergo there are both NL and CR
|
||||||
while ((*in == (char_t)'\r' || *in == (char_t)'\n') && in != end) {
|
while (in < end && (*in == (char_t)'\r' || *in == (char_t)'\n')) {
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
*out = in;
|
*out = in;
|
||||||
return *in != (char_t)'\0';
|
return in < end && *in != (char_t)'\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
@@ -178,11 +178,11 @@ AI_FORCE_INLINE bool SkipLine(const char_t **inout, const char_t *end) {
|
|||||||
/// @return true if valid.
|
/// @return true if valid.
|
||||||
template <class char_t>
|
template <class char_t>
|
||||||
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out, const char_t *end) {
|
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out, const char_t *end) {
|
||||||
while ((*in == (char_t)' ' || *in == (char_t)'\t' || *in == (char_t)'\r' || *in == (char_t)'\n') && in != end) {
|
while (in < end && (*in == (char_t)' ' || *in == (char_t)'\t' || *in == (char_t)'\r' || *in == (char_t)'\n')) {
|
||||||
++in;
|
++in;
|
||||||
}
|
}
|
||||||
*out = in;
|
*out = in;
|
||||||
return *in != '\0';
|
return in < end && *in != '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ typedef unsigned int ai_uint;
|
|||||||
|
|
||||||
/* Numerical limits */
|
/* Numerical limits */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
constexpr ai_real ai_epsilon = (ai_real) 1e-6;
|
inline constexpr ai_real ai_epsilon = (ai_real) 1e-6;
|
||||||
#else
|
#else
|
||||||
# define ai_epsilon ((ai_real)1e-6)
|
# define ai_epsilon ((ai_real)1e-6)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
[[package]]
|
|
||||||
name = "assimp_rs"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
@@ -6,4 +6,5 @@ edition = "2018"
|
|||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[build-dependencies]
|
||||||
|
bindgen = "*"
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
extern crate bindgen;
|
||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Rerun if wrapper header changes
|
||||||
|
println!("cargo:rerun-if-changed=./src/assimp_wrapper.h");
|
||||||
|
|
||||||
|
// Tell cargo to look for shared libraries in the specified directory
|
||||||
|
println!("cargo:rustc-link-search=../../bin/");
|
||||||
|
|
||||||
|
// Tell cargo to tell rustc to link the assimp shared library.
|
||||||
|
println!("cargo:rustc-link-lib=assimp");
|
||||||
|
|
||||||
|
// The bindgen::Builder is the main entry point
|
||||||
|
// to bindgen, and lets you build up options for
|
||||||
|
// the resulting bindings.
|
||||||
|
let bindings = bindgen::Builder::default()
|
||||||
|
// The input header we would like to generate
|
||||||
|
// bindings for.
|
||||||
|
.header("./src/assimp_wrapper.h").clang_arg("-I../../include/")
|
||||||
|
// Tell cargo to invalidate the built crate whenever any of the
|
||||||
|
// included header files changed.
|
||||||
|
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
||||||
|
.blocklist_item("FP_ZERO")
|
||||||
|
.blocklist_item("FP_SUBNORMAL")
|
||||||
|
.blocklist_item("FP_NORMAL")
|
||||||
|
.blocklist_item("FP_INFINITE")
|
||||||
|
.blocklist_item("FP_NAN")
|
||||||
|
// Finish the builder and generate the bindings.
|
||||||
|
.generate()
|
||||||
|
// Unwrap the Result and panic on failure.
|
||||||
|
.expect("Unable to generate bindings");
|
||||||
|
|
||||||
|
// Write the bindings to the $OUT_DIR/bindings.rs file.
|
||||||
|
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
|
bindings
|
||||||
|
.write_to_file(out_path.join("bindings.rs"))
|
||||||
|
.expect("Couldn't write bindings!");
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef ASSIMP_WRAPPER_H_INC
|
||||||
|
#define ASSIMP_WRAPPER_H_INC
|
||||||
|
|
||||||
|
#include <assimp/defs.h>
|
||||||
|
#include <assimp/camera.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/types.h>
|
||||||
|
#include <assimp/vector3.h>
|
||||||
|
#include <assimp/matrix4x4.h>
|
||||||
|
#include <assimp/quaternion.h>
|
||||||
|
#include <assimp/color4.h>
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
#include <assimp/anim.h>
|
||||||
|
#include <assimp/metadata.h>
|
||||||
|
#include <assimp/light.h>
|
||||||
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/texture.h>
|
||||||
|
#include <assimp/postprocess.h>
|
||||||
|
#include <assimp/version.h>
|
||||||
|
#include <assimp/importerdesc.h>
|
||||||
|
#include <assimp/aabb.h>
|
||||||
|
#include <assimp/anim.h>
|
||||||
|
#include <assimp/camera.h>
|
||||||
|
#include <assimp/cexport.h>
|
||||||
|
#include <assimp/cfileio.h>
|
||||||
|
#include <assimp/cimport.h>
|
||||||
|
#include <assimp/color4.h>
|
||||||
|
#include <assimp/commonMetaData.h>
|
||||||
|
#include <assimp/defs.h>
|
||||||
|
#include <assimp/importerdesc.h>
|
||||||
|
#include <assimp/light.h>
|
||||||
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/matrix3x3.h>
|
||||||
|
#include <assimp/matrix4x4.h>
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
#include <assimp/metadata.h>
|
||||||
|
#include <assimp/pbrmaterial.h>
|
||||||
|
#include <assimp/postprocess.h>
|
||||||
|
#include <assimp/quaternion.h>
|
||||||
|
#include <assimp/revision.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/texture.h>
|
||||||
|
#include <assimp/types.h>
|
||||||
|
#include <assimp/vector2.h>
|
||||||
|
#include <assimp/vector3.h>
|
||||||
|
#include <assimp/version.h>
|
||||||
|
|
||||||
|
#endif // ASSIMP_WRAPPER_H_INC
|
||||||
@@ -1 +0,0 @@
|
|||||||
pub use self::structs::{Camera};
|
|
||||||
+15
-11
@@ -1,17 +1,21 @@
|
|||||||
pub mod camera;
|
|
||||||
pub mod core;
|
#![allow(non_upper_case_globals)]
|
||||||
pub mod errors;
|
#![allow(non_camel_case_types)]
|
||||||
pub mod formats;
|
#![allow(non_snake_case)]
|
||||||
pub mod material;
|
|
||||||
pub mod postprocess;
|
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||||
pub mod shims;
|
|
||||||
pub mod socket;
|
|
||||||
pub mod structs;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() {
|
fn import_test() {
|
||||||
assert_eq!(true, true);
|
unsafe {
|
||||||
|
use crate::aiImportFile;
|
||||||
|
let mut file: *mut dyn const i8 = std::ptr::null_mut();
|
||||||
|
//let file = String::from("test.obj");
|
||||||
|
//let (ptr, len, cap) = file.into_raw_parts();
|
||||||
|
//let raw_file = unsafe{String::from_raw_parts}
|
||||||
|
let asset = aiImportFile(file, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
pub struct Animation<'mA, 'mMA, 'nA> {
|
|
||||||
/* The name of the animation. If the modeling package this data was
|
|
||||||
* exported from does support only a single animation channel, this
|
|
||||||
* name is usually empty (length is zero).
|
|
||||||
*/
|
|
||||||
m_name: Option<String>,
|
|
||||||
// Duration of the animation in ticks
|
|
||||||
m_duration: f64,
|
|
||||||
// Ticks per second. Zero (0.000... ticks/second) if not
|
|
||||||
// specified in the imported file
|
|
||||||
m_ticks_per_second: Option<f64>,
|
|
||||||
/* Number of bone animation channels.
|
|
||||||
Each channel affects a single node.
|
|
||||||
*/
|
|
||||||
m_num_channels: u64,
|
|
||||||
/* Node animation channels. Each channel
|
|
||||||
affects a single node.
|
|
||||||
?? -> The array is m_num_channels in size.
|
|
||||||
(maybe refine to a derivative type of usize?)
|
|
||||||
*/
|
|
||||||
m_channels: &'nA NodeAnim,
|
|
||||||
/* Number of mesh animation channels. Each
|
|
||||||
channel affects a single mesh and defines
|
|
||||||
vertex-based animation.
|
|
||||||
*/
|
|
||||||
m_num_mesh_channels: u64,
|
|
||||||
/* The mesh animation channels. Each channel
|
|
||||||
affects a single mesh.
|
|
||||||
The array is m_num_mesh_channels in size
|
|
||||||
(maybe refine to a derivative of usize?)
|
|
||||||
*/
|
|
||||||
m_mesh_channels: &'mA MeshAnim,
|
|
||||||
/* The number of mesh animation channels. Each channel
|
|
||||||
affects a single mesh and defines some morphing animation.
|
|
||||||
*/
|
|
||||||
m_num_morph_mesh_channels: u64,
|
|
||||||
/* The morph mesh animation channels. Each channel affects a single mesh.
|
|
||||||
The array is mNumMorphMeshChannels in size.
|
|
||||||
*/
|
|
||||||
m_morph_mesh_channels: &'mMA MeshMorphAnim
|
|
||||||
}
|
|
||||||
pub struct NodeAnim {}
|
|
||||||
pub struct MeshAnim {}
|
|
||||||
pub struct MeshMorphAnim {}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
mod anim;
|
|
||||||
pub use self::anim::{
|
|
||||||
Animation,
|
|
||||||
NodeAnim,
|
|
||||||
MeshAnim,
|
|
||||||
MeshMorphAnim};
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod blob;
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod bone;
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod camera;
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#[derive(Clone, Debug, Copy)]
|
|
||||||
struct Color3D {
|
|
||||||
r: f32,
|
|
||||||
g: f32,
|
|
||||||
b: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Color3D {
|
|
||||||
pub fn new(r_f32: f32, g_f32: f32, b_f32: f32) -> Color3D {
|
|
||||||
Color3D {r: r_f32, g: g_f32, b: b_f32 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Copy)]
|
|
||||||
struct Color4D {
|
|
||||||
r: f32,
|
|
||||||
g: f32,
|
|
||||||
b: f32,
|
|
||||||
a: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Color4D {
|
|
||||||
pub fn new(r_f32: f32, g_f32: f32, b_f32: f32, a_f32: f32) -> Color4D {
|
|
||||||
Color4D {r: r_f32, g: g_f32, b: b_f32, a: a_f32 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
mod color;
|
|
||||||
pub use self::color::{
|
|
||||||
Color3D,
|
|
||||||
Color4D
|
|
||||||
};
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod face;
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod key;
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod light;
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod material;
|
|
||||||
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
#[derive(Clone, Debug, Copy)]
|
|
||||||
struct Matrix3x3 {
|
|
||||||
a1: f32,
|
|
||||||
a2: f32,
|
|
||||||
a3: f32,
|
|
||||||
b1: f32,
|
|
||||||
b2: f32,
|
|
||||||
b3: f32,
|
|
||||||
c1: f32,
|
|
||||||
c2: f32,
|
|
||||||
c3: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Copy)]
|
|
||||||
struct Matrix4x4 {
|
|
||||||
a1: f32,
|
|
||||||
a2: f32,
|
|
||||||
a3: f32,
|
|
||||||
a4: f32,
|
|
||||||
b1: f32,
|
|
||||||
b2: f32,
|
|
||||||
b3: f32,
|
|
||||||
b4: f32,
|
|
||||||
c1: f32,
|
|
||||||
c2: f32,
|
|
||||||
c3: f32,
|
|
||||||
c4: f32,
|
|
||||||
d1: f32,
|
|
||||||
d2: f32,
|
|
||||||
d3: f32,
|
|
||||||
d4: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Matrix3x3 {
|
|
||||||
pub fn new(
|
|
||||||
a1_f32: f32, a2_f32: f32, a3_f32: f32,
|
|
||||||
b1_f32: f32, b2_f32: f32, b3_f32: f32,
|
|
||||||
c1_f32: f32, c2_f32: f32, c3_f32: f32
|
|
||||||
) -> Matrix3x3 {
|
|
||||||
Matrix3x3 {
|
|
||||||
a1: a1_f32, a2: a2_f32, a3: a3_f32,
|
|
||||||
b1: b1_f32, b2: b2_f32, b3: b3_f32,
|
|
||||||
c1: c1_f32, c2: c2_f32, c3: c3_f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Matrix4x4 {
|
|
||||||
pub fn new(
|
|
||||||
a1_f32: f32, a2_f32: f32, a3_f32: f32, a4_f32: f32,
|
|
||||||
b1_f32: f32, b2_f32: f32, b3_f32: f32, b4_f32: f32,
|
|
||||||
c1_f32: f32, c2_f32: f32, c3_f32: f32, c4_f32: f32,
|
|
||||||
d1_f32: f32, d2_f32: f32, d3_f32: f32, d4_f32: f32
|
|
||||||
) -> Matrix4x4 {
|
|
||||||
Matrix4x4 {
|
|
||||||
a1: a1_f32, a2: a2_f32, a3: a3_f32, a4: a4_f32,
|
|
||||||
b1: b1_f32, b2: b2_f32, b3: b3_f32, b4: b4_f32,
|
|
||||||
c1: c1_f32, c2: c2_f32, c3: c3_f32, c4: c4_f32,
|
|
||||||
d1: d1_f32, d2: d2_f32, d3: d3_f32, d4: d4_f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
mod matrix;
|
|
||||||
pub use self::matrix::{
|
|
||||||
Matrix3x3,
|
|
||||||
Matrix4x4};
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#[derive(Clone, Debug, Copy)]
|
|
||||||
struct MemoryInfo {
|
|
||||||
textures: u32,
|
|
||||||
materials: u32,
|
|
||||||
meshes: u32,
|
|
||||||
nodes: u32,
|
|
||||||
animations: u32,
|
|
||||||
cameras: u32,
|
|
||||||
lights: u32,
|
|
||||||
total: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MemoryInfo {
|
|
||||||
pub fn new(
|
|
||||||
textures_uint: u32,
|
|
||||||
materials_uint: u32,
|
|
||||||
meshes_uint: u32,
|
|
||||||
nodes_uint: u32,
|
|
||||||
animations_uint: u32,
|
|
||||||
cameras_uint: u32,
|
|
||||||
lights_uint: u32,
|
|
||||||
total_uint: u32) -> MemoryInfo {
|
|
||||||
|
|
||||||
MemoryInfo {
|
|
||||||
textures: textures_uint,
|
|
||||||
materials: materials_uint,
|
|
||||||
meshes: meshes_uint,
|
|
||||||
nodes: nodes_uint,
|
|
||||||
animations: animations_uint,
|
|
||||||
cameras: cameras_uint,
|
|
||||||
lights: lights_uint,
|
|
||||||
total: total_uint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod memory;
|
|
||||||
pub use self::memory::MemoryInfo;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
mod mesh;
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod meta;
|
|
||||||
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
mod anim;
|
|
||||||
/* Animation
|
|
||||||
* NodeAnim
|
|
||||||
* MeshAnim
|
|
||||||
* MeshMorphAnim
|
|
||||||
*/
|
|
||||||
mod blob;
|
|
||||||
/* ExportDataBlob
|
|
||||||
*/
|
|
||||||
mod vec;
|
|
||||||
/* Vector2d
|
|
||||||
* Vector3d
|
|
||||||
* */
|
|
||||||
mod matrix;
|
|
||||||
/* Matrix3by3
|
|
||||||
* Matrix4by4
|
|
||||||
*/
|
|
||||||
mod camera;
|
|
||||||
/* Camera */
|
|
||||||
mod color;
|
|
||||||
/* Color3d
|
|
||||||
* Color4d
|
|
||||||
*/
|
|
||||||
mod key;
|
|
||||||
/* MeshKey
|
|
||||||
* MeshMorphKey
|
|
||||||
* QuatKey
|
|
||||||
* VectorKey
|
|
||||||
*/
|
|
||||||
mod texel;
|
|
||||||
mod plane;
|
|
||||||
mod string;
|
|
||||||
/* String
|
|
||||||
*/
|
|
||||||
mod material;
|
|
||||||
/* Material
|
|
||||||
* MaterialPropery
|
|
||||||
* MaterialPropertyString
|
|
||||||
*/
|
|
||||||
mod mem;
|
|
||||||
mod quaternion;
|
|
||||||
mod face;
|
|
||||||
mod vertex_weight;
|
|
||||||
mod mesh;
|
|
||||||
/* Mesh
|
|
||||||
*/
|
|
||||||
mod meta;
|
|
||||||
/* Metadata
|
|
||||||
* MetadataEntry
|
|
||||||
*/
|
|
||||||
mod node;
|
|
||||||
/* Node
|
|
||||||
* */
|
|
||||||
mod light;
|
|
||||||
mod texture;
|
|
||||||
mod ray;
|
|
||||||
mod transform;
|
|
||||||
/* UVTransform */
|
|
||||||
mod bone;
|
|
||||||
mod scene;
|
|
||||||
/* Scene */
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod node;
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod plane;
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#[derive(Clone, Debug, Copy)]
|
|
||||||
struct Plane {
|
|
||||||
a: f32,
|
|
||||||
b: f32,
|
|
||||||
c: f32,
|
|
||||||
d: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Plane {
|
|
||||||
pub fn new(
|
|
||||||
a_f32: f32,
|
|
||||||
b_f32: f32,
|
|
||||||
c_f32: f32,
|
|
||||||
d_f32: f32
|
|
||||||
) -> Plane {
|
|
||||||
Plane {
|
|
||||||
a: a_f32,
|
|
||||||
b: b_f32,
|
|
||||||
c: b_f32,
|
|
||||||
d: d_f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
mod quaternion;
|
|
||||||
|
|
||||||
pub use self::quaternion::Quaternion;
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
use crate::vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Copy)]
|
|
||||||
pub struct Quaternion {
|
|
||||||
_coordinates: vec::Vector4d
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod ray;
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod scene;
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
mod string;
|
|
||||||
pub use self::string::MAXLEN;
|
|
||||||
pub use self::string::Str;
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
pub const MAXLEN: usize = 1024;
|
|
||||||
|
|
||||||
/// Want to consider replacing `Vec<char>`
|
|
||||||
/// with a comparable definition at
|
|
||||||
/// https://doc.rust-lang.org/src/alloc/string.rs.html#415-417
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct Str {
|
|
||||||
length: usize,
|
|
||||||
data: Vec<char>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Str {
|
|
||||||
pub fn new(len_u32: usize, data_string: String) -> Str {
|
|
||||||
Str {
|
|
||||||
length: len_u32,
|
|
||||||
data: data_string.chars().collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// MaterialPropertyStr
|
|
||||||
/// The size of length is truncated to 4 bytes on a 64-bit platform when used as a
|
|
||||||
/// material property (see MaterialSystem.cpp, as aiMaterial::AddProperty() ).
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct MaterialPropertyStr {
|
|
||||||
length: usize,
|
|
||||||
data: Vec<char>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl MaterialPropertyStr {
|
|
||||||
pub fn new(len_u32: usize, data_string: String) -> MaterialPropertyStr {
|
|
||||||
MaterialPropertyStr {
|
|
||||||
length: len_u32,
|
|
||||||
data: data_string.chars().collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
mod texture;
|
|
||||||
pub use self::texture::Texel;
|
|
||||||
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#[derive(Clone, Debug, Copy)]
|
|
||||||
struct Texel {
|
|
||||||
b: u32,
|
|
||||||
g: u32,
|
|
||||||
r: u32,
|
|
||||||
a: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Texel {
|
|
||||||
pub fn new(b_u32: u32, g_u32: u32,
|
|
||||||
r_u32: u32, a_u32: u32) -> Texel {
|
|
||||||
Texel {
|
|
||||||
b: b_u32,
|
|
||||||
g: g_u32,
|
|
||||||
r: r_u32,
|
|
||||||
a: a_u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod transform;
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod vec;
|
|
||||||
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
struct Vector2d {
|
|
||||||
x: f32,
|
|
||||||
y: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Vector3d {
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
z: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Vector4d {
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
z: f32,
|
|
||||||
w: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vector2d {
|
|
||||||
pub fn new(x_f32: f32, y_f32: f32) -> Vector2d {
|
|
||||||
Vector2d {
|
|
||||||
x: x_f32,
|
|
||||||
y: y_f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vector3d {
|
|
||||||
pub fn new(x_f32: f32, y_f32: f32, z_f32: f32) -> Vector3d {
|
|
||||||
Vector3d {
|
|
||||||
x: x_f32,
|
|
||||||
y: y_f32,
|
|
||||||
z: z_f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vector4d {
|
|
||||||
pub fn new(x_f32: f32, y_f32: f32, z_f32: f32, w_f32: f32) -> Vector4d {
|
|
||||||
Vector4d {
|
|
||||||
x: x_f32,
|
|
||||||
y: y_f32,
|
|
||||||
z: z_f32,
|
|
||||||
w: w_f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
mod vertex;
|
|
||||||
// pub use self::vertex::
|
|
||||||
@@ -155,7 +155,7 @@ TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3FromToTest) {
|
|||||||
const auto from = aiVector3D(1,2,1).Normalize(), to = aiVector3D(-1,1,1).Normalize();
|
const auto from = aiVector3D(1,2,1).Normalize(), to = aiVector3D(-1,1,1).Normalize();
|
||||||
aiMatrix3x3::FromToMatrix(from, to, result_cpp);
|
aiMatrix3x3::FromToMatrix(from, to, result_cpp);
|
||||||
aiMatrix3FromTo(&result_c, &from, &to);
|
aiMatrix3FromTo(&result_c, &from, &to);
|
||||||
EXPECT_EQ(result_cpp, result_c);
|
EXPECT_TRUE(result_cpp.Equal(result_c, Epsilon));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AssimpAPITest_aiMatrix3x3, operatorTest) {
|
TEST_F(AssimpAPITest_aiMatrix3x3, operatorTest) {
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromToTest) {
|
|||||||
const auto from = aiVector3D(1,2,1).Normalize(), to = aiVector3D(-1,1,1).Normalize();
|
const auto from = aiVector3D(1,2,1).Normalize(), to = aiVector3D(-1,1,1).Normalize();
|
||||||
aiMatrix4x4::FromToMatrix(from, to, result_cpp);
|
aiMatrix4x4::FromToMatrix(from, to, result_cpp);
|
||||||
aiMatrix4FromTo(&result_c, &from, &to);
|
aiMatrix4FromTo(&result_c, &from, &to);
|
||||||
EXPECT_EQ(result_cpp, result_c);
|
EXPECT_TRUE(result_cpp.Equal(result_c, Epsilon));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AssimpAPITest_aiMatrix4x4, operatorTest) {
|
TEST_F(AssimpAPITest_aiMatrix4x4, operatorTest) {
|
||||||
|
|||||||
@@ -88,7 +88,10 @@ TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionFromNormalizedQuaternionTest) {
|
|||||||
const auto qvec3 = random_unit_vec3();
|
const auto qvec3 = random_unit_vec3();
|
||||||
result_cpp = aiQuaternion(qvec3);
|
result_cpp = aiQuaternion(qvec3);
|
||||||
aiQuaternionFromNormalizedQuaternion(&result_c, &qvec3);
|
aiQuaternionFromNormalizedQuaternion(&result_c, &qvec3);
|
||||||
EXPECT_EQ(result_cpp, result_c);
|
// Use a larger tolerance because FMA contraction differences in
|
||||||
|
// 1.0 - x*x - y*y - z*z can flip the sign of a near-zero residual,
|
||||||
|
// causing w = 0 vs w = sqrt(tiny) ≈ 1e-4.
|
||||||
|
EXPECT_TRUE(result_cpp.Equal(result_c, 1e-4f));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionAreEqualTest) {
|
TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionAreEqualTest) {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ TEST_F( utVersion, aiGetVersionMinorTest ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F( utVersion, aiGetVersionPatchTest ) {
|
TEST_F( utVersion, aiGetVersionPatchTest ) {
|
||||||
EXPECT_EQ(aiGetVersionPatch(), 4U );
|
EXPECT_EQ(aiGetVersionPatch(), 5U );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F( utVersion, aiGetCompileFlagsTest ) {
|
TEST_F( utVersion, aiGetCompileFlagsTest ) {
|
||||||
|
|||||||
Reference in New Issue
Block a user