Build Assimp from source

This commit is contained in:
Dane Johnson
2021-03-15 13:46:19 -05:00
parent b7a83a2876
commit a41fcbe7f4
2126 changed files with 1385127 additions and 40 deletions

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>assimp-regression</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?>
<pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 3.0</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
</pydev_project>

View File

@@ -0,0 +1,95 @@
Asset Importer Lib Regression Test Suite
========================================
1) How does it work?
---------------------------------------------------------------------------------
run.py checks all model in the <root>/test/models* folders and compares the result
against a regression database provided with assimp (db.zip). A few failures
are totally fine (see sections 7+). You need to worry if a huge
majority of all files in a particular format (or post-processing configuration)
fails as this might be a sign of a recent regression in assimp's codebase or
gross incompatibility with your system or compiler.
2) What do I need?
---------------------------------------------------------------------------------
- You need Python installed (2.7+, 3.x). On Windows, run the scripts using "py".
- You need to build the assimp command line tool (ASSIMP_BUILD_ASSIMP_TOOLS
CMake build flag). Both run.py and gen_db.py take the full path to the binary
as first command line parameter.
3) How to add more test files?
---------------------------------------------------------------------------------
Use the following procedure:
- Verify the correctness of your assimp build - run the regression suite.
DO NOT continue if more tests fail than usual.
- Add your additional test files to <root>/test/models/<fileformat>, where
<fileformat> is the file type (typically the file extension).
- If you test file does not meet the BSD license requirements, add it to
<root>/test/models-nonbsd/<fileformat> so people know to be careful with it.
- Rebuild the regression database:
"gen_db.py <binary> -ixyz" where .xyz is the file extension of the new file.
- Run the regression suite again. There should be no new failures and the new
file should not be among the failures.
- Include the db.zip file with your Pull Request. Travis CI enforces a passing
regression suite (with offenders whitelisted as a last resort).
4) I made a change/fix/patch to a loader, how to update the database?
---------------------------------------------------------------------------------
- Rebuild the regression database using "gen_db.py <binary> -ixyz"
where .xyz is the file extension for which the loader was patched.
- Run the regression suite again. There should be no new failures and the new
file should not be among the failures.
- Include the db.zip file with your Pull Request. Travis CI enforces a passing
regression suite (with offenders whitelisted as a last resort).
5) How to add my whole model repository to the database?
---------------------------------------------------------------------------------
Edit the reg_settings.py file and add the path to your repository to
<<model_directories>>. Then, rebuild the database.
6) So what is actually tested?
---------------------------------------------------------------------------------
The regression database includes mini dumps of the aiScene data structure, i.e.
the scene hierarchy plus the sizes of all data arrays MUST match. Floating-point
data buffers, such as vertex positions are handled less strictly: min, max and
average values are stored with low precision. This takes hardware- or
compiler-specific differences in floating-point computations into account.
Generally, almost all significant regressions will be detected while the
number of false positives is relatively low.
7) The test suite fails, what do do?
---------------------------------------------------------------------------------
Get back to <root>/test/results and look at regression_suite_failures.txt.
It contains a list of all files which failed the test. Failing dumps are copied to
<root>/test/results/tmp. Both an EXPECTED and an ACTUAL file is produced per test.
The output of "assimp cmpdump" is written to regressions_suite_output.txt. Grep
for the file name in question and locate the log for the failed comparison. It
contains a full trace of which scene elements have been compared before, which
makes it reasonably easy to locate the offending field.
8) fp:fast vs fp:precise fails the test suite (same for gcc equivalents)
---------------------------------------------------------------------------------
As mentioned above, floating-point inaccuracies between differently optimized
builds are not considered regressions and all float comparisons done by the test
suite involve an epsilon to accommodate. However compiler settings that allow
compilers to perform non-IEEE754 compliant optimizations can cause arbitrary
failures in the test suite. Even if the compiler is configured to be IEE754
comformant, there is lots of code in assimp that leaves the compiler a choice
and different compilers make different choices (for example the precision of
float intermediaries is implementation-specified).

View File

