1 Commits

Author SHA1 Message Date
Syoyo Fujita
98da6829ac Initial support of parsing curve primitive('curv')
Add clang-format style file.
2015-08-20 18:17:13 +09:00
79 changed files with 2208 additions and 34823 deletions

View File

@@ -1,37 +0,0 @@
{
/* Bintray package information.
In case the package already exists on Bintray, only the name, repo and subject
fields are mandatory. */
"package": {
"name": "releases", // Bintray package name
"repo": "tinyobjloader", // Bintray repository name
"subject": "syoyo" // Bintray subject (user or organization)
},
/* Package version information.
In case the version already exists on Bintray, only the name fields is mandatory. */
"version": {
"name": "@VERSION@",
"desc": "@VERSION@",
"released": "@DATE@",
"vcs_tag": "@VERSION@",
"gpgSign": false
},
/* Configure the files you would like to upload to Bintray and their upload path.
You can define one or more groups of patterns.
Each group contains three patterns:
includePattern: Pattern in the form of Ruby regular expression, indicating the path of files to be uploaded to Bintray.
excludePattern: Optional. Pattern in the form of Ruby regular expression, indicating the path of files to be removed from the list of files specified by the includePattern.
uploadPattern: Upload path on Bintray. The path can contain symbols in the form of $1, $2,... that are replaced with capturing groups defined in the include pattern.
Note: Regular expressions defined as part of the includePattern property must be wrapped with brackets. */
"files":
[ {"includePattern": "dist/(.*)", "uploadPattern": "$1"} ],
"publish": true
}

View File

@@ -1,7 +1,7 @@
---
BasedOnStyle: Google
BasedOnStyle: LLVM
IndentWidth: 2
TabWidth: 2
UseTab: Never
UseTab: Always
BreakBeforeBraces: Attach
Standard: Cpp03

View File

@@ -1,81 +0,0 @@
language: cpp
sudo: required
matrix:
include:
- addons: &1
apt:
sources:
- george-edison55-precise-backports
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
packages:
- cmake
- cmake-data
- ninja-build
- g++-4.9
- clang-3.7
compiler: clang
env: DEPLOY_BUILD=1 COMPILER_VERSION=3.7 BUILD_TYPE=Debug
- addons: *1
compiler: clang
env: COMPILER_VERSION=3.7 BUILD_TYPE=Release
- addons: &2
apt:
sources:
- george-edison55-precise-backports
- ubuntu-toolchain-r-test
packages:
- cmake
- cmake-data
- ninja-build
- g++-4.9
compiler: gcc
env: COMPILER_VERSION=4.9 BUILD_TYPE=Debug
- addons: *2
compiler: gcc
env: COMPILER_VERSION=4.9 BUILD_TYPE=Release
- addons: *1
compiler: clang
env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew upgrade; fi
- if [ -n "$REPORT_COVERAGE" ]; then sudo apt-get update python; fi
- if [ -n "$REPORT_COVERAGE" ]; then sudo apt-get install python-dev libffi-dev libssl-dev; fi
- if [ -n "$REPORT_COVERAGE" ]; then sudo pip install --upgrade pip; fi
- if [ -n "$REPORT_COVERAGE" ]; then CXX=g++ pip install --user requests[security]; fi
- if [ -n "$REPORT_COVERAGE" ]; then CXX=g++ pip install --user cpp-coveralls; fi
script:
- cd tests
- make check
- if [ -n "$REPORT_COVERAGE" ]; then coveralls -b . -r .. -e examples -e tools -e
jni -e python -e images -E ".*CompilerId.*" -E ".*feature_tests.*" ; fi
- cd ..
- rm -rf dist
- mkdir dist
- cp tiny_obj_loader.h dist/
before_deploy:
- echo "Creating description file for bintray."
- ./tools/travis_postbuild.sh
deploy:
- provider: bintray
file: ".bintray.json"
user: "syoyo"
key:
secure: W4F1VZcDcVOMe8Ymvo0bHery/JSmVhadl1NgAnGus6o7zVw7ChElKA1ho/NtqUbtoW8o1qUKMJdLQeh786jolocZJEJlns9JZ5FCet6H2b3kITfUa4GR5T11V/ZYwL3SajW8vZ1xu5UrpP5HHgFMYtxb1MFrNLDI60sh0RnyV/qFFBnCJGZPagF/M1mzbJeDml5xK5lShH0r8QpH+7MeQ1J8ungEyJ7UCyr1ao8gY9eq1/05IpHR9vri/d48EXQWHbqtI8EwCc7064oCYQGyYcLsD4yPEokwrdelkCvDquSpJLmbJENfZCc4vZGXsykjnQ8+gltJomBAivQFB9vc06ETEJssMzitbrfEZUrqFwZj/HZM7CYGXfGQWltL828SppCjsuWrgQ/VYXM5UgRpmhlxbqnuyxnYvKZ9EDW4+EnMkOmIl7WSDovp8E/4CZ0ghs+YyFS4SrgeqFCXS8bvxrkDUUPSipHuGBOt02fRnccKzU+3zU6Q5fghyLczz4ZtnOdk+Niz/njyF0SZfPYTUgb3GzAJ8Su6kvWJCAGdedON3n1F/TtybCE2dIdATxaO2uFQbwYjSOCiq209oCJ7MrsQZibRsa5a9YXyjlLkPxwOeVwo8wJyJclqWswIkhdSO8xvTnkwESv4yLzLutEOlBVlQbJzpyuS6vx0yHOYkwc=
all_branches: true
on:
repo: syoyo/tinyobjloader
condition: -n "$DEPLOY_BUILD"
tags: true
skip_cleanup: true
- provider: releases
api_key:
secure: AsXameK4GJn6h6wMmDrKTr7q/o9EI7hX7zWg1W6VaFBQKfkBvOmjJolWimjl6HMoRZ1NpMmK5GDm3zBlTUeABtgVBIyNWgE9vWS39ff6D5iQKcgScFsJkyILt0GikBqbN2pLGQ2t/M1Qh6n1sEIfzqekiCcF5Qvy5yYlYvHtaRGV02QeYAej/xx15/9SMuKTncHhjf63ClYPu8ODid7QUegJUvlQUeXoPsBDbaXMH2uDWoBWF7etX7G2Iob4NE8GX+ZP6dj+Ogi7p4HXThK650mzLL/pUl584EjjY/vePqx0cFhtpiRwvrW8SNPI1aJ1Phwa1enLRUgfS3bnkwQAMw/SCXSK2lnCvkUAXyTgpG03HWrZURj4vhEPXc7qHooO+dsfmi+JanYLaSDyrGpgQznLGjCMnVATimry0KxSufUY8Wt72Wh+nf7N0IgTUCjl32sWnQd/MRZPkxFuaf1h7r9RoH9KZY0yIOV09gABEFCGrOIZA2FcyhC2G26Bc4zyNrfMFpZ2DI76qdcWNdJGkRkpxtH9sGU8JgZu6Em2f1e6+SLgkBsPxbhRk5PwdhA9AXE2p9PmQqhO3jJKusGBZSoHAF7TlwagRY2J01yJxF7ge6zG9U8QuBqs1bB1zdnE34fHWOgs4st3inC+oBDOhvnEg1Nm/qeYVWMBzpwclSg=
file: tiny_obj_loader.h
all_branches: true
on:
repo: syoyo/tinyobjloader
tags: true
skip_cleanup: true

View File

