Compare commits
127 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c3206f919 | ||
|
|
4886eebbf4 | ||
|
|
91c727e204 | ||
|
|
26bdacedf6 | ||
|
|
7212ee47eb | ||
|
|
0fe1bb96c2 | ||
|
|
4bd75baaae | ||
|
|
bbcfe59c0f | ||
|
|
38c07d34c4 | ||
|
|
2019ace3b7 | ||
|
|
ad96ff0769 | ||
|
|
d7f83f29f0 | ||
|
|
98fad65028 | ||
|
|
e88016c63f | ||
|
|
edabf19461 | ||
|
|
8bed734a18 | ||
|
|
60ffb3ca9a | ||
|
|
6507e70236 | ||
|
|
2daec8be53 | ||
|
|
c2ff3f12fc | ||
|
|
a6a134a60e | ||
|
|
e0b39341fc | ||
|
|
947582b592 | ||
|
|
c207ff3561 | ||
|
|
41dd7c806e | ||
|
|
aa4dabe64f | ||
|
|
9868630d0e | ||
|
|
f2397573f3 | ||
|
|
7d5699118e | ||
|
|
0948ca0417 | ||
|
|
582eb2b818 | ||
|
|
c2474e27ab | ||
|
|
6c6390f034 | ||
|
|
4d6649cc6d | ||
|
|
d543b1447f | ||
|
|
d6eeb14216 | ||
|
|
aa670fe91e | ||
|
|
ebdbd8a231 | ||
|
|
fed4322d26 | ||
|
|
039d4a6c54 | ||
|
|
28ee1b42ce | ||
|
|
35889026d6 | ||
|
|
e81ac971b0 | ||
|
|
e05ce6aff0 | ||
|
|
e4598ba84a | ||
|
|
79513077f3 | ||
|
|
72acadca79 | ||
|
|
398e358826 | ||
|
|
7fc9b0fe97 | ||
|
|
71cc967f42 | ||
|
|
3ddad1e377 | ||
|
|
92805d3088 | ||
|
|
60acd05a03 | ||
|
|
4a18e241d9 | ||
|
|
1b88a1e3c7 | ||
|
|
b3feefafdf | ||
|
|
a7a16db908 | ||
|
|
9f92ba34a6 | ||
|
|
25cf039953 | ||
|
|
6bf145d7cf | ||
|
|
69240e18b4 | ||
|
|
5b9f431512 | ||
|
|
ad79762212 | ||
|
|
64149943cc | ||
|
|
714194d353 | ||
|
|
9d81c24934 | ||
|
|
25c194bf71 | ||
|
|
5a4c5ff668 | ||
|
|
f06e814d7c | ||
|
|
5eef2b0914 | ||
|
|
49988672f4 | ||
|
|
d192402800 | ||
|
|
646f1312f1 | ||
|
|
db62a6c1cc | ||
|
|
8e53519a27 | ||
|
|
d3d6932efd | ||
|
|
dea325cdcb | ||
|
|
2b50b31657 | ||
|
|
110b49a0c8 | ||
|
|
319746d3db | ||
|
|
2cb73fa85d | ||
|
|
5a832b470a | ||
|
|
42f04024d4 | ||
|
|
07852e206d | ||
|
|
156b47760d | ||
|
|
673501749f | ||
|
|
b56fc1a0cc | ||
|
|
2ed3222bbe | ||
|
|
c7da23795d | ||
|
|
8ca2bc0de7 | ||
|
|
0a85945767 | ||
|
|
51d13700d8 | ||
|
|
1983e889dc | ||
|
|
dfe9d7bcae | ||
|
|
4dee4cc673 | ||
|
|
a7ea651bef | ||
|
|
4c2afb8814 | ||
|
|
951833812a | ||
|
|
e456cc949d | ||
|
|
75e64cd47a | ||
|
|
3736a5791f | ||
|
|
0b0bf60137 | ||
|
|
d496d8eab6 | ||
|
|
22883def8d | ||
|
|
5826f1e149 | ||
|
|
ef6560298e | ||
|
|
e3a56816d6 | ||
|
|
5ef400882a | ||
|
|
333bb55d84 | ||
|
|
7d6318c3ad | ||
|
|
d5c722125a | ||
|
|
16ed0ac129 | ||
|
|
b69d2a2c55 | ||
|
|
e210379335 | ||
|
|
659976b8f3 | ||
|
|
96ba498d70 | ||
|
|
7ecb0b2f37 | ||
|
|
a14bbdb065 | ||
|
|
bfedfbb1fb | ||
|
|
41f46c7fd7 | ||
|
|
a62dd278e2 | ||
|
|
a20e4ede85 | ||
|
|
1ab0d147cb | ||
|
|
9aee576b99 | ||
|
|
0dcc72239d | ||
|
|
33d5e9aa07 | ||
|
|
e528741a8b |
120
CMakeLists.txt
120
CMakeLists.txt
@@ -2,60 +2,134 @@
|
||||
#This configures the Cmake system with multiple properties, depending
|
||||
#on the platform and configuration it is set to build in.
|
||||
project(tinyobjloader)
|
||||
cmake_minimum_required(VERSION 2.8.6)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
set(TINYOBJLOADER_SOVERSION 1)
|
||||
set(TINYOBJLOADER_VERSION 1.0.4)
|
||||
|
||||
#Folder Shortcuts
|
||||
set(TINYOBJLOADEREXAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/examples)
|
||||
|
||||
set(tinyobjloader-Source
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tiny_obj_loader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tiny_obj_loader.cc
|
||||
)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tiny_obj_loader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tiny_obj_loader.cc
|
||||
)
|
||||
|
||||
set(tinyobjloader-Example-Source
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/loader_example.cc
|
||||
)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/loader_example.cc
|
||||
)
|
||||
|
||||
set(tinyobjloader-examples-objsticher
|
||||
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_writer.h
|
||||
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_writer.cc
|
||||
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_sticher.cc
|
||||
)
|
||||
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_writer.h
|
||||
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_writer.cc
|
||||
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_sticher.cc
|
||||
)
|
||||
|
||||
#Install destinations
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(TINYOBJLOADER_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake)
|
||||
set(TINYOBJLOADER_DOC_DIR ${CMAKE_INSTALL_DOCDIR})
|
||||
set(TINYOBJLOADER_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
set(TINYOBJLOADER_LIBRARY_DIR ${CMAKE_INSTALL_LIBDIR})
|
||||
set(TINYOBJLOADER_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
set(TINYOBJLOADER_RUNTIME_DIR ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
option(TINYOBJLOADER_BUILD_TEST_LOADER "Build Example Loader Application" OFF)
|
||||
option(TINYOBJLOADER_COMPILATION_SHARED "Build as shared library" OFF)
|
||||
|
||||
if (TINYOBJLOADER_COMPILATION_SHARED)
|
||||
add_library(tinyobjloader SHARED ${tinyobjloader-Source})
|
||||
if(TINYOBJLOADER_COMPILATION_SHARED)
|
||||
add_library(tinyobjloader SHARED ${tinyobjloader-Source})
|
||||
set_target_properties(tinyobjloader PROPERTIES
|
||||
SOVERSION ${TINYOBJLOADER_SOVERSION}
|
||||
)
|
||||
else()
|
||||
add_library(tinyobjloader STATIC ${tinyobjloader-Source})
|
||||
add_library(tinyobjloader STATIC ${tinyobjloader-Source})
|
||||
endif()
|
||||
|
||||
set_target_properties(tinyobjloader PROPERTIES VERSION ${TINYOBJLOADER_VERSION})
|
||||
|
||||
target_include_directories(tinyobjloader INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${TINYOBJLOADER_INCLUDE_DIR}>
|
||||
)
|
||||
|
||||
export(TARGETS tinyobjloader FILE ${PROJECT_NAME}-targets.cmake)
|
||||
|
||||
if(TINYOBJLOADER_BUILD_TEST_LOADER)
|
||||
add_executable(test_loader ${tinyobjloader-Example-Source})
|
||||
target_link_libraries(test_loader tinyobjloader)
|
||||
endif()
|
||||
|
||||
option(TINYOBJLOADER_BUILD_OBJ_STICHER "Build OBJ Sticher Application" OFF)
|
||||
if (TINYOBJLOADER_BUILD_OBJ_STICHER)
|
||||
if(TINYOBJLOADER_BUILD_OBJ_STICHER)
|
||||
add_executable(obj_sticher ${tinyobjloader-examples-objsticher})
|
||||
target_link_libraries(obj_sticher tinyobjloader)
|
||||
|
||||
install ( TARGETS
|
||||
install(TARGETS
|
||||
obj_sticher
|
||||
DESTINATION
|
||||
bin
|
||||
${TINYOBJLOADER_RUNTIME_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
#Installation
|
||||
install ( TARGETS
|
||||
tinyobjloader
|
||||
DESTINATION
|
||||
lib
|
||||
#Write CMake package config files
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
configure_package_config_file(
|
||||
tinyobjloader-config.cmake.in
|
||||
tinyobjloader-config.cmake
|
||||
INSTALL_DESTINATION
|
||||
${TINYOBJLOADER_CMAKE_DIR}
|
||||
PATH_VARS
|
||||
TINYOBJLOADER_INCLUDE_DIR
|
||||
TINYOBJLOADER_LIBRARY_DIR
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO
|
||||
)
|
||||
install ( FILES
|
||||
|
||||
write_basic_package_version_file(tinyobjloader-config-version.cmake
|
||||
VERSION
|
||||
${TINYOBJLOADER_VERSION}
|
||||
COMPATIBILITY
|
||||
SameMajorVersion
|
||||
)
|
||||
|
||||
#pkg-config file
|
||||
configure_file(tinyobjloader.pc.in tinyobjloader.pc @ONLY)
|
||||
|
||||
#Installation
|
||||
install(TARGETS
|
||||
tinyobjloader
|
||||
EXPORT ${PROJECT_NAME}-targets
|
||||
DESTINATION
|
||||
${TINYOBJLOADER_LIBRARY_DIR}
|
||||
PUBLIC_HEADER DESTINATION
|
||||
${TINYOBJLOADER_INCLUDE_DIR}
|
||||
RUNTIME DESTINATION
|
||||
${TINYOBJLOADER_RUNTIME_DIR}
|
||||
)
|
||||
install(EXPORT
|
||||
${PROJECT_NAME}-targets
|
||||
DESTINATION
|
||||
${TINYOBJLOADER_CMAKE_DIR}
|
||||
)
|
||||
install(FILES
|
||||
tiny_obj_loader.h
|
||||
DESTINATION
|
||||
include
|
||||
${TINYOBJLOADER_INCLUDE_DIR}
|
||||
)
|
||||
install(FILES
|
||||
LICENSE
|
||||
DESTINATION
|
||||
${TINYOBJLOADER_DOC_DIR}
|
||||
)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tinyobjloader-config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tinyobjloader-config-version.cmake"
|
||||
DESTINATION
|
||||
${TINYOBJLOADER_CMAKE_DIR}
|
||||
)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tinyobjloader.pc"
|
||||
DESTINATION
|
||||
${TINYOBJLOADER_PKGCONFIG_DIR}
|
||||
)
|
||||
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2016 Syoyo Fujita and many contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
88
README.md
88
README.md
@@ -1,5 +1,4 @@
|
||||
tinyobjloader
|
||||
=============
|
||||
# tinyobjloader
|
||||
|
||||
[](https://gitter.im/syoyo/tinyobjloader?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
@@ -17,29 +16,24 @@ Tiny but powerful single file wavefront obj loader written in C++. No dependency
|
||||
|
||||
`tinyobjloader` is good for embedding .obj loader to your (global illumination) renderer ;-)
|
||||
|
||||
If you are looking for C89 version, please see https://github.com/syoyo/tinyobjloader-c .
|
||||
|
||||
What's new
|
||||
----------
|
||||
|
||||
* XX YY, ZZZZ : New data strcutre and API!
|
||||
* Jan 29, 2016 : Support n-polygon(no triangulation) and OpenSubdiv crease tag! Thanks dboogert!
|
||||
* Nov 26, 2015 : Now single-header only!.
|
||||
* Nov 08, 2015 : Improved API.
|
||||
* Jun 23, 2015 : Various fixes and added more projects using tinyobjloader. Thanks many contributors!
|
||||
* Mar 03, 2015 : Replace atof() with hand-written parser for robust reading of numeric value. Thanks skurmedel!
|
||||
* Feb 06, 2015 : Fix parsing multi-material object
|
||||
* Sep 14, 2014 : Add support for multi-material per object/group. Thanks Mykhailo!
|
||||
* Mar 17, 2014 : Fixed trim newline bugs. Thanks ardneran!
|
||||
* Apr 29, 2014 : Add API to read .obj from std::istream. Good for reading compressed .obj or connecting to procedural primitive generator. Thanks burnse!
|
||||
* Apr 21, 2014 : Define default material if no material definition exists in .obj. Thanks YarmUI!
|
||||
* Apr 10, 2014 : Add support for parsing 'illum' and 'd'/'Tr' statements. Thanks mmp!
|
||||
* Jan 27, 2014 : Added CMake project. Thanks bradc6!
|
||||
* Nov 26, 2013 : Performance optimization by NeuralSandwich. 9% improvement in his project, thanks!
|
||||
* Sep 12, 2013 : Added multiple .obj sticher example.
|
||||
|
||||
Example
|
||||
Notice!
|
||||
-------
|
||||
|
||||
We have released new version v1.0.0 on 20 Aug, 2016.
|
||||
Old version is available `v0.9.x` branch https://github.com/syoyo/tinyobjloader/tree/v0.9.x
|
||||
|
||||
## What's new
|
||||
|
||||
* 20 Aug, 2016 : Bump version v1.0.0. New data strcutre and API!
|
||||
|
||||
### Old version
|
||||
|
||||
Previous old version is avaiable in `v0.9.x` branch.
|
||||
|
||||
## Example
|
||||
|
||||

|
||||
|
||||
tinyobjloader can successfully load 6M triangles Rungholt scene.
|
||||
@@ -48,12 +42,21 @@ http://graphics.cs.williams.edu/data/meshes.xml
|
||||

|
||||
|
||||
* [examples/viewer/](examples/viewer) OpenGL .obj viewer
|
||||
* [examples/callback_api/](examples/callback_api/) Callback API example
|
||||
* [examples/voxelize/](examples/voxelize/) Voxelizer example
|
||||
|
||||
Use case
|
||||
--------
|
||||
## Use case
|
||||
|
||||
TinyObjLoader is successfully used in ...
|
||||
|
||||
### New version(v1.0.x)
|
||||
|
||||
* Loading models in Vulkan Tutorial https://vulkan-tutorial.com/Loading_models
|
||||
* .obj viewer with Metal https://github.com/middlefeng/NuoModelViewer/tree/master
|
||||
* Your project here!
|
||||
|
||||
### Old version(v0.9.x)
|
||||
|
||||
* bullet3 https://github.com/erwincoumans/bullet3
|
||||
* pbrt-v2 https://github.com/mmp/pbrt-v2
|
||||
* OpenGL game engine development http://swarminglogic.com/jotting/2013_10_gamedev01
|
||||
@@ -65,10 +68,19 @@ TinyObjLoader is successfully used in ...
|
||||
* pbrt-v3 https://github.com/mmp/pbrt-v3
|
||||
* cocos2d-x https://github.com/cocos2d/cocos2d-x/
|
||||
* Android Vulkan demo https://github.com/SaschaWillems/Vulkan
|
||||
* Your project here!
|
||||
* voxelizer https://github.com/karimnaaji/voxelizer
|
||||
* Probulator https://github.com/kayru/Probulator
|
||||
* OptiX Prime baking https://github.com/nvpro-samples/optix_prime_baking
|
||||
* FireRays SDK https://github.com/GPUOpen-LibrariesAndSDKs/FireRays_SDK
|
||||
* parg, tiny C library of various graphics utilities and GL demos https://github.com/prideout/parg
|
||||
* Opengl unit of ChronoEngine https://github.com/projectchrono/chrono-opengl
|
||||
* Point Based Global Illumination on modern GPU https://pbgi.wordpress.com/code-source/
|
||||
* Fast OBJ file importing and parsing in CUDA http://researchonline.jcu.edu.au/42515/1/2015.CVM.OBJCUDA.pdf
|
||||
* Sorted Shading for Uni-Directional Pathtracing by Joshua Bainbridge https://nccastaff.bournemouth.ac.uk/jmacey/MastersProjects/MSc15/02Josh/joshua_bainbridge_thesis.pdf
|
||||
* GeeXLab http://www.geeks3d.com/hacklab/20160531/geexlab-0-12-0-0-released-for-windows/
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
## Features
|
||||
|
||||
* Group(parse multiple group name)
|
||||
* Vertex
|
||||
@@ -77,23 +89,23 @@ Features
|
||||
* Material
|
||||
* Unknown material attributes are returned as key-value(value is string) map.
|
||||
* Crease tag('t'). This is OpenSubdiv specific(not in wavefront .obj specification)
|
||||
* PBR material extension for .MTL. Its proposed here: http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
|
||||
* Callback API for custom loading.
|
||||
|
||||
|
||||
TODO
|
||||
----
|
||||
## TODO
|
||||
|
||||
* [ ] Fix Python binding.
|
||||
* [ ] Fix obj_sticker example.
|
||||
* [ ] More unit test codes.
|
||||
* [ ] Texture options
|
||||
* [ ] Normal vector generation
|
||||
* [ ] Support smoothing groups
|
||||
|
||||
License
|
||||
-------
|
||||
## License
|
||||
|
||||
Licensed under MIT license.
|
||||
|
||||
Usage
|
||||
-----
|
||||
## Usage
|
||||
|
||||
`attrib_t` contains single and linear array of vertex data(position, normal and texcoord).
|
||||
Each `shape_t` does not contain vertex data but contains array index to `attrib_t`.
|
||||
@@ -148,8 +160,7 @@ for (size_t s = 0; s < shapes.size(); s++) {
|
||||
|
||||
```
|
||||
|
||||
Optimized loader
|
||||
----------------
|
||||
## Optimized loader
|
||||
|
||||
Optimized multi-threaded .obj loader is available at `experimental/` directory.
|
||||
If you want absolute performance to load .obj data, this optimized loader will fit your purpose.
|
||||
@@ -160,10 +171,9 @@ Here is some benchmark result. Time are measured on MacBook 12(Early 2016, Core
|
||||
* Rungholt scene(6M triangles)
|
||||
* old version(v0.9.x): 15500 msecs.
|
||||
* baseline(v1.0.x): 6800 msecs(2.3x faster than old version)
|
||||
* optimised: 1500 msecs(10x faster than old version, 4.5x faster than basedline)
|
||||
* optimised: 1500 msecs(10x faster than old version, 4.5x faster than baseline)
|
||||
|
||||
|
||||
Tests
|
||||
-----
|
||||
## Tests
|
||||
|
||||
Unit tests are provided in `tests` directory. See `tests/README.md` for details.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: 0.9.{build}
|
||||
version: 1.0.{build}
|
||||
|
||||
platform: x64
|
||||
|
||||
@@ -7,7 +7,6 @@ install:
|
||||
# All external dependencies are installed in C:\projects\deps
|
||||
#######################################################################################
|
||||
- mkdir C:\projects\deps
|
||||
- cd C:\projects\deps
|
||||
|
||||
#######################################################################################
|
||||
# Install Ninja
|
||||
|
||||
@@ -1,39 +1,44 @@
|
||||
//
|
||||
// An example of how to use callback API.
|
||||
// This example is minimum and incomplete. Just showing the usage of callback
|
||||
// API.
|
||||
// You need to implement your own Mesh data struct constrution based on this
|
||||
// example in practical.
|
||||
//
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "tiny_obj_loader.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
std::vector<float> vertices;
|
||||
std::vector<float> normals;
|
||||
std::vector<float> texcoords;
|
||||
std::vector<int> v_indices;
|
||||
std::vector<int> vn_indices;
|
||||
std::vector<int> vt_indices;
|
||||
std::vector<int> v_indices;
|
||||
std::vector<int> vn_indices;
|
||||
std::vector<int> vt_indices;
|
||||
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
} MyMesh;
|
||||
|
||||
void vertex_cb(void *user_data, float x, float y, float z)
|
||||
{
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
printf("v[%ld] = %f, %f, %f\n", mesh->vertices.size() / 3, x, y, z);
|
||||
void vertex_cb(void *user_data, float x, float y, float z, float w) {
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
|
||||
printf("v[%ld] = %f, %f, %f (w %f)\n", mesh->vertices.size() / 3, x, y, z, w);
|
||||
|
||||
mesh->vertices.push_back(x);
|
||||
mesh->vertices.push_back(y);
|
||||
mesh->vertices.push_back(z);
|
||||
// Discard w
|
||||
}
|
||||
|
||||
void normal_cb(void *user_data, float x, float y, float z)
|
||||
{
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
void normal_cb(void *user_data, float x, float y, float z) {
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
|
||||
printf("vn[%ld] = %f, %f, %f\n", mesh->normals.size() / 3, x, y, z);
|
||||
|
||||
mesh->normals.push_back(x);
|
||||
@@ -41,49 +46,56 @@ void normal_cb(void *user_data, float x, float y, float z)
|
||||
mesh->normals.push_back(z);
|
||||
}
|
||||
|
||||
void texcoord_cb(void *user_data, float x, float y)
|
||||
{
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
printf("vt[%ld] = %f, %f\n", mesh->texcoords.size() / 2, x, y);
|
||||
void texcoord_cb(void *user_data, float x, float y, float z) {
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
|
||||
printf("vt[%ld] = %f, %f, %f\n", mesh->texcoords.size() / 3, x, y, z);
|
||||
|
||||
mesh->texcoords.push_back(x);
|
||||
mesh->texcoords.push_back(y);
|
||||
mesh->texcoords.push_back(z);
|
||||
}
|
||||
|
||||
void index_cb(void *user_data, int v_idx, int vn_idx, int vt_idx)
|
||||
{
|
||||
// NOTE: the value of each index is raw value.
|
||||
void index_cb(void *user_data, tinyobj::index_t *indices, int num_indices) {
|
||||
// NOTE: the value of each index is raw value.
|
||||
// For example, the application must manually adjust the index with offset
|
||||
// (e.g. v_indices.size()) when the value is negative(relative index).
|
||||
// (e.g. v_indices.size()) when the value is negative(whic means relative
|
||||
// index).
|
||||
// Also, the first index starts with 1, not 0.
|
||||
// See fixIndex() function in tiny_obj_loader.h for details.
|
||||
// Also, -2147483648(0x80000000) is set for the index value which does not exist in .obj
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
printf("idx[%ld] = %d, %d, %d\n", mesh->v_indices.size(), v_idx, vn_idx, vt_idx);
|
||||
// Also, 0 is set for the index value which
|
||||
// does not exist in .obj
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
|
||||
|
||||
if (v_idx != 0x80000000) {
|
||||
mesh->v_indices.push_back(v_idx);
|
||||
}
|
||||
if (vn_idx != 0x80000000) {
|
||||
mesh->vn_indices.push_back(vn_idx);
|
||||
}
|
||||
if (vt_idx != 0x80000000) {
|
||||
mesh->vt_indices.push_back(vt_idx);
|
||||
for (int i = 0; i < num_indices; i++) {
|
||||
tinyobj::index_t idx = indices[i];
|
||||
printf("idx[%ld] = %d, %d, %d\n", mesh->v_indices.size(), idx.vertex_index,
|
||||
idx.normal_index, idx.texcoord_index);
|
||||
|
||||
if (idx.vertex_index != 0) {
|
||||
mesh->v_indices.push_back(idx.vertex_index);
|
||||
}
|
||||
if (idx.normal_index != 0) {
|
||||
mesh->vn_indices.push_back(idx.normal_index);
|
||||
}
|
||||
if (idx.texcoord_index != 0) {
|
||||
mesh->vt_indices.push_back(idx.texcoord_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void usemtl_cb(void *user_data, const char* name, int material_idx)
|
||||
{
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
void usemtl_cb(void *user_data, const char *name, int material_idx) {
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
|
||||
if ((material_idx > -1) && (material_idx < mesh->materials.size())) {
|
||||
printf("usemtl. material id = %d(name = %s)\n", material_idx, mesh->materials[material_idx].name.c_str());
|
||||
printf("usemtl. material id = %d(name = %s)\n", material_idx,
|
||||
mesh->materials[material_idx].name.c_str());
|
||||
} else {
|
||||
printf("usemtl. name = %s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
void mtllib_cb(void *user_data, const tinyobj::material_t *materials, int num_materials)
|
||||
{
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
void mtllib_cb(void *user_data, const tinyobj::material_t *materials,
|
||||
int num_materials) {
|
||||
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
|
||||
printf("mtllib. # of materials = %d\n", num_materials);
|
||||
|
||||
for (int i = 0; i < num_materials; i++) {
|
||||
@@ -91,9 +103,8 @@ void mtllib_cb(void *user_data, const tinyobj::material_t *materials, int num_ma
|
||||
}
|
||||
}
|
||||
|
||||
void group_cb(void *user_data, const char **names, int num_names)
|
||||
{
|
||||
//MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
void group_cb(void *user_data, const char **names, int num_names) {
|
||||
// MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
printf("group : name = \n");
|
||||
|
||||
for (int i = 0; i < num_names; i++) {
|
||||
@@ -101,16 +112,12 @@ void group_cb(void *user_data, const char **names, int num_names)
|
||||
}
|
||||
}
|
||||
|
||||
void object_cb(void *user_data, const char *name)
|
||||
{
|
||||
//MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
void object_cb(void *user_data, const char *name) {
|
||||
// MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
|
||||
printf("object : name = %s\n", name);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
tinyobj::callback_t cb;
|
||||
cb.vertex_cb = vertex_cb;
|
||||
cb.normal_cb = normal_cb;
|
||||
@@ -123,7 +130,11 @@ main(int argc, char** argv)
|
||||
|
||||
MyMesh mesh;
|
||||
std::string err;
|
||||
std::ifstream ifs("../../models/cornell_box.obj");
|
||||
std::string filename = "../../models/cornell_box.obj";
|
||||
if (argc > 1) {
|
||||
filename = std::string(argv[1]);
|
||||
}
|
||||
std::ifstream ifs(filename.c_str());
|
||||
|
||||
if (ifs.fail()) {
|
||||
std::cerr << "file not found." << std::endl;
|
||||
@@ -131,8 +142,8 @@ main(int argc, char** argv)
|
||||
}
|
||||
|
||||
tinyobj::MaterialFileReader mtlReader("../../models/");
|
||||
|
||||
bool ret = tinyobj::LoadObjWithCallback(&mesh, cb, &err, &ifs, &mtlReader);
|
||||
|
||||
bool ret = tinyobj::LoadObjWithCallback(ifs, cb, &mesh, &mtlReader, &err);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
|
||||
6755
examples/viewer/stb_image.h
Normal file
6755
examples/viewer/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,16 @@
|
||||
//
|
||||
// Simple .obj viewer(vertex only)
|
||||
//
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
@@ -26,11 +27,23 @@
|
||||
|
||||
#include "trackball.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#include <mmsystem.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -45,7 +58,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
class timerutil {
|
||||
public:
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
typedef DWORD time_t;
|
||||
|
||||
@@ -81,7 +94,7 @@ public:
|
||||
return (time_t)(t.tv_sec * 1000 + t.tv_usec);
|
||||
}
|
||||
|
||||
#else // C timer
|
||||
#else // C timer
|
||||
// using namespace std;
|
||||
typedef clock_t time_t;
|
||||
|
||||
@@ -96,7 +109,7 @@ public:
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
DWORD t_[2];
|
||||
#else
|
||||
@@ -110,8 +123,9 @@ private:
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GLuint vb; // vertex buffer
|
||||
GLuint vb; // vertex buffer
|
||||
int numTriangles;
|
||||
size_t material_id;
|
||||
} DrawObject;
|
||||
|
||||
std::vector<DrawObject> gDrawObjects;
|
||||
@@ -129,7 +143,26 @@ float eye[3], lookat[3], up[3];
|
||||
|
||||
GLFWwindow* window;
|
||||
|
||||
void CheckErrors(std::string desc) {
|
||||
static std::string GetBaseDir(const std::string &filepath) {
|
||||
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||
return filepath.substr(0, filepath.find_last_of("/\\"));
|
||||
return "";
|
||||
}
|
||||
|
||||
static bool FileExists(const std::string &abs_filename) {
|
||||
bool ret;
|
||||
FILE *fp = fopen(abs_filename.c_str(), "rb");
|
||||
if (fp) {
|
||||
ret = true;
|
||||
fclose(fp);
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void CheckErrors(std::string desc) {
|
||||
GLenum e = glGetError();
|
||||
if (e != GL_NO_ERROR) {
|
||||
fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc.c_str(), e, e);
|
||||
@@ -137,7 +170,7 @@ void CheckErrors(std::string desc) {
|
||||
}
|
||||
}
|
||||
|
||||
void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
||||
static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
||||
float v10[3];
|
||||
v10[0] = v1[0] - v0[0];
|
||||
v10[1] = v1[1] - v0[1];
|
||||
@@ -155,36 +188,46 @@ void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
||||
float len2 = N[0] * N[0] + N[1] * N[1] + N[2] * N[2];
|
||||
if (len2 > 0.0f) {
|
||||
float len = sqrtf(len2);
|
||||
|
||||
|
||||
N[0] /= len;
|
||||
N[1] /= len;
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadObjAndConvert(float bmin[3], float bmax[3], std::vector<DrawObject>& drawObjects, const char* filename)
|
||||
{
|
||||
static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
||||
std::vector<DrawObject>* drawObjects,
|
||||
std::vector<tinyobj::material_t>& materials,
|
||||
std::map<std::string, GLuint>& textures,
|
||||
const char* filename) {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
timerutil tm;
|
||||
|
||||
tm.start();
|
||||
|
||||
|
||||
std::string base_dir = GetBaseDir(filename);
|
||||
#ifdef _WIN32
|
||||
base_dir += "\\";
|
||||
#else
|
||||
base_dir += "/";
|
||||
#endif
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, NULL);
|
||||
bool ret =
|
||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, base_dir.c_str());
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
tm.end();
|
||||
|
||||
|
||||
if (!ret) {
|
||||
std::cerr << "Failed to load " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Parsing time: %d [ms]\n", tm.msec());
|
||||
printf("Parsing time: %d [ms]\n", (int)tm.msec());
|
||||
|
||||
printf("# of vertices = %d\n", (int)(attrib.vertices.size()) / 3);
|
||||
printf("# of normals = %d\n", (int)(attrib.normals.size()) / 3);
|
||||
@@ -192,106 +235,204 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3], std::vector<DrawObject>& dr
|
||||
printf("# of materials = %d\n", (int)materials.size());
|
||||
printf("# of shapes = %d\n", (int)shapes.size());
|
||||
|
||||
// Append `default` material
|
||||
materials.push_back(tinyobj::material_t());
|
||||
|
||||
// Load diffuse textures
|
||||
{
|
||||
for (size_t m = 0; m < materials.size(); m++) {
|
||||
tinyobj::material_t* mp = &materials[m];
|
||||
|
||||
if (mp->diffuse_texname.length() > 0) {
|
||||
// Only load the texture if it is not already loaded
|
||||
if (textures.find(mp->diffuse_texname) == textures.end()) {
|
||||
GLuint texture_id;
|
||||
int w, h;
|
||||
int comp;
|
||||
|
||||
std::string texture_filename = mp->diffuse_texname;
|
||||
if (!FileExists(texture_filename)) {
|
||||
// Append base dir.
|
||||
texture_filename = base_dir + mp->diffuse_texname;
|
||||
if (!FileExists(texture_filename)) {
|
||||
std::cerr << "Unable to find file: " << mp->diffuse_texname << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* image = stbi_load(texture_filename.c_str(), &w, &h, &comp, STBI_default);
|
||||
if (image == nullptr) {
|
||||
std::cerr << "Unable to load texture: " << texture_filename << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
glGenTextures(1, &texture_id);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
if (comp == 3) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
|
||||
}
|
||||
else if (comp == 4) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
stbi_image_free(image);
|
||||
textures.insert(std::make_pair(mp->diffuse_texname, texture_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
|
||||
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
|
||||
|
||||
{
|
||||
for (size_t s = 0; s < shapes.size(); s++) {
|
||||
DrawObject o;
|
||||
std::vector<float> vb; // pos(3float), normal(3float), color(3float)
|
||||
for (size_t f = 0; f < shapes[s].mesh.indices.size()/3; f++) {
|
||||
for (size_t s = 0; s < shapes.size(); s++) {
|
||||
DrawObject o;
|
||||
std::vector<float> vb; // pos(3float), normal(3float), color(3float)
|
||||
for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) {
|
||||
tinyobj::index_t idx0 = shapes[s].mesh.indices[3 * f + 0];
|
||||
tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1];
|
||||
tinyobj::index_t idx2 = shapes[s].mesh.indices[3 * f + 2];
|
||||
|
||||
int current_material_id = shapes[s].mesh.material_ids[f];
|
||||
|
||||
tinyobj::index_t idx0 = shapes[s].mesh.indices[3*f+0];
|
||||
tinyobj::index_t idx1 = shapes[s].mesh.indices[3*f+1];
|
||||
tinyobj::index_t idx2 = shapes[s].mesh.indices[3*f+2];
|
||||
if ((current_material_id < 0) || (current_material_id >= static_cast<int>(materials.size()))) {
|
||||
// Invaid material ID. Use default material.
|
||||
current_material_id = materials.size() - 1; // Default material is added to the last item in `materials`.
|
||||
}
|
||||
//if (current_material_id >= materials.size()) {
|
||||
// std::cerr << "Invalid material index: " << current_material_id << std::endl;
|
||||
//}
|
||||
//
|
||||
float diffuse[3];
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
diffuse[i] = materials[current_material_id].diffuse[i];
|
||||
}
|
||||
float tc[3][2];
|
||||
if (attrib.texcoords.size() > 0) {
|
||||
assert(attrib.texcoords.size() > 2 * idx0.texcoord_index + 1);
|
||||
assert(attrib.texcoords.size() > 2 * idx1.texcoord_index + 1);
|
||||
assert(attrib.texcoords.size() > 2 * idx2.texcoord_index + 1);
|
||||
tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index];
|
||||
tc[0][1] = 1.0f - attrib.texcoords[2 * idx0.texcoord_index + 1];
|
||||
tc[1][0] = attrib.texcoords[2 * idx1.texcoord_index];
|
||||
tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1];
|
||||
tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index];
|
||||
tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1];
|
||||
} else {
|
||||
std::cerr << "Texcoordinates are not defined" << std::endl;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
float v[3][3];
|
||||
float v[3][3];
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int f0 = idx0.vertex_index;
|
||||
int f1 = idx1.vertex_index;
|
||||
int f2 = idx2.vertex_index;
|
||||
assert(f0 >= 0);
|
||||
assert(f1 >= 0);
|
||||
assert(f2 >= 0);
|
||||
|
||||
v[0][k] = attrib.vertices[3 * f0 + k];
|
||||
v[1][k] = attrib.vertices[3 * f1 + k];
|
||||
v[2][k] = attrib.vertices[3 * f2 + k];
|
||||
bmin[k] = std::min(v[0][k], bmin[k]);
|
||||
bmin[k] = std::min(v[1][k], bmin[k]);
|
||||
bmin[k] = std::min(v[2][k], bmin[k]);
|
||||
bmax[k] = std::max(v[0][k], bmax[k]);
|
||||
bmax[k] = std::max(v[1][k], bmax[k]);
|
||||
bmax[k] = std::max(v[2][k], bmax[k]);
|
||||
}
|
||||
|
||||
float n[3][3];
|
||||
if (attrib.normals.size() > 0) {
|
||||
int f0 = idx0.normal_index;
|
||||
int f1 = idx1.normal_index;
|
||||
int f2 = idx2.normal_index;
|
||||
assert(f0 >= 0);
|
||||
assert(f1 >= 0);
|
||||
assert(f2 >= 0);
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int f0 = idx0.vertex_index;
|
||||
int f1 = idx1.vertex_index;
|
||||
int f2 = idx2.vertex_index;
|
||||
assert(f0 >= 0);
|
||||
assert(f1 >= 0);
|
||||
assert(f2 >= 0);
|
||||
|
||||
v[0][k] = attrib.vertices[3*f0+k];
|
||||
v[1][k] = attrib.vertices[3*f1+k];
|
||||
v[2][k] = attrib.vertices[3*f2+k];
|
||||
bmin[k] = std::min(v[0][k], bmin[k]);
|
||||
bmin[k] = std::min(v[1][k], bmin[k]);
|
||||
bmin[k] = std::min(v[2][k], bmin[k]);
|
||||
bmax[k] = std::max(v[0][k], bmax[k]);
|
||||
bmax[k] = std::max(v[1][k], bmax[k]);
|
||||
bmax[k] = std::max(v[2][k], bmax[k]);
|
||||
n[0][k] = attrib.normals[3 * f0 + k];
|
||||
n[1][k] = attrib.normals[3 * f1 + k];
|
||||
n[2][k] = attrib.normals[3 * f2 + k];
|
||||
}
|
||||
} else {
|
||||
// compute geometric normal
|
||||
CalcNormal(n[0], v[0], v[1], v[2]);
|
||||
n[1][0] = n[0][0];
|
||||
n[1][1] = n[0][1];
|
||||
n[1][2] = n[0][2];
|
||||
n[2][0] = n[0][0];
|
||||
n[2][1] = n[0][1];
|
||||
n[2][2] = n[0][2];
|
||||
}
|
||||
|
||||
float n[3][3];
|
||||
for (int k = 0; k < 3; k++) {
|
||||
vb.push_back(v[k][0]);
|
||||
vb.push_back(v[k][1]);
|
||||
vb.push_back(v[k][2]);
|
||||
vb.push_back(n[k][0]);
|
||||
vb.push_back(n[k][1]);
|
||||
vb.push_back(n[k][2]);
|
||||
// Combine normal and diffuse to get color.
|
||||
float normal_factor = 0.2;
|
||||
float diffuse_factor = 1 - normal_factor;
|
||||
float c[3] = {
|
||||
n[k][0] * normal_factor + diffuse[0] * diffuse_factor,
|
||||
n[k][1] * normal_factor + diffuse[1] * diffuse_factor,
|
||||
n[k][2] * normal_factor + diffuse[2] * diffuse_factor
|
||||
};
|
||||
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
|
||||
if (len2 > 0.0f) {
|
||||
float len = sqrtf(len2);
|
||||
|
||||
if (attrib.normals.size() > 0) {
|
||||
int f0 = idx0.normal_index;
|
||||
int f1 = idx1.normal_index;
|
||||
int f2 = idx2.normal_index;
|
||||
assert(f0 >= 0);
|
||||
assert(f1 >= 0);
|
||||
assert(f2 >= 0);
|
||||
for (int k = 0; k < 3; k++) {
|
||||
n[0][k] = attrib.normals[3*f0+k];
|
||||
n[1][k] = attrib.normals[3*f1+k];
|
||||
n[2][k] = attrib.normals[3*f2+k];
|
||||
}
|
||||
} else {
|
||||
// compute geometric normal
|
||||
CalcNormal(n[0], v[0], v[1], v[2]);
|
||||
n[1][0] = n[0][0]; n[1][1] = n[0][1]; n[1][2] = n[0][2];
|
||||
n[2][0] = n[0][0]; n[2][1] = n[0][1]; n[2][2] = n[0][2];
|
||||
}
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
vb.push_back(v[k][0]);
|
||||
vb.push_back(v[k][1]);
|
||||
vb.push_back(v[k][2]);
|
||||
vb.push_back(n[k][0]);
|
||||
vb.push_back(n[k][1]);
|
||||
vb.push_back(n[k][2]);
|
||||
// Use normal as color.
|
||||
float c[3] = {n[k][0], n[k][1], n[k][2]};
|
||||
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
|
||||
if (len2 > 0.0f) {
|
||||
float len = sqrtf(len2);
|
||||
|
||||
c[0] /= len;
|
||||
c[1] /= len;
|
||||
c[2] /= len;
|
||||
}
|
||||
vb.push_back(c[0] * 0.5 + 0.5);
|
||||
vb.push_back(c[1] * 0.5 + 0.5);
|
||||
vb.push_back(c[2] * 0.5 + 0.5);
|
||||
c[0] /= len;
|
||||
c[1] /= len;
|
||||
c[2] /= len;
|
||||
}
|
||||
vb.push_back(c[0] * 0.5 + 0.5);
|
||||
vb.push_back(c[1] * 0.5 + 0.5);
|
||||
vb.push_back(c[2] * 0.5 + 0.5);
|
||||
|
||||
vb.push_back(tc[k][0]);
|
||||
vb.push_back(tc[k][1]);
|
||||
}
|
||||
}
|
||||
|
||||
o.vb = 0;
|
||||
o.numTriangles = 0;
|
||||
if (vb.size() > 0) {
|
||||
glGenBuffers(1, &o.vb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
|
||||
glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0), GL_STATIC_DRAW);
|
||||
o.numTriangles = vb.size() / 9 / 3;
|
||||
printf("shape[%d] # of triangles = %d\n", static_cast<int>(s), o.numTriangles);
|
||||
}
|
||||
o.vb = 0;
|
||||
o.numTriangles = 0;
|
||||
|
||||
gDrawObjects.push_back(o);
|
||||
// OpenGL viewer does not support texturing with per-face material.
|
||||
if (shapes[s].mesh.material_ids.size() > 0 && shapes[s].mesh.material_ids.size() > s) {
|
||||
// Base case
|
||||
o.material_id = shapes[s].mesh.material_ids[s];
|
||||
} else {
|
||||
o.material_id = materials.size() - 1; // = ID for default material.
|
||||
}
|
||||
|
||||
if (vb.size() > 0) {
|
||||
glGenBuffers(1, &o.vb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
|
||||
glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0),
|
||||
GL_STATIC_DRAW);
|
||||
o.numTriangles = vb.size() / (3 + 3 + 3 + 2) * 3;
|
||||
printf("shape[%d] # of triangles = %d\n", static_cast<int>(s),
|
||||
o.numTriangles);
|
||||
}
|
||||
|
||||
drawObjects->push_back(o);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
printf("bmin = %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
|
||||
printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void reshapeFunc(GLFWwindow* window, int w, int h)
|
||||
{
|
||||
static void reshapeFunc(GLFWwindow* window, int w, int h) {
|
||||
int fb_w, fb_h;
|
||||
// Get actual framebuffer size.
|
||||
glfwGetFramebufferSize(window, &fb_w, &fb_h);
|
||||
@@ -307,100 +448,122 @@ void reshapeFunc(GLFWwindow* window, int w, int h)
|
||||
height = h;
|
||||
}
|
||||
|
||||
void keyboardFunc(GLFWwindow *window, int key, int scancode, int action, int mods) {
|
||||
if(action == GLFW_PRESS || action == GLFW_REPEAT){
|
||||
// Move camera
|
||||
float mv_x = 0, mv_y = 0, mv_z = 0;
|
||||
if(key == GLFW_KEY_K) mv_x += 1;
|
||||
else if(key == GLFW_KEY_J) mv_x += -1;
|
||||
else if(key == GLFW_KEY_L) mv_y += 1;
|
||||
else if(key == GLFW_KEY_H) mv_y += -1;
|
||||
else if(key == GLFW_KEY_P) mv_z += 1;
|
||||
else if(key == GLFW_KEY_N) mv_z += -1;
|
||||
//camera.move(mv_x * 0.05, mv_y * 0.05, mv_z * 0.05);
|
||||
// Close window
|
||||
if(key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE) glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
static void keyboardFunc(GLFWwindow* window, int key, int scancode, int action,
|
||||
int mods) {
|
||||
(void)window;
|
||||
(void)scancode;
|
||||
(void)mods;
|
||||
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
||||
// Move camera
|
||||
float mv_x = 0, mv_y = 0, mv_z = 0;
|
||||
if (key == GLFW_KEY_K)
|
||||
mv_x += 1;
|
||||
else if (key == GLFW_KEY_J)
|
||||
mv_x += -1;
|
||||
else if (key == GLFW_KEY_L)
|
||||
mv_y += 1;
|
||||
else if (key == GLFW_KEY_H)
|
||||
mv_y += -1;
|
||||
else if (key == GLFW_KEY_P)
|
||||
mv_z += 1;
|
||||
else if (key == GLFW_KEY_N)
|
||||
mv_z += -1;
|
||||
// camera.move(mv_x * 0.05, mv_y * 0.05, mv_z * 0.05);
|
||||
// Close window
|
||||
if (key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE)
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
|
||||
//init_frame = true;
|
||||
}
|
||||
// init_frame = true;
|
||||
}
|
||||
}
|
||||
|
||||
void clickFunc(GLFWwindow* window, int button, int action, int mods){
|
||||
if(button == GLFW_MOUSE_BUTTON_LEFT){
|
||||
if(action == GLFW_PRESS){
|
||||
mouseLeftPressed = true;
|
||||
trackball(prev_quat, 0.0, 0.0, 0.0, 0.0);
|
||||
} else if(action == GLFW_RELEASE){
|
||||
mouseLeftPressed = false;
|
||||
}
|
||||
static void clickFunc(GLFWwindow* window, int button, int action, int mods) {
|
||||
(void)window;
|
||||
(void)mods;
|
||||
if (button == GLFW_MOUSE_BUTTON_LEFT) {
|
||||
if (action == GLFW_PRESS) {
|
||||
mouseLeftPressed = true;
|
||||
trackball(prev_quat, 0.0, 0.0, 0.0, 0.0);
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
mouseLeftPressed = false;
|
||||
}
|
||||
if(button == GLFW_MOUSE_BUTTON_RIGHT){
|
||||
if(action == GLFW_PRESS){
|
||||
mouseRightPressed = true;
|
||||
} else if(action == GLFW_RELEASE){
|
||||
mouseRightPressed = false;
|
||||
}
|
||||
}
|
||||
if (button == GLFW_MOUSE_BUTTON_RIGHT) {
|
||||
if (action == GLFW_PRESS) {
|
||||
mouseRightPressed = true;
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
mouseRightPressed = false;
|
||||
}
|
||||
if(button == GLFW_MOUSE_BUTTON_MIDDLE){
|
||||
if(action == GLFW_PRESS){
|
||||
mouseMiddlePressed = true;
|
||||
} else if(action == GLFW_RELEASE){
|
||||
mouseMiddlePressed = false;
|
||||
}
|
||||
}
|
||||
if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
|
||||
if (action == GLFW_PRESS) {
|
||||
mouseMiddlePressed = true;
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
mouseMiddlePressed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y){
|
||||
static void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
|
||||
(void)window;
|
||||
float rotScale = 1.0f;
|
||||
float transScale = 2.0f;
|
||||
|
||||
if(mouseLeftPressed){
|
||||
trackball(prev_quat,
|
||||
rotScale * (2.0f * prevMouseX - width) / (float)width,
|
||||
rotScale * (height - 2.0f * prevMouseY) / (float)height,
|
||||
rotScale * (2.0f * mouse_x - width) / (float)width,
|
||||
rotScale * (height - 2.0f * mouse_y) / (float)height);
|
||||
if (mouseLeftPressed) {
|
||||
trackball(prev_quat, rotScale * (2.0f * prevMouseX - width) / (float)width,
|
||||
rotScale * (height - 2.0f * prevMouseY) / (float)height,
|
||||
rotScale * (2.0f * mouse_x - width) / (float)width,
|
||||
rotScale * (height - 2.0f * mouse_y) / (float)height);
|
||||
|
||||
add_quats(prev_quat, curr_quat, curr_quat);
|
||||
} else if (mouseMiddlePressed) {
|
||||
eye[0] -= transScale * (mouse_x - prevMouseX) / (float)width;
|
||||
lookat[0] -= transScale * (mouse_x - prevMouseX) / (float)width;
|
||||
eye[1] += transScale * (mouse_y - prevMouseY) / (float)height;
|
||||
lookat[1] += transScale * (mouse_y - prevMouseY) / (float)height;
|
||||
} else if (mouseRightPressed) {
|
||||
eye[2] += transScale * (mouse_y - prevMouseY) / (float)height;
|
||||
lookat[2] += transScale * (mouse_y - prevMouseY) / (float)height;
|
||||
}
|
||||
add_quats(prev_quat, curr_quat, curr_quat);
|
||||
} else if (mouseMiddlePressed) {
|
||||
eye[0] -= transScale * (mouse_x - prevMouseX) / (float)width;
|
||||
lookat[0] -= transScale * (mouse_x - prevMouseX) / (float)width;
|
||||
eye[1] += transScale * (mouse_y - prevMouseY) / (float)height;
|
||||
lookat[1] += transScale * (mouse_y - prevMouseY) / (float)height;
|
||||
} else if (mouseRightPressed) {
|
||||
eye[2] += transScale * (mouse_y - prevMouseY) / (float)height;
|
||||
lookat[2] += transScale * (mouse_y - prevMouseY) / (float)height;
|
||||
}
|
||||
|
||||
// Update mouse point
|
||||
prevMouseX = mouse_x;
|
||||
prevMouseY = mouse_y;
|
||||
// Update mouse point
|
||||
prevMouseX = mouse_x;
|
||||
prevMouseY = mouse_y;
|
||||
}
|
||||
|
||||
void Draw(const std::vector<DrawObject>& drawObjects)
|
||||
{
|
||||
static void Draw(const std::vector<DrawObject>& drawObjects, std::vector<tinyobj::material_t>& materials, std::map<std::string, GLuint>& textures) {
|
||||
glPolygonMode(GL_FRONT, GL_FILL);
|
||||
glPolygonMode(GL_BACK, GL_FILL);
|
||||
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.0, 1.0);
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
GLsizei stride = (3 + 3 + 3 + 2) * sizeof(float);
|
||||
for (size_t i = 0; i < drawObjects.size(); i++) {
|
||||
DrawObject o = drawObjects[i];
|
||||
if (o.vb < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
|
||||
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float)*3));
|
||||
glColorPointer(3, GL_FLOAT, 36, (const void*)(sizeof(float)*6));
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if ((o.material_id < materials.size())) {
|
||||
std::string diffuse_texname = materials[o.material_id].diffuse_texname;
|
||||
if (textures.find(diffuse_texname) != textures.end()) {
|
||||
glBindTexture(GL_TEXTURE_2D, textures[diffuse_texname]);
|
||||
}
|
||||
}
|
||||
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
||||
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
|
||||
glColorPointer(3, GL_FLOAT, stride, (const void*)(sizeof(float) * 6));
|
||||
glTexCoordPointer(2, GL_FLOAT, stride, (const void*)(sizeof(float) * 9));
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
||||
CheckErrors("drawarrays");
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
// draw wireframe
|
||||
@@ -414,13 +577,16 @@ void Draw(const std::vector<DrawObject>& drawObjects)
|
||||
if (o.vb < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
|
||||
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float)*3));
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
||||
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
|
||||
glColorPointer(3, GL_FLOAT, stride, (const void*)(sizeof(float) * 6));
|
||||
glTexCoordPointer(2, GL_FLOAT, stride, (const void*)(sizeof(float) * 9));
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
||||
CheckErrors("drawarrays");
|
||||
@@ -443,26 +609,21 @@ static void Init() {
|
||||
up[2] = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
std::cout << "Needs input.obj\n" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Init();
|
||||
|
||||
|
||||
if(!glfwInit()){
|
||||
if (!glfwInit()) {
|
||||
std::cerr << "Failed to initialize GLFW." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
window = glfwCreateWindow(width, height, "Obj viewer", NULL, NULL);
|
||||
if(window == NULL){
|
||||
if (window == NULL) {
|
||||
std::cerr << "Failed to open GLFW window. " << std::endl;
|
||||
glfwTerminate();
|
||||
return 1;
|
||||
@@ -486,7 +647,9 @@ int main(int argc, char **argv)
|
||||
reshapeFunc(window, width, height);
|
||||
|
||||
float bmin[3], bmax[3];
|
||||
if (false == LoadObjAndConvert(bmin, bmax, gDrawObjects, argv[1])) {
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::map<std::string, GLuint> textures;
|
||||
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, materials, textures, argv[1])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -498,18 +661,20 @@ int main(int argc, char **argv)
|
||||
maxExtent = 0.5f * (bmax[2] - bmin[2]);
|
||||
}
|
||||
|
||||
while(glfwWindowShouldClose(window) == GL_FALSE) {
|
||||
while (glfwWindowShouldClose(window) == GL_FALSE) {
|
||||
glfwPollEvents();
|
||||
glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
// camera & rotate
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
GLfloat mat[4][4];
|
||||
gluLookAt(eye[0], eye[1], eye[2], lookat[0], lookat[1], lookat[2], up[0], up[1], up[2]);
|
||||
gluLookAt(eye[0], eye[1], eye[2], lookat[0], lookat[1], lookat[2], up[0],
|
||||
up[1], up[2]);
|
||||
build_rotmatrix(mat, curr_quat);
|
||||
glMultMatrixf(&mat[0][0]);
|
||||
|
||||
@@ -517,9 +682,10 @@ int main(int argc, char **argv)
|
||||
glScalef(1.0f / maxExtent, 1.0f / maxExtent, 1.0f / maxExtent);
|
||||
|
||||
// Centerize object.
|
||||
glTranslatef(-0.5*(bmax[0] + bmin[0]), -0.5*(bmax[1] + bmin[1]), -0.5*(bmax[2] + bmin[2]));
|
||||
|
||||
Draw(gDrawObjects);
|
||||
glTranslatef(-0.5 * (bmax[0] + bmin[0]), -0.5 * (bmax[1] + bmin[1]),
|
||||
-0.5 * (bmax[2] + bmin[2]));
|
||||
|
||||
Draw(gDrawObjects, materials, textures);
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
2
examples/voxelize/Makefile
Normal file
2
examples/voxelize/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
g++ -o voxelizer main.cc
|
||||
5
examples/voxelize/README.md
Normal file
5
examples/voxelize/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Voxelize .obj and export it as also in .obj
|
||||
|
||||
## Third party library
|
||||
|
||||
This example uses https://github.com/karimnaaji/voxelizer, which is licensed under MIT Liense.
|
||||
74
examples/voxelize/main.cc
Normal file
74
examples/voxelize/main.cc
Normal file
@@ -0,0 +1,74 @@
|
||||
#define VOXELIZER_IMPLEMENTATION
|
||||
#include "voxelizer.h"
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "../../tiny_obj_loader.h"
|
||||
|
||||
bool Voxelize(const char* filename, float voxelsizex, float voxelsizey, float voxelsizez, float precision)
|
||||
{
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename);
|
||||
|
||||
if (!err.empty()) {
|
||||
printf("err: %s\n", err.c_str());
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
printf("failed to load : %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (shapes.size() == 0) {
|
||||
printf("err: # of shapes are zero.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only use first shape.
|
||||
{
|
||||
vx_mesh_t* mesh;
|
||||
vx_mesh_t* result;
|
||||
|
||||
mesh = vx_mesh_alloc(attrib.vertices.size(), shapes[0].mesh.indices.size());
|
||||
|
||||
for (size_t f = 0; f < shapes[0].mesh.indices.size(); f++) {
|
||||
mesh->indices[f] = shapes[0].mesh.indices[f].vertex_index;
|
||||
}
|
||||
|
||||
for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
|
||||
mesh->vertices[v].x = attrib.vertices[3*v+0];
|
||||
mesh->vertices[v].y = attrib.vertices[3*v+1];
|
||||
mesh->vertices[v].z = attrib.vertices[3*v+2];
|
||||
}
|
||||
|
||||
result = vx_voxelize(mesh, voxelsizex, voxelsizey, voxelsizez, precision);
|
||||
|
||||
printf("Number of vertices: %ld\n", result->nvertices);
|
||||
printf("Number of indices: %ld\n", result->nindices);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(
|
||||
int argc,
|
||||
char** argv)
|
||||
{
|
||||
if (argc < 4) {
|
||||
printf("Usage: voxelize input.obj voxelsizex voxelsizey voxelsizez precision\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
const char* filename = argv[1];
|
||||
float voxelsizex = atof(argv[2]);
|
||||
float voxelsizey = atof(argv[3]);
|
||||
float voxelsizez = atof(argv[4]);
|
||||
float prec = atof(argv[5]);
|
||||
bool ret = Voxelize(filename, voxelsizex, voxelsizey, voxelsizez, prec);
|
||||
|
||||
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
764
examples/voxelize/voxelizer.h
Normal file
764
examples/voxelize/voxelizer.h
Normal file
@@ -0,0 +1,764 @@
|
||||
//
|
||||
// LICENCE:
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2016 Karim Naaji, karim.naaji@gmail.com
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE
|
||||
//
|
||||
// REFERENCES:
|
||||
// http://matthias-mueller-fischer.ch/publications/tetraederCollision.pdf
|
||||
// http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/tribox2.txt
|
||||
//
|
||||
// HOWTO:
|
||||
// #define VOXELIZER_IMPLEMENTATION
|
||||
// #define VOXELIZER_DEBUG // Only if assertions need to be checked
|
||||
// #include "voxelizer.h"
|
||||
//
|
||||
// HISTORY:
|
||||
// - version 0.9.0: Initial
|
||||
//
|
||||
// TODO:
|
||||
// - Triangle face merging
|
||||
// - Add colors from input mesh
|
||||
// - Potential issue with voxel bigger than triangle
|
||||
//
|
||||
|
||||
#ifndef VOXELIZER_H
|
||||
#define VOXELIZER_H
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// VOXELIZER PUBLIC API
|
||||
//
|
||||
|
||||
#ifndef VOXELIZER_HELPERS
|
||||
#include <stdlib.h> // malloc, calloc, free
|
||||
#endif
|
||||
|
||||
typedef struct vx_vertex {
|
||||
union {
|
||||
float v[3];
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
};
|
||||
} vx_vertex_t;
|
||||
|
||||
typedef struct vx_mesh {
|
||||
vx_vertex_t* vertices; // Contiguous mesh vertices
|
||||
vx_vertex_t* normals; // Contiguous mesh normals
|
||||
unsigned int* indices; // Mesh indices
|
||||
unsigned int* normalindices; // Mesh normal indices
|
||||
size_t nindices; // The number of normal indices
|
||||
size_t nvertices; // The number of vertices
|
||||
size_t nnormals; // The number of normals
|
||||
} vx_mesh_t;
|
||||
|
||||
vx_mesh_t* vx_voxelize(vx_mesh_t* _mesh, // The input mesh
|
||||
float voxelsizex, // Voxel size on X-axis
|
||||
float voxelsizey, // Voxel size on Y-axis
|
||||
float voxelsizez, // Voxel size on Z-axis
|
||||
float precision); // A precision factor that reduces "holes" artifact
|
||||
// usually a precision = voxelsize / 10. works ok.
|
||||
|
||||
void vx_mesh_free(vx_mesh_t* _mesh);
|
||||
vx_mesh_t* vx_mesh_alloc(int nindices, int nvertices);
|
||||
|
||||
// Voxelizer Helpers, define your own if needed
|
||||
#ifndef VOXELIZER_HELPERS
|
||||
#define VOXELIZER_HELPERS 1
|
||||
#define VX_MIN(a, b) (a > b ? b : a)
|
||||
#define VX_MAX(a, b) (a > b ? a : b)
|
||||
#define VX_FINDMINMAX(x0, x1, x2, min, max) \
|
||||
min = max = x0; \
|
||||
if (x1 < min) min = x1; \
|
||||
if (x1 > max) max = x1; \
|
||||
if (x2 < min) min = x2; \
|
||||
if (x2 > max) max = x2;
|
||||
#define VX_CLAMP(v, lo, hi) VX_MAX(lo, VX_MIN(hi, v))
|
||||
#define VX_MALLOC(T, N) ((T*) malloc(N * sizeof(T)))
|
||||
#define VX_FREE(T) free(T)
|
||||
#define VX_CALLOC(T, N) ((T*) calloc(N * sizeof(T), 1))
|
||||
#define VX_SWAP(T, A, B) { T tmp = B; B = A; A = tmp; }
|
||||
#ifdef VOXELIZER_DEBUG
|
||||
#define VX_ASSERT(STMT) if (!(STMT)) { *(int *)0 = 0; }
|
||||
#else
|
||||
#define VX_ASSERT(STMT)
|
||||
#endif // VOXELIZER_DEBUG
|
||||
#endif // VOXELIZER_HELPERS
|
||||
|
||||
//
|
||||
// END VOXELIZER PUBLIC API
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#endif // VOXELIZER_H
|
||||
|
||||
#ifdef VOXELIZER_IMPLEMENTATION
|
||||
|
||||
#include <math.h> // ceil, fabs & al.
|
||||
#include <stdbool.h> // hughh
|
||||
#include <string.h> // memcpy
|
||||
|
||||
#define VOXELIZER_EPSILON (0.0000001)
|
||||
#define VOXELIZER_NORMAL_INDICES_SIZE (6)
|
||||
#define VOXELIZER_INDICES_SIZE (36)
|
||||
#define VOXELIZER_HASH_TABLE_SIZE (4096)
|
||||
|
||||
unsigned int vx_voxel_indices[VOXELIZER_INDICES_SIZE] = {
|
||||
0, 1, 2,
|
||||
0, 2, 3,
|
||||
3, 2, 6,
|
||||
3, 6, 7,
|
||||
0, 7, 4,
|
||||
0, 3, 7,
|
||||
4, 7, 5,
|
||||
7, 6, 5,
|
||||
0, 4, 5,
|
||||
0, 5, 1,
|
||||
1, 5, 6,
|
||||
1, 6, 2,
|
||||
};
|
||||
|
||||
float vx_normals[18] = {
|
||||
0.0, -1.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
-1.0, 0.0, 0.0,
|
||||
0.0, 0.0, -1.0,
|
||||
};
|
||||
|
||||
unsigned int vx_normal_indices[VOXELIZER_NORMAL_INDICES_SIZE] = {
|
||||
3, 2, 1, 5, 4, 0,
|
||||
};
|
||||
|
||||
typedef struct vx_aabb {
|
||||
vx_vertex_t min;
|
||||
vx_vertex_t max;
|
||||
} vx_aabb_t;
|
||||
|
||||
typedef struct vx_edge {
|
||||
vx_vertex_t p1;
|
||||
vx_vertex_t p2;
|
||||
} vx_edge_t;
|
||||
|
||||
typedef struct vx_triangle {
|
||||
vx_vertex_t p1;
|
||||
vx_vertex_t p2;
|
||||
vx_vertex_t p3;
|
||||
} vx_triangle_t;
|
||||
|
||||
typedef struct vx_hash_table_node {
|
||||
struct vx_hash_table_node* next;
|
||||
struct vx_hash_table_node* prev;
|
||||
void* data;
|
||||
} vx_hash_table_node_t;
|
||||
|
||||
typedef struct vx_hash_table {
|
||||
vx_hash_table_node_t** elements;
|
||||
size_t size;
|
||||
} vx_hash_table_t;
|
||||
|
||||
vx_hash_table_t* vx__hash_table_alloc(size_t size)
|
||||
{
|
||||
vx_hash_table_t* table = VX_MALLOC(vx_hash_table_t, 1);
|
||||
if (!table) { return NULL; }
|
||||
table->size = size;
|
||||
table->elements = VX_MALLOC(vx_hash_table_node_t*, size);
|
||||
if (!table->elements) { return NULL; }
|
||||
for (size_t i = 0; i < table->size; ++i) {
|
||||
table->elements[i] = NULL;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
void vx__hash_table_free(vx_hash_table_t* table, bool freedata)
|
||||
{
|
||||
for (size_t i = 0; i < table->size; ++i) {
|
||||
vx_hash_table_node_t* node = table->elements[i];
|
||||
|
||||
if (node) {
|
||||
if (node->next) {
|
||||
while (node->next) {
|
||||
node = node->next;
|
||||
if (freedata) {
|
||||
VX_FREE(node->prev->data);
|
||||
}
|
||||
VX_FREE(node->prev);
|
||||
}
|
||||
VX_FREE(node);
|
||||
} else {
|
||||
VX_FREE(node->data);
|
||||
VX_FREE(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VX_FREE(table->elements);
|
||||
VX_FREE(table);
|
||||
}
|
||||
|
||||
bool vx__hash_table_insert(vx_hash_table_t* table,
|
||||
size_t hash,
|
||||
void* data,
|
||||
bool (*compfunc)(void* d1, void* d2))
|
||||
{
|
||||
if (!table->elements[hash]) {
|
||||
table->elements[hash] = VX_MALLOC(vx_hash_table_node_t, 1);
|
||||
table->elements[hash]->prev = NULL;
|
||||
table->elements[hash]->next = NULL;
|
||||
table->elements[hash]->data = data;
|
||||
} else {
|
||||
vx_hash_table_node_t* node = table->elements[hash];
|
||||
|
||||
if (compfunc && compfunc(node->data, data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (node->next) {
|
||||
node = node->next;
|
||||
if (compfunc && compfunc(node->data, data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
vx_hash_table_node_t* nnode = VX_MALLOC(vx_hash_table_node_t, 1);
|
||||
|
||||
nnode->prev = node;
|
||||
nnode->next = NULL;
|
||||
nnode->data = data;
|
||||
node->next = nnode;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void vx_mesh_free(vx_mesh_t* m)
|
||||
{
|
||||
VX_FREE(m->vertices);
|
||||
m->vertices = NULL;
|
||||
m->nvertices = 0;
|
||||
VX_FREE(m->indices);
|
||||
m->indices = NULL;
|
||||
m->nindices = 0;
|
||||
if (m->normals) { VX_FREE(m->normals); }
|
||||
VX_FREE(m);
|
||||
}
|
||||
|
||||
vx_mesh_t* vx_mesh_alloc(int nvertices, int nindices)
|
||||
{
|
||||
vx_mesh_t* m = VX_MALLOC(vx_mesh_t, 1);
|
||||
if (!m) { return NULL; }
|
||||
m->indices = VX_CALLOC(unsigned int, nindices);
|
||||
if (!m->indices) { return NULL; }
|
||||
m->vertices = VX_CALLOC(vx_vertex_t, nvertices);
|
||||
if (!m->vertices) { return NULL; }
|
||||
m->normals = NULL;
|
||||
m->nindices = nindices;
|
||||
m->nvertices = nvertices;
|
||||
return m;
|
||||
}
|
||||
|
||||
float vx__map_to_voxel(float position, float voxelSize, bool min)
|
||||
{
|
||||
float vox = (position + (position < 0.f ? -1.f : 1.f) * voxelSize * 0.5f) / voxelSize;
|
||||
return (min ? floor(vox) : ceil(vox)) * voxelSize;
|
||||
}
|
||||
|
||||
vx_vertex_t vx__vertex_cross(vx_vertex_t* v1, vx_vertex_t* v2)
|
||||
{
|
||||
vx_vertex_t cross;
|
||||
cross.x = v1->y * v2->z - v1->z * v2->y;
|
||||
cross.y = v1->z * v2->x - v1->x * v2->z;
|
||||
cross.z = v1->x * v2->y - v1->y * v2->x;
|
||||
return cross;
|
||||
}
|
||||
|
||||
bool vx__vertex_equals(vx_vertex_t* v1, vx_vertex_t* v2) {
|
||||
return fabs(v1->x - v2->x) < VOXELIZER_EPSILON &&
|
||||
fabs(v1->y - v2->y) < VOXELIZER_EPSILON &&
|
||||
fabs(v1->z - v2->z) < VOXELIZER_EPSILON;
|
||||
}
|
||||
|
||||
bool vx__vertex_comp_func(void* a, void* b)
|
||||
{
|
||||
return vx__vertex_equals((vx_vertex_t*) a, (vx_vertex_t*) b);
|
||||
}
|
||||
|
||||
void vx__vertex_sub(vx_vertex_t* a, vx_vertex_t* b)
|
||||
{
|
||||
a->x -= b->x;
|
||||
a->y -= b->y;
|
||||
a->z -= b->z;
|
||||
}
|
||||
|
||||
void vx__vertex_add(vx_vertex_t* a, vx_vertex_t* b)
|
||||
{
|
||||
a->x += b->x;
|
||||
a->y += b->y;
|
||||
a->z += b->z;
|
||||
}
|
||||
|
||||
void vx__vertex_multiply(vx_vertex_t* a, float v)
|
||||
{
|
||||
a->x *= v;
|
||||
a->y *= v;
|
||||
a->z *= v;
|
||||
}
|
||||
|
||||
float vx__vertex_dot(vx_vertex_t* v1, vx_vertex_t* v2)
|
||||
{
|
||||
return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
|
||||
}
|
||||
|
||||
int vx__plane_box_overlap(vx_vertex_t* normal,
|
||||
float d,
|
||||
vx_vertex_t* halfboxsize)
|
||||
{
|
||||
vx_vertex_t vmin, vmax;
|
||||
|
||||
for (int dim = 0; dim <= 2; dim++) {
|
||||
if (normal->v[dim] > 0.0f) {
|
||||
vmin.v[dim] = -halfboxsize->v[dim];
|
||||
vmax.v[dim] = halfboxsize->v[dim];
|
||||
} else {
|
||||
vmin.v[dim] = halfboxsize->v[dim];
|
||||
vmax.v[dim] = -halfboxsize->v[dim];
|
||||
}
|
||||
}
|
||||
|
||||
if (vx__vertex_dot(normal, &vmin) + d > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vx__vertex_dot(normal, &vmax) + d >= 0.0f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define AXISTEST_X01(a, b, fa, fb) \
|
||||
p1 = a * v1.y - b * v1.z; \
|
||||
p3 = a * v3.y - b * v3.z; \
|
||||
if (p1 < p3) { \
|
||||
min = p1; max = p3; \
|
||||
} else { \
|
||||
min = p3; max = p1; \
|
||||
} \
|
||||
rad = fa * halfboxsize.y + fb * halfboxsize.z; \
|
||||
if (min > rad || max < -rad) { \
|
||||
return false; \
|
||||
} \
|
||||
|
||||
#define AXISTEST_X2(a, b, fa, fb) \
|
||||
p1 = a * v1.y - b * v1.z; \
|
||||
p2 = a * v2.y - b * v2.z; \
|
||||
if (p1 < p2) { \
|
||||
min = p1; max = p2; \
|
||||
} else { \
|
||||
min = p2; max = p1; \
|
||||
} \
|
||||
rad = fa * halfboxsize.y + fb * halfboxsize.z; \
|
||||
if (min > rad || max < -rad) { \
|
||||
return false; \
|
||||
} \
|
||||
|
||||
#define AXISTEST_Y02(a, b, fa, fb) \
|
||||
p1 = -a * v1.x + b * v1.z; \
|
||||
p3 = -a * v3.x + b * v3.z; \
|
||||
if (p1 < p3) { \
|
||||
min = p1; max = p3; \
|
||||
} else { \
|
||||
min = p3; max = p1; \
|
||||
} \
|
||||
rad = fa * halfboxsize.x + fb * halfboxsize.z; \
|
||||
if (min > rad || max < -rad) { \
|
||||
return false; \
|
||||
} \
|
||||
|
||||
#define AXISTEST_Y1(a, b, fa, fb) \
|
||||
p1 = -a * v1.x + b * v1.z; \
|
||||
p2 = -a * v2.x + b * v2.z; \
|
||||
if (p1 < p2) { \
|
||||
min = p1; max = p2; \
|
||||
} else { \
|
||||
min = p2; max = p1; \
|
||||
} \
|
||||
rad = fa * halfboxsize.x + fb * halfboxsize.z; \
|
||||
if (min > rad || max < -rad) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define AXISTEST_Z12(a, b, fa, fb) \
|
||||
p2 = a * v2.x - b * v2.y; \
|
||||
p3 = a * v3.x - b * v3.y; \
|
||||
if (p3 < p2) { \
|
||||
min = p3; max = p2; \
|
||||
} else { \
|
||||
min = p2; max = p3; \
|
||||
} \
|
||||
rad = fa * halfboxsize.x + fb * halfboxsize.y; \
|
||||
if (min > rad || max < -rad) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define AXISTEST_Z0(a, b, fa, fb) \
|
||||
p1 = a * v1.x - b * v1.y; \
|
||||
p2 = a * v2.x - b * v2.y; \
|
||||
if (p1 < p2) { \
|
||||
min = p1; max = p2; \
|
||||
} else { \
|
||||
min = p2; max = p1; \
|
||||
} \
|
||||
rad = fa * halfboxsize.x + fb * halfboxsize.y; \
|
||||
if (min > rad || max < -rad) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
int vx__triangle_box_overlap(vx_vertex_t boxcenter,
|
||||
vx_vertex_t halfboxsize,
|
||||
vx_triangle_t triangle)
|
||||
{
|
||||
vx_vertex_t v1, v2, v3, normal, e1, e2, e3;
|
||||
float min, max, d, p1, p2, p3, rad, fex, fey, fez;
|
||||
|
||||
v1 = triangle.p1;
|
||||
v2 = triangle.p2;
|
||||
v3 = triangle.p3;
|
||||
|
||||
vx__vertex_sub(&v1, &boxcenter);
|
||||
vx__vertex_sub(&v2, &boxcenter);
|
||||
vx__vertex_sub(&v3, &boxcenter);
|
||||
|
||||
e1 = v2;
|
||||
e2 = v3;
|
||||
e3 = v1;
|
||||
|
||||
vx__vertex_sub(&e1, &v1);
|
||||
vx__vertex_sub(&e2, &v2);
|
||||
vx__vertex_sub(&e3, &v3);
|
||||
|
||||
fex = fabs(e1.x);
|
||||
fey = fabs(e1.y);
|
||||
fez = fabs(e1.z);
|
||||
|
||||
AXISTEST_X01(e1.z, e1.y, fez, fey);
|
||||
AXISTEST_Y02(e1.z, e1.x, fez, fex);
|
||||
AXISTEST_Z12(e1.y, e1.x, fey, fex);
|
||||
|
||||
fex = fabs(e2.x);
|
||||
fey = fabs(e2.y);
|
||||
fez = fabs(e2.z);
|
||||
|
||||
AXISTEST_X01(e2.z, e2.y, fez, fey);
|
||||
AXISTEST_Y02(e2.z, e2.x, fez, fex);
|
||||
AXISTEST_Z0(e2.y, e2.x, fey, fex);
|
||||
|
||||
fex = fabs(e3.x);
|
||||
fey = fabs(e3.y);
|
||||
fez = fabs(e3.z);
|
||||
|
||||
AXISTEST_X2(e3.z, e3.y, fez, fey);
|
||||
AXISTEST_Y1(e3.z, e3.x, fez, fex);
|
||||
AXISTEST_Z12(e3.y, e3.x, fey, fex);
|
||||
|
||||
VX_FINDMINMAX(v1.x, v2.x, v3.x, min, max);
|
||||
if (min > halfboxsize.x || max < -halfboxsize.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VX_FINDMINMAX(v1.y, v2.y, v3.y, min, max);
|
||||
if (min > halfboxsize.y || max < -halfboxsize.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VX_FINDMINMAX(v1.z, v2.z, v3.z, min, max);
|
||||
if (min > halfboxsize.z || max < -halfboxsize.z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
normal = vx__vertex_cross(&e1, &e2);
|
||||
d = -vx__vertex_dot(&normal, &v1);
|
||||
|
||||
if (!vx__plane_box_overlap(&normal, d, &halfboxsize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef AXISTEST_X2
|
||||
#undef AXISTEST_X01
|
||||
#undef AXISTEST_Y1
|
||||
#undef AXISTEST_Y02
|
||||
#undef AXISTEST_Z0
|
||||
#undef AXISTEST_Z12
|
||||
|
||||
float vx__triangle_area(vx_triangle_t* triangle) {
|
||||
vx_vertex_t ab = triangle->p2;
|
||||
vx_vertex_t ac = triangle->p3;
|
||||
|
||||
vx__vertex_sub(&ab, &triangle->p1);
|
||||
vx__vertex_sub(&ac, &triangle->p1);
|
||||
|
||||
float a0 = ab.y * ac.z - ab.z * ac.y;
|
||||
float a1 = ab.z * ac.x - ab.x * ac.z;
|
||||
float a2 = ab.x * ac.y - ab.y * ac.x;
|
||||
|
||||
return sqrtf(powf(a0, 2.f) + powf(a1, 2.f) + powf(a2, 2.f)) * 0.5f;
|
||||
}
|
||||
|
||||
void vx__aabb_init(vx_aabb_t* aabb)
|
||||
{
|
||||
aabb->max.x = aabb->max.y = aabb->max.z = -INFINITY;
|
||||
aabb->min.x = aabb->min.y = aabb->min.z = INFINITY;
|
||||
}
|
||||
|
||||
vx_aabb_t vx__triangle_aabb(vx_triangle_t* triangle)
|
||||
{
|
||||
vx_aabb_t aabb;
|
||||
|
||||
vx__aabb_init(&aabb);
|
||||
|
||||
aabb.max.x = VX_MAX(aabb.max.x, triangle->p1.x); aabb.max.x = VX_MAX(aabb.max.x,
|
||||
triangle->p2.x); aabb.max.x = VX_MAX(aabb.max.x, triangle->p3.x);
|
||||
aabb.max.y = VX_MAX(aabb.max.y, triangle->p1.y); aabb.max.y = VX_MAX(aabb.max.y,
|
||||
triangle->p2.y); aabb.max.y = VX_MAX(aabb.max.y, triangle->p3.y);
|
||||
aabb.max.z = VX_MAX(aabb.max.z, triangle->p1.z); aabb.max.z = VX_MAX(aabb.max.z,
|
||||
triangle->p2.z); aabb.max.z = VX_MAX(aabb.max.z, triangle->p3.z);
|
||||
|
||||
aabb.min.x = VX_MIN(aabb.min.x, triangle->p1.x); aabb.min.x = VX_MIN(aabb.min.x,
|
||||
triangle->p2.x); aabb.min.x = VX_MIN(aabb.min.x, triangle->p3.x);
|
||||
aabb.min.y = VX_MIN(aabb.min.y, triangle->p1.y); aabb.min.y = VX_MIN(aabb.min.y,
|
||||
triangle->p2.y); aabb.min.y = VX_MIN(aabb.min.y, triangle->p3.y);
|
||||
aabb.min.z = VX_MIN(aabb.min.z, triangle->p1.z); aabb.min.z = VX_MIN(aabb.min.z,
|
||||
triangle->p2.z); aabb.min.z = VX_MIN(aabb.min.z, triangle->p3.z);
|
||||
|
||||
return aabb;
|
||||
}
|
||||
|
||||
vx_vertex_t vx__aabb_center(vx_aabb_t* a)
|
||||
{
|
||||
vx_vertex_t boxcenter = a->min;
|
||||
vx__vertex_add(&boxcenter, &a->max);
|
||||
vx__vertex_multiply(&boxcenter, 0.5f);
|
||||
|
||||
return boxcenter;
|
||||
}
|
||||
|
||||
vx_vertex_t vx__aabb_half_size(vx_aabb_t* a)
|
||||
{
|
||||
vx_vertex_t size;
|
||||
|
||||
size.x = fabs(a->max.x - a->min.x) * 0.5f;
|
||||
size.y = fabs(a->max.y - a->min.y) * 0.5f;
|
||||
size.z = fabs(a->max.z - a->min.z) * 0.5f;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
vx_aabb_t vx__aabb_merge(vx_aabb_t* a, vx_aabb_t* b)
|
||||
{
|
||||
vx_aabb_t merge;
|
||||
|
||||
merge.min.x = VX_MIN(a->min.x, b->min.x);
|
||||
merge.min.y = VX_MIN(a->min.y, b->min.y);
|
||||
merge.min.z = VX_MIN(a->min.z, b->min.z);
|
||||
|
||||
merge.max.x = VX_MAX(a->max.x, b->max.x);
|
||||
merge.max.y = VX_MAX(a->max.y, b->max.y);
|
||||
merge.max.z = VX_MAX(a->max.z, b->max.z);
|
||||
|
||||
return merge;
|
||||
}
|
||||
|
||||
size_t vx__vertex_hash(vx_vertex_t pos, size_t n)
|
||||
{
|
||||
size_t a = (size_t)(pos.x * 73856093);
|
||||
size_t b = (size_t)(pos.y * 19349663);
|
||||
size_t c = (size_t)(pos.z * 83492791);
|
||||
|
||||
return (a ^ b ^ c) % n;
|
||||
}
|
||||
|
||||
void vx__add_voxel(vx_mesh_t* mesh,
|
||||
vx_vertex_t* pos,
|
||||
float* vertices)
|
||||
{
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
size_t index = i+mesh->nvertices;
|
||||
|
||||
mesh->vertices[index].x = vertices[i*3+0] + pos->x;
|
||||
mesh->vertices[index].y = vertices[i*3+1] + pos->y;
|
||||
mesh->vertices[index].z = vertices[i*3+2] + pos->z;
|
||||
}
|
||||
|
||||
int j = -1;
|
||||
for (size_t i = 0; i < VOXELIZER_INDICES_SIZE; ++i) {
|
||||
if (i % 6 == 0) {
|
||||
j++;
|
||||
}
|
||||
mesh->normalindices[i+mesh->nindices] = vx_normal_indices[j];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < VOXELIZER_INDICES_SIZE; ++i) {
|
||||
mesh->indices[i+mesh->nindices] = vx_voxel_indices[i] + mesh->nvertices;
|
||||
}
|
||||
|
||||
mesh->nindices += VOXELIZER_INDICES_SIZE;
|
||||
mesh->nvertices += 8;
|
||||
}
|
||||
|
||||
vx_mesh_t* vx_voxelize(vx_mesh_t* m,
|
||||
float voxelsizex,
|
||||
float voxelsizey,
|
||||
float voxelsizez,
|
||||
float precision)
|
||||
{
|
||||
vx_mesh_t* outmesh = NULL;
|
||||
vx_hash_table_t* table = NULL;
|
||||
size_t voxels = 0;
|
||||
|
||||
float halfsizex = voxelsizex * 0.5f;
|
||||
float halfsizey = voxelsizey * 0.5f;
|
||||
float halfsizez = voxelsizez * 0.5f;
|
||||
|
||||
table = vx__hash_table_alloc(VOXELIZER_HASH_TABLE_SIZE);
|
||||
|
||||
for (int i = 0; i < m->nindices; i += 3) {
|
||||
vx_triangle_t triangle;
|
||||
|
||||
VX_ASSERT(m->indices[i+0] < m->nvertices);
|
||||
VX_ASSERT(m->indices[i+1] < m->nvertices);
|
||||
VX_ASSERT(m->indices[i+2] < m->nvertices);
|
||||
|
||||
triangle.p1 = m->vertices[m->indices[i+0]];
|
||||
triangle.p2 = m->vertices[m->indices[i+1]];
|
||||
triangle.p3 = m->vertices[m->indices[i+2]];
|
||||
|
||||
if (vx__triangle_area(&triangle) < VOXELIZER_EPSILON) {
|
||||
// triangle with 0 area
|
||||
continue;
|
||||
}
|
||||
|
||||
vx_aabb_t aabb = vx__triangle_aabb(&triangle);
|
||||
|
||||
aabb.min.x = vx__map_to_voxel(aabb.min.x, voxelsizex, true);
|
||||
aabb.min.y = vx__map_to_voxel(aabb.min.y, voxelsizey, true);
|
||||
aabb.min.z = vx__map_to_voxel(aabb.min.z, voxelsizez, true);
|
||||
|
||||
aabb.max.x = vx__map_to_voxel(aabb.max.x, voxelsizex, false);
|
||||
aabb.max.y = vx__map_to_voxel(aabb.max.y, voxelsizey, false);
|
||||
aabb.max.z = vx__map_to_voxel(aabb.max.z, voxelsizez, false);
|
||||
|
||||
for (float x = aabb.min.x; x < aabb.max.x; x += voxelsizex) {
|
||||
for (float y = aabb.min.y; y < aabb.max.y; y += voxelsizey) {
|
||||
for (float z = aabb.min.z; z < aabb.max.z; z += voxelsizez) {
|
||||
vx_aabb_t saabb;
|
||||
|
||||
saabb.min.x = x - halfsizex;
|
||||
saabb.min.y = y - halfsizey;
|
||||
saabb.min.z = z - halfsizez;
|
||||
saabb.max.x = x + halfsizex;
|
||||
saabb.max.y = y + halfsizey;
|
||||
saabb.max.z = z + halfsizez;
|
||||
|
||||
vx_vertex_t boxcenter = vx__aabb_center(&saabb);
|
||||
vx_vertex_t halfsize = vx__aabb_half_size(&saabb);
|
||||
|
||||
// HACK: some holes might appear, this
|
||||
// precision factor reduces the artifact
|
||||
halfsize.x += precision;
|
||||
halfsize.y += precision;
|
||||
halfsize.z += precision;
|
||||
|
||||
if (vx__triangle_box_overlap(boxcenter, halfsize, triangle)) {
|
||||
vx_vertex_t* nodedata = VX_MALLOC(vx_vertex_t, 1);
|
||||
*nodedata = boxcenter;
|
||||
|
||||
size_t hash = vx__vertex_hash(boxcenter, VOXELIZER_HASH_TABLE_SIZE);
|
||||
|
||||
bool insert = vx__hash_table_insert(table,
|
||||
hash,
|
||||
nodedata,
|
||||
vx__vertex_comp_func);
|
||||
|
||||
if (insert) {
|
||||
voxels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outmesh = VX_MALLOC(vx_mesh_t, 1);
|
||||
size_t nvertices = voxels * 8;
|
||||
size_t nindices = voxels * VOXELIZER_INDICES_SIZE;
|
||||
outmesh->nnormals = VOXELIZER_NORMAL_INDICES_SIZE;
|
||||
outmesh->vertices = VX_CALLOC(vx_vertex_t, nvertices);
|
||||
outmesh->normals = VX_CALLOC(vx_vertex_t, 6);
|
||||
outmesh->indices = VX_CALLOC(unsigned int, nindices);
|
||||
outmesh->normalindices = VX_CALLOC(unsigned int, nindices);
|
||||
outmesh->nindices = 0;
|
||||
outmesh->nvertices = 0;
|
||||
|
||||
memcpy(outmesh->normals, vx_normals, 18 * sizeof(float));
|
||||
|
||||
float vertices[24] = {
|
||||
-halfsizex, halfsizey, halfsizez,
|
||||
-halfsizex, -halfsizey, halfsizez,
|
||||
halfsizex, -halfsizey, halfsizez,
|
||||
halfsizex, halfsizey, halfsizez,
|
||||
-halfsizex, halfsizey, -halfsizez,
|
||||
-halfsizex, -halfsizey, -halfsizez,
|
||||
halfsizex, -halfsizey, -halfsizez,
|
||||
halfsizex, halfsizey, -halfsizez,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < table->size; ++i) {
|
||||
if (table->elements[i] != NULL) {
|
||||
vx_hash_table_node_t* node = table->elements[i];
|
||||
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vx_vertex_t* p = (vx_vertex_t*) node->data;
|
||||
vx__add_voxel(outmesh, p, vertices);
|
||||
|
||||
while (node->next) {
|
||||
node = node->next;
|
||||
p = (vx_vertex_t*) node->data;
|
||||
vx__add_voxel(outmesh, p, vertices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vx__hash_table_free(table, true);
|
||||
|
||||
return outmesh;
|
||||
}
|
||||
|
||||
#undef VOXELIZER_EPSILON
|
||||
#undef VOXELIZER_INDICES_SIZE
|
||||
#undef VOXELIZER_HASH_TABLE_SIZE
|
||||
|
||||
#endif // VX_VOXELIZER_IMPLEMENTATION
|
||||
@@ -1,12 +0,0 @@
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
LD_FLAGS=-framework OpenGL -lglfw3 -lglew
|
||||
endif
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
LD_FLAGS=-lGL -lGLU -lglfw3 -lGLEW -lX11 -lXrandr -lXinerama -lXxf86vm -lXcursor -lm -pthread -ldl
|
||||
endif
|
||||
|
||||
all:
|
||||
clang -c trackball.c
|
||||
clang -o viewer -g -O0 -pedantic -ansi -Wno-deprecated-declarations viewer-c.c trackball.o $(LD_FLAGS)
|
||||
# clang -pedantic -ansi -Weverything -Wno-deprecated-declarations viewer-c.c trackball.o -framework OpenGL -lglfw3 -lglew
|
||||
5
experimental/README.md
Normal file
5
experimental/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Experimental code for .obj loader.
|
||||
|
||||
* Multi-threaded optimized parser : tinyobj_loader_opt.h
|
||||
* zstd compressed .obj support. `--with-zstd` premake option.
|
||||
* gzip compressed .obj support. `--with-zlib` premake option.
|
||||
@@ -3,6 +3,11 @@ newoption {
|
||||
description = "Build with zlib."
|
||||
}
|
||||
|
||||
newoption {
|
||||
trigger = "with-zstd",
|
||||
description = "Build with ZStandard compression."
|
||||
}
|
||||
|
||||
solution "objview"
|
||||
-- location ( "build" )
|
||||
configurations { "Release", "Debug" }
|
||||
@@ -16,13 +21,23 @@ solution "objview"
|
||||
includedirs { "./" }
|
||||
includedirs { "../../" }
|
||||
|
||||
buildoptions { "-std=c++11" }
|
||||
flags { "c++11" }
|
||||
--buildoptions { "-std=c++11" }
|
||||
|
||||
if _OPTIONS['with-zlib'] then
|
||||
defines { 'ENABLE_ZLIB' }
|
||||
links { 'z' }
|
||||
end
|
||||
|
||||
if _OPTIONS['with-zstd'] then
|
||||
print("with-zstd")
|
||||
defines { 'ENABLE_ZSTD' }
|
||||
-- Set path to zstd installed dir.
|
||||
includedirs { '$$HOME/local/include' }
|
||||
libdirs { '$$HOME/local/lib' }
|
||||
links { 'zstd' }
|
||||
end
|
||||
|
||||
-- Uncomment if you want address sanitizer(gcc/clang only)
|
||||
--buildoptions { "-fsanitize=address" }
|
||||
--linkoptions { "-fsanitize=address" }
|
||||
@@ -34,14 +49,15 @@ solution "objview"
|
||||
|
||||
configuration { "windows" }
|
||||
-- Path to GLFW3
|
||||
includedirs { '../../../../local/glfw-3.1.2.bin.WIN64/include' }
|
||||
libdirs { '../../../../local/glfw-3.1.2.bin.WIN64/lib-vc2013' }
|
||||
includedirs { '../../../local/glfw-3.2.bin.WIN64/include' }
|
||||
libdirs { '../../../local/glfw-3.2.bin.WIN64/lib-vc2015' }
|
||||
-- Path to GLEW
|
||||
includedirs { '../../../../local/glew-1.13.0/include' }
|
||||
libdirs { '../../../../local/glew-1.13.0/lib/Release/x64' }
|
||||
includedirs { '../../../local/glew-1.13.0/include' }
|
||||
libdirs { '../../../local/glew-1.13.0/lib/Release/x64' }
|
||||
|
||||
links { "glfw3", "glew32", "gdi32", "winmm", "user32", "glu32","opengl32", "kernel32" }
|
||||
defines { "_CRT_SECURE_NO_WARNINGS" }
|
||||
defines { "NOMINMAX" }
|
||||
|
||||
configuration { "macosx" }
|
||||
includedirs { "/usr/local/include" }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,7 @@ THE SOFTWARE.
|
||||
#ifndef TINOBJ_LOADER_OPT_H_
|
||||
#define TINOBJ_LOADER_OPT_H_
|
||||
|
||||
#ifdef _WIN64
|
||||
#ifdef _WIN32
|
||||
#define atoll(S) _atoi64(S)
|
||||
#include <windows.h>
|
||||
#else
|
||||
@@ -292,6 +292,22 @@ typedef struct {
|
||||
std::string bump_texname; // map_bump, bump
|
||||
std::string displacement_texname; // disp
|
||||
std::string alpha_texname; // map_d
|
||||
|
||||
// PBR extension
|
||||
// http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
|
||||
float roughness; // [0, 1] default 0
|
||||
float metallic; // [0, 1] default 0
|
||||
float sheen; // [0, 1] default 0
|
||||
float clearcoat_thickness; // [0, 1] default 0
|
||||
float clearcoat_roughness; // [0, 1] default 0
|
||||
float anisotropy; // aniso. [0, 1] default 0
|
||||
float anisotropy_rotation; // anisor. [0, 1] default 0
|
||||
std::string roughness_texname; // map_Pr
|
||||
std::string metallic_texname; // map_Pm
|
||||
std::string sheen_texname; // map_Ps
|
||||
std::string emissive_texname; // map_Ke
|
||||
std::string normal_texname; // norm. For normal mapping.
|
||||
|
||||
std::map<std::string, std::string> unknown_parameter;
|
||||
} material_t;
|
||||
|
||||
@@ -301,19 +317,20 @@ typedef struct {
|
||||
unsigned int length;
|
||||
} shape_t;
|
||||
|
||||
struct vertex_index {
|
||||
int v_idx, vt_idx, vn_idx;
|
||||
vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {}
|
||||
explicit vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}
|
||||
vertex_index(int vidx, int vtidx, int vnidx)
|
||||
: v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}
|
||||
struct index_t {
|
||||
int vertex_index, texcoord_index, normal_index;
|
||||
index_t() : vertex_index(-1), texcoord_index(-1), normal_index(-1) {}
|
||||
explicit index_t(int idx)
|
||||
: vertex_index(idx), texcoord_index(idx), normal_index(idx) {}
|
||||
index_t(int vidx, int vtidx, int vnidx)
|
||||
: vertex_index(vidx), texcoord_index(vtidx), normal_index(vnidx) {}
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
std::vector<float, lt::allocator<float> > vertices;
|
||||
std::vector<float, lt::allocator<float> > normals;
|
||||
std::vector<float, lt::allocator<float> > texcoords;
|
||||
std::vector<vertex_index, lt::allocator<vertex_index> > faces;
|
||||
std::vector<index_t, lt::allocator<index_t> > indices;
|
||||
std::vector<int, lt::allocator<int> > face_num_verts;
|
||||
std::vector<int, lt::allocator<int> > material_ids;
|
||||
} attrib_t;
|
||||
@@ -386,12 +403,11 @@ static inline int fixIndex(int idx, int n) {
|
||||
}
|
||||
|
||||
// Parse raw triples: i, i/j/k, i//k, i/j
|
||||
static vertex_index parseRawTriple(const char **token) {
|
||||
vertex_index vi(
|
||||
static index_t parseRawTriple(const char **token) {
|
||||
index_t vi(
|
||||
static_cast<int>(0x80000000)); // 0x80000000 = -2147483648 = invalid
|
||||
|
||||
vi.v_idx = my_atoi((*token));
|
||||
//(*token) += strcspn((*token), "/ \t\r");
|
||||
vi.vertex_index = my_atoi((*token));
|
||||
while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
|
||||
(*token)[0] != '\t' && (*token)[0] != '\r') {
|
||||
(*token)++;
|
||||
@@ -404,8 +420,7 @@ static vertex_index parseRawTriple(const char **token) {
|
||||
// i//k
|
||||
if ((*token)[0] == '/') {
|
||||
(*token)++;
|
||||
vi.vn_idx = my_atoi((*token));
|
||||
//(*token) += strcspn((*token), "/ \t\r");
|
||||
vi.normal_index = my_atoi((*token));
|
||||
while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
|
||||
(*token)[0] != '\t' && (*token)[0] != '\r') {
|
||||
(*token)++;
|
||||
@@ -414,8 +429,7 @@ static vertex_index parseRawTriple(const char **token) {
|
||||
}
|
||||
|
||||
// i/j/k or i/j
|
||||
vi.vt_idx = my_atoi((*token));
|
||||
//(*token) += strcspn((*token), "/ \t\r");
|
||||
vi.texcoord_index = my_atoi((*token));
|
||||
while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
|
||||
(*token)[0] != '\t' && (*token)[0] != '\r') {
|
||||
(*token)++;
|
||||
@@ -426,8 +440,7 @@ static vertex_index parseRawTriple(const char **token) {
|
||||
|
||||
// i/j/k
|
||||
(*token)++; // skip '/'
|
||||
vi.vn_idx = my_atoi((*token));
|
||||
//(*token) += strcspn((*token), "/ \t\r");
|
||||
vi.normal_index = my_atoi((*token));
|
||||
while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
|
||||
(*token)[0] != '\t' && (*token)[0] != '\r') {
|
||||
(*token)++;
|
||||
@@ -436,17 +449,17 @@ static vertex_index parseRawTriple(const char **token) {
|
||||
}
|
||||
|
||||
static inline bool parseString(ShortString *s, const char **token) {
|
||||
skip_space(token); //(*token) += strspn((*token), " \t");
|
||||
size_t e = until_space((*token)); // strcspn((*token), " \t\r");
|
||||
skip_space(token);
|
||||
size_t e = until_space((*token));
|
||||
(*s)->insert((*s)->end(), (*token), (*token) + e);
|
||||
(*token) += e;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline int parseInt(const char **token) {
|
||||
skip_space(token); //(*token) += strspn((*token), " \t");
|
||||
skip_space(token);
|
||||
int i = my_atoi((*token));
|
||||
(*token) += until_space((*token)); // strcspn((*token), " \t\r");
|
||||
(*token) += until_space((*token));
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -585,9 +598,9 @@ assemble :
|
||||
|
||||
{
|
||||
// = pow(5.0, exponent);
|
||||
double a = 5.0;
|
||||
double a = 1.0;
|
||||
for (int i = 0; i < exponent; i++) {
|
||||
a = a * a;
|
||||
a = a * 5.0;
|
||||
}
|
||||
*result =
|
||||
//(sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), exponent);
|
||||
@@ -601,13 +614,12 @@ fail:
|
||||
}
|
||||
|
||||
static inline float parseFloat(const char **token) {
|
||||
skip_space(token); //(*token) += strspn((*token), " \t");
|
||||
skip_space(token);
|
||||
#ifdef TINY_OBJ_LOADER_OLD_FLOAT_PARSER
|
||||
float f = static_cast<float>(atof(*token));
|
||||
(*token) += strcspn((*token), " \t\r");
|
||||
#else
|
||||
const char *end =
|
||||
(*token) + until_space((*token)); // strcspn((*token), " \t\r");
|
||||
const char *end = (*token) + until_space((*token));
|
||||
double val = 0.0;
|
||||
tryParseDouble((*token), end, &val);
|
||||
float f = static_cast<float>(val);
|
||||
@@ -665,6 +677,11 @@ static void LoadMtl(std::map<std::string, int> *material_map,
|
||||
|
||||
std::string linebuf(&buf[0]);
|
||||
|
||||
// Trim trailing whitespace.
|
||||
if (linebuf.size() > 0) {
|
||||
linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1);
|
||||
}
|
||||
|
||||
// Trim newline '\r\n' or '\n'
|
||||
if (linebuf.size() > 0) {
|
||||
if (linebuf[linebuf.size() - 1] == '\n')
|
||||
@@ -747,7 +764,8 @@ static void LoadMtl(std::map<std::string, int> *material_map,
|
||||
}
|
||||
|
||||
// transmittance
|
||||
if (token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) {
|
||||
if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) ||
|
||||
(token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) {
|
||||
token += 2;
|
||||
float r, g, b;
|
||||
parseFloat3(&r, &g, &b, &token);
|
||||
@@ -795,6 +813,7 @@ static void LoadMtl(std::map<std::string, int> *material_map,
|
||||
material.dissolve = parseFloat(&token);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) {
|
||||
token += 2;
|
||||
// Invert value of Tr(assume Tr is in range [0, 1])
|
||||
@@ -802,6 +821,55 @@ static void LoadMtl(std::map<std::string, int> *material_map,
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: roughness
|
||||
if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) {
|
||||
token += 2;
|
||||
material.roughness = parseFloat(&token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: metallic
|
||||
if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) {
|
||||
token += 2;
|
||||
material.metallic = parseFloat(&token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: sheen
|
||||
if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) {
|
||||
token += 2;
|
||||
material.sheen = parseFloat(&token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: clearcoat thickness
|
||||
if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) {
|
||||
token += 2;
|
||||
material.clearcoat_thickness = parseFloat(&token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: clearcoat roughness
|
||||
if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) {
|
||||
token += 4;
|
||||
material.clearcoat_roughness = parseFloat(&token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: anisotropy
|
||||
if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) {
|
||||
token += 6;
|
||||
material.anisotropy = parseFloat(&token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: anisotropy rotation
|
||||
if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) {
|
||||
token += 7;
|
||||
material.anisotropy_rotation = parseFloat(&token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ambient texture
|
||||
if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) {
|
||||
token += 7;
|
||||
@@ -858,6 +926,41 @@ static void LoadMtl(std::map<std::string, int> *material_map,
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: roughness texture
|
||||
if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) {
|
||||
token += 7;
|
||||
material.roughness_texname = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: metallic texture
|
||||
if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) {
|
||||
token += 7;
|
||||
material.metallic_texname = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: sheen texture
|
||||
if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) {
|
||||
token += 7;
|
||||
material.sheen_texname = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: emissive texture
|
||||
if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) {
|
||||
token += 7;
|
||||
material.emissive_texname = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
// PBR: normal map texture
|
||||
if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) {
|
||||
token += 5;
|
||||
material.normal_texname = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
// unknown parameter
|
||||
const char *_space = strchr(token, ' ');
|
||||
if (!_space) {
|
||||
@@ -896,8 +999,8 @@ typedef struct {
|
||||
float tx, ty;
|
||||
|
||||
// for f
|
||||
std::vector<vertex_index, lt::allocator<vertex_index> > f;
|
||||
// std::vector<vertex_index> f;
|
||||
std::vector<index_t, lt::allocator<index_t> > f;
|
||||
// std::vector<index_t> f;
|
||||
std::vector<int, lt::allocator<int> > f_num_verts;
|
||||
|
||||
const char *group_name;
|
||||
@@ -918,44 +1021,42 @@ struct CommandCount {
|
||||
size_t num_vn;
|
||||
size_t num_vt;
|
||||
size_t num_f;
|
||||
size_t num_faces;
|
||||
size_t num_indices;
|
||||
CommandCount() {
|
||||
num_v = 0;
|
||||
num_vn = 0;
|
||||
num_vt = 0;
|
||||
num_f = 0;
|
||||
num_faces = 0;
|
||||
num_indices = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class
|
||||
LoadOption
|
||||
{
|
||||
class LoadOption {
|
||||
public:
|
||||
LoadOption() : req_num_threads(-1), triangulate(true), verbose(false) {}
|
||||
|
||||
int req_num_threads;
|
||||
bool triangulate;
|
||||
bool verbose;
|
||||
LoadOption() : req_num_threads(-1), triangulate(true), verbose(false) {}
|
||||
|
||||
int req_num_threads;
|
||||
bool triangulate;
|
||||
bool verbose;
|
||||
};
|
||||
|
||||
|
||||
/// Parse wavefront .obj(.obj string data is expanded to linear char array
|
||||
/// `buf')
|
||||
/// -1 to req_num_threads use the number of HW threads in the running system.
|
||||
bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
size_t len, const LoadOption& option);
|
||||
bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
std::vector<material_t> *materials, const char *buf, size_t len,
|
||||
const LoadOption &option);
|
||||
|
||||
#ifdef TINYOBJ_LOADER_OPT_IMPLEMENTATION
|
||||
|
||||
static bool parseLine(Command *command, const char *p, size_t p_len,
|
||||
bool triangulate = true) {
|
||||
// @todo { operate directly on pointer `p'. to do that, add range check for
|
||||
// string operatoion against `p', since `p' is not null-terminated at p[p_len]
|
||||
// }
|
||||
char linebuf[4096];
|
||||
assert(p_len < 4095);
|
||||
// StackVector<char, 256> linebuf;
|
||||
// linebuf->resize(p_len + 1);
|
||||
memcpy(&linebuf, p, p_len);
|
||||
memcpy(linebuf, p, p_len);
|
||||
linebuf[p_len] = '\0';
|
||||
|
||||
const char *token = linebuf;
|
||||
@@ -963,8 +1064,7 @@ static bool parseLine(Command *command, const char *p, size_t p_len,
|
||||
command->type = COMMAND_EMPTY;
|
||||
|
||||
// Skip leading space.
|
||||
// token += strspn(token, " \t");
|
||||
skip_space(&token); //(*token) += strspn((*token), " \t");
|
||||
skip_space(&token);
|
||||
|
||||
assert(token);
|
||||
if (token[0] == '\0') { // empty line
|
||||
@@ -978,7 +1078,7 @@ static bool parseLine(Command *command, const char *p, size_t p_len,
|
||||
// vertex
|
||||
if (token[0] == 'v' && IS_SPACE((token[1]))) {
|
||||
token += 2;
|
||||
float x, y, z;
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
parseFloat3(&x, &y, &z, &token);
|
||||
command->vx = x;
|
||||
command->vy = y;
|
||||
@@ -990,7 +1090,7 @@ static bool parseLine(Command *command, const char *p, size_t p_len,
|
||||
// normal
|
||||
if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) {
|
||||
token += 3;
|
||||
float x, y, z;
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
parseFloat3(&x, &y, &z, &token);
|
||||
command->nx = x;
|
||||
command->ny = y;
|
||||
@@ -1002,7 +1102,7 @@ static bool parseLine(Command *command, const char *p, size_t p_len,
|
||||
// texcoord
|
||||
if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) {
|
||||
token += 3;
|
||||
float x, y;
|
||||
float x = 0.0f, y = 0.0f;
|
||||
parseFloat2(&x, &y, &token);
|
||||
command->tx = x;
|
||||
command->ty = y;
|
||||
@@ -1013,19 +1113,12 @@ static bool parseLine(Command *command, const char *p, size_t p_len,
|
||||
// face
|
||||
if (token[0] == 'f' && IS_SPACE((token[1]))) {
|
||||
token += 2;
|
||||
// token += strspn(token, " \t");
|
||||
skip_space(&token);
|
||||
|
||||
StackVector<vertex_index, 8> f;
|
||||
StackVector<index_t, 8> f;
|
||||
|
||||
while (!IS_NEW_LINE(token[0])) {
|
||||
vertex_index vi = parseRawTriple(&token);
|
||||
// printf("v = %d, %d, %d\n", vi.v_idx, vi.vn_idx, vi.vt_idx);
|
||||
// if (callback.index_cb) {
|
||||
// callback.index_cb(user_data, vi.v_idx, vi.vn_idx, vi.vt_idx);
|
||||
//}
|
||||
// size_t n = strspn(token, " \t\r");
|
||||
// token += n;
|
||||
index_t vi = parseRawTriple(&token);
|
||||
skip_space_and_cr(&token);
|
||||
|
||||
f->push_back(vi);
|
||||
@@ -1034,9 +1127,9 @@ static bool parseLine(Command *command, const char *p, size_t p_len,
|
||||
command->type = COMMAND_F;
|
||||
|
||||
if (triangulate) {
|
||||
vertex_index i0 = f[0];
|
||||
vertex_index i1(-1);
|
||||
vertex_index i2 = f[1];
|
||||
index_t i0 = f[0];
|
||||
index_t i1(-1);
|
||||
index_t i2 = f[1];
|
||||
|
||||
for (size_t k = 2; k < f->size(); k++) {
|
||||
i1 = i2;
|
||||
@@ -1153,27 +1246,28 @@ static inline bool is_line_ending(const char *p, size_t i, size_t end_i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
size_t len, const LoadOption& option)
|
||||
{
|
||||
bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
std::vector<material_t> *materials, const char *buf, size_t len,
|
||||
const LoadOption &option) {
|
||||
attrib->vertices.clear();
|
||||
attrib->normals.clear();
|
||||
attrib->texcoords.clear();
|
||||
attrib->faces.clear();
|
||||
attrib->indices.clear();
|
||||
attrib->face_num_verts.clear();
|
||||
attrib->material_ids.clear();
|
||||
shapes->clear();
|
||||
|
||||
if (len < 1) return false;
|
||||
|
||||
auto num_threads = (option.req_num_threads < 0) ? std::thread::hardware_concurrency()
|
||||
: option.req_num_threads;
|
||||
auto num_threads = (option.req_num_threads < 0)
|
||||
? std::thread::hardware_concurrency()
|
||||
: option.req_num_threads;
|
||||
num_threads =
|
||||
std::max(1, std::min(static_cast<int>(num_threads), kMaxThreads));
|
||||
(std::max)(1, (std::min)(static_cast<int>(num_threads), kMaxThreads));
|
||||
|
||||
if (option.verbose) {
|
||||
std::cout << "# of threads = " << num_threads << std::endl;
|
||||
}
|
||||
if (option.verbose) {
|
||||
std::cout << "# of threads = " << num_threads << std::endl;
|
||||
}
|
||||
|
||||
auto t1 = std::chrono::high_resolution_clock::now();
|
||||
|
||||
@@ -1201,7 +1295,7 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
for (size_t t = 0; t < static_cast<size_t>(num_threads); t++) {
|
||||
workers->push_back(std::thread([&, t]() {
|
||||
auto start_idx = (t + 0) * chunk_size;
|
||||
auto end_idx = std::min((t + 1) * chunk_size, len - 1);
|
||||
auto end_idx = (std::min)((t + 1) * chunk_size, len - 1);
|
||||
if (t == static_cast<size_t>((num_threads - 1))) {
|
||||
end_idx = len - 1;
|
||||
}
|
||||
@@ -1231,7 +1325,7 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
|
||||
// Find extra line which spand across chunk boundary.
|
||||
if ((t < num_threads) && (buf[end_idx - 1] != '\n')) {
|
||||
auto extra_span_idx = std::min(end_idx - 1 + chunk_size, len - 1);
|
||||
auto extra_span_idx = (std::min)(end_idx - 1 + chunk_size, len - 1);
|
||||
for (size_t i = end_idx; i < extra_span_idx; i++) {
|
||||
if (is_line_ending(buf, i, extra_span_idx)) {
|
||||
LineInfo info;
|
||||
@@ -1304,7 +1398,7 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
command_count[t].num_vt++;
|
||||
} else if (command.type == COMMAND_F) {
|
||||
command_count[t].num_f += command.f.size();
|
||||
command_count[t].num_faces++;
|
||||
command_count[t].num_indices += command.f_num_verts.size();
|
||||
}
|
||||
|
||||
if (command.type == COMMAND_MTLLIB) {
|
||||
@@ -1329,7 +1423,6 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
}
|
||||
|
||||
std::map<std::string, int> material_map;
|
||||
std::vector<material_t> materials;
|
||||
|
||||
// Load material(if exits)
|
||||
if (mtllib_i_index >= 0 && mtllib_t_index >= 0 &&
|
||||
@@ -1344,7 +1437,7 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
|
||||
std::ifstream ifs(material_filename);
|
||||
if (ifs.good()) {
|
||||
LoadMtl(&material_map, &materials, &ifs);
|
||||
LoadMtl(&material_map, materials, &ifs);
|
||||
|
||||
// std::cout << "maetrials = " << materials.size() << std::endl;
|
||||
|
||||
@@ -1368,14 +1461,15 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
size_t num_vn = 0;
|
||||
size_t num_vt = 0;
|
||||
size_t num_f = 0;
|
||||
size_t num_faces = 0;
|
||||
size_t num_indices = 0;
|
||||
for (size_t t = 0; t < num_threads; t++) {
|
||||
num_v += command_count[t].num_v;
|
||||
num_vn += command_count[t].num_vn;
|
||||
num_vt += command_count[t].num_vt;
|
||||
num_f += command_count[t].num_f;
|
||||
num_faces += command_count[t].num_faces;
|
||||
num_indices += command_count[t].num_indices;
|
||||
}
|
||||
|
||||
// std::cout << "# v " << num_v << std::endl;
|
||||
// std::cout << "# vn " << num_vn << std::endl;
|
||||
// std::cout << "# vt " << num_vt << std::endl;
|
||||
@@ -1389,9 +1483,9 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
attrib->vertices.resize(num_v * 3);
|
||||
attrib->normals.resize(num_vn * 3);
|
||||
attrib->texcoords.resize(num_vt * 2);
|
||||
attrib->faces.resize(num_f);
|
||||
attrib->face_num_verts.resize(num_faces);
|
||||
attrib->material_ids.resize(num_faces);
|
||||
attrib->indices.resize(num_f);
|
||||
attrib->face_num_verts.resize(num_indices);
|
||||
attrib->material_ids.resize(num_indices);
|
||||
|
||||
size_t v_offsets[kMaxThreads];
|
||||
size_t n_offsets[kMaxThreads];
|
||||
@@ -1410,7 +1504,7 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
n_offsets[t] = n_offsets[t - 1] + command_count[t - 1].num_vn;
|
||||
t_offsets[t] = t_offsets[t - 1] + command_count[t - 1].num_vt;
|
||||
f_offsets[t] = f_offsets[t - 1] + command_count[t - 1].num_f;
|
||||
face_offsets[t] = face_offsets[t - 1] + command_count[t - 1].num_faces;
|
||||
face_offsets[t] = face_offsets[t - 1] + command_count[t - 1].num_indices;
|
||||
}
|
||||
|
||||
StackVector<std::thread, 16> workers;
|
||||
@@ -1456,17 +1550,20 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
t_count++;
|
||||
} else if (commands[t][i].type == COMMAND_F) {
|
||||
for (size_t k = 0; k < commands[t][i].f.size(); k++) {
|
||||
vertex_index &vi = commands[t][i].f[k];
|
||||
int v_idx = fixIndex(vi.v_idx, v_count);
|
||||
int vn_idx = fixIndex(vi.vn_idx, n_count);
|
||||
int vt_idx = fixIndex(vi.vt_idx, t_count);
|
||||
attrib->faces[f_count + k] = vertex_index(v_idx, vn_idx, vt_idx);
|
||||
index_t &vi = commands[t][i].f[k];
|
||||
int vertex_index = fixIndex(vi.vertex_index, v_count);
|
||||
int texcoord_index = fixIndex(vi.texcoord_index, t_count);
|
||||
int normal_index = fixIndex(vi.normal_index, n_count);
|
||||
attrib->indices[f_count + k] =
|
||||
index_t(vertex_index, texcoord_index, normal_index);
|
||||
}
|
||||
for (size_t k = 0; k < commands[t][i].f_num_verts.size(); k++) {
|
||||
attrib->material_ids[face_count + k] = material_id;
|
||||
attrib->face_num_verts[face_count + k] = commands[t][i].f_num_verts[k];
|
||||
}
|
||||
attrib->material_ids[face_count] = material_id;
|
||||
attrib->face_num_verts[face_count] = commands[t][i].f.size();
|
||||
|
||||
f_count += commands[t][i].f.size();
|
||||
face_count++;
|
||||
face_count += commands[t][i].f_num_verts.size();
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -1556,21 +1653,21 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
|
||||
}
|
||||
|
||||
std::chrono::duration<double, std::milli> ms_total = t4 - t1;
|
||||
if (option.verbose) {
|
||||
std::cout << "total parsing time: " << ms_total.count() << " ms\n";
|
||||
std::cout << " line detection : " << ms_linedetection.count() << " ms\n";
|
||||
std::cout << " alloc buf : " << ms_alloc.count() << " ms\n";
|
||||
std::cout << " parse : " << ms_parse.count() << " ms\n";
|
||||
std::cout << " merge : " << ms_merge.count() << " ms\n";
|
||||
std::cout << " construct : " << ms_construct.count() << " ms\n";
|
||||
std::cout << " mtl load : " << ms_load_mtl.count() << " ms\n";
|
||||
std::cout << "# of vertices = " << attrib->vertices.size() << std::endl;
|
||||
std::cout << "# of normals = " << attrib->normals.size() << std::endl;
|
||||
std::cout << "# of texcoords = " << attrib->texcoords.size() << std::endl;
|
||||
std::cout << "# of face indices = " << attrib->faces.size() << std::endl;
|
||||
std::cout << "# of faces = " << attrib->material_ids.size() << std::endl;
|
||||
std::cout << "# of shapes = " << shapes->size() << std::endl;
|
||||
}
|
||||
if (option.verbose) {
|
||||
std::cout << "total parsing time: " << ms_total.count() << " ms\n";
|
||||
std::cout << " line detection : " << ms_linedetection.count() << " ms\n";
|
||||
std::cout << " alloc buf : " << ms_alloc.count() << " ms\n";
|
||||
std::cout << " parse : " << ms_parse.count() << " ms\n";
|
||||
std::cout << " merge : " << ms_merge.count() << " ms\n";
|
||||
std::cout << " construct : " << ms_construct.count() << " ms\n";
|
||||
std::cout << " mtl load : " << ms_load_mtl.count() << " ms\n";
|
||||
std::cout << "# of vertices = " << attrib->vertices.size() << std::endl;
|
||||
std::cout << "# of normals = " << attrib->normals.size() << std::endl;
|
||||
std::cout << "# of texcoords = " << attrib->texcoords.size() << std::endl;
|
||||
std::cout << "# of face indices = " << attrib->indices.size() << std::endl;
|
||||
std::cout << "# of indices = " << attrib->material_ids.size() << std::endl;
|
||||
std::cout << "# of shapes = " << shapes->size() << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ static void vsub(const float *src1, const float *src2, float *dst) {
|
||||
}
|
||||
|
||||
static void vcopy(const float *v1, float *v2) {
|
||||
register int i;
|
||||
int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
v2[i] = v1[i];
|
||||
}
|
||||
@@ -1,622 +0,0 @@
|
||||
#include <GL/glew.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/glu.h>
|
||||
#else
|
||||
#include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "trackball.h"
|
||||
|
||||
#define TINYOBJ_LOADER_C_IMPLEMENTATION
|
||||
#include "tinyobj_loader_c.h"
|
||||
|
||||
#define MAX_OBJECTS (128)
|
||||
|
||||
typedef struct {
|
||||
GLuint vb;
|
||||
int numTriangles;
|
||||
} DrawObject;
|
||||
|
||||
static DrawObject gDrawObject;
|
||||
|
||||
static int width = 768;
|
||||
static int height = 768;
|
||||
|
||||
static float prevMouseX, prevMouseY;
|
||||
static int mouseLeftPressed;
|
||||
static int mouseMiddlePressed;
|
||||
static int mouseRightPressed;
|
||||
static float curr_quat[4];
|
||||
static float prev_quat[4];
|
||||
static float eye[3], lookat[3], up[3];
|
||||
|
||||
static GLFWwindow* gWindow;
|
||||
|
||||
static void CheckErrors(const char* desc) {
|
||||
GLenum e = glGetError();
|
||||
if (e != GL_NO_ERROR) {
|
||||
fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc, e, e);
|
||||
exit(20);
|
||||
}
|
||||
}
|
||||
|
||||
static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
||||
float v10[3];
|
||||
float v20[3];
|
||||
float len2;
|
||||
|
||||
v10[0] = v1[0] - v0[0];
|
||||
v10[1] = v1[1] - v0[1];
|
||||
v10[2] = v1[2] - v0[2];
|
||||
|
||||
v20[0] = v2[0] - v0[0];
|
||||
v20[1] = v2[1] - v0[1];
|
||||
v20[2] = v2[2] - v0[2];
|
||||
|
||||
N[0] = v20[1] * v10[2] - v20[2] * v10[1];
|
||||
N[1] = v20[2] * v10[0] - v20[0] * v10[2];
|
||||
N[2] = v20[0] * v10[1] - v20[1] * v10[0];
|
||||
|
||||
len2 = N[0] * N[0] + N[1] * N[1] + N[2] * N[2];
|
||||
if (len2 > 0.0f) {
|
||||
float len = sqrt(len2);
|
||||
|
||||
N[0] /= len;
|
||||
N[1] /= len;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* mmap_file(size_t* len, const char* filename) {
|
||||
#ifdef _WIN64
|
||||
HANDLE file =
|
||||
CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
assert(file != INVALID_HANDLE_VALUE);
|
||||
|
||||
HANDLE fileMapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
assert(fileMapping != INVALID_HANDLE_VALUE);
|
||||
|
||||
LPVOID fileMapView = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, 0);
|
||||
auto fileMapViewChar = (const char*)fileMapView;
|
||||
assert(fileMapView != NULL);
|
||||
#else
|
||||
|
||||
FILE* f;
|
||||
long file_size;
|
||||
struct stat sb;
|
||||
char* p;
|
||||
int fd;
|
||||
|
||||
(*len) = 0;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
fseek(f, 0, SEEK_END);
|
||||
file_size = ftell(f);
|
||||
fclose(f);
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror("open");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
perror("fstat");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
fprintf(stderr, "%s is not a file\n", "lineitem.tbl");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = (char*)mmap(0, (size_t)file_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
if (p == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (close(fd) == -1) {
|
||||
perror("close");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*len) = (size_t)file_size;
|
||||
|
||||
return p;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int gz_load(std::vector<char>* buf, const char* filename)
|
||||
{
|
||||
#ifdef ENABLE_ZLIB
|
||||
gzFile file;
|
||||
file = gzopen (filename, "r");
|
||||
if (! file) {
|
||||
fprintf (stderr, "gzopen of '%s' failed: %s.\n", filename,
|
||||
strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
return false;
|
||||
}
|
||||
while (1) {
|
||||
int err;
|
||||
int bytes_read;
|
||||
unsigned char buffer[1024];
|
||||
bytes_read = gzread (file, buffer, 1024);
|
||||
buf->insert(buf->end(), buffer, buffer + 1024);
|
||||
//printf ("%s", buffer);
|
||||
if (bytes_read < 1024) {
|
||||
if (gzeof (file)) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
const char * error_string;
|
||||
error_string = gzerror (file, & err);
|
||||
if (err) {
|
||||
fprintf (stderr, "Error: %s.\n", error_string);
|
||||
exit (EXIT_FAILURE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gzclose (file);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char* get_file_data(size_t* len, const char* filename) {
|
||||
const char* ext = strrchr(filename, '.');
|
||||
|
||||
size_t data_len = 0;
|
||||
const char* data = NULL;
|
||||
|
||||
if (strcmp(ext, ".gz") == 0) {
|
||||
assert(0); /* todo */
|
||||
|
||||
#if 0
|
||||
std::vector<char> buf;
|
||||
bool ret = gz_load(&buf, filename);
|
||||
|
||||
if (ret) {
|
||||
char *p = static_cast<char*>(malloc(buf.size() + 1)); // @fixme { implement deleter }
|
||||
memcpy(p, &buf.at(0), buf.size());
|
||||
p[buf.size()] = '\0';
|
||||
data = p;
|
||||
data_len = buf.size();
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
data = mmap_file(&data_len, filename);
|
||||
}
|
||||
|
||||
(*len) = data_len;
|
||||
return data;
|
||||
}
|
||||
|
||||
static int LoadObjAndConvert(float bmin[3], float bmax[3],
|
||||
const char* filename) {
|
||||
tinyobj_attrib_t attrib;
|
||||
tinyobj_shape_t* shapes = NULL;
|
||||
size_t num_shapes;
|
||||
tinyobj_material_t* materials = NULL;
|
||||
size_t num_materials;
|
||||
|
||||
size_t data_len = 0;
|
||||
const char* data = get_file_data(&data_len, filename);
|
||||
if (data == NULL) {
|
||||
exit(-1);
|
||||
return 0;
|
||||
}
|
||||
printf("filesize: %d\n", (int)data_len);
|
||||
|
||||
{
|
||||
unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
|
||||
int ret = tinyobj_parse_obj(&attrib, &shapes, &num_shapes, &materials,
|
||||
&num_materials, data, data_len, flags);
|
||||
if (ret != TINYOBJ_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("# of shapes = %d\n", (int)num_shapes);
|
||||
printf("# of materiasl = %d\n", (int)num_materials);
|
||||
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < num_shapes; i++) {
|
||||
printf("shape[%d] name = %s\n", i, shapes[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
|
||||
bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;
|
||||
|
||||
{
|
||||
DrawObject o;
|
||||
float* vb;
|
||||
/* std::vector<float> vb; // */
|
||||
size_t face_offset = 0;
|
||||
size_t i;
|
||||
|
||||
/* Assume triangulated face. */
|
||||
size_t num_triangles = attrib.num_face_num_verts;
|
||||
size_t stride = 9; /* 9 = pos(3float), normal(3float), color(3float) */
|
||||
|
||||
vb = (float*)malloc(sizeof(float) * stride * num_triangles * 3);
|
||||
|
||||
for (i = 0; i < attrib.num_face_num_verts; i++) {
|
||||
size_t f;
|
||||
assert(attrib.face_num_verts[i] % 3 ==
|
||||
0); /* assume all triangle faces. */
|
||||
for (f = 0; f < attrib.face_num_verts[i] / 3; f++) {
|
||||
int k;
|
||||
float v[3][3];
|
||||
float n[3][3];
|
||||
float c[3];
|
||||
float len2;
|
||||
|
||||
tinyobj_vertex_index_t idx0 = attrib.faces[face_offset + 3 * f + 0];
|
||||
tinyobj_vertex_index_t idx1 = attrib.faces[face_offset + 3 * f + 1];
|
||||
tinyobj_vertex_index_t idx2 = attrib.faces[face_offset + 3 * f + 2];
|
||||
|
||||
for (k = 0; k < 3; k++) {
|
||||
int f0 = idx0.v_idx;
|
||||
int f1 = idx1.v_idx;
|
||||
int f2 = idx2.v_idx;
|
||||
assert(f0 >= 0);
|
||||
assert(f1 >= 0);
|
||||
assert(f2 >= 0);
|
||||
|
||||
v[0][k] = attrib.vertices[3 * f0 + k];
|
||||
v[1][k] = attrib.vertices[3 * f1 + k];
|
||||
v[2][k] = attrib.vertices[3 * f2 + k];
|
||||
bmin[k] = (v[0][k] < bmin[k]) ? v[0][k] : bmin[k];
|
||||
bmin[k] = (v[1][k] < bmin[k]) ? v[1][k] : bmin[k];
|
||||
bmin[k] = (v[2][k] < bmin[k]) ? v[2][k] : bmin[k];
|
||||
bmax[k] = (v[0][k] > bmax[k]) ? v[0][k] : bmax[k];
|
||||
bmax[k] = (v[1][k] > bmax[k]) ? v[1][k] : bmax[k];
|
||||
bmax[k] = (v[2][k] > bmax[k]) ? v[2][k] : bmax[k];
|
||||
}
|
||||
|
||||
if (attrib.num_normals > 0) {
|
||||
int f0 = idx0.vn_idx;
|
||||
int f1 = idx1.vn_idx;
|
||||
int f2 = idx2.vn_idx;
|
||||
if (f0 >= 0 && f1 >= 0 && f2 >= 0) {
|
||||
assert(3 * f0 + 2 < attrib.num_normals);
|
||||
assert(3 * f1 + 2 < attrib.num_normals);
|
||||
assert(3 * f2 + 2 < attrib.num_normals);
|
||||
for (k = 0; k < 3; k++) {
|
||||
n[0][k] = attrib.normals[3 * f0 + k];
|
||||
n[1][k] = attrib.normals[3 * f1 + k];
|
||||
n[2][k] = attrib.normals[3 * f2 + k];
|
||||
}
|
||||
} else { /* normal index is not defined for this face */
|
||||
/* compute geometric normal */
|
||||
CalcNormal(n[0], v[0], v[1], v[2]);
|
||||
n[1][0] = n[0][0];
|
||||
n[1][1] = n[0][1];
|
||||
n[1][2] = n[0][2];
|
||||
n[2][0] = n[0][0];
|
||||
n[2][1] = n[0][1];
|
||||
n[2][2] = n[0][2];
|
||||
}
|
||||
} else {
|
||||
/* compute geometric normal */
|
||||
CalcNormal(n[0], v[0], v[1], v[2]);
|
||||
n[1][0] = n[0][0];
|
||||
n[1][1] = n[0][1];
|
||||
n[1][2] = n[0][2];
|
||||
n[2][0] = n[0][0];
|
||||
n[2][1] = n[0][1];
|
||||
n[2][2] = n[0][2];
|
||||
}
|
||||
|
||||
for (k = 0; k < 3; k++) {
|
||||
vb[(3 * i + k) * stride + 0] = v[k][0];
|
||||
vb[(3 * i + k) * stride + 1] = v[k][1];
|
||||
vb[(3 * i + k) * stride + 2] = v[k][2];
|
||||
vb[(3 * i + k) * stride + 3] = n[k][0];
|
||||
vb[(3 * i + k) * stride + 4] = n[k][1];
|
||||
vb[(3 * i + k) * stride + 5] = n[k][2];
|
||||
|
||||
/* Use normal as color. */
|
||||
c[0] = n[k][0];
|
||||
c[1] = n[k][1];
|
||||
c[2] = n[k][2];
|
||||
len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
|
||||
if (len2 > 0.0f) {
|
||||
float len = (float)sqrt(len2);
|
||||
|
||||
c[0] /= len;
|
||||
c[1] /= len;
|
||||
c[2] /= len;
|
||||
}
|
||||
|
||||
vb[(3 * i + k) * stride + 6] = (c[0] * 0.5 + 0.5);
|
||||
vb[(3 * i + k) * stride + 7] = (c[1] * 0.5 + 0.5);
|
||||
vb[(3 * i + k) * stride + 8] = (c[2] * 0.5 + 0.5);
|
||||
}
|
||||
}
|
||||
face_offset += attrib.face_num_verts[i];
|
||||
}
|
||||
|
||||
o.vb = 0;
|
||||
o.numTriangles = 0;
|
||||
if (num_triangles > 0) {
|
||||
glGenBuffers(1, &o.vb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
|
||||
glBufferData(GL_ARRAY_BUFFER, num_triangles * 3 * stride * sizeof(float),
|
||||
vb, GL_STATIC_DRAW);
|
||||
o.numTriangles = num_triangles;
|
||||
}
|
||||
|
||||
free(vb);
|
||||
|
||||
gDrawObject = o;
|
||||
}
|
||||
|
||||
printf("bmin = %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
|
||||
printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
|
||||
|
||||
tinyobj_attrib_free(&attrib);
|
||||
tinyobj_shapes_free(shapes, num_shapes);
|
||||
tinyobj_materials_free(materials, num_materials);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void reshapeFunc(GLFWwindow* window, int w, int h) {
|
||||
int fb_w, fb_h;
|
||||
glfwGetFramebufferSize(window, &fb_w, &fb_h);
|
||||
|
||||
glViewport(0, 0, fb_w, fb_h);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(45.0, (GLdouble)w / (GLdouble)h, (GLdouble)0.01f,
|
||||
(GLdouble)100.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
static void keyboardFunc(GLFWwindow* window, int key, int scancode, int action,
|
||||
int mods) {
|
||||
(void)window;
|
||||
(void)scancode;
|
||||
(void)mods;
|
||||
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
||||
/* Move camera */
|
||||
float mv_x = 0, mv_y = 0, mv_z = 0;
|
||||
if (key == GLFW_KEY_K)
|
||||
mv_x += 1;
|
||||
else if (key == GLFW_KEY_J)
|
||||
mv_x += -1;
|
||||
else if (key == GLFW_KEY_L)
|
||||
mv_y += 1;
|
||||
else if (key == GLFW_KEY_H)
|
||||
mv_y += -1;
|
||||
else if (key == GLFW_KEY_P)
|
||||
mv_z += 1;
|
||||
else if (key == GLFW_KEY_N)
|
||||
mv_z += -1;
|
||||
|
||||
if (key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE)
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void clickFunc(GLFWwindow* window, int button, int action, int mods) {
|
||||
(void)window;
|
||||
(void)mods;
|
||||
if (button == GLFW_MOUSE_BUTTON_LEFT) {
|
||||
if (action == GLFW_PRESS) {
|
||||
mouseLeftPressed = 1;
|
||||
trackball(prev_quat, 0.0, 0.0, 0.0, 0.0);
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
mouseLeftPressed = 0;
|
||||
}
|
||||
}
|
||||
if (button == GLFW_MOUSE_BUTTON_RIGHT) {
|
||||
if (action == GLFW_PRESS) {
|
||||
mouseRightPressed = 1;
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
mouseRightPressed = 0;
|
||||
}
|
||||
}
|
||||
if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
|
||||
if (action == GLFW_PRESS) {
|
||||
mouseMiddlePressed = 1;
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
mouseMiddlePressed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
|
||||
float rotScale = 1.0f;
|
||||
float transScale = 2.0f;
|
||||
|
||||
(void)window;
|
||||
|
||||
if (mouseLeftPressed) {
|
||||
trackball(prev_quat, rotScale * (2.0f * prevMouseX - width) / (float)width,
|
||||
rotScale * (height - 2.0f * prevMouseY) / (float)height,
|
||||
rotScale * (2.0f * (float)mouse_x - width) / (float)width,
|
||||
rotScale * (height - 2.0f * (float)mouse_y) / (float)height);
|
||||
|
||||
add_quats(prev_quat, curr_quat, curr_quat);
|
||||
} else if (mouseMiddlePressed) {
|
||||
eye[0] -= transScale * ((float)mouse_x - prevMouseX) / (float)width;
|
||||
lookat[0] -= transScale * ((float)mouse_x - prevMouseX) / (float)width;
|
||||
eye[1] += transScale * ((float)mouse_y - prevMouseY) / (float)height;
|
||||
lookat[1] += transScale * ((float)mouse_y - prevMouseY) / (float)height;
|
||||
} else if (mouseRightPressed) {
|
||||
eye[2] += transScale * ((float)mouse_y - prevMouseY) / (float)height;
|
||||
lookat[2] += transScale * ((float)mouse_y - prevMouseY) / (float)height;
|
||||
}
|
||||
|
||||
prevMouseX = (float)mouse_x;
|
||||
prevMouseY = (float)mouse_y;
|
||||
}
|
||||
|
||||
static void Draw(const DrawObject* draw_object) {
|
||||
int i;
|
||||
|
||||
glPolygonMode(GL_FRONT, GL_FILL);
|
||||
glPolygonMode(GL_BACK, GL_FILL);
|
||||
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.0, 1.0);
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
if (draw_object->vb >= 1) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, draw_object->vb);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
|
||||
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float) * 3));
|
||||
glColorPointer(3, GL_FLOAT, 36, (const void*)(sizeof(float) * 6));
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3 * draw_object->numTriangles);
|
||||
CheckErrors("drawarrays");
|
||||
}
|
||||
|
||||
/* draw wireframe */
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonMode(GL_FRONT, GL_LINE);
|
||||
glPolygonMode(GL_BACK, GL_LINE);
|
||||
|
||||
glColor3f(0.0f, 0.0f, 0.4f);
|
||||
|
||||
if (draw_object->vb >= 1) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, draw_object->vb);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
|
||||
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float) * 3));
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3 * draw_object->numTriangles);
|
||||
CheckErrors("drawarrays");
|
||||
}
|
||||
}
|
||||
|
||||
static void Init() {
|
||||
trackball(curr_quat, 0, 0, 0, 0);
|
||||
|
||||
eye[0] = 0.0f;
|
||||
eye[1] = 0.0f;
|
||||
eye[2] = 3.0f;
|
||||
|
||||
lookat[0] = 0.0f;
|
||||
lookat[1] = 0.0f;
|
||||
lookat[2] = 0.0f;
|
||||
|
||||
up[0] = 0.0f;
|
||||
up[1] = 1.0f;
|
||||
up[2] = 0.0f;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Needs input.obj\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Init();
|
||||
|
||||
printf("Initialize GLFW...\n");
|
||||
|
||||
if (!glfwInit()) {
|
||||
fprintf(stderr, "Failed to initialize GLFW.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
gWindow = glfwCreateWindow(width, height, "Obj viewer", NULL, NULL);
|
||||
if (gWindow == NULL) {
|
||||
fprintf(stderr, "Failed to open GLFW window.\n");
|
||||
glfwTerminate();
|
||||
return 1;
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(gWindow);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
glfwSetWindowSizeCallback(gWindow, reshapeFunc);
|
||||
glfwSetKeyCallback(gWindow, keyboardFunc);
|
||||
glfwSetMouseButtonCallback(gWindow, clickFunc);
|
||||
glfwSetCursorPosCallback(gWindow, motionFunc);
|
||||
|
||||
/* glewExperimental = 1; */
|
||||
if (glewInit() != GLEW_OK) {
|
||||
fprintf(stderr, "Failed to initialize GLEW.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
reshapeFunc(gWindow, width, height);
|
||||
|
||||
{
|
||||
float bmin[3], bmax[3];
|
||||
float maxExtent;
|
||||
if (0 == LoadObjAndConvert(bmin, bmax, argv[1])) {
|
||||
printf("failed to load & conv\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
maxExtent = 0.5f * (bmax[0] - bmin[0]);
|
||||
if (maxExtent < 0.5f * (bmax[1] - bmin[1])) {
|
||||
maxExtent = 0.5f * (bmax[1] - bmin[1]);
|
||||
}
|
||||
if (maxExtent < 0.5f * (bmax[2] - bmin[2])) {
|
||||
maxExtent = 0.5f * (bmax[2] - bmin[2]);
|
||||
}
|
||||
|
||||
while (glfwWindowShouldClose(gWindow) == GL_FALSE) {
|
||||
GLfloat mat[4][4];
|
||||
|
||||
glfwPollEvents();
|
||||
glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt((GLdouble)eye[0], (GLdouble)eye[1], (GLdouble)eye[2],
|
||||
(GLdouble)lookat[0], (GLdouble)lookat[1], (GLdouble)lookat[2],
|
||||
(GLdouble)up[0], (GLdouble)up[1], (GLdouble)up[2]);
|
||||
build_rotmatrix(mat, curr_quat);
|
||||
glMultMatrixf(&mat[0][0]);
|
||||
|
||||
/* Fit to -1, 1 */
|
||||
glScalef(1.0f / maxExtent, 1.0f / maxExtent, 1.0f / maxExtent);
|
||||
|
||||
/* Centerize object. */
|
||||
glTranslatef(-0.5f * (bmax[0] + bmin[0]), -0.5f * (bmax[1] + bmin[1]),
|
||||
-0.5f * (bmax[2] + bmin[2]));
|
||||
|
||||
Draw(&gDrawObject);
|
||||
|
||||
glfwSwapBuffers(gWindow);
|
||||
}
|
||||
}
|
||||
|
||||
glfwTerminate();
|
||||
}
|
||||
@@ -16,6 +16,10 @@
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_ZSTD)
|
||||
#include <zstd.h>
|
||||
#endif
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
@@ -86,16 +90,24 @@ void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
||||
const char *mmap_file(size_t *len, const char* filename)
|
||||
{
|
||||
(*len) = 0;
|
||||
#ifdef _WIN64
|
||||
#ifdef _WIN32
|
||||
HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
assert(file != INVALID_HANDLE_VALUE);
|
||||
assert(file != INVALID_HANDLE_VALUE);
|
||||
|
||||
HANDLE fileMapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
assert(fileMapping != INVALID_HANDLE_VALUE);
|
||||
HANDLE fileMapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
assert(fileMapping != INVALID_HANDLE_VALUE);
|
||||
|
||||
LPVOID fileMapView = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, 0);
|
||||
auto fileMapViewChar = (const char*)fileMapView;
|
||||
assert(fileMapView != NULL);
|
||||
LPVOID fileMapView = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, 0);
|
||||
auto fileMapViewChar = (const char*)fileMapView;
|
||||
assert(fileMapView != NULL);
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
fileSize.QuadPart = 0;
|
||||
GetFileSizeEx(file, &fileSize);
|
||||
|
||||
(*len) = static_cast<size_t>(fileSize.QuadPart);
|
||||
return fileMapViewChar;
|
||||
|
||||
#else
|
||||
|
||||
FILE* f = fopen(filename, "r" );
|
||||
@@ -182,6 +194,71 @@ bool gz_load(std::vector<char>* buf, const char* filename)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ZSTD
|
||||
static off_t fsize_X(const char *filename)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(filename, &st) == 0) return st.st_size;
|
||||
/* error */
|
||||
printf("stat: %s : %s \n", filename, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static FILE* fopen_X(const char *filename, const char *instruction)
|
||||
{
|
||||
FILE* const inFile = fopen(filename, instruction);
|
||||
if (inFile) return inFile;
|
||||
/* error */
|
||||
printf("fopen: %s : %s \n", filename, strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
static void* malloc_X(size_t size)
|
||||
{
|
||||
void* const buff = malloc(size);
|
||||
if (buff) return buff;
|
||||
/* error */
|
||||
printf("malloc: %s \n", strerror(errno));
|
||||
exit(3);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool zstd_load(std::vector<char>* buf, const char* filename)
|
||||
{
|
||||
#ifdef ENABLE_ZSTD
|
||||
off_t const buffSize = fsize_X(filename);
|
||||
FILE* const inFile = fopen_X(filename, "rb");
|
||||
void* const buffer = malloc_X(buffSize);
|
||||
size_t const readSize = fread(buffer, 1, buffSize, inFile);
|
||||
if (readSize != (size_t)buffSize) {
|
||||
printf("fread: %s : %s \n", filename, strerror(errno));
|
||||
exit(4);
|
||||
}
|
||||
fclose(inFile);
|
||||
|
||||
unsigned long long const rSize = ZSTD_getDecompressedSize(buffer, buffSize);
|
||||
if (rSize==0) {
|
||||
printf("%s : original size unknown \n", filename);
|
||||
exit(5);
|
||||
}
|
||||
|
||||
buf->resize(rSize);
|
||||
|
||||
size_t const dSize = ZSTD_decompress(buf->data(), rSize, buffer, buffSize);
|
||||
|
||||
if (dSize != rSize) {
|
||||
printf("error decoding %s : %s \n", filename, ZSTD_getErrorName(dSize));
|
||||
exit(7);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* get_file_data(size_t *len, const char* filename)
|
||||
{
|
||||
|
||||
@@ -204,6 +281,20 @@ const char* get_file_data(size_t *len, const char* filename)
|
||||
data_len = buf.size();
|
||||
}
|
||||
|
||||
} else if (strcmp(ext, ".zst") == 0) {
|
||||
printf("zstd\n");
|
||||
// Zstandard data.
|
||||
|
||||
std::vector<char> buf;
|
||||
bool ret = zstd_load(&buf, filename);
|
||||
|
||||
if (ret) {
|
||||
char *p = static_cast<char*>(malloc(buf.size() + 1)); // @fixme { implement deleter }
|
||||
memcpy(p, &buf.at(0), buf.size());
|
||||
p[buf.size()] = '\0';
|
||||
data = p;
|
||||
data_len = buf.size();
|
||||
}
|
||||
} else {
|
||||
|
||||
data = mmap_file(&data_len, filename);
|
||||
@@ -214,26 +305,43 @@ const char* get_file_data(size_t *len, const char* filename)
|
||||
}
|
||||
|
||||
|
||||
bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int num_threads)
|
||||
bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int num_threads, bool verbose)
|
||||
{
|
||||
#if 1
|
||||
tinyobj_opt::attrib_t attrib;
|
||||
std::vector<tinyobj_opt::shape_t> shapes;
|
||||
std::vector<tinyobj_opt::material_t> materials;
|
||||
|
||||
auto load_t_begin = std::chrono::high_resolution_clock::now();
|
||||
size_t data_len = 0;
|
||||
const char* data = get_file_data(&data_len, filename);
|
||||
if (data == nullptr) {
|
||||
printf("failed to load file\n");
|
||||
exit(-1);
|
||||
return false;
|
||||
}
|
||||
printf("filesize: %d\n", (int)data_len);
|
||||
auto load_t_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double, std::milli> load_ms = load_t_end - load_t_begin;
|
||||
if (verbose) {
|
||||
std::cout << "filesize: " << data_len << std::endl;
|
||||
std::cout << "load time: " << load_ms.count() << " [msecs]" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
tinyobj_opt::LoadOption option;
|
||||
option.req_num_threads = num_threads;
|
||||
bool ret = parseObj(&attrib, &shapes, data, data_len, option);
|
||||
option.verbose = verbose;
|
||||
bool ret = parseObj(&attrib, &shapes, &materials, data, data_len, option);
|
||||
|
||||
if (!ret) {
|
||||
std::cerr << "Failed to parse .obj" << std::endl;
|
||||
return false;
|
||||
}
|
||||
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
|
||||
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
|
||||
|
||||
//std::cout << "vertices.size() = " << attrib.vertices.size() << std::endl;
|
||||
//std::cout << "normals.size() = " << attrib.normals.size() << std::endl;
|
||||
|
||||
{
|
||||
DrawObject o;
|
||||
std::vector<float> vb; // pos(3float), normal(3float), color(3float)
|
||||
@@ -241,15 +349,15 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int n
|
||||
for (size_t v = 0; v < attrib.face_num_verts.size(); v++) {
|
||||
assert(attrib.face_num_verts[v] % 3 == 0); // assume all triangle face.
|
||||
for (size_t f = 0; f < attrib.face_num_verts[v] / 3; f++) {
|
||||
tinyobj_opt::vertex_index idx0 = attrib.faces[face_offset+3*f+0];
|
||||
tinyobj_opt::vertex_index idx1 = attrib.faces[face_offset+3*f+1];
|
||||
tinyobj_opt::vertex_index idx2 = attrib.faces[face_offset+3*f+2];
|
||||
tinyobj_opt::index_t idx0 = attrib.indices[face_offset+3*f+0];
|
||||
tinyobj_opt::index_t idx1 = attrib.indices[face_offset+3*f+1];
|
||||
tinyobj_opt::index_t idx2 = attrib.indices[face_offset+3*f+2];
|
||||
|
||||
float v[3][3];
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int f0 = idx0.v_idx;
|
||||
int f1 = idx1.v_idx;
|
||||
int f2 = idx2.v_idx;
|
||||
int f0 = idx0.vertex_index;
|
||||
int f1 = idx1.vertex_index;
|
||||
int f2 = idx2.vertex_index;
|
||||
assert(f0 >= 0);
|
||||
assert(f1 >= 0);
|
||||
assert(f2 >= 0);
|
||||
@@ -268,19 +376,24 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int n
|
||||
float n[3][3];
|
||||
|
||||
if (attrib.normals.size() > 0) {
|
||||
int f0 = idx0.vn_idx;
|
||||
int f1 = idx1.vn_idx;
|
||||
int f2 = idx2.vn_idx;
|
||||
assert(f0 >= 0);
|
||||
assert(f1 >= 0);
|
||||
assert(f2 >= 0);
|
||||
assert(3*f0+2 < attrib.normals.size());
|
||||
assert(3*f1+2 < attrib.normals.size());
|
||||
assert(3*f2+2 < attrib.normals.size());
|
||||
for (int k = 0; k < 3; k++) {
|
||||
n[0][k] = attrib.normals[3*f0+k];
|
||||
n[1][k] = attrib.normals[3*f1+k];
|
||||
n[2][k] = attrib.normals[3*f2+k];
|
||||
int nf0 = idx0.normal_index;
|
||||
int nf1 = idx1.normal_index;
|
||||
int nf2 = idx2.normal_index;
|
||||
|
||||
if (nf0 >= 0 && nf1 >= 0 && nf2 >= 0) {
|
||||
assert(3*nf0+2 < attrib.normals.size());
|
||||
assert(3*nf1+2 < attrib.normals.size());
|
||||
assert(3*nf2+2 < attrib.normals.size());
|
||||
for (int k = 0; k < 3; k++) {
|
||||
n[0][k] = attrib.normals[3*nf0+k];
|
||||
n[1][k] = attrib.normals[3*nf1+k];
|
||||
n[2][k] = attrib.normals[3*nf2+k];
|
||||
}
|
||||
} else {
|
||||
// compute geometric normal
|
||||
CalcNormal(n[0], v[0], v[1], v[2]);
|
||||
n[1][0] = n[0][0]; n[1][1] = n[0][1]; n[1][2] = n[0][2];
|
||||
n[2][0] = n[0][0]; n[2][1] = n[0][1]; n[2][2] = n[0][2];
|
||||
}
|
||||
} else {
|
||||
// compute geometric normal
|
||||
@@ -299,7 +412,7 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int n
|
||||
// Use normal as color.
|
||||
float c[3] = {n[k][0], n[k][1], n[k][2]};
|
||||
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
|
||||
if (len2 > 0.0f) {
|
||||
if (len2 > 1.0e-6f) {
|
||||
float len = sqrtf(len2);
|
||||
|
||||
c[0] /= len;
|
||||
@@ -330,9 +443,6 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int n
|
||||
printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void reshapeFunc(GLFWwindow* window, int w, int h)
|
||||
@@ -499,35 +609,45 @@ static void Init() {
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::cout << "Needs input.obj\n" << std::endl;
|
||||
std::cout << "view input.obj <num_threads> <benchark_only> <verbose>" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool benchmark_only = false;
|
||||
int num_threads = -1;
|
||||
bool verbose = false;
|
||||
|
||||
if (argc > 2) {
|
||||
num_threads = atoi(argv[2]);
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
benchmark_only = true;
|
||||
benchmark_only = (atoi(argv[3]) > 0) ? true : false;
|
||||
}
|
||||
|
||||
if (argc > 4) {
|
||||
verbose = true;
|
||||
}
|
||||
|
||||
if (benchmark_only) {
|
||||
|
||||
tinyobj_opt::attrib_t attrib;
|
||||
std::vector<tinyobj_opt::shape_t> shapes;
|
||||
std::vector<tinyobj_opt::material_t> materials;
|
||||
|
||||
size_t data_len = 0;
|
||||
const char* data = get_file_data(&data_len, argv[1]);
|
||||
if (data == nullptr) {
|
||||
printf("failed to load file\n");
|
||||
exit(-1);
|
||||
return false;
|
||||
}
|
||||
printf("filesize: %d\n", (int)data_len);
|
||||
tinyobj_opt::LoadOption option;
|
||||
option.req_num_threads = num_threads;
|
||||
bool ret = parseObj(&attrib, &shapes, data, data_len, option);
|
||||
option.verbose = true;
|
||||
|
||||
bool ret = parseObj(&attrib, &shapes, &materials, data, data_len, option);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -569,7 +689,7 @@ int main(int argc, char **argv)
|
||||
reshapeFunc(window, width, height);
|
||||
|
||||
float bmin[3], bmax[3];
|
||||
if (false == LoadObjAndConvert(bmin, bmax, argv[1], num_threads)) {
|
||||
if (false == LoadObjAndConvert(bmin, bmax, argv[1], num_threads, verbose)) {
|
||||
printf("failed to load & conv\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "tiny_obj_loader.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef __cplusplus
|
||||
@@ -30,7 +30,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
class timerutil {
|
||||
public:
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
typedef DWORD time_t;
|
||||
|
||||
@@ -58,7 +58,8 @@ public:
|
||||
static_cast<time_t>((tv[1].tv_usec - tv[0].tv_usec) / 1000);
|
||||
}
|
||||
time_t usec() {
|
||||
return this->sec() * 1000000 + static_cast<time_t>(tv[1].tv_usec - tv[0].tv_usec);
|
||||
return this->sec() * 1000000 +
|
||||
static_cast<time_t>(tv[1].tv_usec - tv[0].tv_usec);
|
||||
}
|
||||
time_t current() {
|
||||
struct timeval t;
|
||||
@@ -66,7 +67,7 @@ public:
|
||||
return static_cast<time_t>(t.tv_sec * 1000 + t.tv_usec);
|
||||
}
|
||||
|
||||
#else // C timer
|
||||
#else // C timer
|
||||
// using namespace std;
|
||||
typedef clock_t time_t;
|
||||
|
||||
@@ -81,7 +82,7 @@ public:
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
DWORD t_[2];
|
||||
#else
|
||||
@@ -94,96 +95,103 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials)
|
||||
{
|
||||
static void PrintInfo(const tinyobj::attrib_t& attrib,
|
||||
const std::vector<tinyobj::shape_t>& shapes,
|
||||
const std::vector<tinyobj::material_t>& materials) {
|
||||
std::cout << "# of vertices : " << (attrib.vertices.size() / 3) << std::endl;
|
||||
std::cout << "# of normals : " << (attrib.normals.size() / 3) << std::endl;
|
||||
std::cout << "# of texcoords : " << (attrib.texcoords.size() / 2) << std::endl;
|
||||
std::cout << "# of texcoords : " << (attrib.texcoords.size() / 2)
|
||||
<< std::endl;
|
||||
|
||||
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
||||
std::cout << "# of materials : " << materials.size() << std::endl;
|
||||
|
||||
for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
|
||||
printf(" v[%ld] = (%f, %f, %f)\n", static_cast<long>(v),
|
||||
static_cast<const double>(attrib.vertices[3*v+0]),
|
||||
static_cast<const double>(attrib.vertices[3*v+1]),
|
||||
static_cast<const double>(attrib.vertices[3*v+2]));
|
||||
static_cast<const double>(attrib.vertices[3 * v + 0]),
|
||||
static_cast<const double>(attrib.vertices[3 * v + 1]),
|
||||
static_cast<const double>(attrib.vertices[3 * v + 2]));
|
||||
}
|
||||
|
||||
for (size_t v = 0; v < attrib.normals.size() / 3; v++) {
|
||||
printf(" n[%ld] = (%f, %f, %f)\n", static_cast<long>(v),
|
||||
static_cast<const double>(attrib.normals[3*v+0]),
|
||||
static_cast<const double>(attrib.normals[3*v+1]),
|
||||
static_cast<const double>(attrib.normals[3*v+2]));
|
||||
static_cast<const double>(attrib.normals[3 * v + 0]),
|
||||
static_cast<const double>(attrib.normals[3 * v + 1]),
|
||||
static_cast<const double>(attrib.normals[3 * v + 2]));
|
||||
}
|
||||
|
||||
for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) {
|
||||
printf(" uv[%ld] = (%f, %f)\n", static_cast<long>(v),
|
||||
static_cast<const double>(attrib.texcoords[2*v+0]),
|
||||
static_cast<const double>(attrib.texcoords[2*v+1]));
|
||||
static_cast<const double>(attrib.texcoords[2 * v + 0]),
|
||||
static_cast<const double>(attrib.texcoords[2 * v + 1]));
|
||||
}
|
||||
|
||||
// For each shape
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
printf("shape[%ld].name = %s\n", static_cast<long>(i), shapes[i].name.c_str());
|
||||
printf("Size of shape[%ld].indices: %lu\n", static_cast<long>(i), static_cast<unsigned long>(shapes[i].mesh.indices.size()));
|
||||
printf("shape[%ld].name = %s\n", static_cast<long>(i),
|
||||
shapes[i].name.c_str());
|
||||
printf("Size of shape[%ld].indices: %lu\n", static_cast<long>(i),
|
||||
static_cast<unsigned long>(shapes[i].mesh.indices.size()));
|
||||
|
||||
size_t index_offset = 0;
|
||||
size_t index_offset = 0;
|
||||
|
||||
assert(shapes[i].mesh.num_face_vertices.size() == shapes[i].mesh.material_ids.size());
|
||||
assert(shapes[i].mesh.num_face_vertices.size() ==
|
||||
shapes[i].mesh.material_ids.size());
|
||||
|
||||
printf("shape[%ld].num_faces: %lu\n", static_cast<long>(i), static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size()));
|
||||
printf("shape[%ld].num_faces: %lu\n", static_cast<long>(i),
|
||||
static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size()));
|
||||
|
||||
// For each face
|
||||
// For each face
|
||||
for (size_t f = 0; f < shapes[i].mesh.num_face_vertices.size(); f++) {
|
||||
size_t fnum = shapes[i].mesh.num_face_vertices[f];
|
||||
size_t fnum = shapes[i].mesh.num_face_vertices[f];
|
||||
|
||||
printf(" face[%ld].fnum = %ld\n", static_cast<long>(f), static_cast<unsigned long>(fnum));
|
||||
printf(" face[%ld].fnum = %ld\n", static_cast<long>(f),
|
||||
static_cast<unsigned long>(fnum));
|
||||
|
||||
// For each vertex in the face
|
||||
for (size_t v = 0; v < fnum; v++) {
|
||||
tinyobj::index_t idx = shapes[i].mesh.indices[index_offset + v];
|
||||
printf(" face[%ld].v[%ld].idx = %d/%d/%d\n", static_cast<long>(f), static_cast<long>(v), idx.vertex_index, idx.normal_index, idx.texcoord_index);
|
||||
}
|
||||
// For each vertex in the face
|
||||
for (size_t v = 0; v < fnum; v++) {
|
||||
tinyobj::index_t idx = shapes[i].mesh.indices[index_offset + v];
|
||||
printf(" face[%ld].v[%ld].idx = %d/%d/%d\n", static_cast<long>(f),
|
||||
static_cast<long>(v), idx.vertex_index, idx.normal_index,
|
||||
idx.texcoord_index);
|
||||
}
|
||||
|
||||
printf(" face[%ld].material_id = %d\n", static_cast<long>(f), shapes[i].mesh.material_ids[f]);
|
||||
printf(" face[%ld].material_id = %d\n", static_cast<long>(f),
|
||||
shapes[i].mesh.material_ids[f]);
|
||||
|
||||
index_offset += fnum;
|
||||
index_offset += fnum;
|
||||
}
|
||||
|
||||
printf("shape[%ld].num_tags: %lu\n", static_cast<long>(i), static_cast<unsigned long>(shapes[i].mesh.tags.size()));
|
||||
printf("shape[%ld].num_tags: %lu\n", static_cast<long>(i),
|
||||
static_cast<unsigned long>(shapes[i].mesh.tags.size()));
|
||||
for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) {
|
||||
printf(" tag[%ld] = %s ", static_cast<long>(t), shapes[i].mesh.tags[t].name.c_str());
|
||||
printf(" tag[%ld] = %s ", static_cast<long>(t),
|
||||
shapes[i].mesh.tags[t].name.c_str());
|
||||
printf(" ints: [");
|
||||
for (size_t j = 0; j < shapes[i].mesh.tags[t].intValues.size(); ++j)
|
||||
{
|
||||
printf("%ld", static_cast<long>(shapes[i].mesh.tags[t].intValues[j]));
|
||||
if (j < (shapes[i].mesh.tags[t].intValues.size()-1))
|
||||
{
|
||||
printf(", ");
|
||||
}
|
||||
for (size_t j = 0; j < shapes[i].mesh.tags[t].intValues.size(); ++j) {
|
||||
printf("%ld", static_cast<long>(shapes[i].mesh.tags[t].intValues[j]));
|
||||
if (j < (shapes[i].mesh.tags[t].intValues.size() - 1)) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("]");
|
||||
|
||||
printf(" floats: [");
|
||||
for (size_t j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j)
|
||||
{
|
||||
printf("%f", static_cast<const double>(shapes[i].mesh.tags[t].floatValues[j]));
|
||||
if (j < (shapes[i].mesh.tags[t].floatValues.size()-1))
|
||||
{
|
||||
printf(", ");
|
||||
}
|
||||
for (size_t j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j) {
|
||||
printf("%f", static_cast<const double>(
|
||||
shapes[i].mesh.tags[t].floatValues[j]));
|
||||
if (j < (shapes[i].mesh.tags[t].floatValues.size() - 1)) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("]");
|
||||
|
||||
printf(" strings: [");
|
||||
for (size_t j = 0; j < shapes[i].mesh.tags[t].stringValues.size(); ++j)
|
||||
{
|
||||
printf("%s", shapes[i].mesh.tags[t].stringValues[j].c_str());
|
||||
if (j < (shapes[i].mesh.tags[t].stringValues.size()-1))
|
||||
{
|
||||
printf(", ");
|
||||
}
|
||||
for (size_t j = 0; j < shapes[i].mesh.tags[t].stringValues.size(); ++j) {
|
||||
printf("%s", shapes[i].mesh.tags[t].stringValues[j].c_str());
|
||||
if (j < (shapes[i].mesh.tags[t].stringValues.size() - 1)) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("]");
|
||||
printf("\n");
|
||||
@@ -191,25 +199,60 @@ static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < materials.size(); i++) {
|
||||
printf("material[%ld].name = %s\n", static_cast<long>(i), materials[i].name.c_str());
|
||||
printf(" material.Ka = (%f, %f ,%f)\n", static_cast<const double>(materials[i].ambient[0]), static_cast<const double>(materials[i].ambient[1]), static_cast<const double>(materials[i].ambient[2]));
|
||||
printf(" material.Kd = (%f, %f ,%f)\n", static_cast<const double>(materials[i].diffuse[0]), static_cast<const double>(materials[i].diffuse[1]), static_cast<const double>(materials[i].diffuse[2]));
|
||||
printf(" material.Ks = (%f, %f ,%f)\n", static_cast<const double>(materials[i].specular[0]), static_cast<const double>(materials[i].specular[1]), static_cast<const double>(materials[i].specular[2]));
|
||||
printf(" material.Tr = (%f, %f ,%f)\n", static_cast<const double>(materials[i].transmittance[0]), static_cast<const double>(materials[i].transmittance[1]), static_cast<const double>(materials[i].transmittance[2]));
|
||||
printf(" material.Ke = (%f, %f ,%f)\n", static_cast<const double>(materials[i].emission[0]), static_cast<const double>(materials[i].emission[1]), static_cast<const double>(materials[i].emission[2]));
|
||||
printf(" material.Ns = %f\n", static_cast<const double>(materials[i].shininess));
|
||||
printf("material[%ld].name = %s\n", static_cast<long>(i),
|
||||
materials[i].name.c_str());
|
||||
printf(" material.Ka = (%f, %f ,%f)\n",
|
||||
static_cast<const double>(materials[i].ambient[0]),
|
||||
static_cast<const double>(materials[i].ambient[1]),
|
||||
static_cast<const double>(materials[i].ambient[2]));
|
||||
printf(" material.Kd = (%f, %f ,%f)\n",
|
||||
static_cast<const double>(materials[i].diffuse[0]),
|
||||
static_cast<const double>(materials[i].diffuse[1]),
|
||||
static_cast<const double>(materials[i].diffuse[2]));
|
||||
printf(" material.Ks = (%f, %f ,%f)\n",
|
||||
static_cast<const double>(materials[i].specular[0]),
|
||||
static_cast<const double>(materials[i].specular[1]),
|
||||
static_cast<const double>(materials[i].specular[2]));
|
||||
printf(" material.Tr = (%f, %f ,%f)\n",
|
||||
static_cast<const double>(materials[i].transmittance[0]),
|
||||
static_cast<const double>(materials[i].transmittance[1]),
|
||||
static_cast<const double>(materials[i].transmittance[2]));
|
||||
printf(" material.Ke = (%f, %f ,%f)\n",
|
||||
static_cast<const double>(materials[i].emission[0]),
|
||||
static_cast<const double>(materials[i].emission[1]),
|
||||
static_cast<const double>(materials[i].emission[2]));
|
||||
printf(" material.Ns = %f\n",
|
||||
static_cast<const double>(materials[i].shininess));
|
||||
printf(" material.Ni = %f\n", static_cast<const double>(materials[i].ior));
|
||||
printf(" material.dissolve = %f\n", static_cast<const double>(materials[i].dissolve));
|
||||
printf(" material.illum = %d\n", materials[i].illum);
|
||||
printf(" material.dissolve = %f\n",
|
||||
static_cast<const double>(materials[i].dissolve));
|
||||
printf(" material.illum = %d\n", materials[i].illum);
|
||||
printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
|
||||
printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
|
||||
printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
|
||||
printf(" material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str());
|
||||
printf(" material.map_Ns = %s\n",
|
||||
materials[i].specular_highlight_texname.c_str());
|
||||
printf(" material.map_bump = %s\n", materials[i].bump_texname.c_str());
|
||||
printf(" bump_multiplier = %f\n", static_cast<const double>(materials[i].bump_texopt.bump_multiplier));
|
||||
printf(" material.map_d = %s\n", materials[i].alpha_texname.c_str());
|
||||
printf(" material.disp = %s\n", materials[i].displacement_texname.c_str());
|
||||
std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin());
|
||||
std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end());
|
||||
printf(" <<PBR>>\n");
|
||||
printf(" material.Pr = %f\n", static_cast<const double>(materials[i].roughness));
|
||||
printf(" material.Pm = %f\n", static_cast<const double>(materials[i].metallic));
|
||||
printf(" material.Ps = %f\n", static_cast<const double>(materials[i].sheen));
|
||||
printf(" material.Pc = %f\n", static_cast<const double>(materials[i].clearcoat_thickness));
|
||||
printf(" material.Pcr = %f\n", static_cast<const double>(materials[i].clearcoat_thickness));
|
||||
printf(" material.aniso = %f\n", static_cast<const double>(materials[i].anisotropy));
|
||||
printf(" material.anisor = %f\n", static_cast<const double>(materials[i].anisotropy_rotation));
|
||||
printf(" material.map_Ke = %s\n", materials[i].emissive_texname.c_str());
|
||||
printf(" material.map_Pr = %s\n", materials[i].roughness_texname.c_str());
|
||||
printf(" material.map_Pm = %s\n", materials[i].metallic_texname.c_str());
|
||||
printf(" material.map_Ps = %s\n", materials[i].sheen_texname.c_str());
|
||||
printf(" material.norm = %s\n", materials[i].normal_texname.c_str());
|
||||
std::map<std::string, std::string>::const_iterator it(
|
||||
materials[i].unknown_parameter.begin());
|
||||
std::map<std::string, std::string>::const_iterator itEnd(
|
||||
materials[i].unknown_parameter.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
|
||||
@@ -218,12 +261,8 @@ static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
TestLoadObj(
|
||||
const char* filename,
|
||||
const char* basepath = NULL,
|
||||
bool triangulate = true)
|
||||
{
|
||||
static bool TestLoadObj(const char* filename, const char* basepath = NULL,
|
||||
bool triangulate = true) {
|
||||
std::cout << "Loading " << filename << std::endl;
|
||||
|
||||
tinyobj::attrib_t attrib;
|
||||
@@ -233,7 +272,8 @@ TestLoadObj(
|
||||
timerutil t;
|
||||
t.start();
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, basepath, triangulate);
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename,
|
||||
basepath, triangulate);
|
||||
t.end();
|
||||
printf("Parsing time: %lu [msecs]\n", t.msec());
|
||||
|
||||
@@ -251,102 +291,102 @@ TestLoadObj(
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
TestStreamLoadObj()
|
||||
{
|
||||
static bool TestStreamLoadObj() {
|
||||
std::cout << "Stream Loading " << std::endl;
|
||||
|
||||
std::stringstream objStream;
|
||||
objStream
|
||||
<< "mtllib cube.mtl\n"
|
||||
"\n"
|
||||
"v 0.000000 2.000000 2.000000\n"
|
||||
"v 0.000000 0.000000 2.000000\n"
|
||||
"v 2.000000 0.000000 2.000000\n"
|
||||
"v 2.000000 2.000000 2.000000\n"
|
||||
"v 0.000000 2.000000 0.000000\n"
|
||||
"v 0.000000 0.000000 0.000000\n"
|
||||
"v 2.000000 0.000000 0.000000\n"
|
||||
"v 2.000000 2.000000 0.000000\n"
|
||||
"# 8 vertices\n"
|
||||
"\n"
|
||||
"g front cube\n"
|
||||
"usemtl white\n"
|
||||
"f 1 2 3 4\n"
|
||||
"g back cube\n"
|
||||
"# expects white material\n"
|
||||
"f 8 7 6 5\n"
|
||||
"g right cube\n"
|
||||
"usemtl red\n"
|
||||
"f 4 3 7 8\n"
|
||||
"g top cube\n"
|
||||
"usemtl white\n"
|
||||
"f 5 1 4 8\n"
|
||||
"g left cube\n"
|
||||
"usemtl green\n"
|
||||
"f 5 6 2 1\n"
|
||||
"g bottom cube\n"
|
||||
"usemtl white\n"
|
||||
"f 2 6 7 3\n"
|
||||
"# 6 elements";
|
||||
objStream << "mtllib cube.mtl\n"
|
||||
"\n"
|
||||
"v 0.000000 2.000000 2.000000\n"
|
||||
"v 0.000000 0.000000 2.000000\n"
|
||||
"v 2.000000 0.000000 2.000000\n"
|
||||
"v 2.000000 2.000000 2.000000\n"
|
||||
"v 0.000000 2.000000 0.000000\n"
|
||||
"v 0.000000 0.000000 0.000000\n"
|
||||
"v 2.000000 0.000000 0.000000\n"
|
||||
"v 2.000000 2.000000 0.000000\n"
|
||||
"# 8 vertices\n"
|
||||
"\n"
|
||||
"g front cube\n"
|
||||
"usemtl white\n"
|
||||
"f 1 2 3 4\n"
|
||||
"g back cube\n"
|
||||
"# expects white material\n"
|
||||
"f 8 7 6 5\n"
|
||||
"g right cube\n"
|
||||
"usemtl red\n"
|
||||
"f 4 3 7 8\n"
|
||||
"g top cube\n"
|
||||
"usemtl white\n"
|
||||
"f 5 1 4 8\n"
|
||||
"g left cube\n"
|
||||
"usemtl green\n"
|
||||
"f 5 6 2 1\n"
|
||||
"g bottom cube\n"
|
||||
"usemtl white\n"
|
||||
"f 2 6 7 3\n"
|
||||
"# 6 elements";
|
||||
|
||||
std::string matStream(
|
||||
"newmtl white\n"
|
||||
"Ka 0 0 0\n"
|
||||
"Kd 1 1 1\n"
|
||||
"Ks 0 0 0\n"
|
||||
"\n"
|
||||
"newmtl red\n"
|
||||
"Ka 0 0 0\n"
|
||||
"Kd 1 0 0\n"
|
||||
"Ks 0 0 0\n"
|
||||
"\n"
|
||||
"newmtl green\n"
|
||||
"Ka 0 0 0\n"
|
||||
"Kd 0 1 0\n"
|
||||
"Ks 0 0 0\n"
|
||||
"\n"
|
||||
"newmtl blue\n"
|
||||
"Ka 0 0 0\n"
|
||||
"Kd 0 0 1\n"
|
||||
"Ks 0 0 0\n"
|
||||
"\n"
|
||||
"newmtl light\n"
|
||||
"Ka 20 20 20\n"
|
||||
"Kd 1 1 1\n"
|
||||
"Ks 0 0 0");
|
||||
std::string matStream(
|
||||
"newmtl white\n"
|
||||
"Ka 0 0 0\n"
|
||||
"Kd 1 1 1\n"
|
||||
"Ks 0 0 0\n"
|
||||
"\n"
|
||||
"newmtl red\n"
|
||||
"Ka 0 0 0\n"
|
||||
"Kd 1 0 0\n"
|
||||
"Ks 0 0 0\n"
|
||||
"\n"
|
||||
"newmtl green\n"
|
||||
"Ka 0 0 0\n"
|
||||
"Kd 0 1 0\n"
|
||||
"Ks 0 0 0\n"
|
||||
"\n"
|
||||
"newmtl blue\n"
|
||||
"Ka 0 0 0\n"
|
||||
"Kd 0 0 1\n"
|
||||
"Ks 0 0 0\n"
|
||||
"\n"
|
||||
"newmtl light\n"
|
||||
"Ka 20 20 20\n"
|
||||
"Kd 1 1 1\n"
|
||||
"Ks 0 0 0");
|
||||
|
||||
using namespace tinyobj;
|
||||
class MaterialStringStreamReader:
|
||||
public MaterialReader
|
||||
{
|
||||
public:
|
||||
MaterialStringStreamReader(const std::string& matSStream): m_matSStream(matSStream) {}
|
||||
virtual ~MaterialStringStreamReader() {}
|
||||
virtual bool operator() (
|
||||
const std::string& matId,
|
||||
std::vector<material_t>* materials,
|
||||
std::map<std::string, int>* matMap,
|
||||
std::string* err)
|
||||
{
|
||||
(void)matId;
|
||||
(void)err;
|
||||
LoadMtl(matMap, materials, &m_matSStream);
|
||||
return true;
|
||||
}
|
||||
using namespace tinyobj;
|
||||
class MaterialStringStreamReader : public MaterialReader {
|
||||
public:
|
||||
MaterialStringStreamReader(const std::string& matSStream)
|
||||
: m_matSStream(matSStream) {}
|
||||
virtual ~MaterialStringStreamReader() {}
|
||||
virtual bool operator()(const std::string& matId,
|
||||
std::vector<material_t>* materials,
|
||||
std::map<std::string, int>* matMap,
|
||||
std::string* err) {
|
||||
(void)matId;
|
||||
std::string warning;
|
||||
LoadMtl(matMap, materials, &m_matSStream, &warning);
|
||||
|
||||
private:
|
||||
std::stringstream m_matSStream;
|
||||
};
|
||||
if (!warning.empty()) {
|
||||
if (err) {
|
||||
(*err) += warning;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::stringstream m_matSStream;
|
||||
};
|
||||
|
||||
MaterialStringStreamReader matSSReader(matStream);
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, &objStream, &matSSReader);
|
||||
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, &objStream,
|
||||
&matSSReader);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
@@ -356,15 +396,11 @@ std::string matStream(
|
||||
}
|
||||
|
||||
PrintInfo(attrib, shapes, materials);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
int main(int argc, char** argv) {
|
||||
if (argc > 1) {
|
||||
const char* basepath = "models/";
|
||||
if (argc > 2) {
|
||||
@@ -372,10 +408,11 @@ main(
|
||||
}
|
||||
assert(true == TestLoadObj(argv[1], basepath));
|
||||
} else {
|
||||
//assert(true == TestLoadObj("cornell_box.obj"));
|
||||
//assert(true == TestLoadObj("cube.obj"));
|
||||
// assert(true == TestLoadObj("cornell_box.obj"));
|
||||
// assert(true == TestLoadObj("cube.obj"));
|
||||
assert(true == TestStreamLoadObj());
|
||||
assert(true == TestLoadObj("models/catmark_torus_creases0.obj", "models/", false));
|
||||
assert(true ==
|
||||
TestLoadObj("models/catmark_torus_creases0.obj", "models/", false));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
6
models/issue-92.mtl
Normal file
6
models/issue-92.mtl
Normal file
@@ -0,0 +1,6 @@
|
||||
newmtl default
|
||||
Ka 0 0 0
|
||||
Kd 0 0 0
|
||||
Ks 0 0 0
|
||||
map_Kd tmp.png
|
||||
|
||||
7
models/issue-92.obj
Normal file
7
models/issue-92.obj
Normal file
@@ -0,0 +1,7 @@
|
||||
mtllib issue-92.mtl
|
||||
o Test
|
||||
v 1.864151 -1.219172 -5.532511
|
||||
v 0.575869 -0.666304 5.896140
|
||||
v 0.940448 1.000000 -1.971128
|
||||
usemtl default
|
||||
f 1 2 3
|
||||
5
models/issue-95-2.mtl
Normal file
5
models/issue-95-2.mtl
Normal file
@@ -0,0 +1,5 @@
|
||||
newmtl default
|
||||
Ka 0 0 0
|
||||
Kd 0 0 0
|
||||
Ks 0 0 0
|
||||
Tf 0.1 0.2 0.3
|
||||
7
models/issue-95-2.obj
Normal file
7
models/issue-95-2.obj
Normal file
@@ -0,0 +1,7 @@
|
||||
mtllib issue-95-2.mtl
|
||||
o Test
|
||||
v 1.864151 -1.219172 -5.532511
|
||||
v 0.575869 -0.666304 5.896140
|
||||
v 0.940448 1.000000 -1.971128
|
||||
usemtl default
|
||||
f 1 2 3
|
||||
5
models/issue-95.mtl
Normal file
5
models/issue-95.mtl
Normal file
@@ -0,0 +1,5 @@
|
||||
newmtl default
|
||||
Ka 0 0 0
|
||||
Kd 0 0 0
|
||||
Ks 0 0 0
|
||||
Kt 0.1 0.2 0.3
|
||||
7
models/issue-95.obj
Normal file
7
models/issue-95.obj
Normal file
@@ -0,0 +1,7 @@
|
||||
mtllib issue-95.mtl
|
||||
o Test
|
||||
v 1.864151 -1.219172 -5.532511
|
||||
v 0.575869 -0.666304 5.896140
|
||||
v 0.940448 1.000000 -1.971128
|
||||
usemtl default
|
||||
f 1 2 3
|
||||
6
models/mtllib-multiple-files-issue-112.mtl
Normal file
6
models/mtllib-multiple-files-issue-112.mtl
Normal file
@@ -0,0 +1,6 @@
|
||||
newmtl default
|
||||
Ka 0 0 0
|
||||
Kd 0 0 0
|
||||
Ks 0 0 0
|
||||
map_Kd tmp.png
|
||||
|
||||
7
models/mtllib-multiple-files-issue-112.obj
Normal file
7
models/mtllib-multiple-files-issue-112.obj
Normal file
@@ -0,0 +1,7 @@
|
||||
mtllib invalid-file-aaa.mtl invalid-file-bbb.mtl mtllib-multiple-files-issue-112.mtl
|
||||
o Test
|
||||
v 1.864151 -1.219172 -5.532511
|
||||
v 0.575869 -0.666304 5.896140
|
||||
v 0.940448 1.000000 -1.971128
|
||||
usemtl default
|
||||
f 1 2 3
|
||||
19
models/pbr-mat-ext.mtl
Normal file
19
models/pbr-mat-ext.mtl
Normal file
@@ -0,0 +1,19 @@
|
||||
# .MTL with PBR extension.
|
||||
newmtl pbr
|
||||
Ka 0 0 0
|
||||
Kd 1 1 1
|
||||
Ks 0 0 0
|
||||
Ke 0.1 0.1 0.1
|
||||
Pr 0.2
|
||||
Pm 0.3
|
||||
Ps 0.4
|
||||
Pc 0.5
|
||||
Pcr 0.6
|
||||
aniso 0.7
|
||||
anisor 0.8
|
||||
map_Pr roughness.tex
|
||||
map_Pm metallic.tex
|
||||
map_Ps sheen.tex
|
||||
map_Ke emissive.tex
|
||||
norm normalmap.tex
|
||||
|
||||
10
models/pbr-mat-ext.obj
Normal file
10
models/pbr-mat-ext.obj
Normal file
@@ -0,0 +1,10 @@
|
||||
mtllib pbr-mat-ext.mtl
|
||||
|
||||
o floor
|
||||
usemtl pbr
|
||||
v 552.8 0.0 0.0
|
||||
v 0.0 0.0 0.0
|
||||
v 0.0 0.0 559.2
|
||||
v 549.6 0.0 559.2
|
||||
|
||||
f 1 2 3 4
|
||||
36
models/texture-options-issue-85.mtl
Normal file
36
models/texture-options-issue-85.mtl
Normal file
@@ -0,0 +1,36 @@
|
||||
newmtl default
|
||||
Ka 0 0 0
|
||||
Kd 0 0 0
|
||||
Ks 0 0 0
|
||||
Kt 0.1 0.2 0.3
|
||||
map_Ka -clamp on ambient.jpg
|
||||
map_Kd -o 0.1 diffuse.jpg
|
||||
map_Ks -s 0.1 0.2 specular.jpg
|
||||
map_Ns -t 0.1 0.2 0.3 specular_highlight.jpg
|
||||
map_bump -bm 3 bumpmap.jpg
|
||||
|
||||
newmtl bm2
|
||||
Ka 0 0 0
|
||||
Kd 0 0 0
|
||||
Ks 0 0 0
|
||||
Kt 0.1 0.2 0.3
|
||||
# blendu
|
||||
map_Kd -blendu on diffuse.jpg
|
||||
map_Ks -blendv off specular.jpg
|
||||
map_Ns -mm 0.1 0.3 specular_highlight.jpg
|
||||
# -bm after filename
|
||||
map_bump -imfchan r bumpmap2.jpg -bm 1.5
|
||||
|
||||
newmtl bm3
|
||||
Ka 0 0 0
|
||||
Kd 0 0 0
|
||||
Ks 0 0 0
|
||||
Kt 0.1 0.2 0.3
|
||||
# type
|
||||
map_Kd -type sphere diffuse.jpg
|
||||
map_Ks -type cube_top specular.jpg
|
||||
map_Ns -type cube_bottom specular_highlight.jpg
|
||||
map_Ka -type cube_left ambient.jpg
|
||||
map_d -type cube_right alpha.jpg
|
||||
map_bump -type cube_front bump.jpg
|
||||
disp -type cube_back displacement.jpg
|
||||
7
models/texture-options-issue-85.obj
Normal file
7
models/texture-options-issue-85.obj
Normal file
@@ -0,0 +1,7 @@
|
||||
mtllib texture-options-issue-85.mtl
|
||||
o Test
|
||||
v 1.864151 -1.219172 -5.532511
|
||||
v 0.575869 -0.666304 5.896140
|
||||
v 0.940448 1.000000 -1.971128
|
||||
usemtl default
|
||||
f 1 2 3
|
||||
13
models/tr-and-d-issue-43.mtl
Normal file
13
models/tr-and-d-issue-43.mtl
Normal file
@@ -0,0 +1,13 @@
|
||||
newmtl Material.001
|
||||
Ka 0 0 0
|
||||
Kd 0 0 0
|
||||
Ks 0 0 0
|
||||
d 0.75
|
||||
Tr 0.5
|
||||
|
||||
newmtl Material.002
|
||||
Ka 0 0 0
|
||||
Kd 0 0 0
|
||||
Ks 0 0 0
|
||||
Tr 0.5
|
||||
d 0.75
|
||||
817
models/tr-and-d-issue-43.obj
Normal file
817
models/tr-and-d-issue-43.obj
Normal file
@@ -0,0 +1,817 @@
|
||||
# https://github.com/syoyo/tinyobjloader/issues/68
|
||||
# Blender v2.73 (sub 0) OBJ File: 'enemy.blend'
|
||||
# www.blender.org
|
||||
mtllib tr-and-d-issue-43.mtl
|
||||
o Cube
|
||||
v 1.864151 -1.219172 -5.532511
|
||||
v 0.575869 -0.666304 5.896140
|
||||
v 0.940448 1.000000 -1.971128
|
||||
v 1.620345 1.000000 -5.815706
|
||||
v 1.864152 1.000000 -6.334323
|
||||
v 0.575869 -0.129842 5.896143
|
||||
v 5.440438 -1.462153 -5.818601
|
||||
v 4.896782 -1.462153 -2.744413
|
||||
v 1.000825 -0.677484 1.899605
|
||||
v 5.440438 -1.246362 -5.818600
|
||||
v 1.000825 0.852342 1.899608
|
||||
v 4.896782 -1.246362 -2.744412
|
||||
v 1.160660 -0.450871 -2.356325
|
||||
v 1.704316 -0.450871 -5.430513
|
||||
v 1.000825 -0.351920 -1.293797
|
||||
v 1.000825 1.000000 -1.293794
|
||||
v 1.160660 -0.877888 -2.356326
|
||||
v 1.704316 -0.877888 -5.430514
|
||||
v 1.000825 -1.219172 -1.452514
|
||||
v 1.000825 1.000000 -1.452511
|
||||
v 1.000825 -0.351920 1.759410
|
||||
v 1.000825 1.000000 1.759413
|
||||
v 9.097919 1.221145 -6.212147
|
||||
v 8.356775 1.221145 -2.021231
|
||||
v 1.864151 -0.109586 -6.334325
|
||||
v 0.575869 -0.398073 5.896141
|
||||
v 9.097919 0.943958 -6.212148
|
||||
v 8.356775 0.943958 -2.021233
|
||||
v 1.061916 0.113661 -1.797961
|
||||
v 1.000825 0.161258 1.899606
|
||||
v 1.000825 0.324040 -1.293795
|
||||
v 1.803060 0.113661 -5.988876
|
||||
v 1.000825 -0.109586 -1.452513
|
||||
v 1.061916 0.776753 -1.797960
|
||||
v 1.803061 0.776753 -5.988875
|
||||
v 1.000825 0.324040 1.759412
|
||||
v 0.000825 -1.219172 -5.532512
|
||||
v 0.000825 -0.666304 5.896139
|
||||
v 0.000826 1.000000 -6.334325
|
||||
v 0.000825 -0.129842 5.896140
|
||||
v 0.000825 0.852342 1.899606
|
||||
v 0.000825 -0.677484 1.899604
|
||||
v 0.000825 -0.351920 -1.293797
|
||||
v 0.000825 1.000000 -1.293796
|
||||
v 0.000825 1.000000 -1.452513
|
||||
v 0.000825 -1.219172 -1.452515
|
||||
v 0.000825 -0.351920 1.759409
|
||||
v 0.000825 1.000000 1.759411
|
||||
v 0.000826 -0.109586 -6.334326
|
||||
v 0.000825 -0.398073 5.896140
|
||||
v 0.152918 1.000000 -5.815708
|
||||
v 0.152917 1.000000 -1.971130
|
||||
v 0.940448 1.168419 -1.971128
|
||||
v 1.620345 1.168419 -5.815706
|
||||
v 0.152918 1.168419 -5.815708
|
||||
v 0.152917 1.168419 -1.971130
|
||||
v 0.921118 1.091883 -1.050430
|
||||
v 0.921118 1.091883 1.516050
|
||||
v 0.080533 1.091883 -1.050432
|
||||
v 0.080533 1.091883 1.516048
|
||||
v 0.613003 -0.553430 5.546911
|
||||
v 0.963691 -0.559956 2.248834
|
||||
v 0.613003 -0.396857 5.546912
|
||||
v 0.963691 -0.070362 2.248835
|
||||
v 1.499370 -0.994317 3.966028
|
||||
v 1.850058 -0.997914 0.667950
|
||||
v 1.499370 -0.908021 3.966029
|
||||
v 1.850058 -0.728071 0.667951
|
||||
v 1.601022 0.760960 -6.334324
|
||||
v 1.601021 0.129454 -6.334325
|
||||
v 0.263955 0.760960 -6.334325
|
||||
v 0.263955 0.129454 -6.334325
|
||||
v 1.334809 0.760960 -7.515329
|
||||
v 1.334809 0.129455 -7.515330
|
||||
v 0.530168 0.760960 -7.515330
|
||||
v 0.530168 0.129455 -7.515330
|
||||
v 1.192720 0.649445 -7.515329
|
||||
v 1.192720 0.240971 -7.515330
|
||||
v 0.672258 0.649445 -7.515330
|
||||
v 0.672258 0.240971 -7.515330
|
||||
v 1.192719 0.649444 -6.524630
|
||||
v 1.192719 0.240970 -6.524631
|
||||
v 0.672257 0.649444 -6.524631
|
||||
v 0.672257 0.240970 -6.524631
|
||||
v 3.851026 0.431116 -1.883326
|
||||
v 3.851026 0.946662 -1.883325
|
||||
v 4.592170 0.946662 -6.074241
|
||||
v 4.592169 0.431116 -6.074242
|
||||
v 4.995714 0.561404 -1.918362
|
||||
v 4.995714 1.016394 -1.918360
|
||||
v 5.736857 1.016394 -6.109276
|
||||
v 5.736857 0.561404 -6.109277
|
||||
v 3.975454 0.471731 -2.162156
|
||||
v 3.975454 0.919244 -2.162155
|
||||
v 4.618796 0.919244 -5.800034
|
||||
v 4.618795 0.471730 -5.800035
|
||||
v 4.969088 0.584825 -2.192568
|
||||
v 4.969088 0.979775 -2.192567
|
||||
v 5.612430 0.979775 -5.830446
|
||||
v 5.612429 0.584825 -5.830447
|
||||
v 0.864214 -0.673890 3.184381
|
||||
v 0.864213 0.489129 3.184384
|
||||
v 0.864213 -0.018552 3.184383
|
||||
v 0.000825 0.489129 3.184382
|
||||
v 0.000825 -0.673890 3.184381
|
||||
v 0.850955 -0.557858 3.309075
|
||||
v 0.850955 -0.175321 3.309076
|
||||
v 1.737321 -0.996758 1.728192
|
||||
v 1.737321 -0.785920 1.728193
|
||||
v -1.864151 -1.219172 -5.532511
|
||||
v -0.575869 -0.666304 5.896140
|
||||
v -0.940448 1.000000 -1.971128
|
||||
v -1.620345 1.000000 -5.815706
|
||||
v -1.864152 1.000000 -6.334323
|
||||
v -0.575869 -0.129842 5.896143
|
||||
v -5.440438 -1.462153 -5.818601
|
||||
v -4.896782 -1.462153 -2.744413
|
||||
v -1.000825 -0.677484 1.899605
|
||||
v -5.440438 -1.246362 -5.818600
|
||||
v -1.000825 0.852342 1.899608
|
||||
v -4.896782 -1.246362 -2.744412
|
||||
v -1.160660 -0.450871 -2.356325
|
||||
v -1.704316 -0.450871 -5.430513
|
||||
v -1.000825 -0.351920 -1.293797
|
||||
v -1.000825 1.000000 -1.293794
|
||||
v -1.160660 -0.877888 -2.356326
|
||||
v -1.704316 -0.877888 -5.430514
|
||||
v -1.000825 -1.219172 -1.452514
|
||||
v -1.000825 1.000000 -1.452511
|
||||
v -1.000825 -0.351920 1.759410
|
||||
v -1.000825 1.000000 1.759413
|
||||
v -9.097919 1.221145 -6.212147
|
||||
v -8.356775 1.221145 -2.021231
|
||||
v -1.864151 -0.109586 -6.334325
|
||||
v -0.575869 -0.398073 5.896141
|
||||
v -9.097919 0.943958 -6.212148
|
||||
v -8.356775 0.943958 -2.021233
|
||||
v -1.061916 0.113661 -1.797961
|
||||
v -1.000825 0.161258 1.899606
|
||||
v -1.000825 0.324040 -1.293795
|
||||
v -1.803060 0.113661 -5.988876
|
||||
v -1.000825 -0.109586 -1.452513
|
||||
v -1.061916 0.776753 -1.797960
|
||||
v -1.803061 0.776753 -5.988875
|
||||
v -1.000825 0.324040 1.759412
|
||||
v -0.000825 -1.219172 -5.532512
|
||||
v -0.000825 -0.666304 5.896139
|
||||
v -0.000826 1.000000 -6.334325
|
||||
v -0.000825 -0.129842 5.896140
|
||||
v -0.000825 0.852342 1.899606
|
||||
v -0.000825 -0.677484 1.899604
|
||||
v -0.000825 -0.351920 -1.293797
|
||||
v -0.000825 1.000000 -1.293796
|
||||
v -0.000825 1.000000 -1.452513
|
||||
v -0.000825 -1.219172 -1.452515
|
||||
v -0.000825 -0.351920 1.759409
|
||||
v -0.000825 1.000000 1.759411
|
||||
v -0.000826 -0.109586 -6.334326
|
||||
v -0.000825 -0.398073 5.896140
|
||||
v -0.152918 1.000000 -5.815708
|
||||
v -0.152917 1.000000 -1.971130
|
||||
v -0.940448 1.168419 -1.971128
|
||||
v -1.620345 1.168419 -5.815706
|
||||
v -0.152918 1.168419 -5.815708
|
||||
v -0.152917 1.168419 -1.971130
|
||||
v -0.921118 1.091883 -1.050430
|
||||
v -0.921118 1.091883 1.516050
|
||||
v -0.080533 1.091883 -1.050432
|
||||
v -0.080533 1.091883 1.516048
|
||||
v -0.613003 -0.553430 5.546911
|
||||
v -0.963691 -0.559956 2.248834
|
||||
v -0.613003 -0.396857 5.546912
|
||||
v -0.963691 -0.070362 2.248835
|
||||
v -1.499370 -0.994317 3.966028
|
||||
v -1.850058 -0.997914 0.667950
|
||||
v -1.499370 -0.908021 3.966029
|
||||
v -1.850058 -0.728071 0.667951
|
||||
v -1.601022 0.760960 -6.334324
|
||||
v -1.601021 0.129454 -6.334325
|
||||
v -0.263955 0.760960 -6.334325
|
||||
v -0.263955 0.129454 -6.334325
|
||||
v -1.334809 0.760960 -7.515329
|
||||
v -1.334809 0.129455 -7.515330
|
||||
v -0.530168 0.760960 -7.515330
|
||||
v -0.530168 0.129455 -7.515330
|
||||
v -1.192720 0.649445 -7.515329
|
||||
v -1.192720 0.240971 -7.515330
|
||||
v -0.672258 0.649445 -7.515330
|
||||
v -0.672258 0.240971 -7.515330
|
||||
v -1.192719 0.649444 -6.524630
|
||||
v -1.192719 0.240970 -6.524631
|
||||
v -0.672257 0.649444 -6.524631
|
||||
v -0.672257 0.240970 -6.524631
|
||||
v -3.851026 0.431116 -1.883326
|
||||
v -3.851026 0.946662 -1.883325
|
||||
v -4.592170 0.946662 -6.074241
|
||||
v -4.592169 0.431116 -6.074242
|
||||
v -4.995714 0.561404 -1.918362
|
||||
v -4.995714 1.016394 -1.918360
|
||||
v -5.736857 1.016394 -6.109276
|
||||
v -5.736857 0.561404 -6.109277
|
||||
v -3.975454 0.471731 -2.162156
|
||||
v -3.975454 0.919244 -2.162155
|
||||
v -4.618796 0.919244 -5.800034
|
||||
v -4.618795 0.471730 -5.800035
|
||||
v -4.969088 0.584825 -2.192568
|
||||
v -4.969088 0.979775 -2.192567
|
||||
v -5.612430 0.979775 -5.830446
|
||||
v -5.612429 0.584825 -5.830447
|
||||
v -0.864214 -0.673890 3.184381
|
||||
v -0.864213 0.489129 3.184384
|
||||
v -0.864213 -0.018552 3.184383
|
||||
v -0.000825 0.489129 3.184382
|
||||
v -0.000825 -0.673890 3.184381
|
||||
v -0.850955 -0.557858 3.309075
|
||||
v -0.850955 -0.175321 3.309076
|
||||
v -1.737321 -0.996758 1.728192
|
||||
v -1.737321 -0.785920 1.728193
|
||||
vt 0.135351 -0.558072
|
||||
vt 0.003035 -0.363507
|
||||
vt 0.092282 -0.976844
|
||||
vt -0.081322 0.947351
|
||||
vt 0.100058 1.958891
|
||||
vt 0.050091 1.852185
|
||||
vt -0.092752 1.055565
|
||||
vt -0.251711 1.059474
|
||||
vt 0.075587 0.041384
|
||||
vt -0.086008 0.279003
|
||||
vt -0.086212 0.249830
|
||||
vt -0.276044 1.968137
|
||||
vt -0.246101 1.859467
|
||||
vt 0.009828 1.911388
|
||||
vt -0.133014 1.114769
|
||||
vt 0.413322 1.261595
|
||||
vt 0.299103 0.624605
|
||||
vt 1.243955 0.407183
|
||||
vt 0.515404 1.111487
|
||||
vt 1.358173 1.044173
|
||||
vt -0.081553 0.914324
|
||||
vt 0.080042 0.676706
|
||||
vt 0.401185 0.474498
|
||||
vt 1.295541 0.331328
|
||||
vt 0.365315 1.568841
|
||||
vt 0.299111 1.575740
|
||||
vt 0.143401 0.707357
|
||||
vt 0.629403 1.011947
|
||||
vt 0.449192 0.167251
|
||||
vt 1.409760 0.968317
|
||||
vt 0.986264 1.738667
|
||||
vt 1.573373 1.877873
|
||||
vt 1.417663 1.009490
|
||||
vt 0.237182 -0.196235
|
||||
vt 0.721785 1.030226
|
||||
vt 0.830554 0.870285
|
||||
vt 0.877494 1.898608
|
||||
vt 1.351399 1.106930
|
||||
vt 0.183935 0.557301
|
||||
vt 1.507109 1.975312
|
||||
vt 0.241636 0.439088
|
||||
vt 0.114297 -0.045011
|
||||
vt 0.140593 1.808834
|
||||
vt -0.015118 0.940452
|
||||
vt 0.156405 -1.071134
|
||||
vt 0.164119 -0.998223
|
||||
vt 0.040336 -1.068281
|
||||
vt 0.104459 -1.162571
|
||||
vt -0.165787 1.882802
|
||||
vt -0.014821 1.660811
|
||||
vt -0.287852 0.283965
|
||||
vt -0.293374 0.366508
|
||||
vt -0.289630 0.900550
|
||||
vt 0.035337 -0.191272
|
||||
vt 0.247348 0.172213
|
||||
vt 0.253300 1.021193
|
||||
vt -0.283166 0.952313
|
||||
vt -0.283398 0.919286
|
||||
vt 0.039792 0.444050
|
||||
vt 0.314806 -0.339851
|
||||
vt 0.112962 -0.334889
|
||||
vt -0.288056 0.254793
|
||||
vt -0.023788 -0.973990
|
||||
vt -0.155922 -0.359599
|
||||
vt 0.220528 -1.165425
|
||||
vt 0.108710 -0.748730
|
||||
vt -0.286364 1.918670
|
||||
vt -0.291973 1.118678
|
||||
vt -0.119962 0.896379
|
||||
vt -0.123707 0.362337
|
||||
vt 0.162891 -0.598569
|
||||
vt 0.467532 -0.853353
|
||||
vt 0.201549 -1.053262
|
||||
vt 0.161663 -0.198915
|
||||
vt 0.267667 -0.752638
|
||||
vt 0.278705 -0.371021
|
||||
vt 0.526390 -0.542053
|
||||
vt 0.483821 -0.479457
|
||||
vt 0.488162 -0.883689
|
||||
vt 0.500110 -0.105561
|
||||
vt 0.564618 -0.200418
|
||||
vt -0.110331 2.127229
|
||||
vt 0.040636 1.905238
|
||||
vt -0.010786 1.578087
|
||||
vt 0.104092 1.876168
|
||||
vt 0.255058 1.654176
|
||||
vt -0.054992 2.087323
|
||||
vt 0.203048 1.901245
|
||||
vt 0.052081 2.123235
|
||||
vt 0.042658 1.943733
|
||||
vt -0.056437 1.881175
|
||||
vt 0.147710 1.941151
|
||||
vt 0.050060 2.084741
|
||||
vt 0.146264 1.735002
|
||||
vt 0.041212 1.737584
|
||||
vt 0.048615 1.878591
|
||||
vt 0.663065 1.872485
|
||||
vt 0.786311 1.691257
|
||||
vt 0.507355 1.004102
|
||||
vt 0.630601 0.822874
|
||||
vt 0.955144 1.689498
|
||||
vt 0.860727 1.828333
|
||||
vt 0.725565 1.074543
|
||||
vt 0.819981 0.935708
|
||||
vt 0.674594 1.805657
|
||||
vt 0.539432 1.051867
|
||||
vt 0.646413 0.894554
|
||||
vt 0.781576 1.648344
|
||||
vt 0.240127 -0.712141
|
||||
vn 0.994400 0.000000 0.105700
|
||||
vn 0.000000 1.000000 0.000000
|
||||
vn 1.000000 0.000000 0.000000
|
||||
vn 0.984700 0.000000 0.174100
|
||||
vn 0.211800 0.976600 0.037500
|
||||
vn -0.103300 0.000000 -0.994600
|
||||
vn 0.103300 -0.000000 0.994600
|
||||
vn 0.911400 0.378700 0.161200
|
||||
vn -0.157300 -0.987200 -0.027800
|
||||
vn 0.113700 -0.993300 0.020100
|
||||
vn 0.030600 -0.000000 0.999500
|
||||
vn -0.061100 0.998100 -0.010800
|
||||
vn -0.030600 0.000000 -0.999500
|
||||
vn -0.000000 -0.000000 1.000000
|
||||
vn 0.000000 0.000000 -1.000000
|
||||
vn -0.755400 0.655300 0.000000
|
||||
vn 0.000000 -1.000000 0.000000
|
||||
vn -0.000000 -0.180000 0.983700
|
||||
vn 0.000000 -0.395500 -0.918500
|
||||
vn -0.000000 0.688500 0.725200
|
||||
vn 0.000000 -0.585700 -0.810500
|
||||
vn -0.000000 0.974900 0.222500
|
||||
vn -0.000000 -1.000000 0.002800
|
||||
vn -1.000000 0.000000 -0.000000
|
||||
vn -0.000000 0.935500 0.353200
|
||||
vn 0.755400 0.655300 0.000000
|
||||
vn 0.000000 0.935500 -0.353200
|
||||
vn 0.673800 0.724900 0.143400
|
||||
vn 0.872300 -0.000000 0.489100
|
||||
vn -0.872300 0.000000 -0.489100
|
||||
vn -0.518300 -0.853500 -0.054200
|
||||
vn -0.975500 0.000000 -0.219900
|
||||
vn 0.975500 0.000000 -0.219900
|
||||
vn -0.913200 0.000000 -0.407500
|
||||
vn -0.436900 0.896200 -0.077300
|
||||
vn -0.995300 -0.000000 0.096600
|
||||
vn -0.297300 -0.953400 -0.052600
|
||||
vn 0.473900 -0.876600 0.083800
|
||||
vn 0.913200 0.000000 0.407500
|
||||
vn 0.342200 0.937700 0.060500
|
||||
vn 0.995300 -0.000000 -0.096600
|
||||
vn -0.519200 -0.853000 -0.054300
|
||||
vn 0.722400 0.676400 0.143800
|
||||
vn -0.994400 0.000000 0.105700
|
||||
vn -0.984700 0.000000 0.174100
|
||||
vn -0.211800 0.976600 0.037500
|
||||
vn 0.103300 0.000000 -0.994600
|
||||
vn -0.103300 -0.000000 0.994600
|
||||
vn -0.911400 0.378700 0.161200
|
||||
vn 0.157300 -0.987200 -0.027800
|
||||
vn -0.113700 -0.993300 0.020100
|
||||
vn -0.030600 -0.000000 0.999500
|
||||
vn 0.061100 0.998100 -0.010800
|
||||
vn 0.030600 0.000000 -0.999500
|
||||
vn -0.691900 0.713200 0.112500
|
||||
vn -0.872300 -0.000000 0.489100
|
||||
vn 0.872300 0.000000 -0.489100
|
||||
vn 0.518300 -0.853500 -0.054200
|
||||
vn 0.913200 0.000000 -0.407500
|
||||
vn 0.436900 0.896200 -0.077300
|
||||
vn 0.995300 0.000000 0.096600
|
||||
vn 0.297300 -0.953300 -0.052600
|
||||
vn -0.473900 -0.876600 0.083800
|
||||
vn -0.913200 -0.000000 0.407500
|
||||
vn -0.342200 0.937700 0.060500
|
||||
vn -0.995300 -0.000000 -0.096600
|
||||
vn 0.519200 -0.853000 -0.054300
|
||||
vn -0.714800 0.690100 0.113700
|
||||
vn 0.974400 0.089700 0.206200
|
||||
vn 0.870400 0.288400 0.399100
|
||||
vn 0.691900 0.713200 0.112500
|
||||
vn -0.518000 -0.853700 -0.053400
|
||||
vn -0.519700 -0.852700 -0.053600
|
||||
vn 0.714800 0.690100 0.113700
|
||||
vn -0.974400 0.089700 0.206200
|
||||
vn -0.870400 0.288400 0.399100
|
||||
vn -0.673800 0.724900 0.143400
|
||||
vn 0.518000 -0.853700 -0.053400
|
||||
vn 0.297300 -0.953400 -0.052600
|
||||
vn 0.519700 -0.852700 -0.053600
|
||||
vn -0.722400 0.676400 0.143800
|
||||
vn -0.000000 0.962300 0.272000
|
||||
usemtl Material.001
|
||||
s off
|
||||
f 103/1/1 102/2/1 6/3/1
|
||||
f 20/4/2 5/5/2 4/6/2
|
||||
f 20/4/2 3/7/2 52/8/2
|
||||
f 36/9/3 22/10/3 11/11/3
|
||||
f 39/12/2 51/13/2 4/6/2
|
||||
f 4/6/4 54/14/4 53/15/4
|
||||
f 14/16/5 13/17/5 12/18/5
|
||||
f 18/19/6 14/16/6 10/20/6
|
||||
f 20/4/3 16/21/3 31/22/3
|
||||
f 17/23/7 8/24/7 12/18/7
|
||||
f 25/25/4 32/26/4 29/27/4
|
||||
f 10/20/4 12/18/4 8/24/4
|
||||
f 1/28/8 18/19/8 17/23/8
|
||||
f 19/29/4 17/23/4 13/17/4
|
||||
f 25/25/4 14/16/4 18/19/4
|
||||
f 18/19/9 7/30/9 8/24/9
|
||||
f 92/31/10 27/32/10 28/33/10
|
||||
f 16/21/3 22/10/3 36/9/3
|
||||
f 31/22/3 36/9/3 21/34/3
|
||||
f 90/35/11 89/36/11 28/33/11
|
||||
f 91/37/12 90/35/12 24/38/12
|
||||
f 33/39/4 13/17/4 14/16/4
|
||||
f 23/40/4 24/38/4 28/33/4
|
||||
f 33/39/3 31/22/3 15/41/3
|
||||
f 21/34/3 36/9/3 30/42/3
|
||||
f 5/5/4 35/43/4 32/26/4
|
||||
f 5/5/4 20/4/4 34/44/4
|
||||
f 33/39/4 29/27/4 34/44/4
|
||||
f 91/37/13 23/40/13 27/32/13
|
||||
f 103/1/1 26/45/1 63/46/1
|
||||
f 26/45/14 50/47/14 38/48/14
|
||||
f 39/12/15 71/49/15 72/50/15
|
||||
f 48/51/16 60/52/16 59/53/16
|
||||
f 15/41/17 21/34/17 47/54/17
|
||||
f 19/29/17 46/55/17 37/56/17
|
||||
f 39/12/2 45/57/2 52/8/2
|
||||
f 20/4/2 45/57/2 44/58/2
|
||||
f 19/29/18 15/41/18 43/59/18
|
||||
f 9/60/19 42/61/19 47/54/19
|
||||
f 22/10/20 48/51/20 41/62/20
|
||||
f 25/25/21 1/28/21 37/56/21
|
||||
f 6/3/14 40/63/14 50/47/14
|
||||
f 104/64/22 40/63/22 6/3/22
|
||||
f 2/65/23 38/48/23 105/66/23
|
||||
f 55/67/2 56/68/2 53/15/2
|
||||
f 3/7/14 53/15/14 56/68/14
|
||||
f 51/13/15 55/67/15 54/14/15
|
||||
f 52/8/24 56/68/24 55/67/24
|
||||
f 57/69/2 59/53/2 60/52/2
|
||||
f 48/51/25 22/10/25 58/70/25
|
||||
f 16/21/26 57/69/26 58/70/26
|
||||
f 16/21/27 44/58/27 59/53/27
|
||||
f 107/71/28 63/46/28 67/72/28
|
||||
f 26/45/1 2/65/1 61/73/1
|
||||
f 9/60/1 30/42/1 64/74/1
|
||||
f 101/75/1 9/60/1 62/76/1
|
||||
f 108/77/1 109/78/1 67/72/1
|
||||
f 61/73/29 65/79/29 67/72/29
|
||||
f 62/76/30 64/74/30 68/80/30
|
||||
f 62/76/31 66/81/31 108/77/31
|
||||
f 71/49/32 75/82/32 76/83/32
|
||||
f 25/25/15 49/84/15 72/50/15
|
||||
f 5/5/15 69/85/15 71/49/15
|
||||
f 25/25/15 70/86/15 69/85/15
|
||||
f 76/83/15 75/82/15 79/87/15
|
||||
f 72/50/17 76/83/17 74/88/17
|
||||
f 71/49/2 69/85/2 73/89/2
|
||||
f 70/86/33 74/88/33 73/89/33
|
||||
f 80/90/3 79/87/3 83/91/3
|
||||
f 76/83/15 80/90/15 78/92/15
|
||||
f 75/82/15 73/89/15 77/93/15
|
||||
f 74/88/15 78/92/15 77/93/15
|
||||
f 82/94/15 84/95/15 83/91/15
|
||||
f 80/90/2 84/95/2 82/94/2
|
||||
f 77/93/17 81/96/17 83/91/17
|
||||
f 77/93/24 78/92/24 82/94/24
|
||||
f 35/43/13 87/97/13 88/98/13
|
||||
f 35/43/12 34/44/12 86/99/12
|
||||
f 34/44/11 29/27/11 85/100/11
|
||||
f 32/26/10 88/98/10 85/100/10
|
||||
f 92/31/34 100/101/34 99/102/34
|
||||
f 90/35/35 91/37/35 99/102/35
|
||||
f 89/36/36 90/35/36 98/103/36
|
||||
f 89/36/37 97/104/37 100/101/37
|
||||
f 95/105/13 99/102/13 100/101/13
|
||||
f 95/105/12 94/106/12 98/103/12
|
||||
f 94/106/11 93/107/11 97/104/11
|
||||
f 96/108/10 100/101/10 97/104/10
|
||||
f 88/98/38 96/108/38 93/107/38
|
||||
f 86/99/39 85/100/39 93/107/39
|
||||
f 87/97/40 86/99/40 94/106/40
|
||||
f 87/97/41 95/105/41 96/108/41
|
||||
f 106/109/42 108/77/42 65/79/42
|
||||
f 66/81/1 68/80/1 109/78/1
|
||||
f 101/75/1 106/109/1 61/73/1
|
||||
f 64/74/43 107/71/43 109/78/43
|
||||
f 101/75/23 105/66/23 42/61/23
|
||||
f 103/1/1 107/71/1 64/74/1
|
||||
f 30/42/1 11/11/1 102/2/1
|
||||
f 212/1/44 135/45/44 115/3/44
|
||||
f 129/4/2 112/7/2 113/6/2
|
||||
f 161/8/2 112/7/2 129/4/2
|
||||
f 145/9/24 139/42/24 120/11/24
|
||||
f 113/6/2 160/13/2 148/12/2
|
||||
f 162/15/45 163/14/45 113/6/45
|
||||
f 123/16/46 119/20/46 121/18/46
|
||||
f 127/19/47 116/30/47 119/20/47
|
||||
f 140/22/24 125/21/24 129/4/24
|
||||
f 121/18/48 117/24/48 126/23/48
|
||||
f 138/27/45 141/26/45 134/25/45
|
||||
f 117/24/45 121/18/45 119/20/45
|
||||
f 126/23/49 127/19/49 110/28/49
|
||||
f 122/17/45 126/23/45 128/29/45
|
||||
f 127/19/45 123/16/45 134/25/45
|
||||
f 117/24/50 116/30/50 127/19/50
|
||||
f 137/33/51 136/32/51 201/31/51
|
||||
f 145/9/24 131/10/24 125/21/24
|
||||
f 130/34/24 145/9/24 140/22/24
|
||||
f 199/35/52 133/38/52 137/33/52
|
||||
f 200/37/53 132/40/53 133/38/53
|
||||
f 123/16/45 122/17/45 142/39/45
|
||||
f 137/33/45 133/38/45 132/40/45
|
||||
f 124/41/24 140/22/24 142/39/24
|
||||
f 130/34/24 118/60/24 139/42/24
|
||||
f 141/26/45 144/43/45 114/5/45
|
||||
f 114/5/45 144/43/45 143/44/45
|
||||
f 143/44/45 138/27/45 142/39/45
|
||||
f 136/32/54 132/40/54 200/37/54
|
||||
f 212/1/44 216/71/44 172/46/44
|
||||
f 147/48/14 159/47/14 135/45/14
|
||||
f 181/50/15 180/49/15 148/12/15
|
||||
f 168/53/26 169/52/26 157/51/26
|
||||
f 124/41/17 152/59/17 156/54/17
|
||||
f 146/56/17 155/55/17 128/29/17
|
||||
f 148/12/2 160/13/2 161/8/2
|
||||
f 129/4/2 125/21/2 153/58/2
|
||||
f 155/55/18 152/59/18 124/41/18
|
||||
f 130/34/19 156/54/19 151/61/19
|
||||
f 131/10/20 120/11/20 150/62/20
|
||||
f 134/25/21 158/84/21 146/56/21
|
||||
f 159/47/14 149/63/14 115/3/14
|
||||
f 115/3/22 149/63/22 213/64/22
|
||||
f 214/66/23 147/48/23 111/65/23
|
||||
f 162/15/2 165/68/2 164/67/2
|
||||
f 165/68/14 162/15/14 112/7/14
|
||||
f 163/14/15 164/67/15 160/13/15
|
||||
f 164/67/3 165/68/3 161/8/3
|
||||
f 166/69/2 167/70/2 169/52/2
|
||||
f 157/51/25 169/52/25 167/70/25
|
||||
f 167/70/16 166/69/16 125/21/16
|
||||
f 125/21/27 166/69/27 168/53/27
|
||||
f 216/71/55 218/78/55 176/72/55
|
||||
f 135/45/44 172/46/44 170/73/44
|
||||
f 118/60/44 171/76/44 173/74/44
|
||||
f 210/75/44 215/109/44 171/76/44
|
||||
f 217/77/44 174/79/44 176/72/44
|
||||
f 176/72/56 174/79/56 170/73/56
|
||||
f 171/76/57 175/81/57 177/80/57
|
||||
f 217/77/58 175/81/58 171/76/58
|
||||
f 185/83/33 184/82/33 180/49/33
|
||||
f 134/25/15 179/86/15 181/50/15
|
||||
f 180/49/15 178/85/15 114/5/15
|
||||
f 178/85/15 179/86/15 134/25/15
|
||||
f 189/90/15 188/87/15 184/82/15
|
||||
f 183/88/17 185/83/17 181/50/17
|
||||
f 180/49/2 184/82/2 182/89/2
|
||||
f 182/89/32 183/88/32 179/86/32
|
||||
f 189/90/24 193/95/24 192/91/24
|
||||
f 187/92/15 189/90/15 185/83/15
|
||||
f 184/82/15 188/87/15 186/93/15
|
||||
f 186/93/15 187/92/15 183/88/15
|
||||
f 192/91/15 193/95/15 191/94/15
|
||||
f 191/94/2 193/95/2 189/90/2
|
||||
f 192/91/17 190/96/17 186/93/17
|
||||
f 186/93/3 190/96/3 191/94/3
|
||||
f 197/98/54 196/97/54 144/43/54
|
||||
f 144/43/53 196/97/53 195/99/53
|
||||
f 143/44/52 195/99/52 194/100/52
|
||||
f 194/100/51 197/98/51 141/26/51
|
||||
f 208/102/59 209/101/59 201/31/59
|
||||
f 199/35/60 207/103/60 208/102/60
|
||||
f 198/36/61 206/104/61 207/103/61
|
||||
f 209/101/62 206/104/62 198/36/62
|
||||
f 209/101/54 208/102/54 204/105/54
|
||||
f 204/105/53 208/102/53 207/103/53
|
||||
f 203/106/52 207/103/52 206/104/52
|
||||
f 206/104/51 209/101/51 205/108/51
|
||||
f 202/107/63 205/108/63 197/98/63
|
||||
f 195/99/64 203/106/64 202/107/64
|
||||
f 196/97/65 204/105/65 203/106/65
|
||||
f 205/108/66 204/105/66 196/97/66
|
||||
f 174/79/67 217/77/67 215/109/67
|
||||
f 175/81/44 217/77/44 218/78/44
|
||||
f 170/73/44 215/109/44 210/75/44
|
||||
f 173/74/68 177/80/68 218/78/68
|
||||
f 151/61/23 214/66/23 210/75/23
|
||||
f 173/74/44 216/71/44 212/1/44
|
||||
f 139/42/44 212/1/44 211/2/44
|
||||
f 26/45/1 103/1/1 6/3/1
|
||||
f 3/7/2 20/4/2 4/6/2
|
||||
f 45/57/2 20/4/2 52/8/2
|
||||
f 30/42/3 36/9/3 11/11/3
|
||||
f 5/5/2 39/12/2 4/6/2
|
||||
f 3/7/4 4/6/4 53/15/4
|
||||
f 10/20/5 14/16/5 12/18/5
|
||||
f 7/30/6 18/19/6 10/20/6
|
||||
f 33/39/3 20/4/3 31/22/3
|
||||
f 13/17/7 17/23/7 12/18/7
|
||||
f 33/39/4 25/25/4 29/27/4
|
||||
f 7/30/4 10/20/4 8/24/4
|
||||
f 19/29/69 1/28/69 17/23/69
|
||||
f 33/39/4 19/29/4 13/17/4
|
||||
f 1/28/70 25/25/70 18/19/70
|
||||
f 17/23/9 18/19/9 8/24/9
|
||||
f 89/36/10 92/31/10 28/33/10
|
||||
f 31/22/3 16/21/3 36/9/3
|
||||
f 15/41/3 31/22/3 21/34/3
|
||||
f 24/38/11 90/35/11 28/33/11
|
||||
f 23/40/12 91/37/12 24/38/12
|
||||
f 25/25/4 33/39/4 14/16/4
|
||||
f 27/32/4 23/40/4 28/33/4
|
||||
f 19/29/3 33/39/3 15/41/3
|
||||
f 9/60/3 21/34/3 30/42/3
|
||||
f 25/25/4 5/5/4 32/26/4
|
||||
f 35/43/4 5/5/4 34/44/4
|
||||
f 20/4/4 33/39/4 34/44/4
|
||||
f 92/31/13 91/37/13 27/32/13
|
||||
f 107/71/1 103/1/1 63/46/1
|
||||
f 2/65/14 26/45/14 38/48/14
|
||||
f 49/84/15 39/12/15 72/50/15
|
||||
f 44/58/16 48/51/16 59/53/16
|
||||
f 43/59/17 15/41/17 47/54/17
|
||||
f 1/28/17 19/29/17 37/56/17
|
||||
f 51/13/2 39/12/2 52/8/2
|
||||
f 16/21/2 20/4/2 44/58/2
|
||||
f 46/55/18 19/29/18 43/59/18
|
||||
f 21/34/19 9/60/19 47/54/19
|
||||
f 11/11/20 22/10/20 41/62/20
|
||||
f 49/84/21 25/25/21 37/56/21
|
||||
f 26/45/14 6/3/14 50/47/14
|
||||
f 102/2/22 104/64/22 6/3/22
|
||||
f 101/75/23 2/65/23 105/66/23
|
||||
f 54/14/2 55/67/2 53/15/2
|
||||
f 52/8/14 3/7/14 56/68/14
|
||||
f 4/6/15 51/13/15 54/14/15
|
||||
f 51/13/24 52/8/24 55/67/24
|
||||
f 58/70/2 57/69/2 60/52/2
|
||||
f 60/52/25 48/51/25 58/70/25
|
||||
f 22/10/26 16/21/26 58/70/26
|
||||
f 57/69/27 16/21/27 59/53/27
|
||||
f 109/78/71 107/71/71 67/72/71
|
||||
f 63/46/1 26/45/1 61/73/1
|
||||
f 62/76/1 9/60/1 64/74/1
|
||||
f 106/109/1 101/75/1 62/76/1
|
||||
f 65/79/1 108/77/1 67/72/1
|
||||
f 63/46/29 61/73/29 67/72/29
|
||||
f 66/81/30 62/76/30 68/80/30
|
||||
f 106/109/72 62/76/72 108/77/72
|
||||
f 72/50/32 71/49/32 76/83/32
|
||||
f 70/86/15 25/25/15 72/50/15
|
||||
f 39/12/15 5/5/15 71/49/15
|
||||
f 5/5/15 25/25/15 69/85/15
|
||||
f 80/90/15 76/83/15 79/87/15
|
||||
f 70/86/17 72/50/17 74/88/17
|
||||
f 75/82/2 71/49/2 73/89/2
|
||||
f 69/85/33 70/86/33 73/89/33
|
||||
f 84/95/3 80/90/3 83/91/3
|
||||
f 74/88/15 76/83/15 78/92/15
|
||||
f 79/87/15 75/82/15 77/93/15
|
||||
f 73/89/15 74/88/15 77/93/15
|
||||
f 81/96/15 82/94/15 83/91/15
|
||||
f 78/92/2 80/90/2 82/94/2
|
||||
f 79/87/17 77/93/17 83/91/17
|
||||
f 81/96/24 77/93/24 82/94/24
|
||||
f 32/26/13 35/43/13 88/98/13
|
||||
f 87/97/12 35/43/12 86/99/12
|
||||
f 86/99/11 34/44/11 85/100/11
|
||||
f 29/27/10 32/26/10 85/100/10
|
||||
f 91/37/34 92/31/34 99/102/34
|
||||
f 98/103/35 90/35/35 99/102/35
|
||||
f 97/104/36 89/36/36 98/103/36
|
||||
f 92/31/37 89/36/37 100/101/37
|
||||
f 96/108/13 95/105/13 100/101/13
|
||||
f 99/102/12 95/105/12 98/103/12
|
||||
f 98/103/11 94/106/11 97/104/11
|
||||
f 93/107/10 96/108/10 97/104/10
|
||||
f 85/100/38 88/98/38 93/107/38
|
||||
f 94/106/39 86/99/39 93/107/39
|
||||
f 95/105/40 87/97/40 94/106/40
|
||||
f 88/98/41 87/97/41 96/108/41
|
||||
f 61/73/73 106/109/73 65/79/73
|
||||
f 108/77/1 66/81/1 109/78/1
|
||||
f 2/65/1 101/75/1 61/73/1
|
||||
f 68/80/74 64/74/74 109/78/74
|
||||
f 9/60/23 101/75/23 42/61/23
|
||||
f 30/42/1 103/1/1 64/74/1
|
||||
f 103/1/1 30/42/1 102/2/1
|
||||
f 211/2/44 212/1/44 115/3/44
|
||||
f 114/5/2 129/4/2 113/6/2
|
||||
f 154/57/2 161/8/2 129/4/2
|
||||
f 131/10/24 145/9/24 120/11/24
|
||||
f 114/5/2 113/6/2 148/12/2
|
||||
f 112/7/45 162/15/45 113/6/45
|
||||
f 122/17/46 123/16/46 121/18/46
|
||||
f 123/16/47 127/19/47 119/20/47
|
||||
f 142/39/24 140/22/24 129/4/24
|
||||
f 122/17/48 121/18/48 126/23/48
|
||||
f 142/39/45 138/27/45 134/25/45
|
||||
f 116/30/45 117/24/45 119/20/45
|
||||
f 128/29/75 126/23/75 110/28/75
|
||||
f 142/39/45 122/17/45 128/29/45
|
||||
f 110/28/76 127/19/76 134/25/76
|
||||
f 126/23/50 117/24/50 127/19/50
|
||||
f 198/36/51 137/33/51 201/31/51
|
||||
f 140/22/24 145/9/24 125/21/24
|
||||
f 124/41/24 130/34/24 140/22/24
|
||||
f 198/36/52 199/35/52 137/33/52
|
||||
f 199/35/53 200/37/53 133/38/53
|
||||
f 134/25/45 123/16/45 142/39/45
|
||||
f 136/32/45 137/33/45 132/40/45
|
||||
f 128/29/24 124/41/24 142/39/24
|
||||
f 145/9/24 130/34/24 139/42/24
|
||||
f 134/25/45 141/26/45 114/5/45
|
||||
f 129/4/45 114/5/45 143/44/45
|
||||
f 129/4/45 143/44/45 142/39/45
|
||||
f 201/31/54 136/32/54 200/37/54
|
||||
f 135/45/44 212/1/44 172/46/44
|
||||
f 111/65/14 147/48/14 135/45/14
|
||||
f 158/84/15 181/50/15 148/12/15
|
||||
f 153/58/26 168/53/26 157/51/26
|
||||
f 130/34/17 124/41/17 156/54/17
|
||||
f 110/28/17 146/56/17 128/29/17
|
||||
f 154/57/2 148/12/2 161/8/2
|
||||
f 154/57/2 129/4/2 153/58/2
|
||||
f 128/29/18 155/55/18 124/41/18
|
||||
f 118/60/19 130/34/19 151/61/19
|
||||
f 157/51/20 131/10/20 150/62/20
|
||||
f 110/28/21 134/25/21 146/56/21
|
||||
f 135/45/14 159/47/14 115/3/14
|
||||
f 211/2/22 115/3/22 213/64/22
|
||||
f 210/75/23 214/66/23 111/65/23
|
||||
f 163/14/2 162/15/2 164/67/2
|
||||
f 161/8/14 165/68/14 112/7/14
|
||||
f 113/6/15 163/14/15 160/13/15
|
||||
f 160/13/3 164/67/3 161/8/3
|
||||
f 168/53/2 166/69/2 169/52/2
|
||||
f 131/10/25 157/51/25 167/70/25
|
||||
f 131/10/16 167/70/16 125/21/16
|
||||
f 153/58/27 125/21/27 168/53/27
|
||||
f 172/46/77 216/71/77 176/72/77
|
||||
f 111/65/44 135/45/44 170/73/44
|
||||
f 139/42/44 118/60/44 173/74/44
|
||||
f 118/60/44 210/75/44 171/76/44
|
||||
f 218/78/44 217/77/44 176/72/44
|
||||
f 172/46/56 176/72/56 170/73/56
|
||||
f 173/74/57 171/76/57 177/80/57
|
||||
f 215/109/78 217/77/78 171/76/78
|
||||
f 181/50/33 185/83/33 180/49/33
|
||||
f 158/84/15 134/25/15 181/50/15
|
||||
f 148/12/15 180/49/15 114/5/15
|
||||
f 114/5/15 178/85/15 134/25/15
|
||||
f 185/83/15 189/90/15 184/82/15
|
||||
f 179/86/17 183/88/17 181/50/17
|
||||
f 178/85/2 180/49/2 182/89/2
|
||||
f 178/85/32 182/89/32 179/86/32
|
||||
f 188/87/24 189/90/24 192/91/24
|
||||
f 183/88/15 187/92/15 185/83/15
|
||||
f 182/89/15 184/82/15 186/93/15
|
||||
f 182/89/15 186/93/15 183/88/15
|
||||
f 190/96/15 192/91/15 191/94/15
|
||||
f 187/92/2 191/94/2 189/90/2
|
||||
f 188/87/17 192/91/17 186/93/17
|
||||
f 187/92/3 186/93/3 191/94/3
|
||||
f 141/26/54 197/98/54 144/43/54
|
||||
f 143/44/53 144/43/53 195/99/53
|
||||
f 138/27/52 143/44/52 194/100/52
|
||||
f 138/27/51 194/100/51 141/26/51
|
||||
f 200/37/59 208/102/59 201/31/59
|
||||
f 200/37/60 199/35/60 208/102/60
|
||||
f 199/35/61 198/36/61 207/103/61
|
||||
f 201/31/79 209/101/79 198/36/79
|
||||
f 205/108/54 209/101/54 204/105/54
|
||||
f 203/106/53 204/105/53 207/103/53
|
||||
f 202/107/52 203/106/52 206/104/52
|
||||
f 202/107/51 206/104/51 205/108/51
|
||||
f 194/100/63 202/107/63 197/98/63
|
||||
f 194/100/64 195/99/64 202/107/64
|
||||
f 195/99/65 196/97/65 203/106/65
|
||||
f 197/98/66 205/108/66 196/97/66
|
||||
f 170/73/80 174/79/80 215/109/80
|
||||
f 177/80/44 175/81/44 218/78/44
|
||||
f 111/65/44 170/73/44 210/75/44
|
||||
f 216/71/81 173/74/81 218/78/81
|
||||
f 118/60/23 151/61/23 210/75/23
|
||||
f 139/42/44 173/74/44 212/1/44
|
||||
f 120/11/44 139/42/44 211/2/44
|
||||
usemtl Material.002
|
||||
f 41/62/82 104/64/82 102/2/82
|
||||
f 211/2/82 213/64/82 150/62/82
|
||||
f 11/11/82 41/62/82 102/2/82
|
||||
f 120/11/82 211/2/82 150/62/82
|
||||
30
models/usemtl-issue-104.obj
Normal file
30
models/usemtl-issue-104.obj
Normal file
@@ -0,0 +1,30 @@
|
||||
# cornell_box.obj and cornell_box.mtl are grabbed from Intel's embree project.
|
||||
# original cornell box data
|
||||
# comment
|
||||
|
||||
# empty line including some space
|
||||
|
||||
|
||||
mtllib cornell_box.mtl
|
||||
|
||||
o floor
|
||||
v 552.8 0.0 0.0
|
||||
v 0.0 0.0 0.0
|
||||
v 0.0 0.0 559.2
|
||||
v 549.6 0.0 559.2
|
||||
|
||||
v 130.0 0.0 65.0
|
||||
v 82.0 0.0 225.0
|
||||
v 240.0 0.0 272.0
|
||||
v 290.0 0.0 114.0
|
||||
|
||||
v 423.0 0.0 247.0
|
||||
v 265.0 0.0 296.0
|
||||
v 314.0 0.0 456.0
|
||||
v 472.0 0.0 406.0
|
||||
|
||||
f 1 2 3 4
|
||||
f 8 7 6 5
|
||||
f 12 11 10 9
|
||||
|
||||
usemtl white
|
||||
2
python/TODO.md
Normal file
2
python/TODO.md
Normal file
@@ -0,0 +1,2 @@
|
||||
* PBR material
|
||||
* Define index_t struct
|
||||
279
python/main.cpp
279
python/main.cpp
@@ -1,160 +1,203 @@
|
||||
//python3 module for tinyobjloader
|
||||
// python2/3 module for tinyobjloader
|
||||
//
|
||||
//usage:
|
||||
// usage:
|
||||
// import tinyobjloader as tol
|
||||
// model = tol.LoadObj(name)
|
||||
// print(model["shapes"])
|
||||
// print(model["materials"]
|
||||
// note:
|
||||
// `shape.mesh.index_t` is represented as flattened array: (vertex_index, normal_index, texcoord_index) * num_faces
|
||||
|
||||
#include <Python.h>
|
||||
#include <vector>
|
||||
#include "../tiny_obj_loader.h"
|
||||
|
||||
typedef std::vector<double> vectd;
|
||||
typedef std::vector<int> vecti;
|
||||
|
||||
PyObject*
|
||||
pyTupleFromfloat3 (float array[3])
|
||||
{
|
||||
int i;
|
||||
PyObject* tuple = PyTuple_New(3);
|
||||
PyObject* pyTupleFromfloat3(float array[3]) {
|
||||
int i;
|
||||
PyObject* tuple = PyTuple_New(3);
|
||||
|
||||
for(i=0; i<=2 ; i++){
|
||||
PyTuple_SetItem(tuple, i, PyFloat_FromDouble(array[i]));
|
||||
}
|
||||
for (i = 0; i <= 2; i++) {
|
||||
PyTuple_SetItem(tuple, i, PyFloat_FromDouble(array[i]));
|
||||
}
|
||||
|
||||
return tuple;
|
||||
return tuple;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
|
||||
static PyObject*
|
||||
pyLoadObj(PyObject* self, PyObject* args)
|
||||
{
|
||||
PyObject *rtndict, *pyshapes, *pymaterials,
|
||||
*current, *meshobj;
|
||||
static PyObject* pyLoadObj(PyObject* self, PyObject* args) {
|
||||
PyObject *rtndict, *pyshapes, *pymaterials, *attribobj, *current, *meshobj;
|
||||
|
||||
char const* filename;
|
||||
char *current_name;
|
||||
vectd vect;
|
||||
char const* current_name;
|
||||
char const* filename;
|
||||
vectd vect;
|
||||
std::vector<tinyobj::index_t> indices;
|
||||
std::vector<unsigned char> face_verts;
|
||||
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "s", &filename))
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args, "s", &filename)) return NULL;
|
||||
|
||||
std::string err;
|
||||
tinyobj::LoadObj(shapes, materials, err, filename);
|
||||
std::string err;
|
||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename);
|
||||
|
||||
pyshapes = PyDict_New();
|
||||
pymaterials = PyDict_New();
|
||||
rtndict = PyDict_New();
|
||||
pyshapes = PyDict_New();
|
||||
pymaterials = PyDict_New();
|
||||
rtndict = PyDict_New();
|
||||
|
||||
for (std::vector<tinyobj::shape_t>::iterator shape = shapes.begin() ;
|
||||
shape != shapes.end(); shape++)
|
||||
{
|
||||
meshobj = PyDict_New();
|
||||
tinyobj::mesh_t cm = (*shape).mesh;
|
||||
attribobj = PyDict_New();
|
||||
|
||||
for (int i = 0; i <= 4; i++ )
|
||||
{
|
||||
current = PyList_New(0);
|
||||
for (int i = 0; i <= 2; i++) {
|
||||
current = PyList_New(0);
|
||||
|
||||
switch(i) {
|
||||
|
||||
case 0:
|
||||
current_name = "positions";
|
||||
vect = vectd(cm.positions.begin(), cm.positions.end()); break;
|
||||
case 1:
|
||||
current_name = "normals";
|
||||
vect = vectd(cm.normals.begin(), cm.normals.end()); break;
|
||||
case 2:
|
||||
current_name = "texcoords";
|
||||
vect = vectd(cm.texcoords.begin(), cm.texcoords.end()); break;
|
||||
case 3:
|
||||
current_name = "indicies";
|
||||
vect = vectd(cm.indices.begin(), cm.indices.end()); break;
|
||||
case 4:
|
||||
current_name = "material_ids";
|
||||
vect = vectd(cm.material_ids.begin(), cm.material_ids.end()); break;
|
||||
|
||||
}
|
||||
|
||||
for (vectd::iterator it = vect.begin() ;
|
||||
it != vect.end(); it++)
|
||||
{
|
||||
PyList_Insert(current, it - vect.begin(), PyFloat_FromDouble(*it));
|
||||
}
|
||||
|
||||
PyDict_SetItemString(meshobj, current_name, current);
|
||||
|
||||
}
|
||||
|
||||
PyDict_SetItemString(pyshapes, (*shape).name.c_str(), meshobj);
|
||||
switch (i) {
|
||||
case 0:
|
||||
current_name = "vertices";
|
||||
vect = vectd(attrib.vertices.begin(), attrib.vertices.end());
|
||||
break;
|
||||
case 1:
|
||||
current_name = "normals";
|
||||
vect = vectd(attrib.normals.begin(), attrib.normals.end());
|
||||
break;
|
||||
case 2:
|
||||
current_name = "texcoords";
|
||||
vect = vectd(attrib.texcoords.begin(), attrib.texcoords.end());
|
||||
break;
|
||||
}
|
||||
|
||||
for (std::vector<tinyobj::material_t>::iterator mat = materials.begin() ;
|
||||
mat != materials.end(); mat++)
|
||||
{
|
||||
PyObject *matobj = PyDict_New();
|
||||
PyObject *unknown_parameter = PyDict_New();
|
||||
|
||||
for (std::map<std::string, std::string>::iterator p = (*mat).unknown_parameter.begin() ;
|
||||
p != (*mat).unknown_parameter.end(); ++p)
|
||||
{
|
||||
PyDict_SetItemString(unknown_parameter, p->first.c_str(), PyUnicode_FromString(p->second.c_str()));
|
||||
}
|
||||
|
||||
PyDict_SetItemString(matobj, "shininess", PyFloat_FromDouble((*mat).shininess));
|
||||
PyDict_SetItemString(matobj, "ior", PyFloat_FromDouble((*mat).ior));
|
||||
PyDict_SetItemString(matobj, "dissolve", PyFloat_FromDouble((*mat).dissolve));
|
||||
PyDict_SetItemString(matobj, "illum", PyLong_FromLong((*mat).illum));
|
||||
PyDict_SetItemString(matobj, "ambient_texname", PyUnicode_FromString((*mat).ambient_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "diffuse_texname", PyUnicode_FromString((*mat).diffuse_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "specular_texname", PyUnicode_FromString((*mat).specular_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "specular_highlight_texname", PyUnicode_FromString((*mat).specular_highlight_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "bump_texname", PyUnicode_FromString((*mat).bump_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "displacement_texname", PyUnicode_FromString((*mat).displacement_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "alpha_texname", PyUnicode_FromString((*mat).alpha_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "ambient", pyTupleFromfloat3((*mat).ambient));
|
||||
PyDict_SetItemString(matobj, "diffuse", pyTupleFromfloat3((*mat).diffuse));
|
||||
PyDict_SetItemString(matobj, "specular", pyTupleFromfloat3((*mat).specular));
|
||||
PyDict_SetItemString(matobj, "transmittance", pyTupleFromfloat3((*mat).transmittance));
|
||||
PyDict_SetItemString(matobj, "emission", pyTupleFromfloat3((*mat).emission));
|
||||
PyDict_SetItemString(matobj, "unknown_parameter", unknown_parameter);
|
||||
|
||||
PyDict_SetItemString(pymaterials, (*mat).name.c_str(), matobj);
|
||||
for (vectd::iterator it = vect.begin(); it != vect.end(); it++) {
|
||||
PyList_Insert(current, it - vect.begin(), PyFloat_FromDouble(*it));
|
||||
}
|
||||
|
||||
PyDict_SetItemString(rtndict, "shapes", pyshapes);
|
||||
PyDict_SetItemString(rtndict, "materials", pymaterials);
|
||||
PyDict_SetItemString(attribobj, current_name, current);
|
||||
}
|
||||
|
||||
return rtndict;
|
||||
for (std::vector<tinyobj::shape_t>::iterator shape = shapes.begin();
|
||||
shape != shapes.end(); shape++) {
|
||||
meshobj = PyDict_New();
|
||||
tinyobj::mesh_t cm = (*shape).mesh;
|
||||
|
||||
{
|
||||
current = PyList_New(0);
|
||||
|
||||
for (size_t i = 0; i < cm.indices.size(); i++) {
|
||||
// Flatten index array: v_idx, vn_idx, vt_idx, v_idx, vn_idx, vt_idx,
|
||||
// ...
|
||||
PyList_Insert(current, 3 * i + 0,
|
||||
PyLong_FromLong(cm.indices[i].vertex_index));
|
||||
PyList_Insert(current, 3 * i + 1,
|
||||
PyLong_FromLong(cm.indices[i].normal_index));
|
||||
PyList_Insert(current, 3 * i + 2,
|
||||
PyLong_FromLong(cm.indices[i].texcoord_index));
|
||||
}
|
||||
|
||||
PyDict_SetItemString(meshobj, "indices", current);
|
||||
}
|
||||
|
||||
{
|
||||
current = PyList_New(0);
|
||||
|
||||
for (size_t i = 0; i < cm.num_face_vertices.size(); i++) {
|
||||
// Widen data type to long.
|
||||
PyList_Insert(current, i, PyLong_FromLong(cm.num_face_vertices[i]));
|
||||
}
|
||||
|
||||
PyDict_SetItemString(meshobj, "num_face_vertices", current);
|
||||
}
|
||||
|
||||
{
|
||||
current = PyList_New(0);
|
||||
|
||||
for (size_t i = 0; i < cm.material_ids.size(); i++) {
|
||||
PyList_Insert(current, i, PyLong_FromLong(cm.material_ids[i]));
|
||||
}
|
||||
|
||||
PyDict_SetItemString(meshobj, "material_ids", current);
|
||||
}
|
||||
|
||||
PyDict_SetItemString(pyshapes, (*shape).name.c_str(), meshobj);
|
||||
}
|
||||
|
||||
for (std::vector<tinyobj::material_t>::iterator mat = materials.begin();
|
||||
mat != materials.end(); mat++) {
|
||||
PyObject* matobj = PyDict_New();
|
||||
PyObject* unknown_parameter = PyDict_New();
|
||||
|
||||
for (std::map<std::string, std::string>::iterator p =
|
||||
(*mat).unknown_parameter.begin();
|
||||
p != (*mat).unknown_parameter.end(); ++p) {
|
||||
PyDict_SetItemString(unknown_parameter, p->first.c_str(),
|
||||
PyUnicode_FromString(p->second.c_str()));
|
||||
}
|
||||
|
||||
PyDict_SetItemString(matobj, "shininess",
|
||||
PyFloat_FromDouble((*mat).shininess));
|
||||
PyDict_SetItemString(matobj, "ior", PyFloat_FromDouble((*mat).ior));
|
||||
PyDict_SetItemString(matobj, "dissolve",
|
||||
PyFloat_FromDouble((*mat).dissolve));
|
||||
PyDict_SetItemString(matobj, "illum", PyLong_FromLong((*mat).illum));
|
||||
PyDict_SetItemString(matobj, "ambient_texname",
|
||||
PyUnicode_FromString((*mat).ambient_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "diffuse_texname",
|
||||
PyUnicode_FromString((*mat).diffuse_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "specular_texname",
|
||||
PyUnicode_FromString((*mat).specular_texname.c_str()));
|
||||
PyDict_SetItemString(
|
||||
matobj, "specular_highlight_texname",
|
||||
PyUnicode_FromString((*mat).specular_highlight_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "bump_texname",
|
||||
PyUnicode_FromString((*mat).bump_texname.c_str()));
|
||||
PyDict_SetItemString(
|
||||
matobj, "displacement_texname",
|
||||
PyUnicode_FromString((*mat).displacement_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "alpha_texname",
|
||||
PyUnicode_FromString((*mat).alpha_texname.c_str()));
|
||||
PyDict_SetItemString(matobj, "ambient", pyTupleFromfloat3((*mat).ambient));
|
||||
PyDict_SetItemString(matobj, "diffuse", pyTupleFromfloat3((*mat).diffuse));
|
||||
PyDict_SetItemString(matobj, "specular",
|
||||
pyTupleFromfloat3((*mat).specular));
|
||||
PyDict_SetItemString(matobj, "transmittance",
|
||||
pyTupleFromfloat3((*mat).transmittance));
|
||||
PyDict_SetItemString(matobj, "emission",
|
||||
pyTupleFromfloat3((*mat).emission));
|
||||
PyDict_SetItemString(matobj, "unknown_parameter", unknown_parameter);
|
||||
|
||||
PyDict_SetItemString(pymaterials, (*mat).name.c_str(), matobj);
|
||||
}
|
||||
|
||||
PyDict_SetItemString(rtndict, "shapes", pyshapes);
|
||||
PyDict_SetItemString(rtndict, "materials", pymaterials);
|
||||
PyDict_SetItemString(rtndict, "attribs", attribobj);
|
||||
|
||||
return rtndict;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef mMethods[] = {
|
||||
|
||||
{"LoadObj", pyLoadObj, METH_VARARGS},
|
||||
{NULL, NULL, 0, NULL}
|
||||
{"LoadObj", pyLoadObj, METH_VARARGS}, {NULL, NULL, 0, NULL}
|
||||
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"tinyobjloader",
|
||||
NULL,
|
||||
-1,
|
||||
mMethods
|
||||
};
|
||||
static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, "tinyobjloader",
|
||||
NULL, -1, mMethods};
|
||||
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_tinyobjloader(void)
|
||||
{
|
||||
return PyModule_Create(&moduledef);
|
||||
PyMODINIT_FUNC PyInit_tinyobjloader(void) {
|
||||
return PyModule_Create(&moduledef);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
PyMODINIT_FUNC inittinyobjloader(void) {
|
||||
Py_InitModule3("tinyobjloader", mMethods, NULL);
|
||||
}
|
||||
|
||||
#endif // PY_MAJOR_VERSION >= 3
|
||||
|
||||
}
|
||||
|
||||
245
tests/tester.cc
245
tests/tester.cc
@@ -184,6 +184,48 @@ TestLoadObj(
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TestLoadObjFromPreopenedFile(
|
||||
const char* filename,
|
||||
const char* basepath = NULL,
|
||||
bool readMaterials = true,
|
||||
bool triangulate = true)
|
||||
{
|
||||
std::string fullFilename = std::string(basepath) + filename;
|
||||
std::cout << "Loading " << fullFilename << std::endl;
|
||||
|
||||
std::ifstream fileStream(fullFilename.c_str());
|
||||
|
||||
if (!fileStream) {
|
||||
std::cerr << "Could not find specified file: " << fullFilename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
tinyobj::MaterialStreamReader materialStreamReader(fileStream);
|
||||
tinyobj::MaterialStreamReader* materialReader = readMaterials
|
||||
? &materialStreamReader
|
||||
: NULL;
|
||||
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, &fileStream, materialReader);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
printf("Failed to load/parse .obj.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Loaded material count: " << materials.size() << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TestStreamLoadObj()
|
||||
@@ -265,7 +307,8 @@ std::string matStream(
|
||||
{
|
||||
(void)matId;
|
||||
(void)err;
|
||||
LoadMtl(matMap, materials, &m_matSStream);
|
||||
std::string warning;
|
||||
LoadMtl(matMap, materials, &m_matSStream, &warning);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -293,7 +336,7 @@ std::string matStream(
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* gMtlBasePath = "../models";
|
||||
const char* gMtlBasePath = "../models/";
|
||||
|
||||
TEST_CASE("cornell_box", "[Loader]") {
|
||||
|
||||
@@ -319,10 +362,208 @@ TEST_CASE("catmark_torus_creases0", "[Loader]") {
|
||||
REQUIRE(8 == shapes[0].mesh.tags.size());
|
||||
}
|
||||
|
||||
TEST_CASE("pbr", "[Loader]") {
|
||||
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/pbr-mat-ext.obj", gMtlBasePath, /*triangulate*/false);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(1 == materials.size());
|
||||
REQUIRE(0.2 == Approx(materials[0].roughness));
|
||||
REQUIRE(0.3 == Approx(materials[0].metallic));
|
||||
REQUIRE(0.4 == Approx(materials[0].sheen));
|
||||
REQUIRE(0.5 == Approx(materials[0].clearcoat_thickness));
|
||||
REQUIRE(0.6 == Approx(materials[0].clearcoat_roughness));
|
||||
REQUIRE(0.7 == Approx(materials[0].anisotropy));
|
||||
REQUIRE(0.8 == Approx(materials[0].anisotropy_rotation));
|
||||
REQUIRE(0 == materials[0].roughness_texname.compare("roughness.tex"));
|
||||
REQUIRE(0 == materials[0].metallic_texname.compare("metallic.tex"));
|
||||
REQUIRE(0 == materials[0].sheen_texname.compare("sheen.tex"));
|
||||
REQUIRE(0 == materials[0].emissive_texname.compare("emissive.tex"));
|
||||
REQUIRE(0 == materials[0].normal_texname.compare("normalmap.tex"));
|
||||
}
|
||||
|
||||
TEST_CASE("stream_load", "[Stream]") {
|
||||
REQUIRE(true == TestStreamLoadObj());
|
||||
}
|
||||
|
||||
TEST_CASE("stream_load_from_file_skipping_materials", "[Stream]") {
|
||||
REQUIRE(true == TestLoadObjFromPreopenedFile(
|
||||
"../models/pbr-mat-ext.obj", gMtlBasePath, /*readMaterials*/false, /*triangulate*/false));
|
||||
}
|
||||
|
||||
TEST_CASE("stream_load_from_file_with_materials", "[Stream]") {
|
||||
REQUIRE(true == TestLoadObjFromPreopenedFile(
|
||||
"../models/pbr-mat-ext.obj", gMtlBasePath, /*readMaterials*/true, /*triangulate*/false));
|
||||
}
|
||||
|
||||
TEST_CASE("trailing_whitespace_in_mtl", "[Issue92]") {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/issue-92.obj", gMtlBasePath);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(1 == materials.size());
|
||||
REQUIRE(0 == materials[0].diffuse_texname.compare("tmp.png"));
|
||||
}
|
||||
|
||||
TEST_CASE("transmittance_filter", "[Issue95]") {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/issue-95.obj", gMtlBasePath);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(1 == materials.size());
|
||||
REQUIRE(0.1 == Approx(materials[0].transmittance[0]));
|
||||
REQUIRE(0.2 == Approx(materials[0].transmittance[1]));
|
||||
REQUIRE(0.3 == Approx(materials[0].transmittance[2]));
|
||||
}
|
||||
|
||||
TEST_CASE("transmittance_filter_Tf", "[Issue95-Tf]") {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/issue-95-2.obj", gMtlBasePath);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(1 == materials.size());
|
||||
REQUIRE(0.1 == Approx(materials[0].transmittance[0]));
|
||||
REQUIRE(0.2 == Approx(materials[0].transmittance[1]));
|
||||
REQUIRE(0.3 == Approx(materials[0].transmittance[2]));
|
||||
}
|
||||
|
||||
TEST_CASE("transmittance_filter_Kt", "[Issue95-Kt]") {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/issue-95.obj", gMtlBasePath);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(1 == materials.size());
|
||||
REQUIRE(0.1 == Approx(materials[0].transmittance[0]));
|
||||
REQUIRE(0.2 == Approx(materials[0].transmittance[1]));
|
||||
REQUIRE(0.3 == Approx(materials[0].transmittance[2]));
|
||||
}
|
||||
|
||||
TEST_CASE("usemtl_at_last_line", "[Issue104]") {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/usemtl-issue-104.obj", gMtlBasePath);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(1 == shapes.size());
|
||||
}
|
||||
|
||||
TEST_CASE("texture_opts", "[Issue85]") {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/texture-options-issue-85.obj", gMtlBasePath);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(1 == shapes.size());
|
||||
REQUIRE(3 == materials.size());
|
||||
REQUIRE(0 == materials[0].name.compare("default"));
|
||||
REQUIRE(0 == materials[1].name.compare("bm2"));
|
||||
REQUIRE(0 == materials[2].name.compare("bm3"));
|
||||
REQUIRE(true == materials[0].ambient_texopt.clamp);
|
||||
REQUIRE(0.1 == Approx(materials[0].diffuse_texopt.origin_offset[0]));
|
||||
REQUIRE(0.0 == Approx(materials[0].diffuse_texopt.origin_offset[1]));
|
||||
REQUIRE(0.0 == Approx(materials[0].diffuse_texopt.origin_offset[2]));
|
||||
REQUIRE(0.1 == Approx(materials[0].specular_texopt.scale[0]));
|
||||
REQUIRE(0.2 == Approx(materials[0].specular_texopt.scale[1]));
|
||||
REQUIRE(1.0 == Approx(materials[0].specular_texopt.scale[2]));
|
||||
REQUIRE(0.1 == Approx(materials[0].specular_highlight_texopt.turbulence[0]));
|
||||
REQUIRE(0.2 == Approx(materials[0].specular_highlight_texopt.turbulence[1]));
|
||||
REQUIRE(0.3 == Approx(materials[0].specular_highlight_texopt.turbulence[2]));
|
||||
REQUIRE(3.0 == Approx(materials[0].bump_texopt.bump_multiplier));
|
||||
|
||||
REQUIRE(0.1 == Approx(materials[1].specular_highlight_texopt.brightness));
|
||||
REQUIRE(0.3 == Approx(materials[1].specular_highlight_texopt.contrast));
|
||||
REQUIRE('r' == materials[1].bump_texopt.imfchan);
|
||||
|
||||
REQUIRE(tinyobj::TEXTURE_TYPE_SPHERE == materials[2].diffuse_texopt.type);
|
||||
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_TOP == materials[2].specular_texopt.type);
|
||||
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_BOTTOM == materials[2].specular_highlight_texopt.type);
|
||||
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_LEFT == materials[2].ambient_texopt.type);
|
||||
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_RIGHT == materials[2].alpha_texopt.type);
|
||||
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_FRONT == materials[2].bump_texopt.type);
|
||||
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_BACK == materials[2].displacement_texopt.type);
|
||||
}
|
||||
|
||||
TEST_CASE("mtllib_multiple_filenames", "[Issue112]") {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/mtllib-multiple-files-issue-112.obj", gMtlBasePath);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(1 == materials.size());
|
||||
}
|
||||
|
||||
TEST_CASE("tr_and_d", "[Issue43]") {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/tr-and-d-issue-43.obj", gMtlBasePath);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(2 == materials.size());
|
||||
|
||||
REQUIRE(0.75 == Approx(materials[0].dissolve));
|
||||
REQUIRE(0.75 == Approx(materials[1].dissolve));
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
main(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
9
tinyobjloader-config.cmake.in
Normal file
9
tinyobjloader-config.cmake.in
Normal file
@@ -0,0 +1,9 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set(TINYOBJLOADER_VERSION "@TINYOBJLOADER_VERSION@")
|
||||
|
||||
set_and_check(TINYOBJLOADER_INCLUDE_DIRS "@PACKAGE_TINYOBJLOADER_INCLUDE_DIR@")
|
||||
set_and_check(TINYOBJLOADER_LIBRARY_DIRS "@PACKAGE_TINYOBJLOADER_LIBRARY_DIR@")
|
||||
set(TINYOBJLOADER_LIBRARIES tinyobjloader)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
|
||||
15
tinyobjloader.pc.in
Normal file
15
tinyobjloader.pc.in
Normal file
@@ -0,0 +1,15 @@
|
||||
# Generated by CMake @CMAKE_VERSION@ for @PROJECT_NAME@. Any changes to this
|
||||
# file will be overwritten by the next CMake run. The input file was
|
||||
# tinyobjloader.pc.in.
|
||||
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/@TINYOBJLOADER_LIBRARY_DIR@
|
||||
includedir=${prefix}/@TINYOBJLOADER_INCLUDE_DIR@
|
||||
|
||||
Name: @PROJECT_NAME@
|
||||
Description: Tiny but powerful single file wavefront obj loader
|
||||
URL: https://syoyo.github.io/tinyobjloader/
|
||||
Version: @TINYOBJLOADER_VERSION@
|
||||
Libs: -L${libdir} -ltinyobjloader
|
||||
Cflags: -I${includedir}
|
||||
Reference in New Issue
Block a user