@@ -0,0 +1,293 @@
#!/usr/bin/env python3
# -*- Coding: UTF-8 -*-
# ---------------------------------------------------------------------------
# Open Asset Import Library (ASSIMP)
# ---------------------------------------------------------------------------
#
# Copyright (c) 2006-2016, ASSIMP Development Team
#
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the following
# conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# * Neither the name of the ASSIMP team, nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior
# written permission of the ASSIMP Development Team.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ---------------------------------------------------------------------------
from tkinter import *
import sys
import os
import platform
import run
import subprocess
import result_checker as rc
INFO = 0
WARN = 1
ERROR = 2
# -------------------------------------------------------------------------------
def log( sev, msg ):
"""
This function is used to log info, warnings and errors.
"""
logEntry = ""
if sev == 0:
logEntry = logEntry + "[INFO]: "
elif sev == 1:
logEntry = logEntry + "[WARN]: "
elif sev == 2:
logEntry = logEntry + "[ERR] : "
logEntry = logEntry + str( msg )
print( logEntry )
# -------------------------------------------------------------------------------
class BaseDialog( Toplevel ):
"""
Helper base class for dialogs used in the UI.
"""
def __init__(self, parent, title = None, buttons=""):
"""
Constructor
"""
Toplevel.__init__( self, parent )
self.transient(parent)
if title:
self.title(title)
self.parent = parent
self.result = None
body = Frame(self)
self.initial_focus = self.body(body)
body.pack(padx=5, pady=5)
self.buttonbox(buttons)
self.grab_set()
if not self.initial_focus:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
self.geometry("+%d+%d" % (parent.winfo_rootx() + 50,
parent.winfo_rooty() + 50))
self.initial_focus.focus_set()
self.wait_window(self)
def body(self, master):
# create dialog body. return widget that should have
# initial focus. this method should be overridden
pass
def buttonbox(self, buttons):
# add standard button box. override if you don't want the
# standard buttons
box = Frame(self)
w = Button(box, text="OK", width=40, command=self.ok, default=ACTIVE)
w.pack(side=LEFT, padx=5, pady=5)
self.bind("<Return>", self.ok)
box.pack()
def ok(self, event=None):
if not self.validate():
self.initial_focus.focus_set() # put focus back
return
self.withdraw()
self.update_idletasks()
self.apply()
self.cancel()
def cancel(self, event=None):
# put focus back to the parent window
self.parent.focus_set()
self.destroy()
def validate(self):
return 1 # override
def apply(self):
pass # override
# -------------------------------------------------------------------------------
class VersionDialog( BaseDialog ):
"""
This class is used to create the info dialog.
"""
def body(self, master):
# info will be read from assimp command line tool
version = "Asset importer lib version unknown"
exe = run.getEnvVar( "assimp_path" )
if len( exe ) != 0:
command = [exe, "version" ]
log( INFO, "command = " + str(command))
stdout = subprocess.check_output(command)
for line in stdout.splitlines():
pos = str(line).find( "Version" )
if -1 != pos:
version = line
Label(master, text=version).pack()
def apply(self):
pass
# -------------------------------------------------------------------------------
class SetupDialog( BaseDialog ):
"""
This class is used to create the setup dialog.
"""
def body(self, master):
Label(master, justify=LEFT, text="Assimp: " ).grid(row=0, column=0)
Label(master, justify=LEFT, text=run.getEnvVar("assimp_path")).grid(row=0, column=1)
Label(master, text="New executable:").grid(row=1)
self.e1 = Entry(master)
self.e1.grid(row=1, column=1)
return self.e1 # initial focus
def apply(self):
exe = str( self.e1.get() )
if len( exe ) == 0:
return 0
if os.path.isfile( exe ):
log( INFO, "Set executable at " + exe)
self.assimp_bin_path = exe
run.setEnvVar("assimp_path", self.assimp_bin_path)
else:
log( ERROR, "Executable not found at "+exe )
return 0
# -------------------------------------------------------------------------------
class RegDialog( object ):
"""
This class is used to create a simplified user interface for running the regression test suite.
"""
def __init__(self, bin_path ):
"""
Constructs the dialog, you can define which executable shal be used.
@param bin_path [in] Path to assimp binary.
"""
run.setEnvVar( "assimp_path", bin_path )
self.b_run_ = None
self.b_update_ = None
self.b_res_checker_ = None
self.b_quit_ = None
if platform.system() == "Windows":
self.editor = "notepad"
elif platform.system() == "Linux":
self.editor = "vim"
self.root = None
self.width=40
def run_reg(self):
log(INFO, "Starting regression test suite.")
run.run_test()
rc.run()
self.b_update_.config( state=ACTIVE )
return 0
def reg_update(self):
assimp_exe = run.getEnvVar( "assimp_path" )
if len( assimp_exe ) == 0:
return 1
exe = "python"
command = [ exe, "gen_db.py", assimp_exe ]
log(INFO, "command = " + str(command))
stdout = subprocess.call(command)
log(INFO, stdout)
return 0
def shop_diff( self ):
log(WARN, "ToDo!")
return 0
def open_log(self):
command = [ self.editor, "../results/run_regression_suite_output.txt", ]
log(INFO, "command = " + str( command ) )
r = subprocess.call(command)
return 0
def show_version( self ):
d = VersionDialog( self.root )
return 0
def setup(self):
d = SetupDialog( self.root )
return 0
def quit(self):
log( INFO, "quit" )
sys.exit( 0 )
def initUi(self):
# create the frame with buttons
self.root = Tk()
self.root.title( "Assimp-Regression UI")
self.b_run_ = Button( self.root, text="Run regression ", command=self.run_reg, width = self.width )
self.b_update_ = Button( self.root, text="Update database", command=self.reg_update, width = self.width )
self.b_show_diff_ = Button( self.root, text="Show diff", command=self.shop_diff, width = self.width )
self.b_log_ = Button( self.root, text="Open log", command=self.open_log, width = self.width )
self.b_setup_ = Button( self.root, text="Setup", command=self.setup, width = self.width )
self.b_version_ = Button( self.root, text="Show version", command=self.show_version, width = self.width )
self.b_quit_ = Button( self.root, text="Quit", command=self.quit, width = self.width )
# define the used grid
self.b_run_.grid( row=0, column=0, sticky=W+E )
self.b_update_.grid( row=1, column=0, sticky=W+E )
self.b_show_diff_.grid( row=2, column=0, sticky=W+E )
self.b_log_.grid( row=3, column=0, sticky=W+E )
self.b_setup_.grid( row=4, column=0, sticky=W+E )
self.b_version_.grid( row=5, column=0, sticky=W+E )
self.b_quit_.grid( row=6, column=0, sticky=W+E )
#self.b_update_.config( state=DISABLED )
self.b_show_diff_.config( state=DISABLED )
# run mainloop
self.root.mainloop()
# -------------------------------------------------------------------------------
def getDefaultExecutable():
assimp_bin_path = ""
if platform.system() == "Windows":
assimp_bin_path = '..\\..\\bin\\debug\\assimpd.exe'
elif platform.system() == "Linux":
assimp_bin_path = '../../bin/assimp'
return assimp_bin_path
# -------------------------------------------------------------------------------
if __name__ == "__main__":
if len(sys.argv) > 1:
assimp_bin_path = sys.argv[1]
else:
assimp_bin_path = getDefaultExecutable()
log( INFO, 'Using assimp binary: ' + assimp_bin_path )
dlg = RegDialog(assimp_bin_path)
dlg.initUi()
# vim: ai ts=4 sts=4 et sw=4