@@ -12,8 +12,8 @@ set(tinyobjloader-Source
${CMAKE_CURRENT_SOURCE_DIR}/tiny_obj_loader.cc
)
set(tinyobjloader-Example-Source
${CMAKE_CURRENT_SOURCE_DIR}/loader_example.cc
set(tinyobjloader-Test-Source
${CMAKE_CURRENT_SOURCE_DIR}/test.cc
)
set(tinyobjloader-examples-objsticher
@@ -22,17 +22,14 @@ set(tinyobjloader-examples-objsticher
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_sticher.cc
)
option(TINYOBJLOADER_BUILD_TEST_LOADER "Build Example Loader Application" OFF)
option(TINYOBJLOADER_COMPILATION_SHARED "Build as shared library" OFF)
add_library(tinyobjloader
${tinyobjloader-Source}
)
if (TINYOBJLOADER_COMPILATION_SHARED)
add_library(tinyobjloader SHARED ${tinyobjloader-Source})
else()
add_library(tinyobjloader STATIC ${tinyobjloader-Source})
endif()
option(TINYOBJLOADER_BUILD_TEST_LOADER "Build Test Loader Application" OFF)
if(TINYOBJLOADER_BUILD_TEST_LOADER)
add_executable(test_loader ${tinyobjloader-Example-Source})
add_executable(test_loader ${tinyobjloader-Test-Source})
target_link_libraries(test_loader tinyobjloader)
endif()

216
README.md
View File

@@ -1,86 +1,60 @@
# tinyobjloader
tinyobjloader
=============
[![Join the chat at https://gitter.im/syoyo/tinyobjloader](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/syoyo/tinyobjloader?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/syoyo/tinyobjloader.svg)](https://travis-ci.org/syoyo/tinyobjloader)
[![wercker status](https://app.wercker.com/status/495a3bac400212cdacdeb4dd9397bf4f/m "wercker status")](https://app.wercker.com/project/bykey/495a3bac400212cdacdeb4dd9397bf4f)
[![Build status](https://ci.appveyor.com/api/projects/status/tlb421q3t2oyobcn/branch/master?svg=true)](https://ci.appveyor.com/project/syoyo/tinyobjloader/branch/master)
[![Coverage Status](https://coveralls.io/repos/github/syoyo/tinyobjloader/badge.svg?branch=master)](https://coveralls.io/github/syoyo/tinyobjloader?branch=master)
http://syoyo.github.io/tinyobjloader/
Tiny but powerful single file wavefront obj loader written in C++. No dependency except for C++ STL. It can parse 10M over polygons with moderate memory and time.
Tiny but poweful single file wavefront obj loader written in C++. No dependency except for C++ STL. It can parse 10M over polygons with moderate memory and time.
`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 .
Notice!
What's new
----------
* 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
-------
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
![Rungholt](images/rungholt.jpg)
![Rungholt](https://github.com/syoyo/tinyobjloader/blob/master/images/rungholt.jpg?raw=true)
tinyobjloader can successfully load 6M triangles Rungholt scene.
http://graphics.cs.williams.edu/data/meshes.xml
![](images/sanmugel.png)
* [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
* pbrt-v2 https://https://github.com/mmp/pbrt-v2
* OpenGL game engine development http://swarminglogic.com/jotting/2013_10_gamedev01
* mallie https://lighttransport.github.io/mallie
* IBLBaker (Image Based Lighting Baker). http://www.derkreature.com/iblbaker/
* Stanford CS148 http://web.stanford.edu/class/cs148/assignments/assignment3.pdf
* Awesome Bump http://awesomebump.besaba.com/about/
* sdlgl3-wavefront OpenGL .obj viewer https://github.com/chrisliebert/sdlgl3-wavefront
* pbrt-v3 https://github.com/mmp/pbrt-v3
* cocos2d-x https://github.com/cocos2d/cocos2d-x/
* Android Vulkan demo https://github.com/SaschaWillems/Vulkan
* 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/
* pbrt-v3 https://https://github.com/mmp/pbrt-v3
* Your project here!
## Features
Features
--------
* Group(parse multiple group name)
* Vertex
@@ -88,92 +62,78 @@ TinyObjLoader is successfully used in ...
* Normal
* 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.
Notes
-----
## TODO
Polygon is converted into triangle.
* [ ] Fix obj_sticker example.
* [ ] More unit test codes.
* [ ] Texture options
* [ ] Normal vector generation
* [ ] Support smoothing groups
TODO
----
## License
- [ ] Support quad polygon and some tags for OpenSubdiv http://graphics.pixar.com/opensubdiv/
Licensed under MIT license.
License
-------
## Usage
Licensed under 2 clause BSD.
`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`.
See `loader_example.cc` for more details.
Usage
-----
```c++
#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
#include "tiny_obj_loader.h"
std::string inputfile = "cornell_box.obj";
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string inputfile = "cornell_box.obj";
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, inputfile.c_str());
std::string err = tinyobj::LoadObj(shapes, materials, inputfile.c_str());
if (!err.empty()) { // `err` may contain warning message.
std::cerr << err << std::endl;
}
if (!ret) {
exit(1);
}
// Loop over shapes
for (size_t s = 0; s < shapes.size(); s++) {
// Loop over faces(polygon)
size_t index_offset = 0;
for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) {
int fv = shapes[s].mesh.num_face_vertices[f];
// Loop over vertices in the face.
for (size_t v = 0; v < fv; v++) {
// access to vertex
tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
float vx = attrib.vertices[3*idx.vertex_index+0];
float vy = attrib.vertices[3*idx.vertex_index+1];
float vz = attrib.vertices[3*idx.vertex_index+2];
float nx = attrib.normals[3*idx.normal_index+0];
float ny = attrib.normals[3*idx.normal_index+1];
float nz = attrib.normals[3*idx.normal_index+2];
float tx = attrib.texcoords[2*idx.texcoord_index+0];
float ty = attrib.texcoords[2*idx.texcoord_index+1];
if (!err.empty()) {
std::cerr << err << std::endl;
exit(1);
}
index_offset += fv;
// per-face material
shapes[s].mesh.material_ids[f];
}
}
std::cout << "# of shapes : " << shapes.size() << std::endl;
std::cout << "# of materials : " << materials.size() << std::endl;
for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert((shapes[i].mesh.indices.size() % 3) == 0);
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
printf(" idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
}
```
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
assert((shapes[i].mesh.positions.size() % 3) == 0);
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
printf(" v[%ld] = (%f, %f, %f)\n", v,
shapes[i].mesh.positions[3*v+0],
shapes[i].mesh.positions[3*v+1],
shapes[i].mesh.positions[3*v+2]);
}
}
## 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.
Note that the optimized loader uses C++11 thread and it does less error checks but may work most .obj data.
Here is some benchmark result. Time are measured on MacBook 12(Early 2016, Core m5 1.2GHz).
* 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)
## Tests
Unit tests are provided in `tests` directory. See `tests/README.md` for details.
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
printf(" material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
printf(" material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
printf(" material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
printf(" material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
printf(" material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
printf(" material.Ns = %f\n", materials[i].shininess);
printf(" material.Ni = %f\n", materials[i].ior);
printf(" material.dissolve = %f\n", 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].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());
}
printf("\n");
}

View File

@@ -1,22 +1,12 @@
version: 1.0.{build}
version: 0.9.{build}
# scripts that runs after repo cloning.
install:
- vcsetup.bat
platform: x64
configuration: Release
install:
#######################################################################################
# All external dependencies are installed in C:\projects\deps
#######################################################################################
- mkdir C:\projects\deps
#######################################################################################
# Install Ninja
#######################################################################################
- set NINJA_URL="https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip"
- appveyor DownloadFile %NINJA_URL% -FileName ninja.zip
- 7z x ninja.zip -oC:\projects\deps\ninja > nul
- set PATH=C:\projects\deps\ninja;%PATH%
- ninja --version
build_script:
- cd tests
- vcbuild.bat
build:
parallel: true
project: TinyObjLoaderSolution.sln

View File

@@ -1,53 +0,0 @@
ninja_required_version = 1.4
gnubuilddir = build
gnudefines =
gnuincludes = -I.
gnucflags = -O2 -g
gnucxxflags = -O2 -g -pedantic -Wall -Wextra -Wcast-align -Wcast-qual $
-Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self $
-Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast $
-Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion $
-Wsign-promo -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror $
-Wno-unused -fsanitize=address
gnuldflags = -fsanitize=address
pool link_pool
depth = 1
rule gnucxx
command = $gnucxx -MMD -MF $out.d $gnudefines $gnuincludes $gnucxxflags $
-c $in -o $out
description = CXX $out
depfile = $out.d
deps = gcc
rule gnucc
command = $gnucc -MMD -MF $out.d $gnudefines $gnuincludes $gnucflags -c $
$in -o $out
description = CC $out
depfile = $out.d
deps = gcc
rule gnulink
command = $gnuld -o $out $in $libs $gnuldflags
description = LINK $out
pool = link_pool
rule gnuar
command = $gnuar rsc $out $in
description = AR $out
pool = link_pool
rule gnustamp
command = touch $out
description = STAMP $out
gnucxx = g++
gnucc = gcc
gnuld = $gnucxx
gnuar = ar
build loader_example.o: gnucxx loader_example.cc
build loader_example: gnulink loader_example.o
build all: phony loader_example
default all

6323
deps/cpplint.py vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
all:
clang++ -I../../ -Wall -g -o example main.cc

View File

@@ -1,166 +0,0 @@
//
// 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 <fstream>
#include <iostream>
#include <sstream>
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<tinyobj::material_t> materials;
} MyMesh;
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);
printf("vn[%ld] = %f, %f, %f\n", mesh->normals.size() / 3, x, y, z);
mesh->normals.push_back(x);
mesh->normals.push_back(y);
mesh->normals.push_back(z);
}
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, 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(whic means relative
// index).
// Also, the first index starts with 1, not 0.
// See fixIndex() function in tiny_obj_loader.h for details.
// Also, 0 is set for the index value which
// does not exist in .obj
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
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);
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());
} 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);
printf("mtllib. # of materials = %d\n", num_materials);
for (int i = 0; i < num_materials; i++) {
mesh->materials.push_back(materials[i]);
}
}
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++) {
printf(" %s\n", names[i]);
}
}
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) {
tinyobj::callback_t cb;
cb.vertex_cb = vertex_cb;
cb.normal_cb = normal_cb;
cb.texcoord_cb = texcoord_cb;
cb.index_cb = index_cb;
cb.usemtl_cb = usemtl_cb;
cb.mtllib_cb = mtllib_cb;
cb.group_cb = group_cb;
cb.object_cb = object_cb;
MyMesh mesh;
std::string err;
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;
return EXIT_FAILURE;
}
tinyobj::MaterialFileReader mtlReader("../../models/");
bool ret = tinyobj::LoadObjWithCallback(ifs, cb, &mesh, &mtlReader, &err);
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
std::cerr << "Failed to parse .obj" << std::endl;
return EXIT_FAILURE;
}
printf("# of vertices = %ld\n", mesh.vertices.size() / 3);
printf("# of normals = %ld\n", mesh.normals.size() / 3);
printf("# of texcoords = %ld\n", mesh.texcoords.size() / 2);
printf("# of vertex indices = %ld\n", mesh.v_indices.size());
printf("# of normal indices = %ld\n", mesh.vn_indices.size());
printf("# of texcoord indices = %ld\n", mesh.vt_indices.size());
printf("# of materials = %ld\n", mesh.materials.size());
return EXIT_SUCCESS;
}

View File

@@ -86,12 +86,9 @@ main(
for (int i = 0; i < num_objfiles; i++) {
std::cout << "Loading " << argv[i+1] << " ... " << std::flush;
std::string err;
bool ret = tinyobj::LoadObj(shapes[i], materials[i], err, argv[i+1]);
std::string err = tinyobj::LoadObj(shapes[i], materials[i], argv[i+1]);
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
exit(1);
}

View File

@@ -1,37 +0,0 @@
# Simple .obj viewer with glew + glfw3 + OpenGL
## Requirements
* premake5
* glfw3
* glew
## Build on MaCOSX
Install glfw3 and glew using brew.
Then,
$ premake5 gmake
$ make
## Build on Linux
Set `PKG_CONFIG_PATH` or Edit path to glfw3 and glew in `premake4.lua`
Then,
$ premake5 gmake
$ make
## Build on Windows.
* Visual Studio 2013
* Windows 64bit
* 32bit may work.
Put glfw3 and glew library somewhere and replace include and lib path in `premake4.lua`
Then,
> premake5.exe vs2013

View File

@@ -1,44 +0,0 @@
solution "objview"
-- location ( "build" )
configurations { "Release", "Debug" }
platforms {"native", "x64", "x32"}
project "objview"
kind "ConsoleApp"
language "C++"
files { "viewer.cc", "trackball.cc" }
includedirs { "./" }
includedirs { "../../" }
configuration { "linux" }
linkoptions { "`pkg-config --libs glfw3`" }
links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" }
linkoptions { "-pthread" }
configuration { "windows" }
-- Path to GLFW3
includedirs { '../../../../local/glfw-3.1.2.bin.WIN64/include' }
libdirs { '../../../../local/glfw-3.1.2.bin.WIN64/lib-vc2013' }
-- Path to GLEW
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" }
configuration { "macosx" }
includedirs { "/usr/local/include" }
buildoptions { "-Wno-deprecated-declarations" }
libdirs { "/usr/local/lib" }
links { "glfw3", "GLEW" }
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" }
configuration "Debug"
defines { "DEBUG" }
flags { "Symbols", "ExtraWarnings"}
configuration "Release"
defines { "NDEBUG" }
flags { "Optimize", "ExtraWarnings"}

File diff suppressed because it is too large Load Diff

View File

@@ -1,292 +0,0 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* Trackball code:
*
* Implementation of a virtual trackball.
* Implemented by Gavin Bell, lots of ideas from Thant Tessman and
* the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
*
* Vector manip code:
*
* Original code from:
* David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
*
* Much mucking with by:
* Gavin Bell
*/
#include <math.h>
#include "trackball.h"
/*
* This size should really be based on the distance from the center of
* rotation to the point on the object underneath the mouse. That
* point would then track the mouse as closely as possible. This is a
* simple example, though, so that is left as an Exercise for the
* Programmer.
*/
#define TRACKBALLSIZE (0.8)
/*
* Local function prototypes (not defined in trackball.h)
*/
static float tb_project_to_sphere(float, float, float);
static void normalize_quat(float[4]);
static void vzero(float *v) {
v[0] = 0.0;
v[1] = 0.0;
v[2] = 0.0;
}
static void vset(float *v, float x, float y, float z) {
v[0] = x;
v[1] = y;
v[2] = z;
}
static void vsub(const float *src1, const float *src2, float *dst) {
dst[0] = src1[0] - src2[0];
dst[1] = src1[1] - src2[1];
dst[2] = src1[2] - src2[2];
}
static void vcopy(const float *v1, float *v2) {
register int i;
for (i = 0; i < 3; i++)
v2[i] = v1[i];
}
static void vcross(const float *v1, const float *v2, float *cross) {
float temp[3];
temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
vcopy(temp, cross);
}
static float vlength(const float *v) {
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
static void vscale(float *v, float div) {
v[0] *= div;
v[1] *= div;
v[2] *= div;
}
static void vnormal(float *v) { vscale(v, 1.0 / vlength(v)); }
static float vdot(const float *v1, const float *v2) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
static void vadd(const float *src1, const float *src2, float *dst) {
dst[0] = src1[0] + src2[0];
dst[1] = src1[1] + src2[1];
dst[2] = src1[2] + src2[2];
}
/*
* Ok, simulate a track-ball. Project the points onto the virtual
* trackball, then figure out the axis of rotation, which is the cross
* product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
* Note: This is a deformed trackball-- is a trackball in the center,
* but is deformed into a hyperbolic sheet of rotation away from the
* center. This particular function was chosen after trying out
* several variations.
*
* It is assumed that the arguments to this routine are in the range
* (-1.0 ... 1.0)
*/
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y) {
float a[3]; /* Axis of rotation */
float phi; /* how much to rotate about axis */
float p1[3], p2[3], d[3];
float t;
if (p1x == p2x && p1y == p2y) {
/* Zero rotation */
vzero(q);
q[3] = 1.0;
return;
}
/*
* First, figure out z-coordinates for projection of P1 and P2 to
* deformed sphere
*/
vset(p1, p1x, p1y, tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y));
vset(p2, p2x, p2y, tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y));
/*
* Now, we want the cross product of P1 and P2
*/
vcross(p2, p1, a);
/*
* Figure out how much to rotate around that axis.
*/
vsub(p1, p2, d);
t = vlength(d) / (2.0 * TRACKBALLSIZE);
/*
* Avoid problems with out-of-control values...
*/
if (t > 1.0)
t = 1.0;
if (t < -1.0)
t = -1.0;
phi = 2.0 * asin(t);
axis_to_quat(a, phi, q);
}
/*
* Given an axis and angle, compute quaternion.
*/
void axis_to_quat(float a[3], float phi, float q[4]) {
vnormal(a);
vcopy(a, q);
vscale(q, sin(phi / 2.0));
q[3] = cos(phi / 2.0);
}
/*
* Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
* if we are away from the center of the sphere.
*/
static float tb_project_to_sphere(float r, float x, float y) {
float d, t, z;
d = sqrt(x * x + y * y);
if (d < r * 0.70710678118654752440) { /* Inside sphere */
z = sqrt(r * r - d * d);
} else { /* On hyperbola */
t = r / 1.41421356237309504880;
z = t * t / d;
}
return z;
}
/*
* Given two rotations, e1 and e2, expressed as quaternion rotations,
* figure out the equivalent single rotation and stuff it into dest.
*
* This routine also normalizes the result every RENORMCOUNT times it is
* called, to keep error from creeping in.
*
* NOTE: This routine is written so that q1 or q2 may be the same
* as dest (or each other).
*/
#define RENORMCOUNT 97
void add_quats(float q1[4], float q2[4], float dest[4]) {
static int count = 0;
float t1[4], t2[4], t3[4];
float tf[4];
vcopy(q1, t1);
vscale(t1, q2[3]);
vcopy(q2, t2);
vscale(t2, q1[3]);
vcross(q2, q1, t3);
vadd(t1, t2, tf);
vadd(t3, tf, tf);
tf[3] = q1[3] * q2[3] - vdot(q1, q2);
dest[0] = tf[0];
dest[1] = tf[1];
dest[2] = tf[2];
dest[3] = tf[3];
if (++count > RENORMCOUNT) {
count = 0;
normalize_quat(dest);
}
}
/*
* Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0
* If they don't add up to 1.0, dividing by their magnitued will
* renormalize them.
*
* Note: See the following for more information on quaternions:
*
* - Shoemake, K., Animating rotation with quaternion curves, Computer
* Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
* - Pletinckx, D., Quaternion calculus as a basic tool in computer
* graphics, The Visual Computer 5, 2-13, 1989.
*/
static void normalize_quat(float q[4]) {
int i;
float mag;
mag = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
for (i = 0; i < 4; i++)
q[i] /= mag;
}
/*
* Build a rotation matrix, given a quaternion rotation.
*
*/
void build_rotmatrix(float m[4][4], const float q[4]) {
m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
m[0][3] = 0.0;
m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
m[1][3] = 0.0;
m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
m[2][3] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
m[3][3] = 1.0;
}

View File

@@ -1,75 +0,0 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* trackball.h
* A virtual trackball implementation
* Written by Gavin Bell for Silicon Graphics, November 1988.
*/
/*
* Pass the x and y coordinates of the last and current positions of
* the mouse, scaled so they are from (-1.0 ... 1.0).
*
* The resulting rotation is returned as a quaternion rotation in the
* first paramater.
*/
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
void negate_quat(float *q, float *qn);
/*
* Given two quaternions, add them together to get a third quaternion.
* Adding quaternions to get a compound rotation is analagous to adding
* translations to get a compound translation. When incrementally
* adding rotations, the first argument here should be the new
* rotation, the second and third the total rotation (which will be
* over-written with the resulting new total rotation).
*/
void add_quats(float *q1, float *q2, float *dest);
/*
* A useful function, builds a rotation matrix in Matrix based on
* given quaternion.
*/
void build_rotmatrix(float m[4][4], const float q[4]);
/*
* This function computes a quaternion based on an axis (defined by
* the given vector) and an angle about which to rotate. The angle is
* expressed in radians. The result is put into the third argument.
*/
void axis_to_quat(float a[3], float phi, float q[4]);

View File

@@ -1,694 +0,0 @@
//
// Simple .obj viewer(vertex only)
//
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <map>
#include <string>
#include <vector>
#include <GL/glew.h>
#ifdef __APPLE__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include <GLFW/glfw3.h>
#define TINYOBJLOADER_IMPLEMENTATION
#include "../../tiny_obj_loader.h"
#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
}
#endif
#pragma comment(lib, "winmm.lib")
#else
#if defined(__unix__) || defined(__APPLE__)
#include <sys/time.h>
#else
#include <ctime>
#endif
#endif
class timerutil {
public:
#ifdef _WIN32
typedef DWORD time_t;
timerutil() { ::timeBeginPeriod(1); }
~timerutil() { ::timeEndPeriod(1); }
void start() { t_[0] = ::timeGetTime(); }
void end() { t_[1] = ::timeGetTime(); }
time_t sec() { return (time_t)((t_[1] - t_[0]) / 1000); }
time_t msec() { return (time_t)((t_[1] - t_[0])); }
time_t usec() { return (time_t)((t_[1] - t_[0]) * 1000); }
time_t current() { return ::timeGetTime(); }
#else
#if defined(__unix__) || defined(__APPLE__)
typedef unsigned long int time_t;
void start() { gettimeofday(tv + 0, &tz); }
void end() { gettimeofday(tv + 1, &tz); }
time_t sec() { return (time_t)(tv[1].tv_sec - tv[0].tv_sec); }
time_t msec() {
return this->sec() * 1000 +
(time_t)((tv[1].tv_usec - tv[0].tv_usec) / 1000);
}
time_t usec() {
return this->sec() * 1000000 + (time_t)(tv[1].tv_usec - tv[0].tv_usec);
}
time_t current() {
struct timeval t;
gettimeofday(&t, NULL);
return (time_t)(t.tv_sec * 1000 + t.tv_usec);
}
#else // C timer
// using namespace std;
typedef clock_t time_t;
void start() { t_[0] = clock(); }
void end() { t_[1] = clock(); }
time_t sec() { return (time_t)((t_[1] - t_[0]) / CLOCKS_PER_SEC); }
time_t msec() { return (time_t)((t_[1] - t_[0]) * 1000 / CLOCKS_PER_SEC); }
time_t usec() { return (time_t)((t_[1] - t_[0]) * 1000000 / CLOCKS_PER_SEC); }
time_t current() { return (time_t)clock(); }
#endif
#endif
private:
#ifdef _WIN32
DWORD t_[2];
#else
#if defined(__unix__) || defined(__APPLE__)
struct timeval tv[2];
struct timezone tz;
#else
time_t t_[2];
#endif
#endif
};
typedef struct {
GLuint vb; // vertex buffer
int numTriangles;
size_t material_id;
} DrawObject;
std::vector<DrawObject> gDrawObjects;
int width = 768;
int height = 768;
double prevMouseX, prevMouseY;
bool mouseLeftPressed;
bool mouseMiddlePressed;
bool mouseRightPressed;
float curr_quat[4];
float prev_quat[4];
float eye[3], lookat[3], up[3];
GLFWwindow* window;
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);
exit(20);
}
}
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];
v10[2] = v1[2] - v0[2];
float v20[3];
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];
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;
}
}
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;
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, 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", (int)tm.msec());
printf("# of vertices = %d\n", (int)(attrib.vertices.size()) / 3);
printf("# of normals = %d\n", (int)(attrib.normals.size()) / 3);
printf("# of texcoords = %d\n", (int)(attrib.texcoords.size()) / 2);
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++) {
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];
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];
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++) {
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]);
// 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);
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;
// 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;
}
static void reshapeFunc(GLFWwindow* window, int w, int h) {
int fb_w, fb_h;
// Get actual framebuffer size.
glfwGetFramebufferSize(window, &fb_w, &fb_h);
glViewport(0, 0, fb_w, fb_h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (float)w / (float)h, 0.01f, 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;
// 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;
}
}
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_MIDDLE) {
if (action == GLFW_PRESS) {
mouseMiddlePressed = true;
} else if (action == GLFW_RELEASE) {
mouseMiddlePressed = false;
}
}
}
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);
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;
}
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);
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);
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
glDisable(GL_POLYGON_OFFSET_FILL);
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);
glColor3f(0.0f, 0.0f, 0.4f);
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);
glDisableClientState(GL_COLOR_ARRAY);
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");
}
}
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) {
std::cout << "Needs input.obj\n" << std::endl;
return 0;
}
Init();
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW." << std::endl;
return -1;
}
window = glfwCreateWindow(width, height, "Obj viewer", NULL, NULL);
if (window == NULL) {
std::cerr << "Failed to open GLFW window. " << std::endl;
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
// Callback
glfwSetWindowSizeCallback(window, reshapeFunc);
glfwSetKeyCallback(window, keyboardFunc);
glfwSetMouseButtonCallback(window, clickFunc);
glfwSetCursorPosCallback(window, motionFunc);
glewExperimental = true;
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialize GLEW." << std::endl;
return -1;
}
reshapeFunc(window, width, height);
float bmin[3], bmax[3];
std::vector<tinyobj::material_t> materials;
std::map<std::string, GLuint> textures;
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, materials, textures, argv[1])) {
return -1;
}
float 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(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]);
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.5 * (bmax[0] + bmin[0]), -0.5 * (bmax[1] + bmin[1]),
-0.5 * (bmax[2] + bmin[2]));
Draw(gDrawObjects, materials, textures);
glfwSwapBuffers(window);
}
glfwTerminate();
}

View File

@@ -1,74 +0,0 @@
#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;
}

View File

@@ -1,26 +0,0 @@
Copyright (c) 2013, Alexander Tretyak
Copyright (c) 2015, r-lyeh
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,5 +0,0 @@
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.

View File

@@ -1,973 +0,0 @@
/*
Copyright (c) 2013, Alexander Tretyak
Copyright (c) 2015, r-lyeh
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Note: The latest version of this memory allocator obtainable at
http://ltalloc.googlecode.com/hg/ltalloc.cc
Project URL: http://code.google.com/p/ltalloc
*/
#include "ltalloc.h"
#define LTALLOC_VERSION "2.0.0" /* (2015/06/16) - ltcalloc(), ltmsize(), ltrealloc(), ltmemalign(), LTALLOC_AUTO_GC_INTERVAL
#define LTALLOC_VERSION "1.0.0" /* (2015/06/16) - standard STL allocator provided [see ltalloc.hpp file](ltalloc.hpp)
#define LTALLOC_VERSION "0.0.0" /* (2013/xx/xx) - fork from public repository */
//Customizable constants
//#define LTALLOC_DISABLE_OPERATOR_NEW_OVERRIDE
//#define LTALLOC_AUTO_GC_INTERVAL 3.0
#ifndef LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO
#define LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO 2//determines how accurately size classes are spaced (i.e. when = 0, allocation requests are rounded up to the nearest power of two (2^n), when = 1, rounded to 2^n, or (2^n)*1.5, when = 2, rounded to 2^n, (2^n)*1.25, (2^n)*1.5, or (2^n)*1.75, and so on); this parameter have direct influence on memory fragmentation - bigger values lead to reducing internal fragmentation (which can be approximately estimated as pow(0.5, VALUE)*100%), but at the same time increasing external fragmentation
#endif
#define CHUNK_SIZE (64*1024)//size of chunk (basic allocation unit for all allocations of size <= MAX_BLOCK_SIZE); must be a power of two (as well as all following parameters), also should not be less than allocation granularity on Windows (which is always 64K by design of NT kernel)
#define CACHE_LINE_SIZE 64
#define MAX_NUM_OF_BLOCKS_IN_BATCH 256//maximum number of blocks to move between a thread cache and a central cache in one shot
static const unsigned int MAX_BATCH_SIZE = 64*1024;//maximum total size of blocks to move between a thread cache and a central cache in one shot (corresponds to half size of thread cache of each size class)
static const unsigned int MAX_BLOCK_SIZE = CHUNK_SIZE;//requesting memory of any size greater than this value will lead to direct call of system virtual memory allocation routine
//Platform-specific stuff
#ifdef __cplusplus
#define CPPCODE(code) code
#include <new>
#else
#define CPPCODE(code)
#endif
#ifdef LTALLOC_AUTO_GC_INTERVAL
#include <time.h>
# if LTALLOC_AUTO_GC_INTERVAL <= 0
# undef LTALLOC_AUTO_GC_INTERVAL
# define LTALLOC_AUTO_GC_INTERVAL 3.00
# endif
#endif
#ifdef __GNUC__
#define __STDC_LIMIT_MACROS
#include <stdint.h> //for SIZE_MAX
#include <limits.h> //for UINT_MAX
#define alignas(a) __attribute__((aligned(a)))
#define thread_local __thread
#define NOINLINE __attribute__((noinline))
#define CAS_LOCK(lock) __sync_lock_test_and_set(lock, 1)
#define SPINLOCK_RELEASE(lock) __sync_lock_release(lock)
#define PAUSE __asm__ __volatile__("pause" ::: "memory")
#define BSR(r, v) r = CODE3264(__builtin_clz(v) ^ 31, __builtin_clzll(v) ^ 63)//x ^ 31 = 31 - x, but gcc does not optimize 31 - __builtin_clz(x) to bsr(x), but generates 31 - (bsr(x) ^ 31)
#elif _MSC_VER
#define _ALLOW_KEYWORD_MACROS
#include <limits.h> //for SIZE_MAX and UINT_MAX
#define alignas(a) __declspec(align(a))
#define thread_local __declspec(thread)
#define NOINLINE __declspec(noinline)
#define CAS_LOCK(lock) _InterlockedExchange((long*)lock, 1)
#define SPINLOCK_RELEASE(lock) _InterlockedExchange((long*)lock, 0)
#define PAUSE _mm_pause()
#define BSR(r, v) CODE3264(_BitScanReverse, _BitScanReverse64)((unsigned long*)&r, v)
CPPCODE(extern "C") long _InterlockedExchange(long volatile *, long);
CPPCODE(extern "C") void _mm_pause();
#pragma warning(disable: 4127 4201 4324 4290)//"conditional expression is constant", "nonstandard extension used : nameless struct/union", and "structure was padded due to __declspec(align())"
#else
#error Unsupported compiler
#endif
#if __GNUC__ || __INTEL_COMPILER
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
static void SPINLOCK_ACQUIRE(volatile int *lock) {if (CAS_LOCK(lock)) while (*lock || CAS_LOCK(lock)) PAUSE;}
#include <assert.h>
#include <string.h> //for memset
#if SIZE_MAX == UINT_MAX
#define CODE3264(c32, c64) c32
#else
#define CODE3264(c32, c64) c64
#endif
typedef char CODE3264_check[sizeof(void*) == CODE3264(4, 8) ? 1 : -1];
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define VMALLOC(size) VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)
#define VMFREE(p, size) VirtualFree(p, 0, MEM_RELEASE)
#else
#include <sys/mman.h>
#include <unistd.h>
#define VMALLOC(size) (void*)(((uintptr_t)mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0)+1)&~1)//with the conversion of MAP_FAILED to 0
#define VMFREE(p, size) munmap(p, size)
static size_t page_size()
{
assert((uintptr_t)MAP_FAILED+1 == 0);//have to use dynamic check somewhere, because some gcc versions (e.g. 4.4.5) won't compile typedef char MAP_FAILED_value_static_check[(uintptr_t)MAP_FAILED+1 == 0 ? 1 : -1];
static size_t pagesize = 0;
if (!pagesize) pagesize = sysconf(_SC_PAGE_SIZE);//assuming that writing of size_t value is atomic, so this can be done safely in different simultaneously running threads
return pagesize;
}
typedef struct PTrieNode // Compressed radix tree (patricia trie) for storing sizes of system allocations
{ // This implementation have some specific properties:
uintptr_t keys[2]; // 1. There are no separate leaf nodes (with both null children), as leaf's value is stored directly in place of corresponding child node pointer. Least significant bit of that pointer used to determine its meaning (i.e., is it a value, or child node pointer).
struct PTrieNode *childNodes[2];// 2. Inserting a new element (key/value) into this tree require to create always an exactly one new node (and similarly for remove key/node operation).
} PTrieNode; // 3. Tree always contains just one node with null child (i.e. all but one nodes in any possible tree are always have two children).
#define PTRIE_NULL_NODE (PTrieNode*)(uintptr_t)1
static PTrieNode *ptrieRoot = PTRIE_NULL_NODE, *ptrieFreeNodesList = NULL, *ptrieNewAllocatedPage = NULL;
static volatile int ptrieLock = 0;
static uintptr_t ptrie_lookup(uintptr_t key)
{
PTrieNode *node = ptrieRoot;
uintptr_t *lastKey = NULL;
while (!((uintptr_t)node & 1))
{
int branch = (key >> (node->keys[0] & 0xFF)) & 1;
lastKey = &node->keys[branch];
node = node->childNodes[branch];
}
assert(lastKey && (*lastKey & ~0xFF) == key);
return (uintptr_t)node & ~1;
}
static void ptrie_insert(uintptr_t key, uintptr_t value, PTrieNode *newNode/* = (PTrieNode*)malloc(sizeof(PTrieNode))*/)
{
PTrieNode **node = &ptrieRoot, *n;
uintptr_t *prevKey = NULL, x, pkey;
unsigned int index, b;
assert(!((value & 1) | (key & 0xFF)));//check constraints for key/value
for (;;)
{
n = *node;
if (!((uintptr_t)n & 1))//not a leaf
{
int prefixEnd = n->keys[0] & 0xFF;
x = key ^ n->keys[0];// & ~0xFF;
if (!(x & (~(uintptr_t)1 << prefixEnd))) {//prefix matches, so go on
int branch = (key >> prefixEnd) & 1;
node = &n->childNodes[branch];
prevKey = &n->keys[branch];
} else {//insert a new node before current
pkey = n->keys[0] & ~0xFF;
break;
}
} else {//leaf
if (*node == PTRIE_NULL_NODE) {
*node = newNode;
newNode->keys[0] = key;//left prefixEnd = 0, so all following insertions will be before this node
newNode->childNodes[0] = (PTrieNode*)(value | 1);
newNode->childNodes[1] = PTRIE_NULL_NODE;
return;
} else {
pkey = *prevKey & ~0xFF;
x = key ^ pkey;
assert(x/*key != pkey*/ && "key already inserted");
break;
}
}
}
BSR(index, x);
b = (key >> index) & 1;
newNode->keys[b] = key;
newNode->keys[b^1] = pkey;
newNode->keys[0] |= index;
newNode->childNodes[b] = (PTrieNode*)(value | 1);
newNode->childNodes[b^1] = n;
*node = newNode;
}
static uintptr_t ptrie_remove(uintptr_t key)
{
PTrieNode **node = &ptrieRoot;
uintptr_t *pkey = NULL;
assert(ptrieRoot != PTRIE_NULL_NODE && "trie is empty!");
for (;;)
{
PTrieNode *n = *node;
int branch = (key >> (n->keys[0] & 0xFF)) & 1;
PTrieNode *cn = n->childNodes[branch];//current child node
if ((uintptr_t)cn & 1)//leaf
{
PTrieNode *other = n->childNodes[branch^1];
assert((n->keys[branch] & ~0xFF) == key);
assert(cn != PTRIE_NULL_NODE && "node's key is probably broken");
// if (other == PTRIE_NULL_NODE) *node = PTRIE_NULL_NODE; else//special handling for null child nodes is not necessary
if (((uintptr_t)other & 1) && other != PTRIE_NULL_NODE)//if other node is not a pointer
*pkey = (n->keys[branch^1] & ~0xFF) | ((*pkey) & 0xFF);
*node = other;
*(PTrieNode**)n = ptrieFreeNodesList; ptrieFreeNodesList = n;//free(n);
return (uintptr_t)cn & ~1;
}
pkey = &n->keys[branch];
node = &n->childNodes[branch];
}
}
#endif
static void *sys_aligned_alloc(size_t alignment, size_t size)
{
void *p = VMALLOC(size);//optimistically try mapping precisely the right amount before falling back to the slow method
assert(!(alignment & (alignment-1)) && "alignment must be a power of two");
if ((uintptr_t)p & (alignment-1)/* && p != MAP_FAILED*/)
{
VMFREE(p, size);
#ifdef _WIN32
{static DWORD allocationGranularity = 0;
if (!allocationGranularity) {
SYSTEM_INFO si;
GetSystemInfo(&si);
allocationGranularity = si.dwAllocationGranularity;
}
if ((uintptr_t)p < 16*1024*1024)//fill "bubbles" (reserve unaligned regions) at the beginning of virtual address space, otherwise there will be always falling back to the slow method
VirtualAlloc(p, alignment - ((uintptr_t)p & (alignment-1)), MEM_RESERVE, PAGE_NOACCESS);
do
{
p = VirtualAlloc(NULL, size + alignment - allocationGranularity, MEM_RESERVE, PAGE_NOACCESS);
if (p == NULL) return NULL;
VirtualFree(p, 0, MEM_RELEASE);//unfortunately, WinAPI doesn't support release a part of allocated region, so release a whole region
p = VirtualAlloc((void*)(((uintptr_t)p + (alignment-1)) & ~(alignment-1)), size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
} while (p == NULL);}
#else
p = VMALLOC(size + alignment - page_size());
if (p/* != MAP_FAILED*/)
{
uintptr_t ap = ((uintptr_t)p + (alignment-1)) & ~(alignment-1);
uintptr_t diff = ap - (uintptr_t)p;
if (diff) VMFREE(p, diff);
diff = alignment - page_size() - diff;
assert((intptr_t)diff >= 0);
if (diff) VMFREE((void*)(ap + size), diff);
return (void*)ap;
}
#endif
}
//if (p == 0) p = sys_aligned_alloc(alignment, size);//just in case (because 0 pointer is handled specially elsewhere)
//if (p == MAP_FAILED) p = NULL;
return p;
}
static NOINLINE void sys_free(void *p)
{
if (p == NULL) return;
#ifdef _WIN32
VirtualFree(p, 0, MEM_RELEASE);
#else
SPINLOCK_ACQUIRE(&ptrieLock);
size_t size = ptrie_remove((uintptr_t)p);
SPINLOCK_RELEASE(&ptrieLock);
munmap(p, size);
#endif
}
static void release_thread_cache(void*);
#ifdef __GNUC__
#include <pthread.h>
#pragma weak pthread_once
#pragma weak pthread_key_create
#pragma weak pthread_setspecific
static pthread_key_t pthread_key;
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
static void init_pthread_key() { pthread_key_create(&pthread_key, release_thread_cache); }
static thread_local int thread_initialized = 0;
static void init_pthread_destructor()//must be called only when some block placed into a thread cache's free list
{
if (unlikely(!thread_initialized))
{
thread_initialized = 1;
if (pthread_once)
{
pthread_once(&init_once, init_pthread_key);
pthread_setspecific(pthread_key, (void*)1);//set nonzero value to force calling of release_thread_cache() on thread terminate
}
}
}
#else
static void NTAPI on_tls_callback(PVOID h, DWORD reason, PVOID pv) { h; pv; if (reason == DLL_THREAD_DETACH) release_thread_cache(0); }
#pragma comment(linker, "/INCLUDE:" CODE3264("_","") "p_thread_callback_ltalloc")
#pragma const_seg(".CRT$XLL")
extern CPPCODE("C") const PIMAGE_TLS_CALLBACK p_thread_callback_ltalloc = on_tls_callback;
#pragma const_seg()
#define init_pthread_destructor()
#endif
//End of platform-specific stuff
#define MAX_BLOCK_SIZE (MAX_BLOCK_SIZE < CHUNK_SIZE - (CHUNK_SIZE >> (1 + LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)) ? \
MAX_BLOCK_SIZE : CHUNK_SIZE - (CHUNK_SIZE >> (1 + LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)))
#define NUMBER_OF_SIZE_CLASSES ((sizeof(void*)*8 + 1) << LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)
typedef struct FreeBlock
{
struct FreeBlock *next,
*nextBatch;//in the central cache blocks are organized into batches to allow fast moving blocks from thread cache and back
} FreeBlock;
typedef struct alignas(CACHE_LINE_SIZE) ChunkBase//force sizeof(Chunk) = cache line size to avoid false sharing
{
unsigned int sizeClass;
} Chunk;
typedef struct alignas(CACHE_LINE_SIZE) ChunkSm//chunk of smallest blocks of size = sizeof(void*)
{
unsigned int sizeClass;//struct ChunkBase chunk;
struct ChunkSm *prev, *next;
int numBatches;
#define NUM_OF_BATCHES_IN_CHUNK_SM CHUNK_SIZE/(sizeof(void*)*MAX_NUM_OF_BLOCKS_IN_BATCH)
FreeBlock *batches[NUM_OF_BATCHES_IN_CHUNK_SM];//batches of blocks inside ChunkSm have to be stored separately (as smallest blocks of size = sizeof(void*) do not have enough space to store second pointer for the batch)
} ChunkSm;
typedef struct alignas(CACHE_LINE_SIZE)//align needed to prevent cache line sharing between adjacent classes accessed from different threads
{
volatile int lock;
unsigned int freeBlocksInLastChunk;
char *lastChunk;//Chunk or ChunkSm
union {
FreeBlock *firstBatch;
ChunkSm *chunkWithFreeBatches;
};
FreeBlock *freeList;//short list of free blocks that for some reason are not organized into batches
unsigned int freeListSize;//should be less than batch size
uintptr_t minChunkAddr, maxChunkAddr;
} CentralCache;
static CentralCache centralCache[NUMBER_OF_SIZE_CLASSES];// = {{0}};
typedef struct
{
FreeBlock *freeList;
FreeBlock *tempList;//intermediate list providing a hysteresis in order to avoid a corner case of too frequent moving free blocks to the central cache and back from
int counter;//number of blocks in freeList (used to determine when to move free blocks list to the central cache)
} ThreadCache;
static thread_local ThreadCache threadCache[NUMBER_OF_SIZE_CLASSES];// = {{0}};
static struct
{
volatile int lock;
void *freeChunk;
size_t size;
} pad = {0, NULL, 0};
static CPPCODE(inline) unsigned int get_size_class(size_t size)
{
unsigned int index;
#if _MSC_VER && LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO == 2
static const unsigned char small_size_classes[256] = {//have to use a const array here, because MS compiler unfortunately does not evaluate _BitScanReverse with a constant argument at compile time (as gcc does for __builtin_clz)
#if CODE3264(1, 0)
131, 4, 15, 17, 19, 20, 21, 22, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43
#else
131, 15, 19, 21, 23, 24, 25, 26, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47
#endif
};
if (size < 256 * sizeof(void*) - (sizeof(void*)-1))
return small_size_classes[(size + (sizeof(void*)-1)) / sizeof(void*)];
#endif
size = (size + (sizeof(void*)-1)) & ~(sizeof(void*)-1);//minimum block size is sizeof(void*), doing this is better than just "size = max(size, sizeof(void*))"
BSR(index, (size-1)|1);//"|1" needed because result of BSR is undefined for zero input
#if LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO == 0
return index;
#else
return (index<<LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO) + (unsigned int)((size-1) >> (index-LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO));
#endif
}
static unsigned int class_to_size(unsigned int c)
{
#if LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO == 0
return 2 << c;
#else
#if LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO >= CODE3264(2, 3)
if (unlikely(c < (LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO<<LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)))//for block sizes less than or equal to pow(2, LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)
return 2 << (c>>LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO);
else
#endif
{
c -= (1<<LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)-1;
return ((c & ((1<<LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)-1)) | (1<<LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)) << ((c>>LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)-LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO);
}
#endif
}
static unsigned int batch_size(unsigned int sizeClass)//calculates a number of blocks to move between a thread cache and a central cache in one shot
{
return ((MAX_BATCH_SIZE-1) >> (sizeClass >> LTALLOC_SIZE_CLASSES_SUBPOWER_OF_TWO)) & (MAX_NUM_OF_BLOCKS_IN_BATCH-1);
}
CPPCODE(template <bool> static) void *ltmalloc(size_t size);
CPPCODE(template <bool throw_>) static void *fetch_from_central_cache(size_t size, ThreadCache *tc, unsigned int sizeClass)
{
void *p;
if (likely(size-1u <= MAX_BLOCK_SIZE-1u))//<=> if (size <= MAX_BLOCK_SIZE && size != 0)
{
FreeBlock *fb = tc->tempList;
if (fb)
{
assert(tc->counter == (int)batch_size(sizeClass)+1);
tc->counter = 1;
tc->freeList = fb->next;
tc->tempList = NULL;
return fb;
}
assert(tc->counter == 0 || tc->counter == (int)batch_size(sizeClass)+1);
tc->counter = 1;
{CentralCache *cc = &centralCache[sizeClass];
SPINLOCK_ACQUIRE(&cc->lock);
if (unlikely(!cc->firstBatch))//no free batch
{no_free_batch:{
unsigned int batchSize = batch_size(sizeClass)+1;
if (cc->freeList)
{
assert(cc->freeListSize);
if (likely(cc->freeListSize <= batchSize + 1))
{
tc->counter = batchSize - cc->freeListSize + 1;
// batchSize = cc->freeListSize;
cc->freeListSize = 0;
fb = cc->freeList;
cc->freeList = NULL;
}
else
{
cc->freeListSize -= batchSize;
fb = cc->freeList;
{FreeBlock *b = cc->freeList;
while (--batchSize) b = b->next;
cc->freeList = b->next;
b->next = NULL;}
}
SPINLOCK_RELEASE(&cc->lock);
tc->freeList = fb->next;
init_pthread_destructor();//this call must be placed carefully to allow recursive memory allocation from pthread_key_create (in case when ltalloc replaces the system malloc)
return fb;
}
{unsigned int blockSize = class_to_size(sizeClass);
if (cc->freeBlocksInLastChunk)
{
char *firstFree = cc->lastChunk;
assert(cc->lastChunk && cc->freeBlocksInLastChunk == (CHUNK_SIZE - ((uintptr_t)cc->lastChunk & (CHUNK_SIZE-1)))/blockSize);
if (cc->freeBlocksInLastChunk < batchSize) {
tc->counter = batchSize - cc->freeBlocksInLastChunk + 1;
batchSize = cc->freeBlocksInLastChunk;
}
cc->freeBlocksInLastChunk -= batchSize;
cc->lastChunk += blockSize * batchSize;
if (cc->freeBlocksInLastChunk == 0) {
assert(((uintptr_t)cc->lastChunk & (CHUNK_SIZE-1)) == 0);
cc->lastChunk = ((char**)cc->lastChunk)[-1];
if (cc->lastChunk)
cc->freeBlocksInLastChunk = (CHUNK_SIZE - ((uintptr_t)cc->lastChunk & (CHUNK_SIZE-1)))/blockSize;
}
SPINLOCK_RELEASE(&cc->lock);
fb = (FreeBlock*)firstFree;
while (--batchSize)
firstFree = (char*)(((FreeBlock*)firstFree)->next = (FreeBlock*)(firstFree + blockSize));
((FreeBlock*)firstFree)->next = NULL;
tc->freeList = fb->next;
init_pthread_destructor();
return fb;
}
//Allocate new chunk
SPINLOCK_RELEASE(&cc->lock);//release lock for a while
SPINLOCK_ACQUIRE(&pad.lock);
if (pad.freeChunk)
{
p = pad.freeChunk;
pad.freeChunk = *(void**)p;
pad.size -= CHUNK_SIZE;
SPINLOCK_RELEASE(&pad.lock);
((char**)((char*)p + CHUNK_SIZE))[-1] = 0;
} else {
SPINLOCK_RELEASE(&pad.lock);
p = sys_aligned_alloc(CHUNK_SIZE, CHUNK_SIZE);
if (unlikely(!p)) { CPPCODE(if (throw_) throw std::bad_alloc(); else) return NULL; }
}
#define CHUNK_IS_SMALL unlikely(sizeClass < get_size_class(2*sizeof(void*)))
{unsigned int numBlocksInChunk = (CHUNK_SIZE - (CHUNK_IS_SMALL ? sizeof(ChunkSm) : sizeof(Chunk)))/blockSize;
#ifndef _WIN32
//intptr_t sz = ((CHUNK_SIZE - numBlocksInChunk*blockSize) & ~(page_size()-1)) - page_size();
//if (sz > 0) mprotect((char*)p + page_size(), sz, PROT_NONE);//munmap((char*)p + page_size(), sz);//to make possible unmapping, we need to be more careful when returning memory to the system, not simply VMFREE(firstFreeChunk, CHUNK_SIZE), so let there be just mprotect
#endif
assert(((char**)((char*)p + CHUNK_SIZE))[-1] == 0);//assume that allocated memory is always zero filled (on first access); it is better not to zero it explicitly because it will lead to allocation of physical page which may never needed otherwise
if (numBlocksInChunk < batchSize) {
tc->counter = batchSize - numBlocksInChunk + 1;
batchSize = numBlocksInChunk;
}
//Prepare chunk
((Chunk*)p)->sizeClass = sizeClass;
{char *firstFree = (char*)p + CHUNK_SIZE - numBlocksInChunk*blockSize;//blocks in chunk are located in such way to achieve a maximum possible alignment
fb = (FreeBlock*)firstFree;
{int n = batchSize; while (--n)
firstFree = (char*)(((FreeBlock*)firstFree)->next = (FreeBlock*)(firstFree + blockSize));}
((FreeBlock*)firstFree)->next = NULL;
firstFree += blockSize;
SPINLOCK_ACQUIRE(&cc->lock);
if ((uintptr_t)p < cc->minChunkAddr || !cc->minChunkAddr) cc->minChunkAddr = (uintptr_t)p;
if ((uintptr_t)p > cc->maxChunkAddr ) cc->maxChunkAddr = (uintptr_t)p;
if (CHUNK_IS_SMALL)//special handling for smallest blocks of size = sizeof(void*)
{
ChunkSm *cs = (ChunkSm*)p;
cs->numBatches = 0;
//Insert new chunk right after chunkWithFreeBatches
cs->prev = cc->chunkWithFreeBatches;
if (cc->chunkWithFreeBatches) {
cs->next = cc->chunkWithFreeBatches->next;
if (cc->chunkWithFreeBatches->next) cc->chunkWithFreeBatches->next->prev = cs;
cc->chunkWithFreeBatches->next = cs;
} else {
cs->next = NULL;
cc->chunkWithFreeBatches = cs;
}
}
if (unlikely(cc->freeBlocksInLastChunk))//so happened that other thread have already allocated chunk for the same size class while the lock was released
{
//Hook pointer to the current lastChunk at the end of new chunk (another way is just put all blocks to cc->freeList which is much less effecient)
((char**)(((uintptr_t)firstFree & ~(CHUNK_SIZE-1)) + CHUNK_SIZE))[-1] = cc->lastChunk;
}
cc->freeBlocksInLastChunk = numBlocksInChunk - batchSize;
cc->lastChunk = firstFree;
}}}}}
else {
if (!CHUNK_IS_SMALL)//smallest blocks of size = sizeof(void*) are handled specially
{
fb = cc->firstBatch;
cc->firstBatch = fb->nextBatch;
}
else//size of block = sizeof(void*)
{
ChunkSm *cs = cc->chunkWithFreeBatches;
if (unlikely(cs->numBatches == 0))
{
if (unlikely(cs->prev == NULL)) goto no_free_batch;
cs = cc->chunkWithFreeBatches = cs->prev;
assert(cs->numBatches == NUM_OF_BATCHES_IN_CHUNK_SM);
}
fb = cs->batches[--cs->numBatches];
}
}
SPINLOCK_RELEASE(&cc->lock);}
tc->freeList = fb->next;
init_pthread_destructor();
return fb;
}
else//allocate block directly from the system
{
if (unlikely(size == 0)) return ltmalloc CPPCODE(<throw_>)(1);//return NULL;//doing this check here is better than on the top level
size = (size + CHUNK_SIZE-1) & ~(CHUNK_SIZE-1);
p = sys_aligned_alloc(CHUNK_SIZE, size);
#ifndef _WIN32
if (p) {
SPINLOCK_ACQUIRE(&ptrieLock);
PTrieNode *newNode;
if (ptrieFreeNodesList)
ptrieFreeNodesList = *(PTrieNode**)(newNode = ptrieFreeNodesList);
else if (ptrieNewAllocatedPage) {
newNode = ptrieNewAllocatedPage;
if (!((uintptr_t)++ptrieNewAllocatedPage & (page_size()-1)))
ptrieNewAllocatedPage = ((PTrieNode**)ptrieNewAllocatedPage)[-1];
} else {
SPINLOCK_RELEASE(&ptrieLock);
newNode = (PTrieNode*)VMALLOC(page_size());
if (unlikely(!newNode)) { CPPCODE(if (throw_) throw std::bad_alloc(); else) return NULL; }
assert(((char**)((char*)newNode + page_size()))[-1] == 0);
SPINLOCK_ACQUIRE(&ptrieLock);
((PTrieNode**)((char*)newNode + page_size()))[-1] = ptrieNewAllocatedPage;//in case if other thread also have just allocated a new page
ptrieNewAllocatedPage = newNode + 1;
}
ptrie_insert((uintptr_t)p, size, newNode);
SPINLOCK_RELEASE(&ptrieLock);
}
#endif
CPPCODE(if (throw_) if (unlikely(!p)) throw std::bad_alloc();)
return p;
}
}
CPPCODE(template <bool throw_> static) void *ltmalloc(size_t size)
{
unsigned int sizeClass = get_size_class(size);
ThreadCache *tc = &threadCache[sizeClass];
FreeBlock *fb = tc->freeList;
if (likely(fb))
{
tc->freeList = fb->next;
tc->counter++;
return fb;
}
else
return fetch_from_central_cache CPPCODE(<throw_>)(size, tc, sizeClass);
}
CPPCODE(void *ltmalloc(size_t size) {return ltmalloc<false>(size);})//for possible external usage
static void add_batch_to_central_cache(CentralCache *cc, unsigned int sizeClass, FreeBlock *batch)
{
if (!CHUNK_IS_SMALL)
{
batch->nextBatch = cc->firstBatch;
cc->firstBatch = batch;
}
else
{
ChunkSm *cs = cc->chunkWithFreeBatches;
if (unlikely(cs->numBatches == NUM_OF_BATCHES_IN_CHUNK_SM))
{
cs = cc->chunkWithFreeBatches = cc->chunkWithFreeBatches->next;
assert(cs && cs->numBatches == 0);
}
cs->batches[cs->numBatches++] = batch;
}
}
static NOINLINE void move_to_central_cache(ThreadCache *tc, unsigned int sizeClass)
{
init_pthread_destructor();//needed for cases when freed memory was allocated in the other thread and no alloc was called in this thread till its termination
tc->counter = batch_size(sizeClass);
if (tc->tempList)//move temp list to the central cache
{
CentralCache *cc = &centralCache[sizeClass];
SPINLOCK_ACQUIRE(&cc->lock);
add_batch_to_central_cache(cc, sizeClass, tc->tempList);
SPINLOCK_RELEASE(&cc->lock);
}
// else if (unlikely(!tc->freeList))//this is a first call (i.e. when counter = 0) - just initialization of counter needed
// {
// tc->counter--;
// return;
// }
tc->tempList = tc->freeList;
tc->freeList = NULL;
}
void ltfree(void *p)
{
if (likely((uintptr_t)p & (CHUNK_SIZE-1)))
{
unsigned int sizeClass = ((Chunk*)((uintptr_t)p & ~(CHUNK_SIZE-1)))->sizeClass;
ThreadCache *tc = &threadCache[sizeClass];
if (unlikely(--tc->counter < 0))
move_to_central_cache(tc, sizeClass);
((FreeBlock*)p)->next = tc->freeList;
tc->freeList = (FreeBlock*)p;
}
else
sys_free(p);
}
size_t ltmsize(void *p)
{
if (likely((uintptr_t)p & (CHUNK_SIZE-1)))
{
return class_to_size(((Chunk*)((uintptr_t)p & ~(CHUNK_SIZE-1)))->sizeClass);
}
else
{
if (p == NULL) return 0;
#ifdef _WIN32
{MEMORY_BASIC_INFORMATION mi;
VirtualQuery(p, &mi, sizeof(mi));
return mi.RegionSize;}
#else
SPINLOCK_ACQUIRE(&ptrieLock);
size_t size = ptrie_lookup((uintptr_t)p);
SPINLOCK_RELEASE(&ptrieLock);
return size;
#endif
}
}
static void release_thread_cache(void *p)
{
unsigned int sizeClass = 0; (void)p;
for (;sizeClass < NUMBER_OF_SIZE_CLASSES; sizeClass++)
{
ThreadCache *tc = &threadCache[sizeClass];
if (tc->freeList || tc->tempList)
{
FreeBlock *tail = tc->freeList;
unsigned int freeListSize = 1;
CentralCache *cc = &centralCache[sizeClass];
if (tail)
while (tail->next)//search for end of list
tail = tail->next, freeListSize++;
SPINLOCK_ACQUIRE(&cc->lock);
if (tc->tempList)
add_batch_to_central_cache(cc, sizeClass, tc->tempList);
if (tc->freeList) {//append tc->freeList to cc->freeList
tail->next = cc->freeList;
cc->freeList = tc->freeList;
assert(freeListSize == batch_size(sizeClass)+1 - tc->counter);
cc->freeListSize += freeListSize;
}
SPINLOCK_RELEASE(&cc->lock);
}
}
}
void ltsqueeze(size_t padsz)
{
unsigned int sizeClass = get_size_class(2*sizeof(void*));//skip small chunks because corresponding batches can not be efficiently detached from the central cache (if that becomes relevant, may be it worths to reimplement batches for small chunks from array to linked lists)
for (;sizeClass < NUMBER_OF_SIZE_CLASSES; sizeClass++)
{
CentralCache *cc = &centralCache[sizeClass];
if (cc->maxChunkAddr - cc->minChunkAddr <= CHUNK_SIZE)//preliminary check without lock (assume that writing to minChunkAddr/maxChunkAddr is atomic)
continue;
SPINLOCK_ACQUIRE(&cc->lock);
if (cc->maxChunkAddr - cc->minChunkAddr <= CHUNK_SIZE) {//quick check for theoretical possibility that at least one chunk is totally free
SPINLOCK_RELEASE(&cc->lock);
continue;
}
{uintptr_t minChunkAddr = cc->minChunkAddr;
size_t bufferSize = ((cc->maxChunkAddr - minChunkAddr) / CHUNK_SIZE + 1) * sizeof(short);
//Quickly detach all batches of the current size class from the central cache
unsigned int freeListSize = cc->freeListSize;
FreeBlock *firstBatch = cc->firstBatch, *freeList = cc->freeList;
cc->firstBatch = NULL;
cc->freeList = NULL;
cc->freeListSize = 0;
SPINLOCK_RELEASE(&cc->lock);
//1. Find out chunks with only free blocks via a simple counting the number of free blocks in each chunk
{char buffer[32*1024];//enough for 1GB address space
unsigned short *inChunkFreeBlocks = (unsigned short*)(bufferSize <= sizeof(buffer) ? memset(buffer, 0, bufferSize) : VMALLOC(bufferSize));
unsigned int numBlocksInChunk = (CHUNK_SIZE - (/*CHUNK_IS_SMALL ? sizeof(ChunkSm) : */sizeof(Chunk)))/class_to_size(sizeClass);
FreeBlock **pbatch, *block, **pblock;
Chunk *firstFreeChunk = NULL;
assert(numBlocksInChunk < (1U<<(sizeof(short)*8)));//in case if CHUNK_SIZE is too big that total count of blocks in it doesn't fit at short type (...may be use static_assert instead?)
if (inChunkFreeBlocks)//consider VMALLOC can fail
{
for (pbatch = &firstBatch; *pbatch; pbatch = &(*pbatch)->nextBatch)
for (block = *pbatch; block; block = block->next)
#define FREE_BLOCK(block) \
if (++inChunkFreeBlocks[((uintptr_t)block - minChunkAddr) / CHUNK_SIZE] == numBlocksInChunk)/*chunk is totally free*/\
{\
Chunk *chunk = (Chunk*)((uintptr_t)block & ~(CHUNK_SIZE-1));\
assert(chunk->sizeClass == sizeClass);/*just in case check before overwriting this info*/\
*(Chunk**)chunk = firstFreeChunk;/*put nextFreeChunk pointer right at the beginning of Chunk as there are always must be a space for one pointer before first memory block*/\
firstFreeChunk = chunk;\
}
FREE_BLOCK(block)
for (pblock = &freeList; *pblock; pblock = &(*pblock)->next)
FREE_BLOCK(*pblock)
#undef FREE_BLOCK
}
else {
for (pbatch = &firstBatch; *pbatch; pbatch = &(*pbatch)->nextBatch);
for (pblock = &freeList; *pblock; pblock = &(*pblock)->next);
}
if (firstFreeChunk)//is anything to release
{
//2. Unlink all matching blocks from the corresponding free lists
FreeBlock *additionalBatchesList = NULL, *additionalBlocksList = NULL, **abatch = &additionalBatchesList, **ablock = &additionalBlocksList;
unsigned int additionalBlocksListSize = 0, batchSize = batch_size(sizeClass)+1;
for (pbatch = &firstBatch; *pbatch;)
{
for (block = *pbatch; block; block = block->next)
if (inChunkFreeBlocks[((uintptr_t)block - minChunkAddr) / CHUNK_SIZE] == numBlocksInChunk)//if at least one block belongs to a releasable chunk, then this batch should be handled specially
{
FreeBlock *nextBatch = (*pbatch)->nextBatch;
for (block = *pbatch; block;)//re-add blocks of not-for-release chunks and organize them into another batches' list (to join it with the main later)
if (inChunkFreeBlocks[((uintptr_t)block - minChunkAddr) / CHUNK_SIZE] != numBlocksInChunk)//skip matching-for-release blocks
{
*ablock = block;
do//this loop needed only to minimize memory write operations, otherwise a simpler approach could be used (like in the next loop below)
{
ablock = &block->next;
block = block->next;
if (++additionalBlocksListSize == batchSize)
{
abatch = &(*abatch = additionalBlocksList)->nextBatch;
*abatch = NULL;
*ablock = NULL;
ablock = &additionalBlocksList;
additionalBlocksList = NULL;
additionalBlocksListSize = 0;
break;//to force *ablock = block; for starting a new batch
}
} while (block && inChunkFreeBlocks[((uintptr_t)block - minChunkAddr) / CHUNK_SIZE] != numBlocksInChunk);
}
else
block = block->next;
*ablock = NULL;
*pbatch = nextBatch;//unlink batch
goto continue_;
}
pbatch = &(*pbatch)->nextBatch;
continue_:;
}
for (block = freeList; block;)
if (inChunkFreeBlocks[((uintptr_t)block - minChunkAddr) / CHUNK_SIZE] != numBlocksInChunk)
{
//*pblock = (*pblock)->next, freeListSize--;//unlink block
ablock = &(*ablock = block)->next;
block = block->next;
*ablock = NULL;
if (++additionalBlocksListSize == batchSize)
{
abatch = &(*abatch = additionalBlocksList)->nextBatch;
*abatch = NULL;
ablock = &additionalBlocksList;
additionalBlocksList = NULL;
additionalBlocksListSize = 0;
}
}
else
block = block->next;
//Add additional lists
*abatch = *pbatch;
*pbatch = additionalBatchesList;
pblock = ablock;
freeList = additionalBlocksList;
freeListSize = additionalBlocksListSize;
//Return back all left not-for-release blocks to the central cache as quickly as possible (as other threads may want to allocate a new memory)
#define GIVE_LISTS_BACK_TO_CC \
SPINLOCK_ACQUIRE(&cc->lock);\
*pbatch = cc->firstBatch;\
cc->firstBatch = firstBatch;\
*pblock = cc->freeList;\
cc->freeList = freeList;\
cc->freeListSize += freeListSize;\
SPINLOCK_RELEASE(&cc->lock);\
if (bufferSize > sizeof(buffer)) VMFREE(inChunkFreeBlocks, bufferSize);//this better to do before 3. as kernel is likely optimized for release of just allocated range
GIVE_LISTS_BACK_TO_CC
if (padsz)
{
SPINLOCK_ACQUIRE(&pad.lock);
if (pad.size < padsz)
{
Chunk *first = firstFreeChunk, **c;
do//put off free chunks up to a specified pad size
{
c = (Chunk**)firstFreeChunk;
firstFreeChunk = *c;
pad.size += CHUNK_SIZE;
} while (pad.size < padsz && firstFreeChunk);
*c = (Chunk*)pad.freeChunk;
pad.freeChunk = first;
}
SPINLOCK_RELEASE(&pad.lock);
}
//3. Return memory to the system
while (firstFreeChunk)
{
Chunk *nextFreeChunk = *(Chunk**)firstFreeChunk;
VMFREE(firstFreeChunk, CHUNK_SIZE);
firstFreeChunk = nextFreeChunk;
}
}
else//nothing to release - just return batches back to the central cache
{
GIVE_LISTS_BACK_TO_CC
#undef GIVE_LISTS_BACK_TO_CC
}}}
}
}
#if defined(__cplusplus) && !defined(LTALLOC_DISABLE_OPERATOR_NEW_OVERRIDE)
void *operator new (size_t size) throw(std::bad_alloc) {return ltmalloc<true> (size);}
void *operator new (size_t size, const std::nothrow_t&) throw() {return ltmalloc<false>(size);}
void *operator new[](size_t size) throw(std::bad_alloc) {return ltmalloc<true> (size);}
void *operator new[](size_t size, const std::nothrow_t&) throw() {return ltmalloc<false>(size);}
void operator delete (void* p) throw() {ltfree(p);}
void operator delete (void* p, const std::nothrow_t&) throw() {ltfree(p);}
void operator delete[](void* p) throw() {ltfree(p);}
void operator delete[](void* p, const std::nothrow_t&) throw() {ltfree(p);}
#endif
/* @r-lyeh's { */
#include <string.h>
void *ltcalloc(size_t elems, size_t size) {
size *= elems;
return memset( ltmalloc( size ), 0, size );
}
void *ltmemalign( size_t align, size_t size ) {
return --align, ltmalloc( (size+align)&~align );
}
void *ltrealloc( void *ptr, size_t sz ) {
if( !ptr ) return ltmalloc( sz );
if( !sz ) return ltfree( ptr ), (void *)0;
size_t osz = ltmsize( ptr );
if( sz <= osz ) {
return ptr;
}
void *nptr = memcpy( ltmalloc(sz), ptr, osz );
ltfree( ptr );
#ifdef LTALLOC_AUTO_GC_INTERVAL
/* this is kind of compromise; the following timer is to guarantee
that memory gets wiped out at least every given seconds between consecutive
ltrealloc() calls (I am assuming frequency usage for ltrealloc() is smaller
than ltmalloc() or ltfree() too) - @r-lyeh */
clock_t now = clock();
static clock_t then = now;
if( ( double(now - then) / CLOCKS_PER_SEC ) > LTALLOC_AUTO_GC_INTERVAL ) {
ltsqueeze(0);
}
then = now;
#endif
return nptr;
}
/* } */

View File

@@ -1,14 +0,0 @@
#include <stdlib.h> /*a more portable size_t definition than stddef.h itself*/
#ifdef __cplusplus
extern "C" {
#endif
void* ltmalloc(size_t);
void ltfree(void*);
void* ltrealloc( void *, size_t );
void* ltcalloc( size_t, size_t );
void* ltmemalign( size_t, size_t );
void ltsqueeze(size_t pad); /*return memory to system (see README.md)*/
size_t ltmsize(void*);
#ifdef __cplusplus
}
#endif

View File

@@ -1,59 +0,0 @@
// based on code by Jerry Coffin (most likely Public Domain)
// - rlyeh
#pragma once
#include <stdlib.h>
#include <new>
#include <limits>
#include "ltalloc.h"
namespace lt {
template <class T>
struct allocator {
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef allocator<U> other; };
allocator() throw() {}
allocator(const allocator&) throw() {}
template <class U> allocator(const allocator<U>&) throw(){}
~allocator() throw() {}
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
pointer allocate(size_type s, void const * = 0) {
if (0 == s)
return NULL;
pointer temp = (pointer)ltmalloc(s * sizeof(T));
if (temp == NULL)
throw std::bad_alloc();
return temp;
}
void deallocate(pointer p, size_type) {
ltfree(p);
}
size_type max_size() const throw() {
return std::numeric_limits<size_t>::max() / sizeof(T);
}
void construct(pointer p, const T& val) {
new((void *)p) T(val);
}
void destroy(pointer p) {
p->~T();
}
};
}

View File

@@ -1,74 +0,0 @@
newoption {
trigger = "with-zlib",
description = "Build with zlib."
}
newoption {
trigger = "with-zstd",
description = "Build with ZStandard compression."
}
solution "objview"
-- location ( "build" )
configurations { "Release", "Debug" }
platforms {"native", "x64", "x32"}
project "objview"
kind "ConsoleApp"
language "C++"
files { "viewer.cc", "trackball.cc", "ltalloc.cc" }
includedirs { "./" }
includedirs { "../../" }
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" }
configuration { "linux" }
linkoptions { "`pkg-config --libs glfw3`" }
links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" }
linkoptions { "-pthread" }
configuration { "windows" }
-- Path to GLFW3
includedirs { '../../../../local/glfw-3.1.2.bin.WIN64/include' }
libdirs { '../../../../local/glfw-3.1.2.bin.WIN64/lib-vc2013' }
-- Path to GLEW
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" }
configuration { "macosx" }
includedirs { "/usr/local/include" }
buildoptions { "-Wno-deprecated-declarations" }
libdirs { "/usr/local/lib" }
links { "glfw3", "GLEW" }
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" }
configuration "Debug"
defines { "DEBUG" }
flags { "Symbols"}
configuration "Release"
defines { "NDEBUG" }
flags { "Optimize"}

File diff suppressed because it is too large Load Diff

View File

@@ -1,292 +0,0 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* Trackball code:
*
* Implementation of a virtual trackball.
* Implemented by Gavin Bell, lots of ideas from Thant Tessman and
* the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
*
* Vector manip code:
*
* Original code from:
* David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
*
* Much mucking with by:
* Gavin Bell
*/
#include <math.h>
#include "trackball.h"
/*
* This size should really be based on the distance from the center of
* rotation to the point on the object underneath the mouse. That
* point would then track the mouse as closely as possible. This is a
* simple example, though, so that is left as an Exercise for the
* Programmer.
*/
#define TRACKBALLSIZE (0.8)
/*
* Local function prototypes (not defined in trackball.h)
*/
static float tb_project_to_sphere(float, float, float);
static void normalize_quat(float[4]);
static void vzero(float *v) {
v[0] = 0.0;
v[1] = 0.0;
v[2] = 0.0;
}
static void vset(float *v, float x, float y, float z) {
v[0] = x;
v[1] = y;
v[2] = z;
}
static void vsub(const float *src1, const float *src2, float *dst) {
dst[0] = src1[0] - src2[0];
dst[1] = src1[1] - src2[1];
dst[2] = src1[2] - src2[2];
}
static void vcopy(const float *v1, float *v2) {
int i;
for (i = 0; i < 3; i++)
v2[i] = v1[i];
}
static void vcross(const float *v1, const float *v2, float *cross) {
float temp[3];
temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
vcopy(temp, cross);
}
static float vlength(const float *v) {
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
static void vscale(float *v, float div) {
v[0] *= div;
v[1] *= div;
v[2] *= div;
}
static void vnormal(float *v) { vscale(v, 1.0 / vlength(v)); }
static float vdot(const float *v1, const float *v2) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
static void vadd(const float *src1, const float *src2, float *dst) {
dst[0] = src1[0] + src2[0];
dst[1] = src1[1] + src2[1];
dst[2] = src1[2] + src2[2];
}
/*
* Ok, simulate a track-ball. Project the points onto the virtual
* trackball, then figure out the axis of rotation, which is the cross
* product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
* Note: This is a deformed trackball-- is a trackball in the center,
* but is deformed into a hyperbolic sheet of rotation away from the
* center. This particular function was chosen after trying out
* several variations.
*
* It is assumed that the arguments to this routine are in the range
* (-1.0 ... 1.0)
*/
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y) {
float a[3]; /* Axis of rotation */
float phi; /* how much to rotate about axis */
float p1[3], p2[3], d[3];
float t;
if (p1x == p2x && p1y == p2y) {
/* Zero rotation */
vzero(q);
q[3] = 1.0;
return;
}
/*
* First, figure out z-coordinates for projection of P1 and P2 to
* deformed sphere
*/
vset(p1, p1x, p1y, tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y));
vset(p2, p2x, p2y, tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y));
/*
* Now, we want the cross product of P1 and P2
*/
vcross(p2, p1, a);
/*
* Figure out how much to rotate around that axis.
*/
vsub(p1, p2, d);
t = vlength(d) / (2.0 * TRACKBALLSIZE);
/*
* Avoid problems with out-of-control values...
*/
if (t > 1.0)
t = 1.0;
if (t < -1.0)
t = -1.0;
phi = 2.0 * asin(t);
axis_to_quat(a, phi, q);
}
/*
* Given an axis and angle, compute quaternion.
*/
void axis_to_quat(float a[3], float phi, float q[4]) {
vnormal(a);
vcopy(a, q);
vscale(q, sin(phi / 2.0));
q[3] = cos(phi / 2.0);
}
/*
* Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
* if we are away from the center of the sphere.
*/
static float tb_project_to_sphere(float r, float x, float y) {
float d, t, z;
d = sqrt(x * x + y * y);
if (d < r * 0.70710678118654752440) { /* Inside sphere */
z = sqrt(r * r - d * d);
} else { /* On hyperbola */
t = r / 1.41421356237309504880;
z = t * t / d;
}
return z;
}
/*
* Given two rotations, e1 and e2, expressed as quaternion rotations,
* figure out the equivalent single rotation and stuff it into dest.
*
* This routine also normalizes the result every RENORMCOUNT times it is
* called, to keep error from creeping in.
*
* NOTE: This routine is written so that q1 or q2 may be the same
* as dest (or each other).
*/
#define RENORMCOUNT 97
void add_quats(float q1[4], float q2[4], float dest[4]) {
static int count = 0;
float t1[4], t2[4], t3[4];
float tf[4];
vcopy(q1, t1);
vscale(t1, q2[3]);
vcopy(q2, t2);
vscale(t2, q1[3]);
vcross(q2, q1, t3);
vadd(t1, t2, tf);
vadd(t3, tf, tf);
tf[3] = q1[3] * q2[3] - vdot(q1, q2);
dest[0] = tf[0];
dest[1] = tf[1];
dest[2] = tf[2];
dest[3] = tf[3];
if (++count > RENORMCOUNT) {
count = 0;
normalize_quat(dest);
}
}
/*
* Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0
* If they don't add up to 1.0, dividing by their magnitued will
* renormalize them.
*
* Note: See the following for more information on quaternions:
*
* - Shoemake, K., Animating rotation with quaternion curves, Computer
* Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
* - Pletinckx, D., Quaternion calculus as a basic tool in computer
* graphics, The Visual Computer 5, 2-13, 1989.
*/
static void normalize_quat(float q[4]) {
int i;
float mag;
mag = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
for (i = 0; i < 4; i++)
q[i] /= mag;
}
/*
* Build a rotation matrix, given a quaternion rotation.
*
*/
void build_rotmatrix(float m[4][4], const float q[4]) {
m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
m[0][3] = 0.0;
m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
m[1][3] = 0.0;
m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
m[2][3] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
m[3][3] = 1.0;
}

View File

@@ -1,75 +0,0 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* trackball.h
* A virtual trackball implementation
* Written by Gavin Bell for Silicon Graphics, November 1988.
*/
/*
* Pass the x and y coordinates of the last and current positions of
* the mouse, scaled so they are from (-1.0 ... 1.0).
*
* The resulting rotation is returned as a quaternion rotation in the
* first paramater.
*/
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
void negate_quat(float *q, float *qn);
/*
* Given two quaternions, add them together to get a third quaternion.
* Adding quaternions to get a compound rotation is analagous to adding
* translations to get a compound translation. When incrementally
* adding rotations, the first argument here should be the new
* rotation, the second and third the total rotation (which will be
* over-written with the resulting new total rotation).
*/
void add_quats(float *q1, float *q2, float *dest);
/*
* A useful function, builds a rotation matrix in Matrix based on
* given quaternion.
*/
void build_rotmatrix(float m[4][4], const float q[4]);
/*
* This function computes a quaternion based on an axis (defined by
* the given vector) and an angle about which to rotate. The angle is
* expressed in radians. The result is put into the third argument.
*/
void axis_to_quat(float a[3], float phi, float q[4]);

View File

@@ -1,720 +0,0 @@
//
// Simple .obj viewer(vertex only)
//
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <cmath>
#include <cassert>
#include <cstring>
#include <algorithm>
#if defined(ENABLE_ZLIB)
#include <zlib.h>
#endif
#if defined(ENABLE_ZSTD)
#include <zstd.h>
#endif
#include <GL/glew.h>
#ifdef __APPLE__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include <GLFW/glfw3.h>
#include "trackball.h"
#define TINYOBJ_LOADER_OPT_IMPLEMENTATION
#include "tinyobj_loader_opt.h"
typedef struct {
GLuint vb; // vertex buffer
int numTriangles;
} DrawObject;
std::vector<DrawObject> gDrawObjects;
int width = 768;
int height = 768;
double prevMouseX, prevMouseY;
bool mouseLeftPressed;
bool mouseMiddlePressed;
bool mouseRightPressed;
float curr_quat[4];
float prev_quat[4];
float eye[3], lookat[3], up[3];
GLFWwindow* window;
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);
exit(20);
}
}
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];
v10[2] = v1[2] - v0[2];
float v20[3];
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];
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;
}
}
const char *mmap_file(size_t *len, const char* filename)
{
(*len) = 0;
#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 = fopen(filename, "r" );
fseek(f, 0, SEEK_END);
long fileSize = ftell(f);
fclose(f);
struct stat sb;
char *p;
int fd;
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, fileSize, PROT_READ, MAP_SHARED, fd, 0);
if (p == MAP_FAILED) {
perror ("mmap");
return NULL;
}
if (close (fd) == -1) {
perror ("close");
return NULL;
}
(*len) = fileSize;
return p;
#endif
}
bool 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
}
#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)
{
const char *ext = strrchr(filename, '.');
size_t data_len = 0;
const char* data = nullptr;
if (strcmp(ext, ".gz") == 0) {
// gzipped data.
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();
}
} 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);
}
(*len) = data_len;
return data;
}
bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int num_threads, bool verbose)
{
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;
}
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;
option.verbose = verbose;
bool ret = parseObj(&attrib, &shapes, &materials, data, data_len, option);
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)
size_t face_offset = 0;
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::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.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 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
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 > 1.0e-6f) {
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);
}
}
face_offset += attrib.face_num_verts[v];
}
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;
}
gDrawObjects.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)
{
(void)window;
// for retinal display.
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, (float)w / (float)h, 0.01f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
width = w;
height = h;
}
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;
}
}
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_MIDDLE){
if(action == GLFW_PRESS){
mouseMiddlePressed = true;
} else if(action == GLFW_RELEASE){
mouseMiddlePressed = false;
}
}
}
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);
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;
}
void Draw(const std::vector<DrawObject>& drawObjects)
{
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);
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));
glDrawArrays(GL_TRIANGLES, 0, 3 * o.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);
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);
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 * o.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) {
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 = (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;
option.verbose = true;
bool ret = parseObj(&attrib, &shapes, &materials, data, data_len, option);
return ret;
}
Init();
std::cout << "Initialize GLFW..." << std::endl;
if(!glfwInit()){
std::cerr << "Failed to initialize GLFW." << std::endl;
return -1;
}
std::cout << "GLFW OK." << std::endl;
window = glfwCreateWindow(width, height, "Obj viewer", NULL, NULL);
if(window == NULL){
std::cerr << "Failed to open GLFW window. " << std::endl;
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
// Callback
glfwSetWindowSizeCallback(window, reshapeFunc);
glfwSetKeyCallback(window, keyboardFunc);
glfwSetMouseButtonCallback(window, clickFunc);
glfwSetCursorPosCallback(window, motionFunc);
glewExperimental = true;
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialize GLEW." << std::endl;
return -1;
}
reshapeFunc(window, width, height);
float bmin[3], bmax[3];
if (false == LoadObjAndConvert(bmin, bmax, argv[1], num_threads, verbose)) {
printf("failed to load & conv\n");
return -1;
}
float 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(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);
// 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]);
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.5*(bmax[0] + bmin[0]), -0.5*(bmax[1] + bmin[1]), -0.5*(bmax[2] + bmin[2]));
Draw(gDrawObjects);
glfwSwapBuffers(window);
}
glfwTerminate();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

View File

@@ -1,12 +0,0 @@
# A simple test for the minimal standard C++ library
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := tinyobjloader
LOCAL_SRC_FILES := ../tiny_obj_loader.cc
LOCAL_C_INCLUDES := ../
include $(BUILD_STATIC_LIBRARY)

View File

@@ -1,2 +0,0 @@
APP_ABI := all
APP_STL := stlport_static

View File

@@ -1,2 +0,0 @@
all:
ndk-build

View File

@@ -1 +0,0 @@
Just tests compilation with Android NDK r10.

View File

@@ -1,413 +0,0 @@
//
// g++ loader_example.cc
//
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#ifdef _WIN32
#ifdef __cplusplus
extern "C" {
#endif
#include <windows.h>
#include <mmsystem.h>
#ifdef __cplusplus
}
#endif
#pragma comment(lib, "winmm.lib")
#else
#if defined(__unix__) || defined(__APPLE__)
#include <sys/time.h>
#else
#include <ctime>
#endif
#endif
class timerutil {
public:
#ifdef _WIN32
typedef DWORD time_t;
timerutil() { ::timeBeginPeriod(1); }
~timerutil() { ::timeEndPeriod(1); }
void start() { t_[0] = ::timeGetTime(); }
void end() { t_[1] = ::timeGetTime(); }
time_t sec() { return (time_t)((t_[1] - t_[0]) / 1000); }
time_t msec() { return (time_t)((t_[1] - t_[0])); }
time_t usec() { return (time_t)((t_[1] - t_[0]) * 1000); }
time_t current() { return ::timeGetTime(); }
#else
#if defined(__unix__) || defined(__APPLE__)
typedef unsigned long int time_t;
void start() { gettimeofday(tv + 0, &tz); }
void end() { gettimeofday(tv + 1, &tz); }
time_t sec() { return static_cast<time_t>(tv[1].tv_sec - tv[0].tv_sec); }
time_t msec() {
return this->sec() * 1000 +
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);
}
time_t current() {
struct timeval t;
gettimeofday(&t, NULL);
return static_cast<time_t>(t.tv_sec * 1000 + t.tv_usec);
}
#else // C timer
// using namespace std;
typedef clock_t time_t;
void start() { t_[0] = clock(); }
void end() { t_[1] = clock(); }
time_t sec() { return (time_t)((t_[1] - t_[0]) / CLOCKS_PER_SEC); }
time_t msec() { return (time_t)((t_[1] - t_[0]) * 1000 / CLOCKS_PER_SEC); }
time_t usec() { return (time_t)((t_[1] - t_[0]) * 1000000 / CLOCKS_PER_SEC); }
time_t current() { return (time_t)clock(); }
#endif
#endif
private:
#ifdef _WIN32
DWORD t_[2];
#else
#if defined(__unix__) || defined(__APPLE__)
struct timeval tv[2];
struct timezone tz;
#else
time_t t_[2];
#endif
#endif
};
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 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]));
}
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]));
}
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]));
}
// 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()));
size_t index_offset = 0;
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()));
// 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];
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);
}
printf(" face[%ld].material_id = %d\n", static_cast<long>(f),
shapes[i].mesh.material_ids[f]);
index_offset += fnum;
}
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(" 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(", ");
}
}
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(", ");
}
}
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(", ");
}
}
printf("]");
printf("\n");
}
}
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.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.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_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());
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());
}
printf("\n");
}
}
static bool TestLoadObj(const char* filename, const char* basepath = NULL,
bool triangulate = true) {
std::cout << "Loading " << filename << std::endl;
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
timerutil t;
t.start();
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename,
basepath, triangulate);
t.end();
printf("Parsing time: %lu [msecs]\n", t.msec());
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
printf("Failed to load/parse .obj.\n");
return false;
}
PrintInfo(attrib, shapes, materials);
return true;
}
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";
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;
}
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);
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
return false;
}
PrintInfo(attrib, shapes, materials);
return true;
}
int main(int argc, char** argv) {
if (argc > 1) {
const char* basepath = "models/";
if (argc > 2) {
basepath = argv[2];
}
assert(true == TestLoadObj(argv[1], basepath));
} else {
// assert(true == TestLoadObj("cornell_box.obj"));
// assert(true == TestLoadObj("cube.obj"));
assert(true == TestStreamLoadObj());
assert(true ==
TestLoadObj("models/catmark_torus_creases0.obj", "models/", false));
}
return 0;
}

View File

@@ -1,101 +0,0 @@
#
# Copyright 2013 Pixar
#
# Licensed under the Apache License, Version 2.0 (the "Apache License")
# with the following modification; you may not use this file except in
# compliance with the Apache License and the following modification to it:
# Section 6. Trademarks. is deleted and replaced with:
#
# 6. Trademarks. This License does not grant permission to use the trade
# names, trademarks, service marks, or product names of the Licensor
# and its affiliates, except as required to comply with Section 4(c) of
# the License and to reproduce the content of the NOTICE file.
#
# You may obtain a copy of the Apache License at
#
# http:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the Apache License with the above modification is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the Apache License for the specific
# language governing permissions and limitations under the Apache License.
#
# This file uses centimeters as units for non-parametric coordinates.
v 1.25052 0.517982 0.353553
v 0.597239 0.247384 0.353553
v 0.597239 0.247384 -0.353553
v 1.25052 0.517982 -0.353553
v 0.517982 1.25052 0.353553
v 0.247384 0.597239 0.353553
v 0.247384 0.597239 -0.353553
v 0.517982 1.25052 -0.353553
v -0.517982 1.25052 0.353553
v -0.247384 0.597239 0.353553
v -0.247384 0.597239 -0.353553
v -0.517982 1.25052 -0.353553
v -1.25052 0.517982 0.353553
v -0.597239 0.247384 0.353553
v -0.597239 0.247384 -0.353553
v -1.25052 0.517982 -0.353553
v -1.25052 -0.517982 0.353553
v -0.597239 -0.247384 0.353553
v -0.597239 -0.247384 -0.353553
v -1.25052 -0.517982 -0.353553
v -0.517982 -1.25052 0.353553
v -0.247384 -0.597239 0.353553
v -0.247384 -0.597239 -0.353553
v -0.517982 -1.25052 -0.353553
v 0.517982 -1.25052 0.353553
v 0.247384 -0.597239 0.353553
v 0.247384 -0.597239 -0.353553
v 0.517982 -1.25052 -0.353553
v 1.25052 -0.517982 0.353553
v 0.597239 -0.247384 0.353553
v 0.597239 -0.247384 -0.353553
v 1.25052 -0.517982 -0.353553
vt 0 0
vt 1 0
vt 1 1
vt 0 1
f 5/1/1 6/2/2 2/3/3 1/4/4
f 6/1/5 7/2/6 3/3/7 2/4/8
f 7/1/9 8/2/10 4/3/11 3/4/12
f 8/1/13 5/2/14 1/3/15 4/4/16
f 9/1/17 10/2/18 6/3/19 5/4/20
f 10/1/21 11/2/22 7/3/23 6/4/24
f 11/1/25 12/2/26 8/3/27 7/4/28
f 12/1/29 9/2/30 5/3/31 8/4/32
f 13/1/33 14/2/34 10/3/35 9/4/36
f 14/1/37 15/2/38 11/3/39 10/4/40
f 15/1/41 16/2/42 12/3/43 11/4/44
f 16/1/45 13/2/46 9/3/47 12/4/48
f 17/1/49 18/2/50 14/3/51 13/4/52
f 18/1/53 19/2/54 15/3/55 14/4/56
f 19/1/57 20/2/58 16/3/59 15/4/60
f 20/1/61 17/2/62 13/3/63 16/4/64
f 21/1/65 22/2/66 18/3/67 17/4/68
f 22/1/69 23/2/70 19/3/71 18/4/72
f 23/1/73 24/2/74 20/3/75 19/4/76
f 24/1/77 21/2/78 17/3/79 20/4/80
f 25/1/81 26/2/82 22/3/83 21/4/84
f 26/1/85 27/2/86 23/3/87 22/4/88
f 27/1/89 28/2/90 24/3/91 23/4/92
f 28/1/93 25/2/94 21/3/95 24/4/96
f 29/1/97 30/2/98 26/3/99 25/4/100
f 30/1/101 31/2/102 27/3/103 26/4/104
f 31/1/105 32/2/106 28/3/107 27/4/108
f 32/1/109 29/2/110 25/3/111 28/4/112
f 1/1/113 2/2/114 30/3/115 29/4/116
f 2/1/117 3/2/118 31/3/119 30/4/120
f 3/1/121 4/2/122 32/3/123 31/4/124
f 4/1/125 1/2/126 29/3/127 32/4/128
t crease 2/1/0 1 5 4.7
t crease 2/1/0 5 9 4.7
t crease 2/1/0 9 13 4.7
t crease 2/1/0 13 17 4.7
t crease 2/1/0 17 21 4.7
t crease 2/1/0 21 25 4.7
t crease 2/1/0 25 29 4.7
t crease 2/1/0 29 1 4.7

View File

@@ -1,6 +0,0 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
map_Kd tmp.png

View File

@@ -1,7 +0,0 @@
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

View File

@@ -1,5 +0,0 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Tf 0.1 0.2 0.3

View File

@@ -1,7 +0,0 @@
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

View File

@@ -1,5 +0,0 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Kt 0.1 0.2 0.3

View File

@@ -1,7 +0,0 @@
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

View File

@@ -1,145 +0,0 @@
# 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 no_material.mtl
o floor
usemtl white
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
o light
usemtl light
v 343.0 548.0 227.0
v 343.0 548.0 332.0
v 213.0 548.0 332.0
v 213.0 548.0 227.0
f -4 -3 -2 -1
o ceiling
usemtl white
v 556.0 548.8 0.0
v 556.0 548.8 559.2
v 0.0 548.8 559.2
v 0.0 548.8 0.0
f -4 -3 -2 -1
o back_wall
usemtl white
v 549.6 0.0 559.2
v 0.0 0.0 559.2
v 0.0 548.8 559.2
v 556.0 548.8 559.2
f -4 -3 -2 -1
o front_wall
usemtl blue
v 549.6 0.0 0
v 0.0 0.0 0
v 0.0 548.8 0
v 556.0 548.8 0
#f -1 -2 -3 -4
o green_wall
usemtl green
v 0.0 0.0 559.2
v 0.0 0.0 0.0
v 0.0 548.8 0.0
v 0.0 548.8 559.2
f -4 -3 -2 -1
o red_wall
usemtl red
v 552.8 0.0 0.0
v 549.6 0.0 559.2
v 556.0 548.8 559.2
v 556.0 548.8 0.0
f -4 -3 -2 -1
o short_block
usemtl white
v 130.0 165.0 65.0
v 82.0 165.0 225.0
v 240.0 165.0 272.0
v 290.0 165.0 114.0
f -4 -3 -2 -1
v 290.0 0.0 114.0
v 290.0 165.0 114.0
v 240.0 165.0 272.0
v 240.0 0.0 272.0
f -4 -3 -2 -1
v 130.0 0.0 65.0
v 130.0 165.0 65.0
v 290.0 165.0 114.0
v 290.0 0.0 114.0
f -4 -3 -2 -1
v 82.0 0.0 225.0
v 82.0 165.0 225.0
v 130.0 165.0 65.0
v 130.0 0.0 65.0
f -4 -3 -2 -1
v 240.0 0.0 272.0
v 240.0 165.0 272.0
v 82.0 165.0 225.0
v 82.0 0.0 225.0
f -4 -3 -2 -1
o tall_block
usemtl white
v 423.0 330.0 247.0
v 265.0 330.0 296.0
v 314.0 330.0 456.0
v 472.0 330.0 406.0
f -4 -3 -2 -1
usemtl white
v 423.0 0.0 247.0
v 423.0 330.0 247.0
v 472.0 330.0 406.0
v 472.0 0.0 406.0
f -4 -3 -2 -1
v 472.0 0.0 406.0
v 472.0 330.0 406.0
v 314.0 330.0 456.0
v 314.0 0.0 456.0
f -4 -3 -2 -1
v 314.0 0.0 456.0
v 314.0 330.0 456.0
v 265.0 330.0 296.0
v 265.0 0.0 296.0
f -4 -3 -2 -1
v 265.0 0.0 296.0
v 265.0 330.0 296.0
v 423.0 330.0 247.0
v 423.0 0.0 247.0
f -4 -3 -2 -1

View File

@@ -1,6 +0,0 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
map_Kd tmp.png

View File

@@ -1,7 +0,0 @@
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

View File

@@ -1,133 +0,0 @@
# cornell_box.obj and cornell_box.mtl are grabbed from Intel's embree project.
# original cornell box data
# comment
# empty line including some space
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
o light
v 343.0 548.0 227.0
v 343.0 548.0 332.0
v 213.0 548.0 332.0
v 213.0 548.0 227.0
f -4 -3 -2 -1
o ceiling
v 556.0 548.8 0.0
v 556.0 548.8 559.2
v 0.0 548.8 559.2
v 0.0 548.8 0.0
f -4 -3 -2 -1
o back_wall
v 549.6 0.0 559.2
v 0.0 0.0 559.2
v 0.0 548.8 559.2
v 556.0 548.8 559.2
f -4 -3 -2 -1
o front_wall
v 549.6 0.0 0
v 0.0 0.0 0
v 0.0 548.8 0
v 556.0 548.8 0
#f -1 -2 -3 -4
o green_wall
v 0.0 0.0 559.2
v 0.0 0.0 0.0
v 0.0 548.8 0.0
v 0.0 548.8 559.2
f -4 -3 -2 -1
o red_wall
v 552.8 0.0 0.0
v 549.6 0.0 559.2
v 556.0 548.8 559.2
v 556.0 548.8 0.0
f -4 -3 -2 -1
o short_block
v 130.0 165.0 65.0
v 82.0 165.0 225.0
v 240.0 165.0 272.0
v 290.0 165.0 114.0
f -4 -3 -2 -1
v 290.0 0.0 114.0
v 290.0 165.0 114.0
v 240.0 165.0 272.0
v 240.0 0.0 272.0
f -4 -3 -2 -1
v 130.0 0.0 65.0
v 130.0 165.0 65.0
v 290.0 165.0 114.0
v 290.0 0.0 114.0
f -4 -3 -2 -1
v 82.0 0.0 225.0
v 82.0 165.0 225.0
v 130.0 165.0 65.0
v 130.0 0.0 65.0
f -4 -3 -2 -1
v 240.0 0.0 272.0
v 240.0 165.0 272.0
v 82.0 165.0 225.0
v 82.0 0.0 225.0
f -4 -3 -2 -1
o tall_block
v 423.0 330.0 247.0
v 265.0 330.0 296.0
v 314.0 330.0 456.0
v 472.0 330.0 406.0
f -4 -3 -2 -1
v 423.0 0.0 247.0
v 423.0 330.0 247.0
v 472.0 330.0 406.0
v 472.0 0.0 406.0
f -4 -3 -2 -1
v 472.0 0.0 406.0
v 472.0 330.0 406.0
v 314.0 330.0 456.0
v 314.0 0.0 456.0
f -4 -3 -2 -1
v 314.0 0.0 456.0
v 314.0 330.0 456.0
v 265.0 330.0 296.0
v 265.0 0.0 296.0
f -4 -3 -2 -1
v 265.0 0.0 296.0
v 265.0 330.0 296.0
v 423.0 330.0 247.0
v 423.0 0.0 247.0
f -4 -3 -2 -1

View File

@@ -1,19 +0,0 @@
# .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

View File

@@ -1,10 +0,0 @@
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

View File

@@ -1,145 +0,0 @@
# 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
usemtl white
v nan -nan nan
v inf -inf inf
v 1.#IND -1.#IND 1.#IND
v 1.#INF -1.#INF 1.#INF
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
o light
usemtl light
v 343.0 548.0 227.0
v 343.0 548.0 332.0
v 213.0 548.0 332.0
v 213.0 548.0 227.0
f -4 -3 -2 -1
o ceiling
usemtl white
v 556.0 548.8 0.0
v 556.0 548.8 559.2
v 0.0 548.8 559.2
v 0.0 548.8 0.0
f -4 -3 -2 -1
o back_wall
usemtl white
v 549.6 0.0 559.2
v 0.0 0.0 559.2
v 0.0 548.8 559.2
v 556.0 548.8 559.2
f -4 -3 -2 -1
o front_wall
usemtl blue
v 549.6 0.0 0
v 0.0 0.0 0
v 0.0 548.8 0
v 556.0 548.8 0
#f -1 -2 -3 -4
o green_wall
usemtl green
v 0.0 0.0 559.2
v 0.0 0.0 0.0
v 0.0 548.8 0.0
v 0.0 548.8 559.2
f -4 -3 -2 -1
o red_wall
usemtl red
v 552.8 0.0 0.0
v 549.6 0.0 559.2
v 556.0 548.8 559.2
v 556.0 548.8 0.0
f -4 -3 -2 -1
o short_block
usemtl white
v 130.0 165.0 65.0
v 82.0 165.0 225.0
v 240.0 165.0 272.0
v 290.0 165.0 114.0
f -4 -3 -2 -1
v 290.0 0.0 114.0
v 290.0 165.0 114.0
v 240.0 165.0 272.0
v 240.0 0.0 272.0
f -4 -3 -2 -1
v 130.0 0.0 65.0
v 130.0 165.0 65.0
v 290.0 165.0 114.0
v 290.0 0.0 114.0
f -4 -3 -2 -1
v 82.0 0.0 225.0
v 82.0 165.0 225.0
v 130.0 165.0 65.0
v 130.0 0.0 65.0
f -4 -3 -2 -1
v 240.0 0.0 272.0
v 240.0 165.0 272.0
v 82.0 165.0 225.0
v 82.0 0.0 225.0
f -4 -3 -2 -1
o tall_block
usemtl white
v 423.0 330.0 247.0
v 265.0 330.0 296.0
v 314.0 330.0 456.0
v 472.0 330.0 406.0
f -4 -3 -2 -1
usemtl white
v 423.0 0.0 247.0
v 423.0 330.0 247.0
v 472.0 330.0 406.0
v 472.0 0.0 406.0
f -4 -3 -2 -1
v 472.0 0.0 406.0
v 472.0 330.0 406.0
v 314.0 330.0 456.0
v 314.0 0.0 456.0
f -4 -3 -2 -1
v 314.0 0.0 456.0
v 314.0 330.0 456.0
v 265.0 330.0 296.0
v 265.0 0.0 296.0
f -4 -3 -2 -1
v 265.0 0.0 296.0
v 265.0 330.0 296.0
v 423.0 330.0 247.0
v 423.0 0.0 247.0
f -4 -3 -2 -1

View File

@@ -1,36 +0,0 @@
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

View File

@@ -1,7 +0,0 @@
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

View File

@@ -1,30 +0,0 @@
# 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

View File

@@ -1,9 +0,0 @@
newmtl Material.001
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
newmtl Material.003
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0

View File

@@ -1,817 +0,0 @@
# https://github.com/syoyo/tinyobjloader/issues/68
# Blender v2.73 (sub 0) OBJ File: 'enemy.blend'
# www.blender.org
mtllib usemtl-issue-68.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.003
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

View File

@@ -1,5 +1,9 @@
lib_sources = {
"tiny_obj_loader.cc"
}
sources = {
"loader_example.cc",
"test.cc",
}
-- premake4.lua
@@ -16,14 +20,14 @@ solution "TinyObjLoaderSolution"
project "tinyobjloader"
kind "ConsoleApp"
language "C++"
files { sources }
files { lib_sources, sources }
configuration "Debug"
defines { "DEBUG" } -- -DDEBUG
flags { "Symbols" }
targetname "loader_example_debug"
targetname "test_tinyobjloader_debug"
configuration "Release"
-- defines { "NDEBUG" } -- -NDEBUG
flags { "Symbols", "Optimize" }
targetname "loader_example"
targetname "test_tinyobjloader"

View File

@@ -1,2 +0,0 @@
* PBR material
* Define index_t struct

View File

@@ -1,581 +0,0 @@
{
"shapes": {
"back_wall": {
"material_ids": [
0.0,
0.0
],
"normals": [],
"positions": [
549.5999755859375,
0.0,
559.2000122070312,
0.0,
0.0,
559.2000122070312,
0.0,
548.7999877929688,
559.2000122070312,
556.0,
548.7999877929688,
559.2000122070312
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"texcoords": []
},
"floor": {
"material_ids": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"normals": [],
"positions": [
552.7999877929688,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
559.2000122070312,
549.5999755859375,
0.0,
559.2000122070312,
290.0,
0.0,
114.0,
240.0,
0.0,
272.0,
82.0,
0.0,
225.0,
130.0,
0.0,
65.0,
472.0,
0.0,
406.0,
314.0,
0.0,
456.0,
265.0,
0.0,
296.0,
423.0,
0.0,
247.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0,
4.0,
5.0,
6.0,
4.0,
6.0,
7.0,
8.0,
9.0,
10.0,
8.0,
10.0,
11.0
],
"texcoords": []
},
"red_wall": {
"material_ids": [
1.0,
1.0
],
"normals": [],
"positions": [
552.7999877929688,
0.0,
0.0,
549.5999755859375,
0.0,
559.2000122070312,
556.0,
548.7999877929688,
559.2000122070312,
556.0,
548.7999877929688,
0.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"texcoords": []
},
"light": {
"material_ids": [
4.0,
4.0
],
"normals": [],
"positions": [
343.0,
548.0,
227.0,
343.0,
548.0,
332.0,
213.0,
548.0,
332.0,
213.0,
548.0,
227.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"texcoords": []
},
"tall_block": {
"material_ids": [
2.0,
2.0,
2.0,
2.0
],
"normals": [],
"positions": [
314.0,
0.0,
456.0,
314.0,
330.0,
456.0,
265.0,
330.0,
296.0,
265.0,
0.0,
296.0,
265.0,
0.0,
296.0,
265.0,
330.0,
296.0,
423.0,
330.0,
247.0,
423.0,
0.0,
247.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0,
4.0,
5.0,
6.0,
4.0,
6.0,
7.0
],
"texcoords": []
},
"short_block": {
"material_ids": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"normals": [],
"positions": [
130.0,
165.0,
65.0,
82.0,
165.0,
225.0,
240.0,
165.0,
272.0,
290.0,
165.0,
114.0,
290.0,
0.0,
114.0,
290.0,
165.0,
114.0,
240.0,
165.0,
272.0,
240.0,
0.0,
272.0,
130.0,
0.0,
65.0,
130.0,
165.0,
65.0,
290.0,
165.0,
114.0,
290.0,
0.0,
114.0,
82.0,
0.0,
225.0,
82.0,
165.0,
225.0,
130.0,
165.0,
65.0,
130.0,
0.0,
65.0,
240.0,
0.0,
272.0,
240.0,
165.0,
272.0,
82.0,
165.0,
225.0,
82.0,
0.0,
225.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0,
4.0,
5.0,
6.0,
4.0,
6.0,
7.0,
8.0,
9.0,
10.0,
8.0,
10.0,
11.0,
12.0,
13.0,
14.0,
12.0,
14.0,
15.0,
16.0,
17.0,
18.0,
16.0,
18.0,
19.0
],
"texcoords": []
},
"green_wall": {
"material_ids": [
2.0,
2.0
],
"normals": [],
"positions": [
0.0,
0.0,
559.2000122070312,
0.0,
0.0,
0.0,
0.0,
548.7999877929688,
0.0,
0.0,
548.7999877929688,
559.2000122070312
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"texcoords": []
},
"ceiling": {
"material_ids": [
0.0,
0.0
],
"normals": [],
"positions": [
556.0,
548.7999877929688,
0.0,
556.0,
548.7999877929688,
559.2000122070312,
0.0,
548.7999877929688,
559.2000122070312,
0.0,
548.7999877929688,
0.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"texcoords": []
}
},
"materials": {
"blue": {
"diffuse_texname": "",
"ambient_texname": "",
"illum": 0,
"displacement_texname": "",
"alpha_texname": "",
"emission": [
0.0,
0.0,
0.0
],
"transmittance": [
0.0,
0.0,
0.0
],
"ambient": [
0.0,
0.0,
0.0
],
"bump_texname": "",
"diffuse": [
0.0,
0.0,
1.0
],
"shininess": 1.0,
"specular_highlight_texname": "",
"unknown_parameter": {},
"ior": 1.0,
"dissolve": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": ""
},
"white": {
"diffuse_texname": "",
"ambient_texname": "",
"illum": 0,
"displacement_texname": "",
"alpha_texname": "",
"emission": [
0.0,
0.0,
0.0
],
"transmittance": [
0.0,
0.0,
0.0
],
"ambient": [
0.0,
0.0,
0.0
],
"bump_texname": "",
"diffuse": [
1.0,
1.0,
1.0
],
"shininess": 1.0,
"specular_highlight_texname": "",
"unknown_parameter": {},
"ior": 1.0,
"dissolve": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": ""
},
"red": {
"diffuse_texname": "",
"ambient_texname": "",
"illum": 0,
"displacement_texname": "",
"alpha_texname": "",
"emission": [
0.0,
0.0,
0.0
],
"transmittance": [
0.0,
0.0,
0.0
],
"ambient": [
0.0,
0.0,
0.0
],
"bump_texname": "",
"diffuse": [
1.0,
0.0,
0.0
],
"shininess": 1.0,
"specular_highlight_texname": "",
"unknown_parameter": {},
"ior": 1.0,
"dissolve": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": ""
},
"light": {
"diffuse_texname": "",
"ambient_texname": "",
"illum": 0,
"displacement_texname": "",
"alpha_texname": "",
"emission": [
0.0,
0.0,
0.0
],
"transmittance": [
0.0,
0.0,
0.0
],
"ambient": [
20.0,
20.0,
20.0
],
"bump_texname": "",
"diffuse": [
1.0,
1.0,
1.0
],
"shininess": 1.0,
"specular_highlight_texname": "",
"unknown_parameter": {},
"ior": 1.0,
"dissolve": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": ""
},
"green": {
"diffuse_texname": "",
"ambient_texname": "",
"illum": 0,
"displacement_texname": "",
"alpha_texname": "",
"emission": [
0.0,
0.0,
0.0
],
"transmittance": [
0.0,
0.0,
0.0
],
"ambient": [
0.0,
0.0,
0.0
],
"bump_texname": "",
"diffuse": [
0.0,
1.0,
0.0
],
"shininess": 1.0,
"specular_highlight_texname": "",
"unknown_parameter": {},
"ior": 1.0,
"dissolve": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": ""
}
}
}

View File

@@ -0,0 +1,601 @@
{
"shapes": {
"ceiling": {
"texcoords": [],
"positions": [
556.0,
548.7999877929688,
0.0,
556.0,
548.7999877929688,
559.2000122070312,
0.0,
548.7999877929688,
559.2000122070312,
0.0,
548.7999877929688,
0.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
0.0,
0.0
],
"normals": []
},
"floor": {
"texcoords": [],
"positions": [
552.7999877929688,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
559.2000122070312,
549.5999755859375,
0.0,
559.2000122070312,
290.0,
0.0,
114.0,
240.0,
0.0,
272.0,
82.0,
0.0,
225.0,
130.0,
0.0,
65.0,
472.0,
0.0,
406.0,
314.0,
0.0,
456.0,
265.0,
0.0,
296.0,
423.0,
0.0,
247.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0,
4.0,
5.0,
6.0,
4.0,
6.0,
7.0,
8.0,
9.0,
10.0,
8.0,
10.0,
11.0
],
"material_ids": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"normals": []
},
"light": {
"texcoords": [],
"positions": [
343.0,
548.0,
227.0,
343.0,
548.0,
332.0,
213.0,
548.0,
332.0,
213.0,
548.0,
227.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
4.0,
4.0
],
"normals": []
},
"green_wall": {
"texcoords": [],
"positions": [
0.0,
0.0,
559.2000122070312,
0.0,
0.0,
0.0,
0.0,
548.7999877929688,
0.0,
0.0,
548.7999877929688,
559.2000122070312
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
2.0,
2.0
],
"normals": []
},
"back_wall": {
"texcoords": [],
"positions": [
549.5999755859375,
0.0,
559.2000122070312,
0.0,
0.0,
559.2000122070312,
0.0,
548.7999877929688,
559.2000122070312,
556.0,
548.7999877929688,
559.2000122070312
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
0.0,
0.0
],
"normals": []
},
"short_block": {
"texcoords": [],
"positions": [
130.0,
165.0,
65.0,
82.0,
165.0,
225.0,
240.0,
165.0,
272.0,
290.0,
165.0,
114.0,
290.0,
0.0,
114.0,
290.0,
165.0,
114.0,
240.0,
165.0,
272.0,
240.0,
0.0,
272.0,
130.0,
0.0,
65.0,
130.0,
165.0,
65.0,
290.0,
165.0,
114.0,
290.0,
0.0,
114.0,
82.0,
0.0,
225.0,
82.0,
165.0,
225.0,
130.0,
165.0,
65.0,
130.0,
0.0,
65.0,
240.0,
0.0,
272.0,
240.0,
165.0,
272.0,
82.0,
165.0,
225.0,
82.0,
0.0,
225.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0,
4.0,
5.0,
6.0,
4.0,
6.0,
7.0,
8.0,
9.0,
10.0,
8.0,
10.0,
11.0,
12.0,
13.0,
14.0,
12.0,
14.0,
15.0,
16.0,
17.0,
18.0,
16.0,
18.0,
19.0
],
"material_ids": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"normals": []
},
"tall_block": {
"texcoords": [],
"positions": [
423.0,
0.0,
247.0,
423.0,
330.0,
247.0,
472.0,
330.0,
406.0,
472.0,
0.0,
406.0,
472.0,
0.0,
406.0,
472.0,
330.0,
406.0,
314.0,
330.0,
456.0,
314.0,
0.0,
456.0,
314.0,
0.0,
456.0,
314.0,
330.0,
456.0,
265.0,
330.0,
296.0,
265.0,
0.0,
296.0,
265.0,
0.0,
296.0,
265.0,
330.0,
296.0,
423.0,
330.0,
247.0,
423.0,
0.0,
247.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0,
4.0,
5.0,
6.0,
4.0,
6.0,
7.0,
8.0,
9.0,
10.0,
8.0,
10.0,
11.0,
12.0,
13.0,
14.0,
12.0,
14.0,
15.0
],
"material_ids": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"normals": []
},
"red_wall": {
"texcoords": [],
"positions": [
552.7999877929688,
0.0,
0.0,
549.5999755859375,
0.0,
559.2000122070312,
556.0,
548.7999877929688,
559.2000122070312,
556.0,
548.7999877929688,
0.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
1.0,
1.0
],
"normals": []
}
},
"materials": {
"blue": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
0.0,
0.0,
1.0
],
"ambient": [
0.0,
0.0,
0.0
],
"dissolve": 1.0
},
"light": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
1.0,
1.0,
1.0
],
"ambient": [
20.0,
20.0,
20.0
],
"dissolve": 1.0
},
"white": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
1.0,
1.0,
1.0
],
"ambient": [
0.0,
0.0,
0.0
],
"dissolve": 1.0
},
"green": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
0.0,
1.0,
0.0
],
"ambient": [
0.0,
0.0,
0.0
],
"dissolve": 1.0
},
"red": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
1.0,
0.0,
0.0
],
"ambient": [
0.0,
0.0,
0.0
],
"dissolve": 1.0
}
}
}

View File

@@ -1,9 +1,11 @@
import tinyobjloader as tol
import json
model = tol.LoadObj("cornell_box_multimaterial.obj")
model = tol.LoadObj("cornell_box.obj")
#print(model["shapes"], model["materials"])
print( json.dumps(model, indent=4) )
#see cornell_box_output.json

View File

@@ -1,203 +1,148 @@
// python2/3 module for tinyobjloader
//python3 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, *attribobj, *current, *meshobj;
static PyObject*
pyLoadObj(PyObject* self, PyObject* args)
{
PyObject *rtndict, *pyshapes, *pymaterials,
*current, *meshobj;
char const* current_name;
char const* filename;
vectd vect;
std::vector<tinyobj::index_t> indices;
std::vector<unsigned char> face_verts;
char const* filename;
char *current_name;
vectd vect;
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
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(&attrib, &shapes, &materials, &err, filename);
tinyobj::LoadObj(shapes, materials, filename);
pyshapes = PyDict_New();
pymaterials = PyDict_New();
rtndict = PyDict_New();
attribobj = PyDict_New();
for (int i = 0; i <= 2; i++) {
current = PyList_New(0);
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 (vectd::iterator it = vect.begin(); it != vect.end(); it++) {
PyList_Insert(current, it - vect.begin(), PyFloat_FromDouble(*it));
}
PyDict_SetItemString(attribobj, current_name, current);
}
for (std::vector<tinyobj::shape_t>::iterator shape = shapes.begin();
shape != shapes.end(); shape++) {
meshobj = PyDict_New();
tinyobj::mesh_t cm = (*shape).mesh;
pyshapes = PyDict_New();
pymaterials = PyDict_New();
rtndict = PyDict_New();
for (std::vector<tinyobj::shape_t>::iterator shape = shapes.begin() ;
shape != shapes.end(); shape++)
{
current = PyList_New(0);
meshobj = PyDict_New();
tinyobj::mesh_t cm = (*shape).mesh;
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));
}
for (int i = 0; i <= 4; i++ )
{
current = PyList_New(0);
PyDict_SetItemString(meshobj, "indices", current);
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);
}
for (std::vector<tinyobj::material_t>::iterator mat = materials.begin() ;
mat != materials.end(); mat++)
{
current = PyList_New(0);
PyObject *matobj = PyDict_New();
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(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, "normal_texname", PyUnicode_FromString((*mat).normal_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(meshobj, "num_face_vertices", current);
PyDict_SetItemString(pymaterials, (*mat).name.c_str(), matobj);
}
{
current = PyList_New(0);
PyDict_SetItemString(rtndict, "shapes", pyshapes);
PyDict_SetItemString(rtndict, "materials", pymaterials);
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;
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
}

96
python/pyTOL.cbp.mak Normal file
View File

@@ -0,0 +1,96 @@
#------------------------------------------------------------------------------#
# This makefile was generated by 'cbp2make' tool rev.147 #
#------------------------------------------------------------------------------#
WORKDIR = `pwd`
CC = gcc
CXX = g++
AR = ar
LD = g++
WINDRES = windres
INC =
CFLAGS = -Wall -fexceptions `python3-config --cflags`
RESINC =
LIBDIR =
LIB =
LDFLAGS = `python3-config --ldflags`
INC_DEBUG = $(INC)
CFLAGS_DEBUG = $(CFLAGS) -g
RESINC_DEBUG = $(RESINC)
RCFLAGS_DEBUG = $(RCFLAGS)
LIBDIR_DEBUG = $(LIBDIR)
LIB_DEBUG = $(LIB)
LDFLAGS_DEBUG = $(LDFLAGS)
OBJDIR_DEBUG = obj/Debug
DEP_DEBUG =
OUT_DEBUG = bin/Debug/tinyobjloader.so
INC_RELEASE = $(INC)
CFLAGS_RELEASE = $(CFLAGS) -O2
RESINC_RELEASE = $(RESINC)
RCFLAGS_RELEASE = $(RCFLAGS)
LIBDIR_RELEASE = $(LIBDIR)
LIB_RELEASE = $(LIB)
LDFLAGS_RELEASE = $(LDFLAGS) -s
OBJDIR_RELEASE = obj/Release
DEP_RELEASE =
OUT_RELEASE = bin/Release/tinyobjloader.so
OBJ_DEBUG = $(OBJDIR_DEBUG)/main.o $(OBJDIR_DEBUG)/tiny_obj_loader.o
OBJ_RELEASE = $(OBJDIR_RELEASE)/main.o $(OBJDIR_RELEASE)/tiny_obj_loader.o
all: debug release
clean: clean_debug clean_release
before_debug:
test -d bin/Debug || mkdir -p bin/Debug
test -d $(OBJDIR_DEBUG) || mkdir -p $(OBJDIR_DEBUG)
after_debug:
debug: before_debug out_debug after_debug
out_debug: before_debug $(OBJ_DEBUG) $(DEP_DEBUG)
$(LD) -shared $(LIBDIR_DEBUG) $(OBJ_DEBUG) -o $(OUT_DEBUG) $(LDFLAGS_DEBUG) $(LIB_DEBUG)
$(OBJDIR_DEBUG)/main.o: main.cpp
$(CXX) $(CFLAGS_DEBUG) $(INC_DEBUG) -c main.cpp -o $(OBJDIR_DEBUG)/main.o
$(OBJDIR_DEBUG)/tiny_obj_loader.o: ../tiny_obj_loader.cc
$(CC) $(CFLAGS_DEBUG) $(INC_DEBUG) -c ../tiny_obj_loader.cc -o $(OBJDIR_DEBUG)/tiny_obj_loader.o
clean_debug:
rm -f $(OBJ_DEBUG) $(OUT_DEBUG)
rm -rf bin/Debug
rm -rf $(OBJDIR_DEBUG)
before_release:
test -d bin/Release || mkdir -p bin/Release
test -d $(OBJDIR_RELEASE) || mkdir -p $(OBJDIR_RELEASE)
after_release:
release: before_release out_release after_release
out_release: before_release $(OBJ_RELEASE) $(DEP_RELEASE)
$(LD) -shared $(LIBDIR_RELEASE) $(OBJ_RELEASE) -o $(OUT_RELEASE) $(LDFLAGS_RELEASE) $(LIB_RELEASE)
$(OBJDIR_RELEASE)/main.o: main.cpp
$(CXX) $(CFLAGS_RELEASE) $(INC_RELEASE) -c main.cpp -o $(OBJDIR_RELEASE)/main.o
$(OBJDIR_RELEASE)/tiny_obj_loader.o: ../tiny_obj_loader.cc
$(CC) $(CFLAGS_RELEASE) $(INC_RELEASE) -c ../tiny_obj_loader.cc -o $(OBJDIR_RELEASE)/tiny_obj_loader.o
clean_release:
rm -f $(OBJ_RELEASE) $(OUT_RELEASE)
rm -rf bin/Release
rm -rf $(OBJDIR_RELEASE)
.PHONY: before_debug after_debug clean_debug before_release after_release clean_release

224
test.cc Normal file
View File

@@ -0,0 +1,224 @@
#include "tiny_obj_loader.h"
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <sstream>
#include <fstream>
static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::curve_t>& curves, const std::vector<tinyobj::material_t>& materials)
{
std::cout << "# of shapes : " << shapes.size() << std::endl;
std::cout << "# of curves : " << curves.size() << std::endl;
std::cout << "# of materials : " << materials.size() << std::endl;
for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert((shapes[i].mesh.indices.size() % 3) == 0);
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
printf(" idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
}
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
assert((shapes[i].mesh.positions.size() % 3) == 0);
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
printf(" v[%ld] = (%f, %f, %f)\n", v,
shapes[i].mesh.positions[3*v+0],
shapes[i].mesh.positions[3*v+1],
shapes[i].mesh.positions[3*v+2]);
}
}
for (size_t i = 0; i < curves.size(); i++) {
printf("curve[%ld].name = %s\n", i, curves[i].name.c_str());
printf("Size of curve[%ld].indices: %ld\n", i, curves[i].indices.size());
printf("curves[%ld].vertices: %ld\n", i, curves[i].positions.size());
assert((curves[i].positions.size() % 3) == 0);
for (size_t v = 0; v < curves[i].positions.size() / 3; v++) {
printf(" v[%ld] = (%f, %f, %f)\n", v,
curves[i].positions[3*v+0],
curves[i].positions[3*v+1],
curves[i].positions[3*v+2]);
}
for (size_t v = 0; v < curves[i].u_params.size(); v++) {
printf(" u[%ld] = %f\n", v, curves[i].u_params[v]);
}
for (size_t v = 0; v < curves[i].v_params.size(); v++) {
printf(" u[%ld] = %f\n", v, curves[i].v_params[v]);
}
}
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
printf(" material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
printf(" material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
printf(" material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
printf(" material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
printf(" material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
printf(" material.Ns = %f\n", materials[i].shininess);
printf(" material.Ni = %f\n", materials[i].ior);
printf(" material.dissolve = %f\n", 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].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());
}
printf("\n");
}
}
static bool
TestLoadObj(
const char* filename,
const char* basepath = NULL)
{
std::cout << "Loading " << filename << std::endl;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::curve_t> curves;
std::vector<tinyobj::material_t> materials;
std::string err = tinyobj::LoadObj(shapes, curves, materials, filename, basepath);
if (!err.empty()) {
std::cerr << err << std::endl;
return false;
}
PrintInfo(shapes, curves, materials);
return true;
}
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";
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 std::string operator() (
const std::string& matId,
std::vector<material_t>& materials,
std::map<std::string, int>& matMap)
{
return LoadMtl(matMap, materials, m_matSStream);
}
private:
std::stringstream m_matSStream;
};
MaterialStringStreamReader matSSReader(matStream);
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::curve_t> curves;
std::vector<tinyobj::material_t> materials;
std::string err = tinyobj::LoadObj(shapes, curves, materials, objStream, matSSReader);
if (!err.empty()) {
std::cerr << err << std::endl;
return false;
}
PrintInfo(shapes, curves, materials);
return true;
}
int
main(
int argc,
char **argv)
{
if (argc > 1) {
const char* basepath = NULL;
if (argc > 2) {
basepath = argv[2];
}
assert(true == TestLoadObj(argv[1], basepath));
} else {
//assert(true == TestLoadObj("cornell_box.obj"));
//assert(true == TestLoadObj("cube.obj"));
assert(true == TestStreamLoadObj());
}
return 0;
}

View File

@@ -1,16 +0,0 @@
.PHONY: clean
CXX ?= g++
CXXFLAGS ?= -g -O2
tester: tester.cc
$(CXX) $(CXXFLAGS) -o tester tester.cc
all: tester
check: tester
./tester
clean:
rm -rf tester

View File

@@ -1,37 +0,0 @@
# Build&Test
## Use makefile
$ make check
## Use ninja + kuroga
Assume
* ninja 1.4+
* python 2.6+
Are installed.
### Linux/MacOSX
$ python kuroga.py config-posix.py
$ ninja
### Windows
Visual Studio 2013 is required to build tester.
On Windows console.
> python kuroga.py config-msvc.py
> vcbuild.bat
Or on msys2 bash,
$ python kuroga.py config-msvc.py
$ cmd //c vcbuild.bat

File diff suppressed because it is too large Load Diff

View File

@@ -1,52 +0,0 @@
exe = "tester.exe"
toolchain = "msvc"
# optional
link_pool_depth = 1
# optional
builddir = {
"gnu" : "build"
, "msvc" : "build"
, "clang" : "build"
}
includes = {
"gnu" : [ "-I." ]
, "msvc" : [ "/I." ]
, "clang" : [ "-I." ]
}
defines = {
"gnu" : [ "-DEXAMPLE=1" ]
, "msvc" : [ "/DEXAMPLE=1" ]
, "clang" : [ "-DEXAMPLE=1" ]
}
cflags = {
"gnu" : [ "-O2", "-g" ]
, "msvc" : [ "/O2" ]
, "clang" : [ "-O2", "-g" ]
}
cxxflags = {
"gnu" : [ "-O2", "-g" ]
, "msvc" : [ "/O2", "/W4", "/EHsc"]
, "clang" : [ "-O2", "-g", "-fsanitize=address" ]
}
ldflags = {
"gnu" : [ ]
, "msvc" : [ ]
, "clang" : [ "-fsanitize=address" ]
}
# optionsl
cxx_files = [ "tester.cc" ]
c_files = [ ]
# You can register your own toolchain through register_toolchain function
def register_toolchain(ninja):
pass

View File

@@ -1,53 +0,0 @@
exe = "tester"
# "gnu" or "clang"
toolchain = "gnu"
# optional
link_pool_depth = 1
# optional
builddir = {
"gnu" : "build"
, "msvc" : "build"
, "clang" : "build"
}
includes = {
"gnu" : [ "-I." ]
, "msvc" : [ "/I." ]
, "clang" : [ "-I." ]
}
defines = {
"gnu" : [ ]
, "msvc" : [ ]
, "clang" : [ ]
}
cflags = {
"gnu" : [ "-O2", "-g" ]
, "msvc" : [ "/O2" ]
, "clang" : [ "-O2", "-g" ]
}
# Warn as much as possible: http://qiita.com/MitsutakaTakeda/items/6b9966f890cc9b944d75
cxxflags = {
"gnu" : [ "-O2", "-g", "-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused", "-fsanitize=address" ]
, "msvc" : [ "/O2", "/W4" ]
, "clang" : [ "-O2", "-g", "-Werror -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic", "-fsanitize=address" ]
}
ldflags = {
"gnu" : [ "-fsanitize=address" ]
, "msvc" : [ ]
, "clang" : [ "-fsanitize=address" ]
}
cxx_files = [ "tester.cc" ]
c_files = [ ]
# You can register your own toolchain through register_toolchain function
def register_toolchain(ninja):
pass

View File

@@ -1,312 +0,0 @@
#!/usr/bin/env python
#
# Kuroga, single python file meta-build system for ninja
# https://github.com/lighttransport/kuroga
#
# Requirements: python 2.6 or 2.7
#
# Usage: $ python kuroga.py input.py
#
import imp
import re
import textwrap
import glob
import os
import sys
# gcc preset
def add_gnu_rule(ninja):
ninja.rule('gnucxx', description='CXX $out',
command='$gnucxx -MMD -MF $out.d $gnudefines $gnuincludes $gnucxxflags -c $in -o $out',
depfile='$out.d', deps='gcc')
ninja.rule('gnucc', description='CC $out',
command='$gnucc -MMD -MF $out.d $gnudefines $gnuincludes $gnucflags -c $in -o $out',
depfile='$out.d', deps='gcc')
ninja.rule('gnulink', description='LINK $out', pool='link_pool',
command='$gnuld -o $out $in $libs $gnuldflags')
ninja.rule('gnuar', description='AR $out', pool='link_pool',
command='$gnuar rsc $out $in')
ninja.rule('gnustamp', description='STAMP $out', command='touch $out')
ninja.newline()
ninja.variable('gnucxx', 'g++')
ninja.variable('gnucc', 'gcc')
ninja.variable('gnuld', '$gnucxx')
ninja.variable('gnuar', 'ar')
ninja.newline()
# clang preset
def add_clang_rule(ninja):
ninja.rule('clangcxx', description='CXX $out',
command='$clangcxx -MMD -MF $out.d $clangdefines $clangincludes $clangcxxflags -c $in -o $out',
depfile='$out.d', deps='gcc')
ninja.rule('clangcc', description='CC $out',
command='$clangcc -MMD -MF $out.d $clangdefines $clangincludes $clangcflags -c $in -o $out',
depfile='$out.d', deps='gcc')
ninja.rule('clanglink', description='LINK $out', pool='link_pool',
command='$clangld -o $out $in $libs $clangldflags')
ninja.rule('clangar', description='AR $out', pool='link_pool',
command='$clangar rsc $out $in')
ninja.rule('clangstamp', description='STAMP $out', command='touch $out')
ninja.newline()
ninja.variable('clangcxx', 'clang++')
ninja.variable('clangcc', 'clang')
ninja.variable('clangld', '$clangcxx')
ninja.variable('clangar', 'ar')
ninja.newline()
# msvc preset
def add_msvc_rule(ninja):
ninja.rule('msvccxx', description='CXX $out',
command='$msvccxx /TP /showIncludes $msvcdefines $msvcincludes $msvccxxflags -c $in /Fo$out',
depfile='$out.d', deps='msvc')
ninja.rule('msvccc', description='CC $out',
command='$msvccc /TC /showIncludes $msvcdefines $msvcincludes $msvccflags -c $in /Fo$out',
depfile='$out.d', deps='msvc')
ninja.rule('msvclink', description='LINK $out', pool='link_pool',
command='$msvcld $msvcldflags $in $libs /OUT:$out')
ninja.rule('msvcar', description='AR $out', pool='link_pool',
command='$msvcar $in /OUT:$out')
#ninja.rule('msvcstamp', description='STAMP $out', command='touch $out')
ninja.newline()
ninja.variable('msvccxx', 'cl.exe')
ninja.variable('msvccc', 'cl.exe')
ninja.variable('msvcld', 'link.exe')
ninja.variable('msvcar', 'lib.exe')
ninja.newline()
# -- from ninja_syntax.py --
def escape_path(word):
return word.replace('$ ', '$$ ').replace(' ', '$ ').replace(':', '$:')
class Writer(object):
def __init__(self, output, width=78):
self.output = output
self.width = width
def newline(self):
self.output.write('\n')
def comment(self, text, has_path=False):
for line in textwrap.wrap(text, self.width - 2, break_long_words=False,
break_on_hyphens=False):
self.output.write('# ' + line + '\n')
def variable(self, key, value, indent=0):
if value is None:
return
if isinstance(value, list):
value = ' '.join(filter(None, value)) # Filter out empty strings.
self._line('%s = %s' % (key, value), indent)
def pool(self, name, depth):
self._line('pool %s' % name)
self.variable('depth', depth, indent=1)
def rule(self, name, command, description=None, depfile=None,
generator=False, pool=None, restat=False, rspfile=None,
rspfile_content=None, deps=None):
self._line('rule %s' % name)
self.variable('command', command, indent=1)
if description:
self.variable('description', description, indent=1)
if depfile:
self.variable('depfile', depfile, indent=1)
if generator:
self.variable('generator', '1', indent=1)
if pool:
self.variable('pool', pool, indent=1)
if restat:
self.variable('restat', '1', indent=1)
if rspfile:
self.variable('rspfile', rspfile, indent=1)
if rspfile_content:
self.variable('rspfile_content', rspfile_content, indent=1)
if deps:
self.variable('deps', deps, indent=1)
def build(self, outputs, rule, inputs=None, implicit=None, order_only=None,
variables=None):
outputs = as_list(outputs)
out_outputs = [escape_path(x) for x in outputs]
all_inputs = [escape_path(x) for x in as_list(inputs)]
if implicit:
implicit = [escape_path(x) for x in as_list(implicit)]
all_inputs.append('|')
all_inputs.extend(implicit)
if order_only:
order_only = [escape_path(x) for x in as_list(order_only)]
all_inputs.append('||')
all_inputs.extend(order_only)
self._line('build %s: %s' % (' '.join(out_outputs),
' '.join([rule] + all_inputs)))
if variables:
if isinstance(variables, dict):
iterator = iter(variables.items())
else:
iterator = iter(variables)
for key, val in iterator:
self.variable(key, val, indent=1)
return outputs
def include(self, path):
self._line('include %s' % path)
def subninja(self, path):
self._line('subninja %s' % path)
def default(self, paths):
self._line('default %s' % ' '.join(as_list(paths)))
def _count_dollars_before_index(self, s, i):
"""Returns the number of '$' characters right in front of s[i]."""
dollar_count = 0
dollar_index = i - 1
while dollar_index > 0 and s[dollar_index] == '$':
dollar_count += 1
dollar_index -= 1
return dollar_count
def _line(self, text, indent=0):
"""Write 'text' word-wrapped at self.width characters."""
leading_space = ' ' * indent
while len(leading_space) + len(text) > self.width:
# The text is too wide; wrap if possible.
# Find the rightmost space that would obey our width constraint and
# that's not an escaped space.
available_space = self.width - len(leading_space) - len(' $')
space = available_space
while True:
space = text.rfind(' ', 0, space)
if (space < 0 or
self._count_dollars_before_index(text, space) % 2 == 0):
break
if space < 0:
# No such space; just use the first unescaped space we can find.
space = available_space - 1
while True:
space = text.find(' ', space + 1)
if (space < 0 or
self._count_dollars_before_index(text, space) % 2 == 0):
break
if space < 0:
# Give up on breaking.
break
self.output.write(leading_space + text[0:space] + ' $\n')
text = text[space+1:]
# Subsequent lines are continuations, so indent them.
leading_space = ' ' * (indent+2)
self.output.write(leading_space + text + '\n')
def close(self):
self.output.close()
def as_list(input):
if input is None:
return []
if isinstance(input, list):
return input
return [input]
# -- end from ninja_syntax.py --
def gen(ninja, toolchain, config):
ninja.variable('ninja_required_version', '1.4')
ninja.newline()
if hasattr(config, "builddir"):
builddir = config.builddir[toolchain]
ninja.variable(toolchain + 'builddir', builddir)
else:
builddir = ''
ninja.variable(toolchain + 'defines', config.defines[toolchain] or [])
ninja.variable(toolchain + 'includes', config.includes[toolchain] or [])
ninja.variable(toolchain + 'cflags', config.cflags[toolchain] or [])
ninja.variable(toolchain + 'cxxflags', config.cxxflags[toolchain] or [])
ninja.variable(toolchain + 'ldflags', config.ldflags[toolchain] or [])
ninja.newline()
if hasattr(config, "link_pool_depth"):
ninja.pool('link_pool', depth=config.link_pool_depth)
else:
ninja.pool('link_pool', depth=4)
ninja.newline()
# Add default toolchain(gnu, clang and msvc)
add_gnu_rule(ninja)
add_clang_rule(ninja)
add_msvc_rule(ninja)
obj_files = []
cc = toolchain + 'cc'
cxx = toolchain + 'cxx'
link = toolchain + 'link'
ar = toolchain + 'ar'
if hasattr(config, "cxx_files"):
for src in config.cxx_files:
srcfile = src
obj = os.path.splitext(srcfile)[0] + '.o'
obj = os.path.join(builddir, obj);
obj_files.append(obj)
ninja.build(obj, cxx, srcfile)
ninja.newline()
if hasattr(config, "c_files"):
for src in config.c_files:
srcfile = src
obj = os.path.splitext(srcfile)[0] + '.o'
obj = os.path.join(builddir, obj);
obj_files.append(obj)
ninja.build(obj, cc, srcfile)
ninja.newline()
targetlist = []
if hasattr(config, "exe"):
ninja.build(config.exe, link, obj_files)
targetlist.append(config.exe)
if hasattr(config, "staticlib"):
ninja.build(config.staticlib, ar, obj_files)
targetlist.append(config.staticlib)
ninja.build('all', 'phony', targetlist)
ninja.newline()
ninja.default('all')
def main():
if len(sys.argv) < 2:
print("Usage: python kuroga.py config.py")
sys.exit(1)
config = imp.load_source("config", sys.argv[1])
f = open('build.ninja', 'w')
ninja = Writer(f)
if hasattr(config, "register_toolchain"):
config.register_toolchain(ninja)
gen(ninja, config.toolchain, config)
f.close()
main()

View File

@@ -1,569 +0,0 @@
#define TINYOBJLOADER_IMPLEMENTATION
#include "../tiny_obj_loader.h"
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <sstream>
#include <fstream>
static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool triangulate = true)
{
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 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", 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]));
}
for (size_t v = 0; v < attrib.normals.size() / 3; v++) {
printf(" n[%ld] = (%f, %f, %f)\n", 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]));
}
for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) {
printf(" uv[%ld] = (%f, %f)\n", v,
static_cast<const double>(attrib.texcoords[2*v+0]),
static_cast<const double>(attrib.texcoords[2*v+1]));
}
for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
if (triangulate)
{
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert((shapes[i].mesh.indices.size() % 3) == 0);
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
tinyobj::index_t i0 = shapes[i].mesh.indices[3*f+0];
tinyobj::index_t i1 = shapes[i].mesh.indices[3*f+1];
tinyobj::index_t i2 = shapes[i].mesh.indices[3*f+2];
printf(" idx[%ld] = %d/%d/%d, %d/%d/%d, %d/%d/%d. mat_id = %d\n", f,
i0.vertex_index, i0.normal_index, i0.texcoord_index,
i1.vertex_index, i1.normal_index, i1.texcoord_index,
i2.vertex_index, i2.normal_index, i2.texcoord_index,
shapes[i].mesh.material_ids[f]);
}
} else {
for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) {
tinyobj::index_t idx = shapes[i].mesh.indices[f];
printf(" idx[%ld] = %d/%d/%d\n", f, idx.vertex_index, idx.normal_index, idx.texcoord_index);
}
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert(shapes[i].mesh.material_ids.size() == shapes[i].mesh.num_face_vertices.size());
for (size_t m = 0; m < shapes[i].mesh.material_ids.size(); m++) {
printf(" material_id[%ld] = %d\n", m,
shapes[i].mesh.material_ids[m]);
}
}
printf("shape[%ld].num_faces: %ld\n", i, shapes[i].mesh.num_face_vertices.size());
for (size_t v = 0; v < shapes[i].mesh.num_face_vertices.size(); v++) {
printf(" num_vertices[%ld] = %ld\n", v,
static_cast<long>(shapes[i].mesh.num_face_vertices[v]));
}
//printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
//assert((shapes[i].mesh.positions.size() % 3) == 0);
//for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
// printf(" v[%ld] = (%f, %f, %f)\n", v,
// static_cast<const double>(shapes[i].mesh.positions[3*v+0]),
// static_cast<const double>(shapes[i].mesh.positions[3*v+1]),
// static_cast<const double>(shapes[i].mesh.positions[3*v+2]));
//}
printf("shape[%ld].num_tags: %ld\n", i, shapes[i].mesh.tags.size());
for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) {
printf(" tag[%ld] = %s ", 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(", ");
}
}
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(", ");
}
}
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(", ");
}
}
printf("]");
printf("\n");
}
}
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%ld].name = %s\n", 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.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_bump = %s\n", materials[i].bump_texname.c_str());
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());
for (; it != itEnd; it++) {
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
}
printf("\n");
}
}
static bool
TestLoadObj(
const char* filename,
const char* basepath = NULL,
bool triangulate = true)
{
std::cout << "Loading " << filename << std::endl;
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, basepath, triangulate);
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
printf("Failed to load/parse .obj.\n");
return false;
}
PrintInfo(attrib, shapes, materials, triangulate);
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()
{
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";
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;
}
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);
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
return false;
}
PrintInfo(attrib, shapes, materials);
return true;
}
const char* gMtlBasePath = "../models/";
TEST_CASE("cornell_box", "[Loader]") {
REQUIRE(true == TestLoadObj("../models/cornell_box.obj", gMtlBasePath));
}
TEST_CASE("catmark_torus_creases0", "[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/catmark_torus_creases0.obj", gMtlBasePath, /*triangulate*/false);
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(1 == shapes.size());
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());
}
#if 0
int
main(
int argc,
char **argv)
{
if (argc > 1) {
const char* basepath = NULL;
if (argc > 2) {
basepath = argv[2];
}
assert(true == TestLoadObj(argv[1], basepath));
} else {
//assert(true == TestLoadObj("cornell_box.obj"));
//assert(true == TestLoadObj("cube.obj"));
assert(true == TestStreamLoadObj());
assert(true == TestLoadObj("catmark_torus_creases0.obj", NULL, false));
}
return 0;
}
#endif

View File

@@ -1,4 +0,0 @@
chcp 437
python kuroga.py config-msvc.py
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64
ninja

View File

@@ -1,2 +1,989 @@
#define TINYOBJLOADER_IMPLEMENTATION
//
// Copyright 2012-2015, Syoyo Fujita.
//
// Licensed under 2-clause BSD liecense.
//
//
// version 0.9.14: Initial support of parsing curve primitive.
// version 0.9.13: Report "Material file not found message" in `err`(#46)
// version 0.9.12: Fix groups being ignored if they have 'usemtl' just before
// 'g' (#44)
// version 0.9.11: Invert `Tr` parameter(#43)
// version 0.9.10: Fix seg fault on windows.
// version 0.9.9 : Replace atof() with custom parser.
// version 0.9.8 : Fix multi-materials(per-face material ID).
// version 0.9.7 : Support multi-materials(per-face material ID) per
// object/group.
// version 0.9.6 : Support Ni(index of refraction) mtl parameter.
// Parse transmittance material parameter correctly.
// version 0.9.5 : Parse multiple group name.
// Add support of specifying the base path to load material
// file.
// version 0.9.4 : Initial suupport of group tag(g)
// version 0.9.3 : Fix parsing triple 'x/y/z'
// version 0.9.2 : Add more .mtl load support
// version 0.9.1 : Add initial .mtl load support
// version 0.9.0 : Initial
//
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <string>
#include <vector>
#include <map>
#include <fstream>
#include <sstream>
#include "tiny_obj_loader.h"
namespace tinyobj {
#define TINYOBJ_SSCANF_BUFFER_SIZE (4096)
struct vertex_index {
int v_idx, vt_idx, vn_idx;
vertex_index(){};
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){};
};
// for std::map
static inline bool operator<(const vertex_index &a, const vertex_index &b) {
if (a.v_idx != b.v_idx)
return (a.v_idx < b.v_idx);
if (a.vn_idx != b.vn_idx)
return (a.vn_idx < b.vn_idx);
if (a.vt_idx != b.vt_idx)
return (a.vt_idx < b.vt_idx);
return false;
}
struct obj_shape {
std::vector<float> v;
std::vector<float> vn;
std::vector<float> vt;
};
static inline bool isSpace(const char c) { return (c == ' ') || (c == '\t'); }
static inline bool isNewLine(const char c) {
return (c == '\r') || (c == '\n') || (c == '\0');
}
// Make index zero-base, and also support relative index.
static inline int fixIndex(int idx, int n) {
if (idx > 0)
return idx - 1;
if (idx == 0)
return 0;
return n + idx; // negative value = relative
}
static inline std::string parseString(const char *&token) {
std::string s;
token += strspn(token, " \t");
size_t e = strcspn(token, " \t\r");
s = std::string(token, &token[e]);
token += e;
return s;
}
static inline int parseInt(const char *&token) {
token += strspn(token, " \t");
int i = atoi(token);
token += strcspn(token, " \t\r");
return i;
}
// Tries to parse a floating point number located at s.
//
// s_end should be a location in the string where reading should absolutely
// stop. For example at the end of the string, to prevent buffer overflows.
//
// Parses the following EBNF grammar:
// sign = "+" | "-" ;
// END = ? anything not in digit ?
// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
// integer = [sign] , digit , {digit} ;
// decimal = integer , ["." , integer] ;
// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ;
//
// Valid strings are for example:
// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2
//
// If the parsing is a success, result is set to the parsed value and true
// is returned.
//
// The function is greedy and will parse until any of the following happens:
// - a non-conforming character is encountered.
// - s_end is reached.
//
// The following situations triggers a failure:
// - s >= s_end.
// - parse failure.
//
static bool tryParseDouble(const char *s, const char *s_end, double *result) {
if (s >= s_end) {
return false;
}
double mantissa = 0.0;
// This exponent is base 2 rather than 10.
// However the exponent we parse is supposed to be one of ten,
// thus we must take care to convert the exponent/and or the
// mantissa to a * 2^E, where a is the mantissa and E is the
// exponent.
// To get the final double we will use ldexp, it requires the
// exponent to be in base 2.
int exponent = 0;
// NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED
// TO JUMP OVER DEFINITIONS.
char sign = '+';
char exp_sign = '+';
char const *curr = s;
// How many characters were read in a loop.
int read = 0;
// Tells whether a loop terminated due to reaching s_end.
bool end_not_reached = false;
/*
BEGIN PARSING.
*/
// Find out what sign we've got.
if (*curr == '+' || *curr == '-') {
sign = *curr;
curr++;
} else if (isdigit(*curr)) { /* Pass through. */
} else {
goto fail;
}
// Read the integer part.
while ((end_not_reached = (curr != s_end)) && isdigit(*curr)) {
mantissa *= 10;
mantissa += static_cast<int>(*curr - 0x30);
curr++;
read++;
}
// We must make sure we actually got something.
if (read == 0)
goto fail;
// We allow numbers of form "#", "###" etc.
if (!end_not_reached)
goto assemble;
// Read the decimal part.
if (*curr == '.') {
curr++;
read = 1;
while ((end_not_reached = (curr != s_end)) && isdigit(*curr)) {
// NOTE: Don't use powf here, it will absolutely murder precision.
mantissa += static_cast<int>(*curr - 0x30) * pow(10.0, -read);
read++;
curr++;
}
} else if (*curr == 'e' || *curr == 'E') {
} else {
goto assemble;
}
if (!end_not_reached)
goto assemble;
// Read the exponent part.
if (*curr == 'e' || *curr == 'E') {
curr++;
// Figure out if a sign is present and if it is.
if ((end_not_reached = (curr != s_end)) && (*curr == '+' || *curr == '-')) {
exp_sign = *curr;
curr++;
} else if (isdigit(*curr)) { /* Pass through. */
} else {
// Empty E is not allowed.
goto fail;
}
read = 0;
while ((end_not_reached = (curr != s_end)) && isdigit(*curr)) {
exponent *= 10;
exponent += static_cast<int>(*curr - 0x30);
curr++;
read++;
}
exponent *= (exp_sign == '+' ? 1 : -1);
if (read == 0)
goto fail;
}
assemble:
*result =
(sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), exponent);
return true;
fail:
return false;
}
static inline float parseFloat(const char *&token) {
token += strspn(token, " \t");
#ifdef TINY_OBJ_LOADER_OLD_FLOAT_PARSER
float f = (float)atof(token);
token += strcspn(token, " \t\r");
#else
const char *end = token + strcspn(token, " \t\r");
double val = 0.0;
tryParseDouble(token, end, &val);
float f = static_cast<float>(val);
token = end;
#endif
return f;
}
static inline void parseFloat2(float &x, float &y, const char *&token) {
x = parseFloat(token);
y = parseFloat(token);
}
static inline void parseFloat3(float &x, float &y, float &z,
const char *&token) {
x = parseFloat(token);
y = parseFloat(token);
z = parseFloat(token);
}
// Parse triples: i, i/j/k, i//k, i/j
static vertex_index parseTriple(const char *&token, int vsize, int vnsize,
int vtsize) {
vertex_index vi(-1);
vi.v_idx = fixIndex(atoi(token), vsize);
token += strcspn(token, "/ \t\r");
if (token[0] != '/') {
return vi;
}
token++;
// i//k
if (token[0] == '/') {
token++;
vi.vn_idx = fixIndex(atoi(token), vnsize);
token += strcspn(token, "/ \t\r");
return vi;
}
// i/j/k or i/j
vi.vt_idx = fixIndex(atoi(token), vtsize);
token += strcspn(token, "/ \t\r");
if (token[0] != '/') {
return vi;
}
// i/j/k
token++; // skip '/'
vi.vn_idx = fixIndex(atoi(token), vnsize);
token += strcspn(token, "/ \t\r");
return vi;
}
static unsigned int
updateVertex(std::map<vertex_index, unsigned int> &vertexCache,
std::vector<float> &positions, std::vector<float> &normals,
std::vector<float> &texcoords,
const std::vector<float> &in_positions,
const std::vector<float> &in_normals,
const std::vector<float> &in_texcoords, const vertex_index &i) {
const std::map<vertex_index, unsigned int>::iterator it = vertexCache.find(i);
if (it != vertexCache.end()) {
// found cache
return it->second;
}
assert(in_positions.size() > (unsigned int)(3 * i.v_idx + 2));
positions.push_back(in_positions[3 * i.v_idx + 0]);
positions.push_back(in_positions[3 * i.v_idx + 1]);
positions.push_back(in_positions[3 * i.v_idx + 2]);
if (i.vn_idx >= 0) {
normals.push_back(in_normals[3 * i.vn_idx + 0]);
normals.push_back(in_normals[3 * i.vn_idx + 1]);
normals.push_back(in_normals[3 * i.vn_idx + 2]);
}
if (i.vt_idx >= 0) {
texcoords.push_back(in_texcoords[2 * i.vt_idx + 0]);
texcoords.push_back(in_texcoords[2 * i.vt_idx + 1]);
}
unsigned int idx = static_cast<unsigned int>(positions.size() / 3 - 1);
vertexCache[i] = idx;
return idx;
}
void InitMaterial(material_t &material) {
material.name = "";
material.ambient_texname = "";
material.diffuse_texname = "";
material.specular_texname = "";
material.normal_texname = "";
for (int i = 0; i < 3; i++) {
material.ambient[i] = 0.f;
material.diffuse[i] = 0.f;
material.specular[i] = 0.f;
material.transmittance[i] = 0.f;
material.emission[i] = 0.f;
}
material.illum = 0;
material.dissolve = 1.f;
material.shininess = 1.f;
material.ior = 1.f;
material.unknown_parameter.clear();
}
static bool exportFaceGroupToShape(
shape_t &shape, std::map<vertex_index, unsigned int> vertexCache,
const std::vector<float> &in_positions,
const std::vector<float> &in_normals,
const std::vector<float> &in_texcoords,
const std::vector<std::vector<vertex_index> > &faceGroup,
const int material_id, const std::string &name, bool clearCache) {
if (faceGroup.empty()) {
return false;
}
// Flatten vertices and indices
for (size_t i = 0; i < faceGroup.size(); i++) {
const std::vector<vertex_index> &face = faceGroup[i];
vertex_index i0 = face[0];
vertex_index i1(-1);
vertex_index i2 = face[1];
size_t npolys = face.size();
// Polygon -> triangle fan conversion
for (size_t k = 2; k < npolys; k++) {
i1 = i2;
i2 = face[k];
unsigned int v0 = updateVertex(
vertexCache, shape.mesh.positions, shape.mesh.normals,
shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i0);
unsigned int v1 = updateVertex(
vertexCache, shape.mesh.positions, shape.mesh.normals,
shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i1);
unsigned int v2 = updateVertex(
vertexCache, shape.mesh.positions, shape.mesh.normals,
shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i2);
shape.mesh.indices.push_back(v0);
shape.mesh.indices.push_back(v1);
shape.mesh.indices.push_back(v2);
shape.mesh.material_ids.push_back(material_id);
}
}
shape.name = name;
if (clearCache)
vertexCache.clear();
return true;
}
std::string LoadMtl(std::map<std::string, int> &material_map,
std::vector<material_t> &materials,
std::istream &inStream) {
std::stringstream err;
// Create a default material anyway.
material_t material;
InitMaterial(material);
int maxchars = 8192; // Alloc enough size.
std::vector<char> buf(maxchars); // Alloc enough size.
while (inStream.peek() != -1) {
inStream.getline(&buf[0], maxchars);
std::string linebuf(&buf[0]);
// Trim newline '\r\n' or '\n'
if (linebuf.size() > 0) {
if (linebuf[linebuf.size() - 1] == '\n')
linebuf.erase(linebuf.size() - 1);
}
if (linebuf.size() > 0) {
if (linebuf[linebuf.size() - 1] == '\r')
linebuf.erase(linebuf.size() - 1);
}
// Skip if empty line.
if (linebuf.empty()) {
continue;
}
// Skip leading space.
const char *token = linebuf.c_str();
token += strspn(token, " \t");
assert(token);
if (token[0] == '\0')
continue; // empty line
if (token[0] == '#')
continue; // comment line
// new mtl
if ((0 == strncmp(token, "newmtl", 6)) && isSpace((token[6]))) {
// flush previous material.
if (!material.name.empty()) {
material_map.insert(std::pair<std::string, int>(
material.name, static_cast<int>(materials.size())));
materials.push_back(material);
}
// initial temporary material
InitMaterial(material);
// set new mtl name
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
token += 7;
#ifdef _MSC_VER
sscanf_s(token, "%s", namebuf, _countof(namebuf));
#else
sscanf(token, "%s", namebuf);
#endif
material.name = namebuf;
continue;
}
// ambient
if (token[0] == 'K' && token[1] == 'a' && isSpace((token[2]))) {
token += 2;
float r, g, b;
parseFloat3(r, g, b, token);
material.ambient[0] = r;
material.ambient[1] = g;
material.ambient[2] = b;
continue;
}
// diffuse
if (token[0] == 'K' && token[1] == 'd' && isSpace((token[2]))) {
token += 2;
float r, g, b;
parseFloat3(r, g, b, token);
material.diffuse[0] = r;
material.diffuse[1] = g;
material.diffuse[2] = b;
continue;
}
// specular
if (token[0] == 'K' && token[1] == 's' && isSpace((token[2]))) {
token += 2;
float r, g, b;
parseFloat3(r, g, b, token);
material.specular[0] = r;
material.specular[1] = g;
material.specular[2] = b;
continue;
}
// transmittance
if (token[0] == 'K' && token[1] == 't' && isSpace((token[2]))) {
token += 2;
float r, g, b;
parseFloat3(r, g, b, token);
material.transmittance[0] = r;
material.transmittance[1] = g;
material.transmittance[2] = b;
continue;
}
// ior(index of refraction)
if (token[0] == 'N' && token[1] == 'i' && isSpace((token[2]))) {
token += 2;
material.ior = parseFloat(token);
continue;
}
// emission
if (token[0] == 'K' && token[1] == 'e' && isSpace(token[2])) {
token += 2;
float r, g, b;
parseFloat3(r, g, b, token);
material.emission[0] = r;
material.emission[1] = g;
material.emission[2] = b;
continue;
}
// shininess
if (token[0] == 'N' && token[1] == 's' && isSpace(token[2])) {
token += 2;
material.shininess = parseFloat(token);
continue;
}
// illum model
if (0 == strncmp(token, "illum", 5) && isSpace(token[5])) {
token += 6;
material.illum = parseInt(token);
continue;
}
// dissolve
if ((token[0] == 'd' && isSpace(token[1]))) {
token += 1;
material.dissolve = parseFloat(token);
continue;
}
if (token[0] == 'T' && token[1] == 'r' && isSpace(token[2])) {
token += 2;
// Invert value of Tr(assume Tr is in range [0, 1])
material.dissolve = 1.0f - parseFloat(token);
continue;
}
// ambient texture
if ((0 == strncmp(token, "map_Ka", 6)) && isSpace(token[6])) {
token += 7;
material.ambient_texname = token;
continue;
}
// diffuse texture
if ((0 == strncmp(token, "map_Kd", 6)) && isSpace(token[6])) {
token += 7;
material.diffuse_texname = token;
continue;
}
// specular texture
if ((0 == strncmp(token, "map_Ks", 6)) && isSpace(token[6])) {
token += 7;
material.specular_texname = token;
continue;
}
// normal texture
if ((0 == strncmp(token, "map_Ns", 6)) && isSpace(token[6])) {
token += 7;
material.normal_texname = token;
continue;
}
// unknown parameter
const char *_space = strchr(token, ' ');
if (!_space) {
_space = strchr(token, '\t');
}
if (_space) {
std::ptrdiff_t len = _space - token;
std::string key(token, len);
std::string value = _space + 1;
material.unknown_parameter.insert(
std::pair<std::string, std::string>(key, value));
}
}
// flush last material.
material_map.insert(std::pair<std::string, int>(
material.name, static_cast<int>(materials.size())));
materials.push_back(material);
return err.str();
}
std::string MaterialFileReader::operator()(const std::string &matId,
std::vector<material_t> &materials,
std::map<std::string, int> &matMap) {
std::string filepath;
if (!m_mtlBasePath.empty()) {
filepath = std::string(m_mtlBasePath) + matId;
} else {
filepath = matId;
}
std::ifstream matIStream(filepath.c_str());
std::string err = LoadMtl(matMap, materials, matIStream);
if (!matIStream) {
std::stringstream ss;
ss << "WARN: Material file [ " << filepath
<< " ] not found. Created a default material.";
err += ss.str();
}
return err;
}
std::string LoadObj(std::vector<shape_t> &shapes, std::vector<curve_t> &curves,
std::vector<material_t> &materials, // [output]
const char *filename, const char *mtl_basepath) {
shapes.clear();
std::stringstream err;
std::ifstream ifs(filename);
if (!ifs) {
err << "Cannot open file [" << filename << "]" << std::endl;
return err.str();
}
std::string basePath;
if (mtl_basepath) {
basePath = mtl_basepath;
}
MaterialFileReader matFileReader(basePath);
return LoadObj(shapes, curves, materials, ifs, matFileReader);
}
std::string LoadObj(std::vector<shape_t> &shapes, // [output]
std::vector<curve_t> &curves, // [output]
std::vector<material_t> &materials, // [output]
std::istream &inStream, MaterialReader &readMatFn) {
std::stringstream err;
std::vector<float> v;
std::vector<float> vn;
std::vector<float> vt;
std::vector<std::vector<vertex_index> > faceGroup;
std::string name;
// curve
int curveType = -1;
int curveDegree = -1;
std::vector<unsigned int> curve_indices;
std::vector<float> u_params;
std::vector<float> v_params;
// material
std::map<std::string, int> material_map;
std::map<vertex_index, unsigned int> vertexCache;
int material = -1;
shape_t shape;
int maxchars = 8192; // Alloc enough size.
std::vector<char> buf(maxchars); // Alloc enough size.
while (inStream.peek() != -1) {
inStream.getline(&buf[0], maxchars);
std::string linebuf(&buf[0]);
// Trim newline '\r\n' or '\n'
if (linebuf.size() > 0) {
if (linebuf[linebuf.size() - 1] == '\n')
linebuf.erase(linebuf.size() - 1);
}
if (linebuf.size() > 0) {
if (linebuf[linebuf.size() - 1] == '\r')
linebuf.erase(linebuf.size() - 1);
}
// Skip if empty line.
if (linebuf.empty()) {
continue;
}
// Skip leading space.
const char *token = linebuf.c_str();
token += strspn(token, " \t");
assert(token);
if (token[0] == '\0')
continue; // empty line
if (token[0] == '#')
continue; // comment line
// vertex
if (token[0] == 'v' && isSpace((token[1]))) {
token += 2;
float x, y, z;
parseFloat3(x, y, z, token);
v.push_back(x);
v.push_back(y);
v.push_back(z);
continue;
}
// normal
if (token[0] == 'v' && token[1] == 'n' && isSpace((token[2]))) {
token += 3;
float x, y, z;
parseFloat3(x, y, z, token);
vn.push_back(x);
vn.push_back(y);
vn.push_back(z);
continue;
}
// texcoord
if (token[0] == 'v' && token[1] == 't' && isSpace((token[2]))) {
token += 3;
float x, y;
parseFloat2(x, y, token);
vt.push_back(x);
vt.push_back(y);
continue;
}
// face
if (token[0] == 'f' && isSpace((token[1]))) {
token += 2;
token += strspn(token, " \t");
std::vector<vertex_index> face;
while (!isNewLine(token[0])) {
vertex_index vi = parseTriple(token, static_cast<int>(v.size() / 3),
static_cast<int>(vn.size() / 3),
static_cast<int>(vt.size() / 2));
face.push_back(vi);
size_t n = strspn(token, " \t\r");
token += n;
}
faceGroup.push_back(face);
continue;
}
// use mtl
if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) {
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
token += 7;
#ifdef _MSC_VER
sscanf_s(token, "%s", namebuf, _countof(namebuf));
#else
sscanf(token, "%s", namebuf);
#endif
// Create face group per material.
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt,
faceGroup, material, name, true);
if (ret) {
shapes.push_back(shape);
}
shape = shape_t();
faceGroup.clear();
if (material_map.find(namebuf) != material_map.end()) {
material = material_map[namebuf];
} else {
// { error!! material not found }
material = -1;
}
continue;
}
// load mtl
if ((0 == strncmp(token, "mtllib", 6)) && isSpace((token[6]))) {
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
token += 7;
#ifdef _MSC_VER
sscanf_s(token, "%s", namebuf, _countof(namebuf));
#else
sscanf(token, "%s", namebuf);
#endif
std::string err_mtl = readMatFn(namebuf, materials, material_map);
if (!err_mtl.empty()) {
faceGroup.clear(); // for safety
return err_mtl;
}
continue;
}
// group name
if (token[0] == 'g' && isSpace((token[1]))) {
// flush previous face group.
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt,
faceGroup, material, name, true);
if (ret) {
shapes.push_back(shape);
}
shape = shape_t();
// material = -1;
faceGroup.clear();
std::vector<std::string> names;
while (!isNewLine(token[0])) {
std::string str = parseString(token);
names.push_back(str);
token += strspn(token, " \t\r"); // skip tag
}
assert(names.size() > 0);
// names[0] must be 'g', so skip the 0th element.
if (names.size() > 1) {
name = names[1];
} else {
name = "";
}
continue;
}
// object name
if (token[0] == 'o' && isSpace((token[1]))) {
// flush previous face group.
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt,
faceGroup, material, name, true);
if (ret) {
shapes.push_back(shape);
}
// material = -1;
faceGroup.clear();
shape = shape_t();
// @todo { multiple object name? }
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
token += 2;
#ifdef _MSC_VER
sscanf_s(token, "%s", namebuf, _countof(namebuf));
#else
sscanf(token, "%s", namebuf);
#endif
name = std::string(namebuf);
continue;
}
// curve type
if ((0 == strncmp(token, "cstype", 6)) && isSpace((token[6]))) {
token += 7;
std::string type = parseString(token);
if (type == "bspline") { // 0
curveType = 0;
} else if (type == "bezier") { // 1
curveType = 1;
} else if (type == "cardinal") {
curveType = 2;
}
}
// degree(curve)
if (token[0] == 'd' && token[1] == 'e' && token[2] == 'g' &&
isSpace((token[3]))) {
token += 4;
curveDegree = parseInt(token);
continue;
}
// curve
if (token[0] == 'c' && token[1] == 'u' && token[2] == 'r' &&
token[3] == 'v' && isSpace((token[4]))) {
token += 5;
// parse u0 and u1
float u0, u1;
parseFloat2(u0, u1, token);
size_t n = strspn(token, " \t\r");
token += n;
// parse vertex indices.
curve_indices.clear();
while (!isNewLine(token[0])) {
vertex_index vi = parseTriple(token, static_cast<int>(v.size() / 3),
static_cast<int>(vn.size() / 3),
static_cast<int>(vt.size() / 2));
curve_indices.push_back(vi.v_idx);
size_t n = strspn(token, " \t\r");
token += n;
}
continue;
}
// curve param
if ((0 == strncmp(token, "parm", 4)) && isSpace((token[4]))) {
token += 5;
std::string name = parseString(token);
if (name == "u") {
u_params.clear();
} else if (name == "v") {
v_params.clear();
}
// parse parameter values.
while (!isNewLine(token[0])) {
float value = parseFloat(token);
if (name == "u") {
u_params.push_back(value);
} else if (name == "v") {
v_params.push_back(value);
}
}
continue;
}
// end(curve)
if (token[0] == 'e' && token[1] == 'n' && token[2] == 'd') {
// size_t n = strspn(token, " \t\r");
// token += n;
// @todo { Consider 'end' at the end of line: parm u 0 0 0 0 ... end }
if ((curveType > -1) && (curveDegree > 0) && (curve_indices.size() > 1)) {
curve_t curve;
curve.name = name;
curve.type = curveType;
curve.degree = curveDegree;
curve.positions = v;
curve.indices = curve_indices;
curve.u_params = u_params;
curve.v_params = v_params;
curves.push_back(curve);
}
u_params.clear();
v_params.clear();
curve_indices.clear();
continue;
}
// Ignore unknown command.
}
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup,
material, name, true);
if (ret) {
shapes.push_back(shape);
}
faceGroup.clear(); // for safety
return err.str();
}
} // namespace

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +0,0 @@
#!/bin/bash
DATEVAL=`date +%Y-%m-%d`
VERSIONVAL=master
# Use tag as version
if [ $TRAVIS_TAG ]; then
VERSIONVAL=$TRAVIS_TAG
fi
sed -e s%@DATE@%${DATEVAL}% .bintray.in > .bintray.tmp
sed -e s%@VERSION@%${VERSIONVAL}% .bintray.tmp > .bintray.json

Binary file not shown.

View File

@@ -6,5 +6,7 @@ build:
name: build
code: |
git clone https://github.com/syoyo/orebuildenv.git
cd tests
make check
chmod +x ./orebuildenv/build/linux/bin/premake4
./orebuildenv/build/linux/bin/premake4 gmake
make
./test_tinyobjloader