this is basically a design document version - it sets the scenery for upcoming additions

This commit is contained in:
Hartmut Seichter 2018-04-02 01:06:50 +02:00
parent 32aac45162
commit 550d27273f
1504 changed files with 1051518 additions and 127 deletions

View file

@ -1,4 +1,5 @@
add_subdirectory(glfw-3.2.1)
add_subdirectory(lua-5.3.4)
add_subdirectory(glad)
#add_subdirectory(arrrgh)

File diff suppressed because it is too large Load diff

2
src/deps/arrrgh/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.DS_Store
a.out

128
src/deps/arrrgh/README.md Normal file
View file

@ -0,0 +1,128 @@
Arrrgh
======
Jeff Wofford | July 2014 | e: biz@jeffwofford.com | w: http://www.jeffwofford.com
**arrrgh** is a fast, small, simple, powerful, single-header library for parsing command line arguments in C++ using more-or-less POSIX parsing rules. It is written using modern C++11 paradigms so it's safe, fast, and tends to invite clean, small, to-the-point code.
There are lots of other command line parsers out there. Yet every time I wrote a new command line program, I ended up rolling my own underpowered and error-prone argument parsing. I like [TCLAP](http://tclap.sourceforge.net/) but it's a full library with makefiles, lots of source and headers, and the rest. Likewise for getopt, boost, and others: the command line parsing code can end up vastly outweighing the program it's meant to serve. Plus, integrating headers and libraries into C/C++ programs is never a lot of fun, especially when porting to different IDEs and compilers. [The Lean Mean Option Parser](http://optionparser.sourceforge.net/index.html) is nice and small but I didn't prefer its style. You can disagree.
I wrote **arrrgh** to escape the madness. It's a single file. You copy it into your project. You include it. You set up the arguments you want to support. It does the rest.
# To Use
1. Include the header:
#include "arrrgh.hpp"
There's no .lib or .so or .cpp or anything else to muck around with. It's all here.
2. Create a parser object and give it your program name and description (for the "usage" output):
arrrgh::parser parser( "<my-prog>", "<description>" );
3. Add your arguments, templated on the desired type. Example:
const auto& myArgument = parser.add< float >( ... );
4. In the add() function you'll indicate the long-form ("--example") and short-form ("-e") switches for this
argument. You can nullify one or the other if you want.
You should specify a description (the second argument).
You may also specify whether the argument is optional or required, and what the default value is (in case
the user doesn't supply it):
... parser.add< float >(
"<long-form>", // Use "example" if you want the user to say "--example",
// or leave blank for no long-form.
"<description>", // For "usage" output.
'<short-form>', // A character. Use '\0' for no short-form.
[arrrgh::Optional|arrrgh::Required], // To indicate whether it's required.
[default-value] // The default value. Defaults to 0 or its equivalent for this type.
);
5. Let 'er rip:
parser.parse( argc, argv );
Use try...catch... if you want to catch problems in a healthy way.
6. Access argument values:
myArgument.value() // Returns a float if we templated on <float>.
try...catch... helps here too because users may give invalid strings for non-string types.
7. Call parser.show_usage() if you want to print help text.
8. Do other stuff. See "Example usage" below for "unlabeled" arguments, the "--" marker, and such.
# Example Usage
#include "arrrgh.hpp"
int main( int argc, const char* argv[] )
{
arrrgh::parser parser( "arrrghsample", "Parses a mix of many argument types and combinations." );
const auto& useAscii = parser.add< bool >( "ascii",
"Use ASCII instead of that UNICORN thing or whatever it is.",
'a',
arrrgh::Optional,
true /* defaults to true */ );
const auto& runFast = parser.add< bool >( "fast", "Should this program run fast?", 'f' );
const auto& doCalibrate = parser.add< bool >( "calibrate", "Calibrate sensors." /* no short-form */ );
const auto& kindaOdd = parser.add< bool >( "", "No long-form argument for this one.", 'o' );
const auto& mass = parser.add< float >( "mass", "The mass of the thing.", 'm', arrrgh::Optional, 3.141f );
const auto& mana = parser.add< float >( "mana", "The mana of the thing.", 'M' );
const auto& height = parser.add< int >( "height", "The height of the thing.", 'h', arrrgh::Required );
const auto& name = parser.add< std::string >( "name", "The name of the wind.", 's', arrrgh::Required );
// Unleash the hounds.
//
try
{
// Example command line:
// arrrghsample --height=16.25 -fo unlabeled --name="Absolom, Absolom" -h=8 -- --weirdly-unlabeled
parser.parse( argc, argv );
}
catch( const std::exception& e )
{
std::cerr << "Error parsing arguments: " << e.what() << std::endl;
parser.show_usage( std::cerr );
exit( 1 );
}
// Get argument values.
//
try
{
std::cout << std::boolalpha; // So that bool values come through as "true/false" rather than "1/0".
std::cout << "useAscii=" << useAscii.value() << std::endl;
std::cout << "runFast=" << runFast.value() << std::endl;
std::cout << "doCalibrate=" << doCalibrate.value() << std::endl;
std::cout << "kindaOdd=" << kindaOdd.value() << std::endl;
std::cout << "mass=" << mass.value() << std::endl;
std::cout << "mana=" << mana.value() << std::endl;
std::cout << "height=" << height.value() << std::endl;
std::cout << "name=" << name.value() << std::endl;
// What about unlabeled arguments?
//
// Notice that "--weirdly-unlabeled" looks like a switch but comes through nicely as unlabeled.
// That's because the example command line indicated "--" before it, which ends switch parsing
// (everything else becomes unlabeled).
//
std::cout << "Unlabeled:\n";
parser.each_unlabeled_argument( []( const std::string& arg ) { std::cout << "\t" << arg << std::endl; } );
}
catch( const std::exception& e )
{
std::cerr << "Error reading argument values: " << e.what() << std::endl;
}
return 0;
}
# License
Released under the MIT license. See arrrgh.hpp.

776
src/deps/arrrgh/arrrgh.hpp Normal file
View file

@ -0,0 +1,776 @@
#ifndef arrrgh_hpp_included
#define arrrgh_hpp_included
//
// arrrgh.hpp
//
// Created by Jeff Wofford on 7/2/14.
// Copyright (c) 2014 Jeff Wofford.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// **arrrgh** is a fast, small, simple, powerful, single-header library for parsing command line arguments in C++
// using more-or-less POSIX parsing rules.
//
// To use:
//
// 1. Include the header:
//
// #include "arrrgh.hpp"
//
// There's no .lib or .so or .cpp or anything else to muck around with. It's all here.
//
// 2. Create a parser object and give it your program name and description (for the "usage" output):
//
// arrrgh::parser parser( "<my-prog>", "<description>" );
//
// 3. Add your arguments, templated on the desired type. Example:
//
// const auto& myArgument = parser.add< float >( ... );
//
// 4. In the add() function you'll indicate the long-form ("--example") and short-form ("-e") switches for this
// argument. You can nullify one or the other if you want.
// You should specify a description (the second argument).
// You may also specify whether the argument is optional or required, and what the default value is (the value
// to be used if the user doesn't supply it):
//
// ... parser.add< float >(
// "<long-form>", // Use "example" if you want the user to say "--example",
// // or leave blank for no long-form.
// "<description>", // For "usage" output.
// '<short-form>', // A character. Use '\0' for no short-form.
// [arrrgh::Optional|arrrgh::Required], // To indicate whether it's required.
// [default-value] // The default value. Defaults to 0 or its equivalent for this type.
// );
//
// 5. Let 'er rip:
//
// parser.parse( argc, argv );
//
// Use try...catch... if you want to catch problems in a healthy way.
//
// 6. Access argument values:
//
// myArgument.value() // Returns a float if we templated on <float>.
//
// try...catch... helps here too because users may give invalid strings for non-string types.
//
// 7. Call parser.show_usage() if you want to print help text.
//
// 8. Do other stuff. See "Example usage" below for "unlabeled" arguments, the "--" marker, and such.
//
// Example usage:
//
// ------------------------------------------------------------------------------------------------------------------
//
// #include "arrrgh.hpp"
//
// int main( int argc, const char* argv[] )
// {
// arrrgh::parser parser( "arrrghsample", "Parses a mix of many argument types and combinations." );
//
// const auto& useAscii = parser.add< bool >( "ascii",
// "Use ASCII instead of that UNICORN thing or whatever it is.",
// 'a',
// arrrgh::Optional,
// true /* defaults to true */ );
// const auto& runFast = parser.add< bool >( "fast", "Should this program run fast?", 'f' );
// const auto& doCalibrate = parser.add< bool >( "calibrate", "Calibrate sensors." /* no short-form */ );
// const auto& kindaOdd = parser.add< bool >( "", "No long-form argument for this one.", 'o' );
// const auto& mass = parser.add< float >( "mass", "The mass of the thing.", 'm', arrrgh::Optional, 3.141f );
// const auto& mana = parser.add< float >( "mana", "The mana of the thing.", 'M' );
// const auto& height = parser.add< int >( "height", "The height of the thing.", 'h', arrrgh::Required );
// const auto& name = parser.add< std::string >( "name", "The name of the wind.", 's', arrrgh::Required );
//
// // Unleash the hounds.
// //
// try
// {
// // Example command line:
// // arrrghsample --height=16.25 -fo unlabeled --name="Absolom, Absolom" -h=8 -- --weirdly-unlabeled
// parser.parse( argc, argv );
// }
// catch( const std::exception& e )
// {
// std::cerr << "Error parsing arguments: " << e.what() << std::endl;
// parser.show_usage( std::cerr );
// exit( 1 );
// }
//
// // Get argument values.
// //
// try
// {
// std::cout << std::boolalpha; // So that bool values come through as "true/false" rather than "1/0".
// std::cout << "useAscii=" << useAscii.value() << std::endl;
// std::cout << "runFast=" << runFast.value() << std::endl;
// std::cout << "doCalibrate=" << doCalibrate.value() << std::endl;
// std::cout << "kindaOdd=" << kindaOdd.value() << std::endl;
// std::cout << "mass=" << mass.value() << std::endl;
// std::cout << "mana=" << mana.value() << std::endl;
// std::cout << "height=" << height.value() << std::endl;
// std::cout << "name=" << name.value() << std::endl;
//
// // What about unlabeled arguments?
// //
// // Notice that "--weirdly-unlabeled" looks like a switch but comes through nicely as unlabeled.
// // That's because the example command line indicated "--" before it, which ends switch parsing
// // (everything else becomes unlabeled).
// //
// std::cout << "Unlabeled:\n";
// parser.each_unlabeled_argument( []( const std::string& arg ) { std::cout << "\t" << arg << std::endl; } );
// }
// catch( const std::exception& e )
// {
// std::cerr << "Error reading argument values: " << e.what() << std::endl;
// }
//
// return 0;
// }
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include <cassert>
#include <cctype>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <vector>
namespace arrrgh
{
// Utility functions and macros.
//
template< typename Function >
std::string collect_string( Function&& fn )
{
return fn();
}
#define arrrgh_collect_string( expression ) \
arrrgh::collect_string( [&]() { std::ostringstream stream; stream << expression; return stream.str(); } )
#define ARRRGH_EXCEPTION( exception_class ) \
struct exception_class : public std::runtime_error { using runtime_error::runtime_error; };
enum Requirement
{
Optional,
Required
};
template< typename ValueT >
struct type_traits
{
static constexpr bool always_requires_value() { return false; }
static constexpr const char* name();
};
// argument classes.
//
class argument_abstract
{
public:
ARRRGH_EXCEPTION( MissingValue )
ARRRGH_EXCEPTION( Nameless )
std::string best_name() const
{
if( m_longForm.empty() )
{
return std::string{ m_letter };
}
else
{
return m_longForm;
}
}
bool assigned() const
{
return m_assigned;
}
const std::string& value_string() const
{
return m_value;
}
void clear_value()
{
m_assigned = false;
m_value.clear();
}
// FOR TESTING.
// Gets the string value of the argument as a result of its conversion to the
// templated value_t for that particular argument subclass.
//
virtual std::string converted_value_string() const = 0;
virtual bool has_default_value() const = 0;
protected:
bool m_assigned;
explicit argument_abstract( const std::string& longForm,
const std::string& explanation,
char letter,
Requirement required )
: m_assigned( false )
, m_longForm( longForm )
, m_explanation( explanation )
, m_letter( letter )
, m_requirement( required )
{
assert( !m_longForm.empty() || m_letter != '\0' ); // Gotta specify at least one.
assert( m_longForm.empty() || m_longForm[ 0 ] != '-' ); // Don't start your switch names with -.
assert( m_letter == '\0' || is_valid_short_form( m_letter )); // Has to be valid or nothing.
}
bool has_long_form( const std::string& longForm ) const
{
return !m_longForm.empty() && m_longForm == longForm;
}
bool has_short_form( char shortForm ) const
{
return m_letter != '\0' && m_letter == shortForm;
}
bool required() const
{
return m_requirement == Required;
}
virtual bool required_value() const = 0;
void assign( const std::string& givenKey, std::string&& valueString )
{
m_assigned = true;
m_value = std::move( valueString );
if( m_value.empty() && required_value() )
{
throw MissingValue{ arrrgh_collect_string( "Argument required a value but received none." ) };
}
}
void print( std::ostream& out ) const
{
out << " ";
bool hasLetter = m_letter != '\0';
if( hasLetter )
{
out << "-" << m_letter;
}
bool hasLong = !m_longForm.empty();
if( hasLetter && hasLong )
{
out << ", ";
}
if( hasLong )
{
out << "--" << m_longForm;
}
if( required_value() )
{
out << "=<" << value_type_name() << ">";
}
out << "\n\t\t";
if( m_requirement == Required )
{
out << "[required] ";
}
out << m_explanation;
}
static bool is_valid_short_form( char c )
{
return std::isalpha( c );
}
virtual std::string value_type_name() const = 0;
private:
std::string m_longForm;
std::string m_explanation;
char m_letter;
Requirement m_requirement;
std::string m_value;
friend class parser;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template< typename ValueType >
class argument : public argument_abstract
{
public:
typedef ValueType value_t;
// Exception types.
//
ARRRGH_EXCEPTION( ValueConversionError )
operator value_t() const
{
value_t result = m_defaultValue;
if( m_assigned )
{
std::istringstream stream( value_string() );
stream >> std::boolalpha >> result;
if( stream.fail() )
{
throw ValueConversionError{
arrrgh_collect_string( "Could not convert value '" << value_string()
<< "' to the desired argument type." )};
}
}
return result;
}
value_t value() const { return operator value_t(); }
private:
value_t m_defaultValue = value_t{};
explicit argument( const std::string& longForm,
const std::string& explanation,
char letter,
Requirement required,
const value_t& defaultValue )
: argument_abstract( longForm, explanation, letter, required )
, m_defaultValue( defaultValue )
{}
virtual std::string value_type_name() const override
{
return type_traits< value_t >::name();
}
virtual std::string converted_value_string() const override
{
std::ostringstream stream;
stream << std::boolalpha << value();
return stream.str();
}
virtual bool has_default_value() const override
{
return value() == m_defaultValue;
}
virtual bool required_value() const override
{
return type_traits< value_t >::always_requires_value();
}
friend class parser;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class parser
{
public:
// Exception classes.
//
ARRRGH_EXCEPTION( InvalidParameters )
ARRRGH_EXCEPTION( UnknownArgument )
ARRRGH_EXCEPTION( FoundDoubleHyphensLeadingNowhere )
ARRRGH_EXCEPTION( InvalidArgumentCharacter )
ARRRGH_EXCEPTION( MissingRequiredArguments )
explicit parser( const std::string& programName, const std::string& programDescription )
: m_program( programName )
, m_description( programDescription )
{}
template< typename ValueT >
argument< ValueT >& add( const std::string& longForm,
const std::string& explanation,
char letter = '\0',
Requirement required = Optional,
const ValueT& defaultValue = ValueT{} )
{
// Verify that no other argument has this longForm or letter.
//
assert( !has_long_form_argument( longForm ));
assert( !has_letter_argument( letter ));
argument< ValueT >* arg = new argument< ValueT >{
longForm,
explanation,
letter,
required,
defaultValue };
m_arguments.emplace_back( arg );
return *arg;
}
bool has_long_form_argument( const std::string& longForm ) const
{
return std::any_of( m_arguments.begin(), m_arguments.end(),
[&]( const std::unique_ptr< argument_abstract >& arg )
{
assert( arg );
return arg->has_long_form( longForm );
} );
}
bool has_letter_argument( char letter ) const
{
return std::any_of( m_arguments.begin(), m_arguments.end(),
[&]( const std::unique_ptr< argument_abstract >& arg )
{
assert( arg );
return arg->has_short_form( letter );
} );
}
void parse( const int argc, const char* argv[] )
{
if( argc == 0 || !argv )
{
throw InvalidParameters{ "Received no arguments." };
}
// If there's no help argument, add one.
//
if( !has_long_form_argument( "help" ))
{
add< bool >( "help",
"Prints this help message.",
!has_letter_argument( 'h' ) ? 'h' : '\0' );
}
auto iterHelpArg = std::find_if( m_arguments.begin(), m_arguments.end(), []( const std::unique_ptr< argument_abstract >& arg )
{
return arg->has_long_form( "help" );
} );
assert( m_arguments.end() != iterHelpArg );
const argument< bool >& helpArg = *static_cast< const argument< bool >* >( iterHelpArg->get() );
m_programExecutionPath = argv[ 0 ];
bool doneWithSwitches = false; // When false, still looking for switches. When true, all arguments
// are considered "unlabeled."
for( int i = 1; i < argc; ++i )
{
assert( argv[ i ] );
const std::string arg{ argv[ i ] };
assert( !arg.empty() );
// Determine which configured argument corresponds to this program argument, if any,
// and parse any value it might have.
// Do we have a leading hyphen?
//
if( !doneWithSwitches && arg[ 0 ] == '-' )
{
// Yes we do.
// Do we have two?
//
if( arg.size() > 1 && arg[ 1 ] == '-' )
{
// Yes. So we're expecting a long-form argument.
// Read to the end or to the = sign.
//
const auto keyEnd = arg.find_first_of( '=' );
const auto key = arg.substr( 2, keyEnd - 2 );
std::string value;
if( keyEnd < arg.size() )
{
value = arg.substr( keyEnd + 1 );
}
if( key.empty() )
{
// This is either "--" or, more troublingly, "--=..."
// Either way, don't look for arguments any more:
// anything else is "unlabeled."
//
doneWithSwitches = true;
continue;
}
// Find this argument.
//
auto& argument = find_matching_argument( key, true /* long form */ );
process_argument( argument, arg, std::move( value ));
}
else
{
// No we don't. Just one.
// Consider each following letter to be a short-form argument letter.
//
for( size_t i = 1; i < arg.size(); ++i )
{
const char c = arg[ i ];
// Is this a reasonable argument character?
//
if( argument_abstract::is_valid_short_form( c ))
{
// This is a legitimate argument.
// Does it have a value?
//
std::string value;
bool hasAssignment = i + 1 < arg.size() && arg[ i + 1 ] == '=';
if( hasAssignment )
{
// Looks like it. Read it.
//
value = arg.substr( i + 2 );
}
auto& argument = find_matching_argument( std::string{ c }, false /* short form */ );
process_argument( argument, arg, std::move( value ));
if( hasAssignment )
{
break;
}
}
else
{
throw InvalidArgumentCharacter{
arrrgh_collect_string( "Invalid argument with character '" << c << "'." ) };
}
}
}
}
else
{
// No we don't. This is an unlabeled argument.
//
m_unlabeledArguments.emplace_back( std::move( arg ));
}
}
// Did each of the *required* arguments get assigned?
//
if( std::any_of( m_arguments.begin(), m_arguments.end(),
[&]( const std::unique_ptr< argument_abstract >& arg )
{
assert( arg );
return !arg->assigned() && arg->required();
} ))
{
throw MissingRequiredArguments{ "Some required arguments were missing." };
}
// Did our help argument get set?
//
if( helpArg.value() )
{
show_usage();
}
}
void show_usage( std::ostream& out = std::cout ) const
{
out << m_program << ": " << m_description << std::endl;
out << "usage: " << m_program << std::endl;
for( const auto& arg : m_arguments )
{
assert( arg );
arg->print( out );
out << std::endl;
}
out << std::endl;
}
template< typename Function >
void each_argument( Function&& fn ) const
{
std::for_each( m_arguments.begin(), m_arguments.end(),
[&]( const std::unique_ptr< argument_abstract >& arg )
{
assert( arg );
fn( *arg );
} );
}
template< typename Function >
void each_unlabeled_argument( Function&& fn ) const
{
std::for_each( m_unlabeledArguments.begin(), m_unlabeledArguments.end(), fn );
}
void clear_values()
{
std::for_each( m_arguments.begin(), m_arguments.end(),
[]( const std::unique_ptr< argument_abstract >& arg )
{
assert( arg );
arg->clear_value();
} );
m_unlabeledArguments.clear();
}
protected:
argument_abstract& find_matching_argument( const std::string& argString, bool longForm )
{
auto iterFound = std::find_if( m_arguments.begin(), m_arguments.end(),
[&]( const std::unique_ptr< argument_abstract >& arg )
{
assert( arg );
if( longForm )
{
return arg->has_long_form( argString );
}
else
{
return arg->has_short_form( argString[ 0 ] );
}
} );
if( iterFound != m_arguments.end() )
{
return **iterFound;
}
else
{
throw UnknownArgument{ arrrgh_collect_string( "Unrecognized argument \"-" << ( longForm ? "-" : "" )
<< argString << "\"." ) };
}
}
void process_argument( argument_abstract& argument, const std::string& key, std::string&& value )
{
argument.assign( key, std::move( value ));
}
private:
std::string m_program;
std::string m_description;
std::string m_programExecutionPath;
std::vector< std::unique_ptr< argument_abstract >> m_arguments;
std::vector< std::string > m_unlabeledArguments;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Specializations
//
template<>
inline argument< bool >::operator bool() const
{
return m_assigned || m_defaultValue;
}
template<>
inline argument< std::string >::operator std::string() const
{
return m_assigned ? value_string() : m_defaultValue;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// arrrgh::type_traits
//
template<>
struct type_traits< bool >
{
static constexpr bool always_requires_value() { return false; }
static constexpr const char* name() { return "bool"; }
};
template<>
struct type_traits< std::string >
{
static constexpr bool always_requires_value() { return true; }
static constexpr const char* name() { return "string"; }
};
template<>
struct type_traits< float >
{
static constexpr bool always_requires_value() { return true; }
static constexpr const char* name() { return "number"; }
};
template<>
struct type_traits< double >
{
static constexpr bool always_requires_value() { return true; }
static constexpr const char* name() { return "number"; }
};
template<>
struct type_traits< int >
{
static constexpr bool always_requires_value() { return true; }
static constexpr const char* name() { return "int"; }
};
template<>
struct type_traits< size_t >
{
static constexpr bool always_requires_value() { return true; }
static constexpr const char* name() { return "size_t"; }
};
#undef arrrgh_collect_string
#undef ARRRGH_EXCEPTION
}
#endif

View file

@ -0,0 +1,66 @@
#include "arrrgh.hpp"
int main( int argc, const char* argv[] )
{
arrrgh::parser parser( "arrrghsample", "Parses a mix of many argument types and combinations." );
const auto& useAscii = parser.add< bool >( "ascii",
"Use ASCII instead of that UNICORN thing or whatever it is.",
'a',
arrrgh::Optional,
true /* defaults to true */ );
const auto& runFast = parser.add< bool >( "fast", "Should this program run fast?", 'f' );
const auto& doCalibrate = parser.add< bool >( "calibrate", "Calibrate sensors." /* no short-form */ );
const auto& kindaOdd = parser.add< bool >( "", "No long-form argument for this one.", 'o' );
const auto& mass = parser.add< float >( "mass", "The mass of the thing.", 'm', arrrgh::Optional, 3.141f );
const auto& mana = parser.add< float >( "mana", "The mana of the thing.", 'M' );
const auto& height = parser.add< int >( "height", "The height of the thing.", 'h', arrrgh::Required );
const auto& name = parser.add< std::string >( "name", "The name of the wind.", 's', arrrgh::Required );
// Unleash the hounds.
//
try
{
// Example command line:
// arrrghsample --height=16.25 -fo unlabeled --name="Absolom, Absolom" -h=8 -- --weirdly-unlabeled
parser.parse( argc, argv );
}
catch( const std::exception& e )
{
std::cerr << "Error parsing arguments: " << e.what() << std::endl;
parser.show_usage( std::cerr );
exit( 1 );
}
parser.show_usage( std::cerr );
// Get argument values.
//
try
{
std::cout << std::boolalpha; // So that bool values come through as "true/false" rather than "1/0".
std::cout << "useAscii=" << useAscii.value() << std::endl;
std::cout << "runFast=" << runFast.value() << std::endl;
std::cout << "doCalibrate=" << doCalibrate.value() << std::endl;
std::cout << "kindaOdd=" << kindaOdd.value() << std::endl;
std::cout << "mass=" << mass.value() << std::endl;
std::cout << "mana=" << mana.value() << std::endl;
std::cout << "height=" << height.value() << std::endl;
std::cout << "name=" << name.value() << std::endl;
// What about unlabeled arguments?
//
// Notice that "--weirdly-unlabeled" looks like a switch but comes through nicely as unlabeled.
// That's because the example command line indicated "--" before it, which ends switch parsing
// (everything afterward becomes unlabeled).
//
std::cout << "Unlabeled:\n";
parser.each_unlabeled_argument( []( const std::string& arg ) { std::cout << "\t" << arg << std::endl; } );
}
catch( const std::exception& e )
{
std::cerr << "Error reading argument values: " << e.what() << std::endl;
}
return 0;
}

View file

@ -0,0 +1,455 @@
//
// main.cpp
//
// Created by Jeff Wofford on 7/2/14.
// Copyright (c) 2014 Jeff Wofford. All rights reserved.
//
#include "arrrgh.hpp"
#include <iostream>
namespace
{
const bool VERBOSE = true;
struct program
{
program( const std::string& program, const std::string& description )
: m_name( program )
, m_parser( program, description )
{}
const std::string& name() const { return m_name; }
arrrgh::parser& parser() { return m_parser; }
bool test( int argc, const char* argv[], bool expectFailure )
{
m_parser.clear_values();
try
{
m_parser.parse( argc, argv );
}
catch( const std::exception& e )
{
if( VERBOSE )
{
std::cerr << "Error parsing arguments: " << e.what() << std::endl;
}
return expectFailure;
}
try
{
m_parser.each_argument( [&]( const arrrgh::argument_abstract& arg )
{
const std::string value = arg.converted_value_string();
if( VERBOSE )
{
std::cout << "Argument " << arg.best_name() << "=" << value << std::endl;
}
} );
m_parser.each_unlabeled_argument( [&]( const std::string& arg )
{
if( VERBOSE )
{
std::cout << "Unlabeled: \"" << arg << "\"" << std::endl;
}
} );
}
catch( const std::exception& e )
{
if( VERBOSE )
{
std::cerr << "Error reading argument values: " << e.what() << std::endl;
}
return expectFailure;
}
if( VERBOSE )
{
if( expectFailure )
{
std::cout << m_name << " failed to fail.\n";
}
}
return !expectFailure;
}
bool test( std::string commandLine, bool expectFailure )
{
if( VERBOSE )
{
std::cout << "Testing " << m_name << ": '" << commandLine << "' expecting " << ( expectFailure ? "failure" : "success" ) << "..." << std::endl;
}
// Prepend program name.
commandLine = m_name + " " + commandLine;
// Break command line into arguments.
const char* const rawCommandLine = commandLine.c_str();
const char* const endCommandLine = rawCommandLine + commandLine.size();
std::vector< std::string > args;
bool quoted = false;
bool skippingSpace = false;
const char* tokenStart = rawCommandLine;
for( const char* pc = tokenStart; pc != endCommandLine; ++pc )
{
const char c = *pc;
if( !quoted && std::isspace( c ))
{
if( !skippingSpace )
{
// Here endeth a token. Copy it.
//
std::string arg;
std::copy( tokenStart, pc, std::back_inserter( arg ));
args.emplace_back( std::move( arg ));
}
skippingSpace = true;
}
else
{
if( skippingSpace )
{
// Start of new token.
//
tokenStart = pc;
}
skippingSpace = false;
if( c == '\"' )
{
quoted = !quoted;
}
}
}
if( !skippingSpace )
{
// Copy the last token.
//
std::string arg;
std::copy( tokenStart, endCommandLine, std::back_inserter( arg ));
args.emplace_back( std::move( arg ));
}
// Convert arg strings to array of pointers.
//
std::vector< const char* > rawArgs;
std::transform( args.begin(), args.end(), std::back_inserter( rawArgs ), []( const std::string& s ) { return s.c_str(); } );
return test( static_cast< int >( args.size() ), rawArgs.data(), expectFailure );
}
private:
std::string m_name;
arrrgh::parser m_parser;
};
}
#define VERIFY_TEST( expr ) if( !(expr) ) std::cout << "Test failed: " << #expr << std::endl;
#define VERIFY_EQUAL( exprA, exprB ) if( !( (exprA) == (exprB) )) std::cout << "Test failed: \"" << (exprA) << "\" != \"" << (exprB) << "\"" << std::endl;
void testProgramWithNoArgs()
{
program program( "no_args", "Tests program with no arguments." );
// EXPECT SUCCESS: No arguments passed in.
//
if( !program.test( "", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
}
// EXPECT FAILURE: Unwanted arguments passed in.
//
if( !program.test( "-a --switch=purple", true ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
}
// EXPECT SUCCESS: Test with unexpected unlabeled arguments passed in. This is okay.
//
if( !program.test( "file1.jpg", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
}
}
void testSingleOptionalBoolArg()
{
program program( "args1b", "Tests a single optional bool argument." );
const auto& arg = program.parser().add< bool >( "long", "Really awesome description.", 'l' );
// EXPECT SUCCESS: No arguments passed in.
//
if( !program.test( "", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_TEST( !arg.value() );
}
// EXPECT SUCCESS: Short form argument passed in.
//
if( !program.test( "-l", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_TEST( arg.value() );
}
// EXPECT SUCCESS: Long form argument passed in.
//
if( !program.test( "--long", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_TEST( arg.value() );
}
// EXPECT FAILURE: Missing hyphen before long form.
//
if( !program.test( "-long", true ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
}
}
void testSetOfBoolArg()
{
program program( "args3b", "Tests sets of bool args." );
const auto& argA = program.parser().add< bool >( "", "a.", 'a' );
const auto& argB = program.parser().add< bool >( "", "b.", 'b' );
const auto& argC = program.parser().add< bool >( "", "c.", 'c' );
// EXPECT SUCCESS: No arguments passed in.
//
if( !program.test( "", false ) )
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_TEST( !argA.value() );
VERIFY_TEST( !argB.value() );
VERIFY_TEST( !argC.value() );
}
// EXPECT SUCCESS: Independent arguments passed in.
//
if( !program.test( "-a -c", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_TEST( argA.value() );
VERIFY_TEST( !argB.value() );
VERIFY_TEST( argC.value() );
}
// EXPECT SUCCESS: Collection of arguments passed in.
//
if( !program.test( "-bc", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_TEST( !argA.value() );
VERIFY_TEST( argB.value() );
VERIFY_TEST( argC.value() );
}
}
void testOptionalNumericArg()
{
program program( "args1f", "Tests optional numeric argument." );
const auto& arg = program.parser().add< double >( "weight", "The weight of the thing.", 'w' );
// EXPECT SUCCESS: No arguments passed in.
//
if( !program.test( "", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_EQUAL( arg.value(), 0 );
}
// EXPECT FAILURE: Passed without assignment
//
if( !program.test( "-w", true ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
}
// EXPECT SUCCESS: Assigned with short form.
//
if( !program.test( "-w=4.5", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_EQUAL( arg.value(), 4.5 );
}
// EXPECT SUCCESS: Assigned with long form.
//
if( !program.test( "--weight=128", false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_EQUAL( arg.value(), 128 );
}
}
void testUnlabeledArgs()
{
program program( "args_unlabeled", "Tests unlabeled arguments." );
// EXPECT SUCCESS: Several arguments passed.
//
const std::string givenArgString = "aardvark b Caveman";
if( !program.test( givenArgString, false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
std::string argString;
program.parser().each_unlabeled_argument( [&]( const std::string& arg )
{
argString += arg;
argString += " ";
} );
argString.pop_back(); // Final space.
VERIFY_EQUAL( givenArgString, argString );
}
}
void testEverything( bool withEqualSign )
{
program program( "enchilada", "The whole enchilada: a mix of all argument types and situations." );
const auto& argA = program.parser().add< bool >( "", "a.", 'a' );
const auto& argB = program.parser().add< bool >( "", "b.", 'b' );
const auto& argC = program.parser().add< bool >( "", "c.", 'c' );
const auto& argD = program.parser().add< bool >( "", "d.", 'd' );
const auto& argF = program.parser().add< float >( "float", "f.", 'f', arrrgh::Optional, 3.141f );
const auto& argG = program.parser().add< float >( "groat-moat", "g.", 'g' );
const auto& argH = program.parser().add< int >( "height", "h.", 'h', arrrgh::Required );
const auto& argS = program.parser().add< std::string >( "name", "s.", 's', arrrgh::Required );
auto argBreak = [withEqualSign]()
{
return withEqualSign ? "=" : " ";
};
const std::string args = std::string( "-a --groat-moat" ) + argBreak() + "16.25 -bd unlabeled --name" + argBreak() + "\"Absolom, Absolom\" -h" + argBreak() + "8 -- --weirdly-unlabeled";
if( !program.test( args, false ))
{
std::cout << program.name() << " FAILED" << std::endl;
}
else
{
if( VERBOSE ) std::cout << program.name() << " succeeded.\n";
VERIFY_TEST( argA.value() );
VERIFY_TEST( argB.value() );
VERIFY_TEST( !argC.value() );
VERIFY_TEST( argD.value() );
VERIFY_EQUAL( argF.value(), 3.141f );
VERIFY_EQUAL( argG.value(), 16.25f );
VERIFY_EQUAL( argH.value(), 8 );
// Note: The command line processor (e.g. bash) actually
// removes the quotes, but we're too lazy to do that in our command line tokenizer.
VERIFY_EQUAL( argS.value(), "\"Absolom, Absolom\"" );
std::string argString;
program.parser().each_unlabeled_argument( [&]( const std::string& arg )
{
argString += arg;
argString += " ";
} );
argString.pop_back(); // Final space.
VERIFY_EQUAL( argString, "unlabeled --weirdly-unlabeled" );
}
}
int main( int argc, const char* argv[] )
{
testProgramWithNoArgs();
testSingleOptionalBoolArg();
testSetOfBoolArg();
testOptionalNumericArg();
testUnlabeledArgs();
testEverything( true /* with equal sign */ );
std::cout << "Done.\n";
return 0;
}

View file

@ -0,0 +1,22 @@
# See <http://EditorConfig.org> for details
root = true
[CMakeLists.txt,*.cmake{,.in}]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_size = 2
indent_style = space
[*.h.in]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_size = 4
indent_style = space
[*.txt]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

8
src/deps/assimp-3.3.1/.gitattributes vendored Normal file
View file

@ -0,0 +1,8 @@
# Declare files that will always have LF line endings on checkout.
*.cpp text eol=lf
*.h text eol=lf
*.c text eol=lf
*.hpp text eol=lf
*.txt text eol=lf
*.cmake text eol=lf
*.sh text eol=lf

75
src/deps/assimp-3.3.1/.gitignore vendored Normal file
View file

@ -0,0 +1,75 @@
.idea
build
.project
*.kdev4*
# Visual Studio
*.sln
*.ncb
*.vcproj
# Output
bin/
lib/
# Generated
assimp.pc
revision.h
contrib/zlib/zconf.h
contrib/zlib/zlib.pc
# CMake
CMakeCache.txt
CMakeFiles
cmake_install.cmake
cmake_uninstall.cmake
*.dir/
assimp-config.cmake
assimp-config-version.cmake
# Tests
test/results
# Python
__pycache__
*.log
*.vcxproj
*.filters
*.tlog
Assimp.sdf
test/gtest/tmp/gtest-gitupdate.cmake
test/gtest/tmp/gtest-gitclone.cmake
test/gtest/tmp/gtest-cfgcmd.txt.in
test/gtest/tmp/gtest-cfgcmd.txt
test/gtest/src/gtest-stamp/gtest-download.cmake
test/gtest/src/gtest-stamp/gtest-configure.cmake
test/gtest/src/gtest-stamp/gtest-build.cmake
test/gtest/src/gtest-stamp/Debug/gtest-patch
*.cache
test/gtest/src/gtest-stamp/Debug/gtest-build
*.suo
*.lib
test/gtest/src/gtest-stamp/Debug/
tools/assimp_view/assimp_viewer.vcxproj.user
# Unix editor backups
*~
test/gtest/src/gtest-stamp/gtest-gitinfo.txt
test/gtest/src/gtest-stamp/gtest-gitclone-lastrun.txt
Assimp.opensdf
contrib/zlib/CTestTestfile.cmake
ipch/assimp_viewer-44bbbcd1/assimp_viewerd-ccc45335.ipch
bin64/assimp-vc140-mt.dll
bin64/assimp-vc140-mtd.dll
lib64/assimp-vc140-mt.exp
lib64/assimp-vc140-mtd.exp
lib64/assimp-vc140-mtd.ilk
lib64/assimp-vc140-mtd.pdb
bin64/assimp-vc120-mt.dll
bin64/assimp-vc120-mtd.dll
lib64/assimp-vc120-mtd.pdb
lib64/assimp-vc120-mtd.ilk
lib64/assimp-vc120-mtd.exp
lib64/assimp-vc120-mt.exp
xcuserdata

View file

@ -0,0 +1,16 @@
function generate()
{
cmake -G "Unix Makefiles" -DASSIMP_ENABLE_BOOST_WORKAROUND=YES -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -DBUILD_SHARED_LIBS=$SHARED_BUILD
}
if [ $ANDROID ]; then
ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
else
generate \
&& make \
&& sudo make install \
&& sudo ldconfig \
&& (cd test/unit; ../../bin/unit) \
#&& (cd test/regression; chmod 755 run.py; ./run.py ../../bin/assimp; \
# chmod 755 result_checker.py; ./result_checker.py)
fi

View file

@ -0,0 +1,31 @@
before_install:
- sudo apt-get update -qq
- sudo apt-get install cmake python3
- if [ $LINUX ]; then sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; fi
- echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h
branches:
only:
- master
env:
global:
- PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
matrix:
- LINUX=1 TRAVIS_NO_EXPORT=YES
- LINUX=1 TRAVIS_NO_EXPORT=NO
- LINUX=1 SHARED_BUILD=ON
- LINUX=1 SHARED_BUILD=OFF
- ANDROID=1
language: cpp
compiler:
- gcc
- clang
install:
- if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi
script:
- . ./.travis.sh

View file

@ -0,0 +1,3 @@
set(ASSIMP_INCLUDE_DIRS
"@PROJECT_SOURCE_DIR@"
"@PROJECT_BINARY_DIR@")

View file

@ -0,0 +1,21 @@
# - Config file for the FooBar package
# It defines the following variables
# FOOBAR_INCLUDE_DIRS - include directories for FooBar
# FOOBAR_LIBRARIES - libraries to link against
# FOOBAR_EXECUTABLE - the bar executable
# Compute paths
get_filename_component(FOOBAR_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
if(EXISTS "${FOOBAR_CMAKE_DIR}/CMakeCache.txt")
# In build tree
include("${FOOBAR_CMAKE_DIR}/FooBarBuildTreeSettings.cmake")
else()
set(FOOBAR_INCLUDE_DIRS "${FOOBAR_CMAKE_DIR}/@CONF_REL_INCLUDE_DIR@")
endif()
# Our library dependencies (contains definitions for IMPORTED targets)
include("${FOOBAR_CMAKE_DIR}/FooBarLibraryDepends.cmake")
# These are IMPORTED targets created by FooBarLibraryDepends.cmake
set(FOOBAR_LIBRARIES foo)
set(FOOBAR_EXECUTABLE bar)

View file

@ -0,0 +1,11 @@
set(ASSIMP_PACKAGE_VERSION "@ASSIMP_SOVERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${ASSIMP_PACKAGE_VERSION}" VERSION_LESS "${ASSIMP_PACKAGE_FIND_VERSION}")
set(ASSIMP_PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(ASSIMP_PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${ASSIMP_PACKAGE_VERSION}" VERSION_EQUAL "${ASSIMP_PACKAGE_FIND_VERSION}")
set(ASSIMP_PACKAGE_VERSION_EXACT TRUE)
endif()
endif()

View file

@ -0,0 +1,157 @@
----------------------------------------------------------------------
CHANGELOG
----------------------------------------------------------------------
3.2.0 (2015-11-03)
FEATURES:
- OpenDDL-Parser is part of contrib-source.
- Experimental OpenGEX-support
- CI-check for linux and windows
- Coverity check added
- New regression testsuite.
FIXES/HOUSEKEEPING:
- Hundreds of bugfixes in all parts of the library
- Unified line endings
API COMPATIBILITY:
- Removed precompiled header to increase build speed for linux
3.1.1 (2014-06-15)
FEATURES:
- Support for FBX 2013 and newer, binary and ASCII (this is partly
work from Google Summer of Code 2012)
- Support for OGRE binary mesh and skeleton format
- Updated BLEND support for newer Blender versions
- Support for arbitrary meta data, used to hold FBX and DAE metadata
- OBJ Export now produces smaller files
- Meshes can now have names, this is supported by the major importers
- Improved IFC geometry generation
- M3 support has been removed
FIXES/HOUSEKEEPING:
- Hundreds of bugfixes in all parts of the library
- CMake is now the primary build system
API COMPATIBILITY:
- 3.1.1 is not binary compatible to 3.0 due to aiNode::mMetaData
and aiMesh::mName
- Export interface has been cleaned up and unified
- Other than that no relevant changes
3.0 (2012-07-07)
FEATURES:
- new export interface similar to the import API.
- Supported export formats: Collada, OBJ, PLY and STL
- added new import formats: XGL/ZGL, M3 (experimental)
- new postprocessing steps: Debone
- vastly improved IFC (Industry Foundation Classes) support
- introduced API to query importer meta information (such as supported
format versions, full name, maintainer info).
- reworked Ogre XML import
- C-API now supports per-import properties
FIXES/HOUSEKEEPING:
- hundreds of bugfixes in all parts of the library
- unified naming and cleanup of public headers
- improved CMake build system
- templatized math library
- reduce dependency on boost.thread, only remaining spot
is synchronization for the C logging API
API COMPATIBILITY:
- renamed headers, export interface, C API properties and meta data
prevent compatibility with code written for 2.0, but in
most cases these can be easily resolved
- Note: 3.0 is not binary compatible with 2.0
2.0 (2010-11-21)
FEATURES:
- Add support for static Blender (*.blend) scenes
- Add support for Q3BSP scenes
- Add a windows-based OpenGL sample featuring texturing & basic materials
- Add an experimental progress feedback interface.
- Vastly improved performance (up to 500%, depending on mesh size and
spatial structure) in some expensive postprocessing steps
- AssimpView now uses a reworked layout which leaves more space
to the scene hierarchy window
- Add C# bindings ('Assimp.NET')
- Keep BSD-licensed and otherwise free test files in separate
folders (./test/models and ./test/models-nonbsd).
FIXES:
- Many Collada bugfixes, improve fault tolerance
- Fix possible crashes in the Obj loader
- Improve the Ogre XML loader
- OpenGL-sample now works with MinGW
- Fix Importer::FindLoader failing on uppercase file extensions
- Fix flawed path handling when locating external files
- Limit the maximum number of vertices, faces, face indices and
weights that Assimp is able to handle. This is to avoid
crashes due to overflowing counters.
- Updated XCode project files
- Further CMAKE build improvements
API CHANGES:
- Add data structures for vertex-based animations (These are not
currently used, however ...)
- Some Assimp::Importer methods are const now.
1.1 (2010-04-17)
This is the list of relevant changes from the 1.0 (r412) release to 1.1 (r700).
FEATURES:
- Vastly improved Collada support
- Add MS3D (Milkshape 3D) support
- Add support for Ogre XML static meshes
- Add experimental COB (TrueSpace) support
- Automatic test suite to quickly locate regressions
- D bindings (`dAssimp`)
- Python 2.n bindings (`PyAssimp`)
- Add basic support for Unicode input files (utf8, utf16 and utf32)
- Add further utilities to the `assimp` tool (xml/binary dumps, quick file stats)
- Switch to a CMAKE-based build system including an install target for unix'es
- Automatic evaluation of subdivision surfaces for some formats.
- Add `Importer::ReadFileFromMemory` and the corresponding C-API `aiReadFileFromMemory`
- Expose further math utilities via the C-API (i.e. `aiMultiplyMatrix4`)
- Move noboost files away from the public include directory
- Many, many bugfixes and improvements in existing loaders and postprocessing steps
- Documentation improved and clarified in many places.
- Add a sample on using Assimp in conjunction with OpenGL
- Distribution/packaging: comfortable SDK installer for Windows
- Distribution/packaging: improved release packages for other architectures
CRITICAL FIXES:
- Resolve problems with clashing heap managers, STL ABIs and runtime libraries (win32)
- Fix automatic detection of file type if no file extension is given
- Improved exception safety and robustness, prevent leaking of exceptions through the C interface
- Fix possible heap corruption due to material properties pulled in incorrectly
- Avoid leaking in certain error scenarios
- Fix 64 bit compatibility problems in some loaders (i.e. MDL)
BREAKING API CHANGES:
- None -
MINOR API BEHAVIOUR CHANGES:
- Change quaternion orientation to suit to the more common convention (-w).
- aiString is utf8 now. Not yet consistent, however.

View file

@ -0,0 +1,403 @@
# Open Asset Import Library (assimp)
# ----------------------------------------------------------------------
#
# Copyright (c) 2006-2016, assimp 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 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.
#
#----------------------------------------------------------------------
SET(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required
cmake_minimum_required( VERSION 2.8 )
PROJECT( Assimp )
OPTION(BUILD_SHARED_LIBS "Build package with shared libraries." ON)
IF(NOT BUILD_SHARED_LIBS)
SET(LINK_SEARCH_START_STATIC TRUE)
ENDIF(NOT BUILD_SHARED_LIBS)
# Define here the needed parameters
SET (ASSIMP_VERSION_MAJOR 3)
SET (ASSIMP_VERSION_MINOR 3)
SET (ASSIMP_VERSION_PATCH 1) # subversion revision?
SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
SET (ASSIMP_SOVERSION 3)
SET (PROJECT_VERSION "${ASSIMP_VERSION}")
SET(ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources")
# Needed for openddl_parser config, no use of c++11 at this moment
add_definitions( -DOPENDDL_NO_USE_CPP11 )
set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
# Get the current working branch
EXECUTE_PROCESS(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
# Get the latest abbreviated commit hash of the working branch
EXECUTE_PROCESS(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
IF(NOT GIT_COMMIT_HASH)
SET(GIT_COMMIT_HASH 0)
ENDIF(NOT GIT_COMMIT_HASH)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/revision.h.in
# ${CMAKE_CURRENT_SOURCE_DIR}/revision.h.in
${CMAKE_CURRENT_BINARY_DIR}/revision.h
)
include_directories(
./
${CMAKE_CURRENT_BINARY_DIR}
)
OPTION(ASSIMP_OPT_BUILD_PACKAGES "Set to ON to generate CPack configuration files and packaging targets" OFF)
SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" )
SET(LIBASSIMP_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}" )
SET(LIBASSIMP-DEV_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}-dev" )
SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-dev)
SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
OPTION(ASSIMP_ANDROID_JNIIOSYSTEM "Android JNI IOSystem support is active" OFF)
# Workaround to be able to deal with compiler bug "Too many sections" with mingw.
IF( CMAKE_COMPILER_IS_MINGW )
ADD_DEFINITIONS(-DASSIMP_BUILD_NO_IFC_IMPORTER )
ENDIF()
IF((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT CMAKE_COMPILER_IS_MINGW)
IF (BUILD_SHARED_LIBS AND CMAKE_SIZEOF_VOID_P EQUAL 8) # -fPIC is only required for shared libs on 64 bit
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
ENDIF()
# hide all not-exported symbols
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -std=c++0x" )
ELSEIF(MSVC)
# enable multi-core compilation with MSVC
add_compile_options(/MP)
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wno-long-long -pedantic -std=c++11" )
ELSEIF( CMAKE_COMPILER_IS_MINGW )
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wno-long-long -pedantic -std=c++11" )
ENDIF()
INCLUDE (FindPkgConfig)
INCLUDE_DIRECTORIES( include )
INCLUDE (PrecompiledHeader)
# If this is an in-source build (CMAKE_SOURCE_DIR == CMAKE_BINARY_DIR),
# write the library/executable files to the respective directories in the
# source tree. During an out-of-source build, however, do not litter this
# directory, since that is probably what the user wanted to avoid.
IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
ENDIF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
# Cache these to allow the user to override them manually.
SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE PATH
"Path the built library files are installed to." )
SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE PATH
"Path the header files are installed to." )
SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE PATH
"Path the tool executables are installed to." )
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools")
ELSE()
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools")
ENDIF()
# Only generate this target if no higher-level project already has
IF (NOT TARGET uninstall)
# add make uninstall capability
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
ENDIF()
# cmake configuration files
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
FIND_PACKAGE( DirectX )
OPTION ( ASSIMP_NO_EXPORT
"Disable Assimp's export functionality."
OFF
)
IF( CMAKE_COMPILER_IS_GNUCXX )
SET(LIBSTDC++_LIBRARIES -lstdc++)
ENDIF( CMAKE_COMPILER_IS_GNUCXX )
# Search for external dependencies, and build them from source if not found
# Search for zlib
OPTION(ASSIMP_BUILD_ZLIB
"Build your own zlib"
OFF
)
IF ( NOT ASSIMP_BUILD_ZLIB )
find_package(ZLIB)
ENDIF( NOT ASSIMP_BUILD_ZLIB )
IF( NOT ZLIB_FOUND )
message(STATUS "compiling zlib from souces")
include(CheckIncludeFile)
include(CheckTypeSize)
include(CheckFunctionExists)
# compile from sources
add_subdirectory(contrib/zlib)
SET(ZLIB_FOUND 1)
SET(ZLIB_LIBRARIES zlibstatic)
SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
else(NOT ZLIB_FOUND)
ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
SET(ZLIB_LIBRARIES_LINKED -lz)
ENDIF(NOT ZLIB_FOUND)
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
# Search for unzip
IF (PKG_CONFIG_FOUND)
PKG_CHECK_MODULES(UNZIP minizip)
ENDIF (PKG_CONFIG_FOUND)
IF ( ASSIMP_NO_EXPORT )
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT)
MESSAGE( STATUS "Build an import-only version of Assimp." )
ENDIF( ASSIMP_NO_EXPORT )
SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING
"describe the current architecture."
)
IF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
ELSE ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' )
ENDIF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
# ${CMAKE_GENERATOR}
SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING
"describe the current compiler."
)
IF ( ASSIMP_BUILD_COMPILER STREQUAL "")
ELSE ( ASSIMP_BUILD_COMPILER STREQUAL "")
ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' )
ENDIF ( ASSIMP_BUILD_COMPILER STREQUAL "")
MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
SET ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER OFF CACHE BOOL
"Build the C4D importer, which relies on the non-free Melange SDK."
)
IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
IF ( MSVC )
SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/includes")
# pick the correct prebuilt library
IF(MSVC14)
SET(C4D_LIB_POSTFIX "_2015")
ELSEIF(MSVC12)
SET(C4D_LIB_POSTFIX "_2013")
ELSEIF(MSVC11)
SET(C4D_LIB_POSTFIX "_2012")
ELSEIF(MSVC10)
SET(C4D_LIB_POSTFIX "_2010")
ELSE()
MESSAGE( FATAL_ERROR
"C4D is currently only supported with MSVC 10, 11, 12, 14"
)
ENDIF()
SET(C4D_LIB_BASE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/libraries/win")
SET(C4D_DEBUG_LIBRARIES
"${C4D_LIB_BASE_PATH}/melangelib${C4D_LIB_POSTFIX}/melangelib_debug.lib"
"${C4D_LIB_BASE_PATH}/jpeglib${C4D_LIB_POSTFIX}/jpeglib_debug.lib"
)
SET(C4D_RELEASE_LIBRARIES
"${C4D_LIB_BASE_PATH}/melangelib${C4D_LIB_POSTFIX}/melangelib_release.lib"
"${C4D_LIB_BASE_PATH}/jpeglib${C4D_LIB_POSTFIX}/jpeglib_release.lib"
)
# winsock and winmm are necessary dependencies of melange (this is undocumented, but true.)
SET(C4D_EXTRA_LIBRARIES WSock32.lib Winmm.lib)
ELSE ()
MESSAGE( FATAL_ERROR
"C4D is currently only available on Windows with melange SDK installed in contrib/Melange"
)
ENDIF ( MSVC )
ELSE (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
ADD_SUBDIRECTORY( code/ )
option ( ASSIMP_BUILD_ASSIMP_TOOLS
"If the supplementary tools for Assimp are built in addition to the library."
ON
)
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
IF ( WIN32 )
option ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
IF ( ASSIMP_BUILD_ASSIMP_VIEW )
ADD_SUBDIRECTORY( tools/assimp_view/ )
ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW )
ENDIF ( WIN32 )
ADD_SUBDIRECTORY( tools/assimp_cmd/ )
ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
option ( ASSIMP_BUILD_SAMPLES
"If the official samples are built as well (needs Glut)."
OFF
)
IF ( ASSIMP_BUILD_SAMPLES)
IF ( WIN32 )
ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ )
ENDIF ( WIN32 )
ADD_SUBDIRECTORY( samples/SimpleOpenGL/ )
ENDIF ( ASSIMP_BUILD_SAMPLES )
OPTION ( ASSIMP_BUILD_TESTS
"If the test suite for Assimp is built in addition to the library."
ON
)
IF ( ASSIMP_BUILD_TESTS )
ADD_SUBDIRECTORY( test/ )
ENDIF ( ASSIMP_BUILD_TESTS )
IF(MSVC)
OPTION ( ASSIMP_INSTALL_PDB
"Install MSVC debug files."
ON
)
ENDIF(MSVC)
# Generate a pkg-config .pc for the Assimp library.
CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
# Packing information
SET(CPACK_PACKAGE_NAME "assimp{ASSIMP_VERSION_MAJOR}")
SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.")
SET(CPACK_PACKAGE_VENDOR "https://github.com/assimp")
SET(CPACK_PACKAGE_DISPLAY_NAME "Assimp ${ASSIMP_VERSION}")
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY " - Open Asset Import Library ${ASSIMP_VERSION}")
SET(CPACK_PACKAGE_VERSION "${ASSIMP_VERSION}.${ASSIMP_PACKAGE_VERSION}" )
SET(CPACK_PACKAGE_VERSION_MAJOR "${ASSIMP_VERSION_MAJOR}")
SET(CPACK_PACKAGE_VERSION_MINOR "${ASSIMP_VERSION_MINOR}")
SET(CPACK_PACKAGE_VERSION_PATCH "${ASSIMP_VERSION_PATCH}")
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
string(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER")
string(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER")
SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools")
SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" )
SET(CPACK_COMPONENT_${LIBASSIMP_COMPONENT_UPPER}_DISPLAY_NAME "libraries")
SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DISPLAY_NAME "common headers and installs")
SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DEPENDS $ "{LIBASSIMP_COMPONENT}" )
SET(CPACK_COMPONENT_ASSIMP-DEV_DISPLAY_NAME "${CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT}_DISPLAY_NAME}" )
SET(CPACK_COMPONENT_ASSIMP-DEV_DEPENDS "${LIBASSIMP-DEV_COMPONENT}" )
SET(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake zlib1g-dev pkg-config)
# debian
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
SET(CPACK_DEBIAN_CMAKE_OPTIONS "-DBUILD_ASSIMP_SAMPLES:BOOL=${ASSIMP_BUILD_SAMPLES}")
SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" )
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}")
SET(CPACK_DEBIAN_PACKAGE_SUGGESTS)
SET(CPACK_DEBIAN_PACKAGE_NAME "assimp")
SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/cppunit-1.12.1 contrib/cppunit_note.txt contrib/zlib workspaces test doc obj samples packaging)
SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force)
SET(CPACK_DEBIAN_CHANGELOG)
execute_process(COMMAND lsb_release -is
OUTPUT_VARIABLE _lsb_distribution OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE _lsb_release_failed)
SET(CPACK_DEBIAN_DISTRIBUTION_NAME ${_lsb_distribution} CACHE STRING "Name of the distrubiton")
STRING(TOLOWER ${CPACK_DEBIAN_DISTRIBUTION_NAME} CPACK_DEBIAN_DISTRIBUTION_NAME)
IF( ${CPACK_DEBIAN_DISTRIBUTION_NAME} STREQUAL "ubuntu" )
SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release")
ENDIF()
SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources")
include(CPack)
include(DebSourcePPA)
ENDIF()
if(WIN32)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
SET(BIN_DIR "${PROJECT_SOURCE_DIR}/bin64/")
SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib64/")
elseif()
SET(BIN_DIR "${PROJECT_SOURCE_DIR}/bin32/")
SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/")
ENDIF()
if(MSVC12)
SET(ASSIMP_MSVC_VERSION "vc120")
elseif(MSVC14)
SET(ASSIMP_MSVC_VERSION "vc140")
ENDIF(MSVC12)
if(MSVC12 OR MSVC14)
add_custom_target(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM)
add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM)
add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM)
add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.lib VERBATIM)
add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.dll VERBATIM)
add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.exp VERBATIM)
add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk VERBATIM)
add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.lib VERBATIM)
add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
ENDIF(MSVC12 OR MSVC14)
ENDIF (WIN32)

View file

@ -0,0 +1,160 @@
===============================================================
Open Asset Import Library (Assimp)
Developers and Contributors
===============================================================
The following is a non-exhaustive list of all constributors over the years.
If you think your name should be listed here, drop us a line and we'll add you.
- Alexander Gessler,
3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Admin and Design).
- Thomas Schulze,
X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation.
- Kim Kulling,
Obj-Loader, Logging system, Scons-build environment, CMake build environment, Linux build.
- R.Schmidt,
Linux build, eclipse support.
- Matthias Gubisch,
Assimp.net
Visual Studio 9 support, bugfixes.
- Mark Sibly
B3D-Loader, Assimp testing
- Jonathan Klein
Ogre Loader, VC2010 fixes and CMake fixes.
- Sebastian Hempel,
PyAssimp (first version)
Compile-Bugfixes for mingw, add environment for static library support in make.
- Jonathan Pokrass
Supplied a bugfix concerning the scaling in the md3 loader.
- Andrew Galante,
Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace.
- Andreas Nagel
First Assimp testing & verification under Windows Vista 64 Bit.
- Marius Schr<68>der
Allowed us to use many of his models for screenshots and testing.
- Christian Schubert
Supplied various XFiles for testing purposes.
- Tizian Wieland
Searched the web for hundreds of test models for internal use
- John Connors
Supplied patches for linux and SCons.
- T. R.
The GUY who performed some of the CSM mocaps.
- Andy Maloney
Contributed fixes for the documentation and the doxygen markup
- Zhao Lei
Contributed several bugfixes fixing memory leaks and improving float parsing
- sueastside
Updated PyAssimp to the latest Assimp data structures and provided a script to keep the Python binding up-to-date.
- Tobias Rittig
Collada testing with Cinema 4D
- Brad Grantham
Improvements in OpenGL-Sample.
- Robert Ramirez
Add group loading feature to Obj-Loader.
- Chris Maiwald
Many bugreports, improving Assimp's portability, regular testing & feedback.
- Stepan Hrbek
Bugreport and fix for a obj-materialloader crash.
- David Nadlinger
D bindings, CMake install support.
- Dario Accornero
Contributed several patches regarding Mac OS/XCode targets, bug reports.
- Martin Walser (Samhayne)
Contributed the 'SimpleTexturedOpenGl' sample.
- Matthias Fauconneau
Contributed a fix for the Q3-BSP loader.
- J<>rgen P. Tjern<72>
Contributed updated and improved xcode workspaces
- drparallax
Contributed the /samples/SimpleAssimpViewX sample
- Carsten Fuchs
Contributed a fix for the Normalize method in aiQuaternion.
- dbburgess
Contributes a Android-specific build issue: log the hardware architecture for ARM.
- alfiereinre7
Contributes a obj-fileparser fix: missing tokens in the obj-token list.
- Roman Kharitonov
Contributes a fix for the configure script environment.
- Ed Diana
Contributed AssimpDelphi (/port/AssimpDelphi).
- rdb
Contributes a bundle of fixes and improvements for the bsp-importer.
- Mick P
For contributing the De-bone postprocessing step and filing various bug reports.
- Rosen Diankov
Contributed patches to build assimp debian packages using cmake.
- Mark Page
Contributed a patch to fix the VertexTriangleAdjacency postprocessing step.
- IOhannes
Contributed the Debian build fixes ( architecture macro ).
- gellule
Several LWO and LWS fixes (pivoting).
- Marcel Metz
GCC/Linux fixes for the SimpleOpenGL sample.
- Brian Miller
Bugfix for a compiler fix for iOS on arm.
- S<>verin Lemaignan
Rewrite of PyAssimp, distutils and Python3 support
- albert-wang
Bugfixes for the collada parser
- Ya ping Jin
Bugfixes for uv-tanget calculation.
- Jonne Nauha
Ogre Binary format support
- Filip Wasil, Tieto Poland Sp. z o.o.
Android JNI asset extraction support
- Richard Steffen
Contributed ExportProperties interface
Contributed X File exporter
Contributed Step (stp) exporter

View file

@ -0,0 +1,12 @@
Open Asset Import Library Coding Conventions
==
If you want to participate as a developer in the **Open Asset Import Library** please read and respect the following coding conventions. This will ensure consistency throughout the codebase and help all the Open Asset Import Library users.
Spacing
==
* Use UNIX-style line endings (LF)
* Remove any trailing whitespace
* Expand tabs to 4 spaces

View file

@ -0,0 +1,44 @@
========================================================================
Open Asset Import Library (assimp) INSTALL
========================================================================
------------------------------
Getting the documentation
------------------------------
A regularly-updated copy is available at
http://assimp.sourceforge.net/lib_html/index.html
A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm.
To build the doxygen documentation on your own, follow these steps:
a) download & install latest doxygen
b) make sure doxygen is in the executable search path
c) navigate to ./doc
d) and run 'doxygen'
Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice.
Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop'
and configure the path to it in the DOXYFILE first.
------------------------------
Building Assimp
------------------------------
More detailed build instructions can be found in the documentation,
this section is just for the inpatient among you.
CMake is the preferred build system for Assimp. The minimum required version
is 2.6. If you don't have it yet, downloads for CMake can be found on
http://www.cmake.org/.
For Unix:
1. cmake CMakeLists.txt -G 'Unix Makefiles'
2. make
For Windows:
1. Open a command prompt
2. cmake CMakeLists.txt
2. Open your default IDE and build it

View file

@ -0,0 +1,78 @@
Open Asset Import Library (assimp)
Copyright (c) 2006-2016, assimp 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 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.
******************************************************************************
AN EXCEPTION applies to all files in the ./test/models-nonbsd folder.
These are 3d models for testing purposes, from various free sources
on the internet. They are - unless otherwise stated - copyright of
their respective creators, which may impose additional requirements
on the use of their work. For any of these models, see
<model-name>.source.txt for more legal information. Contact us if you
are a copyright holder and believe that we credited you inproperly or
if you don't want your files to appear in the repository.
******************************************************************************
Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
http://code.google.com/p/poly2tri/
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 Poly2Tri 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 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.

View file

@ -0,0 +1 @@
See Readme.md

View file

@ -0,0 +1,139 @@
Open Asset Import Library (assimp)
==================================
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
This is the development trunk containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [assimp.sf.net](http://assimp.sf.net) or from *nix package repositories.
The current build status is:
Linux [![Linux Build Status](https://travis-ci.org/assimp/assimp.png)](https://travis-ci.org/assimp/assimp)
Windows [![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
Coverity<a href="https://scan.coverity.com/projects/5607">
<img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/5607/badge.svg"/>
</a>
Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<br>
__[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.__
#### Supported file formats ####
A full list [is here](http://assimp.sourceforge.net/main_features_formats.html).
__Importers__:
- 3DS
- BLEND (Blender)
- DAE/Collada
- FBX
- IFC-STEP
- ASE
- DXF
- HMP
- MD2
- MD3
- MD5
- MDC
- MDL
- NFF
- PLY
- STL
- X
- OBJ
- OpenGEX
- SMD
- LWO
- LXO
- LWS
- TER
- AC3D
- MS3D
- COB
- Q3BSP
- XGL
- CSM
- BVH
- B3D
- NDO
- Ogre Binary
- Ogre XML
- Q3D
- ASSBIN (Assimp custom format)
- glTF (partial)
- 3MF
Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
- C4D (https://github.com/acgessler/assimp-cinema4d)
__Exporters__:
- DAE (Collada)
- STL
- OBJ
- PLY
- X
- 3DS
- JSON (for WebGl, via https://github.com/acgessler/assimp2json)
- ASSBIN
- STEP
- glTF (partial)
### Building ###
Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.
### Ports ###
* [Android](port/AndroidJNI/README.md)
* [Python](port/PyAssimp/README.md)
* [.NET](port/AssimpNET/Readme.md)
* [Pascal](port/AssimpPascal/Readme.md)
#### Repository structure ####
Open Asset Import Library is implemented in C++. The directory structure is:
/code Source code
/contrib Third-party libraries
/doc Documentation (doxysource and pre-compiled docs)
/include Public header C and C++ header files
/scripts Scripts used to generate the loading code for some formats
/port Ports to other languages and scripts to maintain those.
/test Unit- and regression tests, test suite of models
/tools Tools (old assimp viewer, command line `assimp`)
/samples A small number of samples to illustrate possible
use cases for Assimp
/workspaces Build environments for vc,xcode,... (deprecated,
CMake has superseeded all legacy build options!)
### Where to get help ###
For more information, visit [our website](http://assimp.sourceforge.net/). Or check out the `./doc`- folder, which contains the official documentation in HTML format.
(CHMs for Windows are included in some release packages and should be located right here in the root folder).
If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
[(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions)
Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
And we also have an IRC-channel at freenode: #assetimporterlib . You can easily join us via: [KiwiIRC/freenote](https://kiwiirc.com/client/irc.freenode.net), choose your nickname and type
> /join #assetimporterlib
### Contributing ###
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
a pull request with your changes against the main repository's `master` branch.
### Donate ###
If you like assimp, consider buying us a beer (or two):
[Donate](http://sourceforge.net/donate/index.php?group_id=226462)
### License ###
Our license is based on the modified, __3-clause BSD__-License.
An _informal_ summary is: do whatever you want, but include Assimp's license text with your product -
and don't sue us if our code doesn't work. Note that, unlike LGPLed code, you may link statically to Assimp.
For the legal details, see the `LICENSE` file.
### Why this name ###
Sorry, we're germans :-), no english native speakers ...

View file

@ -0,0 +1,40 @@
# AppVeyor file
# http://www.appveyor.com/docs/appveyor-yml
# clone directory
clone_folder: c:\projects\assimp
# branches to build
branches:
# whitelist
only:
- master
platform:
- x86
- x64
configuration:
- 14 2015
- 12 2013
#- MinGW
#- 10 2010 # only works for x86
init:
- if "%platform%" EQU "x64" ( for %%a in (2008 2010 MinGW) do ( if "%Configuration%"=="%%a" (echo "Skipping unsupported configuration" && exit /b 1 ) ) )
install:
# Make compiler command line tools available
- call c:\projects\assimp\scripts\appveyor\compiler_setup.bat
build_script:
- cd c:\projects\assimp
- cmake CMakeLists.txt -G "Visual Studio %Configuration%"
- msbuild /m /p:Configuration=Release /p:Platform="Win32" Assimp.sln
after_build:
- 7z a assimp.7z c:\projects\assimp\bin\release\* c:\projects\assimp\lib\release\*
artifacts:
- path: assimp.7z
name: assimp_lib

View file

@ -0,0 +1,13 @@
set( PACKAGE_VERSION "@ASSIMP_VERSION@" )
if( "${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@ASSIMP_VERSION@")
set(PACKAGE_VERSION_EXACT 1)
endif()
if( "${PACKAGE_FIND_VERSION_MAJOR}.${PACKAGE_FIND_VERSION_MINOR}" EQUAL "@ASSIMP_SOVERSION@" )
set(PACKAGE_VERSION_COMPATIBLE 1)
elseif( "${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@ASSIMP_VERSION_MAJOR@" )
# for now backward compatible if minor version is less
if( ${PACKAGE_FIND_VERSION_MINOR} LESS @ASSIMP_VERSION_MINOR@ )
set(PACKAGE_VERSION_COMPATIBLE 1)
endif()
endif()
set( ASSIMP_STATIC_LIB "@ASSIMP_BUILD_STATIC_LIB@")

View file

@ -0,0 +1,81 @@
# - Find Assimp Installation
#
# Users can set the following variables before calling the module:
# ASSIMP_DIR - The preferred installation prefix for searching for ASSIMP. Set by the user.
#
# ASSIMP_ROOT_DIR - the root directory where the installation can be found
# ASSIMP_CXX_FLAGS - extra flags for compilation
# ASSIMP_LINK_FLAGS - extra flags for linking
# ASSIMP_INCLUDE_DIRS - include directories
# ASSIMP_LIBRARY_DIRS - link directories
# ASSIMP_LIBRARIES - libraries to link plugins with
# ASSIMP_Boost_VERSION - the boost version assimp was compiled with
get_filename_component(_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_PREFIX "${_PREFIX}" PATH)
get_filename_component(_PREFIX "${_PREFIX}" PATH)
get_filename_component(ASSIMP_ROOT_DIR "${_PREFIX}" PATH)
if( MSVC )
# in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix
if( MSVC70 OR MSVC71 )
set(MSVC_PREFIX "vc70")
elseif( MSVC80 )
set(MSVC_PREFIX "vc80")
elseif( MSVC90 )
set(MSVC_PREFIX "vc90")
elseif( MSVC10 )
set(MSVC_PREFIX "vc100")
elseif( MSVC11 )
set(MSVC_PREFIX "vc110")
elseif( MSVC12 )
set(MSVC_PREFIX "vc120")
elseif( MSVC14 )
set(MSVC_PREFIX "vc140")
else()
set(MSVC_PREFIX "vc150")
endif()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" FORCE)
else()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" FORCE)
endif()
set( ASSIMP_CXX_FLAGS ) # dynamically linked library
if( WIN32 )
# for visual studio linking, most of the time boost dlls will be used
set( ASSIMP_CXX_FLAGS " -DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB")
endif()
set( ASSIMP_LINK_FLAGS "" )
set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
set( ASSIMP_LIBRARIES assimp${ASSIMP_LIBRARY_SUFFIX})
set( ASSIMP_LIBRARIES ${ASSIMP_LIBRARIES}@CMAKE_DEBUG_POSTFIX@)
# search for the boost version assimp was compiled with
#set(Boost_USE_MULTITHREAD ON)
#set(Boost_USE_STATIC_LIBS OFF)
#set(Boost_USE_STATIC_RUNTIME OFF)
#find_package(Boost ${ASSIMP_Boost_VERSION} EXACT COMPONENTS thread date_time)
#if(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0")
# set( ASSIMP_INCLUDE_DIRS "${ASSIMP_INCLUDE_DIRS}" ${Boost_INCLUDE_DIRS})
#else(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0")
# message(WARNING "Failed to find Boost ${ASSIMP_Boost_VERSION} necessary for assimp")
#endif(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0")
# the boost version assimp was compiled with
set( ASSIMP_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@")
# for compatibility with pkg-config
set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
MARK_AS_ADVANCED(
ASSIMP_ROOT_DIR
ASSIMP_CXX_FLAGS
ASSIMP_LINK_FLAGS
ASSIMP_INCLUDE_DIRS
ASSIMP_LIBRARIES
ASSIMP_Boost_VERSION
ASSIMP_CFLAGS_OTHER
ASSIMP_LDFLAGS_OTHER
ASSIMP_LIBRARY_SUFFIX
)

View file

@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@/@ASSIMP_BIN_INSTALL_DIR@
libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@
includedir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_INCLUDE_INSTALL_DIR@/assimp
Name: @CMAKE_PROJECT_NAME@
Description: Import various well-known 3D model formats in an uniform manner.
Version: @PROJECT_VERSION@
Libs: -L${libdir} -lassimp@ASSIMP_LIBRARY_SUFFIX@
Libs.private: @LIBSTDC++_LIBRARIES@ @ZLIB_LIBRARIES_LINKED@
Cflags: -I${includedir}

View file

@ -0,0 +1,78 @@
find_package(Threads REQUIRED)
include(ExternalProject)
if(MSYS OR MINGW)
set(DISABLE_PTHREADS ON)
else()
set(DISABLE_PTHREADS OFF)
endif()
if (MSVC)
set(RELEASE_LIB_DIR ReleaseLibs)
set(DEBUG_LIB_DIR DebugLibs)
elseif(XCODE_VERSION)
set(RELEASE_LIB_DIR Release)
set(DEBUG_LIB_DIR Debug)
else()
set(RELEASE_LIB_DIR "")
set(DEBUG_LIB_DIR "")
endif()
set(GTEST_CMAKE_ARGS
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
"-Dgtest_force_shared_crt=ON"
"-Dgtest_disable_pthreads:BOOL=${DISABLE_PTHREADS}"
"-DBUILD_GTEST=ON")
set(GTEST_RELEASE_LIB_DIR "")
set(GTEST_DEBUGLIB_DIR "")
if (MSVC)
set(GTEST_CMAKE_ARGS ${GTEST_CMAKE_ARGS}
"-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=${DEBUG_LIB_DIR}"
"-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=${RELEASE_LIB_DIR}")
set(GTEST_LIB_DIR)
endif()
set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/gtest")
# try to find git - if found, setup gtest
find_package(Git)
if(NOT GIT_FOUND)
set(AddGTest_FOUND false CACHE BOOL "Was gtest setup correctly?")
else(NOT GIT_FOUND)
set(AddGTest_FOUND true CACHE BOOL "Was gtest setup correctly?")
ExternalProject_Add(gtest
GIT_REPOSITORY https://github.com/google/googletest.git
TIMEOUT 10
PREFIX "${GTEST_PREFIX}"
CMAKE_ARGS "${GTEST_CMAKE_ARGS}"
LOG_DOWNLOAD ON
LOG_CONFIGURE ON
LOG_BUILD ON
# Disable install
INSTALL_COMMAND ""
)
set(LIB_PREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}")
set(LIB_SUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(GTEST_LOCATION "${GTEST_PREFIX}/src/gtest-build")
set(GTEST_DEBUG_LIBRARIES
"${LIB_PREFIX}gtest${LIB_SUFFIX}"
"${CMAKE_THREAD_LIBS_INIT}")
SET(GTEST_RELEASE_LIBRARIES
"${LIB_PREFIX}gtest${LIB_SUFFIX}"
"${CMAKE_THREAD_LIBS_INIT}")
if(MSVC_VERSION EQUAL 1700)
add_definitions(-D_VARIADIC_MAX=10)
endif()
ExternalProject_Get_Property(gtest source_dir)
include_directories(${source_dir}/googletest/include)
include_directories(${source_dir}/gtest/include)
ExternalProject_Get_Property(gtest binary_dir)
link_directories(${binary_dir}/googlemock/gtest)
link_directories(${binary_dir}/googlemock/gtest/${RELEASE_LIB_DIR})
link_directories(${binary_dir}/googlemock/gtest/${DEBUG_LIB_DIR})
endif(NOT GIT_FOUND)

View file

@ -0,0 +1,347 @@
## Debian Source Package Generator
#
# Copyright (c) 2010 Daniel Pfeifer <daniel@pfeifer-mail.de>
# Many modifications by Rosen Diankov <rosen.diankov@gmail.com>
#
# Creates source debian files and manages library dependencies
#
# Features:
#
# - Automatically generates symbols and run-time dependencies from the build dependencies
# - Custom copy of source directory via CPACK_DEBIAN_PACKAGE_SOURCE_COPY
# - Simultaneous output of multiple debian source packages for each distribution
# - Can specificy distribution-specific dependencies by suffixing DEPENDS with _${DISTRO_NAME}, for example: CPACK_DEBIAN_PACKAGE_DEPENDS_LUCID, CPACK_COMPONENT_MYCOMP0_DEPENDS_LUCID
#
# Usage:
#
# set(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake)
# set(CPACK_DEBIAN_PACKAGE_PRIORITY optional)
# set(CPACK_DEBIAN_PACKAGE_SECTION devel)
# set(CPACK_DEBIAN_CMAKE_OPTIONS "-DMYOPTION=myvalue")
# set(CPACK_DEBIAN_PACKAGE_DEPENDS mycomp0 mycomp1 some_ubuntu_package)
# set(CPACK_DEBIAN_PACKAGE_DEPENDS_UBUNTU_LUCID mycomp0 mycomp1 lucid_specific_package)
# set(CPACK_DEBIAN_PACKAGE_NAME mypackage)
# set(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES unnecessary_file unnecessary_dir/file0)
# set(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force) # if using subversion
# set(CPACK_DEBIAN_DISTRIBUTION_NAME ubuntu)
# set(CPACK_DEBIAN_DISTRIBUTION_RELEASES karmic lucid maverick natty)
# set(CPACK_DEBIAN_CHANGELOG " * Extra change log lines")
# set(CPACK_DEBIAN_PACKAGE_SUGGESTS "ipython")
# set(CPACK_COMPONENT_X_RECOMMENDS "recommended-package")
##
find_program(DEBUILD_EXECUTABLE debuild)
find_program(DPUT_EXECUTABLE dput)
if(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE)
return()
endif(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE)
# DEBIAN/control
# debian policy enforce lower case for package name
# Package: (mandatory)
IF(NOT CPACK_DEBIAN_PACKAGE_NAME)
STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME)
ENDIF(NOT CPACK_DEBIAN_PACKAGE_NAME)
# Section: (recommended)
IF(NOT CPACK_DEBIAN_PACKAGE_SECTION)
SET(CPACK_DEBIAN_PACKAGE_SECTION "devel")
ENDIF(NOT CPACK_DEBIAN_PACKAGE_SECTION)
# Priority: (recommended)
IF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY)
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
ENDIF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY)
file(STRINGS ${CPACK_PACKAGE_DESCRIPTION_FILE} DESC_LINES)
foreach(LINE ${DESC_LINES})
set(DEB_LONG_DESCRIPTION "${DEB_LONG_DESCRIPTION} ${LINE}\n")
endforeach(LINE ${DESC_LINES})
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/Debian")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/Debian")
set(DEBIAN_SOURCE_ORIG_DIR "${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
if( CPACK_DEBIAN_PACKAGE_SOURCE_COPY )
execute_process(COMMAND ${CPACK_DEBIAN_PACKAGE_SOURCE_COPY} "${CMAKE_SOURCE_DIR}" "${DEBIAN_SOURCE_ORIG_DIR}.orig")
else()
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR} "${DEBIAN_SOURCE_ORIG_DIR}.orig")
execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${DEBIAN_SOURCE_ORIG_DIR}.orig/.git")
execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${DEBIAN_SOURCE_ORIG_DIR}.orig/.svn")
endif()
# remove unnecessary folders
foreach(REMOVE_DIR ${CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES})
file(REMOVE_RECURSE ${DEBIAN_SOURCE_ORIG_DIR}.orig/${REMOVE_DIR})
endforeach()
# create the original source tar
execute_process(COMMAND ${CMAKE_COMMAND} -E tar czf "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz" "${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.orig" WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian)
set(DEB_SOURCE_CHANGES)
foreach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES})
set(DEBIAN_SOURCE_DIR "${DEBIAN_SOURCE_ORIG_DIR}-${CPACK_DEBIAN_DISTRIBUTION_NAME}1~${RELEASE}1")
set(RELEASE_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}-${CPACK_DEBIAN_DISTRIBUTION_NAME}1~${RELEASE}1")
string(TOUPPER ${RELEASE} RELEASE_UPPER)
string(TOUPPER ${CPACK_DEBIAN_DISTRIBUTION_NAME} DISTRIBUTION_NAME_UPPER)
file(MAKE_DIRECTORY ${DEBIAN_SOURCE_DIR}/debian)
##############################################################################
# debian/control
set(DEBIAN_CONTROL ${DEBIAN_SOURCE_DIR}/debian/control)
file(WRITE ${DEBIAN_CONTROL}
"Source: ${CPACK_DEBIAN_PACKAGE_NAME}\n"
"Section: ${CPACK_DEBIAN_PACKAGE_SECTION}\n"
"Priority: ${CPACK_DEBIAN_PACKAGE_PRIORITY}\n"
"DM-Upload-Allowed: yes\n"
"Maintainer: ${CPACK_PACKAGE_CONTACT}\n"
"Build-Depends: "
)
if( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
else( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
if( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}})
else( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS})
endif( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} )
endif( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
file(APPEND ${DEBIAN_CONTROL} "\n"
"Standards-Version: 3.8.4\n"
"Homepage: ${CPACK_PACKAGE_VENDOR}\n"
"\n"
"Package: ${CPACK_DEBIAN_PACKAGE_NAME}\n"
"Architecture: any\n"
"Depends: "
)
if( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
else( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
if( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}})
else( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS})
endif( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} )
endif( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
file(APPEND ${DEBIAN_CONTROL} "\nRecommends: ")
if( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
else( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
if( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}})
else( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS})
endif( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} )
endif( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
file(APPEND ${DEBIAN_CONTROL} "\nSuggests: ")
if( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
else( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
if( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}})
else( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS})
file(APPEND ${DEBIAN_CONTROL} "${DEP}, ")
endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS})
endif( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} )
endif( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
file(APPEND ${DEBIAN_CONTROL} "\n"
"Description: ${CPACK_PACKAGE_DISPLAY_NAME} ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n"
"${DEB_LONG_DESCRIPTION}"
)
foreach(COMPONENT ${CPACK_COMPONENTS_ALL})
string(TOUPPER ${COMPONENT} UPPER_COMPONENT)
set(DEPENDS "\${shlibs:Depends}")
if( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
set(DEPENDS "${DEPENDS}, ${DEP}")
endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
else( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
if( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}})
set(DEPENDS "${DEPENDS}, ${DEP}")
endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}})
else( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS})
set(DEPENDS "${DEPENDS}, ${DEP}")
endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS})
endif( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} )
endif( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
set(RECOMMENDS)
if( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
set(RECOMMENDS "${RECOMMENDS} ${DEP}, ")
endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
else( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
if( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}})
set(RECOMMENDS "${RECOMMENDS} ${DEP}, ")
endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}})
else( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS})
set(RECOMMENDS "${RECOMMENDS} ${DEP}, ")
endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS})
endif( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} )
endif( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
set(SUGGESTS)
if( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
set(SUGGESTS "${SUGGESTS} ${DEP}, ")
endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}})
else( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
if( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}})
set(SUGGESTS "${SUGGESTS} ${DEP}, ")
endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}})
else( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} )
foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS})
set(SUGGESTS "${SUGGESTS} ${DEP}, ")
endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS})
endif( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} )
endif( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} )
file(APPEND ${DEBIAN_CONTROL} "\n"
"Package: ${COMPONENT}\n"
"Architecture: any\n"
"Depends: ${DEPENDS}\n"
"Recommends: ${RECOMMENDS}\n"
"Suggests: ${SUGGESTS}\n"
"Description: ${CPACK_PACKAGE_DISPLAY_NAME} ${CPACK_COMPONENT_${UPPER_COMPONENT}_DISPLAY_NAME}\n"
"${DEB_LONG_DESCRIPTION}"
" .\n"
" ${CPACK_COMPONENT_${UPPER_COMPONENT}_DESCRIPTION}\n"
)
endforeach(COMPONENT ${CPACK_COMPONENTS_ALL})
##############################################################################
# debian/copyright
set(DEBIAN_COPYRIGHT ${DEBIAN_SOURCE_DIR}/debian/copyright)
execute_process(COMMAND ${CMAKE_COMMAND} -E
copy ${CPACK_RESOURCE_FILE_LICENSE} ${DEBIAN_COPYRIGHT}
)
##############################################################################
# debian/rules
set(DEBIAN_RULES ${DEBIAN_SOURCE_DIR}/debian/rules)
file(WRITE ${DEBIAN_RULES}
"#!/usr/bin/make -f\n"
"\n"
"BUILDDIR = build_dir\n"
"\n"
"build:\n"
" mkdir $(BUILDDIR)\n"
" cd $(BUILDDIR); cmake -DCMAKE_BUILD_TYPE=Release ${CPACK_DEBIAN_CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=/usr ..\n"
" $(MAKE) -C $(BUILDDIR) preinstall\n"
" touch build\n"
"\n"
"binary: binary-indep binary-arch\n"
"\n"
"binary-indep: build\n"
"\n"
"binary-arch: build\n"
" cd $(BUILDDIR); cmake -DCOMPONENT=Unspecified -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr -P cmake_install.cmake\n"
" mkdir -p debian/tmp/DEBIAN\n"
" dpkg-gensymbols -p${CPACK_DEBIAN_PACKAGE_NAME}\n"
)
foreach(COMPONENT ${CPACK_COMPONENTS_ALL})
set(PATH debian/${COMPONENT})
file(APPEND ${DEBIAN_RULES}
" cd $(BUILDDIR); cmake -DCOMPONENT=${COMPONENT} -DCMAKE_INSTALL_PREFIX=../${PATH}/usr -P cmake_install.cmake\n"
" mkdir -p ${PATH}/DEBIAN\n"
" dpkg-gensymbols -p${COMPONENT} -P${PATH}\n"
)
endforeach(COMPONENT ${CPACK_COMPONENTS_ALL})
file(APPEND ${DEBIAN_RULES}
" dh_shlibdeps\n"
" dh_strip\n" # for reducing size
" dpkg-gencontrol -p${CPACK_DEBIAN_PACKAGE_NAME}\n"
" dpkg --build debian/tmp ..\n"
)
foreach(COMPONENT ${CPACK_COMPONENTS_ALL})
set(PATH debian/${COMPONENT})
file(APPEND ${DEBIAN_RULES}
" dpkg-gencontrol -p${COMPONENT} -P${PATH} -Tdebian/${COMPONENT}.substvars\n"
" dpkg --build ${PATH} ..\n"
)
endforeach(COMPONENT ${CPACK_COMPONENTS_ALL})
file(APPEND ${DEBIAN_RULES}
"\n"
"clean:\n"
" rm -f build\n"
" rm -rf $(BUILDDIR)\n"
"\n"
".PHONY: binary binary-arch binary-indep clean\n"
)
execute_process(COMMAND chmod +x ${DEBIAN_RULES})
##############################################################################
# debian/compat
file(WRITE ${DEBIAN_SOURCE_DIR}/debian/compat "7")
##############################################################################
# debian/source/format
file(WRITE ${DEBIAN_SOURCE_DIR}/debian/source/format "3.0 (quilt)")
##############################################################################
# debian/changelog
set(DEBIAN_CHANGELOG ${DEBIAN_SOURCE_DIR}/debian/changelog)
execute_process(COMMAND date -R OUTPUT_VARIABLE DATE_TIME)
file(WRITE ${DEBIAN_CHANGELOG}
"${CPACK_DEBIAN_PACKAGE_NAME} (${RELEASE_PACKAGE_VERSION}) ${RELEASE}; urgency=medium\n\n"
" * Package built with CMake\n\n"
"${CPACK_DEBIAN_CHANGELOG}"
" -- ${CPACK_PACKAGE_CONTACT} ${DATE_TIME}"
)
##############################################################################
# debuild -S
if( DEB_SOURCE_CHANGES )
set(DEBUILD_OPTIONS "-sd")
else()
set(DEBUILD_OPTIONS "-sa")
endif()
set(SOURCE_CHANGES_FILE "${CPACK_DEBIAN_PACKAGE_NAME}_${RELEASE_PACKAGE_VERSION}_source.changes")
set(DEB_SOURCE_CHANGES ${DEB_SOURCE_CHANGES} "${SOURCE_CHANGES_FILE}")
add_custom_command(OUTPUT "${SOURCE_CHANGES_FILE}" COMMAND ${DEBUILD_EXECUTABLE} -S ${DEBUILD_OPTIONS} WORKING_DIRECTORY ${DEBIAN_SOURCE_DIR})
endforeach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES})
##############################################################################
# dput ppa:your-lp-id/ppa <source.changes>
add_custom_target(dput ${DPUT_EXECUTABLE} ${DPUT_HOST} ${DEB_SOURCE_CHANGES} DEPENDS ${DEB_SOURCE_CHANGES} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian)

View file

@ -0,0 +1,101 @@
#-------------------------------------------------------------------
# This file is part of the CMake build system for OGRE
# (Object-oriented Graphics Rendering Engine)
# For the latest info, see http://www.ogre3d.org/
#
# The contents of this file are placed in the public domain. Feel
# free to make use of it in any way you like.
#-------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Find DirectX SDK
# Define:
# DirectX_FOUND
# DirectX_INCLUDE_DIR
# DirectX_LIBRARY
# DirectX_ROOT_DIR
if(WIN32) # The only platform it makes sense to check for DirectX SDK
include(FindPkgMacros)
findpkg_begin(DirectX)
# Get path, convert backslashes as ${ENV_DXSDK_DIR}
getenv_path(DXSDK_DIR)
getenv_path(DIRECTX_HOME)
getenv_path(DIRECTX_ROOT)
getenv_path(DIRECTX_BASE)
# construct search paths
set(DirectX_PREFIX_PATH
"${DXSDK_DIR}" "${ENV_DXSDK_DIR}"
"${DIRECTX_HOME}" "${ENV_DIRECTX_HOME}"
"${DIRECTX_ROOT}" "${ENV_DIRECTX_ROOT}"
"${DIRECTX_BASE}" "${ENV_DIRECTX_BASE}"
"C:/apps_x86/Microsoft DirectX SDK*"
"C:/Program Files (x86)/Microsoft DirectX SDK*"
"C:/apps/Microsoft DirectX SDK*"
"C:/Program Files/Microsoft DirectX SDK*"
"C:/Program Files (x86)/Windows Kits/8.1"
"$ENV{ProgramFiles}/Microsoft DirectX SDK*"
)
create_search_paths(DirectX)
# redo search if prefix path changed
clear_if_changed(DirectX_PREFIX_PATH
DirectX_LIBRARY
DirectX_INCLUDE_DIR
)
find_path(DirectX_INCLUDE_DIR NAMES d3d9.h HINTS ${DirectX_INC_SEARCH_PATH})
# dlls are in DirectX_ROOT_DIR/Developer Runtime/x64|x86
# lib files are in DirectX_ROOT_DIR/Lib/x64|x86
if(CMAKE_CL_64)
set(DirectX_LIBPATH_SUFFIX "x64")
else(CMAKE_CL_64)
set(DirectX_LIBPATH_SUFFIX "x86")
endif(CMAKE_CL_64)
find_library(DirectX_LIBRARY NAMES d3d9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
find_library(DirectX_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
find_library(DirectX_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
find_library(DirectX_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
# look for dxgi (needed by both 10 and 11)
find_library(DirectX_DXGI_LIBRARY NAMES dxgi HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
# look for d3dcompiler (needed by 11)
find_library(DirectX_D3DCOMPILER_LIBRARY NAMES d3dcompiler HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
findpkg_finish(DirectX)
set(DirectX_LIBRARIES ${DirectX_LIBRARIES}
${DirectX_D3DX9_LIBRARY}
${DirectX_DXERR_LIBRARY}
${DirectX_DXGUID_LIBRARY}
)
mark_as_advanced(DirectX_D3DX9_LIBRARY DirectX_DXERR_LIBRARY DirectX_DXGUID_LIBRARY
DirectX_DXGI_LIBRARY DirectX_D3DCOMPILER_LIBRARY)
# look for D3D11 components
if (DirectX_FOUND)
find_path(DirectX_D3D11_INCLUDE_DIR NAMES D3D11Shader.h HINTS ${DirectX_INC_SEARCH_PATH})
get_filename_component(DirectX_LIBRARY_DIR "${DirectX_LIBRARY}" PATH)
message(STATUS "DX lib dir: ${DirectX_LIBRARY_DIR}")
find_library(DirectX_D3D11_LIBRARY NAMES d3d11 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
find_library(DirectX_D3DX11_LIBRARY NAMES d3dx11 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
if (DirectX_D3D11_INCLUDE_DIR AND DirectX_D3D11_LIBRARY)
set(DirectX_D3D11_FOUND TRUE)
set(DirectX_D3D11_INCLUDE_DIR ${DirectX_D3D11_INCLUDE_DIR})
set(DirectX_D3D11_LIBRARIES ${DirectX_D3D11_LIBRARIES}
${DirectX_D3D11_LIBRARY}
${DirectX_D3DX11_LIBRARY}
${DirectX_DXGI_LIBRARY}
${DirectX_DXERR_LIBRARY}
${DirectX_DXGUID_LIBRARY}
${DirectX_D3DCOMPILER_LIBRARY}
)
endif ()
mark_as_advanced(DirectX_D3D11_INCLUDE_DIR DirectX_D3D11_LIBRARY DirectX_D3DX11_LIBRARY)
endif ()
endif(WIN32)

View file

@ -0,0 +1,143 @@
#-------------------------------------------------------------------
# This file is part of the CMake build system for OGRE
# (Object-oriented Graphics Rendering Engine)
# For the latest info, see http://www.ogre3d.org/
#
# The contents of this file are placed in the public domain. Feel
# free to make use of it in any way you like.
#-------------------------------------------------------------------
##################################################################
# Provides some common functionality for the FindPackage modules
##################################################################
# Begin processing of package
macro(findpkg_begin PREFIX)
if (NOT ${PREFIX}_FIND_QUIETLY)
message(STATUS "Looking for ${PREFIX}...")
endif ()
endmacro(findpkg_begin)
# Display a status message unless FIND_QUIETLY is set
macro(pkg_message PREFIX)
if (NOT ${PREFIX}_FIND_QUIETLY)
message(STATUS ${ARGN})
endif ()
endmacro(pkg_message)
# Get environment variable, define it as ENV_$var and make sure backslashes are converted to forward slashes
macro(getenv_path VAR)
set(ENV_${VAR} $ENV{${VAR}})
# replace won't work if var is blank
if (ENV_${VAR})
string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} )
endif ()
endmacro(getenv_path)
# Construct search paths for includes and libraries from a PREFIX_PATH
macro(create_search_paths PREFIX)
foreach(dir ${${PREFIX}_PREFIX_PATH})
set(${PREFIX}_INC_SEARCH_PATH ${${PREFIX}_INC_SEARCH_PATH}
${dir}/include ${dir}/include/${PREFIX} ${dir}/Headers)
set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH}
${dir}/lib ${dir}/lib/${PREFIX} ${dir}/Libs)
endforeach(dir)
set(${PREFIX}_FRAMEWORK_SEARCH_PATH ${${PREFIX}_PREFIX_PATH})
endmacro(create_search_paths)
# clear cache variables if a certain variable changed
macro(clear_if_changed TESTVAR)
# test against internal check variable
if (NOT "${${TESTVAR}}" STREQUAL "${${TESTVAR}_INT_CHECK}")
message(STATUS "${TESTVAR} changed.")
foreach(var ${ARGN})
set(${var} "NOTFOUND" CACHE STRING "x" FORCE)
endforeach(var)
endif ()
set(${TESTVAR}_INT_CHECK ${${TESTVAR}} CACHE INTERNAL "x" FORCE)
endmacro(clear_if_changed)
# Try to get some hints from pkg-config, if available
macro(use_pkgconfig PREFIX PKGNAME)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(${PREFIX} ${PKGNAME})
endif ()
endmacro (use_pkgconfig)
# Couple a set of release AND debug libraries (or frameworks)
macro(make_library_set PREFIX)
if (${PREFIX}_FWK)
set(${PREFIX} ${${PREFIX}_FWK})
elseif (${PREFIX}_REL AND ${PREFIX}_DBG)
set(${PREFIX} optimized ${${PREFIX}_REL} debug ${${PREFIX}_DBG})
elseif (${PREFIX}_REL)
set(${PREFIX} ${${PREFIX}_REL})
elseif (${PREFIX}_DBG)
set(${PREFIX} ${${PREFIX}_DBG})
endif ()
endmacro(make_library_set)
# Generate debug names from given release names
macro(get_debug_names PREFIX)
foreach(i ${${PREFIX}})
set(${PREFIX}_DBG ${${PREFIX}_DBG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i})
endforeach(i)
endmacro(get_debug_names)
# Add the parent dir from DIR to VAR
macro(add_parent_dir VAR DIR)
get_filename_component(${DIR}_TEMP "${${DIR}}/.." ABSOLUTE)
set(${VAR} ${${VAR}} ${${DIR}_TEMP})
endmacro(add_parent_dir)
# Do the final processing for the package find.
macro(findpkg_finish PREFIX)
# skip if already processed during this run
if (NOT ${PREFIX}_FOUND)
if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY)
set(${PREFIX}_FOUND TRUE)
set(${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR})
set(${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY})
if (NOT ${PREFIX}_FIND_QUIETLY)
message(STATUS "Found ${PREFIX}: ${${PREFIX}_LIBRARIES}")
endif ()
else ()
if (NOT ${PREFIX}_FIND_QUIETLY)
message(STATUS "Could not locate ${PREFIX}")
endif ()
if (${PREFIX}_FIND_REQUIRED)
message(FATAL_ERROR "Required library ${PREFIX} not found! Install the library (including dev packages) and try again. If the library is already installed, set the missing variables manually in cmake.")
endif ()
endif ()
mark_as_advanced(${PREFIX}_INCLUDE_DIR ${PREFIX}_LIBRARY ${PREFIX}_LIBRARY_REL ${PREFIX}_LIBRARY_DBG ${PREFIX}_LIBRARY_FWK)
endif ()
endmacro(findpkg_finish)
# Slightly customised framework finder
MACRO(findpkg_framework fwk)
IF(APPLE)
SET(${fwk}_FRAMEWORK_PATH
${${fwk}_FRAMEWORK_SEARCH_PATH}
${CMAKE_FRAMEWORK_PATH}
~/Library/Frameworks
/Library/Frameworks
/System/Library/Frameworks
/Network/Library/Frameworks
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/Frameworks/
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/Frameworks/
)
FOREACH(dir ${${fwk}_FRAMEWORK_PATH})
SET(fwkpath ${dir}/${fwk}.framework)
IF(EXISTS ${fwkpath})
SET(${fwk}_FRAMEWORK_INCLUDES ${${fwk}_FRAMEWORK_INCLUDES}
${fwkpath}/Headers ${fwkpath}/PrivateHeaders)
if (NOT ${fwk}_LIBRARY_FWK)
SET(${fwk}_LIBRARY_FWK "-framework ${fwk}")
endif ()
ENDIF(EXISTS ${fwkpath})
ENDFOREACH(dir)
ENDIF(APPLE)
ENDMACRO(findpkg_framework)

View file

@ -0,0 +1,48 @@
#-------------------------------------------------------------------
# This file is part of the CMake build system for OGRE
# (Object-oriented Graphics Rendering Engine)
# For the latest info, see http://www.ogre3d.org/
#
# The contents of this file are placed in the public domain. Feel
# free to make use of it in any way you like.
#-------------------------------------------------------------------
# - Try to find ZLIB
# Once done, this will define
#
# ZLIB_FOUND - system has ZLIB
# ZLIB_INCLUDE_DIRS - the ZLIB include directories
# ZLIB_LIBRARIES - link these to use ZLIB
include(FindPkgMacros)
findpkg_begin(ZLIB)
# Get path, convert backslashes as ${ENV_${var}}
getenv_path(ZLIB_HOME)
# construct search paths
set(ZLIB_PREFIX_PATH ${ZLIB_HOME} ${ENV_ZLIB_HOME})
create_search_paths(ZLIB)
# redo search if prefix path changed
clear_if_changed(ZLIB_PREFIX_PATH
ZLIB_LIBRARY_FWK
ZLIB_LIBRARY_REL
ZLIB_LIBRARY_DBG
ZLIB_INCLUDE_DIR
)
set(ZLIB_LIBRARY_NAMES z zlib zdll)
get_debug_names(ZLIB_LIBRARY_NAMES)
use_pkgconfig(ZLIB_PKGC zzip-zlib-config)
findpkg_framework(ZLIB)
find_path(ZLIB_INCLUDE_DIR NAMES zlib.h HINTS ${ZLIB_INC_SEARCH_PATH} ${ZLIB_PKGC_INCLUDE_DIRS})
find_library(ZLIB_LIBRARY_REL NAMES ${ZLIB_LIBRARY_NAMES} HINTS ${ZLIB_LIB_SEARCH_PATH} ${ZLIB_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel)
find_library(ZLIB_LIBRARY_DBG NAMES ${ZLIB_LIBRARY_NAMES_DBG} HINTS ${ZLIB_LIB_SEARCH_PATH} ${ZLIB_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug)
make_library_set(ZLIB_LIBRARY)
findpkg_finish(ZLIB)

View file

@ -0,0 +1,81 @@
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(ASSIMP_ARCHITECTURE "64")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(ASSIMP_ARCHITECTURE "32")
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
if(WIN32)
set(ASSIMP_ROOT_DIR CACHE PATH "ASSIMP root directory")
# Find path of each library
find_path(ASSIMP_INCLUDE_DIR
NAMES
assimp/anim.h
HINTS
${ASSIMP_ROOT_DIR}/include
)
if(MSVC12)
set(ASSIMP_MSVC_VERSION "vc120")
elseif(MSVC14)
set(ASSIMP_MSVC_VERSION "vc140")
endif(MSVC12)
if(MSVC12 OR MSVC14)
find_path(ASSIMP_LIBRARY_DIR
NAMES
assimp-${ASSIMP_MSVC_VERSION}-mt.lib
HINTS
${ASSIMP_ROOT_DIR}/lib${ASSIMP_ARCHITECTURE}
)
find_library(ASSIMP_LIBRARY_RELEASE assimp-${ASSIMP_MSVC_VERSION}-mt.lib PATHS ${ASSIMP_LIBRARY_DIR})
find_library(ASSIMP_LIBRARY_DEBUG assimp-${ASSIMP_MSVC_VERSION}-mtd.lib PATHS ${ASSIMP_LIBRARY_DIR})
set(ASSIMP_LIBRARY
optimized ${ASSIMP_LIBRARY_RELEASE}
debug ${ASSIMP_LIBRARY_DEBUG}
)
set(ASSIMP_LIBRARIES "ASSIMP_LIBRARY_RELEASE" "ASSIMP_LIBRARY_DEBUG")
FUNCTION(ASSIMP_COPY_BINARIES TargetDirectory)
ADD_CUSTOM_TARGET(AssimpCopyBinaries
COMMAND ${CMAKE_COMMAND} -E copy ${ASSIMP_ROOT_DIR}/bin${ASSIMP_ARCHITECTURE}/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll ${TargetDirectory}/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll
COMMAND ${CMAKE_COMMAND} -E copy ${ASSIMP_ROOT_DIR}/bin${ASSIMP_ARCHITECTURE}/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${TargetDirectory}/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll
COMMENT "Copying Assimp binaries to '${TargetDirectory}'"
VERBATIM)
ENDFUNCTION(ASSIMP_COPY_BINARIES)
endif()
else(WIN32)
find_path(
assimp_INCLUDE_DIRS
NAMES postprocess.h scene.h version.h config.h cimport.h
PATHS /usr/local/include/
)
find_library(
assimp_LIBRARIES
NAMES assimp
PATHS /usr/local/lib/
)
if (assimp_INCLUDE_DIRS AND assimp_LIBRARIES)
SET(assimp_FOUND TRUE)
ENDIF (assimp_INCLUDE_DIRS AND assimp_LIBRARIES)
if (assimp_FOUND)
if (NOT assimp_FIND_QUIETLY)
message(STATUS "Found asset importer library: ${assimp_LIBRARIES}")
endif (NOT assimp_FIND_QUIETLY)
else (assimp_FOUND)
if (assimp_FIND_REQUIRED)
message(FATAL_ERROR "Could not find asset importer library")
endif (assimp_FIND_REQUIRED)
endif (assimp_FOUND)
endif(WIN32)

View file

@ -0,0 +1,16 @@
# this one sets internal to crosscompile (in theory)
SET(CMAKE_SYSTEM_NAME Windows)
# the minimalistic settings
SET(CMAKE_C_COMPILER "/usr/bin/x86_64-w64-mingw32-gcc")
SET(CMAKE_CXX_COMPILER "/usr/bin/x86_64-w64-mingw32-g++")
SET(CMAKE_RC_COMPILER "/usr/bin/x86_64-w64-mingw32-windres")
# where is the target (so called staging) environment
SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
# search for programs in the build host directories (default BOTH)
#SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

View file

@ -0,0 +1,25 @@
MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
IF(MSVC)
GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
SET(PrecompiledBinary "${CMAKE_CFG_INTDIR}/${PrecompiledBasename}.pch")
SET(Sources ${${SourcesVar}})
SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
OBJECT_OUTPUTS "${PrecompiledBinary}")
# Do not consider .c files
foreach(fname ${Sources})
GET_FILENAME_COMPONENT(fext ${fname} EXT)
if(fext STREQUAL ".cpp")
SET_SOURCE_FILES_PROPERTIES(${fname}
PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledBinary}\" /FI\"${PrecompiledBinary}\" /Fp\"${PrecompiledBinary}\""
OBJECT_DEPENDS "${PrecompiledBinary}")
endif(fext STREQUAL ".cpp")
endforeach(fname)
ENDIF(MSVC)
# Add precompiled header to SourcesVar
LIST(APPEND ${SourcesVar} ${PrecompiledSource})
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)

View file

@ -0,0 +1,17 @@
IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
STRING(REGEX REPLACE "\n" ";" files "${files}")
FOREACH(file ${files})
MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
EXEC_PROGRAM(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
IF(NOT "${rm_retval}" STREQUAL 0)
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
ENDIF(NOT "${rm_retval}" STREQUAL 0)
ENDFOREACH(file)

View file

@ -0,0 +1,8 @@
# See <http://EditorConfig.org> for details
[*.{h,hpp,c,cpp}]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_size = 4
indent_style = space

View file

@ -0,0 +1,867 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file Implementation of the 3ds importer class */
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
// internal headers
#include "3DSLoader.h"
#include "TargetAnimation.h"
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include "StringComparison.h"
#include <memory>
#include <cctype>
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Setup final material indices, generae a default material if necessary
void Discreet3DSImporter::ReplaceDefaultMaterial()
{
// Try to find an existing material that matches the
// typical default material setting:
// - no textures
// - diffuse color (in grey!)
// NOTE: This is here to workaround the fact that some
// exporters are writing a default material, too.
unsigned int idx = 0xcdcdcdcd;
for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
{
std::string s = mScene->mMaterials[i].mName;
for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) {
*it = static_cast< char >( ::tolower( *it ) );
}
if (std::string::npos == s.find("default"))continue;
if (mScene->mMaterials[i].mDiffuse.r !=
mScene->mMaterials[i].mDiffuse.g ||
mScene->mMaterials[i].mDiffuse.r !=
mScene->mMaterials[i].mDiffuse.b)continue;
if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexBump.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
{
continue;
}
idx = i;
}
if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size();
// now iterate through all meshes and through all faces and
// find all faces that are using the default material
unsigned int cnt = 0;
for (std::vector<D3DS::Mesh>::iterator
i = mScene->mMeshes.begin();
i != mScene->mMeshes.end();++i)
{
for (std::vector<unsigned int>::iterator
a = (*i).mFaceMaterials.begin();
a != (*i).mFaceMaterials.end();++a)
{
// NOTE: The additional check seems to be necessary,
// some exporters seem to generate invalid data here
if (0xcdcdcdcd == (*a))
{
(*a) = idx;
++cnt;
}
else if ( (*a) >= mScene->mMaterials.size())
{
(*a) = idx;
DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
++cnt;
}
}
}
if (cnt && idx == mScene->mMaterials.size())
{
// We need to create our own default material
D3DS::Material sMat;
sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
sMat.mName = "%%%DEFAULT";
mScene->mMaterials.push_back(sMat);
DefaultLogger::get()->info("3DS: Generating default material");
}
}
// ------------------------------------------------------------------------------------------------
// Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
{
for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
{
// check whether all indices are in range
for (unsigned int a = 0; a < 3;++a)
{
if ((*i).mIndices[a] >= sMesh.mPositions.size())
{
DefaultLogger::get()->warn("3DS: Vertex index overflow)");
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
}
if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
{
DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)");
(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
}
}
}
}
// ------------------------------------------------------------------------------------------------
// Generate out unique verbose format representation
void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
{
// TODO: really necessary? I don't think. Just a waste of memory and time
// to do it now in a separate buffer.
// Allocate output storage
std::vector<aiVector3D> vNew (sMesh.mFaces.size() * 3);
std::vector<aiVector3D> vNew2;
if (sMesh.mTexCoords.size())
vNew2.resize(sMesh.mFaces.size() * 3);
for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
{
D3DS::Face& face = sMesh.mFaces[i];
// Positions
for (unsigned int a = 0; a < 3;++a,++base)
{
vNew[base] = sMesh.mPositions[face.mIndices[a]];
if (sMesh.mTexCoords.size())
vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
face.mIndices[a] = base;
}
}
sMesh.mPositions = vNew;
sMesh.mTexCoords = vNew2;
}
// ------------------------------------------------------------------------------------------------
// Convert a 3DS texture to texture keys in an aiMaterial
void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
{
// Setup the texture name
aiString tex;
tex.Set( texture.mMapName);
mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
// Setup the texture blend factor
if (is_not_qnan(texture.mTextureBlend))
mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
// Setup the texture mapping mode
mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
// Mirroring - double the scaling values
// FIXME: this is not really correct ...
if (texture.mMapMode == aiTextureMapMode_Mirror)
{
texture.mScaleU *= 2.f;
texture.mScaleV *= 2.f;
texture.mOffsetU /= 2.f;
texture.mOffsetV /= 2.f;
}
// Setup texture UV transformations
mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
}
// ------------------------------------------------------------------------------------------------
// Convert a 3DS material to an aiMaterial
void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
aiMaterial& mat)
{
// NOTE: Pass the background image to the viewer by bypassing the
// material system. This is an evil hack, never do it again!
if (0 != mBackgroundImage.length() && bHasBG)
{
aiString tex;
tex.Set( mBackgroundImage);
mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
// Be sure this is only done for the first material
mBackgroundImage = std::string("");
}
// At first add the base ambient color of the scene to the material
oldMat.mAmbient.r += mClrAmbient.r;
oldMat.mAmbient.g += mClrAmbient.g;
oldMat.mAmbient.b += mClrAmbient.b;
aiString name;
name.Set( oldMat.mName);
mat.AddProperty( &name, AI_MATKEY_NAME);
// Material colors
mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
// Phong shininess and shininess strength
if (D3DS::Discreet3DS::Phong == oldMat.mShading ||
D3DS::Discreet3DS::Metal == oldMat.mShading)
{
if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
{
oldMat.mShading = D3DS::Discreet3DS::Gouraud;
}
else
{
mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
}
}
// Opacity
mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
// Bump height scaling
mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
// Two sided rendering?
if (oldMat.mTwoSided)
{
int i = 1;
mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
}
// Shading mode
aiShadingMode eShading = aiShadingMode_NoShading;
switch (oldMat.mShading)
{
case D3DS::Discreet3DS::Flat:
eShading = aiShadingMode_Flat; break;
// I don't know what "Wire" shading should be,
// assume it is simple lambertian diffuse shading
case D3DS::Discreet3DS::Wire:
{
// Set the wireframe flag
unsigned int iWire = 1;
mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
}
case D3DS::Discreet3DS::Gouraud:
eShading = aiShadingMode_Gouraud; break;
// assume cook-torrance shading for metals.
case D3DS::Discreet3DS::Phong :
eShading = aiShadingMode_Phong; break;
case D3DS::Discreet3DS::Metal :
eShading = aiShadingMode_CookTorrance; break;
// FIX to workaround a warning with GCC 4 who complained
// about a missing case Blinn: here - Blinn isn't a valid
// value in the 3DS Loader, it is just needed for ASE
case D3DS::Discreet3DS::Blinn :
eShading = aiShadingMode_Blinn; break;
}
mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
// DIFFUSE texture
if( oldMat.sTexDiffuse.mMapName.length() > 0)
CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
// SPECULAR texture
if( oldMat.sTexSpecular.mMapName.length() > 0)
CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
// OPACITY texture
if( oldMat.sTexOpacity.mMapName.length() > 0)
CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
// EMISSIVE texture
if( oldMat.sTexEmissive.mMapName.length() > 0)
CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
// BUMP texture
if( oldMat.sTexBump.mMapName.length() > 0)
CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
// SHININESS texture
if( oldMat.sTexShininess.mMapName.length() > 0)
CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
// REFLECTION texture
if( oldMat.sTexReflective.mMapName.length() > 0)
CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION);
// Store the name of the material itself, too
if( oldMat.mName.length()) {
aiString tex;
tex.Set( oldMat.mName);
mat.AddProperty( &tex, AI_MATKEY_NAME);
}
}
// ------------------------------------------------------------------------------------------------
// Split meshes by their materials and generate output aiMesh'es
void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
{
std::vector<aiMesh*> avOutMeshes;
avOutMeshes.reserve(mScene->mMeshes.size() * 2);
unsigned int iFaceCnt = 0,num = 0;
aiString name;
// we need to split all meshes by their materials
for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) {
std::unique_ptr< std::vector<unsigned int>[] > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
name.length = ASSIMP_itoa10(name.data,num++);
unsigned int iNum = 0;
for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin();
a != (*i).mFaceMaterials.end();++a,++iNum)
{
aiSplit[*a].push_back(iNum);
}
// now generate submeshes
for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
{
if (aiSplit[p].empty()) {
continue;
}
aiMesh* meshOut = new aiMesh();
meshOut->mName = name;
meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
// be sure to setup the correct material index
meshOut->mMaterialIndex = p;
// use the color data as temporary storage
meshOut->mColors[0] = (aiColor4D*)(&*i);
avOutMeshes.push_back(meshOut);
// convert vertices
meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
meshOut->mNumVertices = meshOut->mNumFaces*3;
// allocate enough storage for faces
meshOut->mFaces = new aiFace[meshOut->mNumFaces];
iFaceCnt += meshOut->mNumFaces;
meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
meshOut->mNormals = new aiVector3D[meshOut->mNumVertices];
if ((*i).mTexCoords.size())
{
meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
}
for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
{
unsigned int index = aiSplit[p][q];
aiFace& face = meshOut->mFaces[q];
face.mIndices = new unsigned int[3];
face.mNumIndices = 3;
for (unsigned int a = 0; a < 3;++a,++base)
{
unsigned int idx = (*i).mFaces[index].mIndices[a];
meshOut->mVertices[base] = (*i).mPositions[idx];
meshOut->mNormals [base] = (*i).mNormals[idx];
if ((*i).mTexCoords.size())
meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
face.mIndices[a] = base;
}
}
}
}
// Copy them to the output array
pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) {
pcOut->mMeshes[a] = avOutMeshes[a];
}
// We should have at least one face here
if (!iFaceCnt) {
throw DeadlyImportError("No faces loaded. The mesh is empty");
}
}
// ------------------------------------------------------------------------------------------------
// Add a node to the scenegraph and setup its final transformation
void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
{
std::vector<unsigned int> iArray;
iArray.reserve(3);
aiMatrix4x4 abs;
// Find all meshes with the same name as the node
for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
{
const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
ai_assert(NULL != pcMesh);
if (pcIn->mName == pcMesh->mName)
iArray.push_back(a);
}
if (!iArray.empty())
{
// The matrix should be identical for all meshes with the
// same name. It HAS to be identical for all meshes .....
D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]);
// Compute the inverse of the transformation matrix to move the
// vertices back to their relative and local space
aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
mInv.Inverse();mInvTransposed.Transpose();
aiVector3D pivot = pcIn->vPivot;
pcOut->mNumMeshes = (unsigned int)iArray.size();
pcOut->mMeshes = new unsigned int[iArray.size()];
for (unsigned int i = 0;i < iArray.size();++i) {
const unsigned int iIndex = iArray[i];
aiMesh* const mesh = pcSOut->mMeshes[iIndex];
if (mesh->mColors[1] == NULL)
{
// Transform the vertices back into their local space
// fixme: consider computing normals after this, so we don't need to transform them
const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices;
aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
*pvCurrent = mInv * (*pvCurrent);
*t2 = mInvTransposed * (*t2);
}
// Handle negative transformation matrix determinant -> invert vertex x
if (imesh->mMat.Determinant() < 0.0f)
{
/* we *must* have normals */
for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
pvCurrent->x *= -1.f;
t2->x *= -1.f;
}
DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
}
// Handle pivot point
if (pivot.x || pivot.y || pivot.z)
{
for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) {
*pvCurrent -= pivot;
}
}
mesh->mColors[1] = (aiColor4D*)1;
}
else
mesh->mColors[1] = (aiColor4D*)1;
// Setup the mesh index
pcOut->mMeshes[i] = iIndex;
}
}
// Setup the name of the node
// First instance keeps its name otherwise something might break, all others will be postfixed with their instance number
if (pcIn->mInstanceNumber > 1)
{
char tmp[12];
ASSIMP_itoa10(tmp, pcIn->mInstanceNumber);
std::string tempStr = pcIn->mName + "_inst_";
tempStr += tmp;
pcOut->mName.Set(tempStr);
}
else
pcOut->mName.Set(pcIn->mName);
// Now build the transformation matrix of the node
// ROTATION
if (pcIn->aRotationKeys.size()){
// FIX to get to Assimp's quaternion conventions
for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
(*it).mValue.w *= -1.f;
}
pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
}
else if (pcIn->aCameraRollKeys.size())
{
aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
pcOut->mTransformation);
}
// SCALING
aiMatrix4x4& m = pcOut->mTransformation;
if (pcIn->aScalingKeys.size())
{
const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
}
// TRANSLATION
if (pcIn->aPositionKeys.size())
{
const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
m.a4 += v.x;
m.b4 += v.y;
m.c4 += v.z;
}
// Generate animation channels for the node
if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 ||
pcIn->aTargetPositionKeys.size() > 1)
{
aiAnimation* anim = pcSOut->mAnimations[0];
ai_assert(NULL != anim);
if (pcIn->aCameraRollKeys.size() > 1)
{
DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
// Camera roll keys - in fact they're just rotations
// around the camera's z axis. The angles are given
// in degrees (and they're clockwise).
pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
{
aiQuatKey& q = pcIn->aRotationKeys[i];
aiFloatKey& f = pcIn->aCameraRollKeys[i];
q.mTime = f.mTime;
// FIX to get to Assimp quaternion conventions
q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue));
}
}
#if 0
if (pcIn->aTargetPositionKeys.size() > 1)
{
DefaultLogger::get()->debug("3DS: Converting target track ...");
// Camera or spot light - need to convert the separate
// target position channel to our representation
TargetAnimationHelper helper;
if (pcIn->aPositionKeys.empty())
{
// We can just pass zero here ...
helper.SetFixedMainAnimationChannel(aiVector3D());
}
else helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
// Do the conversion
std::vector<aiVectorKey> distanceTrack;
helper.Process(&distanceTrack);
// Now add a new node as child, name it <ourName>.Target
// and assign the distance track to it. This is that the
// information where the target is and how it moves is
// not lost
D3DS::Node* nd = new D3DS::Node();
pcIn->push_back(nd);
nd->mName = pcIn->mName + ".Target";
aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
nda->mNodeName.Set(nd->mName);
nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
::memcpy(nda->mPositionKeys,&distanceTrack[0],
sizeof(aiVectorKey)*nda->mNumPositionKeys);
}
#endif
// Cameras or lights define their transformation in their parent node and in the
// corresponding light or camera chunks. However, we read and process the latter
// to to be able to return valid cameras/lights even if no scenegraph is given.
for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) {
if (pcSOut->mCameras[n]->mName == pcOut->mName) {
pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f);
}
}
for (unsigned int n = 0; n < pcSOut->mNumLights;++n) {
if (pcSOut->mLights[n]->mName == pcOut->mName) {
pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f);
}
}
// Allocate a new node anim and setup its name
aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
nda->mNodeName.Set(pcIn->mName);
// POSITION keys
if (pcIn->aPositionKeys.size() > 0)
{
nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
sizeof(aiVectorKey)*nda->mNumPositionKeys);
}
// ROTATION keys
if (pcIn->aRotationKeys.size() > 0)
{
nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
// Rotations are quaternion offsets
aiQuaternion abs1;
for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
{
const aiQuatKey& q = pcIn->aRotationKeys[n];
abs1 = (n ? abs1 * q.mValue : q.mValue);
nda->mRotationKeys[n].mTime = q.mTime;
nda->mRotationKeys[n].mValue = abs1.Normalize();
}
}
// SCALING keys
if (pcIn->aScalingKeys.size() > 0)
{
nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
sizeof(aiVectorKey)*nda->mNumScalingKeys);
}
}
// Allocate storage for children
pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
// Recursively process all children
const unsigned int size = pcIn->mChildren.size();
for (unsigned int i = 0; i < size;++i)
{
pcOut->mChildren[i] = new aiNode();
pcOut->mChildren[i]->mParent = pcOut;
AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs);
}
}
// ------------------------------------------------------------------------------------------------
// Find out how many node animation channels we'll have finally
void CountTracks(D3DS::Node* node, unsigned int& cnt)
{
//////////////////////////////////////////////////////////////////////////////
// We will never generate more than one channel for a node, so
// this is rather easy here.
if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 ||
node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 ||
node->aTargetPositionKeys.size() > 1)
{
++cnt;
// account for the additional channel for the camera/spotlight target position
if (node->aTargetPositionKeys.size() > 1)++cnt;
}
// Recursively process all children
for (unsigned int i = 0; i < node->mChildren.size();++i)
CountTracks(node->mChildren[i],cnt);
}
// ------------------------------------------------------------------------------------------------
// Generate the output node graph
void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
{
pcOut->mRootNode = new aiNode();
if (0 == mRootNode->mChildren.size())
{
//////////////////////////////////////////////////////////////////////////////
// It seems the file is so messed up that it has not even a hierarchy.
// generate a flat hiearachy which looks like this:
//
// ROOT_NODE
// |
// ----------------------------------------
// | | | | |
// MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 ....
//
DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes +
mScene->mCameras.size() + mScene->mLights.size();
pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ];
pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
// Build dummy nodes for all meshes
unsigned int a = 0;
for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
{
aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
pcNode->mParent = pcOut->mRootNode;
pcNode->mMeshes = new unsigned int[1];
pcNode->mMeshes[0] = i;
pcNode->mNumMeshes = 1;
// Build a name for the node
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u",i);
}
// Build dummy nodes for all cameras
for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
{
aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
pcNode->mParent = pcOut->mRootNode;
// Build a name for the node
pcNode->mName = mScene->mCameras[i]->mName;
}
// Build dummy nodes for all lights
for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
{
aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
pcNode->mParent = pcOut->mRootNode;
// Build a name for the node
pcNode->mName = mScene->mLights[i]->mName;
}
}
else
{
// First of all: find out how many scaling, rotation and translation
// animation tracks we'll have afterwards
unsigned int numChannel = 0;
CountTracks(mRootNode,numChannel);
if (numChannel)
{
// Allocate a primary animation channel
pcOut->mNumAnimations = 1;
pcOut->mAnimations = new aiAnimation*[1];
aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation();
anim->mName.Set("3DSMasterAnim");
// Allocate enough storage for all node animation channels,
// but don't set the mNumChannels member - we'll use it to
// index into the array
anim->mChannels = new aiNodeAnim*[numChannel];
}
aiMatrix4x4 m;
AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m);
}
// We used the first and second vertex color set to store some temporary values so we need to cleanup here
for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a)
{
pcOut->mMeshes[a]->mColors[0] = NULL;
pcOut->mMeshes[a]->mColors[1] = NULL;
}
pcOut->mRootNode->mTransformation = aiMatrix4x4(
1.f,0.f,0.f,0.f,
0.f,0.f,1.f,0.f,
0.f,-1.f,0.f,0.f,
0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
// If the root node is unnamed name it "<3DSRoot>"
if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||
(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
{
pcOut->mRootNode->mName.Set("<3DSRoot>");
}
}
// ------------------------------------------------------------------------------------------------
// Convert all meshes in the scene and generate the final output scene.
void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
{
// Allocate enough storage for all output materials
pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials];
// ... and convert the 3DS materials to aiMaterial's
for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
{
aiMaterial* pcNew = new aiMaterial();
ConvertMaterial(mScene->mMaterials[i],*pcNew);
pcOut->mMaterials[i] = pcNew;
}
// Generate the output mesh list
ConvertMeshes(pcOut);
// Now copy all light sources to the output scene
pcOut->mNumLights = (unsigned int)mScene->mLights.size();
if (pcOut->mNumLights)
{
pcOut->mLights = new aiLight*[pcOut->mNumLights];
::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights);
}
// Now copy all cameras to the output scene
pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
if (pcOut->mNumCameras)
{
pcOut->mCameras = new aiCamera*[pcOut->mNumCameras];
::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras);
}
}
#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER

View file

@ -0,0 +1,565 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
#include "3DSExporter.h"
#include "3DSLoader.h"
#include "SceneCombiner.h"
#include "SplitLargeMeshes.h"
#include "StringComparison.h"
#include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Exporter.hpp>
#include <memory>
using namespace Assimp;
namespace Assimp {
namespace {
//////////////////////////////////////////////////////////////////////////////////////
// Scope utility to write a 3DS file chunk.
//
// Upon construction, the chunk header is written with the chunk type (flags)
// filled out, but the chunk size left empty. Upon destruction, the correct chunk
// size based on the then-position of the output stream cursor is filled in.
class ChunkWriter {
enum {
CHUNK_SIZE_NOT_SET = 0xdeadbeef
, SIZE_OFFSET = 2
};
public:
ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
: writer(writer)
{
chunk_start_pos = writer.GetCurrentPos();
writer.PutU2(chunk_type);
writer.PutU4(CHUNK_SIZE_NOT_SET);
}
~ChunkWriter() {
std::size_t head_pos = writer.GetCurrentPos();
ai_assert(head_pos > chunk_start_pos);
const std::size_t chunk_size = head_pos - chunk_start_pos;
writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
writer.PutU4(chunk_size);
writer.SetCurrentPos(head_pos);
}
private:
StreamWriterLE& writer;
std::size_t chunk_start_pos;
};
// Return an unique name for a given |mesh| attached to |node| that
// preserves the mesh's given name if it has one. |index| is the index
// of the mesh in |aiScene::mMeshes|.
std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
static const std::string underscore = "_";
char postfix[10] = {0};
ASSIMP_itoa10(postfix, index);
std::string result = node.mName.C_Str();
if (mesh.mName.length > 0) {
result += underscore + mesh.mName.C_Str();
}
return result + underscore + postfix;
}
// Return an unique name for a given |mat| with original position |index|
// in |aiScene::mMaterials|. The name preserves the original material
// name if possible.
std::string GetMaterialName(const aiMaterial& mat, unsigned int index) {
static const std::string underscore = "_";
char postfix[10] = {0};
ASSIMP_itoa10(postfix, index);
aiString mat_name;
if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
return mat_name.C_Str() + underscore + postfix;
}
return "Material" + underscore + postfix;
}
// Collect world transformations for each node
void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
trafos[node] = parent * node->mTransformation;
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
CollectTrafos(node->mChildren[i], trafos);
}
}
// Generate a flat list of the meshes (by index) assigned to each node
void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
meshes.insert(std::make_pair(node, node->mMeshes[i]));
}
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
CollectMeshes(node->mChildren[i], meshes);
}
}
}
// ------------------------------------------------------------------------------------------------
// Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
{
std::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
if(!outfile) {
throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
}
// TODO: This extra copy should be avoided and all of this made a preprocess
// requirement of the 3DS exporter.
//
// 3DS meshes can be max 0xffff (16 Bit) vertices and faces, respectively.
// SplitLargeMeshes can do this, but it requires the correct limit to be set
// which is not possible with the current way of specifying preprocess steps
// in |Exporter::ExportFormatEntry|.
aiScene* scenecopy_tmp;
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
SplitLargeMeshesProcess_Triangle tri_splitter;
tri_splitter.SetLimit(0xffff);
tri_splitter.Execute(scenecopy.get());
SplitLargeMeshesProcess_Vertex vert_splitter;
vert_splitter.SetLimit(0xffff);
vert_splitter.Execute(scenecopy.get());
// Invoke the actual exporter
Discreet3DSExporter exporter(outfile, scenecopy.get());
}
} // end of namespace Assimp
// ------------------------------------------------------------------------------------------------
Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* scene)
: scene(scene)
, writer(outfile)
{
CollectTrafos(scene->mRootNode, trafos);
CollectMeshes(scene->mRootNode, meshes);
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN);
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH);
WriteMaterials();
WriteMeshes();
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE);
writer.PutF4(1.0f);
}
}
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
WriteHierarchy(*scene->mRootNode, -1, -1);
}
}
// ------------------------------------------------------------------------------------------------
int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
{
// 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
// Assimp node names are unique and distinct from all mesh-node
// names we generate; thus we can use them as-is
WriteString(node.mName);
// Two unknown int16 values - it is even unclear if 0 is a safe value
// but luckily importers do not know better either.
writer.PutI4(0);
int16_t hierarchy_pos = static_cast<int16_t>(seq);
if (sibling_level != -1) {
hierarchy_pos = sibling_level;
}
// Write the hierarchy position
writer.PutI2(hierarchy_pos);
}
}
// TODO: write transformation chunks
++seq;
sibling_level = seq;
// Write all children
for (unsigned int i = 0; i < node.mNumChildren; ++i) {
seq = WriteHierarchy(*node.mChildren[i], seq, i == 0 ? -1 : sibling_level);
}
// Write all meshes as separate nodes to be able to reference the meshes by name
for (unsigned int i = 0; i < node.mNumMeshes; ++i) {
const bool first_child = node.mNumChildren == 0 && i == 0;
const unsigned int mesh_idx = node.mMeshes[i];
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
WriteString(GetMeshName(mesh, mesh_idx, node));
writer.PutI4(0);
writer.PutI2(static_cast<int16_t>(first_child ? seq : sibling_level));
++seq;
}
}
return seq;
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteMaterials()
{
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
const aiMaterial& mat = *scene->mMaterials[i];
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
const std::string& name = GetMaterialName(mat, i);
WriteString(name);
}
aiColor3D color;
if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
WriteColor(color);
}
if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
WriteColor(color);
}
if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
WriteColor(color);
}
if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
WriteColor(color);
}
aiShadingMode shading_mode = aiShadingMode_Flat;
if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
Discreet3DS::shadetype3ds shading_mode_out;
switch(shading_mode) {
case aiShadingMode_Flat:
case aiShadingMode_NoShading:
shading_mode_out = Discreet3DS::Flat;
break;
case aiShadingMode_Gouraud:
case aiShadingMode_Toon:
case aiShadingMode_OrenNayar:
case aiShadingMode_Minnaert:
shading_mode_out = Discreet3DS::Gouraud;
break;
case aiShadingMode_Phong:
case aiShadingMode_Blinn:
case aiShadingMode_CookTorrance:
case aiShadingMode_Fresnel:
shading_mode_out = Discreet3DS::Phong;
break;
default:
shading_mode_out = Discreet3DS::Flat;
ai_assert(false);
};
writer.PutU2(static_cast<uint16_t>(shading_mode_out));
}
float f;
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
WritePercentChunk(f);
}
if (mat.Get(AI_MATKEY_SHININESS_STRENGTH, f) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS_PERCENT);
WritePercentChunk(f);
}
int twosided;
if (mat.Get(AI_MATKEY_TWOSIDED, twosided) == AI_SUCCESS && twosided != 0) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TWO_SIDE);
writer.PutI2(1);
}
WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
WriteTexture(mat, aiTextureType_SPECULAR, Discreet3DS::CHUNK_MAT_SPECMAP);
WriteTexture(mat, aiTextureType_EMISSIVE, Discreet3DS::CHUNK_MAT_SELFIMAP);
WriteTexture(mat, aiTextureType_REFLECTION, Discreet3DS::CHUNK_MAT_REFLMAP);
}
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags)
{
aiString path;
aiTextureMapMode map_mode[2] = {
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
};
float blend = 1.0f;
if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) {
return;
}
// TODO: handle embedded textures properly
if (path.data[0] == '*') {
DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str()));
return;
}
ChunkWriter chunk(writer, chunk_flags);
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE);
WriteString(path);
}
WritePercentChunk(blend);
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
uint16_t val = 0; // WRAP
if (map_mode[0] == aiTextureMapMode_Mirror) {
val = 0x2;
}
else if (map_mode[0] == aiTextureMapMode_Decal) {
val = 0x10;
}
writer.PutU2(val);
}
// TODO: export texture transformation (i.e. UV offset, scale, rotation)
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteMeshes()
{
// NOTE: 3DS allows for instances. However:
// i) not all importers support reading them
// ii) instances are not as flexible as they are in assimp, in particular,
// nodes can carry (and instance) only one mesh.
//
// This exporter currently deep clones all instanced meshes, i.e. for each mesh
// attached to a node a full TRIMESH chunk is written to the file.
//
// Furthermore, the TRIMESH is transformed into world space so that it will
// appear correctly if importers don't read the scene hierarchy at all.
for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
const aiNode& node = *(*it).first;
const unsigned int mesh_idx = (*it).second;
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
// This should not happen if the SLM step is correctly executed
// before the scene is handed to the exporter
ai_assert(mesh.mNumVertices <= 0xffff);
ai_assert(mesh.mNumFaces <= 0xffff);
const aiMatrix4x4& trafo = trafos[&node];
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
// Mesh name is tied to the node it is attached to so it can later be referenced
const std::string& name = GetMeshName(mesh, mesh_idx, node);
WriteString(name);
// TRIMESH chunk
ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
// Vertices in world space
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST);
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
writer.PutU2(count);
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
const aiVector3D& v = trafo * mesh.mVertices[i];
writer.PutF4(v.x);
writer.PutF4(v.y);
writer.PutF4(v.z);
}
}
// UV coordinates
if (mesh.HasTextureCoords(0)) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST);
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
writer.PutU2(count);
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
const aiVector3D& v = mesh.mTextureCoords[0][i];
writer.PutF4(v.x);
writer.PutF4(v.y);
}
}
// Faces (indices)
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST);
ai_assert(mesh.mNumFaces <= 0xffff);
// Count triangles, discard lines and points
uint16_t count = 0;
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
const aiFace& f = mesh.mFaces[i];
if (f.mNumIndices < 3) {
continue;
}
// TRIANGULATE step is a pre-requisite so we should not see polys here
ai_assert(f.mNumIndices == 3);
++count;
}
writer.PutU2(count);
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
const aiFace& f = mesh.mFaces[i];
if (f.mNumIndices < 3) {
continue;
}
for (unsigned int j = 0; j < 3; ++j) {
ai_assert(f.mIndices[j] <= 0xffff);
writer.PutI2(static_cast<uint16_t>(f.mIndices[j]));
}
// Edge visibility flag
writer.PutI2(0x0);
}
// TODO: write smoothing groups (CHUNK_SMOOLIST)
WriteFaceMaterialChunk(mesh);
}
// Transformation matrix by which the mesh vertices have been pre-transformed with.
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX);
for (unsigned int r = 0; r < 4; ++r) {
for (unsigned int c = 0; c < 3; ++c) {
writer.PutF4(trafo[r][c]);
}
}
}
}
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
{
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT);
const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
WriteString(name);
// Because assimp splits meshes by material, only a single
// FACEMAT chunk needs to be written
ai_assert(mesh.mNumFaces <= 0xffff);
const uint16_t count = static_cast<uint16_t>(mesh.mNumFaces);
writer.PutU2(count);
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
writer.PutU2(static_cast<uint16_t>(i));
}
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteString(const std::string& s) {
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
writer.PutI1(*it);
}
writer.PutI1('\0');
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteString(const aiString& s) {
for (std::size_t i = 0; i < s.length; ++i) {
writer.PutI1(s.data[i]);
}
writer.PutI1('\0');
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF);
writer.PutF4(color.r);
writer.PutF4(color.g);
writer.PutF4(color.b);
}
// ------------------------------------------------------------------------------------------------
void Discreet3DSExporter::WritePercentChunk(float f) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF);
writer.PutF4(f);
}
#endif // ASSIMP_BUILD_NO_3DS_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View file

@ -0,0 +1,98 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file 3DSExporter.h
* 3DS Exporter Main Header
*/
#ifndef AI_3DSEXPORTER_H_INC
#define AI_3DSEXPORTER_H_INC
#include <map>
#include <memory>
#include "StreamWriter.h"
#include "./../include/assimp/material.h"
struct aiScene;
struct aiNode;
struct aiMaterial;
struct aiMesh;
namespace Assimp
{
// ------------------------------------------------------------------------------------------------
/** Helper class to export a given scene to a 3DS file. */
// ------------------------------------------------------------------------------------------------
class Discreet3DSExporter
{
public:
Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* pScene);
private:
void WriteMeshes();
void WriteMaterials();
void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
void WriteFaceMaterialChunk(const aiMesh& mesh);
int WriteHierarchy(const aiNode& node, int level, int sibling_level);
void WriteString(const std::string& s);
void WriteString(const aiString& s);
void WriteColor(const aiColor3D& color);
void WritePercentChunk(float f);
private:
const aiScene* const scene;
StreamWriterLE writer;
std::map<const aiNode*, aiMatrix4x4> trafos;
typedef std::multimap<const aiNode*, unsigned int> MeshesByNodeMap;
MeshesByNodeMap meshes;
};
}
#endif

View file

@ -0,0 +1,592 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file Defines helper data structures for the import of 3DS files */
#ifndef AI_3DSFILEHELPER_H_INC
#define AI_3DSFILEHELPER_H_INC
#include "SpatialSort.h"
#include "SmoothingGroups.h"
#include "StringUtils.h"
#include "qnan.h"
#include "./../include/assimp/material.h"
#include "./../include/assimp/camera.h"
#include "./../include/assimp/light.h"
#include "./../include/assimp/anim.h"
#include <stdio.h> //sprintf
namespace Assimp {
namespace D3DS {
#include "./../include/assimp/Compiler/pushpack1.h"
// ---------------------------------------------------------------------------
/** Discreet3DS class: Helper class for loading 3ds files. Defines chunks
* and data structures.
*/
class Discreet3DS
{
private:
inline Discreet3DS() {}
public:
//! data structure for a single chunk in a .3ds file
struct Chunk
{
uint16_t Flag;
uint32_t Size;
} PACK_STRUCT;
//! Used for shading field in material3ds structure
//! From AutoDesk 3ds SDK
typedef enum
{
// translated to gouraud shading with wireframe active
Wire = 0x0,
// if this material is set, no vertex normals will
// be calculated for the model. Face normals + gouraud
Flat = 0x1,
// standard gouraud shading
Gouraud = 0x2,
// phong shading
Phong = 0x3,
// cooktorrance or anistropic phong shading ...
// the exact meaning is unknown, if you know it
// feel free to tell me ;-)
Metal = 0x4,
// required by the ASE loader
Blinn = 0x5
} shadetype3ds;
// Flags for animated keys
enum
{
KEY_USE_TENS = 0x1,
KEY_USE_CONT = 0x2,
KEY_USE_BIAS = 0x4,
KEY_USE_EASE_TO = 0x8,
KEY_USE_EASE_FROM = 0x10
} ;
enum
{
// ********************************************************************
// Basic chunks which can be found everywhere in the file
CHUNK_VERSION = 0x0002,
CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B
CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B
// Linear color values (gamma = 2.2?)
CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B
CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B
CHUNK_PERCENTW = 0x0030, // int2 percentage
CHUNK_PERCENTF = 0x0031, // float4 percentage
// ********************************************************************
// Prj master chunk
CHUNK_PRJ = 0xC23D,
// MDLI master chunk
CHUNK_MLI = 0x3DAA,
// Primary main chunk of the .3ds file
CHUNK_MAIN = 0x4D4D,
// Mesh main chunk
CHUNK_OBJMESH = 0x3D3D,
// Specifies the background color of the .3ds file
// This is passed through the material system for
// viewing purposes.
CHUNK_BKGCOLOR = 0x1200,
// Specifies the ambient base color of the scene.
// This is added to all materials in the file
CHUNK_AMBCOLOR = 0x2100,
// Specifies the background image for the whole scene
// This value is passed through the material system
// to the viewer
CHUNK_BIT_MAP = 0x1100,
CHUNK_BIT_MAP_EXISTS = 0x1101,
// ********************************************************************
// Viewport related stuff. Ignored
CHUNK_DEFAULT_VIEW = 0x3000,
CHUNK_VIEW_TOP = 0x3010,
CHUNK_VIEW_BOTTOM = 0x3020,
CHUNK_VIEW_LEFT = 0x3030,
CHUNK_VIEW_RIGHT = 0x3040,
CHUNK_VIEW_FRONT = 0x3050,
CHUNK_VIEW_BACK = 0x3060,
CHUNK_VIEW_USER = 0x3070,
CHUNK_VIEW_CAMERA = 0x3080,
// ********************************************************************
// Mesh chunks
CHUNK_OBJBLOCK = 0x4000,
CHUNK_TRIMESH = 0x4100,
CHUNK_VERTLIST = 0x4110,
CHUNK_VERTFLAGS = 0x4111,
CHUNK_FACELIST = 0x4120,
CHUNK_FACEMAT = 0x4130,
CHUNK_MAPLIST = 0x4140,
CHUNK_SMOOLIST = 0x4150,
CHUNK_TRMATRIX = 0x4160,
CHUNK_MESHCOLOR = 0x4165,
CHUNK_TXTINFO = 0x4170,
CHUNK_LIGHT = 0x4600,
CHUNK_CAMERA = 0x4700,
CHUNK_HIERARCHY = 0x4F00,
// Specifies the global scaling factor. This is applied
// to the root node's transformation matrix
CHUNK_MASTER_SCALE = 0x0100,
// ********************************************************************
// Material chunks
CHUNK_MAT_MATERIAL = 0xAFFF,
// asciiz containing the name of the material
CHUNK_MAT_MATNAME = 0xA000,
CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk
CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk
CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk
// Specifies the shininess of the material
// followed by percentage chunk
CHUNK_MAT_SHININESS = 0xA040,
CHUNK_MAT_SHININESS_PERCENT = 0xA041 ,
// Specifies the shading mode to be used
// followed by a short
CHUNK_MAT_SHADING = 0xA100,
// NOTE: Emissive color (self illumination) seems not
// to be a color but a single value, type is unknown.
// Make the parser accept both of them.
// followed by percentage chunk (?)
CHUNK_MAT_SELF_ILLUM = 0xA080,
// Always followed by percentage chunk (?)
CHUNK_MAT_SELF_ILPCT = 0xA084,
// Always followed by percentage chunk
CHUNK_MAT_TRANSPARENCY = 0xA050,
// Diffuse texture channel 0
CHUNK_MAT_TEXTURE = 0xA200,
// Contains opacity information for each texel
CHUNK_MAT_OPACMAP = 0xA210,
// Contains a reflection map to be used to reflect
// the environment. This is partially supported.
CHUNK_MAT_REFLMAP = 0xA220,
// Self Illumination map (emissive colors)
CHUNK_MAT_SELFIMAP = 0xA33d,
// Bumpmap. Not specified whether it is a heightmap
// or a normal map. Assme it is a heightmap since
// artist normally prefer this format.
CHUNK_MAT_BUMPMAP = 0xA230,
// Specular map. Seems to influence the specular color
CHUNK_MAT_SPECMAP = 0xA204,
// Holds shininess data.
CHUNK_MAT_MAT_SHINMAP = 0xA33C,
// Scaling in U/V direction.
// (need to gen separate UV coordinate set
// and do this by hand)
CHUNK_MAT_MAP_USCALE = 0xA354,
CHUNK_MAT_MAP_VSCALE = 0xA356,
// Translation in U/V direction.
// (need to gen separate UV coordinate set
// and do this by hand)
CHUNK_MAT_MAP_UOFFSET = 0xA358,
CHUNK_MAT_MAP_VOFFSET = 0xA35a,
// UV-coordinates rotation around the z-axis
// Assumed to be in radians.
CHUNK_MAT_MAP_ANG = 0xA35C,
// Tiling flags for 3DS files
CHUNK_MAT_MAP_TILING = 0xa351,
// Specifies the file name of a texture
CHUNK_MAPFILE = 0xA300,
// Specifies whether a materail requires two-sided rendering
CHUNK_MAT_TWO_SIDE = 0xA081,
// ********************************************************************
// Main keyframer chunk. Contains translation/rotation/scaling data
CHUNK_KEYFRAMER = 0xB000,
// Supported sub chunks
CHUNK_TRACKINFO = 0xB002,
CHUNK_TRACKOBJNAME = 0xB010,
CHUNK_TRACKDUMMYOBJNAME = 0xB011,
CHUNK_TRACKPIVOT = 0xB013,
CHUNK_TRACKPOS = 0xB020,
CHUNK_TRACKROTATE = 0xB021,
CHUNK_TRACKSCALE = 0xB022,
// ********************************************************************
// Keyframes for various other stuff in the file
// Partially ignored
CHUNK_AMBIENTKEY = 0xB001,
CHUNK_TRACKMORPH = 0xB026,
CHUNK_TRACKHIDE = 0xB029,
CHUNK_OBJNUMBER = 0xB030,
CHUNK_TRACKCAMERA = 0xB003,
CHUNK_TRACKFOV = 0xB023,
CHUNK_TRACKROLL = 0xB024,
CHUNK_TRACKCAMTGT = 0xB004,
CHUNK_TRACKLIGHT = 0xB005,
CHUNK_TRACKLIGTGT = 0xB006,
CHUNK_TRACKSPOTL = 0xB007,
CHUNK_FRAMES = 0xB008,
// ********************************************************************
// light sub-chunks
CHUNK_DL_OFF = 0x4620,
CHUNK_DL_OUTER_RANGE = 0x465A,
CHUNK_DL_INNER_RANGE = 0x4659,
CHUNK_DL_MULTIPLIER = 0x465B,
CHUNK_DL_EXCLUDE = 0x4654,
CHUNK_DL_ATTENUATE = 0x4625,
CHUNK_DL_SPOTLIGHT = 0x4610,
// camera sub-chunks
CHUNK_CAM_RANGES = 0x4720
};
};
// ---------------------------------------------------------------------------
/** Helper structure representing a 3ds mesh face */
struct Face : public FaceWithSmoothingGroup
{
};
// ---------------------------------------------------------------------------
/** Helper structure representing a texture */
struct Texture
{
//! Default constructor
Texture()
: mOffsetU (0.0f)
, mOffsetV (0.0f)
, mScaleU (1.0f)
, mScaleV (1.0f)
, mRotation (0.0f)
, mMapMode (aiTextureMapMode_Wrap)
, bPrivate()
, iUVSrc (0)
{
mTextureBlend = get_qnan();
}
//! Specifies the blend factor for the texture
float mTextureBlend;
//! Specifies the filename of the texture
std::string mMapName;
//! Specifies texture coordinate offsets/scaling/rotations
float mOffsetU;
float mOffsetV;
float mScaleU;
float mScaleV;
float mRotation;
//! Specifies the mapping mode to be used for the texture
aiTextureMapMode mMapMode;
//! Used internally
bool bPrivate;
int iUVSrc;
};
#include "./../include/assimp/Compiler/poppack1.h"
// ---------------------------------------------------------------------------
/** Helper structure representing a 3ds material */
struct Material
{
//! Default constructor. Builds a default name for the material
Material()
:
mDiffuse (0.6f,0.6f,0.6f), // FIX ... we won't want object to be black
mSpecularExponent (0.0f),
mShininessStrength (1.0f),
mShading(Discreet3DS::Gouraud),
mTransparency (1.0f),
mBumpHeight (1.0f),
mTwoSided (false)
{
static int iCnt = 0;
char szTemp[128];
ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
mName = szTemp;
}
//! Name of the material
std::string mName;
//! Diffuse color of the material
aiColor3D mDiffuse;
//! Specular exponent
float mSpecularExponent;
//! Shininess strength, in percent
float mShininessStrength;
//! Specular color of the material
aiColor3D mSpecular;
//! Ambient color of the material
aiColor3D mAmbient;
//! Shading type to be used
Discreet3DS::shadetype3ds mShading;
//! Opacity of the material
float mTransparency;
//! Diffuse texture channel
Texture sTexDiffuse;
//! Opacity texture channel
Texture sTexOpacity;
//! Specular texture channel
Texture sTexSpecular;
//! Reflective texture channel
Texture sTexReflective;
//! Bump texture channel
Texture sTexBump;
//! Emissive texture channel
Texture sTexEmissive;
//! Shininess texture channel
Texture sTexShininess;
//! Scaling factor for the bump values
float mBumpHeight;
//! Emissive color
aiColor3D mEmissive;
//! Ambient texture channel
//! (used by the ASE format)
Texture sTexAmbient;
//! True if the material must be rendered from two sides
bool mTwoSided;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent a 3ds file mesh */
struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
{
//! Default constructor
Mesh()
{
static int iCnt = 0;
// Generate a default name for the mesh
char szTemp[128];
ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
mName = szTemp;
}
//! Name of the mesh
std::string mName;
//! Texture coordinates
std::vector<aiVector3D> mTexCoords;
//! Face materials
std::vector<unsigned int> mFaceMaterials;
//! Local transformation matrix
aiMatrix4x4 mMat;
};
// ---------------------------------------------------------------------------
/** Float key - quite similar to aiVectorKey and aiQuatKey. Both are in the
C-API, so it would be difficult to make them a template. */
struct aiFloatKey
{
double mTime; ///< The time of this key
float mValue; ///< The value of this key
#ifdef __cplusplus
// time is not compared
bool operator == (const aiFloatKey& o) const
{return o.mValue == this->mValue;}
bool operator != (const aiFloatKey& o) const
{return o.mValue != this->mValue;}
// Only time is compared. This operator is defined
// for use with std::sort
bool operator < (const aiFloatKey& o) const
{return mTime < o.mTime;}
bool operator > (const aiFloatKey& o) const
{return mTime > o.mTime;}
#endif
};
// ---------------------------------------------------------------------------
/** Helper structure to represent a 3ds file node */
struct Node
{
Node():
mParent(NULL)
, mInstanceNumber(0)
, mHierarchyPos (0)
, mHierarchyIndex (0)
, mInstanceCount (1)
{
static int iCnt = 0;
// Generate a default name for the node
char szTemp[128];
::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
mName = szTemp;
aRotationKeys.reserve (20);
aPositionKeys.reserve (20);
aScalingKeys.reserve (20);
}
~Node()
{
for (unsigned int i = 0; i < mChildren.size();++i)
delete mChildren[i];
}
//! Pointer to the parent node
Node* mParent;
//! Holds all child nodes
std::vector<Node*> mChildren;
//! Name of the node
std::string mName;
//! InstanceNumber of the node
int32_t mInstanceNumber;
//! Dummy nodes: real name to be combined with the $$$DUMMY
std::string mDummyName;
//! Position of the node in the hierarchy (tree depth)
int16_t mHierarchyPos;
//! Index of the node
int16_t mHierarchyIndex;
//! Rotation keys loaded from the file
std::vector<aiQuatKey> aRotationKeys;
//! Position keys loaded from the file
std::vector<aiVectorKey> aPositionKeys;
//! Scaling keys loaded from the file
std::vector<aiVectorKey> aScalingKeys;
// For target lights (spot lights and directional lights):
// The position of the target
std::vector< aiVectorKey > aTargetPositionKeys;
// For cameras: the camera roll angle
std::vector< aiFloatKey > aCameraRollKeys;
//! Pivot position loaded from the file
aiVector3D vPivot;
//instance count, will be kept only for the first node
int32_t mInstanceCount;
//! Add a child node, setup the right parent node for it
//! \param pc Node to be 'adopted'
inline Node& push_back(Node* pc)
{
mChildren.push_back(pc);
pc->mParent = this;
return *this;
}
};
// ---------------------------------------------------------------------------
/** Helper structure analogue to aiScene */
struct Scene
{
//! List of all materials loaded
//! NOTE: 3ds references materials globally
std::vector<Material> mMaterials;
//! List of all meshes loaded
std::vector<Mesh> mMeshes;
//! List of all cameras loaded
std::vector<aiCamera*> mCameras;
//! List of all lights loaded
std::vector<aiLight*> mLights;
//! Pointer to the root node of the scene
// --- moved to main class
// Node* pcRootNode;
};
} // end of namespace D3DS
} // end of namespace Assimp
#endif // AI_XFILEHELPER_H_INC

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,282 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file 3DSLoader.h
* @brief 3DS File format loader
*/
#ifndef AI_3DSIMPORTER_H_INC
#define AI_3DSIMPORTER_H_INC
#include "BaseImporter.h"
#include <assimp/types.h>
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
#include "3DSHelper.h"
#include "StreamReader.h"
struct aiNode;
namespace Assimp {
using namespace D3DS;
// ---------------------------------------------------------------------------------
/** Importer class for 3D Studio r3 and r4 3DS files
*/
class Discreet3DSImporter : public BaseImporter
{
public:
Discreet3DSImporter();
~Discreet3DSImporter();
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.
*/
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list.
*/
void SetupProperties(const Importer* pImp);
protected:
// -------------------------------------------------------------------
/** Return importer meta information.
* See #BaseImporter::GetInfo for the details
*/
const aiImporterDesc* GetInfo () const;
// -------------------------------------------------------------------
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
// -------------------------------------------------------------------
/** Converts a temporary material to the outer representation
*/
void ConvertMaterial(D3DS::Material& p_cMat,
aiMaterial& p_pcOut);
// -------------------------------------------------------------------
/** Read a chunk
*
* @param pcOut Receives the current chunk
*/
void ReadChunk(Discreet3DS::Chunk* pcOut);
// -------------------------------------------------------------------
/** Parse a percentage chunk. mCurrent will point to the next
* chunk behind afterwards. If no percentage chunk is found
* QNAN is returned.
*/
float ParsePercentageChunk();
// -------------------------------------------------------------------
/** Parse a color chunk. mCurrent will point to the next
* chunk behind afterwards. If no color chunk is found
* QNAN is returned in all members.
*/
void ParseColorChunk(aiColor3D* p_pcOut,
bool p_bAcceptPercent = true);
// -------------------------------------------------------------------
/** Skip a chunk in the file
*/
void SkipChunk();
// -------------------------------------------------------------------
/** Generate the nodegraph
*/
void GenerateNodeGraph(aiScene* pcOut);
// -------------------------------------------------------------------
/** Parse a main top-level chunk in the file
*/
void ParseMainChunk();
// -------------------------------------------------------------------
/** Parse a top-level chunk in the file
*/
void ParseChunk(const char* name, unsigned int num);
// -------------------------------------------------------------------
/** Parse a top-level editor chunk in the file
*/
void ParseEditorChunk();
// -------------------------------------------------------------------
/** Parse a top-level object chunk in the file
*/
void ParseObjectChunk();
// -------------------------------------------------------------------
/** Parse a material chunk in the file
*/
void ParseMaterialChunk();
// -------------------------------------------------------------------
/** Parse a mesh chunk in the file
*/
void ParseMeshChunk();
// -------------------------------------------------------------------
/** Parse a light chunk in the file
*/
void ParseLightChunk();
// -------------------------------------------------------------------
/** Parse a camera chunk in the file
*/
void ParseCameraChunk();
// -------------------------------------------------------------------
/** Parse a face list chunk in the file
*/
void ParseFaceChunk();
// -------------------------------------------------------------------
/** Parse a keyframe chunk in the file
*/
void ParseKeyframeChunk();
// -------------------------------------------------------------------
/** Parse a hierarchy chunk in the file
*/
void ParseHierarchyChunk(uint16_t parent);
// -------------------------------------------------------------------
/** Parse a texture chunk in the file
*/
void ParseTextureChunk(D3DS::Texture* pcOut);
// -------------------------------------------------------------------
/** Convert the meshes in the file
*/
void ConvertMeshes(aiScene* pcOut);
// -------------------------------------------------------------------
/** Replace the default material in the scene
*/
void ReplaceDefaultMaterial();
// -------------------------------------------------------------------
/** Convert the whole scene
*/
void ConvertScene(aiScene* pcOut);
// -------------------------------------------------------------------
/** generate unique vertices for a mesh
*/
void MakeUnique(D3DS::Mesh& sMesh);
// -------------------------------------------------------------------
/** Add a node to the node graph
*/
void AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn,
aiMatrix4x4& absTrafo);
// -------------------------------------------------------------------
/** Search for a node in the graph.
* Called recursively
*/
void InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent);
// -------------------------------------------------------------------
/** Apply the master scaling factor to the mesh
*/
void ApplyMasterScale(aiScene* pScene);
// -------------------------------------------------------------------
/** Clamp all indices in the file to a valid range
*/
void CheckIndices(D3DS::Mesh& sMesh);
// -------------------------------------------------------------------
/** Skip the TCB info in a track key
*/
void SkipTCBInfo();
protected:
/** Stream to read from */
StreamReaderLE* stream;
/** Last touched node index */
short mLastNodeIndex;
/** Current node, root node */
D3DS::Node* mCurrentNode, *mRootNode;
/** Scene under construction */
D3DS::Scene* mScene;
/** Ambient base color of the scene */
aiColor3D mClrAmbient;
/** Master scaling factor of the scene */
float mMasterScale;
/** Path to the background image of the scene */
std::string mBackgroundImage;
bool bHasBG;
/** true if PRJ file */
bool bIsPrj;
};
} // end of namespace Assimp
#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER
#endif // AI_3DSIMPORTER_H_INC

View file

@ -0,0 +1,907 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file Implementation of the AC3D importer class */
#ifndef ASSIMP_BUILD_NO_AC_IMPORTER
// internal headers
#include "ACLoader.h"
#include "ParsingUtils.h"
#include "fast_atof.h"
#include "Subdivision.h"
#include "Importer.h"
#include "BaseImporter.h"
#include <assimp/Importer.hpp>
#include <assimp/light.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/material.h>
#include <assimp/scene.h>
#include <assimp/config.h>
#include <assimp/IOSystem.hpp>
#include <memory>
using namespace Assimp;
static const aiImporterDesc desc = {
"AC3D Importer",
"",
"",
"",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"ac acc ac3d"
};
// ------------------------------------------------------------------------------------------------
// skip to the next token
#define AI_AC_SKIP_TO_NEXT_TOKEN() \
if (!SkipSpaces(&buffer)) \
{ \
DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \
continue; \
}
// ------------------------------------------------------------------------------------------------
// read a string (may be enclosed in double quotation marks). buffer must point to "
#define AI_AC_GET_STRING(out) \
if (*buffer == '\0') { \
throw DeadlyImportError("AC3D: Unexpected EOF in string"); \
} \
++buffer; \
const char* sz = buffer; \
while ('\"' != *buffer) \
{ \
if (IsLineEnd( *buffer )) \
{ \
DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \
out = "ERROR"; \
break; \
} \
++buffer; \
} \
if (IsLineEnd( *buffer ))continue; \
out = std::string(sz,(unsigned int)(buffer-sz)); \
++buffer;
// ------------------------------------------------------------------------------------------------
// read 1 to n floats prefixed with an optional predefined identifier
#define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \
AI_AC_SKIP_TO_NEXT_TOKEN(); \
if (name_length) \
{ \
if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \
{ \
DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \
continue; \
} \
buffer += name_length+1; \
} \
for (unsigned int i = 0; i < num;++i) \
{ \
AI_AC_SKIP_TO_NEXT_TOKEN(); \
buffer = fast_atoreal_move<float>(buffer,((float*)out)[i]); \
}
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
AC3DImporter::AC3DImporter()
: buffer(),
configSplitBFCull(),
configEvalSubdivision(),
mNumMeshes(),
mLights(),
lights(),
groups(),
polys(),
worlds()
{
// nothing to be done here
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
AC3DImporter::~AC3DImporter()
{
// nothing to be done here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
{
std::string extension = GetExtension(pFile);
// fixme: are acc and ac3d *really* used? Some sources say they are
if(extension == "ac" || extension == "ac3d" || extension == "acc") {
return true;
}
if (!extension.length() || checkSig) {
uint32_t token = AI_MAKE_MAGIC("AC3D");
return CheckMagicToken(pIOHandler,pFile,&token,1,0);
}
return false;
}
// ------------------------------------------------------------------------------------------------
// Loader meta information
const aiImporterDesc* AC3DImporter::GetInfo () const
{
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Get a pointer to the next line from the file
bool AC3DImporter::GetNextLine( )
{
SkipLine(&buffer);
return SkipSpaces(&buffer);
}
// ------------------------------------------------------------------------------------------------
// Parse an object section in an AC file
void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
{
if (!TokenMatch(buffer,"OBJECT",6))
return;
SkipSpaces(&buffer);
++mNumMeshes;
objects.push_back(Object());
Object& obj = objects.back();
aiLight* light = NULL;
if (!ASSIMP_strincmp(buffer,"light",5))
{
// This is a light source. Add it to the list
mLights->push_back(light = new aiLight());
// Return a point light with no attenuation
light->mType = aiLightSource_POINT;
light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f);
light->mAttenuationConstant = 1.f;
// Generate a default name for both the light source and the node
// FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version.
light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i",static_cast<unsigned int>(mLights->size())-1);
obj.name = std::string( light->mName.data );
DefaultLogger::get()->debug("AC3D: Light source encountered");
obj.type = Object::Light;
}
else if (!ASSIMP_strincmp(buffer,"group",5))
{
obj.type = Object::Group;
}
else if (!ASSIMP_strincmp(buffer,"world",5))
{
obj.type = Object::World;
}
else obj.type = Object::Poly;
while (GetNextLine())
{
if (TokenMatch(buffer,"kids",4))
{
SkipSpaces(&buffer);
unsigned int num = strtoul10(buffer,&buffer);
GetNextLine();
if (num)
{
// load the children of this object recursively
obj.children.reserve(num);
for (unsigned int i = 0; i < num; ++i)
LoadObjectSection(obj.children);
}
return;
}
else if (TokenMatch(buffer,"name",4))
{
SkipSpaces(&buffer);
AI_AC_GET_STRING(obj.name);
// If this is a light source, we'll also need to store
// the name of the node in it.
if (light)
{
light->mName.Set(obj.name);
}
}
else if (TokenMatch(buffer,"texture",7))
{
SkipSpaces(&buffer);
AI_AC_GET_STRING(obj.texture);
}
else if (TokenMatch(buffer,"texrep",6))
{
SkipSpaces(&buffer);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat);
if (!obj.texRepeat.x || !obj.texRepeat.y)
obj.texRepeat = aiVector2D (1.f,1.f);
}
else if (TokenMatch(buffer,"texoff",6))
{
SkipSpaces(&buffer);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset);
}
else if (TokenMatch(buffer,"rot",3))
{
SkipSpaces(&buffer);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation);
}
else if (TokenMatch(buffer,"loc",3))
{
SkipSpaces(&buffer);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation);
}
else if (TokenMatch(buffer,"subdiv",6))
{
SkipSpaces(&buffer);
obj.subDiv = strtoul10(buffer,&buffer);
}
else if (TokenMatch(buffer,"crease",6))
{
SkipSpaces(&buffer);
obj.crease = fast_atof(buffer);
}
else if (TokenMatch(buffer,"numvert",7))
{
SkipSpaces(&buffer);
unsigned int t = strtoul10(buffer,&buffer);
if (t >= AI_MAX_ALLOC(aiVector3D)) {
throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
}
obj.vertices.reserve(t);
for (unsigned int i = 0; i < t;++i)
{
if (!GetNextLine())
{
DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet");
break;
}
else if (!IsNumeric(*buffer))
{
DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet");
--buffer; // make sure the line is processed a second time
break;
}
obj.vertices.push_back(aiVector3D());
aiVector3D& v = obj.vertices.back();
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x);
}
}
else if (TokenMatch(buffer,"numsurf",7))
{
SkipSpaces(&buffer);
bool Q3DWorkAround = false;
const unsigned int t = strtoul10(buffer,&buffer);
obj.surfaces.reserve(t);
for (unsigned int i = 0; i < t;++i)
{
GetNextLine();
if (!TokenMatch(buffer,"SURF",4))
{
// FIX: this can occur for some files - Quick 3D for
// example writes no surf chunks
if (!Q3DWorkAround)
{
DefaultLogger::get()->warn("AC3D: SURF token was expected");
DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled");
}
--buffer; // make sure the line is processed a second time
// break; --- see fix notes above
Q3DWorkAround = true;
}
SkipSpaces(&buffer);
obj.surfaces.push_back(Surface());
Surface& surf = obj.surfaces.back();
surf.flags = strtoul_cppstyle(buffer);
while (1)
{
if(!GetNextLine())
{
throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete");
}
if (TokenMatch(buffer,"mat",3))
{
SkipSpaces(&buffer);
surf.mat = strtoul10(buffer);
}
else if (TokenMatch(buffer,"refs",4))
{
// --- see fix notes above
if (Q3DWorkAround)
{
if (!surf.entries.empty())
{
buffer -= 6;
break;
}
}
SkipSpaces(&buffer);
const unsigned int m = strtoul10(buffer);
surf.entries.reserve(m);
obj.numRefs += m;
for (unsigned int k = 0; k < m; ++k)
{
if(!GetNextLine())
{
DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete");
break;
}
surf.entries.push_back(Surface::SurfaceEntry());
Surface::SurfaceEntry& entry = surf.entries.back();
entry.first = strtoul10(buffer,&buffer);
SkipSpaces(&buffer);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second);
}
}
else
{
--buffer; // make sure the line is processed a second time
break;
}
}
}
}
}
DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected");
}
// ------------------------------------------------------------------------------------------------
// Convert a material from AC3DImporter::Material to aiMaterial
void AC3DImporter::ConvertMaterial(const Object& object,
const Material& matSrc,
aiMaterial& matDest)
{
aiString s;
if (matSrc.name.length())
{
s.Set(matSrc.name);
matDest.AddProperty(&s,AI_MATKEY_NAME);
}
if (object.texture.length())
{
s.Set(object.texture);
matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
// UV transformation
if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y ||
object.texOffset.x || object.texOffset.y)
{
aiUVTransform transform;
transform.mScaling = object.texRepeat;
transform.mTranslation = object.texOffset;
matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
}
}
matDest.AddProperty<aiColor3D>(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE);
matDest.AddProperty<aiColor3D>(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT);
matDest.AddProperty<aiColor3D>(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE);
matDest.AddProperty<aiColor3D>(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR);
int n;
if (matSrc.shin)
{
n = aiShadingMode_Phong;
matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS);
}
else n = aiShadingMode_Gouraud;
matDest.AddProperty<int>(&n,1,AI_MATKEY_SHADING_MODEL);
float f = 1.f - matSrc.trans;
matDest.AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
}
// ------------------------------------------------------------------------------------------------
// Converts the loaded data to the internal verbose representation
aiNode* AC3DImporter::ConvertObjectSection(Object& object,
std::vector<aiMesh*>& meshes,
std::vector<aiMaterial*>& outMaterials,
const std::vector<Material>& materials,
aiNode* parent)
{
aiNode* node = new aiNode();
node->mParent = parent;
if (object.vertices.size())
{
if (!object.surfaces.size() || !object.numRefs)
{
/* " An object with 7 vertices (no surfaces, no materials defined).
This is a good way of getting point data into AC3D.
The Vertex->create convex-surface/object can be used on these
vertices to 'wrap' a 3d shape around them "
(http://www.opencity.info/html/ac3dfileformat.html)
therefore: if no surfaces are defined return point data only
*/
DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, "
"a point list is returned");
meshes.push_back(new aiMesh());
aiMesh* mesh = meshes.back();
mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size();
aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts)
{
*verts = object.vertices[i];
faces->mNumIndices = 1;
faces->mIndices = new unsigned int[1];
faces->mIndices[0] = i;
}
// use the primary material in this case. this should be the
// default material if all objects of the file contain points
// and no faces.
mesh->mMaterialIndex = 0;
outMaterials.push_back(new aiMaterial());
ConvertMaterial(object, materials[0], *outMaterials.back());
}
else
{
// need to generate one or more meshes for this object.
// find out how many different materials we have
typedef std::pair< unsigned int, unsigned int > IntPair;
typedef std::vector< IntPair > MatTable;
MatTable needMat(materials.size(),IntPair(0,0));
std::vector<Surface>::iterator it,end = object.surfaces.end();
std::vector<Surface::SurfaceEntry>::iterator it2,end2;
for (it = object.surfaces.begin(); it != end; ++it)
{
unsigned int idx = (*it).mat;
if (idx >= needMat.size())
{
DefaultLogger::get()->error("AC3D: material index is out of range");
idx = 0;
}
if ((*it).entries.empty())
{
DefaultLogger::get()->warn("AC3D: surface her zero vertex references");
}
// validate all vertex indices to make sure we won't crash here
for (it2 = (*it).entries.begin(),
end2 = (*it).entries.end(); it2 != end2; ++it2)
{
if ((*it2).first >= object.vertices.size())
{
DefaultLogger::get()->warn("AC3D: Invalid vertex reference");
(*it2).first = 0;
}
}
if (!needMat[idx].first)++node->mNumMeshes;
switch ((*it).flags & 0xf)
{
// closed line
case 0x1:
needMat[idx].first += (unsigned int)(*it).entries.size();
needMat[idx].second += (unsigned int)(*it).entries.size()<<1u;
break;
// unclosed line
case 0x2:
needMat[idx].first += (unsigned int)(*it).entries.size()-1;
needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u;
break;
// 0 == polygon, else unknown
default:
if ((*it).flags & 0xf)
{
DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown");
(*it).flags &= ~(0xf);
}
// the number of faces increments by one, the number
// of vertices by surface.numref.
needMat[idx].first++;
needMat[idx].second += (unsigned int)(*it).entries.size();
};
}
unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes];
unsigned int mat = 0;
const size_t oldm = meshes.size();
for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
cit != cend; ++cit, ++mat)
{
if (!(*cit).first)continue;
// allocate a new aiMesh object
*pip++ = (unsigned int)meshes.size();
aiMesh* mesh = new aiMesh();
meshes.push_back(mesh);
mesh->mMaterialIndex = (unsigned int)outMaterials.size();
outMaterials.push_back(new aiMaterial());
ConvertMaterial(object, materials[mat], *outMaterials.back());
// allocate storage for vertices and normals
mesh->mNumFaces = (*cit).first;
if (mesh->mNumFaces == 0) {
throw DeadlyImportError("AC3D: No faces");
} else if (mesh->mNumFaces > AI_MAX_ALLOC(aiFace)) {
throw DeadlyImportError("AC3D: Too many faces, would run out of memory");
}
aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
mesh->mNumVertices = (*cit).second;
if (mesh->mNumVertices == 0) {
throw DeadlyImportError("AC3D: No vertices");
} else if (mesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) {
throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
}
aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
unsigned int cur = 0;
// allocate UV coordinates, but only if the texture name for the
// surface is not empty
aiVector3D* uv = NULL;
if(object.texture.length())
{
uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
mesh->mNumUVComponents[0] = 2;
}
for (it = object.surfaces.begin(); it != end; ++it)
{
if (mat == (*it).mat)
{
const Surface& src = *it;
// closed polygon
unsigned int type = (*it).flags & 0xf;
if (!type)
{
aiFace& face = *faces++;
if((face.mNumIndices = (unsigned int)src.entries.size()))
{
face.mIndices = new unsigned int[face.mNumIndices];
for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices)
{
const Surface::SurfaceEntry& entry = src.entries[i];
face.mIndices[i] = cur++;
// copy vertex positions
if (static_cast<unsigned>(vertices - mesh->mVertices) >= mesh->mNumVertices) {
throw DeadlyImportError("AC3D: Invalid number of vertices");
}
*vertices = object.vertices[entry.first] + object.translation;
// copy texture coordinates
if (uv)
{
uv->x = entry.second.x;
uv->y = entry.second.y;
++uv;
}
}
}
}
else
{
it2 = (*it).entries.begin();
// either a closed or an unclosed line
unsigned int tmp = (unsigned int)(*it).entries.size();
if (0x2 == type)--tmp;
for (unsigned int m = 0; m < tmp;++m)
{
aiFace& face = *faces++;
face.mNumIndices = 2;
face.mIndices = new unsigned int[2];
face.mIndices[0] = cur++;
face.mIndices[1] = cur++;
// copy vertex positions
if (it2 == (*it).entries.end() ) {
throw DeadlyImportError("AC3D: Bad line");
}
ai_assert((*it2).first < object.vertices.size());
*vertices++ = object.vertices[(*it2).first];
// copy texture coordinates
if (uv)
{
uv->x = (*it2).second.x;
uv->y = (*it2).second.y;
++uv;
}
if (0x1 == type && tmp-1 == m)
{
// if this is a closed line repeat its beginning now
it2 = (*it).entries.begin();
}
else ++it2;
// second point
*vertices++ = object.vertices[(*it2).first];
if (uv)
{
uv->x = (*it2).second.x;
uv->y = (*it2).second.y;
++uv;
}
}
}
}
}
}
// Now apply catmull clark subdivision if necessary. We split meshes into
// materials which is not done by AC3D during smoothing, so we need to
// collect all meshes using the same material group.
if (object.subDiv) {
if (configEvalSubdivision) {
std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name);
std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL);
div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true);
std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm);
// previous meshes are deleted vy Subdivide().
}
else {
DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: "
+object.name);
}
}
}
}
if (object.name.length())
node->mName.Set(object.name);
else
{
// generate a name depending on the type of the node
switch (object.type)
{
case Object::Group:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i",groups++);
break;
case Object::Poly:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i",polys++);
break;
case Object::Light:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i",lights++);
break;
// there shouldn't be more than one world, but we don't care
case Object::World:
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i",worlds++);
break;
}
}
// setup the local transformation matrix of the object
// compute the transformation offset to the parent node
node->mTransformation = aiMatrix4x4 ( object.rotation );
if (object.type == Object::Group || !object.numRefs)
{
node->mTransformation.a4 = object.translation.x;
node->mTransformation.b4 = object.translation.y;
node->mTransformation.c4 = object.translation.z;
}
// add children to the object
if (object.children.size())
{
node->mNumChildren = (unsigned int)object.children.size();
node->mChildren = new aiNode*[node->mNumChildren];
for (unsigned int i = 0; i < node->mNumChildren;++i)
{
node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node);
}
}
return node;
}
// ------------------------------------------------------------------------------------------------
void AC3DImporter::SetupProperties(const Importer* pImp)
{
configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false;
configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false;
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void AC3DImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler)
{
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
// Check whether we can read from the file
if( file.get() == NULL)
throw DeadlyImportError( "Failed to open AC3D file " + pFile + ".");
// allocate storage and copy the contents of the file to a memory buffer
std::vector<char> mBuffer2;
TextFileToBuffer(file.get(),mBuffer2);
buffer = &mBuffer2[0];
mNumMeshes = 0;
lights = polys = worlds = groups = 0;
if (::strncmp(buffer,"AC3D",4)) {
throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
}
// print the file format version to the console
unsigned int version = HexDigitToDecimal( buffer[4] );
char msg[3];
ASSIMP_itoa10(msg,3,version);
DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg);
std::vector<Material> materials;
materials.reserve(5);
std::vector<Object> rootObjects;
rootObjects.reserve(5);
std::vector<aiLight*> lights;
mLights = & lights;
while (GetNextLine())
{
if (TokenMatch(buffer,"MATERIAL",8))
{
materials.push_back(Material());
Material& mat = materials.back();
// manually parse the material ... sscanf would use the buldin atof ...
// Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f
AI_AC_SKIP_TO_NEXT_TOKEN();
if ('\"' == *buffer)
{
AI_AC_GET_STRING(mat.name);
AI_AC_SKIP_TO_NEXT_TOKEN();
}
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin);
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans);
}
LoadObjectSection(rootObjects);
}
if (rootObjects.empty() || !mNumMeshes)
{
throw DeadlyImportError("AC3D: No meshes have been loaded");
}
if (materials.empty())
{
DefaultLogger::get()->warn("AC3D: No material has been found");
materials.push_back(Material());
}
mNumMeshes += (mNumMeshes>>2u) + 1;
std::vector<aiMesh*> meshes;
meshes.reserve(mNumMeshes);
std::vector<aiMaterial*> omaterials;
materials.reserve(mNumMeshes);
// generate a dummy root if there are multiple objects on the top layer
Object* root;
if (1 == rootObjects.size())
root = &rootObjects[0];
else
{
root = new Object();
}
// now convert the imported stuff to our output data structure
pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials);
if (1 != rootObjects.size())delete root;
if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4))
pScene->mRootNode->mName.Set("<AC3DWorld>");
// copy meshes
if (meshes.empty())
{
throw DeadlyImportError("An unknown error occurred during converting");
}
pScene->mNumMeshes = (unsigned int)meshes.size();
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));
// copy materials
pScene->mNumMaterials = (unsigned int)omaterials.size();
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*));
// copy lights
pScene->mNumLights = (unsigned int)lights.size();
if (lights.size())
{
pScene->mLights = new aiLight*[lights.size()];
::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*));
}
}
#endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER

View file

@ -0,0 +1,274 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file ACLoader.h
* @brief Declaration of the .ac importer class.
*/
#ifndef AI_AC3DLOADER_H_INCLUDED
#define AI_AC3DLOADER_H_INCLUDED
#include <vector>
#include "BaseImporter.h"
#include <assimp/types.h>
struct aiNode;
struct aiMesh;
struct aiMaterial;
struct aiLight;
namespace Assimp {
// ---------------------------------------------------------------------------
/** AC3D (*.ac) importer class
*/
class AC3DImporter : public BaseImporter
{
public:
AC3DImporter();
~AC3DImporter();
// Represents an AC3D material
struct Material
{
Material()
: rgb (0.6f,0.6f,0.6f)
, spec (1.f,1.f,1.f)
, shin (0.f)
, trans (0.f)
{}
// base color of the material
aiColor3D rgb;
// ambient color of the material
aiColor3D amb;
// emissive color of the material
aiColor3D emis;
// specular color of the material
aiColor3D spec;
// shininess exponent
float shin;
// transparency. 0 == opaque
float trans;
// name of the material. optional.
std::string name;
};
// Represents an AC3D surface
struct Surface
{
Surface()
: mat (0)
, flags (0)
{}
unsigned int mat,flags;
typedef std::pair<unsigned int, aiVector2D > SurfaceEntry;
std::vector< SurfaceEntry > entries;
};
// Represents an AC3D object
struct Object
{
Object()
: type (World)
, name( "" )
, children()
, texture( "" )
, texRepeat( 1.f, 1.f )
, texOffset( 0.0f, 0.0f )
, rotation()
, translation()
, vertices()
, surfaces()
, numRefs (0)
, subDiv (0)
, crease()
{}
// Type description
enum Type
{
World = 0x0,
Poly = 0x1,
Group = 0x2,
Light = 0x4
} type;
// name of the object
std::string name;
// object children
std::vector<Object> children;
// texture to be assigned to all surfaces of the object
std::string texture;
// texture repat factors (scaling for all coordinates)
aiVector2D texRepeat, texOffset;
// rotation matrix
aiMatrix3x3 rotation;
// translation vector
aiVector3D translation;
// vertices
std::vector<aiVector3D> vertices;
// surfaces
std::vector<Surface> surfaces;
// number of indices (= num verts in verbose format)
unsigned int numRefs;
// number of subdivisions to be performed on the
// imported data
unsigned int subDiv;
// max angle limit for smoothing
float crease;
};
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.
*/
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
protected:
// -------------------------------------------------------------------
/** Return importer meta information.
* See #BaseImporter::GetInfo for the details */
const aiImporterDesc* GetInfo () const;
// -------------------------------------------------------------------
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details*/
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list.*/
void SetupProperties(const Importer* pImp);
private:
// -------------------------------------------------------------------
/** Get the next line from the file.
* @return false if the end of the file was reached*/
bool GetNextLine();
// -------------------------------------------------------------------
/** Load the object section. This method is called recursively to
* load subobjects, the method returns after a 'kids 0' was
* encountered.
* @objects List of output objects*/
void LoadObjectSection(std::vector<Object>& objects);
// -------------------------------------------------------------------
/** Convert all objects into meshes and nodes.
* @param object Current object to work on
* @param meshes Pointer to the list of output meshes
* @param outMaterials List of output materials
* @param materials Material list
* @param Scenegraph node for the object */
aiNode* ConvertObjectSection(Object& object,
std::vector<aiMesh*>& meshes,
std::vector<aiMaterial*>& outMaterials,
const std::vector<Material>& materials,
aiNode* parent = NULL);
// -------------------------------------------------------------------
/** Convert a material
* @param object Current object
* @param matSrc Source material description
* @param matDest Destination material to be filled */
void ConvertMaterial(const Object& object,
const Material& matSrc,
aiMaterial& matDest);
private:
// points to the next data line
const char* buffer;
// Configuration option: if enabled, up to two meshes
// are generated per material: those faces who have
// their bf cull flags set are separated.
bool configSplitBFCull;
// Configuration switch: subdivision surfaces are only
// evaluated if the value is true.
bool configEvalSubdivision;
// counts how many objects we have in the tree.
// basing on this information we can find a
// good estimate how many meshes we'll have in the final scene.
unsigned int mNumMeshes;
// current list of light sources
std::vector<aiLight*>* mLights;
// name counters
unsigned int lights, groups, polys, worlds;
};
} // end of namespace Assimp
#endif // AI_AC3DIMPORTER_H_INC

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,205 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file ASELoader.h
* @brief Definition of the .ASE importer class.
*/
#ifndef AI_ASELOADER_H_INCLUDED
#define AI_ASELOADER_H_INCLUDED
#include "BaseImporter.h"
#include <assimp/types.h>
struct aiNode;
#include "ASEParser.h"
namespace Assimp {
// --------------------------------------------------------------------------------
/** Importer class for the 3DS ASE ASCII format.
*
*/
class ASEImporter : public BaseImporter {
public:
ASEImporter();
~ASEImporter();
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.
*/
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
protected:
// -------------------------------------------------------------------
/** Return importer meta information.
* See #BaseImporter::GetInfo for the details
*/
const aiImporterDesc* GetInfo () const;
// -------------------------------------------------------------------
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list.
*/
void SetupProperties(const Importer* pImp);
private:
// -------------------------------------------------------------------
/** Generate normal vectors basing on smoothing groups
* (in some cases the normal are already contained in the file)
* \param mesh Mesh to work on
* \return false if the normals have been recomputed
*/
bool GenerateNormals(ASE::Mesh& mesh);
// -------------------------------------------------------------------
/** Create valid vertex/normal/UV/color/face lists.
* All elements are unique, faces have only one set of indices
* after this step occurs.
* \param mesh Mesh to work on
*/
void BuildUniqueRepresentation(ASE::Mesh& mesh);
/** Create one-material-per-mesh meshes ;-)
* \param mesh Mesh to work with
* \param Receives the list of all created meshes
*/
void ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOut);
// -------------------------------------------------------------------
/** Convert a material to a aiMaterial object
* \param mat Input material
*/
void ConvertMaterial(ASE::Material& mat);
// -------------------------------------------------------------------
/** Setup the final material indices for each mesh
*/
void BuildMaterialIndices();
// -------------------------------------------------------------------
/** Build the node graph
*/
void BuildNodes(std::vector<ASE::BaseNode*>& nodes);
// -------------------------------------------------------------------
/** Build output cameras
*/
void BuildCameras();
// -------------------------------------------------------------------
/** Build output lights
*/
void BuildLights();
// -------------------------------------------------------------------
/** Build output animations
*/
void BuildAnimations(const std::vector<ASE::BaseNode*>& nodes);
// -------------------------------------------------------------------
/** Add sub nodes to a node
* \param pcParent parent node to be filled
* \param szName Name of the parent node
* \param matrix Current transform
*/
void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
aiNode* pcParent,const char* szName);
void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
aiNode* pcParent,const char* szName,
const aiMatrix4x4& matrix);
void AddMeshes(const ASE::BaseNode* snode,aiNode* node);
// -------------------------------------------------------------------
/** Generate a default material and add it to the parser's list
* Called if no material has been found in the file (rare for ASE,
* but not impossible)
*/
void GenerateDefaultMaterial();
protected:
/** Parser instance */
ASE::Parser* mParser;
/** Buffer to hold the loaded file */
char* mBuffer;
/** Scene to be filled */
aiScene* pcScene;
/** Config options: Recompute the normals in every case - WA
for 3DS Max broken ASE normal export */
bool configRecomputeNormals;
bool noSkeletonMesh;
};
} // end of namespace Assimp
#endif // AI_3DSIMPORTER_H_INC

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,664 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file Defines the helper data structures for importing ASE files */
#ifndef AI_ASEFILEHELPER_H_INC
#define AI_ASEFILEHELPER_H_INC
// public ASSIMP headers
#include <assimp/types.h>
#include <assimp/mesh.h>
#include <assimp/anim.h>
// for some helper routines like IsSpace()
#include "ParsingUtils.h"
#include "qnan.h"
// ASE is quite similar to 3ds. We can reuse some structures
#include "3DSLoader.h"
namespace Assimp {
namespace ASE {
using namespace D3DS;
// ---------------------------------------------------------------------------
/** Helper structure representing an ASE material */
struct Material : public D3DS::Material
{
//! Default constructor
Material() : pcInstance(NULL), bNeed (false)
{}
//! Contains all sub materials of this material
std::vector<Material> avSubMaterials;
//! aiMaterial object
aiMaterial* pcInstance;
//! Can we remove this material?
bool bNeed;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file face */
struct Face : public FaceWithSmoothingGroup
{
//! Default constructor. Initializes everything with 0
Face()
{
mColorIndices[0] = mColorIndices[1] = mColorIndices[2] = 0;
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
{
amUVIndices[i][0] = amUVIndices[i][1] = amUVIndices[i][2] = 0;
}
iMaterial = DEFAULT_MATINDEX;
iFace = 0;
}
//! special value to indicate that no material index has
//! been assigned to a face. The default material index
//! will replace this value later.
static const unsigned int DEFAULT_MATINDEX = 0xFFFFFFFF;
//! Indices into each list of texture coordinates
unsigned int amUVIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS][3];
//! Index into the list of vertex colors
unsigned int mColorIndices[3];
//! (Sub)Material index to be assigned to this face
unsigned int iMaterial;
//! Index of the face. It is not specified whether it is
//! a requirement of the file format that all faces are
//! written in sequential order, so we have to expect this case
unsigned int iFace;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file bone */
struct Bone
{
//! Constructor
Bone()
{
static int iCnt = 0;
// Generate a default name for the bone
char szTemp[128];
::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
mName = szTemp;
}
//! Construction from an existing name
explicit Bone( const std::string& name)
: mName (name)
{}
//! Name of the bone
std::string mName;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file bone vertex */
struct BoneVertex
{
//! Bone and corresponding vertex weight.
//! -1 for unrequired bones ....
std::vector<std::pair<int,float> > mBoneWeights;
//! Position of the bone vertex.
//! MUST be identical to the vertex position
//aiVector3D mPosition;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file animation */
struct Animation
{
enum Type
{
TRACK = 0x0,
BEZIER = 0x1,
TCB = 0x2
} mRotationType, mScalingType, mPositionType;
Animation()
: mRotationType (TRACK)
, mScalingType (TRACK)
, mPositionType (TRACK)
{}
//! List of track rotation keyframes
std::vector< aiQuatKey > akeyRotations;
//! List of track position keyframes
std::vector< aiVectorKey > akeyPositions;
//! List of track scaling keyframes
std::vector< aiVectorKey > akeyScaling;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent the inheritance information of an ASE node */
struct InheritanceInfo
{
//! Default constructor
InheritanceInfo()
{
// set the inheritance flag for all axes by default to true
for (unsigned int i = 0; i < 3;++i)
abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true;
}
//! Inherit the parent's position?, axis order is x,y,z
bool abInheritPosition[3];
//! Inherit the parent's rotation?, axis order is x,y,z
bool abInheritRotation[3];
//! Inherit the parent's scaling?, axis order is x,y,z
bool abInheritScaling[3];
};
// ---------------------------------------------------------------------------
/** Represents an ASE file node. Base class for mesh, light and cameras */
struct BaseNode
{
enum Type {Light, Camera, Mesh, Dummy} mType;
//! Constructor. Creates a default name for the node
explicit BaseNode(Type _mType)
: mType (_mType)
, mProcessed (false)
{
// generate a default name for the node
static int iCnt = 0;
char szTemp[128]; // should be sufficiently large
::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
mName = szTemp;
// Set mTargetPosition to qnan
const float qnan = get_qnan();
mTargetPosition.x = qnan;
}
//! Name of the mesh
std::string mName;
//! Name of the parent of the node
//! "" if there is no parent ...
std::string mParent;
//! Transformation matrix of the node
aiMatrix4x4 mTransform;
//! Target position (target lights and cameras)
aiVector3D mTargetPosition;
//! Specifies which axes transformations a node inherits
//! from its parent ...
InheritanceInfo inherit;
//! Animation channels for the node
Animation mAnim;
//! Needed for lights and cameras: target animation channel
//! Should contain position keys only.
Animation mTargetAnim;
bool mProcessed;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file mesh */
struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode
{
//! Constructor.
Mesh()
: BaseNode (BaseNode::Mesh)
, bSkip (false)
{
// use 2 texture vertex components by default
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
this->mNumUVComponents[c] = 2;
// setup the default material index by default
iMaterialIndex = Face::DEFAULT_MATINDEX;
}
//! List of all texture coordinate sets
std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
//! List of all vertex color sets.
std::vector<aiColor4D> mVertexColors;
//! List of all bone vertices
std::vector<BoneVertex> mBoneVertices;
//! List of all bones
std::vector<Bone> mBones;
//! Material index of the mesh
unsigned int iMaterialIndex;
//! Number of vertex components for each UVW set
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
//! used internally
bool bSkip;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE light source */
struct Light : public BaseNode
{
enum LightType
{
OMNI,
TARGET,
FREE,
DIRECTIONAL
};
//! Constructor.
Light()
: BaseNode (BaseNode::Light)
, mLightType (OMNI)
, mColor (1.f,1.f,1.f)
, mIntensity (1.f) // light is white by default
, mAngle (45.f)
, mFalloff (0.f)
{
}
LightType mLightType;
aiColor3D mColor;
float mIntensity;
float mAngle; // in degrees
float mFalloff;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE camera */
struct Camera : public BaseNode
{
enum CameraType
{
FREE,
TARGET
};
//! Constructor
Camera()
: BaseNode (BaseNode::Camera)
, mFOV (0.75f) // in radians
, mNear (0.1f)
, mFar (1000.f) // could be zero
, mCameraType (FREE)
{
}
float mFOV, mNear, mFar;
CameraType mCameraType;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE helper object (dummy) */
struct Dummy : public BaseNode
{
//! Constructor
Dummy()
: BaseNode (BaseNode::Dummy)
{
}
};
// Parameters to Parser::Parse()
#define AI_ASE_NEW_FILE_FORMAT 200
#define AI_ASE_OLD_FILE_FORMAT 110
// Internally we're a little bit more tolerant
#define AI_ASE_IS_NEW_FILE_FORMAT() (iFileFormat >= 200)
#define AI_ASE_IS_OLD_FILE_FORMAT() (iFileFormat < 200)
// -------------------------------------------------------------------------------
/** \brief Class to parse ASE files
*/
class Parser
{
private:
Parser() {}
public:
// -------------------------------------------------------------------
//! Construct a parser from a given input file which is
//! guaranted to be terminated with zero.
//! @param szFile Input file
//! @param fileFormatDefault Assumed file format version. If the
//! file format is specified in the file the new value replaces
//! the default value.
Parser (const char* szFile, unsigned int fileFormatDefault);
// -------------------------------------------------------------------
//! Parses the file into the parsers internal representation
void Parse();
private:
// -------------------------------------------------------------------
//! Parse the *SCENE block in a file
void ParseLV1SceneBlock();
// -------------------------------------------------------------------
//! Parse the *MESH_SOFTSKINVERTS block in a file
void ParseLV1SoftSkinBlock();
// -------------------------------------------------------------------
//! Parse the *MATERIAL_LIST block in a file
void ParseLV1MaterialListBlock();
// -------------------------------------------------------------------
//! Parse a *<xxx>OBJECT block in a file
//! \param mesh Node to be filled
void ParseLV1ObjectBlock(BaseNode& mesh);
// -------------------------------------------------------------------
//! Parse a *MATERIAL blocks in a material list
//! \param mat Material structure to be filled
void ParseLV2MaterialBlock(Material& mat);
// -------------------------------------------------------------------
//! Parse a *NODE_TM block in a file
//! \param mesh Node (!) object to be filled
void ParseLV2NodeTransformBlock(BaseNode& mesh);
// -------------------------------------------------------------------
//! Parse a *TM_ANIMATION block in a file
//! \param mesh Mesh object to be filled
void ParseLV2AnimationBlock(BaseNode& mesh);
void ParseLV3PosAnimationBlock(ASE::Animation& anim);
void ParseLV3ScaleAnimationBlock(ASE::Animation& anim);
void ParseLV3RotAnimationBlock(ASE::Animation& anim);
// -------------------------------------------------------------------
//! Parse a *MESH block in a file
//! \param mesh Mesh object to be filled
void ParseLV2MeshBlock(Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *LIGHT_SETTINGS block in a file
//! \param light Light object to be filled
void ParseLV2LightSettingsBlock(Light& light);
// -------------------------------------------------------------------
//! Parse a *CAMERA_SETTINGS block in a file
//! \param cam Camera object to be filled
void ParseLV2CameraSettingsBlock(Camera& cam);
// -------------------------------------------------------------------
//! Parse the *MAP_XXXXXX blocks in a material
//! \param map Texture structure to be filled
void ParseLV3MapBlock(Texture& map);
// -------------------------------------------------------------------
//! Parse a *MESH_VERTEX_LIST block in a file
//! \param iNumVertices Value of *MESH_NUMVERTEX, if present.
//! Otherwise zero. This is used to check the consistency of the file.
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
void ParseLV3MeshVertexListBlock(
unsigned int iNumVertices,Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_FACE_LIST block in a file
//! \param iNumFaces Value of *MESH_NUMFACES, if present.
//! Otherwise zero. This is used to check the consistency of the file.
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
void ParseLV3MeshFaceListBlock(
unsigned int iNumFaces,Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_TVERT_LIST block in a file
//! \param iNumVertices Value of *MESH_NUMTVERTEX, if present.
//! Otherwise zero. This is used to check the consistency of the file.
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
//! \param iChannel Output UVW channel
void ParseLV3MeshTListBlock(
unsigned int iNumVertices,Mesh& mesh, unsigned int iChannel = 0);
// -------------------------------------------------------------------
//! Parse a *MESH_TFACELIST block in a file
//! \param iNumFaces Value of *MESH_NUMTVFACES, if present.
//! Otherwise zero. This is used to check the consistency of the file.
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
//! \param iChannel Output UVW channel
void ParseLV3MeshTFaceListBlock(
unsigned int iNumFaces,Mesh& mesh, unsigned int iChannel = 0);
// -------------------------------------------------------------------
//! Parse an additional mapping channel
//! (specified via *MESH_MAPPINGCHANNEL)
//! \param iChannel Channel index to be filled
//! \param mesh Mesh object to be filled
void ParseLV3MappingChannel(
unsigned int iChannel, Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_CVERTLIST block in a file
//! \param iNumVertices Value of *MESH_NUMCVERTEX, if present.
//! Otherwise zero. This is used to check the consistency of the file.
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
void ParseLV3MeshCListBlock(
unsigned int iNumVertices, Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_CFACELIST block in a file
//! \param iNumFaces Value of *MESH_NUMCVFACES, if present.
//! Otherwise zero. This is used to check the consistency of the file.
//! A warning is sent to the logger if the validations fails.
//! \param mesh Mesh object to be filled
void ParseLV3MeshCFaceListBlock(
unsigned int iNumFaces, Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_NORMALS block in a file
//! \param mesh Mesh object to be filled
void ParseLV3MeshNormalListBlock(Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_WEIGHTSblock in a file
//! \param mesh Mesh object to be filled
void ParseLV3MeshWeightsBlock(Mesh& mesh);
// -------------------------------------------------------------------
//! Parse the bone list of a file
//! \param mesh Mesh object to be filled
//! \param iNumBones Number of bones in the mesh
void ParseLV4MeshBones(unsigned int iNumBones,Mesh& mesh);
// -------------------------------------------------------------------
//! Parse the bone vertices list of a file
//! \param mesh Mesh object to be filled
//! \param iNumVertices Number of vertices to be parsed
void ParseLV4MeshBonesVertices(unsigned int iNumVertices,Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *MESH_FACE block in a file
//! \param out receive the face data
void ParseLV4MeshFace(ASE::Face& out);
// -------------------------------------------------------------------
//! Parse a *MESH_VERT block in a file
//! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...)
//! \param apOut Output buffer (3 floats)
//! \param rIndexOut Output index
void ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut);
// -------------------------------------------------------------------
//! Parse a *MESH_VERT block in a file
//! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...)
//! \param apOut Output buffer (3 floats)
void ParseLV4MeshFloatTriple(float* apOut);
// -------------------------------------------------------------------
//! Parse a *MESH_TFACE block in a file
//! (also works for MESH_CFACE)
//! \param apOut Output buffer (3 ints)
//! \param rIndexOut Output index
void ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut);
// -------------------------------------------------------------------
//! Parse a *MESH_TFACE block in a file
//! (also works for MESH_CFACE)
//! \param apOut Output buffer (3 ints)
void ParseLV4MeshLongTriple(unsigned int* apOut);
// -------------------------------------------------------------------
//! Parse a single float element
//! \param fOut Output float
void ParseLV4MeshFloat(float& fOut);
// -------------------------------------------------------------------
//! Parse a single int element
//! \param iOut Output integer
void ParseLV4MeshLong(unsigned int& iOut);
// -------------------------------------------------------------------
//! Skip everything to the next: '*' or '\0'
bool SkipToNextToken();
// -------------------------------------------------------------------
//! Skip the current section until the token after the closing }.
//! This function handles embedded subsections correctly
bool SkipSection();
// -------------------------------------------------------------------
//! Output a warning to the logger
//! \param szWarn Warn message
void LogWarning(const char* szWarn);
// -------------------------------------------------------------------
//! Output a message to the logger
//! \param szWarn Message
void LogInfo(const char* szWarn);
// -------------------------------------------------------------------
//! Output an error to the logger
//! \param szWarn Error message
AI_WONT_RETURN void LogError(const char* szWarn) AI_WONT_RETURN_SUFFIX;
// -------------------------------------------------------------------
//! Parse a string, enclosed in double quotation marks
//! \param out Output string
//! \param szName Name of the enclosing element -> used in error
//! messages.
//! \return false if an error occurred
bool ParseString(std::string& out,const char* szName);
public:
//! Pointer to current data
const char* filePtr;
//! background color to be passed to the viewer
//! QNAN if none was found
aiColor3D m_clrBackground;
//! Base ambient color to be passed to all materials
//! QNAN if none was found
aiColor3D m_clrAmbient;
//! List of all materials found in the file
std::vector<Material> m_vMaterials;
//! List of all meshes found in the file
std::vector<Mesh> m_vMeshes;
//! List of all dummies found in the file
std::vector<Dummy> m_vDummies;
//! List of all lights found in the file
std::vector<Light> m_vLights;
//! List of all cameras found in the file
std::vector<Camera> m_vCameras;
//! Current line in the file
unsigned int iLineNumber;
//! First frame
unsigned int iFirstFrame;
//! Last frame
unsigned int iLastFrame;
//! Frame speed - frames per second
unsigned int iFrameSpeed;
//! Ticks per frame
unsigned int iTicksPerFrame;
//! true if the last character read was an end-line character
bool bLastWasEndLine;
//! File format version
unsigned int iFileFormat;
};
} // Namespace ASE
} // Namespace ASSIMP
#endif // !! include guard

View file

@ -0,0 +1,768 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file AssbinExporter.cpp
* ASSBIN exporter main code
*/
#include "assbin_chunks.h"
#include <assimp/version.h>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/Exporter.hpp>
#include "ProcessHelper.h"
#include "Exceptional.h"
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
# include <zlib.h>
#else
# include "../contrib/zlib/zlib.h"
#endif
#include <time.h>
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
using namespace Assimp;
namespace Assimp {
template <typename T>
size_t Write(IOStream * stream, const T& v)
{
return stream->Write( &v, sizeof(T), 1 );
}
// -----------------------------------------------------------------------------------
// Serialize an aiString
template <>
inline size_t Write<aiString>(IOStream * stream, const aiString& s)
{
const size_t s2 = (uint32_t)s.length;
stream->Write(&s,4,1);
stream->Write(s.data,s2,1);
return s2+4;
}
// -----------------------------------------------------------------------------------
// Serialize an unsigned int as uint32_t
template <>
inline size_t Write<unsigned int>(IOStream * stream, const unsigned int& w)
{
const uint32_t t = (uint32_t)w;
if (w > t) {
// this shouldn't happen, integers in Assimp data structures never exceed 2^32
throw new DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
}
stream->Write(&t,4,1);
return 4;
}
// -----------------------------------------------------------------------------------
// Serialize an unsigned int as uint16_t
template <>
inline size_t Write<uint16_t>(IOStream * stream, const uint16_t& w)
{
static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2");
stream->Write(&w,2,1);
return 2;
}
// -----------------------------------------------------------------------------------
// Serialize a float
template <>
inline size_t Write<float>(IOStream * stream, const float& f)
{
static_assert(sizeof(float)==4, "sizeof(float)==4");
stream->Write(&f,4,1);
return 4;
}
// -----------------------------------------------------------------------------------
// Serialize a double
template <>
inline size_t Write<double>(IOStream * stream, const double& f)
{
static_assert(sizeof(double)==8, "sizeof(double)==8");
stream->Write(&f,8,1);
return 8;
}
// -----------------------------------------------------------------------------------
// Serialize a vec3
template <>
inline size_t Write<aiVector3D>(IOStream * stream, const aiVector3D& v)
{
size_t t = Write<float>(stream,v.x);
t += Write<float>(stream,v.y);
t += Write<float>(stream,v.z);
return t;
}
// -----------------------------------------------------------------------------------
// Serialize a color value
template <>
inline size_t Write<aiColor4D>(IOStream * stream, const aiColor4D& v)
{
size_t t = Write<float>(stream,v.r);
t += Write<float>(stream,v.g);
t += Write<float>(stream,v.b);
t += Write<float>(stream,v.a);
return t;
}
// -----------------------------------------------------------------------------------
// Serialize a quaternion
template <>
inline size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v)
{
size_t t = Write<float>(stream,v.w);
t += Write<float>(stream,v.x);
t += Write<float>(stream,v.y);
t += Write<float>(stream,v.z);
return 16;
}
// -----------------------------------------------------------------------------------
// Serialize a vertex weight
template <>
inline size_t Write<aiVertexWeight>(IOStream * stream, const aiVertexWeight& v)
{
size_t t = Write<unsigned int>(stream,v.mVertexId);
return t+Write<float>(stream,v.mWeight);
}
// -----------------------------------------------------------------------------------
// Serialize a mat4x4
template <>
inline size_t Write<aiMatrix4x4>(IOStream * stream, const aiMatrix4x4& m)
{
for (unsigned int i = 0; i < 4;++i) {
for (unsigned int i2 = 0; i2 < 4;++i2) {
Write<float>(stream,m[i][i2]);
}
}
return 64;
}
// -----------------------------------------------------------------------------------
// Serialize an aiVectorKey
template <>
inline size_t Write<aiVectorKey>(IOStream * stream, const aiVectorKey& v)
{
const size_t t = Write<double>(stream,v.mTime);
return t + Write<aiVector3D>(stream,v.mValue);
}
// -----------------------------------------------------------------------------------
// Serialize an aiQuatKey
template <>
inline size_t Write<aiQuatKey>(IOStream * stream, const aiQuatKey& v)
{
const size_t t = Write<double>(stream,v.mTime);
return t + Write<aiQuaternion>(stream,v.mValue);
}
template <typename T>
inline size_t WriteBounds(IOStream * stream, const T* in, unsigned int size)
{
T minc,maxc;
ArrayBounds(in,size,minc,maxc);
const size_t t = Write<T>(stream,minc);
return t + Write<T>(stream,maxc);
}
// We use this to write out non-byte arrays so that we write using the specializations.
// This way we avoid writing out extra bytes that potentially come from struct alignment.
template <typename T>
inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
{
size_t n = 0;
for (unsigned int i=0; i<size; i++) n += Write<T>(stream,in[i]);
return n;
}
// ----------------------------------------------------------------------------------
/** @class AssbinChunkWriter
* @brief Chunk writer mechanism for the .assbin file structure
*
* This is a standard in-memory IOStream (most of the code is based on BlobIOStream),
* the difference being that this takes another IOStream as a "container" in the
* constructor, and when it is destroyed, it appends the magic number, the chunk size,
* and the chunk contents to the container stream. This allows relatively easy chunk
* chunk construction, even recursively.
*/
class AssbinChunkWriter : public IOStream
{
private:
uint8_t* buffer;
uint32_t magic;
IOStream * container;
size_t cur_size, cursor, initial;
private:
// -------------------------------------------------------------------
void Grow(size_t need = 0)
{
size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
const uint8_t* const old = buffer;
buffer = new uint8_t[new_size];
if (old) {
memcpy(buffer,old,cur_size);
delete[] old;
}
cur_size = new_size;
}
public:
AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096)
: buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial)
{
}
virtual ~AssbinChunkWriter()
{
if (container) {
container->Write( &magic, sizeof(uint32_t), 1 );
container->Write( &cursor, sizeof(uint32_t), 1 );
container->Write( buffer, 1, cursor );
}
if (buffer) delete[] buffer;
}
void * GetBufferPointer() { return buffer; }
// -------------------------------------------------------------------
virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; }
virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; }
virtual size_t Tell() const { return cursor; }
virtual void Flush() { }
virtual size_t FileSize() const
{
return cursor;
}
// -------------------------------------------------------------------
virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount)
{
pSize *= pCount;
if (cursor + pSize > cur_size) {
Grow(cursor + pSize);
}
memcpy(buffer+cursor, pvBuffer, pSize);
cursor += pSize;
return pCount;
}
};
// ----------------------------------------------------------------------------------
/** @class AssbinExport
* @brief Assbin exporter class
*
* This class performs the .assbin exporting, and is responsible for the file layout.
*/
class AssbinExport
{
private:
bool shortened;
bool compressed;
protected:
// -----------------------------------------------------------------------------------
void WriteBinaryNode( IOStream * container, const aiNode* node)
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
Write<aiString>(&chunk,node->mName);
Write<aiMatrix4x4>(&chunk,node->mTransformation);
Write<unsigned int>(&chunk,node->mNumChildren);
Write<unsigned int>(&chunk,node->mNumMeshes);
for (unsigned int i = 0; i < node->mNumMeshes;++i) {
Write<unsigned int>(&chunk,node->mMeshes[i]);
}
for (unsigned int i = 0; i < node->mNumChildren;++i) {
WriteBinaryNode( &chunk, node->mChildren[i] );
}
}
// -----------------------------------------------------------------------------------
void WriteBinaryTexture(IOStream * container, const aiTexture* tex)
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE );
Write<unsigned int>(&chunk,tex->mWidth);
Write<unsigned int>(&chunk,tex->mHeight);
chunk.Write( tex->achFormatHint, sizeof(char), 4 );
if(!shortened) {
if (!tex->mHeight) {
chunk.Write(tex->pcData,1,tex->mWidth);
}
else {
chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4);
}
}
}
// -----------------------------------------------------------------------------------
void WriteBinaryBone(IOStream * container, const aiBone* b)
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE );
Write<aiString>(&chunk,b->mName);
Write<unsigned int>(&chunk,b->mNumWeights);
Write<aiMatrix4x4>(&chunk,b->mOffsetMatrix);
// for the moment we write dumb min/max values for the bones, too.
// maybe I'll add a better, hash-like solution later
if (shortened) {
WriteBounds(&chunk,b->mWeights,b->mNumWeights);
} // else write as usual
else WriteArray<aiVertexWeight>(&chunk,b->mWeights,b->mNumWeights);
}
// -----------------------------------------------------------------------------------
void WriteBinaryMesh(IOStream * container, const aiMesh* mesh)
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH );
Write<unsigned int>(&chunk,mesh->mPrimitiveTypes);
Write<unsigned int>(&chunk,mesh->mNumVertices);
Write<unsigned int>(&chunk,mesh->mNumFaces);
Write<unsigned int>(&chunk,mesh->mNumBones);
Write<unsigned int>(&chunk,mesh->mMaterialIndex);
// first of all, write bits for all existent vertex components
unsigned int c = 0;
if (mesh->mVertices) {
c |= ASSBIN_MESH_HAS_POSITIONS;
}
if (mesh->mNormals) {
c |= ASSBIN_MESH_HAS_NORMALS;
}
if (mesh->mTangents && mesh->mBitangents) {
c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS;
}
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
if (!mesh->mTextureCoords[n]) {
break;
}
c |= ASSBIN_MESH_HAS_TEXCOORD(n);
}
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
if (!mesh->mColors[n]) {
break;
}
c |= ASSBIN_MESH_HAS_COLOR(n);
}
Write<unsigned int>(&chunk,c);
aiVector3D minVec, maxVec;
if (mesh->mVertices) {
if (shortened) {
WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices);
} // else write as usual
else WriteArray<aiVector3D>(&chunk,mesh->mVertices,mesh->mNumVertices);
}
if (mesh->mNormals) {
if (shortened) {
WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices);
} // else write as usual
else WriteArray<aiVector3D>(&chunk,mesh->mNormals,mesh->mNumVertices);
}
if (mesh->mTangents && mesh->mBitangents) {
if (shortened) {
WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices);
WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices);
} // else write as usual
else {
WriteArray<aiVector3D>(&chunk,mesh->mTangents,mesh->mNumVertices);
WriteArray<aiVector3D>(&chunk,mesh->mBitangents,mesh->mNumVertices);
}
}
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
if (!mesh->mColors[n])
break;
if (shortened) {
WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices);
} // else write as usual
else WriteArray<aiColor4D>(&chunk,mesh->mColors[n],mesh->mNumVertices);
}
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
if (!mesh->mTextureCoords[n])
break;
// write number of UV components
Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
if (shortened) {
WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
} // else write as usual
else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
}
// write faces. There are no floating-point calculations involved
// in these, so we can write a simple hash over the face data
// to the dump file. We generate a single 32 Bit hash for 512 faces
// using Assimp's standard hashing function.
if (shortened) {
unsigned int processed = 0;
for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) {
uint32_t hash = 0;
for (unsigned int a = 0; a < job;++a) {
const aiFace& f = mesh->mFaces[processed+a];
uint32_t tmp = f.mNumIndices;
hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
for (unsigned int i = 0; i < f.mNumIndices; ++i) {
static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff");
tmp = static_cast<uint32_t>( f.mIndices[i] );
hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
}
}
Write<unsigned int>(&chunk,hash);
}
}
else // else write as usual
{
// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
const aiFace& f = mesh->mFaces[i];
static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
Write<uint16_t>(&chunk,f.mNumIndices);
for (unsigned int a = 0; a < f.mNumIndices;++a) {
if (mesh->mNumVertices < (1u<<16)) {
Write<uint16_t>(&chunk,f.mIndices[a]);
}
else Write<unsigned int>(&chunk,f.mIndices[a]);
}
}
}
// write bones
if (mesh->mNumBones) {
for (unsigned int a = 0; a < mesh->mNumBones;++a) {
const aiBone* b = mesh->mBones[a];
WriteBinaryBone(&chunk,b);
}
}
}
// -----------------------------------------------------------------------------------
void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop)
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY );
Write<aiString>(&chunk,prop->mKey);
Write<unsigned int>(&chunk,prop->mSemantic);
Write<unsigned int>(&chunk,prop->mIndex);
Write<unsigned int>(&chunk,prop->mDataLength);
Write<unsigned int>(&chunk,(unsigned int)prop->mType);
chunk.Write(prop->mData,1,prop->mDataLength);
}
// -----------------------------------------------------------------------------------
void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat)
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL);
Write<unsigned int>(&chunk,mat->mNumProperties);
for (unsigned int i = 0; i < mat->mNumProperties;++i) {
WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]);
}
}
// -----------------------------------------------------------------------------------
void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd)
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM );
Write<aiString>(&chunk,nd->mNodeName);
Write<unsigned int>(&chunk,nd->mNumPositionKeys);
Write<unsigned int>(&chunk,nd->mNumRotationKeys);
Write<unsigned int>(&chunk,nd->mNumScalingKeys);
Write<unsigned int>(&chunk,nd->mPreState);
Write<unsigned int>(&chunk,nd->mPostState);
if (nd->mPositionKeys) {
if (shortened) {
WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
} // else write as usual
else WriteArray<aiVectorKey>(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
}
if (nd->mRotationKeys) {
if (shortened) {
WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
} // else write as usual
else WriteArray<aiQuatKey>(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
}
if (nd->mScalingKeys) {
if (shortened) {
WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
} // else write as usual
else WriteArray<aiVectorKey>(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
}
}
// -----------------------------------------------------------------------------------
void WriteBinaryAnim( IOStream * container, const aiAnimation* anim )
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION );
Write<aiString>(&chunk,anim->mName);
Write<double>(&chunk,anim->mDuration);
Write<double>(&chunk,anim->mTicksPerSecond);
Write<unsigned int>(&chunk,anim->mNumChannels);
for (unsigned int a = 0; a < anim->mNumChannels;++a) {
const aiNodeAnim* nd = anim->mChannels[a];
WriteBinaryNodeAnim(&chunk,nd);
}
}
// -----------------------------------------------------------------------------------
void WriteBinaryLight( IOStream * container, const aiLight* l )
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT );
Write<aiString>(&chunk,l->mName);
Write<unsigned int>(&chunk,l->mType);
if (l->mType != aiLightSource_DIRECTIONAL) {
Write<float>(&chunk,l->mAttenuationConstant);
Write<float>(&chunk,l->mAttenuationLinear);
Write<float>(&chunk,l->mAttenuationQuadratic);
}
Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorDiffuse);
Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorSpecular);
Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorAmbient);
if (l->mType == aiLightSource_SPOT) {
Write<float>(&chunk,l->mAngleInnerCone);
Write<float>(&chunk,l->mAngleOuterCone);
}
}
// -----------------------------------------------------------------------------------
void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
Write<aiString>(&chunk,cam->mName);
Write<aiVector3D>(&chunk,cam->mPosition);
Write<aiVector3D>(&chunk,cam->mLookAt);
Write<aiVector3D>(&chunk,cam->mUp);
Write<float>(&chunk,cam->mHorizontalFOV);
Write<float>(&chunk,cam->mClipPlaneNear);
Write<float>(&chunk,cam->mClipPlaneFar);
Write<float>(&chunk,cam->mAspect);
}
// -----------------------------------------------------------------------------------
void WriteBinaryScene( IOStream * container, const aiScene* scene)
{
AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE );
// basic scene information
Write<unsigned int>(&chunk,scene->mFlags);
Write<unsigned int>(&chunk,scene->mNumMeshes);
Write<unsigned int>(&chunk,scene->mNumMaterials);
Write<unsigned int>(&chunk,scene->mNumAnimations);
Write<unsigned int>(&chunk,scene->mNumTextures);
Write<unsigned int>(&chunk,scene->mNumLights);
Write<unsigned int>(&chunk,scene->mNumCameras);
// write node graph
WriteBinaryNode( &chunk, scene->mRootNode );
// write all meshes
for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
const aiMesh* mesh = scene->mMeshes[i];
WriteBinaryMesh( &chunk,mesh);
}
// write materials
for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
const aiMaterial* mat = scene->mMaterials[i];
WriteBinaryMaterial(&chunk,mat);
}
// write all animations
for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
const aiAnimation* anim = scene->mAnimations[i];
WriteBinaryAnim(&chunk,anim);
}
// write all textures
for (unsigned int i = 0; i < scene->mNumTextures;++i) {
const aiTexture* mesh = scene->mTextures[i];
WriteBinaryTexture(&chunk,mesh);
}
// write lights
for (unsigned int i = 0; i < scene->mNumLights;++i) {
const aiLight* l = scene->mLights[i];
WriteBinaryLight(&chunk,l);
}
// write cameras
for (unsigned int i = 0; i < scene->mNumCameras;++i) {
const aiCamera* cam = scene->mCameras[i];
WriteBinaryCamera(&chunk,cam);
}
}
public:
AssbinExport()
: shortened(false), compressed(false) // temporary settings until properties are introduced for exporters
{
}
// -----------------------------------------------------------------------------------
// Write a binary model dump
void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
{
IOStream * out = pIOSystem->Open( pFile, "wb" );
if (!out) return;
time_t tt = time(NULL);
tm* p = gmtime(&tt);
// header
char s[64];
memset( s, 0, 64 );
#if _MSC_VER >= 1400
sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p));
#else
ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p));
#endif
out->Write( s, 44, 1 );
// == 44 bytes
Write<unsigned int>( out, ASSBIN_VERSION_MAJOR );
Write<unsigned int>( out, ASSBIN_VERSION_MINOR );
Write<unsigned int>( out, aiGetVersionRevision() );
Write<unsigned int>( out, aiGetCompileFlags() );
Write<uint16_t>( out, shortened );
Write<uint16_t>( out, compressed );
// == 20 bytes
char buff[256];
strncpy(buff,pFile,256);
out->Write(buff,sizeof(char),256);
char cmd[] = "\0";
strncpy(buff,cmd,128);
out->Write(buff,sizeof(char),128);
// leave 64 bytes free for future extensions
memset(buff,0xcd,64);
out->Write(buff,sizeof(char),64);
// == 435 bytes
// ==== total header size: 512 bytes
ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH );
// Up to here the data is uncompressed. For compressed files, the rest
// is compressed using standard DEFLATE from zlib.
if (compressed)
{
AssbinChunkWriter uncompressedStream( NULL, 0 );
WriteBinaryScene( &uncompressedStream, pScene );
uLongf uncompressedSize = uncompressedStream.Tell();
uLongf compressedSize = (uLongf)(uncompressedStream.Tell() * 1.001 + 12.);
uint8_t* compressedBuffer = new uint8_t[ compressedSize ];
compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 );
out->Write( &uncompressedSize, sizeof(uint32_t), 1 );
out->Write( compressedBuffer, sizeof(char), compressedSize );
delete[] compressedBuffer;
}
else
{
WriteBinaryScene( out, pScene );
}
pIOSystem->Close( out );
}
};
void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
{
AssbinExport exporter;
exporter.WriteBinaryDump( pFile, pIOSystem, pScene );
}
} // end of namespace Assimp
#endif // ASSIMP_BUILD_NO_ASSBIN_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View file

@ -0,0 +1,49 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file AssbinExporter.h
* ASSBIN Exporter Main Header
*/
#ifndef AI_ASSBINEXPORTER_H_INC
#define AI_ASSBINEXPORTER_H_INC
// nothing really needed here - reserved for future use like properties
#endif

View file

@ -0,0 +1,686 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file AssbinLoader.cpp
* @brief Implementation of the .assbin importer class
*
* see assbin_chunks.h
*/
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
// internal headers
#include "AssbinLoader.h"
#include "assbin_chunks.h"
#include "MemoryIOWrapper.h"
#include <assimp/mesh.h>
#include <assimp/anim.h>
#include <assimp/scene.h>
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
# include <zlib.h>
#else
# include <contrib/zlib/zlib.h>
#endif
using namespace Assimp;
static const aiImporterDesc desc = {
".assbin Importer",
"Gargaj / Conspiracy",
"",
"",
aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
0,
0,
0,
0,
"assbin"
};
const aiImporterDesc* AssbinImporter::GetInfo() const
{
return &desc;
}
bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const
{
IOStream * in = pIOHandler->Open(pFile);
if (!in)
return false;
char s[32];
in->Read( s, sizeof(char), 32 );
pIOHandler->Close(in);
return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0;
}
template <typename T>
T Read(IOStream * stream)
{
T t;
stream->Read( &t, sizeof(T), 1 );
return t;
}
template <>
aiVector3D Read<aiVector3D>(IOStream * stream)
{
aiVector3D v;
v.x = Read<float>(stream);
v.y = Read<float>(stream);
v.z = Read<float>(stream);
return v;
}
template <>
aiColor4D Read<aiColor4D>(IOStream * stream)
{
aiColor4D c;
c.r = Read<float>(stream);
c.g = Read<float>(stream);
c.b = Read<float>(stream);
c.a = Read<float>(stream);
return c;
}
template <>
aiQuaternion Read<aiQuaternion>(IOStream * stream)
{
aiQuaternion v;
v.w = Read<float>(stream);
v.x = Read<float>(stream);
v.y = Read<float>(stream);
v.z = Read<float>(stream);
return v;
}
template <>
aiString Read<aiString>(IOStream * stream)
{
aiString s;
stream->Read(&s.length,4,1);
stream->Read(s.data,s.length,1);
s.data[s.length] = 0;
return s;
}
template <>
aiVertexWeight Read<aiVertexWeight>(IOStream * stream)
{
aiVertexWeight w;
w.mVertexId = Read<unsigned int>(stream);
w.mWeight = Read<float>(stream);
return w;
}
template <>
aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream)
{
aiMatrix4x4 m;
for (unsigned int i = 0; i < 4;++i) {
for (unsigned int i2 = 0; i2 < 4;++i2) {
m[i][i2] = Read<float>(stream);
}
}
return m;
}
template <>
aiVectorKey Read<aiVectorKey>(IOStream * stream)
{
aiVectorKey v;
v.mTime = Read<double>(stream);
v.mValue = Read<aiVector3D>(stream);
return v;
}
template <>
aiQuatKey Read<aiQuatKey>(IOStream * stream)
{
aiQuatKey v;
v.mTime = Read<double>(stream);
v.mValue = Read<aiQuaternion>(stream);
return v;
}
template <typename T>
void ReadArray(IOStream * stream, T * out, unsigned int size)
{
for (unsigned int i=0; i<size; i++) out[i] = Read<T>(stream);
}
template <typename T> void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n )
{
// not sure what to do here, the data isn't really useful.
stream->Seek( sizeof(T) * n, aiOrigin_CUR );
}
void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node )
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AINODE);
/*uint32_t size =*/ Read<uint32_t>(stream);
*node = new aiNode();
(*node)->mName = Read<aiString>(stream);
(*node)->mTransformation = Read<aiMatrix4x4>(stream);
(*node)->mNumChildren = Read<unsigned int>(stream);
(*node)->mNumMeshes = Read<unsigned int>(stream);
if ((*node)->mNumMeshes)
{
(*node)->mMeshes = new unsigned int[(*node)->mNumMeshes];
for (unsigned int i = 0; i < (*node)->mNumMeshes; ++i) {
(*node)->mMeshes[i] = Read<unsigned int>(stream);
}
}
if ((*node)->mNumChildren)
{
(*node)->mChildren = new aiNode*[(*node)->mNumChildren];
for (unsigned int i = 0; i < (*node)->mNumChildren; ++i) {
ReadBinaryNode( stream, &(*node)->mChildren[i] );
}
}
}
// -----------------------------------------------------------------------------------
void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b )
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AIBONE);
/*uint32_t size =*/ Read<uint32_t>(stream);
b->mName = Read<aiString>(stream);
b->mNumWeights = Read<unsigned int>(stream);
b->mOffsetMatrix = Read<aiMatrix4x4>(stream);
// for the moment we write dumb min/max values for the bones, too.
// maybe I'll add a better, hash-like solution later
if (shortened)
{
ReadBounds(stream,b->mWeights,b->mNumWeights);
} // else write as usual
else
{
b->mWeights = new aiVertexWeight[b->mNumWeights];
ReadArray<aiVertexWeight>(stream,b->mWeights,b->mNumWeights);
}
}
void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AIMESH);
/*uint32_t size =*/ Read<uint32_t>(stream);
mesh->mPrimitiveTypes = Read<unsigned int>(stream);
mesh->mNumVertices = Read<unsigned int>(stream);
mesh->mNumFaces = Read<unsigned int>(stream);
mesh->mNumBones = Read<unsigned int>(stream);
mesh->mMaterialIndex = Read<unsigned int>(stream);
// first of all, write bits for all existent vertex components
unsigned int c = Read<unsigned int>(stream);
if (c & ASSBIN_MESH_HAS_POSITIONS)
{
if (shortened) {
ReadBounds(stream,mesh->mVertices,mesh->mNumVertices);
} // else write as usual
else
{
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
ReadArray<aiVector3D>(stream,mesh->mVertices,mesh->mNumVertices);
}
}
if (c & ASSBIN_MESH_HAS_NORMALS)
{
if (shortened) {
ReadBounds(stream,mesh->mNormals,mesh->mNumVertices);
} // else write as usual
else
{
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
ReadArray<aiVector3D>(stream,mesh->mNormals,mesh->mNumVertices);
}
}
if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS)
{
if (shortened) {
ReadBounds(stream,mesh->mTangents,mesh->mNumVertices);
ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices);
} // else write as usual
else
{
mesh->mTangents = new aiVector3D[mesh->mNumVertices];
ReadArray<aiVector3D>(stream,mesh->mTangents,mesh->mNumVertices);
mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
ReadArray<aiVector3D>(stream,mesh->mBitangents,mesh->mNumVertices);
}
}
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n)
{
if (!(c & ASSBIN_MESH_HAS_COLOR(n)))
break;
if (shortened)
{
ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices);
} // else write as usual
else
{
mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
ReadArray<aiColor4D>(stream,mesh->mColors[n],mesh->mNumVertices);
}
}
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
{
if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n)))
break;
// write number of UV components
mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
if (shortened) {
ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
} // else write as usual
else
{
mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
ReadArray<aiVector3D>(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
}
}
// write faces. There are no floating-point calculations involved
// in these, so we can write a simple hash over the face data
// to the dump file. We generate a single 32 Bit hash for 512 faces
// using Assimp's standard hashing function.
if (shortened) {
Read<unsigned int>(stream);
}
else // else write as usual
{
// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
mesh->mFaces = new aiFace[mesh->mNumFaces];
for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
aiFace& f = mesh->mFaces[i];
static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
f.mNumIndices = Read<uint16_t>(stream);
f.mIndices = new unsigned int[f.mNumIndices];
for (unsigned int a = 0; a < f.mNumIndices;++a) {
if (mesh->mNumVertices < (1u<<16))
{
f.mIndices[a] = Read<uint16_t>(stream);
}
else
{
f.mIndices[a] = Read<unsigned int>(stream);
}
}
}
}
// write bones
if (mesh->mNumBones) {
mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones];
for (unsigned int a = 0; a < mesh->mNumBones;++a) {
mesh->mBones[a] = new aiBone();
ReadBinaryBone(stream,mesh->mBones[a]);
}
}
}
void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop)
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY);
/*uint32_t size =*/ Read<uint32_t>(stream);
prop->mKey = Read<aiString>(stream);
prop->mSemantic = Read<unsigned int>(stream);
prop->mIndex = Read<unsigned int>(stream);
prop->mDataLength = Read<unsigned int>(stream);
prop->mType = (aiPropertyTypeInfo)Read<unsigned int>(stream);
prop->mData = new char [ prop->mDataLength ];
stream->Read(prop->mData,1,prop->mDataLength);
}
// -----------------------------------------------------------------------------------
void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat)
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIAL);
/*uint32_t size =*/ Read<uint32_t>(stream);
mat->mNumAllocated = mat->mNumProperties = Read<unsigned int>(stream);
if (mat->mNumProperties)
{
if (mat->mProperties)
{
delete[] mat->mProperties;
}
mat->mProperties = new aiMaterialProperty*[mat->mNumProperties];
for (unsigned int i = 0; i < mat->mNumProperties;++i) {
mat->mProperties[i] = new aiMaterialProperty();
ReadBinaryMaterialProperty( stream, mat->mProperties[i]);
}
}
}
// -----------------------------------------------------------------------------------
void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AINODEANIM);
/*uint32_t size =*/ Read<uint32_t>(stream);
nd->mNodeName = Read<aiString>(stream);
nd->mNumPositionKeys = Read<unsigned int>(stream);
nd->mNumRotationKeys = Read<unsigned int>(stream);
nd->mNumScalingKeys = Read<unsigned int>(stream);
nd->mPreState = (aiAnimBehaviour)Read<unsigned int>(stream);
nd->mPostState = (aiAnimBehaviour)Read<unsigned int>(stream);
if (nd->mNumPositionKeys) {
if (shortened) {
ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys);
} // else write as usual
else {
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
ReadArray<aiVectorKey>(stream,nd->mPositionKeys,nd->mNumPositionKeys);
}
}
if (nd->mNumRotationKeys) {
if (shortened) {
ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys);
} // else write as usual
else
{
nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
ReadArray<aiQuatKey>(stream,nd->mRotationKeys,nd->mNumRotationKeys);
}
}
if (nd->mNumScalingKeys) {
if (shortened) {
ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys);
} // else write as usual
else
{
nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
ReadArray<aiVectorKey>(stream,nd->mScalingKeys,nd->mNumScalingKeys);
}
}
}
// -----------------------------------------------------------------------------------
void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AIANIMATION);
/*uint32_t size =*/ Read<uint32_t>(stream);
anim->mName = Read<aiString> (stream);
anim->mDuration = Read<double> (stream);
anim->mTicksPerSecond = Read<double> (stream);
anim->mNumChannels = Read<unsigned int>(stream);
if (anim->mNumChannels)
{
anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ];
for (unsigned int a = 0; a < anim->mNumChannels;++a) {
anim->mChannels[a] = new aiNodeAnim();
ReadBinaryNodeAnim(stream,anim->mChannels[a]);
}
}
}
void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex)
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AITEXTURE);
/*uint32_t size =*/ Read<uint32_t>(stream);
tex->mWidth = Read<unsigned int>(stream);
tex->mHeight = Read<unsigned int>(stream);
stream->Read( tex->achFormatHint, sizeof(char), 4 );
if(!shortened) {
if (!tex->mHeight) {
tex->pcData = new aiTexel[ tex->mWidth ];
stream->Read(tex->pcData,1,tex->mWidth);
}
else {
tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ];
stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4);
}
}
}
// -----------------------------------------------------------------------------------
void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AILIGHT);
/*uint32_t size =*/ Read<uint32_t>(stream);
l->mName = Read<aiString>(stream);
l->mType = (aiLightSourceType)Read<unsigned int>(stream);
if (l->mType != aiLightSource_DIRECTIONAL) {
l->mAttenuationConstant = Read<float>(stream);
l->mAttenuationLinear = Read<float>(stream);
l->mAttenuationQuadratic = Read<float>(stream);
}
l->mColorDiffuse = Read<aiColor3D>(stream);
l->mColorSpecular = Read<aiColor3D>(stream);
l->mColorAmbient = Read<aiColor3D>(stream);
if (l->mType == aiLightSource_SPOT) {
l->mAngleInnerCone = Read<float>(stream);
l->mAngleOuterCone = Read<float>(stream);
}
}
// -----------------------------------------------------------------------------------
void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AICAMERA);
/*uint32_t size =*/ Read<uint32_t>(stream);
cam->mName = Read<aiString>(stream);
cam->mPosition = Read<aiVector3D>(stream);
cam->mLookAt = Read<aiVector3D>(stream);
cam->mUp = Read<aiVector3D>(stream);
cam->mHorizontalFOV = Read<float>(stream);
cam->mClipPlaneNear = Read<float>(stream);
cam->mClipPlaneFar = Read<float>(stream);
cam->mAspect = Read<float>(stream);
}
void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
{
uint32_t chunkID = Read<uint32_t>(stream);
ai_assert(chunkID == ASSBIN_CHUNK_AISCENE);
/*uint32_t size =*/ Read<uint32_t>(stream);
scene->mFlags = Read<unsigned int>(stream);
scene->mNumMeshes = Read<unsigned int>(stream);
scene->mNumMaterials = Read<unsigned int>(stream);
scene->mNumAnimations = Read<unsigned int>(stream);
scene->mNumTextures = Read<unsigned int>(stream);
scene->mNumLights = Read<unsigned int>(stream);
scene->mNumCameras = Read<unsigned int>(stream);
// Read node graph
scene->mRootNode = new aiNode[1];
ReadBinaryNode( stream, &scene->mRootNode );
// Read all meshes
if (scene->mNumMeshes)
{
scene->mMeshes = new aiMesh*[scene->mNumMeshes];
for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
scene->mMeshes[i] = new aiMesh();
ReadBinaryMesh( stream,scene->mMeshes[i]);
}
}
// Read materials
if (scene->mNumMaterials)
{
scene->mMaterials = new aiMaterial*[scene->mNumMaterials];
for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
scene->mMaterials[i] = new aiMaterial();
ReadBinaryMaterial(stream,scene->mMaterials[i]);
}
}
// Read all animations
if (scene->mNumAnimations)
{
scene->mAnimations = new aiAnimation*[scene->mNumAnimations];
for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
scene->mAnimations[i] = new aiAnimation();
ReadBinaryAnim(stream,scene->mAnimations[i]);
}
}
// Read all textures
if (scene->mNumTextures)
{
scene->mTextures = new aiTexture*[scene->mNumTextures];
for (unsigned int i = 0; i < scene->mNumTextures;++i) {
scene->mTextures[i] = new aiTexture();
ReadBinaryTexture(stream,scene->mTextures[i]);
}
}
// Read lights
if (scene->mNumLights)
{
scene->mLights = new aiLight*[scene->mNumLights];
for (unsigned int i = 0; i < scene->mNumLights;++i) {
scene->mLights[i] = new aiLight();
ReadBinaryLight(stream,scene->mLights[i]);
}
}
// Read cameras
if (scene->mNumCameras)
{
scene->mCameras = new aiCamera*[scene->mNumCameras];
for (unsigned int i = 0; i < scene->mNumCameras;++i) {
scene->mCameras[i] = new aiCamera();
ReadBinaryCamera(stream,scene->mCameras[i]);
}
}
}
void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler )
{
IOStream * stream = pIOHandler->Open(pFile,"rb");
if (!stream)
return;
stream->Seek( 44, aiOrigin_CUR ); // signature
/*unsigned int versionMajor =*/ Read<unsigned int>(stream);
/*unsigned int versionMinor =*/ Read<unsigned int>(stream);
/*unsigned int versionRevision =*/ Read<unsigned int>(stream);
/*unsigned int compileFlags =*/ Read<unsigned int>(stream);
shortened = Read<uint16_t>(stream) > 0;
compressed = Read<uint16_t>(stream) > 0;
if (shortened)
throw DeadlyImportError( "Shortened binaries are not supported!" );
stream->Seek( 256, aiOrigin_CUR ); // original filename
stream->Seek( 128, aiOrigin_CUR ); // options
stream->Seek( 64, aiOrigin_CUR ); // padding
if (compressed)
{
uLongf uncompressedSize = Read<uint32_t>(stream);
uLongf compressedSize = stream->FileSize() - stream->Tell();
unsigned char * compressedData = new unsigned char[ compressedSize ];
stream->Read( compressedData, 1, compressedSize );
unsigned char * uncompressedData = new unsigned char[ uncompressedSize ];
uncompress( uncompressedData, &uncompressedSize, compressedData, compressedSize );
MemoryIOStream io( uncompressedData, uncompressedSize );
ReadBinaryScene(&io,pScene);
delete[] uncompressedData;
delete[] compressedData;
}
else
{
ReadBinaryScene(stream,pScene);
}
pIOHandler->Close(stream);
}
#endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER

View file

@ -0,0 +1,105 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file AssbinLoader.h
* @brief .assbin File format loader
*/
#ifndef AI_ASSBINIMPORTER_H_INC
#define AI_ASSBINIMPORTER_H_INC
#include "BaseImporter.h"
#include <assimp/types.h>
struct aiMesh;
struct aiNode;
struct aiBone;
struct aiMaterial;
struct aiMaterialProperty;
struct aiNodeAnim;
struct aiAnimation;
struct aiTexture;
struct aiLight;
struct aiCamera;
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
namespace Assimp {
// ---------------------------------------------------------------------------------
/** Importer class for 3D Studio r3 and r4 3DS files
*/
class AssbinImporter : public BaseImporter
{
private:
bool shortened;
bool compressed;
protected:
public:
virtual bool CanRead(
const std::string& pFile,
IOSystem* pIOHandler,
bool checkSig
) const;
virtual const aiImporterDesc* GetInfo() const;
virtual void InternReadFile(
const std::string& pFile,
aiScene* pScene,
IOSystem* pIOHandler
);
void ReadBinaryScene( IOStream * stream, aiScene* pScene );
void ReadBinaryNode( IOStream * stream, aiNode** mRootNode );
void ReadBinaryMesh( IOStream * stream, aiMesh* mesh );
void ReadBinaryBone( IOStream * stream, aiBone* bone );
void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat);
void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop);
void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd);
void ReadBinaryAnim( IOStream * stream, aiAnimation* anim );
void ReadBinaryTexture(IOStream * stream, aiTexture* tex);
void ReadBinaryLight( IOStream * stream, aiLight* l );
void ReadBinaryCamera( IOStream * stream, aiCamera* cam );
};
} // end of namespace Assimp
#endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER
#endif // AI_ASSBINIMPORTER_H_INC

View file

@ -0,0 +1,700 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file Assimp.cpp
* @brief Implementation of the Plain-C API
*/
#include <assimp/cimport.h>
#include <assimp/LogStream.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include "GenericProperty.h"
#include "CInterfaceIOWrapper.h"
#include "Importer.h"
#include "Exceptional.h"
#include "ScenePrivate.h"
#include "BaseImporter.h"
#include <list>
// ------------------------------------------------------------------------------------------------
#ifndef ASSIMP_BUILD_SINGLETHREADED
# include <thread>
# include <mutex>
#endif
// ------------------------------------------------------------------------------------------------
using namespace Assimp;
namespace Assimp
{
// underlying structure for aiPropertyStore
typedef BatchLoader::PropertyMap PropertyMap;
/** Stores the LogStream objects for all active C log streams */
struct mpred {
bool operator () (const aiLogStream& s0, const aiLogStream& s1) const {
return s0.callback<s1.callback&&s0.user<s1.user;
}
};
typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
/** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
/** Local storage of all active log streams */
static LogStreamMap gActiveLogStreams;
/** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
static PredefLogStreamMap gPredefinedStreams;
/** Error message of the last failed import process */
static std::string gLastErrorString;
/** Verbose logging active or not? */
static aiBool gVerboseLogging = false;
/** will return all registered importers. */
void GetImporterInstanceList(std::vector< BaseImporter* >& out);
/** will delete all registered importers. */
void DeleteImporterInstanceList(std::vector< BaseImporter* >& out);
} // namespace assimp
#ifndef ASSIMP_BUILD_SINGLETHREADED
/** Global mutex to manage the access to the log-stream map */
static std::mutex gLogStreamMutex;
#endif
// ------------------------------------------------------------------------------------------------
// Custom LogStream implementation for the C-API
class LogToCallbackRedirector : public LogStream
{
public:
explicit LogToCallbackRedirector(const aiLogStream& s)
: stream (s) {
ai_assert(NULL != s.callback);
}
~LogToCallbackRedirector() {
#ifndef ASSIMP_BUILD_SINGLETHREADED
std::lock_guard<std::mutex> lock(gLogStreamMutex);
#endif
// (HACK) Check whether the 'stream.user' pointer points to a
// custom LogStream allocated by #aiGetPredefinedLogStream.
// In this case, we need to delete it, too. Of course, this
// might cause strange problems, but the chance is quite low.
PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
if (it != gPredefinedStreams.end()) {
delete *it;
gPredefinedStreams.erase(it);
}
}
/** @copydoc LogStream::write */
void write(const char* message) {
stream.callback(message,stream.user);
}
private:
aiLogStream stream;
};
// ------------------------------------------------------------------------------------------------
void ReportSceneNotFoundError()
{
DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
"The C-API does not accept scenes produced by the C++ API and vice versa");
assert(false);
}
// ------------------------------------------------------------------------------------------------
// Reads the given file and returns its content.
const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
{
return aiImportFileEx(pFile,pFlags,NULL);
}
// ------------------------------------------------------------------------------------------------
const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS)
{
return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
}
// ------------------------------------------------------------------------------------------------
const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags,
aiFileIO* pFS,
const aiPropertyStore* props)
{
ai_assert(NULL != pFile);
const aiScene* scene = NULL;
ASSIMP_BEGIN_EXCEPTION_REGION();
// create an Importer for this file
Assimp::Importer* imp = new Assimp::Importer();
// copy properties
if(props) {
const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
ImporterPimpl* pimpl = imp->Pimpl();
pimpl->mIntProperties = pp->ints;
pimpl->mFloatProperties = pp->floats;
pimpl->mStringProperties = pp->strings;
pimpl->mMatrixProperties = pp->matrices;
}
// setup a custom IO system if necessary
if (pFS) {
imp->SetIOHandler( new CIOSystemWrapper (pFS) );
}
// and have it read the file
scene = imp->ReadFile( pFile, pFlags);
// if succeeded, store the importer in the scene and keep it alive
if( scene) {
ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
priv->mOrigImporter = imp;
}
else {
// if failed, extract error code and destroy the import
gLastErrorString = imp->GetErrorString();
delete imp;
}
// return imported data. If the import failed the pointer is NULL anyways
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
return scene;
}
// ------------------------------------------------------------------------------------------------
const aiScene* aiImportFileFromMemory(
const char* pBuffer,
unsigned int pLength,
unsigned int pFlags,
const char* pHint)
{
return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
}
// ------------------------------------------------------------------------------------------------
const aiScene* aiImportFileFromMemoryWithProperties(
const char* pBuffer,
unsigned int pLength,
unsigned int pFlags,
const char* pHint,
const aiPropertyStore* props)
{
ai_assert( NULL != pBuffer );
ai_assert( 0 != pLength );
const aiScene* scene = NULL;
ASSIMP_BEGIN_EXCEPTION_REGION();
// create an Importer for this file
Assimp::Importer* imp = new Assimp::Importer();
// copy properties
if(props) {
const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
ImporterPimpl* pimpl = imp->Pimpl();
pimpl->mIntProperties = pp->ints;
pimpl->mFloatProperties = pp->floats;
pimpl->mStringProperties = pp->strings;
pimpl->mMatrixProperties = pp->matrices;
}
// and have it read the file from the memory buffer
scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
// if succeeded, store the importer in the scene and keep it alive
if( scene) {
ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
priv->mOrigImporter = imp;
}
else {
// if failed, extract error code and destroy the import
gLastErrorString = imp->GetErrorString();
delete imp;
}
// return imported data. If the import failed the pointer is NULL anyways
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
return scene;
}
// ------------------------------------------------------------------------------------------------
// Releases all resources associated with the given import process.
void aiReleaseImport( const aiScene* pScene)
{
if (!pScene) {
return;
}
ASSIMP_BEGIN_EXCEPTION_REGION();
// find the importer associated with this data
const ScenePrivateData* priv = ScenePriv(pScene);
if( !priv || !priv->mOrigImporter) {
delete pScene;
}
else {
// deleting the Importer also deletes the scene
// Note: the reason that this is not written as 'delete priv->mOrigImporter'
// is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
Importer* importer = priv->mOrigImporter;
delete importer;
}
ASSIMP_END_EXCEPTION_REGION(void);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene,
unsigned int pFlags)
{
const aiScene* sc = NULL;
ASSIMP_BEGIN_EXCEPTION_REGION();
// find the importer associated with this data
const ScenePrivateData* priv = ScenePriv(pScene);
if( !priv || !priv->mOrigImporter) {
ReportSceneNotFoundError();
return NULL;
}
sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
if (!sc) {
aiReleaseImport(pScene);
return NULL;
}
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
return sc;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing( const aiScene *scene,
BaseProcess* process,
bool requestValidation ) {
const aiScene* sc( NULL );
ASSIMP_BEGIN_EXCEPTION_REGION();
// find the importer associated with this data
const ScenePrivateData* priv = ScenePriv( scene );
if ( NULL == priv || NULL == priv->mOrigImporter ) {
ReportSceneNotFoundError();
return NULL;
}
sc = priv->mOrigImporter->ApplyCustomizedPostProcessing( process, requestValidation );
if ( !sc ) {
aiReleaseImport( scene );
return NULL;
}
ASSIMP_END_EXCEPTION_REGION( const aiScene* );
return sc;
}
// ------------------------------------------------------------------------------------------------
void CallbackToLogRedirector (const char* msg, char* dt)
{
ai_assert( NULL != msg );
ai_assert( NULL != dt );
LogStream* s = (LogStream*)dt;
s->write(msg);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file)
{
aiLogStream sout;
ASSIMP_BEGIN_EXCEPTION_REGION();
LogStream* stream = LogStream::createDefaultStream(pStream,file);
if (!stream) {
sout.callback = NULL;
sout.user = NULL;
}
else {
sout.callback = &CallbackToLogRedirector;
sout.user = (char*)stream;
}
gPredefinedStreams.push_back(stream);
ASSIMP_END_EXCEPTION_REGION(aiLogStream);
return sout;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
{
ASSIMP_BEGIN_EXCEPTION_REGION();
#ifndef ASSIMP_BUILD_SINGLETHREADED
std::lock_guard<std::mutex> lock(gLogStreamMutex);
#endif
LogStream* lg = new LogToCallbackRedirector(*stream);
gActiveLogStreams[*stream] = lg;
if (DefaultLogger::isNullLogger()) {
DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
}
DefaultLogger::get()->attachStream(lg);
ASSIMP_END_EXCEPTION_REGION(void);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
{
ASSIMP_BEGIN_EXCEPTION_REGION();
#ifndef ASSIMP_BUILD_SINGLETHREADED
std::lock_guard<std::mutex> lock(gLogStreamMutex);
#endif
// find the log-stream associated with this data
LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
// it should be there... else the user is playing fools with us
if( it == gActiveLogStreams.end()) {
return AI_FAILURE;
}
DefaultLogger::get()->detatchStream( it->second );
delete it->second;
gActiveLogStreams.erase( it);
if (gActiveLogStreams.empty()) {
DefaultLogger::kill();
}
ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_SUCCESS;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiDetachAllLogStreams(void)
{
ASSIMP_BEGIN_EXCEPTION_REGION();
#ifndef ASSIMP_BUILD_SINGLETHREADED
std::lock_guard<std::mutex> lock(gLogStreamMutex);
#endif
Logger *logger( DefaultLogger::get() );
if ( NULL == logger ) {
return;
}
for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
logger->detatchStream( it->second );
delete it->second;
}
gActiveLogStreams.clear();
DefaultLogger::kill();
ASSIMP_END_EXCEPTION_REGION(void);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiEnableVerboseLogging(aiBool d)
{
if (!DefaultLogger::isNullLogger()) {
DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
}
gVerboseLogging = d;
}
// ------------------------------------------------------------------------------------------------
// Returns the error text of the last failed import process.
const char* aiGetErrorString()
{
return gLastErrorString.c_str();
}
// -----------------------------------------------------------------------------------------------
// Return the description of a importer given its index
const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex)
{
return Importer().GetImporterInfo(pIndex);
}
// -----------------------------------------------------------------------------------------------
// Return the number of importers
size_t aiGetImportFormatCount(void)
{
return Importer().GetImporterCount();
}
// ------------------------------------------------------------------------------------------------
// Returns the error text of the last failed import process.
aiBool aiIsExtensionSupported(const char* szExtension)
{
ai_assert(NULL != szExtension);
aiBool candoit=AI_FALSE;
ASSIMP_BEGIN_EXCEPTION_REGION();
// FIXME: no need to create a temporary Importer instance just for that ..
Assimp::Importer tmp;
candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
ASSIMP_END_EXCEPTION_REGION(aiBool);
return candoit;
}
// ------------------------------------------------------------------------------------------------
// Get a list of all file extensions supported by ASSIMP
void aiGetExtensionList(aiString* szOut)
{
ai_assert(NULL != szOut);
ASSIMP_BEGIN_EXCEPTION_REGION();
// FIXME: no need to create a temporary Importer instance just for that ..
Assimp::Importer tmp;
tmp.GetExtensionList(*szOut);
ASSIMP_END_EXCEPTION_REGION(void);
}
// ------------------------------------------------------------------------------------------------
// Get the memory requirements for a particular import.
void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
C_STRUCT aiMemoryInfo* in)
{
ASSIMP_BEGIN_EXCEPTION_REGION();
// find the importer associated with this data
const ScenePrivateData* priv = ScenePriv(pIn);
if( !priv || !priv->mOrigImporter) {
ReportSceneNotFoundError();
return;
}
return priv->mOrigImporter->GetMemoryRequirements(*in);
ASSIMP_END_EXCEPTION_REGION(void);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void)
{
return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p)
{
delete reinterpret_cast<PropertyMap*>(p);
}
// ------------------------------------------------------------------------------------------------
// Importer::SetPropertyInteger
ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value)
{
ASSIMP_BEGIN_EXCEPTION_REGION();
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
SetGenericProperty<int>(pp->ints,szName,value);
ASSIMP_END_EXCEPTION_REGION(void);
}
// ------------------------------------------------------------------------------------------------
// Importer::SetPropertyFloat
ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, float value)
{
ASSIMP_BEGIN_EXCEPTION_REGION();
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
SetGenericProperty<float>(pp->floats,szName,value);
ASSIMP_END_EXCEPTION_REGION(void);
}
// ------------------------------------------------------------------------------------------------
// Importer::SetPropertyString
ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName,
const C_STRUCT aiString* st)
{
if (!st) {
return;
}
ASSIMP_BEGIN_EXCEPTION_REGION();
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()));
ASSIMP_END_EXCEPTION_REGION(void);
}
// ------------------------------------------------------------------------------------------------
// Importer::SetPropertyMatrix
ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName,
const C_STRUCT aiMatrix4x4* mat)
{
if (!mat) {
return;
}
ASSIMP_BEGIN_EXCEPTION_REGION();
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat);
ASSIMP_END_EXCEPTION_REGION(void);
}
// ------------------------------------------------------------------------------------------------
// Rotation matrix to quaternion
ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
{
ai_assert( NULL != quat );
ai_assert( NULL != mat );
*quat = aiQuaternion(*mat);
}
// ------------------------------------------------------------------------------------------------
// Matrix decomposition
ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling,
aiQuaternion* rotation,
aiVector3D* position)
{
ai_assert( NULL != rotation );
ai_assert( NULL != position );
ai_assert( NULL != scaling );
ai_assert( NULL != mat );
mat->Decompose(*scaling,*rotation,*position);
}
// ------------------------------------------------------------------------------------------------
// Matrix transpose
ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat)
{
ai_assert(NULL != mat);
mat->Transpose();
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat)
{
ai_assert(NULL != mat);
mat->Transpose();
}
// ------------------------------------------------------------------------------------------------
// Vector transformation
ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec,
const aiMatrix3x3* mat)
{
ai_assert( NULL != mat );
ai_assert( NULL != vec);
*vec *= (*mat);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec,
const aiMatrix4x4* mat)
{
ai_assert( NULL != mat );
ai_assert( NULL != vec );
*vec *= (*mat);
}
// ------------------------------------------------------------------------------------------------
// Matrix multiplication
ASSIMP_API void aiMultiplyMatrix4(
aiMatrix4x4* dst,
const aiMatrix4x4* src)
{
ai_assert( NULL != dst );
ai_assert( NULL != src );
*dst = (*dst) * (*src);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiMultiplyMatrix3(
aiMatrix3x3* dst,
const aiMatrix3x3* src)
{
ai_assert( NULL != dst );
ai_assert( NULL != src );
*dst = (*dst) * (*src);
}
// ------------------------------------------------------------------------------------------------
// Matrix identity
ASSIMP_API void aiIdentityMatrix3(
aiMatrix3x3* mat)
{
ai_assert(NULL != mat);
*mat = aiMatrix3x3();
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiIdentityMatrix4(
aiMatrix4x4* mat)
{
ai_assert(NULL != mat);
*mat = aiMatrix4x4();
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) {
if( NULL == extension ) {
return NULL;
}
const aiImporterDesc *desc( NULL );
std::vector< BaseImporter* > out;
GetImporterInstanceList( out );
for( size_t i = 0; i < out.size(); ++i ) {
if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) {
desc = out[ i ]->GetInfo();
break;
}
}
DeleteImporterInstanceList(out);
return desc;
}
// ------------------------------------------------------------------------------------------------

View file

@ -0,0 +1,154 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file AssimpCExport.cpp
Assimp C export interface. See Exporter.cpp for some notes.
*/
#ifndef ASSIMP_BUILD_NO_EXPORT
#include "CInterfaceIOWrapper.h"
#include "SceneCombiner.h"
#include "ScenePrivate.h"
#include <assimp/Exporter.hpp>
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
ASSIMP_API size_t aiGetExportFormatCount(void)
{
return Exporter().GetExportFormatCount();
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index)
{
// Note: this is valid as the index always pertains to a built-in exporter,
// for which the returned structure is guaranteed to be of static storage duration.
Exporter exporter;
const aiExportFormatDesc* orig( exporter.GetExportFormatDescription( index ) );
if (NULL == orig) {
return NULL;
}
aiExportFormatDesc *desc = new aiExportFormatDesc;
desc->description = new char[ strlen( orig->description ) + 1 ];
::strncpy( (char*) desc->description, orig->description, strlen( orig->description ) );
desc->fileExtension = new char[ strlen( orig->fileExtension ) + 1 ];
::strncpy( ( char* ) desc->fileExtension, orig->fileExtension, strlen( orig->fileExtension ) );
desc->id = new char[ strlen( orig->id ) + 1 ];
::strncpy( ( char* ) desc->id, orig->id, strlen( orig->id ) );
return desc;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiReleaseExportFormatDescription( const aiExportFormatDesc *desc ) {
if (NULL == desc) {
return;
}
delete [] desc->description;
delete [] desc->fileExtension;
delete [] desc->id;
delete desc;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut)
{
if (!pOut || !pIn) {
return;
}
SceneCombiner::CopyScene(pOut,pIn,true);
ScenePriv(*pOut)->mIsCopy = true;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiFreeScene(const C_STRUCT aiScene* pIn)
{
// note: aiReleaseImport() is also able to delete scene copies, but in addition
// it also handles scenes with import metadata.
delete pIn;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing )
{
return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, aiFileIO* pIO, unsigned int pPreprocessing )
{
Exporter exp;
if (pIO) {
exp.SetIOHandler(new CIOSystemWrapper(pIO));
}
return exp.Export(pScene,pFormatId,pFileName,pPreprocessing);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing )
{
Exporter exp;
if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) {
return NULL;
}
const aiExportDataBlob* blob = exp.GetOrphanedBlob();
ai_assert(blob);
return blob;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API C_STRUCT void aiReleaseExportBlob( const aiExportDataBlob* pData )
{
delete pData;
}
#endif // !ASSIMP_BUILD_NO_EXPORT

View file

@ -0,0 +1,648 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file AssxmlExporter.cpp
* ASSXML exporter main code
*/
#include <stdarg.h>
#include "./../include/assimp/version.h"
#include "ProcessHelper.h"
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/Exporter.hpp>
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
# include <zlib.h>
#else
# include <contrib/zlib/zlib.h>
#endif
#include <time.h>
#include <stdio.h>
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
using namespace Assimp;
namespace Assimp {
namespace AssxmlExport {
// -----------------------------------------------------------------------------------
static int ioprintf( IOStream * io, const char *format, ... ) {
using namespace std;
if ( nullptr == io ) {
return -1;
}
static const size_t Size = 4096;
char sz[ Size ];
size_t len( strlen( format ) );
::memset( sz, '\0', Size );
va_list va;
va_start( va, format );
int nSize = vsnprintf( sz, Size-1, format, va );
ai_assert( nSize < Size );
va_end( va );
io->Write( sz, sizeof(char), nSize );
return nSize;
}
// -----------------------------------------------------------------------------------
// Convert a name to standard XML format
static void ConvertName(aiString& out, const aiString& in) {
out.length = 0;
for (unsigned int i = 0; i < in.length; ++i) {
switch (in.data[i]) {
case '<':
out.Append("&lt;");break;
case '>':
out.Append("&gt;");break;
case '&':
out.Append("&amp;");break;
case '\"':
out.Append("&quot;");break;
case '\'':
out.Append("&apos;");break;
default:
out.data[out.length++] = in.data[i];
}
}
out.data[out.length] = 0;
}
// -----------------------------------------------------------------------------------
// Write a single node as text dump
static void WriteNode(const aiNode* node, IOStream * io, unsigned int depth) {
char prefix[512];
for (unsigned int i = 0; i < depth;++i)
prefix[i] = '\t';
prefix[depth] = '\0';
const aiMatrix4x4& m = node->mTransformation;
aiString name;
ConvertName(name,node->mName);
ioprintf(io,"%s<Node name=\"%s\"> \n"
"%s\t<Matrix4> \n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
"%s\t</Matrix4> \n",
prefix,name.data,prefix,
prefix,m.a1,m.a2,m.a3,m.a4,
prefix,m.b1,m.b2,m.b3,m.b4,
prefix,m.c1,m.c2,m.c3,m.c4,
prefix,m.d1,m.d2,m.d3,m.d4,prefix);
if (node->mNumMeshes) {
ioprintf(io, "%s\t<MeshRefs num=\"%i\">\n%s\t",
prefix,node->mNumMeshes,prefix);
for (unsigned int i = 0; i < node->mNumMeshes;++i) {
ioprintf(io,"%i ",node->mMeshes[i]);
}
ioprintf(io,"\n%s\t</MeshRefs>\n",prefix);
}
if (node->mNumChildren) {
ioprintf(io,"%s\t<NodeList num=\"%i\">\n",
prefix,node->mNumChildren);
for (unsigned int i = 0; i < node->mNumChildren;++i) {
WriteNode(node->mChildren[i],io,depth+2);
}
ioprintf(io,"%s\t</NodeList>\n",prefix);
}
ioprintf(io,"%s</Node>\n",prefix);
}
// -----------------------------------------------------------------------------------
// Some chuncks of text will need to be encoded for XML
// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377
static std::string encodeXML(const std::string& data) {
std::string buffer;
buffer.reserve(data.size());
for(size_t pos = 0; pos != data.size(); ++pos) {
switch(data[pos]) {
case '&': buffer.append("&amp;"); break;
case '\"': buffer.append("&quot;"); break;
case '\'': buffer.append("&apos;"); break;
case '<': buffer.append("&lt;"); break;
case '>': buffer.append("&gt;"); break;
default: buffer.append(&data[pos], 1); break;
}
}
return buffer;
}
// -----------------------------------------------------------------------------------
// Write a text model dump
static
void WriteDump(const aiScene* scene, IOStream* io, bool shortened) {
time_t tt = ::time( NULL );
tm* p = ::gmtime( &tt );
ai_assert( nullptr != p );
// write header
std::string header(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<ASSIMP format_id=\"1\">\n\n"
"<!-- XML Model dump produced by assimp dump\n"
" Library version: %i.%i.%i\n"
" %s\n"
"-->"
" \n\n"
"<Scene flags=\"%d\" postprocessing=\"%i\">\n"
);
const unsigned int majorVersion( aiGetVersionMajor() );
const unsigned int minorVersion( aiGetVersionMinor() );
const unsigned int rev( aiGetVersionRevision() );
const char *curtime( asctime( p ) );
ioprintf( io, header.c_str(), majorVersion, minorVersion, rev, curtime, scene->mFlags, 0 );
// write the node graph
WriteNode(scene->mRootNode, io, 0);
#if 0
// write cameras
for (unsigned int i = 0; i < scene->mNumCameras;++i) {
aiCamera* cam = scene->mCameras[i];
ConvertName(name,cam->mName);
// camera header
ioprintf(io,"\t<Camera parent=\"%s\">\n"
"\t\t<Vector3 name=\"up\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"lookat\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"pos\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Float name=\"fov\" > %f </Float>\n"
"\t\t<Float name=\"aspect\" > %f </Float>\n"
"\t\t<Float name=\"near_clip\" > %f </Float>\n"
"\t\t<Float name=\"far_clip\" > %f </Float>\n"
"\t</Camera>\n",
name.data,
cam->mUp.x,cam->mUp.y,cam->mUp.z,
cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z,
cam->mPosition.x,cam->mPosition.y,cam->mPosition.z,
cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i);
}
// write lights
for (unsigned int i = 0; i < scene->mNumLights;++i) {
aiLight* l = scene->mLights[i];
ConvertName(name,l->mName);
// light header
ioprintf(io,"\t<Light parent=\"%s\"> type=\"%s\"\n"
"\t\t<Vector3 name=\"diffuse\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"specular\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Vector3 name=\"ambient\" > %0 8f %0 8f %0 8f </Vector3>\n",
name.data,
(l->mType == aiLightSource_DIRECTIONAL ? "directional" :
(l->mType == aiLightSource_POINT ? "point" : "spot" )),
l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b,
l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b,
l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b);
if (l->mType != aiLightSource_DIRECTIONAL) {
ioprintf(io,
"\t\t<Vector3 name=\"pos\" > %0 8f %0 8f %0 8f </Vector3>\n"
"\t\t<Float name=\"atten_cst\" > %f </Float>\n"
"\t\t<Float name=\"atten_lin\" > %f </Float>\n"
"\t\t<Float name=\"atten_sqr\" > %f </Float>\n",
l->mPosition.x,l->mPosition.y,l->mPosition.z,
l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic);
}
if (l->mType != aiLightSource_POINT) {
ioprintf(io,
"\t\t<Vector3 name=\"lookat\" > %0 8f %0 8f %0 8f </Vector3>\n",
l->mDirection.x,l->mDirection.y,l->mDirection.z);
}
if (l->mType == aiLightSource_SPOT) {
ioprintf(io,
"\t\t<Float name=\"cone_out\" > %f </Float>\n"
"\t\t<Float name=\"cone_inn\" > %f </Float>\n",
l->mAngleOuterCone,l->mAngleInnerCone);
}
ioprintf(io,"\t</Light>\n");
}
#endif
aiString name;
// write textures
if (scene->mNumTextures) {
ioprintf(io,"<TextureList num=\"%i\">\n",scene->mNumTextures);
for (unsigned int i = 0; i < scene->mNumTextures;++i) {
aiTexture* tex = scene->mTextures[i];
bool compressed = (tex->mHeight == 0);
// mesh header
ioprintf(io,"\t<Texture width=\"%i\" height=\"%i\" compressed=\"%s\"> \n",
(compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight),
(compressed ? "true" : "false"));
if (compressed) {
ioprintf(io,"\t\t<Data length=\"%i\"> \n",tex->mWidth);
if (!shortened) {
for (unsigned int n = 0; n < tex->mWidth;++n) {
ioprintf(io,"\t\t\t%2x",reinterpret_cast<uint8_t*>(tex->pcData)[n]);
if (n && !(n % 50)) {
ioprintf(io,"\n");
}
}
}
}
else if (!shortened){
ioprintf(io,"\t\t<Data length=\"%i\"> \n",tex->mWidth*tex->mHeight*4);
// const unsigned int width = (unsigned int)log10((double)std::max(tex->mHeight,tex->mWidth))+1;
for (unsigned int y = 0; y < tex->mHeight;++y) {
for (unsigned int x = 0; x < tex->mWidth;++x) {
aiTexel* tx = tex->pcData + y*tex->mWidth+x;
unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a;
ioprintf(io,"\t\t\t%2x %2x %2x %2x",r,g,b,a);
// group by four for readability
if ( 0 == ( x + y*tex->mWidth ) % 4 ) {
ioprintf( io, "\n" );
}
}
}
}
ioprintf(io,"\t\t</Data>\n\t</Texture>\n");
}
ioprintf(io,"</TextureList>\n");
}
// write materials
if (scene->mNumMaterials) {
ioprintf(io,"<MaterialList num=\"%i\">\n",scene->mNumMaterials);
for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
const aiMaterial* mat = scene->mMaterials[i];
ioprintf(io,"\t<Material>\n");
ioprintf(io,"\t\t<MatPropertyList num=\"%i\">\n",mat->mNumProperties);
for (unsigned int n = 0; n < mat->mNumProperties;++n) {
const aiMaterialProperty* prop = mat->mProperties[n];
const char* sz = "";
if (prop->mType == aiPTI_Float) {
sz = "float";
}
else if (prop->mType == aiPTI_Integer) {
sz = "integer";
}
else if (prop->mType == aiPTI_String) {
sz = "string";
}
else if (prop->mType == aiPTI_Buffer) {
sz = "binary_buffer";
}
ioprintf(io,"\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%i\"",
prop->mKey.data, sz,
::TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex);
if (prop->mType == aiPTI_Float) {
ioprintf(io," size=\"%i\">\n\t\t\t\t",
static_cast<int>(prop->mDataLength/sizeof(float)));
for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) {
ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float))));
}
}
else if (prop->mType == aiPTI_Integer) {
ioprintf(io," size=\"%i\">\n\t\t\t\t",
static_cast<int>(prop->mDataLength/sizeof(int)));
for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) {
ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int))));
}
}
else if (prop->mType == aiPTI_Buffer) {
ioprintf(io," size=\"%i\">\n\t\t\t\t",
static_cast<int>(prop->mDataLength));
for (unsigned int p = 0; p < prop->mDataLength;++p) {
ioprintf(io,"%2x ",prop->mData[p]);
if (p && 0 == p%30) {
ioprintf(io,"\n\t\t\t\t");
}
}
}
else if (prop->mType == aiPTI_String) {
ioprintf(io,">\n\t\t\t\t\"%s\"",encodeXML(prop->mData+4).c_str() /* skip length */);
}
ioprintf(io,"\n\t\t\t</MatProperty>\n");
}
ioprintf(io,"\t\t</MatPropertyList>\n");
ioprintf(io,"\t</Material>\n");
}
ioprintf(io,"</MaterialList>\n");
}
// write animations
if (scene->mNumAnimations) {
ioprintf(io,"<AnimationList num=\"%i\">\n",scene->mNumAnimations);
for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
aiAnimation* anim = scene->mAnimations[i];
// anim header
ConvertName(name,anim->mName);
ioprintf(io,"\t<Animation name=\"%s\" duration=\"%e\" tick_cnt=\"%e\">\n",
name.data, anim->mDuration, anim->mTicksPerSecond);
// write bone animation channels
if (anim->mNumChannels) {
ioprintf(io,"\t\t<NodeAnimList num=\"%i\">\n",anim->mNumChannels);
for (unsigned int n = 0; n < anim->mNumChannels;++n) {
aiNodeAnim* nd = anim->mChannels[n];
// node anim header
ConvertName(name,nd->mNodeName);
ioprintf(io,"\t\t\t<NodeAnim node=\"%s\">\n",name.data);
if (!shortened) {
// write position keys
if (nd->mNumPositionKeys) {
ioprintf(io,"\t\t\t\t<PositionKeyList num=\"%i\">\n",nd->mNumPositionKeys);
for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) {
aiVectorKey* vc = nd->mPositionKeys+a;
ioprintf(io,"\t\t\t\t\t<PositionKey time=\"%e\">\n"
"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</PositionKey>\n",
vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z);
}
ioprintf(io,"\t\t\t\t</PositionKeyList>\n");
}
// write scaling keys
if (nd->mNumScalingKeys) {
ioprintf(io,"\t\t\t\t<ScalingKeyList num=\"%i\">\n",nd->mNumScalingKeys);
for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) {
aiVectorKey* vc = nd->mScalingKeys+a;
ioprintf(io,"\t\t\t\t\t<ScalingKey time=\"%e\">\n"
"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</ScalingKey>\n",
vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z);
}
ioprintf(io,"\t\t\t\t</ScalingKeyList>\n");
}
// write rotation keys
if (nd->mNumRotationKeys) {
ioprintf(io,"\t\t\t\t<RotationKeyList num=\"%i\">\n",nd->mNumRotationKeys);
for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) {
aiQuatKey* vc = nd->mRotationKeys+a;
ioprintf(io,"\t\t\t\t\t<RotationKey time=\"%e\">\n"
"\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t</RotationKey>\n",
vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w);
}
ioprintf(io,"\t\t\t\t</RotationKeyList>\n");
}
}
ioprintf(io,"\t\t\t</NodeAnim>\n");
}
ioprintf(io,"\t\t</NodeAnimList>\n");
}
ioprintf(io,"\t</Animation>\n");
}
ioprintf(io,"</AnimationList>\n");
}
// write meshes
if (scene->mNumMeshes) {
ioprintf(io,"<MeshList num=\"%i\">\n",scene->mNumMeshes);
for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
aiMesh* mesh = scene->mMeshes[i];
// const unsigned int width = (unsigned int)log10((double)mesh->mNumVertices)+1;
// mesh header
ioprintf(io,"\t<Mesh types=\"%s %s %s %s\" material_index=\"%i\">\n",
(mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""),
(mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""),
(mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""),
(mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""),
mesh->mMaterialIndex);
// bones
if (mesh->mNumBones) {
ioprintf(io,"\t\t<BoneList num=\"%i\">\n",mesh->mNumBones);
for (unsigned int n = 0; n < mesh->mNumBones;++n) {
aiBone* bone = mesh->mBones[n];
ConvertName(name,bone->mName);
// bone header
ioprintf(io,"\t\t\t<Bone name=\"%s\">\n"
"\t\t\t\t<Matrix4> \n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
"\t\t\t\t</Matrix4> \n",
name.data,
bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4,
bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4,
bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4,
bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4);
if (!shortened && bone->mNumWeights) {
ioprintf(io,"\t\t\t\t<WeightList num=\"%i\">\n",bone->mNumWeights);
// bone weights
for (unsigned int a = 0; a < bone->mNumWeights;++a) {
aiVertexWeight* wght = bone->mWeights+a;
ioprintf(io,"\t\t\t\t\t<Weight index=\"%i\">\n\t\t\t\t\t\t%f\n\t\t\t\t\t</Weight>\n",
wght->mVertexId,wght->mWeight);
}
ioprintf(io,"\t\t\t\t</WeightList>\n");
}
ioprintf(io,"\t\t\t</Bone>\n");
}
ioprintf(io,"\t\t</BoneList>\n");
}
// faces
if (!shortened && mesh->mNumFaces) {
ioprintf(io,"\t\t<FaceList num=\"%i\">\n",mesh->mNumFaces);
for (unsigned int n = 0; n < mesh->mNumFaces; ++n) {
aiFace& f = mesh->mFaces[n];
ioprintf(io,"\t\t\t<Face num=\"%i\">\n"
"\t\t\t\t",f.mNumIndices);
for (unsigned int j = 0; j < f.mNumIndices;++j)
ioprintf(io,"%i ",f.mIndices[j]);
ioprintf(io,"\n\t\t\t</Face>\n");
}
ioprintf(io,"\t\t</FaceList>\n");
}
// vertex positions
if (mesh->HasPositions()) {
ioprintf(io,"\t\t<Positions num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
mesh->mVertices[n].x,
mesh->mVertices[n].y,
mesh->mVertices[n].z);
}
}
ioprintf(io,"\t\t</Positions>\n");
}
// vertex normals
if (mesh->HasNormals()) {
ioprintf(io,"\t\t<Normals num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
mesh->mNormals[n].x,
mesh->mNormals[n].y,
mesh->mNormals[n].z);
}
}
else {
}
ioprintf(io,"\t\t</Normals>\n");
}
// vertex tangents and bitangents
if (mesh->HasTangentsAndBitangents()) {
ioprintf(io,"\t\t<Tangents num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
mesh->mTangents[n].x,
mesh->mTangents[n].y,
mesh->mTangents[n].z);
}
}
ioprintf(io,"\t\t</Tangents>\n");
ioprintf(io,"\t\t<Bitangents num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
mesh->mBitangents[n].x,
mesh->mBitangents[n].y,
mesh->mBitangents[n].z);
}
}
ioprintf(io,"\t\t</Bitangents>\n");
}
// texture coordinates
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
if (!mesh->mTextureCoords[a])
break;
ioprintf(io,"\t\t<TextureCoords num=\"%i\" set=\"%i\" num_components=\"%i\"> \n",mesh->mNumVertices,
a,mesh->mNumUVComponents[a]);
if (!shortened) {
if (mesh->mNumUVComponents[a] == 3) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
mesh->mTextureCoords[a][n].x,
mesh->mTextureCoords[a][n].y,
mesh->mTextureCoords[a][n].z);
}
}
else {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io,"\t\t%0 8f %0 8f\n",
mesh->mTextureCoords[a][n].x,
mesh->mTextureCoords[a][n].y);
}
}
}
ioprintf(io,"\t\t</TextureCoords>\n");
}
// vertex colors
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
if (!mesh->mColors[a])
break;
ioprintf(io,"\t\t<Colors num=\"%i\" set=\"%i\" num_components=\"4\"> \n",mesh->mNumVertices,a);
if (!shortened) {
for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
ioprintf(io,"\t\t%0 8f %0 8f %0 8f %0 8f\n",
mesh->mColors[a][n].r,
mesh->mColors[a][n].g,
mesh->mColors[a][n].b,
mesh->mColors[a][n].a);
}
}
ioprintf(io,"\t\t</Colors>\n");
}
ioprintf(io,"\t</Mesh>\n");
}
ioprintf(io,"</MeshList>\n");
}
ioprintf(io,"</Scene>\n</ASSIMP>");
}
} // end of namespace AssxmlExport
void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
{
IOStream * out = pIOSystem->Open( pFile, "wt" );
if (!out) return;
bool shortened = false;
AssxmlExport::WriteDump( pScene, out, shortened );
pIOSystem->Close( out );
}
} // end of namespace Assimp
#endif // ASSIMP_BUILD_NO_ASSXML_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View file

@ -0,0 +1,49 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file AssxmlExporter.h
* ASSXML Exporter Main Header
*/
#ifndef AI_ASSXMLEXPORTER_H_INC
#define AI_ASSXMLEXPORTER_H_INC
// nothing really needed here - reserved for future use like properties
#endif

View file

@ -0,0 +1,696 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file B3DImporter.cpp
* @brief Implementation of the b3d importer class
*/
#ifndef ASSIMP_BUILD_NO_B3D_IMPORTER
// internal headers
#include "B3DImporter.h"
#include "TextureTransform.h"
#include "ConvertToLHProcess.h"
#include "StringUtils.h"
#include <memory>
#include <assimp/IOSystem.hpp>
#include <assimp/anim.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
using namespace Assimp;
using namespace std;
static const aiImporterDesc desc = {
"BlitzBasic 3D Importer",
"",
"",
"http://www.blitzbasic.com/",
aiImporterFlags_SupportBinaryFlavour,
0,
0,
0,
0,
"b3d"
};
// (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings
#ifdef _MSC_VER
# pragma warning (disable: 4018)
#endif
//#define DEBUG_B3D
// ------------------------------------------------------------------------------------------------
bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{
size_t pos=pFile.find_last_of( '.' );
if( pos==string::npos ) return false;
string ext=pFile.substr( pos+1 );
if( ext.size()!=3 ) return false;
return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D');
}
// ------------------------------------------------------------------------------------------------
// Loader meta information
const aiImporterDesc* B3DImporter::GetInfo () const
{
return &desc;
}
#ifdef DEBUG_B3D
extern "C"{ void _stdcall AllocConsole(); }
#endif
// ------------------------------------------------------------------------------------------------
void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){
#ifdef DEBUG_B3D
AllocConsole();
freopen( "conin$","r",stdin );
freopen( "conout$","w",stdout );
freopen( "conout$","w",stderr );
cout<<"Hello world from the B3DImporter!"<<endl;
#endif
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
// Check whether we can read from the file
if( file.get() == NULL)
throw DeadlyImportError( "Failed to open B3D file " + pFile + ".");
// check whether the .b3d file is large enough to contain
// at least one chunk.
size_t fileSize = file->FileSize();
if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small.");
_pos=0;
_buf.resize( fileSize );
file->Read( &_buf[0],1,fileSize );
_stack.clear();
ReadBB3D( pScene );
}
// ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void B3DImporter::Oops(){
throw DeadlyImportError( "B3D Importer - INTERNAL ERROR" );
}
// ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void B3DImporter::Fail( string str ){
#ifdef DEBUG_B3D
cout<<"Error in B3D file data: "<<str<<endl;
#endif
throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
}
// ------------------------------------------------------------------------------------------------
int B3DImporter::ReadByte(){
if( _pos<_buf.size() ) return _buf[_pos++];
Fail( "EOF" );
return 0;
}
// ------------------------------------------------------------------------------------------------
int B3DImporter::ReadInt(){
if( _pos+4<=_buf.size() ){
int n=*(int*)&_buf[_pos];
_pos+=4;
return n;
}
Fail( "EOF" );
return 0;
}
// ------------------------------------------------------------------------------------------------
float B3DImporter::ReadFloat(){
if( _pos+4<=_buf.size() ){
float n=*(float*)&_buf[_pos];
_pos+=4;
return n;
}
Fail( "EOF" );
return 0.0f;
}
// ------------------------------------------------------------------------------------------------
aiVector2D B3DImporter::ReadVec2(){
float x=ReadFloat();
float y=ReadFloat();
return aiVector2D( x,y );
}
// ------------------------------------------------------------------------------------------------
aiVector3D B3DImporter::ReadVec3(){
float x=ReadFloat();
float y=ReadFloat();
float z=ReadFloat();
return aiVector3D( x,y,z );
}
// ------------------------------------------------------------------------------------------------
aiQuaternion B3DImporter::ReadQuat(){
// (aramis_acg) Fix to adapt the loader to changed quat orientation
float w=-ReadFloat();
float x=ReadFloat();
float y=ReadFloat();
float z=ReadFloat();
return aiQuaternion( w,x,y,z );
}
// ------------------------------------------------------------------------------------------------
string B3DImporter::ReadString(){
string str;
while( _pos<_buf.size() ){
char c=(char)ReadByte();
if( !c ) return str;
str+=c;
}
Fail( "EOF" );
return string();
}
// ------------------------------------------------------------------------------------------------
string B3DImporter::ReadChunk(){
string tag;
for( int i=0;i<4;++i ){
tag+=char( ReadByte() );
}
#ifdef DEBUG_B3D
// cout<<"ReadChunk:"<<tag<<endl;
#endif
unsigned sz=(unsigned)ReadInt();
_stack.push_back( _pos+sz );
return tag;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ExitChunk(){
_pos=_stack.back();
_stack.pop_back();
}
// ------------------------------------------------------------------------------------------------
unsigned B3DImporter::ChunkSize(){
return _stack.back()-_pos;
}
// ------------------------------------------------------------------------------------------------
template<class T>
T *B3DImporter::to_array( const vector<T> &v ){
if( v.empty() ) {
return 0;
}
T *p=new T[ v.size() ];
for( size_t i=0;i<v.size();++i ){
p[i]=v[i];
}
return p;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadTEXS(){
while( ChunkSize() ){
string name=ReadString();
/*int flags=*/ReadInt();
/*int blend=*/ReadInt();
/*aiVector2D pos=*/ReadVec2();
/*aiVector2D scale=*/ReadVec2();
/*float rot=*/ReadFloat();
_textures.push_back( name );
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBRUS(){
int n_texs=ReadInt();
if( n_texs<0 || n_texs>8 ){
Fail( "Bad texture count" );
}
while( ChunkSize() ){
string name=ReadString();
aiVector3D color=ReadVec3();
float alpha=ReadFloat();
float shiny=ReadFloat();
/*int blend=**/ReadInt();
int fx=ReadInt();
aiMaterial *mat=new aiMaterial;
_materials.push_back( mat );
// Name
aiString ainame( name );
mat->AddProperty( &ainame,AI_MATKEY_NAME );
// Diffuse color
mat->AddProperty( &color,1,AI_MATKEY_COLOR_DIFFUSE );
// Opacity
mat->AddProperty( &alpha,1,AI_MATKEY_OPACITY );
// Specular color
aiColor3D speccolor( shiny,shiny,shiny );
mat->AddProperty( &speccolor,1,AI_MATKEY_COLOR_SPECULAR );
// Specular power
float specpow=shiny*128;
mat->AddProperty( &specpow,1,AI_MATKEY_SHININESS );
// Double sided
if( fx & 0x10 ){
int i=1;
mat->AddProperty( &i,1,AI_MATKEY_TWOSIDED );
}
//Textures
for( int i=0;i<n_texs;++i ){
int texid=ReadInt();
if( texid<-1 || (texid>=0 && texid>=static_cast<int>(_textures.size())) ){
Fail( "Bad texture id" );
}
if( i==0 && texid>=0 ){
aiString texname( _textures[texid] );
mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) );
}
}
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadVRTS(){
_vflags=ReadInt();
_tcsets=ReadInt();
_tcsize=ReadInt();
if( _tcsets<0 || _tcsets>4 || _tcsize<0 || _tcsize>4 ){
Fail( "Bad texcoord data" );
}
int sz=12+(_vflags&1?12:0)+(_vflags&2?16:0)+(_tcsets*_tcsize*4);
int n_verts=ChunkSize()/sz;
int v0=_vertices.size();
_vertices.resize( v0+n_verts );
for( int i=0;i<n_verts;++i ){
Vertex &v=_vertices[v0+i];
memset( v.bones,0,sizeof(v.bones) );
memset( v.weights,0,sizeof(v.weights) );
v.vertex=ReadVec3();
if( _vflags & 1 ) v.normal=ReadVec3();
if( _vflags & 2 ) ReadQuat(); //skip v 4bytes...
for( int i=0;i<_tcsets;++i ){
float t[4]={0,0,0,0};
for( int j=0;j<_tcsize;++j ){
t[j]=ReadFloat();
}
t[1]=1-t[1];
if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] );
}
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadTRIS( int v0 ){
int matid=ReadInt();
if( matid==-1 ){
matid=0;
}else if( matid<0 || matid>=(int)_materials.size() ){
#ifdef DEBUG_B3D
cout<<"material id="<<matid<<endl;
#endif
Fail( "Bad material id" );
}
aiMesh *mesh=new aiMesh;
_meshes.push_back( mesh );
mesh->mMaterialIndex=matid;
mesh->mNumFaces=0;
mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE;
int n_tris=ChunkSize()/12;
aiFace *face=mesh->mFaces=new aiFace[n_tris];
for( int i=0;i<n_tris;++i ){
int i0=ReadInt()+v0;
int i1=ReadInt()+v0;
int i2=ReadInt()+v0;
if( i0<0 || i0>=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){
#ifdef DEBUG_B3D
cout<<"Bad triangle index: i0="<<i0<<", i1="<<i1<<", i2="<<i2<<endl;
#endif
Fail( "Bad triangle index" );
continue;
}
face->mNumIndices=3;
face->mIndices=new unsigned[3];
face->mIndices[0]=i0;
face->mIndices[1]=i1;
face->mIndices[2]=i2;
++mesh->mNumFaces;
++face;
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadMESH(){
/*int matid=*/ReadInt();
int v0=_vertices.size();
while( ChunkSize() ){
string t=ReadChunk();
if( t=="VRTS" ){
ReadVRTS();
}else if( t=="TRIS" ){
ReadTRIS( v0 );
}
ExitChunk();
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBONE( int id ){
while( ChunkSize() ){
int vertex=ReadInt();
float weight=ReadFloat();
if( vertex<0 || vertex>=(int)_vertices.size() ){
Fail( "Bad vertex index" );
}
Vertex &v=_vertices[vertex];
int i;
for( i=0;i<4;++i ){
if( !v.weights[i] ){
v.bones[i]=id;
v.weights[i]=weight;
break;
}
}
#ifdef DEBUG_B3D
if( i==4 ){
cout<<"Too many bone weights"<<endl;
}
#endif
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadKEYS( aiNodeAnim *nodeAnim ){
vector<aiVectorKey> trans,scale;
vector<aiQuatKey> rot;
int flags=ReadInt();
while( ChunkSize() ){
int frame=ReadInt();
if( flags & 1 ){
trans.push_back( aiVectorKey( frame,ReadVec3() ) );
}
if( flags & 2 ){
scale.push_back( aiVectorKey( frame,ReadVec3() ) );
}
if( flags & 4 ){
rot.push_back( aiQuatKey( frame,ReadQuat() ) );
}
}
if( flags & 1 ){
nodeAnim->mNumPositionKeys=trans.size();
nodeAnim->mPositionKeys=to_array( trans );
}
if( flags & 2 ){
nodeAnim->mNumScalingKeys=scale.size();
nodeAnim->mScalingKeys=to_array( scale );
}
if( flags & 4 ){
nodeAnim->mNumRotationKeys=rot.size();
nodeAnim->mRotationKeys=to_array( rot );
}
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadANIM(){
/*int flags=*/ReadInt();
int frames=ReadInt();
float fps=ReadFloat();
aiAnimation *anim=new aiAnimation;
_animations.push_back( anim );
anim->mDuration=frames;
anim->mTicksPerSecond=fps;
}
// ------------------------------------------------------------------------------------------------
aiNode *B3DImporter::ReadNODE( aiNode *parent ){
string name=ReadString();
aiVector3D t=ReadVec3();
aiVector3D s=ReadVec3();
aiQuaternion r=ReadQuat();
aiMatrix4x4 trans,scale,rot;
aiMatrix4x4::Translation( t,trans );
aiMatrix4x4::Scaling( s,scale );
rot=aiMatrix4x4( r.GetMatrix() );
aiMatrix4x4 tform=trans * rot * scale;
int nodeid=_nodes.size();
aiNode *node=new aiNode( name );
_nodes.push_back( node );
node->mParent=parent;
node->mTransformation=tform;
aiNodeAnim *nodeAnim=0;
vector<unsigned> meshes;
vector<aiNode*> children;
while( ChunkSize() ){
string t=ReadChunk();
if( t=="MESH" ){
int n=_meshes.size();
ReadMESH();
for( int i=n;i<(int)_meshes.size();++i ){
meshes.push_back( i );
}
}else if( t=="BONE" ){
ReadBONE( nodeid );
}else if( t=="ANIM" ){
ReadANIM();
}else if( t=="KEYS" ){
if( !nodeAnim ){
nodeAnim=new aiNodeAnim;
_nodeAnims.push_back( nodeAnim );
nodeAnim->mNodeName=node->mName;
}
ReadKEYS( nodeAnim );
}else if( t=="NODE" ){
aiNode *child=ReadNODE( node );
children.push_back( child );
}
ExitChunk();
}
node->mNumMeshes=meshes.size();
node->mMeshes=to_array( meshes );
node->mNumChildren=children.size();
node->mChildren=to_array( children );
return node;
}
// ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBB3D( aiScene *scene ){
_textures.clear();
_materials.clear();
_vertices.clear();
_meshes.clear();
_nodes.clear();
_nodeAnims.clear();
_animations.clear();
string t=ReadChunk();
if( t=="BB3D" ){
int version=ReadInt();
if (!DefaultLogger::isNullLogger()) {
char dmp[128];
ai_snprintf(dmp, 128, "B3D file format version: %i",version);
DefaultLogger::get()->info(dmp);
}
while( ChunkSize() ){
string t=ReadChunk();
if( t=="TEXS" ){
ReadTEXS();
}else if( t=="BRUS" ){
ReadBRUS();
}else if( t=="NODE" ){
ReadNODE( 0 );
}
ExitChunk();
}
}
ExitChunk();
if( !_nodes.size() ) Fail( "No nodes" );
if( !_meshes.size() ) Fail( "No meshes" );
//Fix nodes/meshes/bones
for(size_t i=0;i<_nodes.size();++i ){
aiNode *node=_nodes[i];
for( size_t j=0;j<node->mNumMeshes;++j ){
aiMesh *mesh=_meshes[node->mMeshes[j]];
int n_tris=mesh->mNumFaces;
int n_verts=mesh->mNumVertices=n_tris * 3;
aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0;
if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ];
if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ];
aiFace *face=mesh->mFaces;
vector< vector<aiVertexWeight> > vweights( _nodes.size() );
for( int i=0;i<n_verts;i+=3 ){
for( int j=0;j<3;++j ){
Vertex &v=_vertices[face->mIndices[j]];
*mv++=v.vertex;
if( mn ) *mn++=v.normal;
if( mc ) *mc++=v.texcoords;
face->mIndices[j]=i+j;
for( int k=0;k<4;++k ){
if( !v.weights[k] ) break;
int bone=v.bones[k];
float weight=v.weights[k];
vweights[bone].push_back( aiVertexWeight(i+j,weight) );
}
}
++face;
}
vector<aiBone*> bones;
for(size_t i=0;i<vweights.size();++i ){
vector<aiVertexWeight> &weights=vweights[i];
if( !weights.size() ) continue;
aiBone *bone=new aiBone;
bones.push_back( bone );
aiNode *bnode=_nodes[i];
bone->mName=bnode->mName;
bone->mNumWeights=weights.size();
bone->mWeights=to_array( weights );
aiMatrix4x4 mat=bnode->mTransformation;
while( bnode->mParent ){
bnode=bnode->mParent;
mat=bnode->mTransformation * mat;
}
bone->mOffsetMatrix=mat.Inverse();
}
mesh->mNumBones=bones.size();
mesh->mBones=to_array( bones );
}
}
//nodes
scene->mRootNode=_nodes[0];
//material
if( !_materials.size() ){
_materials.push_back( new aiMaterial );
}
scene->mNumMaterials=_materials.size();
scene->mMaterials=to_array( _materials );
//meshes
scene->mNumMeshes=_meshes.size();
scene->mMeshes=to_array( _meshes );
//animations
if( _animations.size()==1 && _nodeAnims.size() ){
aiAnimation *anim=_animations.back();
anim->mNumChannels=_nodeAnims.size();
anim->mChannels=to_array( _nodeAnims );
scene->mNumAnimations=_animations.size();
scene->mAnimations=to_array( _animations );
}
// convert to RH
MakeLeftHandedProcess makeleft;
makeleft.Execute( scene );
FlipWindingOrderProcess flip;
flip.Execute( scene );
}
#endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER

View file

@ -0,0 +1,130 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file Definition of the .b3d importer class. */
#ifndef AI_B3DIMPORTER_H_INC
#define AI_B3DIMPORTER_H_INC
#include <assimp/types.h>
#include <assimp/mesh.h>
#include <assimp/material.h>
#include "BaseImporter.h"
#include <string>
#include <vector>
struct aiNodeAnim;
struct aiNode;
struct aiAnimation;
namespace Assimp{
class B3DImporter : public BaseImporter{
public:
virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
protected:
virtual const aiImporterDesc* GetInfo () const;
virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
private:
int ReadByte();
int ReadInt();
float ReadFloat();
aiVector2D ReadVec2();
aiVector3D ReadVec3();
aiQuaternion ReadQuat();
std::string ReadString();
std::string ReadChunk();
void ExitChunk();
unsigned ChunkSize();
template<class T>
T *to_array( const std::vector<T> &v );
struct Vertex{
aiVector3D vertex;
aiVector3D normal;
aiVector3D texcoords;
unsigned char bones[4];
float weights[4];
};
AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void Fail( std::string str ) AI_WONT_RETURN_SUFFIX;
void ReadTEXS();
void ReadBRUS();
void ReadVRTS();
void ReadTRIS( int v0 );
void ReadMESH();
void ReadBONE( int id );
void ReadKEYS( aiNodeAnim *nodeAnim );
void ReadANIM();
aiNode *ReadNODE( aiNode *parent );
void ReadBB3D( aiScene *scene );
unsigned _pos;
// unsigned _size;
std::vector<unsigned char> _buf;
std::vector<unsigned> _stack;
std::vector<std::string> _textures;
std::vector<aiMaterial*> _materials;
int _vflags,_tcsets,_tcsize;
std::vector<Vertex> _vertices;
std::vector<aiNode*> _nodes;
std::vector<aiMesh*> _meshes;
std::vector<aiNodeAnim*> _nodeAnims;
std::vector<aiAnimation*> _animations;
};
}
#endif

View file

@ -0,0 +1,543 @@
/** Implementation of the BVH loader */
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
#include "BVHLoader.h"
#include "fast_atof.h"
#include "SkeletonMeshBuilder.h"
#include <assimp/Importer.hpp>
#include <memory>
#include "TinyFormatter.h"
#include <assimp/IOSystem.hpp>
#include <assimp/scene.h>
using namespace Assimp;
using namespace Assimp::Formatter;
static const aiImporterDesc desc = {
"BVH Importer (MoCap)",
"",
"",
"",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"bvh"
};
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
BVHLoader::BVHLoader()
: mLine(),
mAnimTickDuration(),
mAnimNumFrames(),
noSkeletonMesh()
{}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
BVHLoader::~BVHLoader()
{}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
{
// check file extension
const std::string extension = GetExtension(pFile);
if( extension == "bvh")
return true;
if ((!extension.length() || cs) && pIOHandler) {
const char* tokens[] = {"HIERARCHY"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
}
return false;
}
// ------------------------------------------------------------------------------------------------
void BVHLoader::SetupProperties(const Importer* pImp)
{
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
}
// ------------------------------------------------------------------------------------------------
// Loader meta information
const aiImporterDesc* BVHLoader::GetInfo () const
{
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
{
mFileName = pFile;
// read file into memory
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
if( file.get() == NULL)
throw DeadlyImportError( "Failed to open file " + pFile + ".");
size_t fileSize = file->FileSize();
if( fileSize == 0)
throw DeadlyImportError( "File is too small.");
mBuffer.resize( fileSize);
file->Read( &mBuffer.front(), 1, fileSize);
// start reading
mReader = mBuffer.begin();
mLine = 1;
ReadStructure( pScene);
if (!noSkeletonMesh) {
// build a dummy mesh for the skeleton so that we see something at least
SkeletonMeshBuilder meshBuilder( pScene);
}
// construct an animation from all the motion data we read
CreateAnimation( pScene);
}
// ------------------------------------------------------------------------------------------------
// Reads the file
void BVHLoader::ReadStructure( aiScene* pScene)
{
// first comes hierarchy
std::string header = GetNextToken();
if( header != "HIERARCHY")
ThrowException( "Expected header string \"HIERARCHY\".");
ReadHierarchy( pScene);
// then comes the motion data
std::string motion = GetNextToken();
if( motion != "MOTION")
ThrowException( "Expected beginning of motion data \"MOTION\".");
ReadMotion( pScene);
}
// ------------------------------------------------------------------------------------------------
// Reads the hierarchy
void BVHLoader::ReadHierarchy( aiScene* pScene)
{
std::string root = GetNextToken();
if( root != "ROOT")
ThrowException( "Expected root node \"ROOT\".");
// Go read the hierarchy from here
pScene->mRootNode = ReadNode();
}
// ------------------------------------------------------------------------------------------------
// Reads a node and recursively its childs and returns the created node;
aiNode* BVHLoader::ReadNode()
{
// first token is name
std::string nodeName = GetNextToken();
if( nodeName.empty() || nodeName == "{")
ThrowException( format() << "Expected node name, but found \"" << nodeName << "\"." );
// then an opening brace should follow
std::string openBrace = GetNextToken();
if( openBrace != "{")
ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"." );
// Create a node
aiNode* node = new aiNode( nodeName);
std::vector<aiNode*> childNodes;
// and create an bone entry for it
mNodes.push_back( Node( node));
Node& internNode = mNodes.back();
// now read the node's contents
while( 1)
{
std::string token = GetNextToken();
// node offset to parent node
if( token == "OFFSET")
ReadNodeOffset( node);
else if( token == "CHANNELS")
ReadNodeChannels( internNode);
else if( token == "JOINT")
{
// child node follows
aiNode* child = ReadNode();
child->mParent = node;
childNodes.push_back( child);
}
else if( token == "End")
{
// The real symbol is "End Site". Second part comes in a separate token
std::string siteToken = GetNextToken();
if( siteToken != "Site")
ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
aiNode* child = ReadEndSite( nodeName);
child->mParent = node;
childNodes.push_back( child);
}
else if( token == "}")
{
// we're done with that part of the hierarchy
break;
} else
{
// everything else is a parse error
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
}
}
// add the child nodes if there are any
if( childNodes.size() > 0)
{
node->mNumChildren = childNodes.size();
node->mChildren = new aiNode*[node->mNumChildren];
std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
}
// and return the sub-hierarchy we built here
return node;
}
// ------------------------------------------------------------------------------------------------
// Reads an end node and returns the created node.
aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
{
// check opening brace
std::string openBrace = GetNextToken();
if( openBrace != "{")
ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
// Create a node
aiNode* node = new aiNode( "EndSite_" + pParentName);
// now read the node's contents. Only possible entry is "OFFSET"
while( 1)
{
std::string token = GetNextToken();
// end node's offset
if( token == "OFFSET")
{
ReadNodeOffset( node);
}
else if( token == "}")
{
// we're done with the end node
break;
} else
{
// everything else is a parse error
ThrowException( format() << "Unknown keyword \"" << token << "\"." );
}
}
// and return the sub-hierarchy we built here
return node;
}
// ------------------------------------------------------------------------------------------------
// Reads a node offset for the given node
void BVHLoader::ReadNodeOffset( aiNode* pNode)
{
// Offset consists of three floats to read
aiVector3D offset;
offset.x = GetNextTokenAsFloat();
offset.y = GetNextTokenAsFloat();
offset.z = GetNextTokenAsFloat();
// build a transformation matrix from it
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
}
// ------------------------------------------------------------------------------------------------
// Reads the animation channels for the given node
void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
{
// number of channels. Use the float reader because we're lazy
float numChannelsFloat = GetNextTokenAsFloat();
unsigned int numChannels = (unsigned int) numChannelsFloat;
for( unsigned int a = 0; a < numChannels; a++)
{
std::string channelToken = GetNextToken();
if( channelToken == "Xposition")
pNode.mChannels.push_back( Channel_PositionX);
else if( channelToken == "Yposition")
pNode.mChannels.push_back( Channel_PositionY);
else if( channelToken == "Zposition")
pNode.mChannels.push_back( Channel_PositionZ);
else if( channelToken == "Xrotation")
pNode.mChannels.push_back( Channel_RotationX);
else if( channelToken == "Yrotation")
pNode.mChannels.push_back( Channel_RotationY);
else if( channelToken == "Zrotation")
pNode.mChannels.push_back( Channel_RotationZ);
else
ThrowException( format() << "Invalid channel specifier \"" << channelToken << "\"." );
}
}
// ------------------------------------------------------------------------------------------------
// Reads the motion data
void BVHLoader::ReadMotion( aiScene* /*pScene*/)
{
// Read number of frames
std::string tokenFrames = GetNextToken();
if( tokenFrames != "Frames:")
ThrowException( format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
float numFramesFloat = GetNextTokenAsFloat();
mAnimNumFrames = (unsigned int) numFramesFloat;
// Read frame duration
std::string tokenDuration1 = GetNextToken();
std::string tokenDuration2 = GetNextToken();
if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
ThrowException( format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"." );
mAnimTickDuration = GetNextTokenAsFloat();
// resize value vectors for each node
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
// now read all the data and store it in the corresponding node's value vector
for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
{
// on each line read the values for all nodes
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
{
// get as many values as the node has channels
for( unsigned int c = 0; c < it->mChannels.size(); ++c)
it->mChannelValues.push_back( GetNextTokenAsFloat());
}
// after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
}
}
// ------------------------------------------------------------------------------------------------
// Retrieves the next token
std::string BVHLoader::GetNextToken()
{
// skip any preceding whitespace
while( mReader != mBuffer.end())
{
if( !isspace( *mReader))
break;
// count lines
if( *mReader == '\n')
mLine++;
++mReader;
}
// collect all chars till the next whitespace. BVH is easy in respect to that.
std::string token;
while( mReader != mBuffer.end())
{
if( isspace( *mReader))
break;
token.push_back( *mReader);
++mReader;
// little extra logic to make sure braces are counted correctly
if( token == "{" || token == "}")
break;
}
// empty token means end of file, which is just fine
return token;
}
// ------------------------------------------------------------------------------------------------
// Reads the next token as a float
float BVHLoader::GetNextTokenAsFloat()
{
std::string token = GetNextToken();
if( token.empty())
ThrowException( "Unexpected end of file while trying to read a float");
// check if the float is valid by testing if the atof() function consumed every char of the token
const char* ctoken = token.c_str();
float result = 0.0f;
ctoken = fast_atoreal_move<float>( ctoken, result);
if( ctoken != token.c_str() + token.length())
ThrowException( format() << "Expected a floating point number, but found \"" << token << "\"." );
return result;
}
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError)
{
throw DeadlyImportError( format() << mFileName << ":" << mLine << " - " << pError);
}
// ------------------------------------------------------------------------------------------------
// Constructs an animation for the motion data and stores it in the given scene
void BVHLoader::CreateAnimation( aiScene* pScene)
{
// create the animation
pScene->mNumAnimations = 1;
pScene->mAnimations = new aiAnimation*[1];
aiAnimation* anim = new aiAnimation;
pScene->mAnimations[0] = anim;
// put down the basic parameters
anim->mName.Set( "Motion");
anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
anim->mDuration = double( mAnimNumFrames - 1);
// now generate the tracks for all nodes
anim->mNumChannels = mNodes.size();
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
// FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
for (unsigned int i = 0; i < anim->mNumChannels;++i)
anim->mChannels[i] = NULL;
for( unsigned int a = 0; a < anim->mNumChannels; a++)
{
const Node& node = mNodes[a];
const std::string nodeName = std::string( node.mNode->mName.data );
aiNodeAnim* nodeAnim = new aiNodeAnim;
anim->mChannels[a] = nodeAnim;
nodeAnim->mNodeName.Set( nodeName);
// translational part, if given
if( node.mChannels.size() == 6)
{
nodeAnim->mNumPositionKeys = mAnimNumFrames;
nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
aiVectorKey* poskey = nodeAnim->mPositionKeys;
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
{
poskey->mTime = double( fr);
// Now compute all translations in the right order
for( unsigned int channel = 0; channel < 3; ++channel)
{
switch( node.mChannels[channel])
{
case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
}
}
++poskey;
}
} else
{
// if no translation part is given, put a default sequence
aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
nodeAnim->mNumPositionKeys = 1;
nodeAnim->mPositionKeys = new aiVectorKey[1];
nodeAnim->mPositionKeys[0].mTime = 0.0;
nodeAnim->mPositionKeys[0].mValue = nodePos;
}
// rotation part. Always present. First find value offsets
{
unsigned int rotOffset = 0;
if( node.mChannels.size() == 6)
{
// Offset all further calculations
rotOffset = 3;
}
// Then create the number of rotation keys
nodeAnim->mNumRotationKeys = mAnimNumFrames;
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
aiQuatKey* rotkey = nodeAnim->mRotationKeys;
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
{
aiMatrix4x4 temp;
aiMatrix3x3 rotMatrix;
for( unsigned int channel = 0; channel < 3; ++channel)
{
// translate ZXY euler angels into a quaternion
const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f;
// Compute rotation transformations in the right order
switch (node.mChannels[rotOffset+channel])
{
case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
}
}
rotkey->mTime = double( fr);
rotkey->mValue = aiQuaternion( rotMatrix);
++rotkey;
}
}
// scaling part. Always just a default track
{
nodeAnim->mNumScalingKeys = 1;
nodeAnim->mScalingKeys = new aiVectorKey[1];
nodeAnim->mScalingKeys[0].mTime = 0.0;
nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
}
}
}
#endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER

View file

@ -0,0 +1,171 @@
/** Defines the BHV motion capturing loader class */
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BVHLoader.h
* @brief Biovision BVH import
*/
#ifndef AI_BVHLOADER_H_INC
#define AI_BVHLOADER_H_INC
#include "BaseImporter.h"
struct aiNode;
namespace Assimp
{
// --------------------------------------------------------------------------------
/** Loader class to read Motion Capturing data from a .bvh file.
*
* This format only contains a hierarchy of joints and a series of keyframes for
* the hierarchy. It contains no actual mesh data, but we generate a dummy mesh
* inside the loader just to be able to see something.
*/
class BVHLoader : public BaseImporter
{
/** Possible animation channels for which the motion data holds the values */
enum ChannelType
{
Channel_PositionX,
Channel_PositionY,
Channel_PositionZ,
Channel_RotationX,
Channel_RotationY,
Channel_RotationZ
};
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
struct Node
{
const aiNode* mNode;
std::vector<ChannelType> mChannels;
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
Node() { }
explicit Node( const aiNode* pNode) : mNode( pNode) { }
};
public:
BVHLoader();
~BVHLoader();
public:
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const;
void SetupProperties(const Importer* pImp);
const aiImporterDesc* GetInfo () const;
protected:
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
protected:
/** Reads the file */
void ReadStructure( aiScene* pScene);
/** Reads the hierarchy */
void ReadHierarchy( aiScene* pScene);
/** Reads a node and recursively its childs and returns the created node. */
aiNode* ReadNode();
/** Reads an end node and returns the created node. */
aiNode* ReadEndSite( const std::string& pParentName);
/** Reads a node offset for the given node */
void ReadNodeOffset( aiNode* pNode);
/** Reads the animation channels into the given node */
void ReadNodeChannels( BVHLoader::Node& pNode);
/** Reads the motion data */
void ReadMotion( aiScene* pScene);
/** Retrieves the next token */
std::string GetNextToken();
/** Reads the next token as a float */
float GetNextTokenAsFloat();
/** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
/** Constructs an animation for the motion data and stores it in the given scene */
void CreateAnimation( aiScene* pScene);
protected:
/** Filename, for a verbose error message */
std::string mFileName;
/** Buffer to hold the loaded file */
std::vector<char> mBuffer;
/** Next char to read from the buffer */
std::vector<char>::const_iterator mReader;
/** Current line, for error messages */
unsigned int mLine;
/** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index.
* Also contain the motion data for the node's channels
*/
std::vector<Node> mNodes;
/** basic Animation parameters */
float mAnimTickDuration;
unsigned int mAnimNumFrames;
bool noSkeletonMesh;
};
} // end of namespace Assimp
#endif // AI_BVHLOADER_H_INC

View file

@ -0,0 +1,617 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file BaseImporter.cpp
* @brief Implementation of BaseImporter
*/
#include "BaseImporter.h"
#include "FileSystemFilter.h"
#include "Importer.h"
#include "ByteSwapper.h"
#include <assimp/scene.h>
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <ios>
#include <list>
#include <memory>
#include <sstream>
#include <cctype>
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
BaseImporter::BaseImporter()
: m_progress()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
BaseImporter::~BaseImporter()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Imports the given file and returns the imported data.
aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler)
{
m_progress = pImp->GetProgressHandler();
ai_assert(m_progress);
// Gather configuration properties for this run
SetupProperties( pImp );
// Construct a file system filter to improve our success ratio at reading external files
FileSystemFilter filter(pFile,pIOHandler);
// create a scene object to hold the data
ScopeGuard<aiScene> sc(new aiScene());
// dispatch importing
try
{
InternReadFile( pFile, sc, &filter);
} catch( const std::exception& err ) {
// extract error description
m_ErrorText = err.what();
DefaultLogger::get()->error(m_ErrorText);
return NULL;
}
// return what we gathered from the import.
sc.dismiss();
return sc;
}
// ------------------------------------------------------------------------------------------------
void BaseImporter::SetupProperties(const Importer* /*pImp*/)
{
// the default implementation does nothing
}
// ------------------------------------------------------------------------------------------------
void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
{
const aiImporterDesc* desc = GetInfo();
ai_assert(desc != NULL);
const char* ext = desc->mFileExtensions;
ai_assert(ext != NULL);
const char* last = ext;
do {
if (!*ext || *ext == ' ') {
extensions.insert(std::string(last,ext-last));
ai_assert(ext-last > 0);
last = ext;
while(*last == ' ') {
++last;
}
}
}
while(*ext++);
}
// ------------------------------------------------------------------------------------------------
/*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler,
const std::string& pFile,
const char** tokens,
unsigned int numTokens,
unsigned int searchBytes /* = 200 */,
bool tokensSol /* false */)
{
ai_assert(NULL != tokens && 0 != numTokens && 0 != searchBytes);
if (!pIOHandler)
return false;
std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
if (pStream.get() ) {
// read 200 characters from the file
std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]);
char* buffer = _buffer.get();
if( NULL == buffer ) {
return false;
}
const size_t read = pStream->Read(buffer,1,searchBytes);
if( !read ) {
return false;
}
for( size_t i = 0; i < read; ++i ) {
buffer[ i ] = ::tolower( buffer[ i ] );
}
// It is not a proper handling of unicode files here ...
// ehm ... but it works in most cases.
char* cur = buffer,*cur2 = buffer,*end = &buffer[read];
while (cur != end) {
if( *cur ) {
*cur2++ = *cur;
}
++cur;
}
*cur2 = '\0';
for (unsigned int i = 0; i < numTokens;++i) {
ai_assert(NULL != tokens[i]);
const char* r = strstr(buffer,tokens[i]);
if( !r ) {
continue;
}
// We got a match, either we don't care where it is, or it happens to
// be in the beginning of the file / line
if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]);
return true;
}
}
}
return false;
}
// ------------------------------------------------------------------------------------------------
// Simple check for file extension
/*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile,
const char* ext0,
const char* ext1,
const char* ext2)
{
std::string::size_type pos = pFile.find_last_of('.');
// no file extension - can't read
if( pos == std::string::npos)
return false;
const char* ext_real = & pFile[ pos+1 ];
if( !ASSIMP_stricmp(ext_real,ext0) )
return true;
// check for other, optional, file extensions
if (ext1 && !ASSIMP_stricmp(ext_real,ext1))
return true;
if (ext2 && !ASSIMP_stricmp(ext_real,ext2))
return true;
return false;
}
// ------------------------------------------------------------------------------------------------
// Get file extension from path
/*static*/ std::string BaseImporter::GetExtension (const std::string& pFile)
{
std::string::size_type pos = pFile.find_last_of('.');
// no file extension at all
if( pos == std::string::npos)
return "";
std::string ret = pFile.substr(pos+1);
std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint
return ret;
}
// ------------------------------------------------------------------------------------------------
// Check for magic bytes at the beginning of the file.
/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
{
ai_assert(size <= 16 && _magic);
if (!pIOHandler) {
return false;
}
union {
const char* magic;
const uint16_t* magic_u16;
const uint32_t* magic_u32;
};
magic = reinterpret_cast<const char*>(_magic);
std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
if (pStream.get() ) {
// skip to offset
pStream->Seek(offset,aiOrigin_SET);
// read 'size' characters from the file
union {
char data[16];
uint16_t data_u16[8];
uint32_t data_u32[4];
};
if(size != pStream->Read(data,1,size)) {
return false;
}
for (unsigned int i = 0; i < num; ++i) {
// also check against big endian versions of tokens with size 2,4
// that's just for convenience, the chance that we cause conflicts
// is quite low and it can save some lines and prevent nasty bugs
if (2 == size) {
uint16_t rev = *magic_u16;
ByteSwap::Swap(&rev);
if (data_u16[0] == *magic_u16 || data_u16[0] == rev) {
return true;
}
}
else if (4 == size) {
uint32_t rev = *magic_u32;
ByteSwap::Swap(&rev);
if (data_u32[0] == *magic_u32 || data_u32[0] == rev) {
return true;
}
}
else {
// any length ... just compare
if(!memcmp(magic,data,size)) {
return true;
}
}
magic += size;
}
}
return false;
}
#include "../contrib/ConvertUTF/ConvertUTF.h"
// ------------------------------------------------------------------------------------------------
void ReportResult(ConversionResult res)
{
if(res == sourceExhausted) {
DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails");
}
else if(res == sourceIllegal) {
DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails");
}
}
// ------------------------------------------------------------------------------------------------
// Convert to UTF8 data
void BaseImporter::ConvertToUTF8(std::vector<char>& data)
{
ConversionResult result;
if(data.size() < 8) {
throw DeadlyImportError("File is too small");
}
// UTF 8 with BOM
if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
DefaultLogger::get()->debug("Found UTF-8 BOM ...");
std::copy(data.begin()+3,data.end(),data.begin());
data.resize(data.size()-3);
return;
}
// UTF 32 BE with BOM
if(*((uint32_t*)&data.front()) == 0xFFFE0000) {
// swap the endianness ..
for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) {
AI_SWAP4P(p);
}
}
// UTF 32 LE with BOM
if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
DefaultLogger::get()->debug("Found UTF-32 BOM ...");
const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1;
char* dstart,*dend;
std::vector<char> output;
do {
output.resize(output.size()?output.size()*3/2:data.size()/2);
dstart = &output.front(),dend = &output.back()+1;
result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
} while(result == targetExhausted);
ReportResult(result);
// copy to output buffer.
const size_t outlen = (size_t)(dstart-&output.front());
data.assign(output.begin(),output.begin()+outlen);
return;
}
// UTF 16 BE with BOM
if(*((uint16_t*)&data.front()) == 0xFFFE) {
// swap the endianness ..
for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) {
ByteSwap::Swap2(p);
}
}
// UTF 16 LE with BOM
if(*((uint16_t*)&data.front()) == 0xFEFF) {
DefaultLogger::get()->debug("Found UTF-16 BOM ...");
const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1);
char* dstart,*dend;
std::vector<char> output;
do {
output.resize(output.size()?output.size()*3/2:data.size()*3/4);
dstart = &output.front(),dend = &output.back()+1;
result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
} while(result == targetExhausted);
ReportResult(result);
// copy to output buffer.
const size_t outlen = (size_t)(dstart-&output.front());
data.assign(output.begin(),output.begin()+outlen);
return;
}
}
// ------------------------------------------------------------------------------------------------
// Convert to UTF8 data to ISO-8859-1
void BaseImporter::ConvertUTF8toISO8859_1(std::string& data)
{
size_t size = data.size();
size_t i = 0, j = 0;
while(i < size) {
if ((unsigned char) data[i] < (size_t) 0x80) {
data[j] = data[i];
} else if(i < size - 1) {
if((unsigned char) data[i] == 0xC2) {
data[j] = data[++i];
} else if((unsigned char) data[i] == 0xC3) {
data[j] = ((unsigned char) data[++i] + 0x40);
} else {
std::stringstream stream;
stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
DefaultLogger::get()->error(stream.str());
data[j++] = data[i++];
data[j] = data[i];
}
} else {
DefaultLogger::get()->error("UTF8 code but only one character remaining");
data[j] = data[i];
}
i++; j++;
}
data.resize(j);
}
// ------------------------------------------------------------------------------------------------
void BaseImporter::TextFileToBuffer(IOStream* stream,
std::vector<char>& data,
TextFileMode mode)
{
ai_assert(NULL != stream);
const size_t fileSize = stream->FileSize();
if (mode == FORBID_EMPTY) {
if(!fileSize) {
throw DeadlyImportError("File is empty");
}
}
data.reserve(fileSize+1);
data.resize(fileSize);
if(fileSize > 0) {
if(fileSize != stream->Read( &data[0], 1, fileSize)) {
throw DeadlyImportError("File read error");
}
ConvertToUTF8(data);
}
// append a binary zero to simplify string parsing
data.push_back(0);
}
// ------------------------------------------------------------------------------------------------
namespace Assimp
{
// Represents an import request
struct LoadRequest
{
LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id)
: file(_file), flags(_flags), refCnt(1),scene(NULL), loaded(false), id(_id)
{
if (_map)
map = *_map;
}
const std::string file;
unsigned int flags;
unsigned int refCnt;
aiScene* scene;
bool loaded;
BatchLoader::PropertyMap map;
unsigned int id;
bool operator== (const std::string& f) {
return file == f;
}
};
}
// ------------------------------------------------------------------------------------------------
// BatchLoader::pimpl data structure
struct Assimp::BatchData
{
BatchData()
: pIOSystem()
, pImporter()
, next_id(0xffff)
{}
// IO system to be used for all imports
IOSystem* pIOSystem;
// Importer used to load all meshes
Importer* pImporter;
// List of all imports
std::list<LoadRequest> requests;
// Base path
std::string pathBase;
// Id for next item
unsigned int next_id;
};
// ------------------------------------------------------------------------------------------------
BatchLoader::BatchLoader(IOSystem* pIO)
{
ai_assert(NULL != pIO);
data = new BatchData();
data->pIOSystem = pIO;
data->pImporter = new Importer();
data->pImporter->SetIOHandler(data->pIOSystem);
}
// ------------------------------------------------------------------------------------------------
BatchLoader::~BatchLoader()
{
// delete all scenes wthat have not been polled by the user
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
delete (*it).scene;
}
data->pImporter->SetIOHandler(NULL); /* get pointer back into our possession */
delete data->pImporter;
delete data;
}
// ------------------------------------------------------------------------------------------------
unsigned int BatchLoader::AddLoadRequest (const std::string& file,
unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/)
{
ai_assert(!file.empty());
// check whether we have this loading request already
std::list<LoadRequest>::iterator it;
for (it = data->requests.begin();it != data->requests.end(); ++it) {
// Call IOSystem's path comparison function here
if (data->pIOSystem->ComparePaths((*it).file,file)) {
if (map) {
if (!((*it).map == *map))
continue;
}
else if (!(*it).map.empty())
continue;
(*it).refCnt++;
return (*it).id;
}
}
// no, we don't have it. So add it to the queue ...
data->requests.push_back(LoadRequest(file,steps,map,data->next_id));
return data->next_id++;
}
// ------------------------------------------------------------------------------------------------
aiScene* BatchLoader::GetImport (unsigned int which)
{
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
if ((*it).id == which && (*it).loaded) {
aiScene* sc = (*it).scene;
if (!(--(*it).refCnt)) {
data->requests.erase(it);
}
return sc;
}
}
return NULL;
}
// ------------------------------------------------------------------------------------------------
void BatchLoader::LoadAll()
{
// no threaded implementation for the moment
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
// force validation in debug builds
unsigned int pp = (*it).flags;
#ifdef ASSIMP_BUILD_DEBUG
pp |= aiProcess_ValidateDataStructure;
#endif
// setup config properties if necessary
ImporterPimpl* pimpl = data->pImporter->Pimpl();
pimpl->mFloatProperties = (*it).map.floats;
pimpl->mIntProperties = (*it).map.ints;
pimpl->mStringProperties = (*it).map.strings;
pimpl->mMatrixProperties = (*it).map.matrices;
if (!DefaultLogger::isNullLogger())
{
DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%");
DefaultLogger::get()->info("File: " + (*it).file);
}
data->pImporter->ReadFile((*it).file,pp);
(*it).scene = data->pImporter->GetOrphanedScene();
(*it).loaded = true;
DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%");
}
}

View file

@ -0,0 +1,400 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file Definition of the base class for all importer worker classes. */
#ifndef INCLUDED_AI_BASEIMPORTER_H
#define INCLUDED_AI_BASEIMPORTER_H
#include "Exceptional.h"
#include <string>
#include <map>
#include <vector>
#include <set>
#include <assimp/types.h>
#include <assimp/ProgressHandler.hpp>
struct aiScene;
namespace Assimp {
class Importer;
class IOSystem;
class BaseProcess;
class SharedPostProcessInfo;
class IOStream;
// utility to do char4 to uint32 in a portable manner
#define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \
(string[1] << 16) + (string[2] << 8) + string[3]))
// ---------------------------------------------------------------------------
template <typename T>
struct ScopeGuard
{
explicit ScopeGuard(T* obj) : obj(obj), mdismiss() {}
~ScopeGuard () throw() {
if (!mdismiss) {
delete obj;
}
obj = NULL;
}
T* dismiss() {
mdismiss=true;
return obj;
}
operator T*() {
return obj;
}
T* operator -> () {
return obj;
}
private:
// no copying allowed.
ScopeGuard();
ScopeGuard( const ScopeGuard & );
ScopeGuard &operator = ( const ScopeGuard & );
T* obj;
bool mdismiss;
};
// ---------------------------------------------------------------------------
/** FOR IMPORTER PLUGINS ONLY: The BaseImporter defines a common interface
* for all importer worker classes.
*
* The interface defines two functions: CanRead() is used to check if the
* importer can handle the format of the given file. If an implementation of
* this function returns true, the importer then calls ReadFile() which
* imports the given file. ReadFile is not overridable, it just calls
* InternReadFile() and catches any ImportErrorException that might occur.
*/
class ASSIMP_API BaseImporter
{
friend class Importer;
public:
/** Constructor to be privately used by #Importer */
BaseImporter();
/** Destructor, private as well */
virtual ~BaseImporter();
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
*
* The implementation should be as quick as possible. A check for
* the file extension is enough. If no suitable loader is found with
* this strategy, CanRead() is called again, the 'checkSig' parameter
* set to true this time. Now the implementation is expected to
* perform a full check of the file structure, possibly searching the
* first bytes of the file for magic identifiers or keywords.
*
* @param pFile Path and file name of the file to be examined.
* @param pIOHandler The IO handler to use for accessing any file.
* @param checkSig Set to true if this method is called a second time.
* This time, the implementation may take more time to examine the
* contents of the file to be loaded for magic bytes, keywords, etc
* to be able to load files with unknown/not existent file extensions.
* @return true if the class can read this file, false if not.
*/
virtual bool CanRead(
const std::string& pFile,
IOSystem* pIOHandler,
bool checkSig
) const = 0;
// -------------------------------------------------------------------
/** Imports the given file and returns the imported data.
* If the import succeeds, ownership of the data is transferred to
* the caller. If the import fails, NULL is returned. The function
* takes care that any partially constructed data is destroyed
* beforehand.
*
* @param pImp #Importer object hosting this loader.
* @param pFile Path of the file to be imported.
* @param pIOHandler IO-Handler used to open this and possible other files.
* @return The imported data or NULL if failed. If it failed a
* human-readable error description can be retrieved by calling
* GetErrorText()
*
* @note This function is not intended to be overridden. Implement
* InternReadFile() to do the import. If an exception is thrown somewhere
* in InternReadFile(), this function will catch it and transform it into
* a suitable response to the caller.
*/
aiScene* ReadFile(
const Importer* pImp,
const std::string& pFile,
IOSystem* pIOHandler
);
// -------------------------------------------------------------------
/** Returns the error description of the last error that occurred.
* @return A description of the last error that occurred. An empty
* string if there was no error.
*/
const std::string& GetErrorText() const {
return m_ErrorText;
}
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list.
* @param pImp Importer instance
*/
virtual void SetupProperties(
const Importer* pImp
);
// -------------------------------------------------------------------
/** Called by #Importer::GetImporterInfo to get a description of
* some loader features. Importers must provide this information. */
virtual const aiImporterDesc* GetInfo() const = 0;
// -------------------------------------------------------------------
/** Called by #Importer::GetExtensionList for each loaded importer.
* Take the extension list contained in the structure returned by
* #GetInfo and insert all file extensions into the given set.
* @param extension set to collect file extensions in*/
void GetExtensionList(std::set<std::string>& extensions);
protected:
// -------------------------------------------------------------------
/** Imports the given file into the given scene structure. The
* function is expected to throw an ImportErrorException if there is
* an error. If it terminates normally, the data in aiScene is
* expected to be correct. Override this function to implement the
* actual importing.
* <br>
* The output scene must meet the following requirements:<br>
* <ul>
* <li>At least a root node must be there, even if its only purpose
* is to reference one mesh.</li>
* <li>aiMesh::mPrimitiveTypes may be 0. The types of primitives
* in the mesh are determined automatically in this case.</li>
* <li>the vertex data is stored in a pseudo-indexed "verbose" format.
* In fact this means that every vertex that is referenced by
* a face is unique. Or the other way round: a vertex index may
* not occur twice in a single aiMesh.</li>
* <li>aiAnimation::mDuration may be -1. Assimp determines the length
* of the animation automatically in this case as the length of
* the longest animation channel.</li>
* <li>aiMesh::mBitangents may be NULL if tangents and normals are
* given. In this case bitangents are computed as the cross product
* between normal and tangent.</li>
* <li>There needn't be a material. If none is there a default material
* is generated. However, it is recommended practice for loaders
* to generate a default material for yourself that matches the
* default material setting for the file format better than Assimp's
* generic default material. Note that default materials *should*
* be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded
* or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy)
* texture. </li>
* </ul>
* If the AI_SCENE_FLAGS_INCOMPLETE-Flag is <b>not</b> set:<ul>
* <li> at least one mesh must be there</li>
* <li> there may be no meshes with 0 vertices or faces</li>
* </ul>
* This won't be checked (except by the validation step): Assimp will
* crash if one of the conditions is not met!
*
* @param pFile Path of the file to be imported.
* @param pScene The scene object to hold the imported data.
* NULL is not a valid parameter.
* @param pIOHandler The IO handler to use for any file access.
* NULL is not a valid parameter. */
virtual void InternReadFile(
const std::string& pFile,
aiScene* pScene,
IOSystem* pIOHandler
) = 0;
public: // static utilities
// -------------------------------------------------------------------
/** A utility for CanRead().
*
* The function searches the header of a file for a specific token
* and returns true if this token is found. This works for text
* files only. There is a rudimentary handling of UNICODE files.
* The comparison is case independent.
*
* @param pIOSystem IO System to work with
* @param file File name of the file
* @param tokens List of tokens to search for
* @param numTokens Size of the token array
* @param searchBytes Number of bytes to be searched for the tokens.
*/
static bool SearchFileHeaderForToken(
IOSystem* pIOSystem,
const std::string& file,
const char** tokens,
unsigned int numTokens,
unsigned int searchBytes = 200,
bool tokensSol = false);
// -------------------------------------------------------------------
/** @brief Check whether a file has a specific file extension
* @param pFile Input file
* @param ext0 Extension to check for. Lowercase characters only, no dot!
* @param ext1 Optional second extension
* @param ext2 Optional third extension
* @note Case-insensitive
*/
static bool SimpleExtensionCheck (
const std::string& pFile,
const char* ext0,
const char* ext1 = NULL,
const char* ext2 = NULL);
// -------------------------------------------------------------------
/** @brief Extract file extension from a string
* @param pFile Input file
* @return Extension without trailing dot, all lowercase
*/
static std::string GetExtension (
const std::string& pFile);
// -------------------------------------------------------------------
/** @brief Check whether a file starts with one or more magic tokens
* @param pFile Input file
* @param pIOHandler IO system to be used
* @param magic n magic tokens
* @params num Size of magic
* @param offset Offset from file start where tokens are located
* @param Size of one token, in bytes. Maximally 16 bytes.
* @return true if one of the given tokens was found
*
* @note For convinence, the check is also performed for the
* byte-swapped variant of all tokens (big endian). Only for
* tokens of size 2,4.
*/
static bool CheckMagicToken(
IOSystem* pIOHandler,
const std::string& pFile,
const void* magic,
unsigned int num,
unsigned int offset = 0,
unsigned int size = 4);
// -------------------------------------------------------------------
/** An utility for all text file loaders. It converts a file to our
* UTF8 character set. Errors are reported, but ignored.
*
* @param data File buffer to be converted to UTF8 data. The buffer
* is resized as appropriate. */
static void ConvertToUTF8(
std::vector<char>& data);
// -------------------------------------------------------------------
/** An utility for all text file loaders. It converts a file from our
* UTF8 character set back to ISO-8859-1. Errors are reported, but ignored.
*
* @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer
* is resized as appropriate. */
static void ConvertUTF8toISO8859_1(
std::string& data);
enum TextFileMode { ALLOW_EMPTY, FORBID_EMPTY };
// -------------------------------------------------------------------
/** Utility for text file loaders which copies the contents of the
* file into a memory buffer and converts it to our UTF8
* representation.
* @param stream Stream to read from.
* @param data Output buffer to be resized and filled with the
* converted text file data. The buffer is terminated with
* a binary 0.
* @param mode Whether it is OK to load empty text files. */
static void TextFileToBuffer(
IOStream* stream,
std::vector<char>& data,
TextFileMode mode = FORBID_EMPTY);
// -------------------------------------------------------------------
/** Utility function to move a std::vector into a aiScene array
* @param vec The vector to be moved
* @param out The output pointer to the allocated array.
* @param numOut The output count of elements copied. */
template<typename T>
AI_FORCE_INLINE
static void CopyVector(
std::vector<T>& vec,
T*& out,
unsigned int& outLength)
{
outLength = unsigned(vec.size());
if (outLength) {
out = new T[outLength];
std::swap_ranges(vec.begin(), vec.end(), out);
}
}
protected:
/** Error description in case there was one. */
std::string m_ErrorText;
/** Currently set progress handler */
ProgressHandler* m_progress;
};
} // end of namespace Assimp
#endif // AI_BASEIMPORTER_H_INC

View file

@ -0,0 +1,105 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file Implementation of BaseProcess */
#include "BaseImporter.h"
#include "BaseProcess.h"
#include <assimp/DefaultLogger.hpp>
#include <assimp/scene.h>
#include "Importer.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
BaseProcess::BaseProcess()
: shared()
, progress()
{
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
BaseProcess::~BaseProcess()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
void BaseProcess::ExecuteOnScene( Importer* pImp)
{
ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene);
progress = pImp->GetProgressHandler();
ai_assert(progress);
SetupProperties( pImp );
// catch exceptions thrown inside the PostProcess-Step
try
{
Execute(pImp->Pimpl()->mScene);
} catch( const std::exception& err ) {
// extract error description
pImp->Pimpl()->mErrorString = err.what();
DefaultLogger::get()->error(pImp->Pimpl()->mErrorString);
// and kill the partially imported data
delete pImp->Pimpl()->mScene;
pImp->Pimpl()->mScene = NULL;
}
}
// ------------------------------------------------------------------------------------------------
void BaseProcess::SetupProperties(const Importer* /*pImp*/)
{
// the default implementation does nothing
}
// ------------------------------------------------------------------------------------------------
bool BaseProcess::RequireVerboseFormat() const
{
return true;
}

View file

@ -0,0 +1,294 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file Base class of all import post processing steps */
#ifndef INCLUDED_AI_BASEPROCESS_H
#define INCLUDED_AI_BASEPROCESS_H
#include <map>
#include <assimp/types.h>
#include "GenericProperty.h"
struct aiScene;
namespace Assimp {
class Importer;
// ---------------------------------------------------------------------------
/** Helper class to allow post-processing steps to interact with each other.
*
* The class maintains a simple property list that can be used by pp-steps
* to provide additional information to other steps. This is primarily
* intended for cross-step optimizations.
*/
class SharedPostProcessInfo
{
public:
struct Base
{
virtual ~Base()
{}
};
//! Represents data that is allocated on the heap, thus needs to be deleted
template <typename T>
struct THeapData : public Base
{
explicit THeapData(T* in)
: data (in)
{}
~THeapData()
{
delete data;
}
T* data;
};
//! Represents static, by-value data not allocated on the heap
template <typename T>
struct TStaticData : public Base
{
explicit TStaticData(T in)
: data (in)
{}
~TStaticData()
{}
T data;
};
// some typedefs for cleaner code
typedef unsigned int KeyType;
typedef std::map<KeyType, Base*> PropertyMap;
public:
//! Destructor
~SharedPostProcessInfo()
{
Clean();
}
//! Remove all stored properties from the table
void Clean()
{
// invoke the virtual destructor for all stored properties
for (PropertyMap::iterator it = pmap.begin(), end = pmap.end();
it != end; ++it)
{
delete (*it).second;
}
pmap.clear();
}
//! Add a heap property to the list
template <typename T>
void AddProperty( const char* name, T* in ){
AddProperty(name,(Base*)new THeapData<T>(in));
}
//! Add a static by-value property to the list
template <typename T>
void AddProperty( const char* name, T in ){
AddProperty(name,(Base*)new TStaticData<T>(in));
}
//! Get a heap property
template <typename T>
bool GetProperty( const char* name, T*& out ) const
{
THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name);
if(!t)
{
out = NULL;
return false;
}
out = t->data;
return true;
}
//! Get a static, by-value property
template <typename T>
bool GetProperty( const char* name, T& out ) const
{
TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name);
if(!t)return false;
out = t->data;
return true;
}
//! Remove a property of a specific type
void RemoveProperty( const char* name) {
SetGenericPropertyPtr<Base>(pmap,name,NULL);
}
private:
void AddProperty( const char* name, Base* data) {
SetGenericPropertyPtr<Base>(pmap,name,data);
}
Base* GetPropertyInternal( const char* name) const {
return GetGenericProperty<Base*>(pmap,name,NULL);
}
private:
//! Map of all stored properties
PropertyMap pmap;
};
#if 0
// ---------------------------------------------------------------------------
/** @brief Represents a dependency table for a postprocessing steps.
*
* For future use.
*/
struct PPDependencyTable
{
unsigned int execute_me_before_these;
unsigned int execute_me_after_these;
unsigned int only_if_these_are_not_specified;
unsigned int mutually_exclusive_with;
};
#endif
#define AI_SPP_SPATIAL_SORT "$Spat"
// ---------------------------------------------------------------------------
/** The BaseProcess defines a common interface for all post processing steps.
* A post processing step is run after a successful import if the caller
* specified the corresponding flag when calling ReadFile().
* Enum #aiPostProcessSteps defines which flags are available.
* After a successful import the Importer iterates over its internal array
* of processes and calls IsActive() on each process to evaluate if the step
* should be executed. If the function returns true, the class' Execute()
* function is called subsequently.
*/
class ASSIMP_API_WINONLY BaseProcess
{
friend class Importer;
public:
/** Constructor to be privately used by Importer */
BaseProcess();
/** Destructor, private as well */
virtual ~BaseProcess();
public:
// -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag.
* @param pFlags The processing flags the importer was called with. A
* bitwise combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields,
* false if not.
*/
virtual bool IsActive( unsigned int pFlags) const = 0;
// -------------------------------------------------------------------
/** Check whether this step expects its input vertex data to be
* in verbose format. */
virtual bool RequireVerboseFormat() const;
// -------------------------------------------------------------------
/** Executes the post processing step on the given imported data.
* The function deletes the scene if the postprocess step fails (
* the object pointer will be set to NULL).
* @param pImp Importer instance (pImp->mScene must be valid)
*/
void ExecuteOnScene( Importer* pImp);
// -------------------------------------------------------------------
/** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration
* basing on the Importer's configuration property list.
*/
virtual void SetupProperties(const Importer* pImp);
// -------------------------------------------------------------------
/** Executes the post processing step on the given imported data.
* A process should throw an ImportErrorException* if it fails.
* This method must be implemented by deriving classes.
* @param pScene The imported data to work at.
*/
virtual void Execute( aiScene* pScene) = 0;
// -------------------------------------------------------------------
/** Assign a new SharedPostProcessInfo to the step. This object
* allows multiple postprocess steps to share data.
* @param sh May be NULL
*/
inline void SetSharedData(SharedPostProcessInfo* sh) {
shared = sh;
}
// -------------------------------------------------------------------
/** Get the shared data that is assigned to the step.
*/
inline SharedPostProcessInfo* GetSharedData() {
return shared;
}
protected:
/** See the doc of #SharedPostProcessInfo for more details */
SharedPostProcessInfo* shared;
/** Currently active progress handler */
ProgressHandler* progress;
};
} // end of namespace Assimp
#endif // AI_BASEPROCESS_H_INC

View file

@ -0,0 +1,152 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file Bitmap.cpp
* @brief Defines bitmap format helper for textures
*
* Used for file formats which embed their textures into the model file.
*/
#include "Bitmap.h"
#include <assimp/texture.h>
#include <assimp/IOStream.hpp>
#include "ByteSwapper.h"
namespace Assimp {
void Bitmap::Save(aiTexture* texture, IOStream* file) {
if(file != NULL) {
Header header;
DIB dib;
dib.size = DIB::dib_size;
dib.width = texture->mWidth;
dib.height = texture->mHeight;
dib.planes = 1;
dib.bits_per_pixel = 8 * mBytesPerPixel;
dib.compression = 0;
dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height;
dib.x_resolution = 0;
dib.y_resolution = 0;
dib.nb_colors = 0;
dib.nb_important_colors = 0;
header.type = 0x4D42; // 'BM'
header.offset = Header::header_size + DIB::dib_size;
header.size = header.offset + dib.image_size;
header.reserved1 = 0;
header.reserved2 = 0;
WriteHeader(header, file);
WriteDIB(dib, file);
WriteData(texture, file);
}
}
template<typename T>
inline std::size_t Copy(uint8_t* data, T& field) {
#ifdef AI_BUILD_BIG_ENDIAN
T field_swapped=AI_BE(field);
std::memcpy(data, &field_swapped, sizeof(field)); return sizeof(field);
#else
std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
#endif
}
void Bitmap::WriteHeader(Header& header, IOStream* file) {
uint8_t data[Header::header_size];
std::size_t offset = 0;
offset += Copy(&data[offset], header.type);
offset += Copy(&data[offset], header.size);
offset += Copy(&data[offset], header.reserved1);
offset += Copy(&data[offset], header.reserved2);
offset += Copy(&data[offset], header.offset);
file->Write(data, Header::header_size, 1);
}
void Bitmap::WriteDIB(DIB& dib, IOStream* file) {
uint8_t data[DIB::dib_size];
std::size_t offset = 0;
offset += Copy(&data[offset], dib.size);
offset += Copy(&data[offset], dib.width);
offset += Copy(&data[offset], dib.height);
offset += Copy(&data[offset], dib.planes);
offset += Copy(&data[offset], dib.bits_per_pixel);
offset += Copy(&data[offset], dib.compression);
offset += Copy(&data[offset], dib.image_size);
offset += Copy(&data[offset], dib.x_resolution);
offset += Copy(&data[offset], dib.y_resolution);
offset += Copy(&data[offset], dib.nb_colors);
offset += Copy(&data[offset], dib.nb_important_colors);
file->Write(data, DIB::dib_size, 1);
}
void Bitmap::WriteData(aiTexture* texture, IOStream* file) {
static const std::size_t padding_offset = 4;
static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0};
unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset;
uint8_t pixel[mBytesPerPixel];
for(std::size_t i = 0; i < texture->mHeight; ++i) {
for(std::size_t j = 0; j < texture->mWidth; ++j) {
const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format
pixel[0] = texel.r;
pixel[1] = texel.g;
pixel[2] = texel.b;
pixel[3] = texel.a;
file->Write(pixel, mBytesPerPixel, 1);
}
file->Write(padding_data, padding, 1);
}
}
}

View file

@ -0,0 +1,144 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file Bitmap.h
* @brief Defines bitmap format helper for textures
*
* Used for file formats which embed their textures into the model file.
*/
#ifndef AI_BITMAP_H_INC
#define AI_BITMAP_H_INC
#include <stdint.h>
#include <cstddef>
struct aiTexture;
namespace Assimp {
class IOStream;
class Bitmap {
protected:
struct Header {
uint16_t type;
uint32_t size;
uint16_t reserved1;
uint16_t reserved2;
uint32_t offset;
// We define the struct size because sizeof(Header) might return a wrong result because of structure padding.
// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
static const std::size_t header_size =
sizeof(uint16_t) + // type
sizeof(uint32_t) + // size
sizeof(uint16_t) + // reserved1
sizeof(uint16_t) + // reserved2
sizeof(uint32_t); // offset
};
struct DIB {
uint32_t size;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bits_per_pixel;
uint32_t compression;
uint32_t image_size;
int32_t x_resolution;
int32_t y_resolution;
uint32_t nb_colors;
uint32_t nb_important_colors;
// We define the struct size because sizeof(DIB) might return a wrong result because of structure padding.
// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
static const std::size_t dib_size =
sizeof(uint32_t) + // size
sizeof(int32_t) + // width
sizeof(int32_t) + // height
sizeof(uint16_t) + // planes
sizeof(uint16_t) + // bits_per_pixel
sizeof(uint32_t) + // compression
sizeof(uint32_t) + // image_size
sizeof(int32_t) + // x_resolution
sizeof(int32_t) + // y_resolution
sizeof(uint32_t) + // nb_colors
sizeof(uint32_t); // nb_important_colors
};
static const std::size_t mBytesPerPixel = 4;
public:
static void Save(aiTexture* texture, IOStream* file);
protected:
static void WriteHeader(Header& header, IOStream* file);
static void WriteDIB(DIB& dib, IOStream* file);
static void WriteData(aiTexture* texture, IOStream* file);
};
}
#endif // AI_BITMAP_H_INC

View file

@ -0,0 +1,202 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2013, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderBMesh.cpp
* @brief Conversion of Blender's new BMesh stuff
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderDNA.h"
#include "BlenderScene.h"
#include "BlenderBMesh.h"
#include "BlenderTessellator.h"
namespace Assimp
{
template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: ";
}
using namespace Assimp;
using namespace Assimp::Blender;
using namespace Assimp::Formatter;
// ------------------------------------------------------------------------------------------------
BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ):
BMesh( mesh ),
triMesh( NULL )
{
}
// ------------------------------------------------------------------------------------------------
BlenderBMeshConverter::~BlenderBMeshConverter( )
{
DestroyTriMesh( );
}
// ------------------------------------------------------------------------------------------------
bool BlenderBMeshConverter::ContainsBMesh( ) const
{
// TODO - Should probably do some additional verification here
return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
}
// ------------------------------------------------------------------------------------------------
const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
{
AssertValidMesh( );
AssertValidSizes( );
PrepareTriMesh( );
for ( int i = 0; i < BMesh->totpoly; ++i )
{
const MPoly& poly = BMesh->mpoly[ i ];
ConvertPolyToFaces( poly );
}
return triMesh;
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AssertValidMesh( )
{
if ( !ContainsBMesh( ) )
{
ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" );
}
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AssertValidSizes( )
{
if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
{
ThrowException( "BMesh poly array has incorrect size" );
}
if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
{
ThrowException( "BMesh loop array has incorrect size" );
}
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::PrepareTriMesh( )
{
if ( triMesh )
{
DestroyTriMesh( );
}
triMesh = new Mesh( *BMesh );
triMesh->totface = 0;
triMesh->mface.clear( );
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::DestroyTriMesh( )
{
delete triMesh;
triMesh = NULL;
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
{
const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
if ( poly.totloop == 3 || poly.totloop == 4 )
{
AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
// UVs are optional, so only convert when present.
if ( BMesh->mloopuv.size() )
{
if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
{
ThrowException( "BMesh uv loop array has incorrect size" );
}
const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
}
}
else if ( poly.totloop > 4 )
{
#if ASSIMP_BLEND_WITH_GLU_TESSELLATE
BlenderTessellatorGL tessGL( *this );
tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
#elif ASSIMP_BLEND_WITH_POLY_2_TRI
BlenderTessellatorP2T tessP2T( *this );
tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
#endif
}
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
{
MFace face;
face.v1 = v1;
face.v2 = v2;
face.v3 = v3;
face.v4 = v4;
// TODO - Work out how materials work
face.mat_nr = 0;
triMesh->mface.push_back( face );
triMesh->totface = triMesh->mface.size( );
}
// ------------------------------------------------------------------------------------------------
void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 )
{
MTFace mtface;
memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
if ( uv4 )
{
memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
}
triMesh->mtface.push_back( mtface );
}
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

View file

@ -0,0 +1,94 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2013, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderBMesh.h
* @brief Conversion of Blender's new BMesh stuff
*/
#ifndef INCLUDED_AI_BLEND_BMESH_H
#define INCLUDED_AI_BLEND_BMESH_H
#include "LogAux.h"
namespace Assimp
{
// TinyFormatter.h
namespace Formatter
{
template < typename T,typename TR, typename A > class basic_formatter;
typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
}
// BlenderScene.h
namespace Blender
{
struct Mesh;
struct MPoly;
struct MLoop;
}
class BlenderBMeshConverter: public LogFunctions< BlenderBMeshConverter >
{
public:
BlenderBMeshConverter( const Blender::Mesh* mesh );
~BlenderBMeshConverter( );
bool ContainsBMesh( ) const;
const Blender::Mesh* TriangulateBMesh( );
private:
void AssertValidMesh( );
void AssertValidSizes( );
void PrepareTriMesh( );
void DestroyTriMesh( );
void ConvertPolyToFaces( const Blender::MPoly& poly );
void AddFace( int v1, int v2, int v3, int v4 = 0 );
void AddTFace( const float* uv1, const float* uv2, const float *uv3, const float* uv4 = 0 );
const Blender::Mesh* BMesh;
Blender::Mesh* triMesh;
friend class BlenderTessellatorGL;
friend class BlenderTessellatorP2T;
};
} // end of namespace Assimp
#endif // INCLUDED_AI_BLEND_BMESH_H

View file

@ -0,0 +1,373 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderDNA.cpp
* @brief Implementation of the Blender `DNA`, that is its own
* serialized set of data structures.
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderDNA.h"
#include "StreamReader.h"
#include "fast_atof.h"
using namespace Assimp;
using namespace Assimp::Blender;
using namespace Assimp::Formatter;
bool match4(StreamReaderAny& stream, const char* string) {
char tmp[] = {
(stream).GetI1(),
(stream).GetI1(),
(stream).GetI1(),
(stream).GetI1()
};
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
}
struct Type {
size_t size;
std::string name;
};
// ------------------------------------------------------------------------------------------------
void DNAParser :: Parse ()
{
StreamReaderAny& stream = *db.reader.get();
DNA& dna = db.dna;
if(!match4(stream,"SDNA")) {
throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
}
// name dictionary
if(!match4(stream,"NAME")) {
throw DeadlyImportError("BlenderDNA: Expected NAME field");
}
std::vector<std::string> names (stream.GetI4());
for(std::string& s : names) {
while (char c = stream.GetI1()) {
s += c;
}
}
// type dictionary
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
if(!match4(stream,"TYPE")) {
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
}
std::vector<Type> types (stream.GetI4());
for(Type& s : types) {
while (char c = stream.GetI1()) {
s.name += c;
}
}
// type length dictionary
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
if(!match4(stream,"TLEN")) {
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
}
for(Type& s : types) {
s.size = stream.GetI2();
}
// structures dictionary
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
if(!match4(stream,"STRC")) {
throw DeadlyImportError("BlenderDNA: Expected STRC field");
}
size_t end = stream.GetI4(), fields = 0;
dna.structures.reserve(end);
for(size_t i = 0; i != end; ++i) {
uint16_t n = stream.GetI2();
if (n >= types.size()) {
throw DeadlyImportError((format(),
"BlenderDNA: Invalid type index in structure name" ,n,
" (there are only ", types.size(), " entries)"
));
}
// maintain separate indexes
dna.indices[types[n].name] = dna.structures.size();
dna.structures.push_back(Structure());
Structure& s = dna.structures.back();
s.name = types[n].name;
//s.index = dna.structures.size()-1;
n = stream.GetI2();
s.fields.reserve(n);
size_t offset = 0;
for (size_t m = 0; m < n; ++m, ++fields) {
uint16_t j = stream.GetI2();
if (j >= types.size()) {
throw DeadlyImportError((format(),
"BlenderDNA: Invalid type index in structure field ", j,
" (there are only ", types.size(), " entries)"
));
}
s.fields.push_back(Field());
Field& f = s.fields.back();
f.offset = offset;
f.type = types[j].name;
f.size = types[j].size;
j = stream.GetI2();
if (j >= names.size()) {
throw DeadlyImportError((format(),
"BlenderDNA: Invalid name index in structure field ", j,
" (there are only ", names.size(), " entries)"
));
}
f.name = names[j];
f.flags = 0u;
// pointers always specify the size of the pointee instead of their own.
// The pointer asterisk remains a property of the lookup name.
if (f.name[0] == '*') {
f.size = db.i64bit ? 8 : 4;
f.flags |= FieldFlag_Pointer;
}
// arrays, however, specify the size of a single element so we
// need to parse the (possibly multi-dimensional) array declaration
// in order to obtain the actual size of the array in the file.
// Also we need to alter the lookup name to include no array
// brackets anymore or size fixup won't work (if our size does
// not match the size read from the DNA).
if (*f.name.rbegin() == ']') {
const std::string::size_type rb = f.name.find('[');
if (rb == std::string::npos) {
throw DeadlyImportError((format(),
"BlenderDNA: Encountered invalid array declaration ",
f.name
));
}
f.flags |= FieldFlag_Array;
DNA::ExtractArraySize(f.name,f.array_sizes);
f.name = f.name.substr(0,rb);
f.size *= f.array_sizes[0] * f.array_sizes[1];
}
// maintain separate indexes
s.indices[f.name] = s.fields.size()-1;
offset += f.size;
}
s.size = offset;
}
DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
" structures with totally ",fields," fields"));
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
dna.DumpToFile();
#endif
dna.AddPrimitiveStructures();
dna.RegisterConverters();
}
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
#include <fstream>
// ------------------------------------------------------------------------------------------------
void DNA :: DumpToFile()
{
// we dont't bother using the VFS here for this is only for debugging.
// (and all your bases are belong to us).
std::ofstream f("dna.txt");
if (f.fail()) {
DefaultLogger::get()->error("Could not dump dna to dna.txt");
return;
}
f << "Field format: type name offset size" << "\n";
f << "Structure format: name size" << "\n";
for(const Structure& s : structures) {
f << s.name << " " << s.size << "\n\n";
for(const Field& ff : s.fields) {
f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << "\n";
}
f << "\n";
}
f << std::flush;
DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
}
#endif
// ------------------------------------------------------------------------------------------------
/*static*/ void DNA :: ExtractArraySize(
const std::string& out,
size_t array_sizes[2]
)
{
array_sizes[0] = array_sizes[1] = 1;
std::string::size_type pos = out.find('[');
if (pos++ == std::string::npos) {
return;
}
array_sizes[0] = strtoul10(&out[pos]);
pos = out.find('[',pos);
if (pos++ == std::string::npos) {
return;
}
array_sizes[1] = strtoul10(&out[pos]);
}
// ------------------------------------------------------------------------------------------------
std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
const Structure& structure,
const FileDatabase& db
) const
{
std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
if (it == converters.end()) {
return std::shared_ptr< ElemBase >();
}
std::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
(structure.*((*it).second.second))(ret,db);
return ret;
}
// ------------------------------------------------------------------------------------------------
DNA::FactoryPair DNA :: GetBlobToStructureConverter(
const Structure& structure,
const FileDatabase& /*db*/
) const
{
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
return it == converters.end() ? FactoryPair() : (*it).second;
}
// basing on http://www.blender.org/development/architecture/notes-on-sdna/
// ------------------------------------------------------------------------------------------------
void DNA :: AddPrimitiveStructures()
{
// NOTE: these are just dummies. Their presence enforces
// Structure::Convert<target_type> to be called on these
// empty structures. These converters are special
// overloads which scan the name of the structure and
// perform the required data type conversion if one
// of these special names is found in the structure
// in question.
indices["int"] = structures.size();
structures.push_back( Structure() );
structures.back().name = "int";
structures.back().size = 4;
indices["short"] = structures.size();
structures.push_back( Structure() );
structures.back().name = "short";
structures.back().size = 2;
indices["char"] = structures.size();
structures.push_back( Structure() );
structures.back().name = "char";
structures.back().size = 1;
indices["float"] = structures.size();
structures.push_back( Structure() );
structures.back().name = "float";
structures.back().size = 4;
indices["double"] = structures.size();
structures.push_back( Structure() );
structures.back().name = "double";
structures.back().size = 8;
// no long, seemingly.
}
// ------------------------------------------------------------------------------------------------
void SectionParser :: Next()
{
stream.SetCurrentPos(current.start + current.size);
const char tmp[] = {
stream.GetI1(),
stream.GetI1(),
stream.GetI1(),
stream.GetI1()
};
current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
current.size = stream.GetI4();
current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
current.dna_index = stream.GetI4();
current.num = stream.GetI4();
current.start = stream.GetCurrentPos();
if (stream.GetRemainingSizeToLimit() < current.size) {
throw DeadlyImportError("BLEND: invalid size of file block");
}
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
DefaultLogger::get()->debug(current.id);
#endif
}
#endif

View file

@ -0,0 +1,809 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderDNA.h
* @brief Blender `DNA` (file format specification embedded in
* blend file itself) loader.
*/
#ifndef INCLUDED_AI_BLEND_DNA_H
#define INCLUDED_AI_BLEND_DNA_H
#include "BaseImporter.h"
#include "TinyFormatter.h"
#include "StreamReader.h"
#include <assimp/DefaultLogger.hpp>
#include <stdint.h>
#include <memory>
// enable verbose log output. really verbose, so be careful.
#ifdef ASSIMP_BUILD_DEBUG
# define ASSIMP_BUILD_BLENDER_DEBUG
#endif
// #define ASSIMP_BUILD_BLENDER_NO_STATS
namespace Assimp {
template <bool,bool> class StreamReader;
typedef StreamReader<true,true> StreamReaderAny;
namespace Blender {
class FileDatabase;
struct FileBlockHead;
template <template <typename> class TOUT>
class ObjectCache;
// -------------------------------------------------------------------------------
/** Exception class used by the blender loader to selectively catch exceptions
* thrown in its own code (DeadlyImportErrors thrown in general utility
* functions are untouched then). If such an exception is not caught by
* the loader itself, it will still be caught by Assimp due to its
* ancestry. */
// -------------------------------------------------------------------------------
struct Error : DeadlyImportError
{
Error (const std::string& s)
: DeadlyImportError(s)
{}
};
// -------------------------------------------------------------------------------
/** The only purpose of this structure is to feed a virtual dtor into its
* descendents. It serves as base class for all data structure fields. */
// -------------------------------------------------------------------------------
struct ElemBase
{
virtual ~ElemBase() {}
/** Type name of the element. The type
* string points is the `c_str` of the `name` attribute of the
* corresponding `Structure`, that is, it is only valid as long
* as the DNA is not modified. The dna_type is only set if the
* data type is not static, i.e. a std::shared_ptr<ElemBase>
* in the scene description would have its type resolved
* at runtime, so this member is always set. */
const char* dna_type;
};
// -------------------------------------------------------------------------------
/** Represents a generic pointer to a memory location, which can be either 32
* or 64 bits. These pointers are loaded from the BLEND file and finally
* fixed to point to the real, converted representation of the objects
* they used to point to.*/
// -------------------------------------------------------------------------------
struct Pointer
{
Pointer() : val() {}
uint64_t val;
};
// -------------------------------------------------------------------------------
/** Represents a generic offset within a BLEND file */
// -------------------------------------------------------------------------------
struct FileOffset
{
FileOffset() : val() {}
uint64_t val;
};
// -------------------------------------------------------------------------------
/** Dummy derivate of std::vector to be able to use it in templates simultaenously
* with std::shared_ptr, which takes only one template argument
* while std::vector takes three. Also we need to provide some special member
* functions of shared_ptr */
// -------------------------------------------------------------------------------
template <typename T>
class vector : public std::vector<T>
{
public:
using std::vector<T>::resize;
using std::vector<T>::empty;
void reset() {
resize(0);
}
operator bool () const {
return !empty();
}
};
// -------------------------------------------------------------------------------
/** Mixed flags for use in #Field */
// -------------------------------------------------------------------------------
enum FieldFlags
{
FieldFlag_Pointer = 0x1,
FieldFlag_Array = 0x2
};
// -------------------------------------------------------------------------------
/** Represents a single member of a data structure in a BLEND file */
// -------------------------------------------------------------------------------
struct Field
{
std::string name;
std::string type;
size_t size;
size_t offset;
/** Size of each array dimension. For flat arrays,
* the second dimension is set to 1. */
size_t array_sizes[2];
/** Any of the #FieldFlags enumerated values */
unsigned int flags;
};
// -------------------------------------------------------------------------------
/** Range of possible behaviours for fields absend in the input file. Some are
* mission critical so we need them, while others can silently be default
* initialized and no animations are harmed. */
// -------------------------------------------------------------------------------
enum ErrorPolicy
{
/** Substitute default value and ignore */
ErrorPolicy_Igno,
/** Substitute default value and write to log */
ErrorPolicy_Warn,
/** Substitute a massive error message and crash the whole matrix. Its time for another zion */
ErrorPolicy_Fail
};
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
# define ErrorPolicy_Igno ErrorPolicy_Warn
#endif
// -------------------------------------------------------------------------------
/** Represents a data structure in a BLEND file. A Structure defines n fields
* and their locatios and encodings the input stream. Usually, every
* Structure instance pertains to one equally-named data structure in the
* BlenderScene.h header. This class defines various utilities to map a
* binary `blob` read from the file to such a structure instance with
* meaningful contents. */
// -------------------------------------------------------------------------------
class Structure
{
template <template <typename> class> friend class ObjectCache;
public:
Structure()
: cache_idx(static_cast<size_t>(-1) )
{}
public:
// publicly accessible members
std::string name;
vector< Field > fields;
std::map<std::string, size_t> indices;
size_t size;
public:
// --------------------------------------------------------
/** Access a field of the structure by its canonical name. The pointer version
* returns NULL on failure while the reference version raises an import error. */
inline const Field& operator [] (const std::string& ss) const;
inline const Field* Get (const std::string& ss) const;
// --------------------------------------------------------
/** Access a field of the structure by its index */
inline const Field& operator [] (const size_t i) const;
// --------------------------------------------------------
inline bool operator== (const Structure& other) const {
return name == other.name; // name is meant to be an unique identifier
}
// --------------------------------------------------------
inline bool operator!= (const Structure& other) const {
return name != other.name;
}
public:
// --------------------------------------------------------
/** Try to read an instance of the structure from the stream
* and attempt to convert to `T`. This is done by
* an appropriate specialization. If none is available,
* a compiler complain is the result.
* @param dest Destination value to be written
* @param db File database, including input stream. */
template <typename T> inline void Convert (T& dest,
const FileDatabase& db) const;
// --------------------------------------------------------
// generic converter
template <typename T>
void Convert(std::shared_ptr<ElemBase> in,const FileDatabase& db) const;
// --------------------------------------------------------
// generic allocator
template <typename T> std::shared_ptr<ElemBase> Allocate() const;
// --------------------------------------------------------
// field parsing for 1d arrays
template <int error_policy, typename T, size_t M>
void ReadFieldArray(T (& out)[M], const char* name,
const FileDatabase& db) const;
// --------------------------------------------------------
// field parsing for 2d arrays
template <int error_policy, typename T, size_t M, size_t N>
void ReadFieldArray2(T (& out)[M][N], const char* name,
const FileDatabase& db) const;
// --------------------------------------------------------
// field parsing for pointer or dynamic array types
// (std::shared_ptr)
// The return value indicates whether the data was already cached.
template <int error_policy, template <typename> class TOUT, typename T>
bool ReadFieldPtr(TOUT<T>& out, const char* name,
const FileDatabase& db,
bool non_recursive = false) const;
// --------------------------------------------------------
// field parsing for static arrays of pointer or dynamic
// array types (std::shared_ptr[])
// The return value indicates whether the data was already cached.
template <int error_policy, template <typename> class TOUT, typename T, size_t N>
bool ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
const FileDatabase& db) const;
// --------------------------------------------------------
// field parsing for `normal` values
// The return value indicates whether the data was already cached.
template <int error_policy, typename T>
void ReadField(T& out, const char* name,
const FileDatabase& db) const;
private:
// --------------------------------------------------------
template <template <typename> class TOUT, typename T>
bool ResolvePointer(TOUT<T>& out, const Pointer & ptrval,
const FileDatabase& db, const Field& f,
bool non_recursive = false) const;
// --------------------------------------------------------
template <template <typename> class TOUT, typename T>
bool ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval,
const FileDatabase& db, const Field& f, bool) const;
// --------------------------------------------------------
bool ResolvePointer( std::shared_ptr< FileOffset >& out, const Pointer & ptrval,
const FileDatabase& db, const Field& f, bool) const;
// --------------------------------------------------------
inline const FileBlockHead* LocateFileBlockForAddress(
const Pointer & ptrval,
const FileDatabase& db) const;
private:
// ------------------------------------------------------------------------------
template <typename T> T* _allocate(std::shared_ptr<T>& out, size_t& s) const {
out = std::shared_ptr<T>(new T());
s = 1;
return out.get();
}
template <typename T> T* _allocate(vector<T>& out, size_t& s) const {
out.resize(s);
return s ? &out.front() : NULL;
}
// --------------------------------------------------------
template <int error_policy>
struct _defaultInitializer {
template <typename T, unsigned int N>
void operator ()(T (& out)[N], const char* = NULL) {
for (unsigned int i = 0; i < N; ++i) {
out[i] = T();
}
}
template <typename T, unsigned int N, unsigned int M>
void operator ()(T (& out)[N][M], const char* = NULL) {
for (unsigned int i = 0; i < N; ++i) {
for (unsigned int j = 0; j < M; ++j) {
out[i][j] = T();
}
}
}
template <typename T>
void operator ()(T& out, const char* = NULL) {
out = T();
}
};
private:
mutable size_t cache_idx;
};
// --------------------------------------------------------
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
template <typename T>
void operator ()(T& out, const char* reason = "<add reason>") {
DefaultLogger::get()->warn(reason);
// ... and let the show go on
_defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
}
};
template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
template <typename T>
void operator ()(T& /*out*/,const char* = "") {
// obviously, it is crucial that _DefaultInitializer is used
// only from within a catch clause.
throw;
}
};
// -------------------------------------------------------------------------------------------------------
template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shared_ptr<ElemBase>& out,
const Pointer & ptrval,
const FileDatabase& db,
const Field& f,
bool
) const;
// -------------------------------------------------------------------------------
/** Represents the full data structure information for a single BLEND file.
* This data is extracted from the DNA1 chunk in the file.
* #DNAParser does the reading and represents currently the only place where
* DNA is altered.*/
// -------------------------------------------------------------------------------
class DNA
{
public:
typedef void (Structure::*ConvertProcPtr) (
std::shared_ptr<ElemBase> in,
const FileDatabase&
) const;
typedef std::shared_ptr<ElemBase> (
Structure::*AllocProcPtr) () const;
typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair;
public:
std::map<std::string, FactoryPair > converters;
vector<Structure > structures;
std::map<std::string, size_t> indices;
public:
// --------------------------------------------------------
/** Access a structure by its canonical name, the pointer version returns NULL on failure
* while the reference version raises an error. */
inline const Structure& operator [] (const std::string& ss) const;
inline const Structure* Get (const std::string& ss) const;
// --------------------------------------------------------
/** Access a structure by its index */
inline const Structure& operator [] (const size_t i) const;
public:
// --------------------------------------------------------
/** Add structure definitions for all the primitive types,
* i.e. integer, short, char, float */
void AddPrimitiveStructures();
// --------------------------------------------------------
/** Fill the @c converters member with converters for all
* known data types. The implementation of this method is
* in BlenderScene.cpp and is machine-generated.
* Converters are used to quickly handle objects whose
* exact data type is a runtime-property and not yet
* known at compile time (consier Object::data).*/
void RegisterConverters();
// --------------------------------------------------------
/** Take an input blob from the stream, interpret it according to
* a its structure name and convert it to the intermediate
* representation.
* @param structure Destination structure definition
* @param db File database.
* @return A null pointer if no appropriate converter is available.*/
std::shared_ptr< ElemBase > ConvertBlobToStructure(
const Structure& structure,
const FileDatabase& db
) const;
// --------------------------------------------------------
/** Find a suitable conversion function for a given Structure.
* Such a converter function takes a blob from the input
* stream, reads as much as it needs, and builds up a
* complete object in intermediate representation.
* @param structure Destination structure definition
* @param db File database.
* @return A null pointer in .first if no appropriate converter is available.*/
FactoryPair GetBlobToStructureConverter(
const Structure& structure,
const FileDatabase& db
) const;
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
// --------------------------------------------------------
/** Dump the DNA to a text file. This is for debugging purposes.
* The output file is `dna.txt` in the current working folder*/
void DumpToFile();
#endif
// --------------------------------------------------------
/** Extract array dimensions from a C array declaration, such
* as `...[4][6]`. Returned string would be `...[][]`.
* @param out
* @param array_sizes Receive maximally two array dimensions,
* the second element is set to 1 if the array is flat.
* Both are set to 1 if the input is not an array.
* @throw DeadlyImportError if more than 2 dimensions are
* encountered. */
static void ExtractArraySize(
const std::string& out,
size_t array_sizes[2]
);
};
// special converters for primitive types
template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const;
template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const;
// -------------------------------------------------------------------------------
/** Describes a master file block header. Each master file sections holds n
* elements of a certain SDNA structure (or otherwise unspecified data). */
// -------------------------------------------------------------------------------
struct FileBlockHead
{
// points right after the header of the file block
StreamReaderAny::pos start;
std::string id;
size_t size;
// original memory address of the data
Pointer address;
// index into DNA
unsigned int dna_index;
// number of structure instances to follow
size_t num;
// file blocks are sorted by address to quickly locate specific memory addresses
bool operator < (const FileBlockHead& o) const {
return address.val < o.address.val;
}
// for std::upper_bound
operator const Pointer& () const {
return address;
}
};
// for std::upper_bound
inline bool operator< (const Pointer& a, const Pointer& b) {
return a.val < b.val;
}
// -------------------------------------------------------------------------------
/** Utility to read all master file blocks in turn. */
// -------------------------------------------------------------------------------
class SectionParser
{
public:
// --------------------------------------------------------
/** @param stream Inout stream, must point to the
* first section in the file. Call Next() once
* to have it read.
* @param ptr64 Pointer size in file is 64 bits? */
SectionParser(StreamReaderAny& stream,bool ptr64)
: stream(stream)
, ptr64(ptr64)
{
current.size = current.start = 0;
}
public:
// --------------------------------------------------------
const FileBlockHead& GetCurrent() const {
return current;
}
public:
// --------------------------------------------------------
/** Advance to the next section.
* @throw DeadlyImportError if the last chunk was passed. */
void Next();
public:
FileBlockHead current;
StreamReaderAny& stream;
bool ptr64;
};
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
// -------------------------------------------------------------------------------
/** Import statistics, i.e. number of file blocks read*/
// -------------------------------------------------------------------------------
class Statistics {
public:
Statistics ()
: fields_read ()
, pointers_resolved ()
, cache_hits ()
// , blocks_read ()
, cached_objects ()
{}
public:
/** total number of fields we read */
unsigned int fields_read;
/** total number of resolved pointers */
unsigned int pointers_resolved;
/** number of pointers resolved from the cache */
unsigned int cache_hits;
/** number of blocks (from FileDatabase::entries)
we did actually read from. */
// unsigned int blocks_read;
/** objects in FileData::cache */
unsigned int cached_objects;
};
#endif
// -------------------------------------------------------------------------------
/** The object cache - all objects addressed by pointers are added here. This
* avoids circular references and avoids object duplication. */
// -------------------------------------------------------------------------------
template <template <typename> class TOUT>
class ObjectCache
{
public:
typedef std::map< Pointer, TOUT<ElemBase> > StructureCache;
public:
ObjectCache(const FileDatabase& db)
: db(db)
{
// currently there are only ~400 structure records per blend file.
// we read only a small part of them and don't cache objects
// which we don't need, so this should suffice.
caches.reserve(64);
}
public:
// --------------------------------------------------------
/** Check whether a specific item is in the cache.
* @param s Data type of the item
* @param out Output pointer. Unchanged if the
* cache doens't know the item yet.
* @param ptr Item address to look for. */
template <typename T> void get (
const Structure& s,
TOUT<T>& out,
const Pointer& ptr) const;
// --------------------------------------------------------
/** Add an item to the cache after the item has
* been fully read. Do not insert anything that
* may be faulty or might cause the loading
* to abort.
* @param s Data type of the item
* @param out Item to insert into the cache
* @param ptr address (cache key) of the item. */
template <typename T> void set
(const Structure& s,
const TOUT<T>& out,
const Pointer& ptr);
private:
mutable vector<StructureCache> caches;
const FileDatabase& db;
};
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
template <> class ObjectCache<Blender::vector>
{
public:
ObjectCache(const FileDatabase&) {}
template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {}
template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {}
};
#ifdef _MSC_VER
# pragma warning(disable:4355)
#endif
// -------------------------------------------------------------------------------
/** Memory representation of a full BLEND file and all its dependencies. The
* output aiScene is constructed from an instance of this data structure. */
// -------------------------------------------------------------------------------
class FileDatabase
{
template <template <typename> class TOUT> friend class ObjectCache;
public:
FileDatabase()
: _cacheArrays(*this)
, _cache(*this)
, next_cache_idx()
{}
public:
// publicly accessible fields
bool i64bit;
bool little;
DNA dna;
std::shared_ptr< StreamReaderAny > reader;
vector< FileBlockHead > entries;
public:
Statistics& stats() const {
return _stats;
}
// For all our templates to work on both shared_ptr's and vector's
// using the same code, a dummy cache for arrays is provided. Actually,
// arrays of objects are never cached because we can't easily
// ensure their proper destruction.
template <typename T>
ObjectCache<std::shared_ptr>& cache(std::shared_ptr<T>& /*in*/) const {
return _cache;
}
template <typename T>
ObjectCache<vector>& cache(vector<T>& /*in*/) const {
return _cacheArrays;
}
private:
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
mutable Statistics _stats;
#endif
mutable ObjectCache<vector> _cacheArrays;
mutable ObjectCache<std::shared_ptr> _cache;
mutable size_t next_cache_idx;
};
#ifdef _MSC_VER
# pragma warning(default:4355)
#endif
// -------------------------------------------------------------------------------
/** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
// -------------------------------------------------------------------------------
class DNAParser
{
public:
/** Bind the parser to a empty DNA and an input stream */
DNAParser(FileDatabase& db)
: db(db)
{}
public:
// --------------------------------------------------------
/** Locate the DNA in the file and parse it. The input
* stream is expected to point to the beginning of the DN1
* chunk at the time this method is called and is
* undefined afterwards.
* @throw DeadlyImportError if the DNA cannot be read.
* @note The position of the stream pointer is undefined
* afterwards.*/
void Parse ();
public:
/** Obtain a reference to the extracted DNA information */
const Blender::DNA& GetDNA() const {
return db.dna;
}
private:
FileDatabase& db;
};
} // end Blend
} // end Assimp
#include "BlenderDNA.inl"
#endif

View file

@ -0,0 +1,734 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderDNA.inl
* @brief Blender `DNA` (file format specification embedded in
* blend file itself) loader.
*/
#ifndef INCLUDED_AI_BLEND_DNA_INL
#define INCLUDED_AI_BLEND_DNA_INL
#include <memory>
namespace Assimp {
namespace Blender {
//--------------------------------------------------------------------------------
const Field& Structure :: operator [] (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) {
throw Error((Formatter::format(),
"BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"
));
}
return fields[(*it).second];
}
//--------------------------------------------------------------------------------
const Field* Structure :: Get (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
return it == indices.end() ? NULL : &fields[(*it).second];
}
//--------------------------------------------------------------------------------
const Field& Structure :: operator [] (const size_t i) const
{
if (i >= fields.size()) {
throw Error((Formatter::format(),
"BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
));
}
return fields[i];
}
//--------------------------------------------------------------------------------
template <typename T> std::shared_ptr<ElemBase> Structure :: Allocate() const
{
return std::shared_ptr<T>(new T());
}
//--------------------------------------------------------------------------------
template <typename T> void Structure :: Convert(
std::shared_ptr<ElemBase> in,
const FileDatabase& db) const
{
Convert<T> (*static_cast<T*> ( in.get() ),db);
}
//--------------------------------------------------------------------------------
template <int error_policy, typename T, size_t M>
void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatabase& db) const
{
const StreamReaderAny::pos old = db.reader->GetCurrentPos();
try {
const Field& f = (*this)[name];
const Structure& s = db.dna[f.type];
// is the input actually an array?
if (!(f.flags & FieldFlag_Array)) {
throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be an array of size ",M
));
}
db.reader->IncPtr(f.offset);
// size conversions are always allowed, regardless of error_policy
unsigned int i = 0;
for(; i < std::min(f.array_sizes[0],M); ++i) {
s.Convert(out[i],db);
}
for(; i < M; ++i) {
_defaultInitializer<ErrorPolicy_Igno>()(out[i]);
}
}
catch (const Error& e) {
_defaultInitializer<error_policy>()(out,e.what());
}
// and recover the previous stream position
db.reader->SetCurrentPos(old);
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().fields_read;
#endif
}
//--------------------------------------------------------------------------------
template <int error_policy, typename T, size_t M, size_t N>
void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileDatabase& db) const
{
const StreamReaderAny::pos old = db.reader->GetCurrentPos();
try {
const Field& f = (*this)[name];
const Structure& s = db.dna[f.type];
// is the input actually an array?
if (!(f.flags & FieldFlag_Array)) {
throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be an array of size ",M,"*",N
));
}
db.reader->IncPtr(f.offset);
// size conversions are always allowed, regardless of error_policy
unsigned int i = 0;
for(; i < std::min(f.array_sizes[0],M); ++i) {
unsigned int j = 0;
for(; j < std::min(f.array_sizes[1],N); ++j) {
s.Convert(out[i][j],db);
}
for(; j < N; ++j) {
_defaultInitializer<ErrorPolicy_Igno>()(out[i][j]);
}
}
for(; i < M; ++i) {
_defaultInitializer<ErrorPolicy_Igno>()(out[i]);
}
}
catch (const Error& e) {
_defaultInitializer<error_policy>()(out,e.what());
}
// and recover the previous stream position
db.reader->SetCurrentPos(old);
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().fields_read;
#endif
}
//--------------------------------------------------------------------------------
template <int error_policy, template <typename> class TOUT, typename T>
bool Structure :: ReadFieldPtr(TOUT<T>& out, const char* name, const FileDatabase& db,
bool non_recursive /*= false*/) const
{
const StreamReaderAny::pos old = db.reader->GetCurrentPos();
Pointer ptrval;
const Field* f;
try {
f = &(*this)[name];
// sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be a pointer"));
}
db.reader->IncPtr(f->offset);
Convert(ptrval,db);
// actually it is meaningless on which Structure the Convert is called
// because the `Pointer` argument triggers a special implementation.
}
catch (const Error& e) {
_defaultInitializer<error_policy>()(out,e.what());
out.reset();
return false;
}
// resolve the pointer and load the corresponding structure
const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive);
if(!non_recursive) {
// and recover the previous stream position
db.reader->SetCurrentPos(old);
}
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().fields_read;
#endif
return res;
}
//--------------------------------------------------------------------------------
template <int error_policy, template <typename> class TOUT, typename T, size_t N>
bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
const FileDatabase& db) const
{
// XXX see if we can reduce this to call to the 'normal' ReadFieldPtr
const StreamReaderAny::pos old = db.reader->GetCurrentPos();
Pointer ptrval[N];
const Field* f;
try {
f = &(*this)[name];
// sanity check, should never happen if the genblenddna script is right
if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
throw Error((Formatter::format(),"Field `",name,"` of structure `",
this->name,"` ought to be a pointer AND an array"));
}
db.reader->IncPtr(f->offset);
size_t i = 0;
for(; i < std::min(f->array_sizes[0],N); ++i) {
Convert(ptrval[i],db);
}
for(; i < N; ++i) {
_defaultInitializer<ErrorPolicy_Igno>()(ptrval[i]);
}
// actually it is meaningless on which Structure the Convert is called
// because the `Pointer` argument triggers a special implementation.
}
catch (const Error& e) {
_defaultInitializer<error_policy>()(out,e.what());
for(size_t i = 0; i < N; ++i) {
out[i].reset();
}
return false;
}
bool res = true;
for(size_t i = 0; i < N; ++i) {
// resolve the pointer and load the corresponding structure
res = ResolvePointer(out[i],ptrval[i],db,*f) && res;
}
// and recover the previous stream position
db.reader->SetCurrentPos(old);
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().fields_read;
#endif
return res;
}
//--------------------------------------------------------------------------------
template <int error_policy, typename T>
void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) const
{
const StreamReaderAny::pos old = db.reader->GetCurrentPos();
try {
const Field& f = (*this)[name];
// find the structure definition pertaining to this field
const Structure& s = db.dna[f.type];
db.reader->IncPtr(f.offset);
s.Convert(out,db);
}
catch (const Error& e) {
_defaultInitializer<error_policy>()(out,e.what());
}
// and recover the previous stream position
db.reader->SetCurrentPos(old);
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().fields_read;
#endif
}
//--------------------------------------------------------------------------------
template <template <typename> class TOUT, typename T>
bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const FileDatabase& db,
const Field& f,
bool non_recursive /*= false*/) const
{
out.reset(); // ensure null pointers work
if (!ptrval.val) {
return false;
}
const Structure& s = db.dna[f.type];
// find the file block the pointer is pointing to
const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
// also determine the target type from the block header
// and check if it matches the type which we expect.
const Structure& ss = db.dna[block->dna_index];
if (ss != s) {
throw Error((Formatter::format(),"Expected target to be of type `",s.name,
"` but seemingly it is a `",ss.name,"` instead"
));
}
// try to retrieve the object from the cache
db.cache(out).get(s,out,ptrval);
if (out) {
return true;
}
// seek to this location, but save the previous stream pointer.
const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
// FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
// I really ought to improve StreamReader to work with 64 bit indices exclusively.
// continue conversion after allocating the required storage
size_t num = block->size / ss.size;
T* o = _allocate(out,num);
// cache the object before we convert it to avoid cyclic recursion.
db.cache(out).set(s,out,ptrval);
// if the non_recursive flag is set, we don't do anything but leave
// the cursor at the correct position to resolve the object.
if (!non_recursive) {
for (size_t i = 0; i < num; ++i,++o) {
s.Convert(*o,db);
}
db.reader->SetCurrentPos(pold);
}
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
if(out) {
++db.stats().pointers_resolved;
}
#endif
return false;
}
//--------------------------------------------------------------------------------
inline bool Structure :: ResolvePointer( std::shared_ptr< FileOffset >& out, const Pointer & ptrval,
const FileDatabase& db,
const Field&,
bool) const
{
// Currently used exclusively by PackedFile::data to represent
// a simple offset into the mapped BLEND file.
out.reset();
if (!ptrval.val) {
return false;
}
// find the file block the pointer is pointing to
const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
out = std::shared_ptr< FileOffset > (new FileOffset());
out->val = block->start+ static_cast<size_t>((ptrval.val - block->address.val) );
return false;
}
//--------------------------------------------------------------------------------
template <template <typename> class TOUT, typename T>
bool Structure :: ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval,
const FileDatabase& db,
const Field& f,
bool) const
{
// This is a function overload, not a template specialization. According to
// the partial ordering rules, it should be selected by the compiler
// for array-of-pointer inputs, i.e. Object::mats.
out.reset();
if (!ptrval.val) {
return false;
}
// find the file block the pointer is pointing to
const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
const size_t num = block->size / (db.i64bit?8:4);
// keep the old stream position
const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
bool res = false;
// allocate raw storage for the array
out.resize(num);
for (size_t i = 0; i< num; ++i) {
Pointer val;
Convert(val,db);
// and resolve the pointees
res = ResolvePointer(out[i],val,db,f) && res;
}
db.reader->SetCurrentPos(pold);
return res;
}
//--------------------------------------------------------------------------------
template <> bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shared_ptr<ElemBase>& out,
const Pointer & ptrval,
const FileDatabase& db,
const Field&,
bool
) const
{
// Special case when the data type needs to be determined at runtime.
// Less secure than in the `strongly-typed` case.
out.reset();
if (!ptrval.val) {
return false;
}
// find the file block the pointer is pointing to
const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db);
// determine the target type from the block header
const Structure& s = db.dna[block->dna_index];
// try to retrieve the object from the cache
db.cache(out).get(s,out,ptrval);
if (out) {
return true;
}
// seek to this location, but save the previous stream pointer.
const StreamReaderAny::pos pold = db.reader->GetCurrentPos();
db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) ));
// FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
// I really ought to improve StreamReader to work with 64 bit indices exclusively.
// continue conversion after allocating the required storage
DNA::FactoryPair builders = db.dna.GetBlobToStructureConverter(s,db);
if (!builders.first) {
// this might happen if DNA::RegisterConverters hasn't been called so far
// or if the target type is not contained in `our` DNA.
out.reset();
DefaultLogger::get()->warn((Formatter::format(),
"Failed to find a converter for the `",s.name,"` structure"
));
return false;
}
// allocate the object hull
out = (s.*builders.first)();
// cache the object immediately to prevent infinite recursion in a
// circular list with a single element (i.e. a self-referencing element).
db.cache(out).set(s,out,ptrval);
// and do the actual conversion
(s.*builders.second)(out,db);
db.reader->SetCurrentPos(pold);
// store a pointer to the name string of the actual type
// in the object itself. This allows the conversion code
// to perform additional type checking.
out->dna_type = s.name.c_str();
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().pointers_resolved;
#endif
return false;
}
//--------------------------------------------------------------------------------
const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrval, const FileDatabase& db) const
{
// the file blocks appear in list sorted by
// with ascending base addresses so we can run a
// binary search to locate the pointee quickly.
// NOTE: Blender seems to distinguish between side-by-side
// data (stored in the same data block) and far pointers,
// which are only used for structures starting with an ID.
// We don't need to make this distinction, our algorithm
// works regardless where the data is stored.
vector<FileBlockHead>::const_iterator it = std::lower_bound(db.entries.begin(),db.entries.end(),ptrval);
if (it == db.entries.end()) {
// this is crucial, pointers may not be invalid.
// this is either a corrupted file or an attempted attack.
throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
std::hex,ptrval.val,", no file block falls into this address range"
));
}
if (ptrval.val >= (*it).address.val + (*it).size) {
throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
std::hex,ptrval.val,", nearest file block starting at 0x",
(*it).address.val," ends at 0x",
(*it).address.val + (*it).size
));
}
return &*it;
}
// ------------------------------------------------------------------------------------------------
// NOTE: The MSVC debugger keeps showing up this annoying `a cast to a smaller data type has
// caused a loss of data`-warning. Avoid this warning by a masking with an appropriate bitmask.
template <typename T> struct signless;
template <> struct signless<char> {typedef unsigned char type;};
template <> struct signless<short> {typedef unsigned short type;};
template <> struct signless<int> {typedef unsigned int type;};
template <typename T>
struct static_cast_silent {
template <typename V>
T operator()(V in) {
return static_cast<T>(in & static_cast<typename signless<T>::type>(-1));
}
};
template <> struct static_cast_silent<float> {
template <typename V> float operator()(V in) {
return static_cast<float> (in);
}
};
template <> struct static_cast_silent<double> {
template <typename V> double operator()(V in) {
return static_cast<double>(in);
}
};
// ------------------------------------------------------------------------------------------------
template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,const FileDatabase& db)
{
if (in.name == "int") {
out = static_cast_silent<T>()(db.reader->GetU4());
}
else if (in.name == "short") {
out = static_cast_silent<T>()(db.reader->GetU2());
}
else if (in.name == "char") {
out = static_cast_silent<T>()(db.reader->GetU1());
}
else if (in.name == "float") {
out = static_cast<T>(db.reader->GetF4());
}
else if (in.name == "double") {
out = static_cast<T>(db.reader->GetF8());
}
else {
throw DeadlyImportError("Unknown source for conversion to primitive data type: "+in.name);
}
}
// ------------------------------------------------------------------------------------------------
template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const
{
ConvertDispatcher(dest,*this,db);
}
// ------------------------------------------------------------------------------------------------
template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const
{
// automatic rescaling from short to float and vice versa (seems to be used by normals)
if (name == "float") {
dest = static_cast<short>(db.reader->GetF4() * 32767.f);
//db.reader->IncPtr(-4);
return;
}
else if (name == "double") {
dest = static_cast<short>(db.reader->GetF8() * 32767.);
//db.reader->IncPtr(-8);
return;
}
ConvertDispatcher(dest,*this,db);
}
// ------------------------------------------------------------------------------------------------
template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const
{
// automatic rescaling from char to float and vice versa (seems useful for RGB colors)
if (name == "float") {
dest = static_cast<char>(db.reader->GetF4() * 255.f);
return;
}
else if (name == "double") {
dest = static_cast<char>(db.reader->GetF8() * 255.f);
return;
}
ConvertDispatcher(dest,*this,db);
}
// ------------------------------------------------------------------------------------------------
template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const
{
// automatic rescaling from char to float and vice versa (seems useful for RGB colors)
if (name == "char") {
dest = db.reader->GetI1() / 255.f;
return;
}
// automatic rescaling from short to float and vice versa (used by normals)
else if (name == "short") {
dest = db.reader->GetI2() / 32767.f;
return;
}
ConvertDispatcher(dest,*this,db);
}
// ------------------------------------------------------------------------------------------------
template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const
{
if (name == "char") {
dest = db.reader->GetI1() / 255.;
return;
}
else if (name == "short") {
dest = db.reader->GetI2() / 32767.;
return;
}
ConvertDispatcher(dest,*this,db);
}
// ------------------------------------------------------------------------------------------------
template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const
{
if (db.i64bit) {
dest.val = db.reader->GetU8();
//db.reader->IncPtr(-8);
return;
}
dest.val = db.reader->GetU4();
//db.reader->IncPtr(-4);
}
//--------------------------------------------------------------------------------
const Structure& DNA :: operator [] (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
if (it == indices.end()) {
throw Error((Formatter::format(),
"BlendDNA: Did not find a structure named `",ss,"`"
));
}
return structures[(*it).second];
}
//--------------------------------------------------------------------------------
const Structure* DNA :: Get (const std::string& ss) const
{
std::map<std::string, size_t>::const_iterator it = indices.find(ss);
return it == indices.end() ? NULL : &structures[(*it).second];
}
//--------------------------------------------------------------------------------
const Structure& DNA :: operator [] (const size_t i) const
{
if (i >= structures.size()) {
throw Error((Formatter::format(),
"BlendDNA: There is no structure with index `",i,"`"
));
}
return structures[i];
}
//--------------------------------------------------------------------------------
template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: get (
const Structure& s,
TOUT<T>& out,
const Pointer& ptr
) const {
if(s.cache_idx == static_cast<size_t>(-1)) {
s.cache_idx = db.next_cache_idx++;
caches.resize(db.next_cache_idx);
return;
}
typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr);
if (it != caches[s.cache_idx].end()) {
out = std::static_pointer_cast<T>( (*it).second );
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().cache_hits;
#endif
}
// otherwise, out remains untouched
}
//--------------------------------------------------------------------------------
template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: set (
const Structure& s,
const TOUT<T>& out,
const Pointer& ptr
) {
if(s.cache_idx == static_cast<size_t>(-1)) {
s.cache_idx = db.next_cache_idx++;
caches.resize(db.next_cache_idx);
}
caches[s.cache_idx][ptr] = std::static_pointer_cast<ElemBase>( out );
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().cached_objects;
#endif
}
}}
#endif

View file

@ -0,0 +1,201 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderIntermediate.h
* @brief Internal utility structures for the BlenderLoader. It also serves
* as master include file for the whole (internal) Blender subsystem.
*/
#ifndef INCLUDED_AI_BLEND_INTERMEDIATE_H
#define INCLUDED_AI_BLEND_INTERMEDIATE_H
#include "BlenderLoader.h"
#include "BlenderDNA.h"
#include "BlenderScene.h"
#include "BlenderSceneGen.h"
#include <deque>
#include "./../include/assimp/material.h"
struct aiTexture;
namespace Assimp {
namespace Blender {
// --------------------------------------------------------------------
/** Mini smart-array to avoid pulling in even more boost stuff. usable with vector and deque */
// --------------------------------------------------------------------
template <template <typename,typename> class TCLASS, typename T>
struct TempArray {
typedef TCLASS< T*,std::allocator<T*> > mywrap;
TempArray() {
}
~TempArray () {
for(T* elem : arr) {
delete elem;
}
}
void dismiss() {
arr.clear();
}
mywrap* operator -> () {
return &arr;
}
operator mywrap& () {
return arr;
}
operator const mywrap& () const {
return arr;
}
mywrap& get () {
return arr;
}
const mywrap& get () const {
return arr;
}
T* operator[] (size_t idx) const {
return arr[idx];
}
T*& operator[] (size_t idx) {
return arr[idx];
}
private:
// no copy semantics
void operator= (const TempArray&) {
}
TempArray(const TempArray& arr) {
}
private:
mywrap arr;
};
#ifdef _MSC_VER
# pragma warning(disable:4351)
#endif
struct ObjectCompare {
bool operator() (const Object* left, const Object* right) const {
return strcmp(left->id.name, right->id.name) == -1;
}
};
// When keeping objects in sets, sort them by their name.
typedef std::set<const Object*, ObjectCompare> ObjectSet;
// --------------------------------------------------------------------
/** ConversionData acts as intermediate storage location for
* the various ConvertXXX routines in BlenderImporter.*/
// --------------------------------------------------------------------
struct ConversionData
{
ConversionData(const FileDatabase& db)
: sentinel_cnt()
, next_texture()
, db(db)
{}
struct ObjectCompare {
bool operator() (const Object* left, const Object* right) const {
return strcmp(left->id.name, right->id.name) == -1;
}
};
ObjectSet objects;
TempArray <std::vector, aiMesh> meshes;
TempArray <std::vector, aiCamera> cameras;
TempArray <std::vector, aiLight> lights;
TempArray <std::vector, aiMaterial> materials;
TempArray <std::vector, aiTexture> textures;
// set of all materials referenced by at least one mesh in the scene
std::deque< std::shared_ptr< Material > > materials_raw;
// counter to name sentinel textures inserted as substitutes for procedural textures.
unsigned int sentinel_cnt;
// next texture ID for each texture type, respectively
unsigned int next_texture[aiTextureType_UNKNOWN+1];
// original file data
const FileDatabase& db;
};
#ifdef _MSC_VER
# pragma warning(default:4351)
#endif
// ------------------------------------------------------------------------------------------------
inline const char* GetTextureTypeDisplayString(Tex::Type t)
{
switch (t) {
case Tex::Type_CLOUDS : return "Clouds";
case Tex::Type_WOOD : return "Wood";
case Tex::Type_MARBLE : return "Marble";
case Tex::Type_MAGIC : return "Magic";
case Tex::Type_BLEND : return "Blend";
case Tex::Type_STUCCI : return "Stucci";
case Tex::Type_NOISE : return "Noise";
case Tex::Type_PLUGIN : return "Plugin";
case Tex::Type_MUSGRAVE : return "Musgrave";
case Tex::Type_VORONOI : return "Voronoi";
case Tex::Type_DISTNOISE : return "DistortedNoise";
case Tex::Type_ENVMAP : return "EnvMap";
case Tex::Type_IMAGE : return "Image";
default:
break;
}
return "<Unknown>";
}
} // ! Blender
} // ! Assimp
#endif // ! INCLUDED_AI_BLEND_INTERMEDIATE_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,239 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderLoader.h
* @brief Declaration of the Blender 3D (*.blend) importer class.
*/
#ifndef INCLUDED_AI_BLEND_LOADER_H
#define INCLUDED_AI_BLEND_LOADER_H
#include "BaseImporter.h"
#include "LogAux.h"
#include <memory>
struct aiNode;
struct aiMesh;
struct aiLight;
struct aiCamera;
struct aiMaterial;
namespace Assimp {
// TinyFormatter.h
namespace Formatter {
template <typename T,typename TR, typename A> class basic_formatter;
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
}
// BlenderDNA.h
namespace Blender {
class FileDatabase;
struct ElemBase;
}
// BlenderScene.h
namespace Blender {
struct Scene;
struct Object;
struct Mesh;
struct Camera;
struct Lamp;
struct MTex;
struct Image;
struct Material;
}
// BlenderIntermediate.h
namespace Blender {
struct ConversionData;
template <template <typename,typename> class TCLASS, typename T> struct TempArray;
}
// BlenderModifier.h
namespace Blender {
class BlenderModifierShowcase;
class BlenderModifier;
}
// -------------------------------------------------------------------------------------------
/** Load blenders official binary format. The actual file structure (the `DNA` how they
* call it is outsourced to BlenderDNA.cpp/BlenderDNA.h. This class only performs the
* conversion from intermediate format to aiScene. */
// -------------------------------------------------------------------------------------------
class BlenderImporter : public BaseImporter, public LogFunctions<BlenderImporter>
{
public:
BlenderImporter();
~BlenderImporter();
public:
// --------------------
bool CanRead( const std::string& pFile,
IOSystem* pIOHandler,
bool checkSig
) const;
protected:
// --------------------
const aiImporterDesc* GetInfo () const;
// --------------------
void GetExtensionList(std::set<std::string>& app);
// --------------------
void SetupProperties(const Importer* pImp);
// --------------------
void InternReadFile( const std::string& pFile,
aiScene* pScene,
IOSystem* pIOHandler
);
// --------------------
void ParseBlendFile(Blender::FileDatabase& out,
std::shared_ptr<IOStream> stream
);
// --------------------
void ExtractScene(Blender::Scene& out,
const Blender::FileDatabase& file
);
// --------------------
void ConvertBlendFile(aiScene* out,
const Blender::Scene& in,
const Blender::FileDatabase& file
);
private:
// --------------------
aiNode* ConvertNode(const Blender::Scene& in,
const Blender::Object* obj,
Blender::ConversionData& conv_info,
const aiMatrix4x4& parentTransform
);
// --------------------
void ConvertMesh(const Blender::Scene& in,
const Blender::Object* obj,
const Blender::Mesh* mesh,
Blender::ConversionData& conv_data,
Blender::TempArray<std::vector,aiMesh>& temp
);
// --------------------
aiLight* ConvertLight(const Blender::Scene& in,
const Blender::Object* obj,
const Blender::Lamp* mesh,
Blender::ConversionData& conv_data
);
// --------------------
aiCamera* ConvertCamera(const Blender::Scene& in,
const Blender::Object* obj,
const Blender::Camera* mesh,
Blender::ConversionData& conv_data
);
// --------------------
void BuildDefaultMaterial(
Blender::ConversionData& conv_data
);
void AddBlendParams(
aiMaterial* result,
const Blender::Material* source
);
void BuildMaterials(
Blender::ConversionData& conv_data
);
// --------------------
void ResolveTexture(
aiMaterial* out,
const Blender::Material* mat,
const Blender::MTex* tex,
Blender::ConversionData& conv_data
);
// --------------------
void ResolveImage(
aiMaterial* out,
const Blender::Material* mat,
const Blender::MTex* tex,
const Blender::Image* img,
Blender::ConversionData& conv_data
);
void AddSentinelTexture(
aiMaterial* out,
const Blender::Material* mat,
const Blender::MTex* tex,
Blender::ConversionData& conv_data
);
private: // static stuff, mostly logging and error reporting.
// --------------------
static void CheckActualType(const Blender::ElemBase* dt,
const char* check
);
// --------------------
static void NotSupportedObjectType(const Blender::Object* obj,
const char* type
);
private:
Blender::BlenderModifierShowcase* modifier_cache;
}; // !class BlenderImporter
} // end of namespace Assimp
#endif // AI_UNREALIMPORTER_H_INC

View file

@ -0,0 +1,326 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderModifier.cpp
* @brief Implementation of some blender modifiers (i.e subdivision, mirror).
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderModifier.h"
#include "SceneCombiner.h"
#include "Subdivision.h"
#include <assimp/scene.h>
#include <memory>
#include <functional>
using namespace Assimp;
using namespace Assimp::Blender;
template <typename T> BlenderModifier* god() {
return new T();
}
// add all available modifiers here
typedef BlenderModifier* (*fpCreateModifier)();
static const fpCreateModifier creators[] = {
&god<BlenderModifier_Mirror>,
&god<BlenderModifier_Subdivision>,
NULL // sentinel
};
// ------------------------------------------------------------------------------------------------
// just testing out some new macros to simplify logging
#define ASSIMP_LOG_WARN_F(string,...)\
DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
#define ASSIMP_LOG_ERROR_F(string,...)\
DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
#define ASSIMP_LOG_DEBUG_F(string,...)\
DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
#define ASSIMP_LOG_INFO_F(string,...)\
DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
#define ASSIMP_LOG_WARN(string)\
DefaultLogger::get()->warn(string)
#define ASSIMP_LOG_ERROR(string)\
DefaultLogger::get()->error(string)
#define ASSIMP_LOG_DEBUG(string)\
DefaultLogger::get()->debug(string)
#define ASSIMP_LOG_INFO(string)\
DefaultLogger::get()->info(string)
// ------------------------------------------------------------------------------------------------
struct SharedModifierData : ElemBase
{
ModifierData modifier;
};
// ------------------------------------------------------------------------------------------------
void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object )
{
size_t cnt = 0u, ful = 0u;
// NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
// we're allowed to dereference the pointers without risking to crash. We might still be
// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
// structures is at offset sizeof(vftable) with no padding.
const SharedModifierData* cur = static_cast<const SharedModifierData *> ( orig_object.modifiers.first.get() );
for (; cur; cur = static_cast<const SharedModifierData *> ( cur->modifier.next.get() ), ++ful) {
ai_assert(cur->dna_type);
const Structure* s = conv_data.db.dna.Get( cur->dna_type );
if (!s) {
ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
continue;
}
// this is a common trait of all XXXMirrorData structures in BlenderDNA
const Field* f = s->Get("modifier");
if (!f || f->offset != 0) {
ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
continue;
}
s = conv_data.db.dna.Get( f->type );
if (!s || s->name != "ModifierData") {
ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
continue;
}
// now, we can be sure that we should be fine to dereference *cur* as
// ModifierData (with the above note).
const ModifierData& dat = cur->modifier;
const fpCreateModifier* curgod = creators;
std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
if (curmod == endmod) {
cached_modifiers->push_back((*curgod)());
endmod = cached_modifiers->end();
curmod = endmod-1;
}
BlenderModifier* const modifier = *curmod;
if(modifier->IsActive(dat)) {
modifier->DoIt(out,conv_data,*static_cast<const ElemBase *>(cur),in,orig_object);
cnt++;
curgod = NULL;
break;
}
}
if (curgod) {
ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
}
}
// Even though we managed to resolve some or all of the modifiers on this
// object, we still can't say whether our modifier implementations were
// able to fully do their job.
if (ful) {
ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
"`, check log messages above for errors");
}
}
// ------------------------------------------------------------------------------------------------
bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
{
return modin.type == ModifierData::eModifierType_Mirror;
}
// ------------------------------------------------------------------------------------------------
void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
const Scene& /*in*/,
const Object& orig_object )
{
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
// XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
// take all input meshes and clone them
for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
aiMesh* mesh;
SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
if (mir.mirror_ob) {
const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mVertices[i];
v.x = center.x + xs*(center.x - v.x);
v.y = center.y + ys*(center.y - v.y);
v.z = center.z + zs*(center.z - v.z);
}
}
else {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mVertices[i];
v.x *= xs;v.y *= ys;v.z *= zs;
}
}
if (mesh->mNormals) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mNormals[i];
v.x *= xs;v.y *= ys;v.z *= zs;
}
}
if (mesh->mTangents) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mTangents[i];
v.x *= xs;v.y *= ys;v.z *= zs;
}
}
if (mesh->mBitangents) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mBitangents[i];
v.x *= xs;v.y *= ys;v.z *= zs;
}
}
const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f;
const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D& v = mesh->mTextureCoords[n][i];
v.x *= us;v.y *= vs;
}
}
// Only reverse the winding order if an odd number of axes were mirrored.
if (xs * ys * zs < 0) {
for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
aiFace& face = mesh->mFaces[i];
for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
}
}
conv_data.meshes->push_back(mesh);
}
unsigned int* nind = new unsigned int[out.mNumMeshes*2];
std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
std::bind1st(std::plus< unsigned int >(),out.mNumMeshes));
delete[] out.mMeshes;
out.mMeshes = nind;
out.mNumMeshes *= 2;
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
orig_object.id.name,"`");
}
// ------------------------------------------------------------------------------------------------
bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
{
return modin.type == ModifierData::eModifierType_Subsurf;
}
// ------------------------------------------------------------------------------------------------
void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
const Scene& /*in*/,
const Object& orig_object )
{
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
Subdivider::Algorithm algo;
switch (mir.subdivType)
{
case SubsurfModifierData::TYPE_CatmullClarke:
algo = Subdivider::CATMULL_CLARKE;
break;
case SubsurfModifierData::TYPE_Simple:
ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
algo = Subdivider::CATMULL_CLARKE;
break;
default:
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
return;
};
std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
ai_assert(subd);
aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
std::unique_ptr<aiMesh*[]> tempmeshes(new aiMesh*[out.mNumMeshes]());
subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
orig_object.id.name,"`");
}
#endif

View file

@ -0,0 +1,156 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderModifier.h
* @brief Declare dedicated helper classes to simulate some blender modifiers (i.e. mirror)
*/
#ifndef INCLUDED_AI_BLEND_MODIFIER_H
#define INCLUDED_AI_BLEND_MODIFIER_H
#include "BlenderIntermediate.h"
#include "TinyFormatter.h"
namespace Assimp {
namespace Blender {
// -------------------------------------------------------------------------------------------
/** Dummy base class for all blender modifiers. Modifiers are reused between imports, so
* they should be stateless and not try to cache model data. */
// -------------------------------------------------------------------------------------------
class BlenderModifier
{
public:
virtual ~BlenderModifier() {
// empty
}
public:
// --------------------
/** Check if *this* modifier is active, given a ModifierData& block.*/
virtual bool IsActive( const ModifierData& /*modin*/) {
return false;
}
// --------------------
/** Apply the modifier to a given output node. The original data used
* to construct the node is given as well. Not called unless IsActive()
* was called and gave positive response. */
virtual void DoIt(aiNode& /*out*/,
ConversionData& /*conv_data*/,
const ElemBase& orig_modifier,
const Scene& /*in*/,
const Object& /*orig_object*/
) {
DefaultLogger::get()->warn((Formatter::format("This modifier is not supported, skipping: "),orig_modifier.dna_type));
return;
}
};
// -------------------------------------------------------------------------------------------
/** Manage all known modifiers and instance and apply them if necessary */
// -------------------------------------------------------------------------------------------
class BlenderModifierShowcase
{
public:
// --------------------
/** Apply all requested modifiers provided we support them. */
void ApplyModifiers(aiNode& out,
ConversionData& conv_data,
const Scene& in,
const Object& orig_object
);
private:
TempArray< std::vector,BlenderModifier > cached_modifiers;
};
// MODIFIERS
// -------------------------------------------------------------------------------------------
/** Mirror modifier. Status: implemented. */
// -------------------------------------------------------------------------------------------
class BlenderModifier_Mirror : public BlenderModifier
{
public:
// --------------------
virtual bool IsActive( const ModifierData& modin);
// --------------------
virtual void DoIt(aiNode& out,
ConversionData& conv_data,
const ElemBase& orig_modifier,
const Scene& in,
const Object& orig_object
) ;
};
// -------------------------------------------------------------------------------------------
/** Subdivision modifier. Status: dummy. */
// -------------------------------------------------------------------------------------------
class BlenderModifier_Subdivision : public BlenderModifier
{
public:
// --------------------
virtual bool IsActive( const ModifierData& modin);
// --------------------
virtual void DoIt(aiNode& out,
ConversionData& conv_data,
const ElemBase& orig_modifier,
const Scene& in,
const Object& orig_object
) ;
};
}}
#endif // !INCLUDED_AI_BLEND_MODIFIER_H

View file

@ -0,0 +1,809 @@
/*
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.
----------------------------------------------------------------------
*/
/** @file BlenderScene.cpp
* @brief MACHINE GENERATED BY ./scripts/BlenderImporter/genblenddna.py
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderDNA.h"
#include "BlenderScene.h"
#include "BlenderSceneGen.h"
using namespace Assimp;
using namespace Assimp::Blender;
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Object> (
Object& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
ReadFieldArray2<ErrorPolicy_Warn>(dest.obmat,"obmat",db);
ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv,"parentinv",db);
ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr,"parsubstr",db);
{
std::shared_ptr<Object> parent;
ReadFieldPtr<ErrorPolicy_Warn>(parent,"*parent",db);
dest.parent = parent.get();
}
ReadFieldPtr<ErrorPolicy_Warn>(dest.track,"*track",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy,"*proxy",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_from,"*proxy_from",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_group,"*proxy_group",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.dup_group,"*dup_group",db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.data,"*data",db);
ReadField<ErrorPolicy_Igno>(dest.modifiers,"modifiers",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Group> (
Group& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
ReadField<ErrorPolicy_Igno>(dest.layer,"layer",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.gobject,"*gobject",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MTex> (
MTex& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Igno>((short&)dest.mapto,"mapto",db);
ReadField<ErrorPolicy_Igno>((int&)dest.blendtype,"blendtype",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.object,"*object",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.tex,"*tex",db);
ReadFieldArray<ErrorPolicy_Igno>(dest.uvname,"uvname",db);
ReadField<ErrorPolicy_Igno>((int&)dest.projx,"projx",db);
ReadField<ErrorPolicy_Igno>((int&)dest.projy,"projy",db);
ReadField<ErrorPolicy_Igno>((int&)dest.projz,"projz",db);
ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);
ReadField<ErrorPolicy_Igno>(dest.rot,"rot",db);
ReadField<ErrorPolicy_Igno>(dest.texflag,"texflag",db);
ReadField<ErrorPolicy_Igno>(dest.colormodel,"colormodel",db);
ReadField<ErrorPolicy_Igno>(dest.pmapto,"pmapto",db);
ReadField<ErrorPolicy_Igno>(dest.pmaptoneg,"pmaptoneg",db);
ReadField<ErrorPolicy_Warn>(dest.r,"r",db);
ReadField<ErrorPolicy_Warn>(dest.g,"g",db);
ReadField<ErrorPolicy_Warn>(dest.b,"b",db);
ReadField<ErrorPolicy_Warn>(dest.k,"k",db);
ReadField<ErrorPolicy_Igno>(dest.colspecfac,"colspecfac",db);
ReadField<ErrorPolicy_Igno>(dest.mirrfac,"mirrfac",db);
ReadField<ErrorPolicy_Igno>(dest.alphafac,"alphafac",db);
ReadField<ErrorPolicy_Igno>(dest.difffac,"difffac",db);
ReadField<ErrorPolicy_Igno>(dest.specfac,"specfac",db);
ReadField<ErrorPolicy_Igno>(dest.emitfac,"emitfac",db);
ReadField<ErrorPolicy_Igno>(dest.hardfac,"hardfac",db);
ReadField<ErrorPolicy_Igno>(dest.norfac,"norfac",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<TFace> (
TFace& dest,
const FileDatabase& db
) const
{
ReadFieldArray2<ErrorPolicy_Fail>(dest.uv,"uv",db);
ReadFieldArray<ErrorPolicy_Fail>(dest.col,"col",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db);
ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db);
ReadField<ErrorPolicy_Igno>(dest.unwrap,"unwrap",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<SubsurfModifierData> (
SubsurfModifierData& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.modifier,"modifier",db);
ReadField<ErrorPolicy_Warn>(dest.subdivType,"subdivType",db);
ReadField<ErrorPolicy_Fail>(dest.levels,"levels",db);
ReadField<ErrorPolicy_Igno>(dest.renderLevels,"renderLevels",db);
ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MFace> (
MFace& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.v1,"v1",db);
ReadField<ErrorPolicy_Fail>(dest.v2,"v2",db);
ReadField<ErrorPolicy_Fail>(dest.v3,"v3",db);
ReadField<ErrorPolicy_Fail>(dest.v4,"v4",db);
ReadField<ErrorPolicy_Fail>(dest.mat_nr,"mat_nr",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Lamp> (
Lamp& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db);
ReadField<ErrorPolicy_Igno>(dest.colormodel,"colormodel",db);
ReadField<ErrorPolicy_Igno>(dest.totex,"totex",db);
ReadField<ErrorPolicy_Warn>(dest.r,"r",db);
ReadField<ErrorPolicy_Warn>(dest.g,"g",db);
ReadField<ErrorPolicy_Warn>(dest.b,"b",db);
ReadField<ErrorPolicy_Warn>(dest.k,"k",db);
ReadField<ErrorPolicy_Igno>(dest.energy,"energy",db);
ReadField<ErrorPolicy_Igno>(dest.dist,"dist",db);
ReadField<ErrorPolicy_Igno>(dest.spotsize,"spotsize",db);
ReadField<ErrorPolicy_Igno>(dest.spotblend,"spotblend",db);
ReadField<ErrorPolicy_Igno>(dest.att1,"att1",db);
ReadField<ErrorPolicy_Igno>(dest.att2,"att2",db);
ReadField<ErrorPolicy_Igno>((int&)dest.falloff_type,"falloff_type",db);
ReadField<ErrorPolicy_Igno>(dest.sun_brightness,"sun_brightness",db);
ReadField<ErrorPolicy_Igno>(dest.area_size,"area_size",db);
ReadField<ErrorPolicy_Igno>(dest.area_sizey,"area_sizey",db);
ReadField<ErrorPolicy_Igno>(dest.area_sizez,"area_sizez",db);
ReadField<ErrorPolicy_Igno>(dest.area_shape,"area_shape",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MDeformWeight> (
MDeformWeight& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.def_nr,"def_nr",db);
ReadField<ErrorPolicy_Fail>(dest.weight,"weight",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<PackedFile> (
PackedFile& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Warn>(dest.size,"size",db);
ReadField<ErrorPolicy_Warn>(dest.seek,"seek",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.data,"*data",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Base> (
Base& dest,
const FileDatabase& db
) const
{
// note: as per https://github.com/assimp/assimp/issues/128,
// reading the Object linked list recursively is prone to stack overflow.
// This structure converter is therefore an hand-written exception that
// does it iteratively.
const int initial_pos = db.reader->GetCurrentPos();
std::pair<Base*, int> todo = std::make_pair(&dest, initial_pos);
for ( ;; ) {
Base& cur_dest = *todo.first;
db.reader->SetCurrentPos(todo.second);
// we know that this is a double-linked, circular list which we never
// traverse backwards, so don't bother resolving the back links.
cur_dest.prev = NULL;
ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object,"*object",db);
// the return value of ReadFieldPtr indicates whether the object
// was already cached. In this case, we don't need to resolve
// it again.
if(!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next,"*next",db, true) && cur_dest.next) {
todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
continue;
}
break;
}
db.reader->SetCurrentPos(initial_pos + size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MTFace> (
MTFace& dest,
const FileDatabase& db
) const
{
ReadFieldArray2<ErrorPolicy_Fail>(dest.uv,"uv",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db);
ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db);
ReadField<ErrorPolicy_Igno>(dest.unwrap,"unwrap",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Material> (
Material& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
ReadField<ErrorPolicy_Warn>(dest.r,"r",db);
ReadField<ErrorPolicy_Warn>(dest.g,"g",db);
ReadField<ErrorPolicy_Warn>(dest.b,"b",db);
ReadField<ErrorPolicy_Warn>(dest.specr,"specr",db);
ReadField<ErrorPolicy_Warn>(dest.specg,"specg",db);
ReadField<ErrorPolicy_Warn>(dest.specb,"specb",db);
ReadField<ErrorPolicy_Igno>(dest.har,"har",db);
ReadField<ErrorPolicy_Warn>(dest.ambr,"ambr",db);
ReadField<ErrorPolicy_Warn>(dest.ambg,"ambg",db);
ReadField<ErrorPolicy_Warn>(dest.ambb,"ambb",db);
ReadField<ErrorPolicy_Igno>(dest.mirr,"mirr",db);
ReadField<ErrorPolicy_Igno>(dest.mirg,"mirg",db);
ReadField<ErrorPolicy_Igno>(dest.mirb,"mirb",db);
ReadField<ErrorPolicy_Warn>(dest.emit,"emit",db);
ReadField<ErrorPolicy_Igno>(dest.ray_mirror,"ray_mirror",db);
ReadField<ErrorPolicy_Warn>(dest.alpha,"alpha",db);
ReadField<ErrorPolicy_Igno>(dest.ref,"ref",db);
ReadField<ErrorPolicy_Igno>(dest.translucency,"translucency",db);
ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db);
ReadField<ErrorPolicy_Igno>(dest.roughness,"roughness",db);
ReadField<ErrorPolicy_Igno>(dest.darkness,"darkness",db);
ReadField<ErrorPolicy_Igno>(dest.refrac,"refrac",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.group,"*group",db);
ReadField<ErrorPolicy_Warn>(dest.diff_shader,"diff_shader",db);
ReadField<ErrorPolicy_Warn>(dest.spec_shader,"spec_shader",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtex,"*mtex",db);
ReadField<ErrorPolicy_Igno>(dest.amb, "amb", db);
ReadField<ErrorPolicy_Igno>(dest.ang, "ang", db);
ReadField<ErrorPolicy_Igno>(dest.spectra, "spectra", db);
ReadField<ErrorPolicy_Igno>(dest.spec, "spec", db);
ReadField<ErrorPolicy_Igno>(dest.zoffs, "zoffs", db);
ReadField<ErrorPolicy_Igno>(dest.add, "add", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_mir, "fresnel_mir", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_mir_i, "fresnel_mir_i", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_tra, "fresnel_tra", db);
ReadField<ErrorPolicy_Igno>(dest.fresnel_tra_i, "fresnel_tra_i", db);
ReadField<ErrorPolicy_Igno>(dest.filter, "filter", db);
ReadField<ErrorPolicy_Igno>(dest.tx_limit, "tx_limit", db);
ReadField<ErrorPolicy_Igno>(dest.tx_falloff, "tx_falloff", db);
ReadField<ErrorPolicy_Igno>(dest.gloss_mir, "gloss_mir", db);
ReadField<ErrorPolicy_Igno>(dest.gloss_tra, "gloss_tra", db);
ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_mir, "adapt_thresh_mir", db);
ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_tra, "adapt_thresh_tra", db);
ReadField<ErrorPolicy_Igno>(dest.aniso_gloss_mir, "aniso_gloss_mir", db);
ReadField<ErrorPolicy_Igno>(dest.dist_mir, "dist_mir", db);
ReadField<ErrorPolicy_Igno>(dest.hasize, "hasize", db);
ReadField<ErrorPolicy_Igno>(dest.flaresize, "flaresize", db);
ReadField<ErrorPolicy_Igno>(dest.subsize, "subsize", db);
ReadField<ErrorPolicy_Igno>(dest.flareboost, "flareboost", db);
ReadField<ErrorPolicy_Igno>(dest.strand_sta, "strand_sta", db);
ReadField<ErrorPolicy_Igno>(dest.strand_end, "strand_end", db);
ReadField<ErrorPolicy_Igno>(dest.strand_ease, "strand_ease", db);
ReadField<ErrorPolicy_Igno>(dest.strand_surfnor, "strand_surfnor", db);
ReadField<ErrorPolicy_Igno>(dest.strand_min, "strand_min", db);
ReadField<ErrorPolicy_Igno>(dest.strand_widthfade, "strand_widthfade", db);
ReadField<ErrorPolicy_Igno>(dest.sbias, "sbias", db);
ReadField<ErrorPolicy_Igno>(dest.lbias, "lbias", db);
ReadField<ErrorPolicy_Igno>(dest.shad_alpha, "shad_alpha", db);
ReadField<ErrorPolicy_Igno>(dest.param, "param", db);
ReadField<ErrorPolicy_Igno>(dest.rms, "rms", db);
ReadField<ErrorPolicy_Igno>(dest.rampfac_col, "rampfac_col", db);
ReadField<ErrorPolicy_Igno>(dest.rampfac_spec, "rampfac_spec", db);
ReadField<ErrorPolicy_Igno>(dest.friction, "friction", db);
ReadField<ErrorPolicy_Igno>(dest.fh, "fh", db);
ReadField<ErrorPolicy_Igno>(dest.reflect, "reflect", db);
ReadField<ErrorPolicy_Igno>(dest.fhdist, "fhdist", db);
ReadField<ErrorPolicy_Igno>(dest.xyfrict, "xyfrict", db);
ReadField<ErrorPolicy_Igno>(dest.sss_radius, "sss_radius", db);
ReadField<ErrorPolicy_Igno>(dest.sss_col, "sss_col", db);
ReadField<ErrorPolicy_Igno>(dest.sss_error, "sss_error", db);
ReadField<ErrorPolicy_Igno>(dest.sss_scale, "sss_scale", db);
ReadField<ErrorPolicy_Igno>(dest.sss_ior, "sss_ior", db);
ReadField<ErrorPolicy_Igno>(dest.sss_colfac, "sss_colfac", db);
ReadField<ErrorPolicy_Igno>(dest.sss_texfac, "sss_texfac", db);
ReadField<ErrorPolicy_Igno>(dest.sss_front, "sss_front", db);
ReadField<ErrorPolicy_Igno>(dest.sss_back, "sss_back", db);
ReadField<ErrorPolicy_Igno>(dest.material_type, "material_type", db);
ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Igno>(dest.ray_depth, "ray_depth", db);
ReadField<ErrorPolicy_Igno>(dest.ray_depth_tra, "ray_depth_tra", db);
ReadField<ErrorPolicy_Igno>(dest.samp_gloss_mir, "samp_gloss_mir", db);
ReadField<ErrorPolicy_Igno>(dest.samp_gloss_tra, "samp_gloss_tra", db);
ReadField<ErrorPolicy_Igno>(dest.fadeto_mir, "fadeto_mir", db);
ReadField<ErrorPolicy_Igno>(dest.shade_flag, "shade_flag", db);
ReadField<ErrorPolicy_Igno>(dest.flarec, "flarec", db);
ReadField<ErrorPolicy_Igno>(dest.starc, "starc", db);
ReadField<ErrorPolicy_Igno>(dest.linec, "linec", db);
ReadField<ErrorPolicy_Igno>(dest.ringc, "ringc", db);
ReadField<ErrorPolicy_Igno>(dest.pr_lamp, "pr_lamp", db);
ReadField<ErrorPolicy_Igno>(dest.pr_texture, "pr_texture", db);
ReadField<ErrorPolicy_Igno>(dest.ml_flag, "ml_flag", db);
ReadField<ErrorPolicy_Igno>(dest.diff_shader, "diff_shader", db);
ReadField<ErrorPolicy_Igno>(dest.spec_shader, "spec_shader", db);
ReadField<ErrorPolicy_Igno>(dest.texco, "texco", db);
ReadField<ErrorPolicy_Igno>(dest.mapto, "mapto", db);
ReadField<ErrorPolicy_Igno>(dest.ramp_show, "ramp_show", db);
ReadField<ErrorPolicy_Igno>(dest.pad3, "pad3", db);
ReadField<ErrorPolicy_Igno>(dest.dynamode, "dynamode", db);
ReadField<ErrorPolicy_Igno>(dest.pad2, "pad2", db);
ReadField<ErrorPolicy_Igno>(dest.sss_flag, "sss_flag", db);
ReadField<ErrorPolicy_Igno>(dest.sss_preset, "sss_preset", db);
ReadField<ErrorPolicy_Igno>(dest.shadowonly_flag, "shadowonly_flag", db);
ReadField<ErrorPolicy_Igno>(dest.index, "index", db);
ReadField<ErrorPolicy_Igno>(dest.vcol_alpha, "vcol_alpha", db);
ReadField<ErrorPolicy_Igno>(dest.pad4, "pad4", db);
ReadField<ErrorPolicy_Igno>(dest.seed1, "seed1", db);
ReadField<ErrorPolicy_Igno>(dest.seed2, "seed2", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MTexPoly> (
MTexPoly& dest,
const FileDatabase& db
) const
{
{
std::shared_ptr<Image> tpage;
ReadFieldPtr<ErrorPolicy_Igno>(tpage,"*tpage",db);
dest.tpage = tpage.get();
}
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
ReadField<ErrorPolicy_Igno>(dest.transp,"transp",db);
ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db);
ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db);
ReadField<ErrorPolicy_Igno>(dest.pad,"pad",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Mesh> (
Mesh& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
ReadField<ErrorPolicy_Fail>(dest.totface,"totface",db);
ReadField<ErrorPolicy_Fail>(dest.totedge,"totedge",db);
ReadField<ErrorPolicy_Fail>(dest.totvert,"totvert",db);
ReadField<ErrorPolicy_Igno>(dest.totloop,"totloop",db);
ReadField<ErrorPolicy_Igno>(dest.totpoly,"totpoly",db);
ReadField<ErrorPolicy_Igno>(dest.subdiv,"subdiv",db);
ReadField<ErrorPolicy_Igno>(dest.subdivr,"subdivr",db);
ReadField<ErrorPolicy_Igno>(dest.subsurftype,"subsurftype",db);
ReadField<ErrorPolicy_Igno>(dest.smoothresh,"smoothresh",db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mface,"*mface",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtface,"*mtface",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.tface,"*tface",db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mvert,"*mvert",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.medge,"*medge",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mloop,"*mloop",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopuv,"*mloopuv",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopcol,"*mloopcol",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mpoly,"*mpoly",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtpoly,"*mtpoly",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.dvert,"*dvert",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol,"*mcol",db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mat,"**mat",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MDeformVert> (
MDeformVert& dest,
const FileDatabase& db
) const
{
ReadFieldPtr<ErrorPolicy_Warn>(dest.dw,"*dw",db);
ReadField<ErrorPolicy_Igno>(dest.totweight,"totweight",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<World> (
World& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MLoopCol> (
MLoopCol& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Igno>(dest.r,"r",db);
ReadField<ErrorPolicy_Igno>(dest.g,"g",db);
ReadField<ErrorPolicy_Igno>(dest.b,"b",db);
ReadField<ErrorPolicy_Igno>(dest.a,"a",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MVert> (
MVert& dest,
const FileDatabase& db
) const
{
ReadFieldArray<ErrorPolicy_Fail>(dest.co,"co",db);
ReadFieldArray<ErrorPolicy_Fail>(dest.no,"no",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
ReadField<ErrorPolicy_Igno>(dest.bweight,"bweight",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MEdge> (
MEdge& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.v1,"v1",db);
ReadField<ErrorPolicy_Fail>(dest.v2,"v2",db);
ReadField<ErrorPolicy_Igno>(dest.crease,"crease",db);
ReadField<ErrorPolicy_Igno>(dest.bweight,"bweight",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MLoopUV> (
MLoopUV& dest,
const FileDatabase& db
) const
{
ReadFieldArray<ErrorPolicy_Igno>(dest.uv,"uv",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<GroupObject> (
GroupObject& dest,
const FileDatabase& db
) const
{
ReadFieldPtr<ErrorPolicy_Fail>(dest.prev,"*prev",db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.next,"*next",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.ob,"*ob",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<ListBase> (
ListBase& dest,
const FileDatabase& db
) const
{
ReadFieldPtr<ErrorPolicy_Igno>(dest.first,"*first",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.last,"*last",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MLoop> (
MLoop& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Igno>(dest.v,"v",db);
ReadField<ErrorPolicy_Igno>(dest.e,"e",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<ModifierData> (
ModifierData& dest,
const FileDatabase& db
) const
{
ReadFieldPtr<ErrorPolicy_Warn>(dest.next,"*next",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.prev,"*prev",db);
ReadField<ErrorPolicy_Igno>(dest.type,"type",db);
ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db);
ReadFieldArray<ErrorPolicy_Igno>(dest.name,"name",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<ID> (
ID& dest,
const FileDatabase& db
) const
{
ReadFieldArray<ErrorPolicy_Warn>(dest.name,"name",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MCol> (
MCol& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.r,"r",db);
ReadField<ErrorPolicy_Fail>(dest.g,"g",db);
ReadField<ErrorPolicy_Fail>(dest.b,"b",db);
ReadField<ErrorPolicy_Fail>(dest.a,"a",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MPoly> (
MPoly& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Igno>(dest.loopstart,"loopstart",db);
ReadField<ErrorPolicy_Igno>(dest.totloop,"totloop",db);
ReadField<ErrorPolicy_Igno>(dest.mat_nr,"mat_nr",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Scene> (
Scene& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.camera,"*camera",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.world,"*world",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.basact,"*basact",db);
ReadField<ErrorPolicy_Igno>(dest.base,"base",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Library> (
Library& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name,"name",db);
ReadFieldArray<ErrorPolicy_Fail>(dest.filename,"filename",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.parent,"*parent",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Tex> (
Tex& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Igno>((short&)dest.imaflag,"imaflag",db);
ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.ima,"*ima",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Camera> (
Camera& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
ReadField<ErrorPolicy_Warn>((int&)dest.type,"type",db);
ReadField<ErrorPolicy_Warn>((int&)dest.flag,"flag",db);
ReadField<ErrorPolicy_Warn>(dest.lens,"lens",db);
ReadField<ErrorPolicy_Warn>(dest.sensor_x,"sensor_x",db);
ReadField<ErrorPolicy_Igno>(dest.clipsta,"clipsta",db);
ReadField<ErrorPolicy_Igno>(dest.clipend,"clipend",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<MirrorModifierData> (
MirrorModifierData& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.modifier,"modifier",db);
ReadField<ErrorPolicy_Igno>(dest.axis,"axis",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
ReadField<ErrorPolicy_Igno>(dest.tolerance,"tolerance",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.mirror_ob,"*mirror_ob",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure :: Convert<Image> (
Image& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name,"name",db);
ReadField<ErrorPolicy_Igno>(dest.ok,"ok",db);
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
ReadField<ErrorPolicy_Igno>(dest.source,"source",db);
ReadField<ErrorPolicy_Igno>(dest.type,"type",db);
ReadField<ErrorPolicy_Igno>(dest.pad,"pad",db);
ReadField<ErrorPolicy_Igno>(dest.pad1,"pad1",db);
ReadField<ErrorPolicy_Igno>(dest.lastframe,"lastframe",db);
ReadField<ErrorPolicy_Igno>(dest.tpageflag,"tpageflag",db);
ReadField<ErrorPolicy_Igno>(dest.totbind,"totbind",db);
ReadField<ErrorPolicy_Igno>(dest.xrep,"xrep",db);
ReadField<ErrorPolicy_Igno>(dest.yrep,"yrep",db);
ReadField<ErrorPolicy_Igno>(dest.twsta,"twsta",db);
ReadField<ErrorPolicy_Igno>(dest.twend,"twend",db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.packedfile,"*packedfile",db);
ReadField<ErrorPolicy_Igno>(dest.lastupdate,"lastupdate",db);
ReadField<ErrorPolicy_Igno>(dest.lastused,"lastused",db);
ReadField<ErrorPolicy_Igno>(dest.animspeed,"animspeed",db);
ReadField<ErrorPolicy_Igno>(dest.gen_x,"gen_x",db);
ReadField<ErrorPolicy_Igno>(dest.gen_y,"gen_y",db);
ReadField<ErrorPolicy_Igno>(dest.gen_type,"gen_type",db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
void DNA::RegisterConverters() {
converters["Object"] = DNA::FactoryPair( &Structure::Allocate<Object>, &Structure::Convert<Object> );
converters["Group"] = DNA::FactoryPair( &Structure::Allocate<Group>, &Structure::Convert<Group> );
converters["MTex"] = DNA::FactoryPair( &Structure::Allocate<MTex>, &Structure::Convert<MTex> );
converters["TFace"] = DNA::FactoryPair( &Structure::Allocate<TFace>, &Structure::Convert<TFace> );
converters["SubsurfModifierData"] = DNA::FactoryPair( &Structure::Allocate<SubsurfModifierData>, &Structure::Convert<SubsurfModifierData> );
converters["MFace"] = DNA::FactoryPair( &Structure::Allocate<MFace>, &Structure::Convert<MFace> );
converters["Lamp"] = DNA::FactoryPair( &Structure::Allocate<Lamp>, &Structure::Convert<Lamp> );
converters["MDeformWeight"] = DNA::FactoryPair( &Structure::Allocate<MDeformWeight>, &Structure::Convert<MDeformWeight> );
converters["PackedFile"] = DNA::FactoryPair( &Structure::Allocate<PackedFile>, &Structure::Convert<PackedFile> );
converters["Base"] = DNA::FactoryPair( &Structure::Allocate<Base>, &Structure::Convert<Base> );
converters["MTFace"] = DNA::FactoryPair( &Structure::Allocate<MTFace>, &Structure::Convert<MTFace> );
converters["Material"] = DNA::FactoryPair( &Structure::Allocate<Material>, &Structure::Convert<Material> );
converters["MTexPoly"] = DNA::FactoryPair( &Structure::Allocate<MTexPoly>, &Structure::Convert<MTexPoly> );
converters["Mesh"] = DNA::FactoryPair( &Structure::Allocate<Mesh>, &Structure::Convert<Mesh> );
converters["MDeformVert"] = DNA::FactoryPair( &Structure::Allocate<MDeformVert>, &Structure::Convert<MDeformVert> );
converters["World"] = DNA::FactoryPair( &Structure::Allocate<World>, &Structure::Convert<World> );
converters["MLoopCol"] = DNA::FactoryPair( &Structure::Allocate<MLoopCol>, &Structure::Convert<MLoopCol> );
converters["MVert"] = DNA::FactoryPair( &Structure::Allocate<MVert>, &Structure::Convert<MVert> );
converters["MEdge"] = DNA::FactoryPair( &Structure::Allocate<MEdge>, &Structure::Convert<MEdge> );
converters["MLoopUV"] = DNA::FactoryPair( &Structure::Allocate<MLoopUV>, &Structure::Convert<MLoopUV> );
converters["GroupObject"] = DNA::FactoryPair( &Structure::Allocate<GroupObject>, &Structure::Convert<GroupObject> );
converters["ListBase"] = DNA::FactoryPair( &Structure::Allocate<ListBase>, &Structure::Convert<ListBase> );
converters["MLoop"] = DNA::FactoryPair( &Structure::Allocate<MLoop>, &Structure::Convert<MLoop> );
converters["ModifierData"] = DNA::FactoryPair( &Structure::Allocate<ModifierData>, &Structure::Convert<ModifierData> );
converters["ID"] = DNA::FactoryPair( &Structure::Allocate<ID>, &Structure::Convert<ID> );
converters["MCol"] = DNA::FactoryPair( &Structure::Allocate<MCol>, &Structure::Convert<MCol> );
converters["MPoly"] = DNA::FactoryPair( &Structure::Allocate<MPoly>, &Structure::Convert<MPoly> );
converters["Scene"] = DNA::FactoryPair( &Structure::Allocate<Scene>, &Structure::Convert<Scene> );
converters["Library"] = DNA::FactoryPair( &Structure::Allocate<Library>, &Structure::Convert<Library> );
converters["Tex"] = DNA::FactoryPair( &Structure::Allocate<Tex>, &Structure::Convert<Tex> );
converters["Camera"] = DNA::FactoryPair( &Structure::Allocate<Camera>, &Structure::Convert<Camera> );
converters["MirrorModifierData"] = DNA::FactoryPair( &Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData> );
converters["Image"] = DNA::FactoryPair( &Structure::Allocate<Image>, &Structure::Convert<Image> );
}
#endif

View file

@ -0,0 +1,843 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderScene.h
* @brief Intermediate representation of a BLEND scene.
*/
#ifndef INCLUDED_AI_BLEND_SCENE_H
#define INCLUDED_AI_BLEND_SCENE_H
#include "BlenderDNA.h"
namespace Assimp {
namespace Blender {
// Minor parts of this file are extracts from blender data structures,
// declared in the ./source/blender/makesdna directory.
// Stuff that is not used by Assimp is commented.
// NOTE
// this file serves as input data to the `./scripts/genblenddna.py`
// script. This script generates the actual binding code to read a
// blender file with a possibly different DNA into our structures.
// Only `struct` declarations are considered and the following
// rules must be obeyed in order for the script to work properly:
//
// * C++ style comments only
//
// * Structures may include the primitive types char, int, short,
// float, double. Signedness specifiers are not allowed on
// integers. Enum types are allowed, but they must have been
// defined in this header.
//
// * Structures may aggregate other structures, unless not defined
// in this header.
//
// * Pointers to other structures or primitive types are allowed.
// No references or double pointers or arrays of pointers.
// A pointer to a T is normally written as std::shared_ptr, while a
// pointer to an array of elements is written as boost::
// shared_array. To avoid cyclic pointers, use raw pointers in
// one direction.
//
// * Arrays can have maximally two-dimensions. Any non-pointer
// type can form them.
//
// * Multiple fields can be declare in a single line (i.e `int a,b;`)
// provided they are neither pointers nor arrays.
//
// * One of WARN, FAIL can be appended to the declaration (
// prior to the semiolon to specifiy the error handling policy if
// this field is missing in the input DNA). If none of those
// is specified the default policy is to subtitute a default
// value for the field.
//
#define WARN // warn if field is missing, substitute default value
#define FAIL // fail the import if the field does not exist
struct Object;
struct MTex;
struct Image;
#include <memory>
#define AI_BLEND_MESH_MAX_VERTS 2000000000L
// -------------------------------------------------------------------------------
struct ID : ElemBase {
char name[1024] WARN;
short flag;
};
// -------------------------------------------------------------------------------
struct ListBase : ElemBase {
std::shared_ptr<ElemBase> first;
std::shared_ptr<ElemBase> last;
};
// -------------------------------------------------------------------------------
struct PackedFile : ElemBase {
int size WARN;
int seek WARN;
std::shared_ptr< FileOffset > data WARN;
};
// -------------------------------------------------------------------------------
struct GroupObject : ElemBase {
std::shared_ptr<GroupObject> prev,next FAIL;
std::shared_ptr<Object> ob;
};
// -------------------------------------------------------------------------------
struct Group : ElemBase {
ID id FAIL;
int layer;
std::shared_ptr<GroupObject> gobject;
};
// -------------------------------------------------------------------------------
struct World : ElemBase {
ID id FAIL;
};
// -------------------------------------------------------------------------------
struct MVert : ElemBase {
float co[3] FAIL;
float no[3] FAIL;
char flag;
int mat_nr WARN;
int bweight;
};
// -------------------------------------------------------------------------------
struct MEdge : ElemBase {
int v1, v2 FAIL;
char crease, bweight;
short flag;
};
// -------------------------------------------------------------------------------
struct MLoop : ElemBase {
int v, e;
};
// -------------------------------------------------------------------------------
struct MLoopUV : ElemBase {
float uv[2];
int flag;
};
// -------------------------------------------------------------------------------
// Note that red and blue are not swapped, as with MCol
struct MLoopCol : ElemBase {
char r, g, b, a;
};
// -------------------------------------------------------------------------------
struct MPoly : ElemBase {
int loopstart;
int totloop;
short mat_nr;
char flag;
};
// -------------------------------------------------------------------------------
struct MTexPoly : ElemBase {
Image* tpage;
char flag, transp;
short mode, tile, pad;
};
// -------------------------------------------------------------------------------
struct MCol : ElemBase {
char r,g,b,a FAIL;
};
// -------------------------------------------------------------------------------
struct MFace : ElemBase {
int v1,v2,v3,v4 FAIL;
int mat_nr FAIL;
char flag;
};
// -------------------------------------------------------------------------------
struct TFace : ElemBase {
float uv[4][2] FAIL;
int col[4] FAIL;
char flag;
short mode;
short tile;
short unwrap;
};
// -------------------------------------------------------------------------------
struct MTFace : ElemBase {
float uv[4][2] FAIL;
char flag;
short mode;
short tile;
short unwrap;
// std::shared_ptr<Image> tpage;
};
// -------------------------------------------------------------------------------
struct MDeformWeight : ElemBase {
int def_nr FAIL;
float weight FAIL;
};
// -------------------------------------------------------------------------------
struct MDeformVert : ElemBase {
vector<MDeformWeight> dw WARN;
int totweight;
};
// -------------------------------------------------------------------------------
#define MA_RAYMIRROR 0x40000
#define MA_TRANSPARENCY 0x10000
#define MA_RAYTRANSP 0x20000
#define MA_ZTRANSP 0x00040
struct Material : ElemBase {
ID id FAIL;
float r,g,b WARN;
float specr,specg,specb WARN;
short har;
float ambr,ambg,ambb WARN;
float mirr,mirg,mirb;
float emit WARN;
float ray_mirror;
float alpha WARN;
float ref;
float translucency;
int mode;
float roughness;
float darkness;
float refrac;
float amb;
float ang;
float spectra;
float spec;
float zoffs;
float add;
float fresnel_mir;
float fresnel_mir_i;
float fresnel_tra;
float fresnel_tra_i;
float filter;
float tx_limit;
float tx_falloff;
float gloss_mir;
float gloss_tra;
float adapt_thresh_mir;
float adapt_thresh_tra;
float aniso_gloss_mir;
float dist_mir;
float hasize;
float flaresize;
float subsize;
float flareboost;
float strand_sta;
float strand_end;
float strand_ease;
float strand_surfnor;
float strand_min;
float strand_widthfade;
float sbias;
float lbias;
float shad_alpha;
float param;
float rms;
float rampfac_col;
float rampfac_spec;
float friction;
float fh;
float reflect;
float fhdist;
float xyfrict;
float sss_radius;
float sss_col;
float sss_error;
float sss_scale;
float sss_ior;
float sss_colfac;
float sss_texfac;
float sss_front;
float sss_back;
short material_type;
short flag;
short ray_depth;
short ray_depth_tra;
short samp_gloss_mir;
short samp_gloss_tra;
short fadeto_mir;
short shade_flag;
short flarec;
short starc;
short linec;
short ringc;
short pr_lamp;
short pr_texture;
short ml_flag;
short texco;
short mapto;
short ramp_show;
short pad3;
short dynamode;
short pad2;
short sss_flag;
short sss_preset;
short shadowonly_flag;
short index;
short vcol_alpha;
short pad4;
char seed1;
char seed2;
std::shared_ptr<Group> group;
short diff_shader WARN;
short spec_shader WARN;
std::shared_ptr<MTex> mtex[18];
};
// -------------------------------------------------------------------------------
struct Mesh : ElemBase {
ID id FAIL;
int totface FAIL;
int totedge FAIL;
int totvert FAIL;
int totloop;
int totpoly;
short subdiv;
short subdivr;
short subsurftype;
short smoothresh;
vector<MFace> mface FAIL;
vector<MTFace> mtface;
vector<TFace> tface;
vector<MVert> mvert FAIL;
vector<MEdge> medge WARN;
vector<MLoop> mloop;
vector<MLoopUV> mloopuv;
vector<MLoopCol> mloopcol;
vector<MPoly> mpoly;
vector<MTexPoly> mtpoly;
vector<MDeformVert> dvert;
vector<MCol> mcol;
vector< std::shared_ptr<Material> > mat FAIL;
};
// -------------------------------------------------------------------------------
struct Library : ElemBase {
ID id FAIL;
char name[240] WARN;
char filename[240] FAIL;
std::shared_ptr<Library> parent WARN;
};
// -------------------------------------------------------------------------------
struct Camera : ElemBase {
enum Type {
Type_PERSP = 0
,Type_ORTHO = 1
};
ID id FAIL;
Type type,flag WARN;
float lens WARN;
float sensor_x WARN;
float clipsta, clipend;
};
// -------------------------------------------------------------------------------
struct Lamp : ElemBase {
enum FalloffType {
FalloffType_Constant = 0x0
,FalloffType_InvLinear = 0x1
,FalloffType_InvSquare = 0x2
//,FalloffType_Curve = 0x3
//,FalloffType_Sliders = 0x4
};
enum Type {
Type_Local = 0x0
,Type_Sun = 0x1
,Type_Spot = 0x2
,Type_Hemi = 0x3
,Type_Area = 0x4
//,Type_YFPhoton = 0x5
};
ID id FAIL;
//AnimData *adt;
Type type FAIL;
short flags;
//int mode;
short colormodel, totex;
float r,g,b,k WARN;
//float shdwr, shdwg, shdwb;
float energy, dist, spotsize, spotblend;
//float haint;
float att1, att2;
//struct CurveMapping *curfalloff;
FalloffType falloff_type;
//float clipsta, clipend, shadspotsize;
//float bias, soft, compressthresh;
//short bufsize, samp, buffers, filtertype;
//char bufflag, buftype;
//short ray_samp, ray_sampy, ray_sampz;
//short ray_samp_type;
short area_shape;
float area_size, area_sizey, area_sizez;
//float adapt_thresh;
//short ray_samp_method;
//short texact, shadhalostep;
//short sun_effect_type;
//short skyblendtype;
//float horizon_brightness;
//float spread;
float sun_brightness;
//float sun_size;
//float backscattered_light;
//float sun_intensity;
//float atm_turbidity;
//float atm_inscattering_factor;
//float atm_extinction_factor;
//float atm_distance_factor;
//float skyblendfac;
//float sky_exposure;
//short sky_colorspace;
// int YF_numphotons, YF_numsearch;
// short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
// float YF_causticblur, YF_ltradius;
// float YF_glowint, YF_glowofs;
// short YF_glowtype, YF_pad2;
//struct Ipo *ipo;
//struct MTex *mtex[18];
// short pr_texture;
//struct PreviewImage *preview;
};
// -------------------------------------------------------------------------------
struct ModifierData : ElemBase {
enum ModifierType {
eModifierType_None = 0,
eModifierType_Subsurf,
eModifierType_Lattice,
eModifierType_Curve,
eModifierType_Build,
eModifierType_Mirror,
eModifierType_Decimate,
eModifierType_Wave,
eModifierType_Armature,
eModifierType_Hook,
eModifierType_Softbody,
eModifierType_Boolean,
eModifierType_Array,
eModifierType_EdgeSplit,
eModifierType_Displace,
eModifierType_UVProject,
eModifierType_Smooth,
eModifierType_Cast,
eModifierType_MeshDeform,
eModifierType_ParticleSystem,
eModifierType_ParticleInstance,
eModifierType_Explode,
eModifierType_Cloth,
eModifierType_Collision,
eModifierType_Bevel,
eModifierType_Shrinkwrap,
eModifierType_Fluidsim,
eModifierType_Mask,
eModifierType_SimpleDeform,
eModifierType_Multires,
eModifierType_Surface,
eModifierType_Smoke,
eModifierType_ShapeKey
};
std::shared_ptr<ElemBase> next WARN;
std::shared_ptr<ElemBase> prev WARN;
int type, mode;
char name[32];
};
// -------------------------------------------------------------------------------
struct SubsurfModifierData : ElemBase {
enum Type {
TYPE_CatmullClarke = 0x0,
TYPE_Simple = 0x1
};
enum Flags {
// some omitted
FLAGS_SubsurfUV =1<<3
};
ModifierData modifier FAIL;
short subdivType WARN;
short levels FAIL;
short renderLevels ;
short flags;
};
// -------------------------------------------------------------------------------
struct MirrorModifierData : ElemBase {
enum Flags {
Flags_CLIPPING =1<<0,
Flags_MIRROR_U =1<<1,
Flags_MIRROR_V =1<<2,
Flags_AXIS_X =1<<3,
Flags_AXIS_Y =1<<4,
Flags_AXIS_Z =1<<5,
Flags_VGROUP =1<<6
};
ModifierData modifier FAIL;
short axis, flag;
float tolerance;
std::shared_ptr<Object> mirror_ob;
};
// -------------------------------------------------------------------------------
struct Object : ElemBase {
ID id FAIL;
enum Type {
Type_EMPTY = 0
,Type_MESH = 1
,Type_CURVE = 2
,Type_SURF = 3
,Type_FONT = 4
,Type_MBALL = 5
,Type_LAMP = 10
,Type_CAMERA = 11
,Type_WAVE = 21
,Type_LATTICE = 22
};
Type type FAIL;
float obmat[4][4] WARN;
float parentinv[4][4] WARN;
char parsubstr[32] WARN;
Object* parent WARN;
std::shared_ptr<Object> track WARN;
std::shared_ptr<Object> proxy,proxy_from,proxy_group WARN;
std::shared_ptr<Group> dup_group WARN;
std::shared_ptr<ElemBase> data FAIL;
ListBase modifiers;
};
// -------------------------------------------------------------------------------
struct Base : ElemBase {
Base* prev WARN;
std::shared_ptr<Base> next WARN;
std::shared_ptr<Object> object WARN;
};
// -------------------------------------------------------------------------------
struct Scene : ElemBase {
ID id FAIL;
std::shared_ptr<Object> camera WARN;
std::shared_ptr<World> world WARN;
std::shared_ptr<Base> basact WARN;
ListBase base;
};
// -------------------------------------------------------------------------------
struct Image : ElemBase {
ID id FAIL;
char name[240] WARN;
//struct anim *anim;
short ok, flag;
short source, type, pad, pad1;
int lastframe;
short tpageflag, totbind;
short xrep, yrep;
short twsta, twend;
//unsigned int bindcode;
//unsigned int *repbind;
std::shared_ptr<PackedFile> packedfile;
//struct PreviewImage * preview;
float lastupdate;
int lastused;
short animspeed;
short gen_x, gen_y, gen_type;
};
// -------------------------------------------------------------------------------
struct Tex : ElemBase {
// actually, the only texture type we support is Type_IMAGE
enum Type {
Type_CLOUDS = 1
,Type_WOOD = 2
,Type_MARBLE = 3
,Type_MAGIC = 4
,Type_BLEND = 5
,Type_STUCCI = 6
,Type_NOISE = 7
,Type_IMAGE = 8
,Type_PLUGIN = 9
,Type_ENVMAP = 10
,Type_MUSGRAVE = 11
,Type_VORONOI = 12
,Type_DISTNOISE = 13
,Type_POINTDENSITY = 14
,Type_VOXELDATA = 15
};
enum ImageFlags {
ImageFlags_INTERPOL = 1
,ImageFlags_USEALPHA = 2
,ImageFlags_MIPMAP = 4
,ImageFlags_IMAROT = 16
,ImageFlags_CALCALPHA = 32
,ImageFlags_NORMALMAP = 2048
,ImageFlags_GAUSS_MIP = 4096
,ImageFlags_FILTER_MIN = 8192
,ImageFlags_DERIVATIVEMAP = 16384
};
ID id FAIL;
// AnimData *adt;
//float noisesize, turbul;
//float bright, contrast, rfac, gfac, bfac;
//float filtersize;
//float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain;
//float dist_amount, ns_outscale;
//float vn_w1;
//float vn_w2;
//float vn_w3;
//float vn_w4;
//float vn_mexp;
//short vn_distm, vn_coltype;
//short noisedepth, noisetype;
//short noisebasis, noisebasis2;
//short flag;
ImageFlags imaflag;
Type type FAIL;
//short stype;
//float cropxmin, cropymin, cropxmax, cropymax;
//int texfilter;
//int afmax;
//short xrepeat, yrepeat;
//short extend;
//short fie_ima;
//int len;
//int frames, offset, sfra;
//float checkerdist, nabla;
//float norfac;
//ImageUser iuser;
//bNodeTree *nodetree;
//Ipo *ipo;
std::shared_ptr<Image> ima WARN;
//PluginTex *plugin;
//ColorBand *coba;
//EnvMap *env;
//PreviewImage * preview;
//PointDensity *pd;
//VoxelData *vd;
//char use_nodes;
};
// -------------------------------------------------------------------------------
struct MTex : ElemBase {
enum Projection {
Proj_N = 0
,Proj_X = 1
,Proj_Y = 2
,Proj_Z = 3
};
enum Flag {
Flag_RGBTOINT = 0x1
,Flag_STENCIL = 0x2
,Flag_NEGATIVE = 0x4
,Flag_ALPHAMIX = 0x8
,Flag_VIEWSPACE = 0x10
};
enum BlendType {
BlendType_BLEND = 0
,BlendType_MUL = 1
,BlendType_ADD = 2
,BlendType_SUB = 3
,BlendType_DIV = 4
,BlendType_DARK = 5
,BlendType_DIFF = 6
,BlendType_LIGHT = 7
,BlendType_SCREEN = 8
,BlendType_OVERLAY = 9
,BlendType_BLEND_HUE = 10
,BlendType_BLEND_SAT = 11
,BlendType_BLEND_VAL = 12
,BlendType_BLEND_COLOR = 13
};
enum MapType {
MapType_COL = 1
,MapType_NORM = 2
,MapType_COLSPEC = 4
,MapType_COLMIR = 8
,MapType_REF = 16
,MapType_SPEC = 32
,MapType_EMIT = 64
,MapType_ALPHA = 128
,MapType_HAR = 256
,MapType_RAYMIRR = 512
,MapType_TRANSLU = 1024
,MapType_AMB = 2048
,MapType_DISPLACE = 4096
,MapType_WARP = 8192
};
// short texco, maptoneg;
MapType mapto;
BlendType blendtype;
std::shared_ptr<Object> object;
std::shared_ptr<Tex> tex;
char uvname[32];
Projection projx,projy,projz;
char mapping;
float ofs[3], size[3], rot;
int texflag;
short colormodel, pmapto, pmaptoneg;
//short normapspace, which_output;
//char brush_map_mode;
float r,g,b,k WARN;
//float def_var, rt;
//float colfac, varfac;
float norfac;
//float dispfac, warpfac;
float colspecfac, mirrfac, alphafac;
float difffac, specfac, emitfac, hardfac;
//float raymirrfac, translfac, ambfac;
//float colemitfac, colreflfac, coltransfac;
//float densfac, scatterfac, reflfac;
//float timefac, lengthfac, clumpfac;
//float kinkfac, roughfac, padensfac;
//float lifefac, sizefac, ivelfac, pvelfac;
//float shadowfac;
//float zenupfac, zendownfac, blendfac;
};
}
}
#endif

View file

@ -0,0 +1,255 @@
/*
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.
----------------------------------------------------------------------
*/
/** @file BlenderSceneGen.h
* @brief MACHINE GENERATED BY ./scripts/BlenderImporter/genblenddna.py
*/
#ifndef INCLUDED_AI_BLEND_SCENEGEN_H
#define INCLUDED_AI_BLEND_SCENEGEN_H
#include "BlenderDNA.h"
#include "BlenderScene.h"
namespace Assimp {
namespace Blender {
template <> void Structure :: Convert<Object> (
Object& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Group> (
Group& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MTex> (
MTex& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<TFace> (
TFace& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<SubsurfModifierData> (
SubsurfModifierData& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MFace> (
MFace& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Lamp> (
Lamp& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MDeformWeight> (
MDeformWeight& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<PackedFile> (
PackedFile& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Base> (
Base& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MTFace> (
MTFace& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Material> (
Material& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MTexPoly> (
MTexPoly& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Mesh> (
Mesh& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MDeformVert> (
MDeformVert& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<World> (
World& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MLoopCol> (
MLoopCol& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MVert> (
MVert& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MEdge> (
MEdge& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MLoopUV> (
MLoopUV& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<GroupObject> (
GroupObject& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<ListBase> (
ListBase& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MLoop> (
MLoop& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<ModifierData> (
ModifierData& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<ID> (
ID& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MCol> (
MCol& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MPoly> (
MPoly& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Scene> (
Scene& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Library> (
Library& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Tex> (
Tex& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Camera> (
Camera& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MirrorModifierData> (
MirrorModifierData& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<Image> (
Image& dest,
const FileDatabase& db
) const
;
}
}
#endif

View file

@ -0,0 +1,516 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderTessellator.cpp
* @brief A simple tessellation wrapper
*/
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
#include "BlenderDNA.h"
#include "BlenderScene.h"
#include "BlenderBMesh.h"
#include "BlenderTessellator.h"
#include <stddef.h>
static const unsigned int BLEND_TESS_MAGIC = 0x83ed9ac3;
#if ASSIMP_BLEND_WITH_GLU_TESSELLATE
namspace Assimp
{
template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
}
using namespace Assimp;
using namespace Assimp::Blender;
#ifndef CALLBACK
#define CALLBACK
#endif
// ------------------------------------------------------------------------------------------------
BlenderTessellatorGL::BlenderTessellatorGL( BlenderBMeshConverter& converter ):
converter( &converter )
{
}
// ------------------------------------------------------------------------------------------------
BlenderTessellatorGL::~BlenderTessellatorGL( )
{
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
{
AssertVertexCount( vertexCount );
std::vector< VertexGL > polyLoopGL;
GenerateLoopVerts( polyLoopGL, polyLoop, vertexCount, vertices );
TessDataGL tessData;
Tesssellate( polyLoopGL, tessData );
TriangulateDrawCalls( tessData );
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::AssertVertexCount( int vertexCount )
{
if ( vertexCount <= 4 )
{
ThrowException( "Expected more than 4 vertices for tessellation" );
}
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::GenerateLoopVerts( std::vector< VertexGL >& polyLoopGL, const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
{
for ( int i = 0; i < vertexCount; ++i )
{
const MLoop& loopItem = polyLoop[ i ];
const MVert& vertex = vertices[ loopItem.v ];
polyLoopGL.push_back( VertexGL( vertex.co[ 0 ], vertex.co[ 1 ], vertex.co[ 2 ], loopItem.v, BLEND_TESS_MAGIC ) );
}
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::Tesssellate( std::vector< VertexGL >& polyLoopGL, TessDataGL& tessData )
{
GLUtesselator* tessellator = gluNewTess( );
gluTessCallback( tessellator, GLU_TESS_BEGIN_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateBegin ) );
gluTessCallback( tessellator, GLU_TESS_END_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEnd ) );
gluTessCallback( tessellator, GLU_TESS_VERTEX_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateVertex ) );
gluTessCallback( tessellator, GLU_TESS_COMBINE_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateCombine ) );
gluTessCallback( tessellator, GLU_TESS_EDGE_FLAG_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEdgeFlag ) );
gluTessCallback( tessellator, GLU_TESS_ERROR_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateError ) );
gluTessProperty( tessellator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO );
gluTessBeginPolygon( tessellator, &tessData );
gluTessBeginContour( tessellator );
for ( unsigned int i = 0; i < polyLoopGL.size( ); ++i )
{
gluTessVertex( tessellator, reinterpret_cast< GLdouble* >( &polyLoopGL[ i ] ), &polyLoopGL[ i ] );
}
gluTessEndContour( tessellator );
gluTessEndPolygon( tessellator );
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::TriangulateDrawCalls( const TessDataGL& tessData )
{
// NOTE - Because we are supplying a callback to GLU_TESS_EDGE_FLAG_DATA we don't technically
// need support for GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN but we'll keep it here in case
// GLU tessellate changes or tri-strips and fans are wanted.
// See: http://www.opengl.org/sdk/docs/man2/xhtml/gluTessCallback.xml
for ( unsigned int i = 0; i < tessData.drawCalls.size( ); ++i )
{
const DrawCallGL& drawCallGL = tessData.drawCalls[ i ];
const VertexGL* vertices = &tessData.vertices[ drawCallGL.baseVertex ];
if ( drawCallGL.drawMode == GL_TRIANGLES )
{
MakeFacesFromTris( vertices, drawCallGL.vertexCount );
}
else if ( drawCallGL.drawMode == GL_TRIANGLE_STRIP )
{
MakeFacesFromTriStrip( vertices, drawCallGL.vertexCount );
}
else if ( drawCallGL.drawMode == GL_TRIANGLE_FAN )
{
MakeFacesFromTriFan( vertices, drawCallGL.vertexCount );
}
}
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::MakeFacesFromTris( const VertexGL* vertices, int vertexCount )
{
const int triangleCount = vertexCount / 3;
for ( int i = 0; i < triangleCount; ++i )
{
int vertexBase = i * 3;
converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
}
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::MakeFacesFromTriStrip( const VertexGL* vertices, int vertexCount )
{
const int triangleCount = vertexCount - 2;
for ( int i = 0; i < triangleCount; ++i )
{
int vertexBase = i;
converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
}
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::MakeFacesFromTriFan( const VertexGL* vertices, int vertexCount )
{
const int triangleCount = vertexCount - 2;
for ( int i = 0; i < triangleCount; ++i )
{
int vertexBase = i;
converter->AddFace( vertices[ 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
}
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::TessellateBegin( GLenum drawModeGL, void* userData )
{
TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
tessData.drawCalls.push_back( DrawCallGL( drawModeGL, tessData.vertices.size( ) ) );
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::TessellateEnd( void* )
{
// Do nothing
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::TessellateVertex( const void* vtxData, void* userData )
{
TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
const VertexGL& vertex = *reinterpret_cast< const VertexGL* >( vtxData );
if ( vertex.magic != BLEND_TESS_MAGIC )
{
ThrowException( "Point returned by GLU Tessellate was probably not one of ours. This indicates we need a new way to store vertex information" );
}
tessData.vertices.push_back( vertex );
if ( tessData.drawCalls.size( ) == 0 )
{
ThrowException( "\"Vertex\" callback received before \"Begin\"" );
}
++( tessData.drawCalls.back( ).vertexCount );
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData )
{
ThrowException( "Intersected polygon loops are not yet supported" );
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::TessellateEdgeFlag( GLboolean, void* )
{
// Do nothing
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* )
{
ThrowException( reinterpret_cast< const char* >( gluErrorString( errorCode ) ) );
}
#endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE
#if ASSIMP_BLEND_WITH_POLY_2_TRI
namespace Assimp
{
template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: ";
}
using namespace Assimp;
using namespace Assimp::Blender;
// ------------------------------------------------------------------------------------------------
BlenderTessellatorP2T::BlenderTessellatorP2T( BlenderBMeshConverter& converter ):
converter( &converter )
{
}
// ------------------------------------------------------------------------------------------------
BlenderTessellatorP2T::~BlenderTessellatorP2T( )
{
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorP2T::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
{
AssertVertexCount( vertexCount );
// NOTE - We have to hope that points in a Blender polygon are roughly on the same plane.
// There may be some triangulation artifacts if they are wildly different.
std::vector< PointP2T > points;
Copy3DVertices( polyLoop, vertexCount, vertices, points );
PlaneP2T plane = FindLLSQPlane( points );
aiMatrix4x4 transform = GeneratePointTransformMatrix( plane );
TransformAndFlattenVectices( transform, points );
std::vector< p2t::Point* > pointRefs;
ReferencePoints( points, pointRefs );
p2t::CDT cdt( pointRefs );
cdt.Triangulate( );
std::vector< p2t::Triangle* > triangles = cdt.GetTriangles( );
MakeFacesFromTriangles( triangles );
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorP2T::AssertVertexCount( int vertexCount )
{
if ( vertexCount <= 4 )
{
ThrowException( "Expected more than 4 vertices for tessellation" );
}
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorP2T::Copy3DVertices( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices, std::vector< PointP2T >& points ) const
{
points.resize( vertexCount );
for ( int i = 0; i < vertexCount; ++i )
{
const MLoop& loop = polyLoop[ i ];
const MVert& vert = vertices[ loop.v ];
PointP2T& point = points[ i ];
point.point3D.Set( vert.co[ 0 ], vert.co[ 1 ], vert.co[ 2 ] );
point.index = loop.v;
point.magic = BLEND_TESS_MAGIC;
}
}
// ------------------------------------------------------------------------------------------------
aiMatrix4x4 BlenderTessellatorP2T::GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const
{
aiVector3D sideA( 1.0f, 0.0f, 0.0f );
if ( std::fabs( plane.normal * sideA ) > 0.999f )
{
sideA = aiVector3D( 0.0f, 1.0f, 0.0f );
}
aiVector3D sideB( plane.normal ^ sideA );
sideB.Normalize( );
sideA = sideB ^ plane.normal;
aiMatrix4x4 result;
result.a1 = sideA.x;
result.a2 = sideA.y;
result.a3 = sideA.z;
result.b1 = sideB.x;
result.b2 = sideB.y;
result.b3 = sideB.z;
result.c1 = plane.normal.x;
result.c2 = plane.normal.y;
result.c3 = plane.normal.z;
result.a4 = plane.centre.x;
result.b4 = plane.centre.y;
result.c4 = plane.centre.z;
result.Inverse( );
return result;
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorP2T::TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const
{
for ( size_t i = 0; i < vertices.size( ); ++i )
{
PointP2T& point = vertices[ i ];
point.point3D = transform * point.point3D;
point.point2D.set( point.point3D.y, point.point3D.z );
}
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorP2T::ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const
{
pointRefs.resize( points.size( ) );
for ( size_t i = 0; i < points.size( ); ++i )
{
pointRefs[ i ] = &points[ i ].point2D;
}
}
// ------------------------------------------------------------------------------------------------
inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const
{
unsigned int pointOffset = offsetof( PointP2T, point2D );
PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
{
ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" );
}
return pointStruct;
}
// ------------------------------------------------------------------------------------------------
void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const
{
for ( size_t i = 0; i < triangles.size( ); ++i )
{
p2t::Triangle& Triangle = *triangles[ i ];
PointP2T& pointA = GetActualPointStructure( *Triangle.GetPoint( 0 ) );
PointP2T& pointB = GetActualPointStructure( *Triangle.GetPoint( 1 ) );
PointP2T& pointC = GetActualPointStructure( *Triangle.GetPoint( 2 ) );
converter->AddFace( pointA.index, pointB.index, pointC.index );
}
}
// ------------------------------------------------------------------------------------------------
inline float p2tMax( float a, float b )
{
return a > b ? a : b;
}
// ------------------------------------------------------------------------------------------------
// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
float BlenderTessellatorP2T::FindLargestMatrixElem( const aiMatrix3x3& mtx ) const
{
float result = 0.0f;
for ( size_t x = 0; x < 3; ++x )
{
for ( size_t y = 0; y < 3; ++y )
{
result = p2tMax( std::fabs( mtx[ x ][ y ] ), result );
}
}
return result;
}
// ------------------------------------------------------------------------------------------------
// Apparently Assimp doesn't have matrix scaling
aiMatrix3x3 BlenderTessellatorP2T::ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const
{
aiMatrix3x3 result;
for ( size_t x = 0; x < 3; ++x )
{
for ( size_t y = 0; y < 3; ++y )
{
result[ x ][ y ] = mtx[ x ][ y ] * scale;
}
}
return result;
}
// ------------------------------------------------------------------------------------------------
// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
aiVector3D BlenderTessellatorP2T::GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const
{
const float scale = FindLargestMatrixElem( mtx );
aiMatrix3x3 mc = ScaleMatrix( mtx, 1.0f / scale );
mc = mc * mc * mc;
aiVector3D v( 1.0f );
aiVector3D lastV = v;
for ( int i = 0; i < 100; ++i )
{
v = mc * v;
v.Normalize( );
if ( ( v - lastV ).SquareLength( ) < 1e-16f )
{
break;
}
lastV = v;
}
return v;
}
// ------------------------------------------------------------------------------------------------
// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
PlaneP2T BlenderTessellatorP2T::FindLLSQPlane( const std::vector< PointP2T >& points ) const
{
PlaneP2T result;
aiVector3D sum( 0.0f );
for ( size_t i = 0; i < points.size( ); ++i )
{
sum += points[ i ].point3D;
}
result.centre = sum * ( 1.0f / points.size( ) );
float sumXX = 0.0f;
float sumXY = 0.0f;
float sumXZ = 0.0f;
float sumYY = 0.0f;
float sumYZ = 0.0f;
float sumZZ = 0.0f;
for ( size_t i = 0; i < points.size( ); ++i )
{
aiVector3D offset = points[ i ].point3D - result.centre;
sumXX += offset.x * offset.x;
sumXY += offset.x * offset.y;
sumXZ += offset.x * offset.z;
sumYY += offset.y * offset.y;
sumYZ += offset.y * offset.z;
sumZZ += offset.z * offset.z;
}
aiMatrix3x3 mtx( sumXX, sumXY, sumXZ, sumXY, sumYY, sumYZ, sumXZ, sumYZ, sumZZ );
const float det = mtx.Determinant( );
if ( det == 0.0f )
{
result.normal = aiVector3D( 0.0f );
}
else
{
aiMatrix3x3 invMtx = mtx;
invMtx.Inverse( );
result.normal = GetEigenVectorFromLargestEigenValue( invMtx );
}
return result;
}
#endif // ASSIMP_BLEND_WITH_POLY_2_TRI
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

View file

@ -0,0 +1,208 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file BlenderTessellator.h
* @brief A simple tessellation wrapper
*/
#ifndef INCLUDED_AI_BLEND_TESSELLATOR_H
#define INCLUDED_AI_BLEND_TESSELLATOR_H
// Use these to toggle between GLU Tessellate or poly2tri
// Note (acg) keep GLU Tesselate disabled by default - if it is turned on,
// assimp needs to be linked against GLU, which is currently not yet
// made configurable in CMake and potentially not wanted by most users
// as it requires a Gl environment.
#ifndef ASSIMP_BLEND_WITH_GLU_TESSELLATE
# define ASSIMP_BLEND_WITH_GLU_TESSELLATE 0
#endif
#ifndef ASSIMP_BLEND_WITH_POLY_2_TRI
# define ASSIMP_BLEND_WITH_POLY_2_TRI 1
#endif
#include "LogAux.h"
#if ASSIMP_BLEND_WITH_GLU_TESSELLATE
#if defined( WIN32 ) || defined( _WIN32 ) || defined( _MSC_VER )
#include <windows.h>
#endif
#include <GL/glu.h>
namespace Assimp
{
class BlenderBMeshConverter;
// TinyFormatter.h
namespace Formatter
{
template < typename T,typename TR, typename A > class basic_formatter;
typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
}
// BlenderScene.h
namespace Blender
{
struct MLoop;
struct MVert;
struct VertexGL
{
GLdouble X;
GLdouble Y;
GLdouble Z;
int index;
int magic;
VertexGL( GLdouble X, GLdouble Y, GLdouble Z, int index, int magic ): X( X ), Y( Y ), Z( Z ), index( index ), magic( magic ) { }
};
struct DrawCallGL
{
GLenum drawMode;
int baseVertex;
int vertexCount;
DrawCallGL( GLenum drawMode, int baseVertex ): drawMode( drawMode ), baseVertex( baseVertex ), vertexCount( 0 ) { }
};
struct TessDataGL
{
std::vector< DrawCallGL > drawCalls;
std::vector< VertexGL > vertices;
};
}
class BlenderTessellatorGL: public LogFunctions< BlenderTessellatorGL >
{
public:
BlenderTessellatorGL( BlenderBMeshConverter& converter );
~BlenderTessellatorGL( );
void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
private:
void AssertVertexCount( int vertexCount );
void GenerateLoopVerts( std::vector< Blender::VertexGL >& polyLoopGL, const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
void Tesssellate( std::vector< Blender::VertexGL >& polyLoopGL, Blender::TessDataGL& tessData );
void TriangulateDrawCalls( const Blender::TessDataGL& tessData );
void MakeFacesFromTris( const Blender::VertexGL* vertices, int vertexCount );
void MakeFacesFromTriStrip( const Blender::VertexGL* vertices, int vertexCount );
void MakeFacesFromTriFan( const Blender::VertexGL* vertices, int vertexCount );
static void TessellateBegin( GLenum drawModeGL, void* userData );
static void TessellateEnd( void* userData );
static void TessellateVertex( const void* vtxData, void* userData );
static void TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData );
static void TessellateEdgeFlag( GLboolean edgeFlag, void* userData );
static void TessellateError( GLenum errorCode, void* userData );
BlenderBMeshConverter* converter;
};
} // end of namespace Assimp
#endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE
#if ASSIMP_BLEND_WITH_POLY_2_TRI
#include "../contrib/poly2tri/poly2tri/poly2tri.h"
namespace Assimp
{
class BlenderBMeshConverter;
// TinyFormatter.h
namespace Formatter
{
template < typename T,typename TR, typename A > class basic_formatter;
typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
}
// BlenderScene.h
namespace Blender
{
struct MLoop;
struct MVert;
struct PointP2T
{
aiVector3D point3D;
p2t::Point point2D;
int magic;
int index;
};
struct PlaneP2T
{
aiVector3D centre;
aiVector3D normal;
};
}
class BlenderTessellatorP2T: public LogFunctions< BlenderTessellatorP2T >
{
public:
BlenderTessellatorP2T( BlenderBMeshConverter& converter );
~BlenderTessellatorP2T( );
void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
private:
void AssertVertexCount( int vertexCount );
void Copy3DVertices( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices, std::vector< Blender::PointP2T >& targetVertices ) const;
aiMatrix4x4 GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const;
void TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const;
void ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const;
inline Blender::PointP2T& GetActualPointStructure( p2t::Point& point ) const;
void MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const;
// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
float FindLargestMatrixElem( const aiMatrix3x3& mtx ) const;
aiMatrix3x3 ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const;
aiVector3D GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const;
Blender::PlaneP2T FindLLSQPlane( const std::vector< Blender::PointP2T >& points ) const;
BlenderBMeshConverter* converter;
};
} // end of namespace Assimp
#endif // ASSIMP_BLEND_WITH_POLY_2_TRI
#endif // INCLUDED_AI_BLEND_TESSELLATOR_H

View file

@ -0,0 +1,336 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file Provides cheat implementations for IOSystem and IOStream to
* redirect exporter output to a blob chain.*/
#ifndef AI_BLOBIOSYSTEM_H_INCLUDED
#define AI_BLOBIOSYSTEM_H_INCLUDED
#include "./../include/assimp/IOStream.hpp"
#include "./../include/assimp/cexport.h"
#include "./../include/assimp/IOSystem.hpp"
#include "./../include/assimp/DefaultLogger.hpp"
#include <stdint.h>
#include <set>
#include <vector>
namespace Assimp {
class BlobIOSystem;
// --------------------------------------------------------------------------------------------
/** Redirect IOStream to a blob */
// --------------------------------------------------------------------------------------------
class BlobIOStream : public IOStream
{
public:
BlobIOStream(BlobIOSystem* creator, const std::string& file, size_t initial = 4096)
: buffer()
, cur_size()
, file_size()
, cursor()
, initial(initial)
, file(file)
, creator(creator)
{
}
virtual ~BlobIOStream();
public:
// -------------------------------------------------------------------
aiExportDataBlob* GetBlob()
{
aiExportDataBlob* blob = new aiExportDataBlob();
blob->size = file_size;
blob->data = buffer;
buffer = NULL;
return blob;
}
public:
// -------------------------------------------------------------------
virtual size_t Read( void *,
size_t,
size_t )
{
return 0;
}
// -------------------------------------------------------------------
virtual size_t Write(const void* pvBuffer,
size_t pSize,
size_t pCount)
{
pSize *= pCount;
if (cursor + pSize > cur_size) {
Grow(cursor + pSize);
}
memcpy(buffer+cursor, pvBuffer, pSize);
cursor += pSize;
file_size = std::max(file_size,cursor);
return pCount;
}
// -------------------------------------------------------------------
virtual aiReturn Seek(size_t pOffset,
aiOrigin pOrigin)
{
switch(pOrigin)
{
case aiOrigin_CUR:
cursor += pOffset;
break;
case aiOrigin_END:
cursor = file_size - pOffset;
break;
case aiOrigin_SET:
cursor = pOffset;
break;
default:
return AI_FAILURE;
}
if (cursor > file_size) {
Grow(cursor);
}
file_size = std::max(cursor,file_size);
return AI_SUCCESS;
}
// -------------------------------------------------------------------
virtual size_t Tell() const
{
return cursor;
}
// -------------------------------------------------------------------
virtual size_t FileSize() const
{
return file_size;
}
// -------------------------------------------------------------------
virtual void Flush()
{
// ignore
}
private:
// -------------------------------------------------------------------
void Grow(size_t need = 0)
{
// 1.5 and phi are very heap-friendly growth factors (the first
// allows for frequent re-use of heap blocks, the second
// forms a fibonacci sequence with similar characteristics -
// since this heavily depends on the heap implementation
// and other factors as well, i'll just go with 1.5 since
// it is quicker to compute).
size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
const uint8_t* const old = buffer;
buffer = new uint8_t[new_size];
if (old) {
memcpy(buffer,old,cur_size);
delete[] old;
}
cur_size = new_size;
}
private:
uint8_t* buffer;
size_t cur_size,file_size, cursor, initial;
const std::string file;
BlobIOSystem* const creator;
};
#define AI_BLOBIO_MAGIC "$blobfile"
// --------------------------------------------------------------------------------------------
/** Redirect IOSystem to a blob */
// --------------------------------------------------------------------------------------------
class BlobIOSystem : public IOSystem
{
friend class BlobIOStream;
typedef std::pair<std::string, aiExportDataBlob*> BlobEntry;
public:
BlobIOSystem()
{
}
virtual ~BlobIOSystem()
{
for(BlobEntry& blobby : blobs) {
delete blobby.second;
}
}
public:
// -------------------------------------------------------------------
const char* GetMagicFileName() const
{
return AI_BLOBIO_MAGIC;
}
// -------------------------------------------------------------------
aiExportDataBlob* GetBlobChain()
{
// one must be the master
aiExportDataBlob* master = NULL, *cur;
for(const BlobEntry& blobby : blobs) {
if (blobby.first == AI_BLOBIO_MAGIC) {
master = blobby.second;
break;
}
}
if (!master) {
DefaultLogger::get()->error("BlobIOSystem: no data written or master file was not closed properly.");
return NULL;
}
master->name.Set("");
cur = master;
for(const BlobEntry& blobby : blobs) {
if (blobby.second == master) {
continue;
}
cur->next = blobby.second;
cur = cur->next;
// extract the file extension from the file written
const std::string::size_type s = blobby.first.find_first_of('.');
cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s+1));
}
// give up blob ownership
blobs.clear();
return master;
}
public:
// -------------------------------------------------------------------
virtual bool Exists( const char* pFile) const {
return created.find(std::string(pFile)) != created.end();
}
// -------------------------------------------------------------------
virtual char getOsSeparator() const {
return '/';
}
// -------------------------------------------------------------------
virtual IOStream* Open(const char* pFile,
const char* pMode)
{
if (pMode[0] != 'w') {
return NULL;
}
created.insert(std::string(pFile));
return new BlobIOStream(this,std::string(pFile));
}
// -------------------------------------------------------------------
virtual void Close( IOStream* pFile)
{
delete pFile;
}
private:
// -------------------------------------------------------------------
void OnDestruct(const std::string& filename, BlobIOStream* child)
{
// we don't know in which the files are closed, so we
// can't reliably say that the first must be the master
// file ...
blobs.push_back( BlobEntry(filename,child->GetBlob()) );
}
private:
std::set<std::string> created;
std::vector< BlobEntry > blobs;
};
// --------------------------------------------------------------------------------------------
BlobIOStream :: ~BlobIOStream()
{
creator->OnDestruct(file,this);
delete[] buffer;
}
} // end Assimp
#endif

View file

@ -0,0 +1,286 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file Helper class tp perform various byte oder swappings
(e.g. little to big endian) */
#ifndef AI_BYTESWAPPER_H_INC
#define AI_BYTESWAPPER_H_INC
#include <assimp/ai_assert.h>
#include <assimp/types.h>
#include <stdint.h>
#if _MSC_VER >= 1400
#include <stdlib.h>
#endif
namespace Assimp {
// --------------------------------------------------------------------------------------
/** Defines some useful byte order swap routines.
*
* This is required to read big-endian model formats on little-endian machines,
* and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */
// --------------------------------------------------------------------------------------
class ByteSwap
{
ByteSwap() {}
public:
// ----------------------------------------------------------------------
/** Swap two bytes of data
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
static inline void Swap2(void* _szOut)
{
ai_assert(_szOut);
#if _MSC_VER >= 1400
uint16_t* const szOut = reinterpret_cast<uint16_t*>(_szOut);
*szOut = _byteswap_ushort(*szOut);
#else
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
std::swap(szOut[0],szOut[1]);
#endif
}
// ----------------------------------------------------------------------
/** Swap four bytes of data
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
static inline void Swap4(void* _szOut)
{
ai_assert(_szOut);
#if _MSC_VER >= 1400
uint32_t* const szOut = reinterpret_cast<uint32_t*>(_szOut);
*szOut = _byteswap_ulong(*szOut);
#else
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
std::swap(szOut[0],szOut[3]);
std::swap(szOut[1],szOut[2]);
#endif
}
// ----------------------------------------------------------------------
/** Swap eight bytes of data
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
static inline void Swap8(void* _szOut)
{
ai_assert(_szOut);
#if _MSC_VER >= 1400
uint64_t* const szOut = reinterpret_cast<uint64_t*>(_szOut);
*szOut = _byteswap_uint64(*szOut);
#else
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
std::swap(szOut[0],szOut[7]);
std::swap(szOut[1],szOut[6]);
std::swap(szOut[2],szOut[5]);
std::swap(szOut[3],szOut[4]);
#endif
}
// ----------------------------------------------------------------------
/** ByteSwap a float. Not a joke.
* @param[inout] fOut ehm. .. */
static inline void Swap(float* fOut) {
Swap4(fOut);
}
// ----------------------------------------------------------------------
/** ByteSwap a double. Not a joke.
* @param[inout] fOut ehm. .. */
static inline void Swap(double* fOut) {
Swap8(fOut);
}
// ----------------------------------------------------------------------
/** ByteSwap an int16t. Not a joke.
* @param[inout] fOut ehm. .. */
static inline void Swap(int16_t* fOut) {
Swap2(fOut);
}
static inline void Swap(uint16_t* fOut) {
Swap2(fOut);
}
// ----------------------------------------------------------------------
/** ByteSwap an int32t. Not a joke.
* @param[inout] fOut ehm. .. */
static inline void Swap(int32_t* fOut){
Swap4(fOut);
}
static inline void Swap(uint32_t* fOut){
Swap4(fOut);
}
// ----------------------------------------------------------------------
/** ByteSwap an int64t. Not a joke.
* @param[inout] fOut ehm. .. */
static inline void Swap(int64_t* fOut) {
Swap8(fOut);
}
static inline void Swap(uint64_t* fOut) {
Swap8(fOut);
}
// ----------------------------------------------------------------------
//! Templatized ByteSwap
//! \returns param tOut as swapped
template<typename Type>
static inline Type Swapped(Type tOut)
{
return _swapper<Type,sizeof(Type)>()(tOut);
}
private:
template <typename T, size_t size> struct _swapper;
};
template <typename T> struct ByteSwap::_swapper<T,2> {
T operator() (T tOut) {
Swap2(&tOut);
return tOut;
}
};
template <typename T> struct ByteSwap::_swapper<T,4> {
T operator() (T tOut) {
Swap4(&tOut);
return tOut;
}
};
template <typename T> struct ByteSwap::_swapper<T,8> {
T operator() (T tOut) {
Swap8(&tOut);
return tOut;
}
};
// --------------------------------------------------------------------------------------
// ByteSwap macros for BigEndian/LittleEndian support
// --------------------------------------------------------------------------------------
#if (defined AI_BUILD_BIG_ENDIAN)
# define AI_LE(t) (t)
# define AI_BE(t) ByteSwap::Swapped(t)
# define AI_LSWAP2(p)
# define AI_LSWAP4(p)
# define AI_LSWAP8(p)
# define AI_LSWAP2P(p)
# define AI_LSWAP4P(p)
# define AI_LSWAP8P(p)
# define LE_NCONST const
# define AI_SWAP2(p) ByteSwap::Swap2(&(p))
# define AI_SWAP4(p) ByteSwap::Swap4(&(p))
# define AI_SWAP8(p) ByteSwap::Swap8(&(p))
# define AI_SWAP2P(p) ByteSwap::Swap2((p))
# define AI_SWAP4P(p) ByteSwap::Swap4((p))
# define AI_SWAP8P(p) ByteSwap::Swap8((p))
# define BE_NCONST
#else
# define AI_BE(t) (t)
# define AI_LE(t) ByteSwap::Swapped(t)
# define AI_SWAP2(p)
# define AI_SWAP4(p)
# define AI_SWAP8(p)
# define AI_SWAP2P(p)
# define AI_SWAP4P(p)
# define AI_SWAP8P(p)
# define BE_NCONST const
# define AI_LSWAP2(p) ByteSwap::Swap2(&(p))
# define AI_LSWAP4(p) ByteSwap::Swap4(&(p))
# define AI_LSWAP8(p) ByteSwap::Swap8(&(p))
# define AI_LSWAP2P(p) ByteSwap::Swap2((p))
# define AI_LSWAP4P(p) ByteSwap::Swap4((p))
# define AI_LSWAP8P(p) ByteSwap::Swap8((p))
# define LE_NCONST
#endif
namespace Intern {
// --------------------------------------------------------------------------------------------
template <typename T, bool doit>
struct ByteSwapper {
void operator() (T* inout) {
ByteSwap::Swap(inout);
}
};
template <typename T>
struct ByteSwapper<T,false> {
void operator() (T*) {
}
};
// --------------------------------------------------------------------------------------------
template <bool SwapEndianess, typename T, bool RuntimeSwitch>
struct Getter {
void operator() (T* inout, bool le) {
#ifdef AI_BUILD_BIG_ENDIAN
le = le;
#else
le = !le;
#endif
if (le) {
ByteSwapper<T,(sizeof(T)>1?true:false)> () (inout);
}
else ByteSwapper<T,false> () (inout);
}
};
template <bool SwapEndianess, typename T>
struct Getter<SwapEndianess,T,false> {
void operator() (T* inout, bool /*le*/) {
// static branch
ByteSwapper<T,(SwapEndianess && sizeof(T)>1)> () (inout);
}
};
} // end Intern
} // end Assimp
#endif //!! AI_BYTESWAPPER_H_INC

View file

@ -0,0 +1,650 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2012, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file C4DImporter.cpp
* @brief Implementation of the Cinema4D importer class.
*/
#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
// no #ifdefing here, Cinema4D support is carried out in a branch of assimp
// where it is turned on in the CMake settings.
#ifndef _MSC_VER
# error C4D support is currently MSVC only
#endif
#include "C4DImporter.h"
#include "TinyFormatter.h"
#include <memory>
#include <assimp/IOSystem.hpp>
#include <assimp/scene.h>
#include <assimp/ai_assert.h>
#if defined(_M_X64) || defined(__amd64__)
# define __C4D_64BIT
#endif
#define __PC
#include "c4d_file.h"
#include "default_alien_overloads.h"
using namespace melange;
// overload this function and fill in your own unique data
void GetWriterInfo(int &id, String &appname)
{
id = 2424226;
appname = "Open Asset Import Library";
}
using namespace Assimp;
using namespace Assimp::Formatter;
namespace Assimp {
template<> const std::string LogFunctions<C4DImporter>::log_prefix = "C4D: ";
}
static const aiImporterDesc desc = {
"Cinema4D Importer",
"",
"",
"",
aiImporterFlags_SupportBinaryFlavour,
0,
0,
0,
0,
"c4d"
};
// ------------------------------------------------------------------------------------------------
C4DImporter::C4DImporter()
{}
// ------------------------------------------------------------------------------------------------
C4DImporter::~C4DImporter()
{}
// ------------------------------------------------------------------------------------------------
bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
{
const std::string& extension = GetExtension(pFile);
if (extension == "c4d") {
return true;
}
else if ((!extension.length() || checkSig) && pIOHandler) {
// TODO
}
return false;
}
// ------------------------------------------------------------------------------------------------
const aiImporterDesc* C4DImporter::GetInfo () const
{
return &desc;
}
// ------------------------------------------------------------------------------------------------
void C4DImporter::SetupProperties(const Importer* /*pImp*/)
{
// nothing to be done for the moment
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void C4DImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler)
{
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
if( file.get() == NULL) {
ThrowException("failed to open file " + pFile);
}
const size_t file_size = file->FileSize();
std::vector<uint8_t> mBuffer(file_size);
file->Read(&mBuffer[0], 1, file_size);
Filename f;
f.SetMemoryReadMode(&mBuffer[0], file_size);
// open document first
BaseDocument* doc = LoadDocument(f, SCENEFILTER_OBJECTS | SCENEFILTER_MATERIALS);
if(doc == NULL) {
ThrowException("failed to read document " + pFile);
}
pScene->mRootNode = new aiNode("<C4DRoot>");
// first convert all materials
ReadMaterials(doc->GetFirstMaterial());
// process C4D scenegraph recursively
try {
RecurseHierarchy(doc->GetFirstObject(), pScene->mRootNode);
}
catch(...) {
for(aiMesh* mesh : meshes) {
delete mesh;
}
BaseDocument::Free(doc);
throw;
}
BaseDocument::Free(doc);
// copy meshes over
pScene->mNumMeshes = static_cast<unsigned int>(meshes.size());
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]();
std::copy(meshes.begin(), meshes.end(), pScene->mMeshes);
// copy materials over, adding a default material if necessary
unsigned int mat_count = static_cast<unsigned int>(materials.size());
for(aiMesh* mesh : meshes) {
ai_assert(mesh->mMaterialIndex <= mat_count);
if(mesh->mMaterialIndex >= mat_count) {
++mat_count;
ScopeGuard<aiMaterial> def_material(new aiMaterial());
const aiString name(AI_DEFAULT_MATERIAL_NAME);
def_material->AddProperty(&name, AI_MATKEY_NAME);
materials.push_back(def_material.dismiss());
break;
}
}
pScene->mNumMaterials = static_cast<unsigned int>(materials.size());
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]();
std::copy(materials.begin(), materials.end(), pScene->mMaterials);
}
// ------------------------------------------------------------------------------------------------
bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader)
{
// based on Melange sample code (C4DImportExport.cpp)
while(shader) {
if(shader->GetType() == Xlayer) {
BaseContainer* container = shader->GetDataInstance();
GeData blend = container->GetData(SLA_LAYER_BLEND);
iBlendDataType* blend_list = reinterpret_cast<iBlendDataType*>(blend.GetCustomDataType(CUSTOMDATA_BLEND_LIST));
if (!blend_list)
{
LogWarn("ignoring XLayer shader: no blend list given");
continue;
}
LayerShaderLayer *lsl = dynamic_cast<LayerShaderLayer*>(blend_list->m_BlendLayers.GetObject(0));
// Ignore the actual layer blending - models for real-time rendering should not
// use them in a non-trivial way. Just try to find textures that we can apply
// to the model.
while (lsl)
{
if (lsl->GetType() == TypeFolder)
{
BlendFolder* const folder = dynamic_cast<BlendFolder*>(lsl);
LayerShaderLayer *subLsl = dynamic_cast<LayerShaderLayer*>(folder->m_Children.GetObject(0));
while (subLsl)
{
if (subLsl->GetType() == TypeShader) {
BlendShader* const shader = dynamic_cast<BlendShader*>(subLsl);
if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
return true;
}
}
subLsl = subLsl->GetNext();
}
}
else if (lsl->GetType() == TypeShader) {
BlendShader* const shader = dynamic_cast<BlendShader*>(lsl);
if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
return true;
}
}
lsl = lsl->GetNext();
}
}
else if ( shader->GetType() == Xbitmap )
{
aiString path;
shader->GetFileName().GetString().GetCString(path.data, MAXLEN-1);
path.length = ::strlen(path.data);
out->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
return true;
}
else {
LogWarn("ignoring shader type: " + std::string(GetObjectTypeName(shader->GetType())));
}
shader = shader->GetNext();
}
return false;
}
// ------------------------------------------------------------------------------------------------
void C4DImporter::ReadMaterials(melange::BaseMaterial* mat)
{
// based on Melange sample code
while (mat)
{
const String& name = mat->GetName();
if (mat->GetType() == Mmaterial)
{
aiMaterial* out = new aiMaterial();
material_mapping[mat] = static_cast<unsigned int>(materials.size());
materials.push_back(out);
aiString ai_name;
name.GetCString(ai_name.data, MAXLEN-1);
ai_name.length = ::strlen(ai_name.data);
out->AddProperty(&ai_name, AI_MATKEY_NAME);
Material& m = dynamic_cast<Material&>(*mat);
if (m.GetChannelState(CHANNEL_COLOR))
{
GeData data;
mat->GetParameter(MATERIAL_COLOR_COLOR, data);
Vector color = data.GetVector();
mat->GetParameter(MATERIAL_COLOR_BRIGHTNESS, data);
const Float brightness = data.GetFloat();
color *= brightness;
aiVector3D v;
v.x = color.x;
v.y = color.y;
v.z = color.z;
out->AddProperty(&v, 1, AI_MATKEY_COLOR_DIFFUSE);
}
BaseShader* const shader = m.GetShader(MATERIAL_COLOR_SHADER);
if(shader) {
ReadShader(out, shader);
}
}
else
{
LogWarn("ignoring plugin material: " + std::string(GetObjectTypeName(mat->GetType())));
}
mat = mat->GetNext();
}
}
// ------------------------------------------------------------------------------------------------
void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent)
{
ai_assert(parent != NULL);
std::vector<aiNode*> nodes;
// based on Melange sample code
while (object)
{
const String& name = object->GetName();
const LONG type = object->GetType();
const Matrix& ml = object->GetMl();
aiString string;
name.GetCString(string.data, MAXLEN-1);
string.length = ::strlen(string.data);
aiNode* const nd = new aiNode();
nd->mParent = parent;
nd->mName = string;
nd->mTransformation.a1 = ml.v1.x;
nd->mTransformation.b1 = ml.v1.y;
nd->mTransformation.c1 = ml.v1.z;
nd->mTransformation.a2 = ml.v2.x;
nd->mTransformation.b2 = ml.v2.y;
nd->mTransformation.c2 = ml.v2.z;
nd->mTransformation.a3 = ml.v3.x;
nd->mTransformation.b3 = ml.v3.y;
nd->mTransformation.c3 = ml.v3.z;
nd->mTransformation.a4 = ml.off.x;
nd->mTransformation.b4 = ml.off.y;
nd->mTransformation.c4 = ml.off.z;
nodes.push_back(nd);
GeData data;
if (type == Ocamera)
{
object->GetParameter(CAMERAOBJECT_FOV, data);
// TODO: read camera
}
else if (type == Olight)
{
// TODO: read light
}
else if (type == Opolygon)
{
aiMesh* const mesh = ReadMesh(object);
if(mesh != NULL) {
nd->mNumMeshes = 1;
nd->mMeshes = new unsigned int[1];
nd->mMeshes[0] = static_cast<unsigned int>(meshes.size());
meshes.push_back(mesh);
}
}
else {
LogWarn("ignoring object: " + std::string(GetObjectTypeName(type)));
}
RecurseHierarchy(object->GetDown(), nd);
object = object->GetNext();
}
// copy nodes over to parent
parent->mNumChildren = static_cast<unsigned int>(nodes.size());
parent->mChildren = new aiNode*[parent->mNumChildren]();
std::copy(nodes.begin(), nodes.end(), parent->mChildren);
}
// ------------------------------------------------------------------------------------------------
aiMesh* C4DImporter::ReadMesh(BaseObject* object)
{
assert(object != NULL && object->GetType() == Opolygon);
// based on Melange sample code
PolygonObject* const polyObject = dynamic_cast<PolygonObject*>(object);
ai_assert(polyObject != NULL);
const LONG pointCount = polyObject->GetPointCount();
const LONG polyCount = polyObject->GetPolygonCount();
if(!polyObject || !pointCount) {
LogWarn("ignoring mesh with zero vertices or faces");
return NULL;
}
const Vector* points = polyObject->GetPointR();
ai_assert(points != NULL);
const CPolygon* polys = polyObject->GetPolygonR();
ai_assert(polys != NULL);
ScopeGuard<aiMesh> mesh(new aiMesh());
mesh->mNumFaces = static_cast<unsigned int>(polyCount);
aiFace* face = mesh->mFaces = new aiFace[mesh->mNumFaces]();
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
mesh->mMaterialIndex = 0;
unsigned int vcount = 0;
// first count vertices
for (LONG i = 0; i < polyCount; i++)
{
vcount += 3;
// TODO: do we also need to handle lines or points with similar checks?
if (polys[i].c != polys[i].d)
{
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
++vcount;
}
}
ai_assert(vcount > 0);
mesh->mNumVertices = vcount;
aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
aiVector3D* normals, *uvs, *tangents, *bitangents;
unsigned int n = 0;
// check if there are normals, tangents or UVW coordinates
BaseTag* tag = object->GetTag(Tnormal);
NormalTag* normals_src = NULL;
if(tag) {
normals_src = dynamic_cast<NormalTag*>(tag);
normals = mesh->mNormals = new aiVector3D[mesh->mNumVertices]();
}
tag = object->GetTag(Ttangent);
TangentTag* tangents_src = NULL;
if(tag) {
tangents_src = dynamic_cast<TangentTag*>(tag);
tangents = mesh->mTangents = new aiVector3D[mesh->mNumVertices]();
bitangents = mesh->mBitangents = new aiVector3D[mesh->mNumVertices]();
}
tag = object->GetTag(Tuvw);
UVWTag* uvs_src = NULL;
if(tag) {
uvs_src = dynamic_cast<UVWTag*>(tag);
uvs = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]();
}
// copy vertices and extra channels over and populate faces
for (LONG i = 0; i < polyCount; ++i, ++face)
{
ai_assert(polys[i].a < pointCount && polys[i].a >= 0);
const Vector& pointA = points[polys[i].a];
verts->x = pointA.x;
verts->y = pointA.y;
verts->z = pointA.z;
++verts;
ai_assert(polys[i].b < pointCount && polys[i].b >= 0);
const Vector& pointB = points[polys[i].b];
verts->x = pointB.x;
verts->y = pointB.y;
verts->z = pointB.z;
++verts;
ai_assert(polys[i].c < pointCount && polys[i].c >= 0);
const Vector& pointC = points[polys[i].c];
verts->x = pointC.x;
verts->y = pointC.y;
verts->z = pointC.z;
++verts;
// TODO: do we also need to handle lines or points with similar checks?
if (polys[i].c != polys[i].d)
{
ai_assert(polys[i].d < pointCount && polys[i].d >= 0);
face->mNumIndices = 4;
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
const Vector& pointD = points[polys[i].d];
verts->x = pointD.x;
verts->y = pointD.y;
verts->z = pointD.z;
++verts;
}
else {
face->mNumIndices = 3;
}
face->mIndices = new unsigned int[face->mNumIndices];
for(unsigned int j = 0; j < face->mNumIndices; ++j) {
face->mIndices[j] = n++;
}
// copy normals
if (normals_src) {
if(i >= normals_src->GetDataCount()) {
LogError("unexpected number of normals, ignoring");
}
else {
ConstNormalHandle normal_handle = normals_src->GetDataAddressR();
NormalStruct nor;
NormalTag::Get(normal_handle, i, nor);
normals->x = nor.a.x;
normals->y = nor.a.y;
normals->z = nor.a.z;
++normals;
normals->x = nor.b.x;
normals->y = nor.b.y;
normals->z = nor.b.z;
++normals;
normals->x = nor.c.x;
normals->y = nor.c.y;
normals->z = nor.c.z;
++normals;
if(face->mNumIndices == 4) {
normals->x = nor.d.x;
normals->y = nor.d.y;
normals->z = nor.d.z;
++normals;
}
}
}
// copy tangents and bitangents
if (tangents_src) {
for(unsigned int k = 0; k < face->mNumIndices; ++k) {
LONG l;
switch(k) {
case 0:
l = polys[i].a;
break;
case 1:
l = polys[i].b;
break;
case 2:
l = polys[i].c;
break;
case 3:
l = polys[i].d;
break;
default:
ai_assert(false);
}
if(l >= tangents_src->GetDataCount()) {
LogError("unexpected number of tangents, ignoring");
break;
}
Tangent tan = tangents_src->GetDataR()[l];
tangents->x = tan.vl.x;
tangents->y = tan.vl.y;
tangents->z = tan.vl.z;
++tangents;
bitangents->x = tan.vr.x;
bitangents->y = tan.vr.y;
bitangents->z = tan.vr.z;
++bitangents;
}
}
// copy UVs
if (uvs_src) {
if(i >= uvs_src->GetDataCount()) {
LogError("unexpected number of UV coordinates, ignoring");
}
else {
UVWStruct uvw;
uvs_src->Get(uvs_src->GetDataAddressR(),i,uvw);
uvs->x = uvw.a.x;
uvs->y = 1.0f-uvw.a.y;
uvs->z = uvw.a.z;
++uvs;
uvs->x = uvw.b.x;
uvs->y = 1.0f-uvw.b.y;
uvs->z = uvw.b.z;
++uvs;
uvs->x = uvw.c.x;
uvs->y = 1.0f-uvw.c.y;
uvs->z = uvw.c.z;
++uvs;
if(face->mNumIndices == 4) {
uvs->x = uvw.d.x;
uvs->y = 1.0f-uvw.d.y;
uvs->z = uvw.d.z;
++uvs;
}
}
}
}
mesh->mMaterialIndex = ResolveMaterial(polyObject);
return mesh.dismiss();
}
// ------------------------------------------------------------------------------------------------
unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj)
{
ai_assert(obj != NULL);
const unsigned int mat_count = static_cast<unsigned int>(materials.size());
BaseTag* tag = obj->GetTag(Ttexture);
if(tag == NULL) {
return mat_count;
}
TextureTag& ttag = dynamic_cast<TextureTag&>(*tag);
BaseMaterial* const mat = ttag.GetMaterial();
assert(mat != NULL);
const MaterialMap::const_iterator it = material_mapping.find(mat);
if(it == material_mapping.end()) {
return mat_count;
}
ai_assert((*it).second < mat_count);
return (*it).second;
}
#endif // ASSIMP_BUILD_NO_C4D_IMPORTER

View file

@ -0,0 +1,123 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2012, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file C4DImporter.h
* @brief Declaration of the Cinema4D (*.c4d) importer class.
*/
#ifndef INCLUDED_AI_CINEMA_4D_LOADER_H
#define INCLUDED_AI_CINEMA_4D_LOADER_H
#include "BaseImporter.h"
#include "LogAux.h"
#include <set>
struct aiNode;
struct aiMesh;
struct aiMaterial;
struct aiImporterDesc;
namespace melange {
class BaseObject; // c4d_file.h
class PolygonObject;
class BaseMaterial;
class BaseShader;
}
namespace Assimp {
// TinyFormatter.h
namespace Formatter {
template <typename T,typename TR, typename A> class basic_formatter;
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
}
// -------------------------------------------------------------------------------------------
/** Importer class to load Cinema4D files using the Melange library to be obtained from
* www.plugincafe.com
*
* Note that Melange is not free software. */
// -------------------------------------------------------------------------------------------
class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter>
{
public:
C4DImporter();
~C4DImporter();
public:
// --------------------
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
protected:
// --------------------
const aiImporterDesc* GetInfo () const;
// --------------------
void SetupProperties(const Importer* pImp);
// --------------------
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
private:
void ReadMaterials(melange::BaseMaterial* mat);
void RecurseHierarchy(melange::BaseObject* object, aiNode* parent);
aiMesh* ReadMesh(melange::BaseObject* object);
unsigned int ResolveMaterial(melange::PolygonObject* obj);
bool ReadShader(aiMaterial* out, melange::BaseShader* shader);
std::vector<aiMesh*> meshes;
std::vector<aiMaterial*> materials;
typedef std::map<melange::BaseMaterial*, unsigned int> MaterialMap;
MaterialMap material_mapping;
}; // !class C4DImporter
} // end of namespace Assimp
#endif // INCLUDED_AI_CINEMA_4D_LOADER_H

View file

@ -0,0 +1,160 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file aiFileIO -> IOSystem wrapper*/
#ifndef AI_CIOSYSTEM_H_INCLUDED
#define AI_CIOSYSTEM_H_INCLUDED
#include <assimp/cfileio.h>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
namespace Assimp {
// ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API
class CIOStreamWrapper : public IOStream
{
friend class CIOSystemWrapper;
public:
explicit CIOStreamWrapper(aiFile* pFile)
: mFile(pFile)
{}
// ...................................................................
size_t Read(void* pvBuffer,
size_t pSize,
size_t pCount
){
// need to typecast here as C has no void*
return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount);
}
// ...................................................................
size_t Write(const void* pvBuffer,
size_t pSize,
size_t pCount
){
// need to typecast here as C has no void*
return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount);
}
// ...................................................................
aiReturn Seek(size_t pOffset,
aiOrigin pOrigin
){
return mFile->SeekProc(mFile,pOffset,pOrigin);
}
// ...................................................................
size_t Tell(void) const {
return mFile->TellProc(mFile);
}
// ...................................................................
size_t FileSize() const {
return mFile->FileSizeProc(mFile);
}
// ...................................................................
void Flush () {
return mFile->FlushProc(mFile);
}
private:
aiFile* mFile;
};
// ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API
class CIOSystemWrapper : public IOSystem
{
public:
explicit CIOSystemWrapper(aiFileIO* pFile)
: mFileSystem(pFile)
{}
// ...................................................................
bool Exists( const char* pFile) const {
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,"rb");
if (p){
mFileSystem->CloseProc(mFileSystem,p);
return true;
}
return false;
}
// ...................................................................
char getOsSeparator() const {
#ifndef _WIN32
return '/';
#else
return '\\';
#endif
}
// ...................................................................
IOStream* Open(const char* pFile,const char* pMode = "rb") {
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode);
if (!p) {
return NULL;
}
return new CIOStreamWrapper(p);
}
// ...................................................................
void Close( IOStream* pFile) {
if (!pFile) {
return;
}
mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile);
delete pFile;
}
private:
aiFileIO* mFileSystem;
};
}
#endif

View file

@ -0,0 +1,846 @@
# Open Asset Import Library (assimp)
# ----------------------------------------------------------------------
#
# Copyright (c) 2006-2016, assimp 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 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.
#
#----------------------------------------------------------------------
# Listing and grouping of all the source files.
# 1) Set the file lists for each component
# 2) Create a Source Group for each component, for IDE project orginization
# 3) Add libassimp using the file lists (eliminates duplication of file names between
# source groups and library command)
#
cmake_minimum_required( VERSION 2.6 )
SET( HEADER_PATH ../include/assimp )
SET( COMPILER_HEADERS
${HEADER_PATH}/Compiler/pushpack1.h
${HEADER_PATH}/Compiler/poppack1.h
${HEADER_PATH}/Compiler/pstdint.h
)
SOURCE_GROUP( Compiler FILES ${COMPILER_HEADERS})
SET( PUBLIC_HEADERS
${HEADER_PATH}/anim.h
${HEADER_PATH}/ai_assert.h
${HEADER_PATH}/camera.h
${HEADER_PATH}/color4.h
${HEADER_PATH}/color4.inl
${HEADER_PATH}/config.h
${HEADER_PATH}/defs.h
${HEADER_PATH}/cfileio.h
${HEADER_PATH}/light.h
${HEADER_PATH}/material.h
${HEADER_PATH}/material.inl
${HEADER_PATH}/matrix3x3.h
${HEADER_PATH}/matrix3x3.inl
${HEADER_PATH}/matrix4x4.h
${HEADER_PATH}/matrix4x4.inl
${HEADER_PATH}/mesh.h
${HEADER_PATH}/postprocess.h
${HEADER_PATH}/quaternion.h
${HEADER_PATH}/quaternion.inl
${HEADER_PATH}/scene.h
${HEADER_PATH}/metadata.h
${HEADER_PATH}/texture.h
${HEADER_PATH}/types.h
${HEADER_PATH}/vector2.h
${HEADER_PATH}/vector2.inl
${HEADER_PATH}/vector3.h
${HEADER_PATH}/vector3.inl
${HEADER_PATH}/version.h
${HEADER_PATH}/cimport.h
${HEADER_PATH}/importerdesc.h
${HEADER_PATH}/Importer.hpp
${HEADER_PATH}/DefaultLogger.hpp
${HEADER_PATH}/ProgressHandler.hpp
${HEADER_PATH}/IOStream.hpp
${HEADER_PATH}/IOSystem.hpp
${HEADER_PATH}/Logger.hpp
${HEADER_PATH}/LogStream.hpp
${HEADER_PATH}/NullLogger.hpp
${HEADER_PATH}/cexport.h
${HEADER_PATH}/Exporter.hpp
)
SET( Core_SRCS
Assimp.cpp
)
SET( Logging_SRCS
${HEADER_PATH}/DefaultLogger.hpp
${HEADER_PATH}/LogStream.hpp
${HEADER_PATH}/Logger.hpp
${HEADER_PATH}/NullLogger.hpp
Win32DebugLogStream.h
DefaultLogger.cpp
FileLogStream.h
StdOStreamLogStream.h
)
SOURCE_GROUP(Logging FILES ${Logging_SRCS})
SET( Common_SRCS
fast_atof.h
qnan.h
BaseImporter.cpp
BaseImporter.h
BaseProcess.cpp
BaseProcess.h
Importer.h
ScenePrivate.h
PostStepRegistry.cpp
ImporterRegistry.cpp
ByteSwapper.h
DefaultProgressHandler.h
DefaultIOStream.cpp
DefaultIOStream.h
DefaultIOSystem.cpp
DefaultIOSystem.h
CInterfaceIOWrapper.h
Hash.h
Importer.cpp
IFF.h
MemoryIOWrapper.h
ParsingUtils.h
StreamReader.h
StreamWriter.h
StringComparison.h
StringUtils.h
SGSpatialSort.cpp
SGSpatialSort.h
VertexTriangleAdjacency.cpp
VertexTriangleAdjacency.h
GenericProperty.h
SpatialSort.cpp
SpatialSort.h
SceneCombiner.cpp
SceneCombiner.h
ScenePreprocessor.cpp
ScenePreprocessor.h
SkeletonMeshBuilder.cpp
SkeletonMeshBuilder.h
SplitByBoneCountProcess.cpp
SplitByBoneCountProcess.h
SmoothingGroups.h
StandardShapes.cpp
StandardShapes.h
TargetAnimation.cpp
TargetAnimation.h
RemoveComments.cpp
RemoveComments.h
Subdivision.cpp
Subdivision.h
Vertex.h
LineSplitter.h
TinyFormatter.h
Profiler.h
LogAux.h
Bitmap.cpp
Bitmap.h
XMLTools.h
Version.cpp
)
SOURCE_GROUP(Common FILES ${Common_SRCS})
IF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER )
SET( C4D_SRCS
C4DImporter.cpp
C4DImporter.h
)
SOURCE_GROUP( C4D FILES ${C4D_SRCS})
ENDIF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER )
# macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader
# this way selective loaders can be compiled (reduces filesize + compile time)
MACRO(ADD_ASSIMP_IMPORTER name)
OPTION(ASSIMP_BUILD_${name}_IMPORTER "build the ${name} importer" TRUE)
IF(ASSIMP_BUILD_${name}_IMPORTER)
LIST(APPEND ASSIMP_LOADER_SRCS ${ARGN})
SET(ASSIMP_IMPORTERS_ENABLED "${ASSIMP_IMPORTERS_ENABLED} ${name}")
SET(${name}_SRCS ${ARGN})
SOURCE_GROUP(${name} FILES ${ARGN})
ELSE()
SET(${name}_SRC "")
SET(ASSIMP_IMPORTERS_DISABLED "${ASSIMP_IMPORTERS_DISABLED} ${name}")
add_definitions(-DASSIMP_BUILD_NO_${name}_IMPORTER)
ENDIF()
ENDMACRO()
SET(ASSIMP_LOADER_SRCS "")
SET(ASSIMP_IMPORTERS_ENABLED "") # list of enabled importers
SET(ASSIMP_IMPORTERS_DISABLED "") # disabled list (used to print)
ADD_ASSIMP_IMPORTER( 3DS
3DSConverter.cpp
3DSHelper.h
3DSLoader.cpp
3DSLoader.h
3DSExporter.h
3DSExporter.cpp
)
ADD_ASSIMP_IMPORTER( AC
ACLoader.cpp
ACLoader.h
)
ADD_ASSIMP_IMPORTER( ASE
ASELoader.cpp
ASELoader.h
ASEParser.cpp
ASEParser.h
)
ADD_ASSIMP_IMPORTER( ASSBIN
AssbinExporter.h
AssbinExporter.cpp
AssbinLoader.h
AssbinLoader.cpp
)
ADD_ASSIMP_IMPORTER( ASSXML
AssxmlExporter.h
AssxmlExporter.cpp
)
ADD_ASSIMP_IMPORTER( B3D
B3DImporter.cpp
B3DImporter.h
)
ADD_ASSIMP_IMPORTER( BVH
BVHLoader.cpp
BVHLoader.h
)
ADD_ASSIMP_IMPORTER( COLLADA
ColladaHelper.h
ColladaLoader.cpp
ColladaLoader.h
ColladaParser.cpp
ColladaParser.h
ColladaExporter.h
ColladaExporter.cpp
)
ADD_ASSIMP_IMPORTER( DXF
DXFLoader.cpp
DXFLoader.h
DXFHelper.h
)
ADD_ASSIMP_IMPORTER( CSM
CSMLoader.cpp
CSMLoader.h
)
ADD_ASSIMP_IMPORTER( HMP
HMPFileData.h
HMPLoader.cpp
HMPLoader.h
HalfLifeFileData.h
)
ADD_ASSIMP_IMPORTER( IRRMESH
IRRMeshLoader.cpp
IRRMeshLoader.h
IRRShared.cpp
IRRShared.h
)
ADD_ASSIMP_IMPORTER( IRR
IRRLoader.cpp
IRRLoader.h
IRRShared.cpp
IRRShared.h
)
ADD_ASSIMP_IMPORTER( LWO
LWOAnimation.cpp
LWOAnimation.h
LWOBLoader.cpp
LWOFileData.h
LWOLoader.cpp
LWOLoader.h
LWOMaterial.cpp
)
ADD_ASSIMP_IMPORTER( LWS
LWSLoader.cpp
LWSLoader.h
)
ADD_ASSIMP_IMPORTER( MD2
MD2FileData.h
MD2Loader.cpp
MD2Loader.h
MD2NormalTable.h
)
ADD_ASSIMP_IMPORTER( MD3
MD3FileData.h
MD3Loader.cpp
MD3Loader.h
)
ADD_ASSIMP_IMPORTER( MD5
MD5Loader.cpp
MD5Loader.h
MD5Parser.cpp
MD5Parser.h
)
ADD_ASSIMP_IMPORTER( MDC
MDCFileData.h
MDCLoader.cpp
MDCLoader.h
MDCNormalTable.h
)
ADD_ASSIMP_IMPORTER( MDL
MDLDefaultColorMap.h
MDLFileData.h
MDLLoader.cpp
MDLLoader.h
MDLMaterialLoader.cpp
)
SET( MaterialSystem_SRCS
MaterialSystem.cpp
MaterialSystem.h
)
SOURCE_GROUP( MaterialSystem FILES ${MaterialSystem_SRCS})
ADD_ASSIMP_IMPORTER( NFF
NFFLoader.cpp
NFFLoader.h
)
ADD_ASSIMP_IMPORTER( NDO
NDOLoader.cpp
NDOLoader.h
)
ADD_ASSIMP_IMPORTER( OFF
OFFLoader.cpp
OFFLoader.h
)
ADD_ASSIMP_IMPORTER( OBJ
ObjFileData.h
ObjFileImporter.cpp
ObjFileImporter.h
ObjFileMtlImporter.cpp
ObjFileMtlImporter.h
ObjFileParser.cpp
ObjFileParser.h
ObjTools.h
ObjExporter.h
ObjExporter.cpp
)
ADD_ASSIMP_IMPORTER( OGRE
OgreImporter.h
OgreStructs.h
OgreParsingUtils.h
OgreBinarySerializer.h
OgreXmlSerializer.h
OgreImporter.cpp
OgreStructs.cpp
OgreBinarySerializer.cpp
OgreXmlSerializer.cpp
OgreMaterial.cpp
)
ADD_ASSIMP_IMPORTER( OPENGEX
OpenGEXExporter.cpp
OpenGEXExporter.h
OpenGEXImporter.cpp
OpenGEXImporter.h
OpenGEXStructs.h
)
ADD_ASSIMP_IMPORTER( PLY
PlyLoader.cpp
PlyLoader.h
PlyParser.cpp
PlyParser.h
PlyExporter.cpp
PlyExporter.h
)
ADD_ASSIMP_IMPORTER( MS3D
MS3DLoader.cpp
MS3DLoader.h
)
ADD_ASSIMP_IMPORTER( COB
COBLoader.cpp
COBLoader.h
COBScene.h
)
ADD_ASSIMP_IMPORTER( BLEND
BlenderLoader.cpp
BlenderLoader.h
BlenderDNA.cpp
BlenderDNA.h
BlenderDNA.inl
BlenderScene.cpp
BlenderScene.h
BlenderSceneGen.h
BlenderIntermediate.h
BlenderModifier.h
BlenderModifier.cpp
BlenderBMesh.h
BlenderBMesh.cpp
BlenderTessellator.h
BlenderTessellator.cpp
)
ADD_ASSIMP_IMPORTER( IFC
IFCLoader.cpp
IFCLoader.h
IFCReaderGen.cpp
IFCReaderGen.h
IFCUtil.h
IFCUtil.cpp
IFCGeometry.cpp
IFCMaterial.cpp
IFCProfile.cpp
IFCCurve.cpp
IFCBoolean.cpp
IFCOpenings.cpp
STEPFile.h
STEPFileReader.h
STEPFileReader.cpp
STEPFileEncoding.cpp
STEPFileEncoding.h
)
if (MSVC AND ASSIMP_BUILD_IFC_IMPORTER)
set_source_files_properties(IFCReaderGen.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
endif (MSVC AND ASSIMP_BUILD_IFC_IMPORTER)
ADD_ASSIMP_IMPORTER( XGL
XGLLoader.cpp
XGLLoader.h
)
ADD_ASSIMP_IMPORTER( FBX
FBXImporter.cpp
FBXCompileConfig.h
FBXImporter.h
FBXParser.cpp
FBXParser.h
FBXTokenizer.cpp
FBXTokenizer.h
FBXImportSettings.h
FBXConverter.h
FBXConverter.cpp
FBXUtil.h
FBXUtil.cpp
FBXDocument.h
FBXDocument.cpp
FBXProperties.h
FBXProperties.cpp
FBXMeshGeometry.h
FBXMeshGeometry.cpp
FBXMaterial.cpp
FBXModel.cpp
FBXAnimation.cpp
FBXNodeAttribute.cpp
FBXDeformer.cpp
FBXBinaryTokenizer.cpp
FBXDocumentUtil.cpp
)
SET( PostProcessing_SRCS
CalcTangentsProcess.cpp
CalcTangentsProcess.h
ComputeUVMappingProcess.cpp
ComputeUVMappingProcess.h
ConvertToLHProcess.cpp
ConvertToLHProcess.h
FindDegenerates.cpp
FindDegenerates.h
FindInstancesProcess.cpp
FindInstancesProcess.h
FindInvalidDataProcess.cpp
FindInvalidDataProcess.h
FixNormalsStep.cpp
FixNormalsStep.h
GenFaceNormalsProcess.cpp
GenFaceNormalsProcess.h
GenVertexNormalsProcess.cpp
GenVertexNormalsProcess.h
PretransformVertices.cpp
PretransformVertices.h
ImproveCacheLocality.cpp
ImproveCacheLocality.h
JoinVerticesProcess.cpp
JoinVerticesProcess.h
LimitBoneWeightsProcess.cpp
LimitBoneWeightsProcess.h
RemoveRedundantMaterials.cpp
RemoveRedundantMaterials.h
RemoveVCProcess.cpp
RemoveVCProcess.h
SortByPTypeProcess.cpp
SortByPTypeProcess.h
SplitLargeMeshes.cpp
SplitLargeMeshes.h
TextureTransform.cpp
TextureTransform.h
TriangulateProcess.cpp
TriangulateProcess.h
ValidateDataStructure.cpp
ValidateDataStructure.h
OptimizeGraph.cpp
OptimizeGraph.h
OptimizeMeshes.cpp
OptimizeMeshes.h
DeboneProcess.cpp
DeboneProcess.h
ProcessHelper.h
ProcessHelper.cpp
PolyTools.h
MakeVerboseFormat.cpp
MakeVerboseFormat.h
)
SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS})
ADD_ASSIMP_IMPORTER( Q3D
Q3DLoader.cpp
Q3DLoader.h
)
ADD_ASSIMP_IMPORTER( Q3BSP
Q3BSPFileData.h
Q3BSPFileParser.h
Q3BSPFileParser.cpp
Q3BSPFileImporter.h
Q3BSPFileImporter.cpp
Q3BSPZipArchive.h
Q3BSPZipArchive.cpp
)
ADD_ASSIMP_IMPORTER( RAW
RawLoader.cpp
RawLoader.h
)
ADD_ASSIMP_IMPORTER( SIB
SIBImporter.cpp
SIBImporter.h
)
ADD_ASSIMP_IMPORTER( SMD
SMDLoader.cpp
SMDLoader.h
)
ADD_ASSIMP_IMPORTER( STL
STLLoader.cpp
STLLoader.h
STLExporter.h
STLExporter.cpp
)
ADD_ASSIMP_IMPORTER( TERRAGEN
TerragenLoader.cpp
TerragenLoader.h
)
ADD_ASSIMP_IMPORTER( 3D
UnrealLoader.cpp
UnrealLoader.h
)
ADD_ASSIMP_IMPORTER( X
XFileHelper.h
XFileImporter.cpp
XFileImporter.h
XFileParser.cpp
XFileParser.h
XFileExporter.h
XFileExporter.cpp
)
ADD_ASSIMP_IMPORTER( GLTF
glTFAsset.h
glTFAsset.inl
glTFAssetWriter.h
glTFAssetWriter.inl
glTFImporter.cpp
glTFImporter.h
glTFExporter.h
glTFExporter.cpp
)
ADD_ASSIMP_IMPORTER( 3MF
D3MFImporter.h
D3MFImporter.cpp
D3MFOpcPackage.h
D3MFOpcPackage.cpp
)
SET( Step_SRCS
StepExporter.h
StepExporter.cpp
)
SOURCE_GROUP( Step FILES ${Step_SRCS})
SET( Exporter_SRCS
Exporter.cpp
AssimpCExport.cpp
BlobIOSystem.h
)
SOURCE_GROUP( Exporter FILES ${Exporter_SRCS})
SET( Extra_SRCS
MD4FileData.h
)
SOURCE_GROUP( Extra FILES ${Extra_SRCS})
SET( IrrXML_SRCS
irrXMLWrapper.h
../contrib/irrXML/CXMLReaderImpl.h
../contrib/irrXML/heapsort.h
../contrib/irrXML/irrArray.h
../contrib/irrXML/irrString.h
../contrib/irrXML/irrTypes.h
../contrib/irrXML/irrXML.cpp
../contrib/irrXML/irrXML.h
)
SOURCE_GROUP( IrrXML FILES ${IrrXML_SRCS})
SET( ConvertUTF_SRCS
../contrib/ConvertUTF/ConvertUTF.h
../contrib/ConvertUTF/ConvertUTF.c
)
SOURCE_GROUP( ConvertUTF FILES ${ConvertUTF_SRCS})
SET( Clipper_SRCS
../contrib/clipper/clipper.hpp
../contrib/clipper/clipper.cpp
)
SOURCE_GROUP( Clipper FILES ${Clipper_SRCS})
SET( Poly2Tri_SRCS
../contrib/poly2tri/poly2tri/common/shapes.cc
../contrib/poly2tri/poly2tri/common/shapes.h
../contrib/poly2tri/poly2tri/common/utils.h
../contrib/poly2tri/poly2tri/sweep/advancing_front.h
../contrib/poly2tri/poly2tri/sweep/advancing_front.cc
../contrib/poly2tri/poly2tri/sweep/cdt.cc
../contrib/poly2tri/poly2tri/sweep/cdt.h
../contrib/poly2tri/poly2tri/sweep/sweep.cc
../contrib/poly2tri/poly2tri/sweep/sweep.h
../contrib/poly2tri/poly2tri/sweep/sweep_context.cc
../contrib/poly2tri/poly2tri/sweep/sweep_context.h
)
SOURCE_GROUP( Poly2Tri FILES ${Poly2Tri_SRCS})
SET( unzip_SRCS
../contrib/unzip/crypt.h
../contrib/unzip/ioapi.c
../contrib/unzip/ioapi.h
../contrib/unzip/unzip.c
../contrib/unzip/unzip.h
)
SOURCE_GROUP( unzip FILES ${unzip_SRCS})
SET ( openddl_parser_SRCS
../contrib/openddlparser/code/OpenDDLParser.cpp
../contrib/openddlparser/code/DDLNode.cpp
../contrib/openddlparser/code/OpenDDLCommon.cpp
../contrib/openddlparser/code/OpenDDLExport.cpp
../contrib/openddlparser/code/Value.cpp
../contrib/openddlparser/include/openddlparser/OpenDDLParser.h
../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
../contrib/openddlparser/include/openddlparser/OpenDDLExport.h
../contrib/openddlparser/include/openddlparser/DDLNode.h
../contrib/openddlparser/include/openddlparser/Value.h
)
SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" )
# VC2010 fixes
if(MSVC10)
option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF )
if( VC10_STDINT_FIX )
ADD_DEFINITIONS( -D_STDINT )
endif( VC10_STDINT_FIX )
endif(MSVC10)
ADD_DEFINITIONS( -DASSIMP_BUILD_DLL_EXPORT )
if ( MSVC )
ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
endif ( MSVC )
if (UNZIP_FOUND)
SET (unzip_compile_SRCS "")
else (UNZIP_FOUND)
SET (unzip_compile_SRCS ${unzip_SRCS})
endif (UNZIP_FOUND)
MESSAGE(STATUS "Enabled formats:${ASSIMP_IMPORTERS_ENABLED}")
MESSAGE(STATUS "Disabled formats:${ASSIMP_IMPORTERS_DISABLED}")
SET( assimp_src
# Assimp Files
${Core_SRCS}
${Common_SRCS}
${Logging_SRCS}
${Exporter_SRCS}
${PostProcessing_SRCS}
${MaterialSystem_SRCS}
${Step_SRCS}
# Model Support
${ASSIMP_LOADER_SRCS}
# Third-party libraries
${IrrXML_SRCS}
${ConvertUTF_SRCS}
${unzip_compile_SRCS}
${Poly2Tri_SRCS}
${Clipper_SRCS}
${openddl_parser_SRCS}
# Necessary to show the headers in the project when using the VC++ generator:
${PUBLIC_HEADERS}
${COMPILER_HEADERS}
)
ADD_DEFINITIONS( -DOPENDDLPARSER_BUILD )
INCLUDE_DIRECTORIES(
../contrib/openddlparser/include
)
IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
SET( assimp_src ${assimp_src} ${C4D_SRCS})
INCLUDE_DIRECTORIES(${C4D_INCLUDES})
ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
ADD_LIBRARY( assimp ${assimp_src} )
TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} )
if(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
set(ASSIMP_ANDROID_JNIIOSYSTEM_PATH port/AndroidJNI)
add_subdirectory(../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/ ../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/)
target_link_libraries(assimp android_jniiosystem)
endif(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
TARGET_LINK_LIBRARIES(assimp optimized ${C4D_RELEASE_LIBRARIES})
TARGET_LINK_LIBRARIES(assimp debug ${C4D_DEBUG_LIBRARIES})
TARGET_LINK_LIBRARIES(assimp ${C4D_EXTRA_LIBRARIES})
ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
if( MSVC )
# in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix
if( MSVC70 OR MSVC71 )
set(MSVC_PREFIX "vc70")
elseif( MSVC80 )
set(MSVC_PREFIX "vc80")
elseif( MSVC90 )
set(MSVC_PREFIX "vc90")
elseif( MSVC10 )
set(MSVC_PREFIX "vc100")
elseif( MSVC11 )
set(MSVC_PREFIX "vc110")
elseif( MSVC12 )
set(MSVC_PREFIX "vc120")
elseif( MSVC14 )
set(MSVC_PREFIX "vc140")
else()
set(MSVC_PREFIX "vc150")
endif()
set(LIBRARY_SUFFIX "${ASSIMP_LIBRARY_SUFFIX}-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library")
endif()
SET_TARGET_PROPERTIES( assimp PROPERTIES
VERSION ${ASSIMP_VERSION}
SOVERSION ${ASSIMP_SOVERSION} # use full version
OUTPUT_NAME assimp${LIBRARY_SUFFIX}
)
if (APPLE)
SET_TARGET_PROPERTIES( assimp PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR}")
endif()
# Build against external unzip, or add ../contrib/unzip so
# assimp can #include "unzip.h"
if (UNZIP_FOUND)
INCLUDE_DIRECTORIES(${UNZIP_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES})
else (UNZIP_FOUND)
INCLUDE_DIRECTORIES("../")
endif (UNZIP_FOUND)
INSTALL( TARGETS assimp
LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR}
COMPONENT ${LIBASSIMP_COMPONENT})
INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)
INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev)
if (ASSIMP_ANDROID_JNIIOSYSTEM)
INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h
DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
COMPONENT assimp-dev)
endif(ASSIMP_ANDROID_JNIIOSYSTEM)
if(MSVC AND ASSIMP_INSTALL_PDB)
install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS Debug
)
install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp.pdb
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS RelWithDebInfo
)
endif ()

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,174 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file COBLoader.h
* @brief Declaration of the TrueSpace (*.cob,*.scn) importer class.
*/
#ifndef INCLUDED_AI_COB_LOADER_H
#define INCLUDED_AI_COB_LOADER_H
#include "BaseImporter.h"
#include "StreamReader.h"
struct aiNode;
namespace Assimp {
class LineSplitter;
// TinyFormatter.h
namespace Formatter {
template <typename T,typename TR, typename A> class basic_formatter;
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
}
// COBScene.h
namespace COB {
struct ChunkInfo;
struct Node;
struct Scene;
}
// -------------------------------------------------------------------------------------------
/** Importer class to load TrueSpace files (cob,scn) up to v6.
*
* Currently relatively limited, loads only ASCII files and needs more test coverage. */
// -------------------------------------------------------------------------------------------
class COBImporter : public BaseImporter
{
public:
COBImporter();
~COBImporter();
public:
// --------------------
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
protected:
// --------------------
const aiImporterDesc* GetInfo () const;
// --------------------
void SetupProperties(const Importer* pImp);
// --------------------
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
private:
// -------------------------------------------------------------------
/** Prepend 'COB: ' and throw msg.*/
AI_WONT_RETURN static void ThrowException(const std::string& msg) AI_WONT_RETURN_SUFFIX;
// -------------------------------------------------------------------
/** @brief Read from an ascii scene/object file
* @param out Receives output data.
* @param stream Stream to read from. */
void ReadAsciiFile(COB::Scene& out, StreamReaderLE* stream);
// -------------------------------------------------------------------
/** @brief Read from a binary scene/object file
* @param out Receives output data.
* @param stream Stream to read from. */
void ReadBinaryFile(COB::Scene& out, StreamReaderLE* stream);
private:
// Conversion to Assimp output format
aiNode* BuildNodes(const COB::Node& root,const COB::Scene& scin,aiScene* fill);
private:
// ASCII file support
void UnsupportedChunk_Ascii(LineSplitter& splitter, const COB::ChunkInfo& nfo, const char* name);
void ReadChunkInfo_Ascii(COB::ChunkInfo& out, const LineSplitter& splitter);
void ReadBasicNodeInfo_Ascii(COB::Node& msh, LineSplitter& splitter, const COB::ChunkInfo& nfo);
template <typename T> void ReadFloat3Tuple_Ascii(T& fill, const char** in);
void ReadPolH_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
void ReadBitM_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
void ReadMat1_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
void ReadGrou_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
void ReadBone_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
void ReadCame_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
void ReadLght_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
void ReadUnit_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
void ReadChan_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
// ASCII file logging stuff to add proper line numbers to messages
static void LogWarn_Ascii (const LineSplitter& splitter, const Formatter::format& message);
static void LogError_Ascii(const LineSplitter& splitter, const Formatter::format& message);
static void LogInfo_Ascii (const LineSplitter& splitter, const Formatter::format& message);
static void LogDebug_Ascii(const LineSplitter& splitter, const Formatter::format& message);
static void LogWarn_Ascii (const Formatter::format& message);
static void LogError_Ascii (const Formatter::format& message);
static void LogInfo_Ascii (const Formatter::format& message);
static void LogDebug_Ascii (const Formatter::format& message);
// Binary file support
void UnsupportedChunk_Binary(StreamReaderLE& reader, const COB::ChunkInfo& nfo, const char* name);
void ReadString_Binary(std::string& out, StreamReaderLE& reader);
void ReadBasicNodeInfo_Binary(COB::Node& msh, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
void ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
void ReadBitM_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
void ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
void ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
void ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
void ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
void ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
}; // !class COBImporter
} // end of namespace Assimp
#endif // AI_UNREALIMPORTER_H_INC

View file

@ -0,0 +1,274 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file COBScene.h
* @brief Utilities for the COB importer.
*/
#ifndef INCLUDED_AI_COB_SCENE_H
#define INCLUDED_AI_COB_SCENE_H
#include <memory>
#include <deque>
#include "BaseImporter.h"
#include "./../include/assimp/material.h"
namespace Assimp {
namespace COB {
// ------------------
/** Represents a single vertex index in a face */
struct VertexIndex
{
// intentionally uninitialized
unsigned int pos_idx,uv_idx;
};
// ------------------
/** COB Face data structure */
struct Face
{
// intentionally uninitialized
unsigned int material, flags;
std::vector<VertexIndex> indices;
};
// ------------------
/** COB chunk header information */
struct ChunkInfo
{
enum {NO_SIZE=UINT_MAX};
ChunkInfo ()
: id (0)
, parent_id (0)
, version (0)
, size (NO_SIZE)
{}
// Id of this chunk, unique within file
unsigned int id;
// and the corresponding parent
unsigned int parent_id;
// version. v1.23 becomes 123
unsigned int version;
// chunk size in bytes, only relevant for binary files
// NO_SIZE is also valid.
unsigned int size;
};
// ------------------
/** A node in the scenegraph */
struct Node : public ChunkInfo
{
enum Type {
TYPE_MESH,TYPE_GROUP,TYPE_LIGHT,TYPE_CAMERA,TYPE_BONE
};
virtual ~Node() {}
Node(Type type) : type(type), unit_scale(1.f){}
Type type;
// used during resolving
typedef std::deque<const Node*> ChildList;
mutable ChildList temp_children;
// unique name
std::string name;
// local mesh transformation
aiMatrix4x4 transform;
// scaling for this node to get to the metric system
float unit_scale;
};
// ------------------
/** COB Mesh data structure */
struct Mesh : public Node
{
using ChunkInfo::operator=;
enum DrawFlags {
SOLID = 0x1,
TRANS = 0x2,
WIRED = 0x4,
BBOX = 0x8,
HIDE = 0x10
};
Mesh()
: Node(TYPE_MESH)
, draw_flags(SOLID)
{}
// vertex elements
std::vector<aiVector2D> texture_coords;
std::vector<aiVector3D> vertex_positions;
// face data
std::vector<Face> faces;
// misc. drawing flags
unsigned int draw_flags;
// used during resolving
typedef std::deque<Face*> FaceRefList;
typedef std::map< unsigned int,FaceRefList > TempMap;
TempMap temp_map;
};
// ------------------
/** COB Group data structure */
struct Group : public Node
{
using ChunkInfo::operator=;
Group() : Node(TYPE_GROUP) {}
};
// ------------------
/** COB Bone data structure */
struct Bone : public Node
{
using ChunkInfo::operator=;
Bone() : Node(TYPE_BONE) {}
};
// ------------------
/** COB Light data structure */
struct Light : public Node
{
enum LightType {
SPOT,LOCAL,INFINITE
};
using ChunkInfo::operator=;
Light() : Node(TYPE_LIGHT),angle(),inner_angle(),ltype(SPOT) {}
aiColor3D color;
float angle,inner_angle;
LightType ltype;
};
// ------------------
/** COB Camera data structure */
struct Camera : public Node
{
using ChunkInfo::operator=;
Camera() : Node(TYPE_CAMERA) {}
};
// ------------------
/** COB Texture data structure */
struct Texture
{
std::string path;
aiUVTransform transform;
};
// ------------------
/** COB Material data structure */
struct Material : ChunkInfo
{
using ChunkInfo::operator=;
enum Shader {
FLAT,PHONG,METAL
};
enum AutoFacet {
FACETED,AUTOFACETED,SMOOTH
};
Material() : alpha(),exp(),ior(),ka(),ks(1.f),
matnum(UINT_MAX),
shader(FLAT),autofacet(FACETED),
autofacet_angle()
{}
std::string type;
aiColor3D rgb;
float alpha, exp, ior,ka,ks;
unsigned int matnum;
Shader shader;
AutoFacet autofacet;
float autofacet_angle;
std::shared_ptr<Texture> tex_env,tex_bump,tex_color;
};
// ------------------
/** Embedded bitmap, for instance for the thumbnail image */
struct Bitmap : ChunkInfo
{
Bitmap() : orig_size() {}
struct BitmapHeader
{
};
BitmapHeader head;
size_t orig_size;
std::vector<char> buff_zipped;
};
typedef std::deque< std::shared_ptr<Node> > NodeList;
typedef std::vector< Material > MaterialList;
// ------------------
/** Represents a master COB scene, even if we loaded just a single COB file */
struct Scene
{
NodeList nodes;
MaterialList materials;
// becomes *0 later
Bitmap thumbnail;
};
} // end COB
} // end Assimp
#endif

View file

@ -0,0 +1,306 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file CSMLoader.cpp
* Implementation of the CSM importer class.
*/
#ifndef ASSIMP_BUILD_NO_CSM_IMPORTER
#include "CSMLoader.h"
#include "SkeletonMeshBuilder.h"
#include "ParsingUtils.h"
#include "fast_atof.h"
#include <assimp/Importer.hpp>
#include <memory>
#include <assimp/IOSystem.hpp>
#include <assimp/anim.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/scene.h>
using namespace Assimp;
static const aiImporterDesc desc = {
"CharacterStudio Motion Importer (MoCap)",
"",
"",
"",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"csm"
};
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
CSMImporter::CSMImporter()
: noSkeletonMesh()
{}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
CSMImporter::~CSMImporter()
{}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
{
// check file extension
const std::string extension = GetExtension(pFile);
if( extension == "csm")
return true;
if ((checkSig || !extension.length()) && pIOHandler) {
const char* tokens[] = {"$Filename"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
}
return false;
}
// ------------------------------------------------------------------------------------------------
// Build a string of all file extensions supported
const aiImporterDesc* CSMImporter::GetInfo () const
{
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader
void CSMImporter::SetupProperties(const Importer* pImp)
{
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void CSMImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler)
{
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
// Check whether we can read from the file
if( file.get() == NULL) {
throw DeadlyImportError( "Failed to open CSM file " + pFile + ".");
}
// allocate storage and copy the contents of the file to a memory buffer
std::vector<char> mBuffer2;
TextFileToBuffer(file.get(),mBuffer2);
const char* buffer = &mBuffer2[0];
aiAnimation* anim = new aiAnimation();
int first = 0, last = 0x00ffffff;
// now process the file and look out for '$' sections
while (1) {
SkipSpaces(&buffer);
if ('\0' == *buffer)
break;
if ('$' == *buffer) {
++buffer;
if (TokenMatchI(buffer,"firstframe",10)) {
SkipSpaces(&buffer);
first = strtol10(buffer,&buffer);
}
else if (TokenMatchI(buffer,"lastframe",9)) {
SkipSpaces(&buffer);
last = strtol10(buffer,&buffer);
}
else if (TokenMatchI(buffer,"rate",4)) {
SkipSpaces(&buffer);
float d;
buffer = fast_atoreal_move<float>(buffer,d);
anim->mTicksPerSecond = d;
}
else if (TokenMatchI(buffer,"order",5)) {
std::vector< aiNodeAnim* > anims_temp;
anims_temp.reserve(30);
while (1) {
SkipSpaces(&buffer);
if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$')
break; // next section
// Construct a new node animation channel and setup its name
anims_temp.push_back(new aiNodeAnim());
aiNodeAnim* nda = anims_temp.back();
char* ot = nda->mNodeName.data;
while (!IsSpaceOrNewLine(*buffer))
*ot++ = *buffer++;
*ot = '\0';
nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data);
}
anim->mNumChannels = anims_temp.size();
if (!anim->mNumChannels)
throw DeadlyImportError("CSM: Empty $order section");
// copy over to the output animation
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels);
}
else if (TokenMatchI(buffer,"points",6)) {
if (!anim->mNumChannels)
throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'");
// If we know how many frames we'll read, we can preallocate some storage
unsigned int alloc = 100;
if (last != 0x00ffffff)
{
alloc = last-first;
alloc += alloc>>2u; // + 25%
for (unsigned int i = 0; i < anim->mNumChannels;++i)
anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc];
}
unsigned int filled = 0;
// Now read all point data.
while (1) {
SkipSpaces(&buffer);
if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) {
break; // next section
}
// read frame
const int frame = ::strtoul10(buffer,&buffer);
last = std::max(frame,last);
first = std::min(frame,last);
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
aiNodeAnim* s = anim->mChannels[i];
if (s->mNumPositionKeys == alloc) { /* need to reallocate? */
aiVectorKey* old = s->mPositionKeys;
s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2];
::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc);
delete[] old;
}
// read x,y,z
if(!SkipSpacesAndLineEnd(&buffer))
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample x coord");
if (TokenMatchI(buffer, "DROPOUT", 7)) {
// seems this is invalid marker data; at least the doc says it's possible
DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)");
}
else {
aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
sub->mTime = (double)frame;
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
if(!SkipSpacesAndLineEnd(&buffer))
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample y coord");
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
if(!SkipSpacesAndLineEnd(&buffer))
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample z coord");
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
++s->mNumPositionKeys;
}
}
// update allocation granularity
if (filled == alloc)
alloc *= 2;
++filled;
}
// all channels must be complete in order to continue safely.
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
if (!anim->mChannels[i]->mNumPositionKeys)
throw DeadlyImportError("CSM: Invalid marker track");
}
}
}
else {
// advance to the next line
SkipLine(&buffer);
}
}
// Setup a proper animation duration
anim->mDuration = last - std::min( first, 0 );
// build a dummy root node with the tiny markers as children
pScene->mRootNode = new aiNode();
pScene->mRootNode->mName.Set("$CSM_DummyRoot");
pScene->mRootNode->mNumChildren = anim->mNumChannels;
pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels];
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
aiNodeAnim* na = anim->mChannels[i];
aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode();
nd->mName = anim->mChannels[i]->mNodeName;
nd->mParent = pScene->mRootNode;
aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation);
}
// Store the one and only animation in the scene
pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1];
pScene->mAnimations[0] = anim;
anim->mName.Set("$CSM_MasterAnim");
// mark the scene as incomplete and run SkeletonMeshBuilder on it
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
if (!noSkeletonMesh) {
SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true);
}
}
#endif // !! ASSIMP_BUILD_NO_CSM_IMPORTER

View file

@ -0,0 +1,91 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file CSMLoader.h
* Declaration of the CharacterStudio Motion importer class.
*/
#ifndef INCLUDED_AI_CSM_LOADER_H
#define INCLUDED_AI_CSM_LOADER_H
#include "BaseImporter.h"
namespace Assimp {
// ---------------------------------------------------------------------------
/** Importer class to load MOCAPs in CharacterStudio Motion format.
*
* A very rudimentary loader for the moment. No support for the hierarchy,
* every marker is returned as child of root.
*
* Link to file format specification:
* <max_8_dvd>\samples\Motion\Docs\CSM.rtf
*/
class CSMImporter : public BaseImporter
{
public:
CSMImporter();
~CSMImporter();
public:
// -------------------------------------------------------------------
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
protected:
// -------------------------------------------------------------------
const aiImporterDesc* GetInfo () const;
// -------------------------------------------------------------------
void SetupProperties(const Importer* pImp);
// -------------------------------------------------------------------
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
private:
bool noSkeletonMesh;
}; // end of class CSMImporter
} // end of namespace Assimp
#endif // AI_AC3DIMPORTER_H_INC

View file

@ -0,0 +1,317 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
---------------------------------------------------------------------------
*/
/** @file Implementation of the post processing step to calculate
* tangents and bitangents for all imported meshes
*/
// internal headers
#include "CalcTangentsProcess.h"
#include "ProcessHelper.h"
#include "TinyFormatter.h"
#include "qnan.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
CalcTangentsProcess::CalcTangentsProcess()
: configMaxAngle( AI_DEG_TO_RAD(45.f) )
, configSourceUV( 0 ) {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
CalcTangentsProcess::~CalcTangentsProcess()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
{
return (pFlags & aiProcess_CalcTangentSpace) != 0;
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void CalcTangentsProcess::SetupProperties(const Importer* pImp)
{
ai_assert( NULL != pImp );
// get the current value of the property
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f);
configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0);
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void CalcTangentsProcess::Execute( aiScene* pScene)
{
ai_assert( NULL != pScene );
DefaultLogger::get()->debug("CalcTangentsProcess begin");
bool bHas = false;
for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
if(ProcessMesh( pScene->mMeshes[a],a))bHas = true;
}
if ( bHas ) {
DefaultLogger::get()->info("CalcTangentsProcess finished. Tangents have been calculated");
} else {
DefaultLogger::get()->debug("CalcTangentsProcess finished");
}
}
// ------------------------------------------------------------------------------------------------
// Calculates tangents and bi-tangents for the given mesh
bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
{
// we assume that the mesh is still in the verbose vertex format where each face has its own set
// of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
// assert() it here.
// assert( must be verbose, dammit);
if (pMesh->mTangents) // this implies that mBitangents is also there
return false;
// If the mesh consists of lines and/or points but not of
// triangles or higher-order polygons the normal vectors
// are undefined.
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
{
DefaultLogger::get()->info("Tangents are undefined for line and point meshes");
return false;
}
// what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
if( pMesh->mNormals == NULL)
{
DefaultLogger::get()->error("Failed to compute tangents; need normals");
return false;
}
if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] )
{
DefaultLogger::get()->error((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
return false;
}
const float angleEpsilon = 0.9999f;
std::vector<bool> vertexDone( pMesh->mNumVertices, false);
const float qnan = get_qnan();
// create space for the tangents and bitangents
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
const aiVector3D* meshPos = pMesh->mVertices;
const aiVector3D* meshNorm = pMesh->mNormals;
const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV];
aiVector3D* meshTang = pMesh->mTangents;
aiVector3D* meshBitang = pMesh->mBitangents;
// calculate the tangent and bitangent for every face
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
{
const aiFace& face = pMesh->mFaces[a];
if (face.mNumIndices < 3)
{
// There are less than three indices, thus the tangent vector
// is not defined. We are finished with these vertices now,
// their tangent vectors are set to qnan.
for (unsigned int i = 0; i < face.mNumIndices;++i)
{
unsigned int idx = face.mIndices[i];
vertexDone [idx] = true;
meshTang [idx] = aiVector3D(qnan);
meshBitang [idx] = aiVector3D(qnan);
}
continue;
}
// triangle or polygon... we always use only the first three indices. A polygon
// is supposed to be planar anyways....
// FIXME: (thom) create correct calculation for multi-vertex polygons maybe?
const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2];
// position differences p1->p2 and p1->p3
aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
// texture offset p1->p2 and p1->p3
float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
// when t1, t2, t3 in same position in UV space, just use default UV direction.
if ( 0 == sx && 0 ==sy && 0 == tx && 0 == ty ) {
sx = 0.0; sy = 1.0;
tx = 1.0; ty = 0.0;
}
// tangent points in the direction where to positive X axis of the texture coord's would point in model space
// bitangent's points along the positive Y axis of the texture coord's, respectively
aiVector3D tangent, bitangent;
tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
// store for every vertex of that face
for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
unsigned int p = face.mIndices[b];
// project tangent and bitangent into the plane formed by the vertex' normal
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
localTangent.Normalize(); localBitangent.Normalize();
// reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z);
bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z);
if (invalid_tangent != invalid_bitangent) {
if (invalid_tangent) {
localTangent = meshNorm[p] ^ localBitangent;
localTangent.Normalize();
} else {
localBitangent = localTangent ^ meshNorm[p];
localBitangent.Normalize();
}
}
// and write it into the mesh.
meshTang[ p ] = localTangent;
meshBitang[ p ] = localBitangent;
}
}
// create a helper to quickly find locally close vertices among the vertex array
// FIX: check whether we can reuse the SpatialSort of a previous step
SpatialSort* vertexFinder = NULL;
SpatialSort _vertexFinder;
float posEpsilon;
if (shared)
{
std::vector<std::pair<SpatialSort,float> >* avf;
shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
if (avf)
{
std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
vertexFinder = &blubb.first;
posEpsilon = blubb.second;;
}
}
if (!vertexFinder)
{
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
vertexFinder = &_vertexFinder;
posEpsilon = ComputePositionEpsilon(pMesh);
}
std::vector<unsigned int> verticesFound;
const float fLimit = cosf(configMaxAngle);
std::vector<unsigned int> closeVertices;
// in the second pass we now smooth out all tangents and bitangents at the same local position
// if they are not too far off.
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
{
if( vertexDone[a])
continue;
const aiVector3D& origPos = pMesh->mVertices[a];
const aiVector3D& origNorm = pMesh->mNormals[a];
const aiVector3D& origTang = pMesh->mTangents[a];
const aiVector3D& origBitang = pMesh->mBitangents[a];
closeVertices.resize( 0 );
// find all vertices close to that position
vertexFinder->FindPositions( origPos, posEpsilon, verticesFound);
closeVertices.reserve (verticesFound.size()+5);
closeVertices.push_back( a);
// look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
for( unsigned int b = 0; b < verticesFound.size(); b++)
{
unsigned int idx = verticesFound[b];
if( vertexDone[idx])
continue;
if( meshNorm[idx] * origNorm < angleEpsilon)
continue;
if( meshTang[idx] * origTang < fLimit)
continue;
if( meshBitang[idx] * origBitang < fLimit)
continue;
// it's similar enough -> add it to the smoothing group
closeVertices.push_back( idx);
vertexDone[idx] = true;
}
// smooth the tangents and bitangents of all vertices that were found to be close enough
aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0);
for( unsigned int b = 0; b < closeVertices.size(); ++b)
{
smoothTangent += meshTang[ closeVertices[b] ];
smoothBitangent += meshBitang[ closeVertices[b] ];
}
smoothTangent.Normalize();
smoothBitangent.Normalize();
// and write it back into all affected tangents
for( unsigned int b = 0; b < closeVertices.size(); ++b)
{
meshTang[ closeVertices[b] ] = smoothTangent;
meshBitang[ closeVertices[b] ] = smoothBitangent;
}
}
return true;
}

View file

@ -0,0 +1,115 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file Defines a post processing step to calculate tangents and
bitangents on all imported meshes.*/
#ifndef AI_CALCTANGENTSPROCESS_H_INC
#define AI_CALCTANGENTSPROCESS_H_INC
#include "BaseProcess.h"
struct aiMesh;
namespace Assimp
{
// ---------------------------------------------------------------------------
/** The CalcTangentsProcess calculates the tangent and bitangent for any vertex
* of all meshes. It is expected to be run before the JoinVerticesProcess runs
* because the joining of vertices also considers tangents and bitangents for
* uniqueness.
*/
class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess
{
public:
CalcTangentsProcess();
~CalcTangentsProcess();
public:
// -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag.
* @param pFlags The processing flags the importer was called with.
* A bitwise combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields,
* false if not.
*/
bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
/** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration
* basing on the Importer's configuration property list.
*/
void SetupProperties(const Importer* pImp);
// setter for configMaxAngle
inline void SetMaxSmoothAngle(float f)
{
configMaxAngle =f;
}
protected:
// -------------------------------------------------------------------
/** Calculates tangents and bitangents for a specific mesh.
* @param pMesh The mesh to process.
* @param meshIndex Index of the mesh
*/
bool ProcessMesh( aiMesh* pMesh, unsigned int meshIndex);
// -------------------------------------------------------------------
/** Executes the post processing step on the given imported data.
* @param pScene The imported data to work at.
*/
void Execute( aiScene* pScene);
private:
/** Configuration option: maximum smoothing angle, in radians*/
float configMaxAngle;
unsigned int configSourceUV;
};
} // end of namespace Assimp
#endif // AI_CALCTANGENTSPROCESS_H_INC

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,201 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
/** @file ColladaExporter.h
* Declares the exporter class to write a scene to a Collada file
*/
#ifndef AI_COLLADAEXPORTER_H_INC
#define AI_COLLADAEXPORTER_H_INC
#include <assimp/ai_assert.h>
#include <assimp/material.h>
#include <assimp/mesh.h>
#include <assimp/light.h>
#include <assimp/Exporter.hpp>
#include <sstream>
#include <vector>
#include <map>
struct aiScene;
struct aiNode;
namespace Assimp
{
/// Helper class to export a given scene to a Collada file. Just for my personal
/// comfort when implementing it.
class ColladaExporter
{
public:
/// Constructor for a specific scene to export
ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file);
/// Destructor
virtual ~ColladaExporter();
protected:
/// Starts writing the contents
void WriteFile();
/// Writes the asset header
void WriteHeader();
/// Writes the embedded textures
void WriteTextures();
/// Writes the material setup
void WriteMaterials();
/// Writes the cameras library
void WriteCamerasLibrary();
// Write a camera entry
void WriteCamera(size_t pIndex);
/// Writes the cameras library
void WriteLightsLibrary();
// Write a camera entry
void WriteLight(size_t pIndex);
void WritePointLight(const aiLight *const light);
void WriteDirectionalLight(const aiLight *const light);
void WriteSpotLight(const aiLight *const light);
void WriteAmbienttLight(const aiLight *const light);
/// Writes the geometry library
void WriteGeometryLibrary();
/// Writes the given mesh
void WriteGeometry( size_t pIndex);
enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color };
/// Writes a float array of the given type
void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount);
/// Writes the scene library
void WriteSceneLibrary();
/// Recursively writes the given node
void WriteNode( const aiScene* scene, aiNode* pNode);
/// Enters a new xml element, which increases the indentation
void PushTag() { startstr.append( " "); }
/// Leaves an element, decreasing the indentation
void PopTag() { ai_assert( startstr.length() > 1); startstr.erase( startstr.length() - 2); }
/// Creates a mesh ID for the given mesh
std::string GetMeshId( size_t pIndex) const { return std::string( "meshId" ) + std::to_string(pIndex); }
public:
/// Stringstream to write all output into
std::stringstream mOutput;
protected:
/// The IOSystem for output
IOSystem* mIOSystem;
/// Path of the directory where the scene will be exported
const std::string mPath;
/// Name of the file (without extension) where the scene will be exported
const std::string mFile;
/// The scene to be written
const aiScene* mScene;
bool mSceneOwned;
/// current line start string, contains the current indentation for simple stream insertion
std::string startstr;
/// current line end string for simple stream insertion
std::string endstr;
// pair of color and texture - texture precedences color
struct Surface
{
bool exist;
aiColor4D color;
std::string texture;
size_t channel;
Surface() { exist = false; channel = 0; }
};
struct Property
{
bool exist;
float value;
Property()
: exist(false)
, value(0.0f)
{}
};
// summarize a material in an convinient way.
struct Material
{
std::string name;
std::string shading_model;
Surface ambient, diffuse, specular, emissive, reflective, transparent, normal;
Property shininess, transparency, index_refraction;
Material() {}
};
std::vector<Material> materials;
std::map<unsigned int, std::string> textures;
protected:
/// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
/// Reads a single surface entry from the given material keys
void ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex);
/// Writes an image entry for the given surface
void WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd);
/// Writes the two parameters necessary for referencing a texture in an effect entry
void WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName);
/// Writes a color-or-texture entry into an effect definition
void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName);
/// Writes a scalar property
void WriteFloatEntry( const Property& pProperty, const std::string& pTypeName);
};
}
#endif // !! AI_COLLADAEXPORTER_H_INC

View file

@ -0,0 +1,672 @@
/** Helper structures for the Collada loader */
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
#ifndef AI_COLLADAHELPER_H_INC
#define AI_COLLADAHELPER_H_INC
#include <string>
#include <map>
#include <vector>
#include <stdint.h>
#include <assimp/light.h>
#include <assimp/mesh.h>
#include <assimp/material.h>
struct aiMaterial;
namespace Assimp {
namespace Collada {
/** Collada file versions which evolved during the years ... */
enum FormatVersion
{
FV_1_5_n,
FV_1_4_n,
FV_1_3_n
};
/** Transformation types that can be applied to a node */
enum TransformType
{
TF_LOOKAT,
TF_ROTATE,
TF_TRANSLATE,
TF_SCALE,
TF_SKEW,
TF_MATRIX
};
/** Different types of input data to a vertex or face */
enum InputType
{
IT_Invalid,
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
IT_Position,
IT_Normal,
IT_Texcoord,
IT_Color,
IT_Tangent,
IT_Bitangent
};
/** Contains all data for one of the different transformation types */
struct Transform
{
std::string mID; ///< SID of the transform step, by which anim channels address their target node
TransformType mType;
float f[16]; ///< Interpretation of data depends on the type of the transformation
};
/** A collada camera. */
struct Camera
{
Camera()
: mOrtho (false)
, mHorFov (10e10f)
, mVerFov (10e10f)
, mAspect (10e10f)
, mZNear (0.1f)
, mZFar (1000.f)
{}
// Name of camera
std::string mName;
// True if it is an orthografic camera
bool mOrtho;
//! Horizontal field of view in degrees
float mHorFov;
//! Vertical field of view in degrees
float mVerFov;
//! Screen aspect
float mAspect;
//! Near& far z
float mZNear, mZFar;
};
#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
/** A collada light source. */
struct Light
{
Light()
: mType (aiLightSource_UNDEFINED)
, mAttConstant (1.f)
, mAttLinear (0.f)
, mAttQuadratic (0.f)
, mFalloffAngle (180.f)
, mFalloffExponent (0.f)
, mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
, mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
, mIntensity (1.f)
{}
//! Type of the light source aiLightSourceType + ambient
unsigned int mType;
//! Color of the light
aiColor3D mColor;
//! Light attenuation
float mAttConstant,mAttLinear,mAttQuadratic;
//! Spot light falloff
float mFalloffAngle;
float mFalloffExponent;
// -----------------------------------------------------
// FCOLLADA extension from here
//! ... related stuff from maja and max extensions
float mPenumbraAngle;
float mOuterAngle;
//! Common light intensity
float mIntensity;
};
/** Short vertex index description */
struct InputSemanticMapEntry
{
InputSemanticMapEntry()
: mSet(0)
, mType(IT_Invalid)
{}
//! Index of set, optional
unsigned int mSet;
//! Type of referenced vertex input
InputType mType;
};
/** Table to map from effect to vertex input semantics */
struct SemanticMappingTable
{
//! Name of material
std::string mMatName;
//! List of semantic map commands, grouped by effect semantic name
std::map<std::string, InputSemanticMapEntry> mMap;
//! For std::find
bool operator == (const std::string& s) const {
return s == mMatName;
}
};
/** A reference to a mesh inside a node, including materials assigned to the various subgroups.
* The ID refers to either a mesh or a controller which specifies the mesh
*/
struct MeshInstance
{
///< ID of the mesh or controller to be instanced
std::string mMeshOrController;
///< Map of materials by the subgroup ID they're applied to
std::map<std::string, SemanticMappingTable> mMaterials;
};
/** A reference to a camera inside a node*/
struct CameraInstance
{
///< ID of the camera
std::string mCamera;
};
/** A reference to a light inside a node*/
struct LightInstance
{
///< ID of the camera
std::string mLight;
};
/** A reference to a node inside a node*/
struct NodeInstance
{
///< ID of the node
std::string mNode;
};
/** A node in a scene hierarchy */
struct Node
{
std::string mName;
std::string mID;
std::string mSID;
Node* mParent;
std::vector<Node*> mChildren;
/** Operations in order to calculate the resulting transformation to parent. */
std::vector<Transform> mTransforms;
/** Meshes at this node */
std::vector<MeshInstance> mMeshes;
/** Lights at this node */
std::vector<LightInstance> mLights;
/** Cameras at this node */
std::vector<CameraInstance> mCameras;
/** Node instances at this node */
std::vector<NodeInstance> mNodeInstances;
/** Rootnodes: Name of primary camera, if any */
std::string mPrimaryCamera;
//! Constructor. Begin with a zero parent
Node() {
mParent = NULL;
}
//! Destructor: delete all children subsequently
~Node() {
for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
delete *it;
}
};
/** Data source array: either floats or strings */
struct Data
{
bool mIsStringArray;
std::vector<float> mValues;
std::vector<std::string> mStrings;
};
/** Accessor to a data array */
struct Accessor
{
size_t mCount; // in number of objects
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
size_t mOffset; // in number of values
size_t mStride; // Stride in number of values
std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
// For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
std::string mSource; // URL of the source array
mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
Accessor()
{
mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL;
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
}
};
/** A single face in a mesh */
struct Face
{
std::vector<size_t> mIndices;
};
/** An input channel for mesh data, referring to a single accessor */
struct InputChannel
{
InputType mType; // Type of the data
size_t mIndex; // Optional index, if multiple sets of the same data type are given
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
std::string mAccessor; // ID of the accessor where to read the actual values from.
mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
};
/** Subset of a mesh with a certain material */
struct SubMesh
{
std::string mMaterial; ///< subgroup identifier
size_t mNumFaces; ///< number of faces in this submesh
};
/** Contains data for a single mesh */
struct Mesh
{
Mesh()
{
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
mNumUVComponents[i] = 2;
}
std::string mName;
// just to check if there's some sophisticated addressing involved...
// which we don't support, and therefore should warn about.
std::string mVertexID;
// Vertex data addressed by vertex indices
std::vector<InputChannel> mPerVertexData;
// actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
std::vector<aiVector3D> mPositions;
std::vector<aiVector3D> mNormals;
std::vector<aiVector3D> mTangents;
std::vector<aiVector3D> mBitangents;
std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
// Faces. Stored are only the number of vertices for each face.
// 1 == point, 2 == line, 3 == triangle, 4+ == poly
std::vector<size_t> mFaceSize;
// Position indices for all faces in the sequence given in mFaceSize -
// necessary for bone weight assignment
std::vector<size_t> mFacePosIndices;
// Submeshes in this mesh, each with a given material
std::vector<SubMesh> mSubMeshes;
};
/** Which type of primitives the ReadPrimitives() function is going to read */
enum PrimitiveType
{
Prim_Invalid,
Prim_Lines,
Prim_LineStrip,
Prim_Triangles,
Prim_TriStrips,
Prim_TriFans,
Prim_Polylist,
Prim_Polygon
};
/** A skeleton controller to deform a mesh with the use of joints */
struct Controller
{
// the URL of the mesh deformed by the controller.
std::string mMeshId;
// accessor URL of the joint names
std::string mJointNameSource;
///< The bind shape matrix, as array of floats. I'm not sure what this matrix actually describes, but it can't be ignored in all cases
float mBindShapeMatrix[16];
// accessor URL of the joint inverse bind matrices
std::string mJointOffsetMatrixSource;
// input channel: joint names.
InputChannel mWeightInputJoints;
// input channel: joint weights
InputChannel mWeightInputWeights;
// Number of weights per vertex.
std::vector<size_t> mWeightCounts;
// JointIndex-WeightIndex pairs for all vertices
std::vector< std::pair<size_t, size_t> > mWeights;
};
/** A collada material. Pretty much the only member is a reference to an effect. */
struct Material
{
std::string mName;
std::string mEffect;
};
/** Type of the effect param */
enum ParamType
{
Param_Sampler,
Param_Surface
};
/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
struct EffectParam
{
ParamType mType;
std::string mReference; // to which other thing the param is referring to.
};
/** Shading type supported by the standard effect spec of Collada */
enum ShadeType
{
Shade_Invalid,
Shade_Constant,
Shade_Lambert,
Shade_Phong,
Shade_Blinn
};
/** Represents a texture sampler in collada */
struct Sampler
{
Sampler()
: mWrapU (true)
, mWrapV (true)
, mMirrorU ()
, mMirrorV ()
, mOp (aiTextureOp_Multiply)
, mUVId (UINT_MAX)
, mWeighting (1.f)
, mMixWithPrevious (1.f)
{}
/** Name of image reference
*/
std::string mName;
/** Wrap U?
*/
bool mWrapU;
/** Wrap V?
*/
bool mWrapV;
/** Mirror U?
*/
bool mMirrorU;
/** Mirror V?
*/
bool mMirrorV;
/** Blend mode
*/
aiTextureOp mOp;
/** UV transformation
*/
aiUVTransform mTransform;
/** Name of source UV channel
*/
std::string mUVChannel;
/** Resolved UV channel index or UINT_MAX if not known
*/
unsigned int mUVId;
// OKINO/MAX3D extensions from here
// -------------------------------------------------------
/** Weighting factor
*/
float mWeighting;
/** Mixing factor from OKINO
*/
float mMixWithPrevious;
};
/** A collada effect. Can contain about anything according to the Collada spec,
but we limit our version to a reasonable subset. */
struct Effect
{
// Shading mode
ShadeType mShadeType;
// Colors
aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
mTransparent, mReflective;
// Textures
Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
mTexTransparent, mTexBump, mTexReflective;
// Scalar factory
float mShininess, mRefractIndex, mReflectivity;
float mTransparency;
bool mHasTransparency;
bool mRGBTransparency;
bool mInvertTransparency;
// local params referring to each other by their SID
typedef std::map<std::string, Collada::EffectParam> ParamLibrary;
ParamLibrary mParams;
// MAX3D extensions
// ---------------------------------------------------------
// Double-sided?
bool mDoubleSided, mWireframe, mFaceted;
Effect()
: mShadeType (Shade_Phong)
, mEmissive ( 0, 0, 0, 1)
, mAmbient ( 0.1f, 0.1f, 0.1f, 1)
, mDiffuse ( 0.6f, 0.6f, 0.6f, 1)
, mSpecular ( 0.4f, 0.4f, 0.4f, 1)
, mTransparent ( 0, 0, 0, 1)
, mShininess (10.0f)
, mRefractIndex (1.f)
, mReflectivity (0.f)
, mTransparency (1.f)
, mHasTransparency (false)
, mRGBTransparency(false)
, mInvertTransparency(false)
, mDoubleSided (false)
, mWireframe (false)
, mFaceted (false)
{
}
};
/** An image, meaning texture */
struct Image
{
std::string mFileName;
/** If image file name is zero, embedded image data
*/
std::vector<uint8_t> mImageData;
/** If image file name is zero, file format of
* embedded image data.
*/
std::string mEmbeddedFormat;
};
/** An animation channel. */
struct AnimationChannel
{
/** URL of the data to animate. Could be about anything, but we support only the
* "NodeID/TransformID.SubElement" notation
*/
std::string mTarget;
/** Source URL of the time values. Collada calls them "input". Meh. */
std::string mSourceTimes;
/** Source URL of the value values. Collada calls them "output". */
std::string mSourceValues;
};
/** An animation. Container for 0-x animation channels or 0-x animations */
struct Animation
{
/** Anim name */
std::string mName;
/** the animation channels, if any */
std::vector<AnimationChannel> mChannels;
/** the sub-animations, if any */
std::vector<Animation*> mSubAnims;
/** Destructor */
~Animation()
{
for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
delete *it;
}
/** Collect all channels in the animation hierarchy into a single channel list. */
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels)
{
channels.insert(channels.end(), mChannels.begin(), mChannels.end());
for (std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
{
Animation *pAnim = (*it);
pAnim->CollectChannelsRecursively(channels);
}
}
/** Combine all single-channel animations' channel into the same (parent) animation channel list. */
void CombineSingleChannelAnimations()
{
CombineSingleChannelAnimationsRecursively(this);
}
void CombineSingleChannelAnimationsRecursively(Animation *pParent)
{
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
{
Animation *anim = *it;
CombineSingleChannelAnimationsRecursively(anim);
if (anim->mChannels.size() == 1)
{
pParent->mChannels.push_back(anim->mChannels[0]);
it = pParent->mSubAnims.erase(it);
delete anim;
}
else
{
++it;
}
}
}
};
/** Description of a collada animation channel which has been determined to affect the current node */
struct ChannelEntry
{
const Collada::AnimationChannel* mChannel; ///> the source channel
std::string mTransformId; // the ID of the transformation step of the node which is influenced
size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
size_t mSubElement; // starting index inside the transform data
// resolved data references
const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
const Collada::Data* mTimeData; ///> Source data array for the time values
const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values
const Collada::Data* mValueData; ///> Source datat array for the key value values
ChannelEntry()
: mChannel()
, mTransformIndex()
, mSubElement()
, mTimeAccessor()
, mTimeData()
, mValueAccessor()
, mValueData()
{}
};
} // end of namespace Collada
} // end of namespace Assimp
#endif // AI_COLLADAHELPER_H_INC

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,251 @@
/** Defines the collada loader class */
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp 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 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.
----------------------------------------------------------------------
*/
#ifndef AI_COLLADALOADER_H_INC
#define AI_COLLADALOADER_H_INC
#include "BaseImporter.h"
#include "ColladaParser.h"
struct aiNode;
struct aiCamera;
struct aiLight;
struct aiTexture;
struct aiAnimation;
namespace Assimp
{
struct ColladaMeshIndex
{
std::string mMeshID;
size_t mSubMesh;
std::string mMaterial;
ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial)
: mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial)
{ }
bool operator < (const ColladaMeshIndex& p) const
{
if( mMeshID == p.mMeshID)
{
if( mSubMesh == p.mSubMesh)
return mMaterial < p.mMaterial;
else
return mSubMesh < p.mSubMesh;
} else
{
return mMeshID < p.mMeshID;
}
}
};
/** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing
* more useless stuff, so I limited the data to what I think is useful for games.
*/
class ColladaLoader : public BaseImporter
{
public:
ColladaLoader();
~ColladaLoader();
public:
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
protected:
/** Return importer meta information.
* See #BaseImporter::GetInfo for the details
*/
const aiImporterDesc* GetInfo () const;
void SetupProperties(const Importer* pImp);
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
/** Recursively constructs a scene node for the given parser node and returns it. */
aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
/** Resolve node instances */
void ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
std::vector<const Collada::Node*>& resolved);
/** Builds meshes for the given node and references them */
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
aiNode* pTarget);
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace);
/** Builds cameras for the given node and references them */
void BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode,
aiNode* pTarget);
/** Builds lights for the given node and references them */
void BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode,
aiNode* pTarget);
/** Stores all meshes in the given scene */
void StoreSceneMeshes( aiScene* pScene);
/** Stores all materials in the given scene */
void StoreSceneMaterials( aiScene* pScene);
/** Stores all lights in the given scene */
void StoreSceneLights( aiScene* pScene);
/** Stores all cameras in the given scene */
void StoreSceneCameras( aiScene* pScene);
/** Stores all textures in the given scene */
void StoreSceneTextures( aiScene* pScene);
/** Stores all animations
* @param pScene target scene to store the anims
*/
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser);
/** Stores all animations for the given source anim and its nested child animations
* @param pScene target scene to store the anims
* @param pSrcAnim the source animation to process
* @param pPrefix Prefix to the name in case of nested animations
*/
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pPrefix);
/** Constructs the animation for the given source anim */
void CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName);
/** Constructs materials from the collada material definitions */
void BuildMaterials( ColladaParser& pParser, aiScene* pScene);
/** Fill materials from the collada material definitions */
void FillMaterials( const ColladaParser& pParser, aiScene* pScene);
/** Resolve UV channel mappings*/
void ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
const Collada::SemanticMappingTable& table);
/** Add a texture and all of its sampling properties to a material*/
void AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
const Collada::Effect& effect,
const Collada::Sampler& sampler,
aiTextureType type, unsigned int idx = 0);
/** Resolves the texture name for the given effect texture entry */
aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
const Collada::Effect& pEffect, const std::string& pName);
/** Converts a path read from a collada file to the usual representation */
void ConvertPath( aiString& ss);
/** Reads a float value from an accessor and its data array.
* @param pAccessor The accessor to use for reading
* @param pData The data array to read from
* @param pIndex The index of the element to retrieve
* @param pOffset Offset into the element, for multipart elements such as vectors or matrices
* @return the specified value
*/
float ReadFloat( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const;
/** Reads a string value from an accessor and its data array.
* @param pAccessor The accessor to use for reading
* @param pData The data array to read from
* @param pIndex The index of the element to retrieve
* @return the specified value
*/
const std::string& ReadString( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const;
/** Recursively collects all nodes into the given array */
void CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const;
/** Finds a node in the collada scene by the given name */
const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName) const;
/** Finds a node in the collada scene by the given SID */
const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const;
/** Finds a proper name for a node derived from the collada-node's properties */
std::string FindNameForNode( const Collada::Node* pNode);
protected:
/** Filename, for a verbose error message */
std::string mFileName;
/** Which mesh-material compound was stored under which mesh ID */
std::map<ColladaMeshIndex, size_t> mMeshIndexByID;
/** Which material was stored under which index in the scene */
std::map<std::string, size_t> mMaterialIndexByName;
/** Accumulated meshes for the target scene */
std::vector<aiMesh*> mMeshes;
/** Temporary material list */
std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats;
/** Temporary camera list */
std::vector<aiCamera*> mCameras;
/** Temporary light list */
std::vector<aiLight*> mLights;
/** Temporary texture list */
std::vector<aiTexture*> mTextures;
/** Accumulated animations for the target scene */
std::vector<aiAnimation*> mAnims;
bool noSkeletonMesh;
bool ignoreUpDirection;
/** Used by FindNameForNode() to generate unique node names */
unsigned int mNodeNameCounter;
};
} // end of namespace Assimp
#endif // AI_COLLADALOADER_H_INC

Some files were not shown because too many files have changed in this diff Show more