View File

@@ -0,0 +1,225 @@
#!/usr/bin/env python3
# -*- Coding: UTF-8 -*-
# ---------------------------------------------------------------------------
# Open Asset Import Library (ASSIMP)
# ---------------------------------------------------------------------------
#
# Copyright (c) 2006-2010, ASSIMP Development Team
#
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the following
# conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# * Neither the name of the ASSIMP team, nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior
# written permission of the ASSIMP Development Team.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ---------------------------------------------------------------------------
"""
Generate the regression database db.zip from the files in the <root>/test/models
directory. Older databases are overwritten with no prompt but can be restored
using Git as needed.
Use --help for usage.
On Windows, use ``py run.py <arguments>`` to make sure command line parameters
are forwarded to the script.
"""
import sys
import os
import subprocess
import zipfile
import settings
import utils
usage = """gen_db [assimp_binary] [-i=...] [-e=...] [-p] [-n]
The assimp_cmd (or assimp) binary to use is specified by the first
command line argument and defaults to ``assimp``.
To build, set ``ASSIMP_BUILD_ASSIMP_TOOLS=ON`` in CMake. If generating
configs for an IDE, make sure to build the assimp_cmd project.
-i,--include: List of file extensions to update dumps for. If omitted,
all file extensions are updated except those in `exclude`.
Example: -ixyz,abc
-i.xyz,.abc
--include=xyz,abc
-e,--exclude: Merged with settings.exclude_extensions to produce a
list of all file extensions to ignore. If dumps exist,
they are not altered. If not, theu are not created.
-p,--preview: Preview list of file extensions touched by the update.
Dont' change anything.
-n,--nozip: Don't pack to ZIP archive. Keep all dumps in individual files.
"""
# -------------------------------------------------------------------------------
def process_dir(d, outfile, file_filter):
""" Generate small dump records for all files in 'd' """
print("Processing directory " + d)
num = 0
for f in os.listdir(d):
fullp = os.path.join(d, f)
if os.path.isdir(fullp) and not f == ".svn":
num += process_dir(fullp, outfile, file_filter)
continue
if file_filter(f):
for pp in settings.pp_configs_to_test:
num += 1
print("DUMP " + fullp + "\n post-processing: " + pp)
outf = os.path.join(os.getcwd(), settings.database_name,
utils.hashing(fullp, pp))
cmd = [ assimp_bin_path, "dump", fullp, outf, "-b", "-s", "-l" ] + pp.split()
outfile.write("assimp dump "+"-"*80+"\n")
outfile.flush()
if subprocess.call(cmd, stdout=outfile, stderr=outfile, shell=False):
print("Failure processing " + fullp)
# spit out an empty file to indicate that this failure is expected
with open(outf,'wb') as f:
pass
return num
# -------------------------------------------------------------------------------
def make_zip():
"""Zip the contents of ./<settings.database_name>
to <settings.database_name>.zip using DEFLATE
compression to minimize the file size. """
num = 0
zipout = zipfile.ZipFile(settings.database_name + ".zip", "w", zipfile.ZIP_DEFLATED)
for f in os.listdir(settings.database_name):
p = os.path.join(settings.database_name, f)
zipout.write(p, f)
if settings.remove_old:
os.remove(p)
num += 1
if settings.remove_old:
os.rmdir(settings.database_name)
bad = zipout.testzip()
assert bad is None
print("="*60)
print("Database contains {0} entries".format(num))
# -------------------------------------------------------------------------------
def extract_zip():
"""Unzip <settings.database_name>.zip to
./<settings.database_name>"""
try:
zipout = zipfile.ZipFile(settings.database_name + ".zip", "r", 0)
zipout.extractall(path=settings.database_name)
except (RuntimeError,IOError) as r:
print(r)
print("failed to extract previous ZIP contents. "\
"DB is generated from scratch.")
# -------------------------------------------------------------------------------
def gen_db(ext_list,outfile):
"""Generate the crash dump database in
./<settings.database_name>"""
try:
os.mkdir(settings.database_name)
except OSError:
pass
num = 0
for tp in settings.model_directories:
num += process_dir(tp, outfile,
lambda x: os.path.splitext(x)[1].lower() in ext_list and not x in settings.files_to_ignore)
print("="*60)
print("Updated {0} entries".format(num))
# -------------------------------------------------------------------------------
if __name__ == "__main__":
def clean(f):
f = f.strip("* \'")
return "."+f if f[:1] != '.' else f
if len(sys.argv) <= 1 or sys.argv[1] == "--help" or sys.argv[1] == "-h":
print(usage)
sys.exit(0)
assimp_bin_path = sys.argv[1]
ext_list, preview, nozip = None, False, False
for m in sys.argv[2:]:
if m[:10]=="--exclude=":
settings.exclude_extensions += map(clean, m[10:].split(","))
elif m[:2]=="-e":
settings.exclude_extensions += map(clean, m[2:].split(","))
elif m[:10]=="--include=":
ext_list = m[10:].split(",")
elif m[:2]=="-i":
ext_list = m[2:].split(",")
elif m=="-p" or m == "--preview":
preview = True
elif m=="-n" or m == "--nozip":
nozip = True
else:
print("Unrecognized parameter: " + m)
sys.exit(-1)
outfile = open(os.path.join("..", "results", "gen_regression_db_output.txt"), "w")
if ext_list is None:
(ext_list, err) = subprocess.Popen([assimp_bin_path, "listext"],
stdout=subprocess.PIPE).communicate()
ext_list = str(ext_list.strip()).lower().split(";")
# todo: Fix for multi dot extensions like .skeleton.xml
ext_list = list(filter(lambda f: not f in settings.exclude_extensions,
map(clean, ext_list)))
print('File extensions processed: ' + ', '.join(ext_list))
if preview:
sys.exit(1)
extract_zip()
gen_db(ext_list,outfile)
make_zip()
print("="*60)
input("Press any key to continue")
sys.exit(0)
# vim: ai ts=4 sts=4 et sw=4

