Add initial unit test codes using Catch.
Add Kuroga build script.
This commit is contained in:
@@ -3,6 +3,8 @@ cc = clang
|
||||
cxx = clang++
|
||||
cflags = -Werror -Weverything
|
||||
cxxflags = -Werror -Weverything
|
||||
#cflags = -O2
|
||||
#cxxflags = -O2
|
||||
|
||||
rule compile
|
||||
command = $cxx $cxxflags -c $in -o $out
|
||||
@@ -10,7 +12,7 @@ rule compile
|
||||
rule link
|
||||
command = $cxx $in -o $out
|
||||
|
||||
build test.o: compile test.cc
|
||||
build test: link test.o
|
||||
build loader_example.o: compile loader_example.cc
|
||||
build loader_example: link loader_example.o
|
||||
|
||||
default test
|
||||
default loader_example
|
||||
|
||||
6323
deps/cpplint.py
vendored
Executable file
6323
deps/cpplint.py
vendored
Executable file
File diff suppressed because it is too large
Load Diff
@@ -296,7 +296,7 @@ main(
|
||||
char **argv)
|
||||
{
|
||||
if (argc > 1) {
|
||||
const char* basepath = NULL;
|
||||
const char* basepath = "models/";
|
||||
if (argc > 2) {
|
||||
basepath = argv[2];
|
||||
}
|
||||
@@ -305,7 +305,7 @@ main(
|
||||
//assert(true == TestLoadObj("cornell_box.obj"));
|
||||
//assert(true == TestLoadObj("cube.obj"));
|
||||
assert(true == TestStreamLoadObj());
|
||||
assert(true == TestLoadObj("catmark_torus_creases0.obj", NULL, false));
|
||||
assert(true == TestLoadObj("models/catmark_torus_creases0.obj", "models/", false));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1,5 +1,5 @@
|
||||
sources = {
|
||||
"test.cc",
|
||||
"loader_example.cc",
|
||||
}
|
||||
|
||||
-- premake4.lua
|
||||
@@ -21,9 +21,9 @@ solution "TinyObjLoaderSolution"
|
||||
configuration "Debug"
|
||||
defines { "DEBUG" } -- -DDEBUG
|
||||
flags { "Symbols" }
|
||||
targetname "test_tinyobjloader_debug"
|
||||
targetname "loader_example_debug"
|
||||
|
||||
configuration "Release"
|
||||
-- defines { "NDEBUG" } -- -NDEBUG
|
||||
flags { "Symbols", "Optimize" }
|
||||
targetname "test_tinyobjloader"
|
||||
targetname "loader_example"
|
||||
|
||||
13
tests/Makefile
Normal file
13
tests/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
.PHONY: clean
|
||||
|
||||
tester: tester.cc
|
||||
g++ -g -O0 -o tester tester.cc
|
||||
|
||||
all: tester
|
||||
|
||||
check: tester
|
||||
./tester
|
||||
|
||||
clean:
|
||||
rm -rf tester
|
||||
|
||||
25
tests/README.md
Normal file
25
tests/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 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
|
||||
|
||||
> python kuroga.py config-msvc.py
|
||||
> vcbuild.bat
|
||||
|
||||
10445
tests/catch.hpp
Normal file
10445
tests/catch.hpp
Normal file
File diff suppressed because it is too large
Load Diff
52
tests/config-msvc.py
Normal file
52
tests/config-msvc.py
Normal file
@@ -0,0 +1,52 @@
|
||||
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" ]
|
||||
, "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
|
||||
|
||||
53
tests/config-posix.py
Normal file
53
tests/config-posix.py
Normal file
@@ -0,0 +1,53 @@
|
||||
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
|
||||
|
||||
312
tests/kuroga.py
Executable file
312
tests/kuroga.py
Executable file
@@ -0,0 +1,312 @@
|
||||
#!/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()
|
||||
324
tests/tester.cc
Normal file
324
tests/tester.cc
Normal file
@@ -0,0 +1,324 @@
|
||||
#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_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_vertices.size());
|
||||
for (size_t v = 0; v < shapes[i].mesh.num_vertices.size(); v++) {
|
||||
printf(" num_vertices[%ld] = %ld\n", v,
|
||||
static_cast<long>(shapes[i].mesh.num_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
|
||||
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));
|
||||
}
|
||||
|
||||
#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
|
||||
3
tests/vcbuild.bat
Normal file
3
tests/vcbuild.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
chcp 437
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64
|
||||
ninja
|
||||
@@ -111,6 +111,33 @@ typedef struct {
|
||||
std::vector<float> texcoords; // 'vt'
|
||||
} attrib_t;
|
||||
|
||||
typedef struct callback_t_ {
|
||||
void (*vertex_cb)(void *user_data, float x, float y, float z);
|
||||
void (*normal_cb)(void *user_data, float x, float y, float z);
|
||||
void (*texcoord_cb)(void *user_data, float x, float y);
|
||||
// -2147483648 will be passed for undefined index
|
||||
void (*index_cb)(void *user_data, int v_idx, int vn_idx, int vt_idx);
|
||||
// Index to material
|
||||
void (*usemtl_cb)(void *user_data, int material_idx);
|
||||
void (*mtllib_cb)(void *user_data, const material_t *materials,
|
||||
int num_materials);
|
||||
// There may be multiple group names
|
||||
void (*group_cb)(void *user_data, const char **names, int num_names);
|
||||
void (*object_cb)(void *user_data, const char *name);
|
||||
|
||||
callback_t_() :
|
||||
vertex_cb(NULL),
|
||||
normal_cb(NULL),
|
||||
texcoord_cb(NULL),
|
||||
index_cb(NULL),
|
||||
usemtl_cb(NULL),
|
||||
mtllib_cb(NULL),
|
||||
group_cb(NULL),
|
||||
object_cb(NULL) {
|
||||
}
|
||||
|
||||
} callback_t;
|
||||
|
||||
class MaterialReader {
|
||||
public:
|
||||
MaterialReader() {}
|
||||
@@ -138,7 +165,6 @@ class MaterialFileReader : public MaterialReader {
|
||||
/// Loads .obj from a file.
|
||||
/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data
|
||||
/// 'shapes' will be filled with parsed shape data
|
||||
/// The function returns error string.
|
||||
/// Returns true when loading .obj become success.
|
||||
/// Returns warning and error message into `err`
|
||||
/// 'mtl_basepath' is optional, and used for base path for .mtl file.
|
||||
@@ -149,6 +175,18 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
const char *filename, const char *mtl_basepath = NULL,
|
||||
bool triangulate = true);
|
||||
|
||||
/// Loads .obj from a file with custom user callback.
|
||||
/// .mtl is loaded as usual and parsed material_t data will be passed to
|
||||
/// `callback.mtllib_cb`.
|
||||
/// Returns true when loading .obj/.mtl become success.
|
||||
/// Returns warning and error message into `err`
|
||||
/// 'mtl_basepath' is optional, and used for base path for .mtl file.
|
||||
/// 'triangulate' is optional, and used whether triangulate polygon face in .obj
|
||||
/// or not.
|
||||
bool LoadObjWithCallback(void *user_data, const callback_t &callback,
|
||||
std::string *err, std::istream *inStream,
|
||||
MaterialReader *readMatFn);
|
||||
|
||||
/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve
|
||||
/// std::istream for materials.
|
||||
/// Returns true when loading .obj become success.
|
||||
@@ -418,7 +456,7 @@ static tag_sizes parseTagTriple(const char **token) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
// Parse triples: i, i/j/k, i//k, i/j
|
||||
// Parse triples with index offsets: 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);
|
||||
@@ -452,6 +490,39 @@ static vertex_index parseTriple(const char **token, int vsize, int vnsize,
|
||||
return vi;
|
||||
}
|
||||
|
||||
// Parse raw triples: i, i/j/k, i//k, i/j
|
||||
static vertex_index parseRawTriple(const char **token) {
|
||||
vertex_index vi(0x8000000); // -2147483648 = invalid
|
||||
|
||||
vi.v_idx = atoi((*token));
|
||||
(*token) += strcspn((*token), "/ \t\r");
|
||||
if ((*token)[0] != '/') {
|
||||
return vi;
|
||||
}
|
||||
(*token)++;
|
||||
|
||||
// i//k
|
||||
if ((*token)[0] == '/') {
|
||||
(*token)++;
|
||||
vi.vn_idx = atoi((*token));
|
||||
(*token) += strcspn((*token), "/ \t\r");
|
||||
return vi;
|
||||
}
|
||||
|
||||
// i/j/k or i/j
|
||||
vi.vt_idx = atoi((*token));
|
||||
(*token) += strcspn((*token), "/ \t\r");
|
||||
if ((*token)[0] != '/') {
|
||||
return vi;
|
||||
}
|
||||
|
||||
// i/j/k
|
||||
(*token)++; // skip '/'
|
||||
vi.vn_idx = atoi((*token));
|
||||
(*token) += strcspn((*token), "/ \t\r");
|
||||
return vi;
|
||||
}
|
||||
|
||||
static void InitMaterial(material_t *material) {
|
||||
material->name = "";
|
||||
material->ambient_texname = "";
|
||||
@@ -831,7 +902,6 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
|
||||
// material
|
||||
std::map<std::string, int> material_map;
|
||||
// std::map<vertex_index, unsigned int> vertexCache;
|
||||
int material = -1;
|
||||
|
||||
shape_t shape;
|
||||
@@ -1103,6 +1173,270 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadObjWithCallback(void *user_data, const callback_t &callback,
|
||||
std::string *err, std::istream *inStream,
|
||||
MaterialReader *readMatFn) {
|
||||
std::stringstream errss;
|
||||
|
||||
std::string name;
|
||||
|
||||
// material
|
||||
std::map<std::string, int> material_map;
|
||||
int material = -1;
|
||||
|
||||
shape_t shape;
|
||||
|
||||
int maxchars = 8192; // Alloc enough size.
|
||||
std::vector<char> buf(static_cast<size_t>(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' && IS_SPACE((token[1]))) {
|
||||
token += 2;
|
||||
float x, y, z;
|
||||
parseFloat3(&x, &y, &z, &token);
|
||||
if (callback.vertex_cb) {
|
||||
callback.vertex_cb(user_data, x, y, z);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// normal
|
||||
if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) {
|
||||
token += 3;
|
||||
float x, y, z;
|
||||
parseFloat3(&x, &y, &z, &token);
|
||||
if (callback.normal_cb) {
|
||||
callback.normal_cb(user_data, x, y, z);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// texcoord
|
||||
if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) {
|
||||
token += 3;
|
||||
float x, y;
|
||||
parseFloat2(&x, &y, &token);
|
||||
if (callback.texcoord_cb) {
|
||||
callback.texcoord_cb(user_data, x, y);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// face
|
||||
if (token[0] == 'f' && IS_SPACE((token[1]))) {
|
||||
token += 2;
|
||||
token += strspn(token, " \t");
|
||||
|
||||
while (!IS_NEW_LINE(token[0])) {
|
||||
vertex_index vi = parseRawTriple(&token);
|
||||
if (callback.index_cb) {
|
||||
callback.index_cb(user_data, vi.v_idx, vi.vn_idx, vi.vt_idx);
|
||||
}
|
||||
size_t n = strspn(token, " \t\r");
|
||||
token += n;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// use mtl
|
||||
if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) {
|
||||
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
||||
token += 7;
|
||||
#ifdef _MSC_VER
|
||||
sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf));
|
||||
#else
|
||||
sscanf(token, "%s", namebuf);
|
||||
#endif
|
||||
|
||||
int newMaterialId = -1;
|
||||
if (material_map.find(namebuf) != material_map.end()) {
|
||||
newMaterialId = material_map[namebuf];
|
||||
} else {
|
||||
// { error!! material not found }
|
||||
}
|
||||
|
||||
if (newMaterialId != material) {
|
||||
material = newMaterialId;
|
||||
}
|
||||
|
||||
if (callback.usemtl_cb) {
|
||||
callback.usemtl_cb(user_data, material);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// load mtl
|
||||
if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
|
||||
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
||||
token += 7;
|
||||
#ifdef _MSC_VER
|
||||
sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf));
|
||||
#else
|
||||
sscanf(token, "%s", namebuf);
|
||||
#endif
|
||||
|
||||
std::string err_mtl;
|
||||
std::vector<material_t> materials;
|
||||
bool ok = (*readMatFn)(namebuf, &materials, &material_map, &err_mtl);
|
||||
if (err) {
|
||||
(*err) += err_mtl;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (callback.mtllib_cb) {
|
||||
callback.mtllib_cb(user_data, &materials.at(0),
|
||||
static_cast<int>(materials.size()));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// group name
|
||||
if (token[0] == 'g' && IS_SPACE((token[1]))) {
|
||||
std::vector<std::string> names;
|
||||
names.reserve(2);
|
||||
|
||||
while (!IS_NEW_LINE(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 = "";
|
||||
}
|
||||
|
||||
if (callback.group_cb) {
|
||||
if (names.size() > 1) {
|
||||
// create const char* array.
|
||||
std::vector<const char *> tmp(names.size() - 1);
|
||||
for (size_t j = 0; j < tmp.size(); j++) {
|
||||
tmp[j] = names[j + 1].c_str();
|
||||
}
|
||||
callback.group_cb(user_data, &tmp.at(0),
|
||||
static_cast<int>(tmp.size()));
|
||||
|
||||
} else {
|
||||
callback.group_cb(user_data, NULL, 0);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// object name
|
||||
if (token[0] == 'o' && IS_SPACE((token[1]))) {
|
||||
// @todo { multiple object name? }
|
||||
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
||||
token += 2;
|
||||
#ifdef _MSC_VER
|
||||
sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf));
|
||||
#else
|
||||
sscanf(token, "%s", namebuf);
|
||||
#endif
|
||||
name = std::string(namebuf);
|
||||
|
||||
if (callback.object_cb) {
|
||||
callback.object_cb(user_data, name.c_str());
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 0 // @todo
|
||||
if (token[0] == 't' && IS_SPACE(token[1])) {
|
||||
tag_t tag;
|
||||
|
||||
char namebuf[4096];
|
||||
token += 2;
|
||||
#ifdef _MSC_VER
|
||||
sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf));
|
||||
#else
|
||||
sscanf(token, "%s", namebuf);
|
||||
#endif
|
||||
tag.name = std::string(namebuf);
|
||||
|
||||
token += tag.name.size() + 1;
|
||||
|
||||
tag_sizes ts = parseTagTriple(&token);
|
||||
|
||||
tag.intValues.resize(static_cast<size_t>(ts.num_ints));
|
||||
|
||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
|
||||
tag.intValues[i] = atoi(token);
|
||||
token += strcspn(token, "/ \t\r") + 1;
|
||||
}
|
||||
|
||||
tag.floatValues.resize(static_cast<size_t>(ts.num_floats));
|
||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_floats); ++i) {
|
||||
tag.floatValues[i] = parseFloat(&token);
|
||||
token += strcspn(token, "/ \t\r") + 1;
|
||||
}
|
||||
|
||||
tag.stringValues.resize(static_cast<size_t>(ts.num_strings));
|
||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
|
||||
char stringValueBuffer[4096];
|
||||
|
||||
#ifdef _MSC_VER
|
||||
sscanf_s(token, "%s", stringValueBuffer,
|
||||
(unsigned)_countof(stringValueBuffer));
|
||||
#else
|
||||
sscanf(token, "%s", stringValueBuffer);
|
||||
#endif
|
||||
tag.stringValues[i] = stringValueBuffer;
|
||||
token += tag.stringValues[i].size() + 1;
|
||||
}
|
||||
|
||||
tags.push_back(tag);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Ignore unknown command.
|
||||
}
|
||||
|
||||
if (err) {
|
||||
(*err) += errss.str();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace tinyobj
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user