View File

@@ -0,0 +1,113 @@
#!/usr/bin/env python3
# -*- Coding: UTF-8 -*-
# ---------------------------------------------------------------------------
# Open Asset Import Library (ASSIMP)
# ---------------------------------------------------------------------------
#
# Copyright (c) 2006-2016, ASSIMP Development Team
#
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the following
# conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# * Neither the name of the ASSIMP team, nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior
# written permission of the ASSIMP Development Team.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ---------------------------------------------------------------------------
"""
This script runs as part of the Travis CI build on Github and controls
whether a patch passes the regression test suite.
Given the failures encountered by the regression suite runner (run.py) in
../results/whitelist.csv
and the current whitelist of failures considered acceptable in
./run_regression_suite_failures_whitelisted.csv
determine PASSED or FAILED.
"""
import sys
import os
RESULTS_FILE = os.path.join('..', 'results', 'run_regression_suite_failures.csv')
WHITELIST_FILE = os.path.join('whitelist.csv')
BANNER = """
*****************************************************************
Regression suite result checker
(test/regression/result_checker.py)
*****************************************************************
"""
def passed(message):
print('\n\n**PASSED: {0}.\n'.format(message))
return 0
def failed(message):
print('\n\n**FAILED: {0}. \nFor more information see test/regression/README.\n'
.format(message))
return -1
def read_results_csv(filename):
parse = lambda line: map(str.strip, line.split(';')[:2])
try:
with open(filename, 'rt') as results:
return dict(parse(line) for line in results.readlines()[1:])
except IOError:
print('Failed to read {0}.'.format(filename))
return None
def run():
print(BANNER)
print('Reading input files.')
result_dict = read_results_csv(RESULTS_FILE)
whitelist_dict = read_results_csv(WHITELIST_FILE)
if result_dict is None or whitelist_dict is None:
return failed('Could not locate input files')
if not result_dict:
return passed('No failures encountered')
print('Failures:\n' + '\n'.join(sorted(result_dict.keys())))
print('Whitelisted:\n' + '\n'.join(sorted(whitelist_dict.keys())))
non_whitelisted_failures = set(result_dict.keys()) - set(whitelist_dict.keys())
print('Failures not whitelisted:\n' + '\n'.join(sorted(non_whitelisted_failures)))
if not non_whitelisted_failures:
return passed('All failures are whitelisted and considered acceptable \n' +
'due to implementation differences, library shortcomings and bugs \n' +
'that have not been fixed for a long time')
return failed('Encountered new regression failures that are not whitelisted. \n' +
'Please carefully review the changes you made and use the gen_db.py script\n' +
'to update the regression database for the affected files')
if __name__ == "__main__":
sys.exit(run())
# vim: ai ts=4 sts=4 et sw=4

320
thirdparty/assimp/test/regression/run.py vendored Executable file
View File

@@ -0,0 +1,320 @@
#!/usr/bin/env python3
# -*- Coding: UTF-8 -*-
# ---------------------------------------------------------------------------
# Open Asset Import Library (ASSIMP)
# ---------------------------------------------------------------------------
#
# Copyright (c) 2006-2010, ASSIMP Development Team
#
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the following
# conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# * Neither the name of the ASSIMP team, nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior
# written permission of the ASSIMP Development Team.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ---------------------------------------------------------------------------
"""
Run the regression test suite using settings from settings.py.
The assimp_cmd (or assimp) binary to use is specified by the first
command line argument and defaults to ``assimp``.
To build, set ``ASSIMP_BUILD_ASSIMP_TOOLS=ON`` in CMake. If generating
configs for an IDE, make sure to build the assimp_cmd project.
On Windows, use ``py run.py <path to assimp>`` to make sure the command
line parameter is forwarded to the script.
"""
import sys
import os
import subprocess
import zipfile
import collections
import multiprocessing
import settings
import utils
# -------------------------------------------------------------------------------
EXPECTED_FAILURE_NOT_MET, DATABASE_LENGTH_MISMATCH, \
DATABASE_VALUE_MISMATCH, IMPORT_FAILURE, \
FILE_NOT_READABLE, COMPARE_SUCCESS, EXPECTED_FAILURE = range(7)
messages = collections.defaultdict(lambda: "<unknown", {
EXPECTED_FAILURE_NOT_MET:
"""Unexpected success during import\n\
\tReturn code was 0""",
DATABASE_LENGTH_MISMATCH:
"""Database mismatch: lengths don't match\n\
\tExpected: {0} Actual: {1}""",
DATABASE_VALUE_MISMATCH:
"""Database mismatch: """,
IMPORT_FAILURE:
"""Unexpected failure during import\n\
\tReturn code was {0}""",
FILE_NOT_READABLE:
"""Unexpected failure reading file""",
COMPARE_SUCCESS:
"""Results match archived reference dump in database\n\
\tNumber of bytes compared: {0}""",
EXPECTED_FAILURE:
"""Expected failure was met.""",
})
outfilename_output = "run_regression_suite_output.txt"
outfilename_failur = "run_regression_suite_failures.csv"
Environment = {}
# -------------------------------------------------------------------------------
class results:
""" Handle formatting of results"""
def __init__(self, zipin):
"""Init, given a ZIPed database """
self.failures = []
self.success = []
self.zipin = zipin
def fail(self, failfile, filename_expect, pp, msg, *args):
"""
Report failure of a sub-test
File f failed a test for pp config pp, failure notice is msg,
*args is format()ting args for msg
"""
print("[FAILURE] " + messages[msg].format(*args))
self.failures.append((failfile, filename_expect, pp))
def ok(self, f, pp, msg, *args):
"""
Report success of a sub-test
File f passed the test, msg is a happy success note,
*args is format()ing args for msg.
"""
print("[SUCCESS] " + messages[msg].format(*args))
self.success.append(f)
def report_results(self):
"""Write results to ../results/run_regression_suite_failures.txt"""
count_success = len(self.success)
count_fail = len(self.failures)
percent_good = float(count_success) / (count_success + count_fail)
print("\n" + ('='*60) + "\n" + "SUCCESS: {0}\nFAILURE: {1}\nPercentage good: {2}".format(
count_success, count_fail, percent_good) +
"\n" + ('='*60) + "\n")
with open(os.path.join('..', 'results',outfilename_failur), "wt") as f:
f.write("ORIGINAL FILE;EXPECTED DUMP\n")
f.writelines(map(
lambda x: x[0] + ' ' + x[2] + ";" + x[1] + "\n", self.failures))
if self.failures:
print("\nSee " + settings.results + "\\" + outfilename_failur
+ " for more details\n\n")
def hasFailures( self ):
""" Return True, if any failures there. """
return 0 != len( self.failures )
# -------------------------------------------------------------------------------
def setEnvVar( var, value ):
print ( "set var " + var +" to" + value)
Environment[ var ] = value
# -------------------------------------------------------------------------------
def getEnvVar( var ):
if var in Environment:
return Environment[ var ]
else:
print ( "Error: cannot find " + var )
return ""
# -------------------------------------------------------------------------------
def prepare_output_dir(fullpath, myhash, app):
outfile = os.path.join(settings.results, "tmp", os.path.split(fullpath)[1] + "_" + myhash)
try:
os.mkdir(outfile)
except OSError:
pass
outfile = os.path.join(outfile, app)
return outfile
# -------------------------------------------------------------------------------
def process_dir(d, outfile_results, zipin, result ):
shellparams = {'stdout':outfile_results, 'stderr':outfile_results, 'shell':False}
print("Processing directory " + d)
all = ""
for f in sorted(os.listdir(d)):
fullpath = os.path.join(d, f)
if os.path.isdir(fullpath) and not f[:1] == '.':
process_dir(fullpath, outfile_results, zipin, result)
continue
if f in settings.files_to_ignore or os.path.splitext(f)[1] in settings.exclude_extensions:
print("Ignoring " + f)
return
for pppreset in settings.pp_configs_to_test:
filehash = utils.hashing(fullpath, pppreset)
failure = False
try:
input_expected = zipin.open(filehash, "r").read()
# empty dump files indicate 'expected import failure'
if not len(input_expected):
failure = True
except KeyError:
# TODO(acgessler): Keep track of this and report as error in the end.
print("Didn't find "+fullpath+" (Hash is "+filehash+") in database. Outdated "+\
"regression database? Use gen_db.zip to re-generate.")
continue
print("-"*60 + "\n " + os.path.realpath(fullpath) + " pp: " + pppreset)
outfile_actual = prepare_output_dir(fullpath, filehash, "ACTUAL")
outfile_expect = prepare_output_dir(fullpath, filehash, "EXPECT")
outfile_results.write("assimp dump "+"-"*80+"\n")
outfile_results.flush()
assimp_bin_path = getEnvVar("assimp_path")
command = [assimp_bin_path,
"dump",
fullpath, outfile_actual, "-b", "-s", "-l" ] +\
pppreset.split()
print( "command = " + str( command ) )
r = subprocess.call(command, **shellparams)
outfile_results.flush()
if r and not failure:
result.fail(fullpath, outfile_expect, pppreset, IMPORT_FAILURE, r)
outfile_results.write("Failed to import\n")
continue
elif failure and not r:
result.fail(fullpath, outfile_expect, pppreset, EXPECTED_FAILURE_NOT_MET)
outfile_results.write("Expected import to fail\n")
continue
elif failure and r:
result.ok(fullpath, pppreset, EXPECTED_FAILURE)
outfile_results.write("Failed as expected, skipping.\n")
continue
with open(outfile_expect, "wb") as s:
s.write(input_expected)
try:
with open(outfile_actual, "rb") as s:
input_actual = s.read()
except IOError:
continue
outfile_results.write("Expected data length: {0}\n".format(len(input_expected)))
outfile_results.write("Actual data length: {0}\n".format(len(input_actual)))
failed = False
if len(input_expected) != len(input_actual):
result.fail(fullpath, outfile_expect, pppreset, DATABASE_LENGTH_MISMATCH,
len(input_expected), len(input_actual))
# Still compare the dumps to see what the difference is
failed = True
outfile_results.write("assimp cmpdump "+"-"*80+"\n")
outfile_results.flush()
command = [ assimp_bin_path, 'cmpdump', outfile_actual, outfile_expect ]
if subprocess.call(command, **shellparams) != 0:
if not failed:
result.fail(fullpath, outfile_expect, pppreset, DATABASE_VALUE_MISMATCH)
continue
result.ok(fullpath, pppreset, COMPARE_SUCCESS, len(input_expected))
# -------------------------------------------------------------------------------
def del_folder_with_contents(folder):
for root, dirs, files in os.walk(folder, topdown=False):
for name in files:
os.remove(os.path.join(root, name))
for name in dirs:
os.rmdir(os.path.join(root, name))
# -------------------------------------------------------------------------------
def run_test():
tmp_target_path = os.path.join(settings.results, "tmp")
try:
print( "try to make " + tmp_target_path )
os.mkdir(tmp_target_path)
except OSError as oerr:
# clear contents if tmp folder exists already
del_folder_with_contents(tmp_target_path)
try:
zipin = zipfile.ZipFile(settings.database_name + ".zip",
"r", zipfile.ZIP_STORED)
except IOError:
print("Regression database ", settings.database_name,
".zip was not found")
return
res = results(zipin)
with open(os.path.join(settings.results, outfilename_output), "wt") as outfile:
for tp in settings.model_directories:
process_dir(tp, outfile, zipin, res)
res.report_results()
if res.hasFailures():
return 1
return 0
# -------------------------------------------------------------------------------
if __name__ == "__main__":
if len(sys.argv) > 1:
assimp_bin_path = sys.argv[1]
else:
assimp_bin_path = 'assimp'
setEnvVar("assimp_path", assimp_bin_path)
print('Using assimp binary: ' + assimp_bin_path)
sys.exit( run_test() )
# vim: ai ts=4 sts=4 et sw=4

View File

@@ -0,0 +1,134 @@
#!/usr/bin/env python3
# -*- Coding: UTF-8 -*-
# ---------------------------------------------------------------------------
# Open Asset Import Library (ASSIMP)
# ---------------------------------------------------------------------------
#
# Copyright (c) 2006-2010, ASSIMP Development Team
#
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the following
# conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# * Neither the name of the ASSIMP team, nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior
# written permission of the ASSIMP Development Team.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ---------------------------------------------------------------------------
"""Shared settings for the regression suite (bold builder and
test scripts rely on this)
"""
import os
# -------------------------------------------------------------------------------
# Files to ignore (with reason)
#
# pond.0.ply - loads with 40k identical triangles, causing postprocessing
# to have quadratic runtime.
# -------------------------------------------------------------------------------
files_to_ignore = ["pond.0.ply"]
# -------------------------------------------------------------------------------
# List of file extensions to be excluded from the regression suite
# File extensions are case insensitive
# -------------------------------------------------------------------------------
exclude_extensions = [
".assbin", ".assxml", ".txt", ".md",
".jpeg", ".jpg", ".png", ".gif", ".tga", ".bmp",
".skeleton", ".skeleton.xml", ".license", ".mtl", ".material", ".pk3"
]
# -------------------------------------------------------------------------------
# Post processing configurations to be included in the test. The
# strings are parameters for assimp_cmd, see assimp_cmd's doxydoc
# for more details.
# The defaults are (validate-data-structure is always enabled, for
# self-explanatory reasons :-):
#
# '-cfull' :apply all post processing except 'og' and 'ptv' (optimize-scenegraph)
# '-og -om' :run optimize-scenegraph in combination with optimize-meshes.
# '-vds -jiv' :join-identical-vertices alone. This is a hotspot where
# floating-point inaccuracies can cause severe damage.
# '-ptv': transform all meshes to world-space
# As you can see, not all possible combinations of pp steps are covered -
# but at least each step is executed at least once on each model.
# -------------------------------------------------------------------------------
pp_configs_to_test = [
"-cfull",
"-og -om -vds",
"-vds -jiv",
"-ptv -gsn -cts -db",
# this is especially important: if no failures are present with this
# preset, the regression is most likely caused by the post
# processing pipeline.
""
]
# -------------------------------------------------------------------------------
# Name of the regression database file to be used
# gen_db.py writes to this directory, run.py checks against this directory.
# If a zip file with the same name exists, its contents are favoured to a
# normal directory, so in order to test against unzipped files the ZIP needs
# to be deleted.
# -------------------------------------------------------------------------------
database_name = "db"
# -------------------------------------------------------------------------------
# List of directories to be processed. Paths are processed recursively.
# -------------------------------------------------------------------------------
model_directories = [
os.path.join("..","models"),
os.path.join("..","models-nonbsd")
]
# -------------------------------------------------------------------------------
# Remove the original database files after the ZIP has been built?
# -------------------------------------------------------------------------------
remove_old = True
# -------------------------------------------------------------------------------
# Bytes to skip at the beginning of a dump. This skips the file header, which
# is currently the same 500 bytes header for both assbin, assxml and minidumps.
# -------------------------------------------------------------------------------
dump_header_skip = 500
# -------------------------------------------------------------------------------
# Directory to write all results and logs to. The dumps pertaining to failed
# tests are written to a subfolder of this directory ('tmp').
# -------------------------------------------------------------------------------
results = os.path.join("..","results")
# Create results directory if it does not exist
if not os.path.exists(results):
os.makedirs(results)
# vim: ai ts=4 sts=4 et sw=4

View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python3
# -*- Coding: UTF-8 -*-
# ---------------------------------------------------------------------------
# Open Asset Import Library (ASSIMP)
# ---------------------------------------------------------------------------
#
# Copyright (c) 2006-2010, ASSIMP Development Team
#
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the following
# conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# * Neither the name of the ASSIMP team, nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior
# written permission of the ASSIMP Development Team.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ---------------------------------------------------------------------------
"""Shared stuff for the gen_db and run scripts"""
# -------------------------------------------------------------------------------
def hashing(file,pp):
""" Map an input file and a postprocessing config to an unique hash.
The hash is used to store the item in the database. It
needs to be persistent across different python implementations
and platforms, so we implement the hashing manually.
"""
file = file.lower()
file = file.replace('\\','/')+":"+pp
# SDBM hash
res = 0
for t in file:
res = (ord(t) + (res<<6) + (res<<16) - res) % 2**32
return '{:x}'.format(res)
# vim: ai ts=4 sts=4 et sw=4

View File

@@ -0,0 +1,32 @@
ORIGINAL FILE;EXPECTED DUMP
../models/AC/SphereWithLightUvScaling4X.ac -cfull;../results/tmp/SphereWithLightUvScaling4X.ac_30edbbcd/EXPECT
../models/AC/SphereWithLightUvScaling4X.ac -vds -jiv;../results/tmp/SphereWithLightUvScaling4X.ac_a627320a/EXPECT
../models/AC/sample_subdiv.ac -cfull;../results/tmp/sample_subdiv.ac_669c529e/EXPECT
../models/AC/sample_subdiv.ac -vds -jiv;../results/tmp/sample_subdiv.ac_d5987f9/EXPECT
../models/BLEND/CubeHierarchy_248.blend -cfull;../results/tmp/CubeHierarchy_248.blend_4e04cc99/EXPECT
../models/BLEND/CubeHierarchy_248.blend -og -om -vds;../results/tmp/CubeHierarchy_248.blend_5e78ea9c/EXPECT
../models/BLEND/CubeHierarchy_248.blend -vds -jiv;../results/tmp/CubeHierarchy_248.blend_8aca7a3e/EXPECT
../models/BLEND/CubeHierarchy_248.blend -ptv -gsn -cts -db;../results/tmp/CubeHierarchy_248.blend_1f2b8aa4/EXPECT
../models/BLEND/CubeHierarchy_248.blend ;../results/tmp/CubeHierarchy_248.blend_b827f814/EXPECT
../models/BLEND/SuzanneSubdiv_252.blend -cfull;../results/tmp/SuzanneSubdiv_252.blend_4a8dd3d3/EXPECT
../models/BLEND/SuzanneSubdiv_252.blend -vds -jiv;../results/tmp/SuzanneSubdiv_252.blend_7f41fe84/EXPECT
../models/STL/Spider_ascii.stl -cfull;../results/tmp/Spider_ascii.stl_8047fd91/EXPECT
../models/STL/Spider_ascii.stl -vds -jiv;../results/tmp/Spider_ascii.stl_d4858346/EXPECT
../models/STL/Spider_binary.stl -cfull;../results/tmp/Spider_binary.stl_dd4fe21/EXPECT
../models/STL/Spider_binary.stl -vds -jiv;../results/tmp/Spider_binary.stl_2c8deeb6/EXPECT
../models-nonbsd/BLEND/Bob.blend -cfull;../results/tmp/Bob.blend_7f8349ba/EXPECT
../models-nonbsd/BLEND/Bob.blend -og -om -vds;../results/tmp/Bob.blend_4f4a63d/EXPECT
../models-nonbsd/BLEND/Bob.blend -vds -jiv;../results/tmp/Bob.blend_ab1aa5dd/EXPECT
../models-nonbsd/BLEND/Bob.blend -ptv -gsn -cts -db;../results/tmp/Bob.blend_6a5ec4c5/EXPECT
../models-nonbsd/BLEND/Bob.blend ;../results/tmp/Bob.blend_2fc376b5/EXPECT
../models-nonbsd/BLEND/fleurOptonl.blend -cfull;../results/tmp/fleurOptonl.blend_6e87e039/EXPECT
../models-nonbsd/BLEND/fleurOptonl.blend -og -om -vds;../results/tmp/fleurOptonl.blend_95048e3c/EXPECT
../models-nonbsd/BLEND/fleurOptonl.blend -vds -jiv;../results/tmp/fleurOptonl.blend_52481e9e/EXPECT
../models-nonbsd/BLEND/fleurOptonl.blend -ptv -gsn -cts -db;../results/tmp/fleurOptonl.blend_5e7be44/EXPECT
../models-nonbsd/BLEND/fleurOptonl.blend ;../results/tmp/fleurOptonl.blend_18ca7bb4/EXPECT
../models-nonbsd/LWS/QuickDraw v.2.2_oldformat_56.lws -ptv -gsn -cts -db;../results/tmp/QuickDraw v.2.2_oldformat_56.lws_da6fa6e2/EXPECT
../models-nonbsd/LWS/QuickDraw v.2.2_oldformat_56.lws ;../results/tmp/QuickDraw v.2.2_oldformat_56.lws_d37dcb52/EXPECT
../models-nonbsd/Ogre/OgreSDK/ninja.mesh.xml -cfull;../results/tmp/ninja.mesh.xml_2a5e7eb6/EXPECT
../models-nonbsd/PK3/SGDTT3.pk3 -ptv -gsn -cts -db;../results/tmp/SGDTT3.pk3_591f74f1/EXPECT
../models-nonbsd/PK3/SGDTT3.pk3 ;../results/tmp/SGDTT3.pk3_ad4b2ce1/EXPECT
../models-nonbsd/PK3/SGDTT3.pk3 -cfull;../results/tmp/SGDTT3.pk3_ad4b2ce1/EXPECT
1 ORIGINAL FILE EXPECTED DUMP
2 ../models/AC/SphereWithLightUvScaling4X.ac -cfull ../results/tmp/SphereWithLightUvScaling4X.ac_30edbbcd/EXPECT
3 ../models/AC/SphereWithLightUvScaling4X.ac -vds -jiv ../results/tmp/SphereWithLightUvScaling4X.ac_a627320a/EXPECT
4 ../models/AC/sample_subdiv.ac -cfull ../results/tmp/sample_subdiv.ac_669c529e/EXPECT
5 ../models/AC/sample_subdiv.ac -vds -jiv ../results/tmp/sample_subdiv.ac_d5987f9/EXPECT
6 ../models/BLEND/CubeHierarchy_248.blend -cfull ../results/tmp/CubeHierarchy_248.blend_4e04cc99/EXPECT
7 ../models/BLEND/CubeHierarchy_248.blend -og -om -vds ../results/tmp/CubeHierarchy_248.blend_5e78ea9c/EXPECT
8 ../models/BLEND/CubeHierarchy_248.blend -vds -jiv ../results/tmp/CubeHierarchy_248.blend_8aca7a3e/EXPECT
9 ../models/BLEND/CubeHierarchy_248.blend -ptv -gsn -cts -db ../results/tmp/CubeHierarchy_248.blend_1f2b8aa4/EXPECT
10 ../models/BLEND/CubeHierarchy_248.blend ../results/tmp/CubeHierarchy_248.blend_b827f814/EXPECT
11 ../models/BLEND/SuzanneSubdiv_252.blend -cfull ../results/tmp/SuzanneSubdiv_252.blend_4a8dd3d3/EXPECT
12 ../models/BLEND/SuzanneSubdiv_252.blend -vds -jiv ../results/tmp/SuzanneSubdiv_252.blend_7f41fe84/EXPECT
13 ../models/STL/Spider_ascii.stl -cfull ../results/tmp/Spider_ascii.stl_8047fd91/EXPECT
14 ../models/STL/Spider_ascii.stl -vds -jiv ../results/tmp/Spider_ascii.stl_d4858346/EXPECT
15 ../models/STL/Spider_binary.stl -cfull ../results/tmp/Spider_binary.stl_dd4fe21/EXPECT
16 ../models/STL/Spider_binary.stl -vds -jiv ../results/tmp/Spider_binary.stl_2c8deeb6/EXPECT
17 ../models-nonbsd/BLEND/Bob.blend -cfull ../results/tmp/Bob.blend_7f8349ba/EXPECT
18 ../models-nonbsd/BLEND/Bob.blend -og -om -vds ../results/tmp/Bob.blend_4f4a63d/EXPECT
19 ../models-nonbsd/BLEND/Bob.blend -vds -jiv ../results/tmp/Bob.blend_ab1aa5dd/EXPECT
20 ../models-nonbsd/BLEND/Bob.blend -ptv -gsn -cts -db ../results/tmp/Bob.blend_6a5ec4c5/EXPECT
21 ../models-nonbsd/BLEND/Bob.blend ../results/tmp/Bob.blend_2fc376b5/EXPECT
22 ../models-nonbsd/BLEND/fleurOptonl.blend -cfull ../results/tmp/fleurOptonl.blend_6e87e039/EXPECT
23 ../models-nonbsd/BLEND/fleurOptonl.blend -og -om -vds ../results/tmp/fleurOptonl.blend_95048e3c/EXPECT
24 ../models-nonbsd/BLEND/fleurOptonl.blend -vds -jiv ../results/tmp/fleurOptonl.blend_52481e9e/EXPECT
25 ../models-nonbsd/BLEND/fleurOptonl.blend -ptv -gsn -cts -db ../results/tmp/fleurOptonl.blend_5e7be44/EXPECT
26 ../models-nonbsd/BLEND/fleurOptonl.blend ../results/tmp/fleurOptonl.blend_18ca7bb4/EXPECT
27 ../models-nonbsd/LWS/QuickDraw v.2.2_oldformat_56.lws -ptv -gsn -cts -db ../results/tmp/QuickDraw v.2.2_oldformat_56.lws_da6fa6e2/EXPECT
28 ../models-nonbsd/LWS/QuickDraw v.2.2_oldformat_56.lws ../results/tmp/QuickDraw v.2.2_oldformat_56.lws_d37dcb52/EXPECT
29 ../models-nonbsd/Ogre/OgreSDK/ninja.mesh.xml -cfull ../results/tmp/ninja.mesh.xml_2a5e7eb6/EXPECT
30 ../models-nonbsd/PK3/SGDTT3.pk3 -ptv -gsn -cts -db ../results/tmp/SGDTT3.pk3_591f74f1/EXPECT
31 ../models-nonbsd/PK3/SGDTT3.pk3 ../results/tmp/SGDTT3.pk3_ad4b2ce1/EXPECT
32 ../models-nonbsd/PK3/SGDTT3.pk3 -cfull ../results/tmp/SGDTT3.pk3_ad4b2ce1/EXPECT