#ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
#include <stdlib.h>
#include "ObjFileMtlImporter.h"
#include "ObjTools.h"
#include "ObjFileData.h"
#include "fast_atof.h"
#include "ParsingUtils.h"
#include <assimp/material.h>
#include <assimp/DefaultLogger.hpp>
namespace Assimp {
static const std::string DiffuseTexture = "map_Kd";
static const std::string AmbientTexture = "map_Ka";
static const std::string SpecularTexture = "map_Ks";
static const std::string OpacityTexture = "map_d";
static const std::string EmissiveTexture = "map_emissive";
static const std::string EmissiveTexture_1 = "map_Ke";
static const std::string BumpTexture1 = "map_bump";
static const std::string BumpTexture2 = "map_Bump";
static const std::string BumpTexture3 = "bump";
static const std::string NormalTexture = "map_Kn";
static const std::string ReflectionTexture = "refl";
static const std::string DisplacementTexture = "disp";
static const std::string SpecularityTexture = "map_ns";
static const std::string BlendUOption = "-blendu";
static const std::string BlendVOption = "-blendv";
static const std::string BoostOption = "-boost";
static const std::string ModifyMapOption = "-mm";
static const std::string OffsetOption = "-o";
static const std::string ScaleOption = "-s";
static const std::string TurbulenceOption = "-t";
static const std::string ResolutionOption = "-texres";
static const std::string ClampOption = "-clamp";
static const std::string BumpOption = "-bm";
static const std::string ChannelOption = "-imfchan";
static const std::string TypeOption = "-type";
ObjFileMtlImporter::ObjFileMtlImporter( std::vector<char> &buffer,
const std::string &,
ObjFile::Model *pModel ) :
m_DataIt( buffer.begin() ),
m_DataItEnd( buffer.end() ),
m_pModel( pModel ),
m_uiLine( 0 )
{
ai_assert( NULL != m_pModel );
if ( NULL == m_pModel->m_pDefaultMaterial )
{
m_pModel->m_pDefaultMaterial = new ObjFile::Material;
m_pModel->m_pDefaultMaterial->MaterialName.Set( "default" );
}
load();
}
ObjFileMtlImporter::~ObjFileMtlImporter()
{
}
ObjFileMtlImporter::ObjFileMtlImporter(const ObjFileMtlImporter & )
{
}
ObjFileMtlImporter &ObjFileMtlImporter::operator = ( const ObjFileMtlImporter & )
{
return *this;
}
void ObjFileMtlImporter::load()
{
if ( m_DataIt == m_DataItEnd )
return;
while ( m_DataIt != m_DataItEnd )
{
switch (*m_DataIt)
{
case 'k':
case 'K':
{
++m_DataIt;
if (*m_DataIt == 'a') {
++m_DataIt;
getColorRGBA( &m_pModel->m_pCurrentMaterial->ambient );
}
else if (*m_DataIt == 'd') {
++m_DataIt;
getColorRGBA( &m_pModel->m_pCurrentMaterial->diffuse );
}
else if (*m_DataIt == 's')
{
++m_DataIt;
getColorRGBA( &m_pModel->m_pCurrentMaterial->specular );
}
else if (*m_DataIt == 'e')
{
++m_DataIt;
getColorRGBA( &m_pModel->m_pCurrentMaterial->emissive );
}
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
}
break;
case 'T':
{
++m_DataIt;
if (*m_DataIt == 'f') {
++m_DataIt;
getColorRGBA( &m_pModel->m_pCurrentMaterial->transparent);
}
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
}
break;
case 'd':
{
if( *(m_DataIt+1) == 'i' && *( m_DataIt + 2 ) == 's' && *( m_DataIt + 3 ) == 'p' ) {
getTexture();
} else {
++m_DataIt;
getFloatValue( m_pModel->m_pCurrentMaterial->alpha );
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
}
}
break;
case 'N':
case 'n':
{
++m_DataIt;
switch(*m_DataIt)
{
case 's': ++m_DataIt;
getFloatValue(m_pModel->m_pCurrentMaterial->shineness);
break;
case 'i': ++m_DataIt;
getFloatValue(m_pModel->m_pCurrentMaterial->ior);
break;
case 'e': createMaterial();
break;
}
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
}
break;
case 'm': case 'b': case 'r': {
getTexture();
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
}
break;
case 'i': {
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
getIlluminationModel( m_pModel->m_pCurrentMaterial->illumination_model );
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
}
break;
default:
{
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
}
break;
}
}
}
void ObjFileMtlImporter::getColorRGBA( aiColor3D *pColor )
{
ai_assert( NULL != pColor );
ai_real r( 0.0 ), g( 0.0 ), b( 0.0 );
m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, r );
pColor->r = r;
if( !IsLineEnd( *m_DataIt ) ) {
m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, g );
m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, b );
}
pColor->g = g;
pColor->b = b;
}
void ObjFileMtlImporter::getIlluminationModel( int &illum_model )
{
m_DataIt = CopyNextWord<DataArrayIt>( m_DataIt, m_DataItEnd, m_buffer, BUFFERSIZE );
illum_model = atoi(m_buffer);
}
void ObjFileMtlImporter::getFloatValue( ai_real &value )
{
m_DataIt = CopyNextWord<DataArrayIt>( m_DataIt, m_DataItEnd, m_buffer, BUFFERSIZE );
value = (ai_real) fast_atof(m_buffer);
}
void ObjFileMtlImporter::createMaterial()
{
std::string line( "" );
while( !IsLineEnd( *m_DataIt ) ) {
line += *m_DataIt;
++m_DataIt;
}
std::vector<std::string> token;
const unsigned int numToken = tokenize<std::string>( line, token, " \t" );
std::string name( "" );
if ( numToken == 1 ) {
name = AI_DEFAULT_MATERIAL_NAME;
} else {
std::size_t first_ws_pos = line.find_first_of(" \t");
std::size_t first_non_ws_pos = line.find_first_not_of(" \t", first_ws_pos);
if (first_non_ws_pos != std::string::npos) {
name = line.substr(first_non_ws_pos);
}
}
name = trim_whitespaces(name);
std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( name );
if ( m_pModel->m_MaterialMap.end() == it) {
m_pModel->m_pCurrentMaterial = new ObjFile::Material();
m_pModel->m_pCurrentMaterial->MaterialName.Set( name );
if (m_pModel->m_pCurrentMesh) {
m_pModel->m_pCurrentMesh->m_uiMaterialIndex = m_pModel->m_MaterialLib.size() - 1;
}
m_pModel->m_MaterialLib.push_back( name );
m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial;
} else {
m_pModel->m_pCurrentMaterial = (*it).second;
}
}
void ObjFileMtlImporter::getTexture() {
aiString *out( NULL );
int clampIndex = -1;
const char *pPtr( &(*m_DataIt) );
if ( !ASSIMP_strincmp( pPtr, DiffuseTexture.c_str(), static_cast<unsigned int>(DiffuseTexture.size()) ) ) {
out = & m_pModel->m_pCurrentMaterial->texture;
clampIndex = ObjFile::Material::TextureDiffuseType;
} else if ( !ASSIMP_strincmp( pPtr,AmbientTexture.c_str(), static_cast<unsigned int>(AmbientTexture.size()) ) ) {
out = & m_pModel->m_pCurrentMaterial->textureAmbient;
clampIndex = ObjFile::Material::TextureAmbientType;
} else if (!ASSIMP_strincmp( pPtr, SpecularTexture.c_str(), static_cast<unsigned int>(SpecularTexture.size()) ) ) {
out = & m_pModel->m_pCurrentMaterial->textureSpecular;
clampIndex = ObjFile::Material::TextureSpecularType;
} else if ( !ASSIMP_strincmp( pPtr, OpacityTexture.c_str(), static_cast<unsigned int>(OpacityTexture.size()) ) ) {
out = & m_pModel->m_pCurrentMaterial->textureOpacity;
clampIndex = ObjFile::Material::TextureOpacityType;
} else if (!ASSIMP_strincmp( pPtr, EmissiveTexture.c_str(), static_cast<unsigned int>(EmissiveTexture.size()) ) ) {
out = & m_pModel->m_pCurrentMaterial->textureEmissive;
clampIndex = ObjFile::Material::TextureEmissiveType;
} else if ( !ASSIMP_strincmp( pPtr, EmissiveTexture_1.c_str(), static_cast<unsigned int>(EmissiveTexture_1.size()) ) ) {
out = &m_pModel->m_pCurrentMaterial->textureEmissive;
clampIndex = ObjFile::Material::TextureEmissiveType;
} else if ( !ASSIMP_strincmp( pPtr, BumpTexture1.c_str(), static_cast<unsigned int>(BumpTexture1.size()) ) ||
!ASSIMP_strincmp( pPtr, BumpTexture2.c_str(), static_cast<unsigned int>(BumpTexture2.size()) ) ||
!ASSIMP_strincmp( pPtr, BumpTexture3.c_str(), static_cast<unsigned int>(BumpTexture3.size()) ) ) {
out = & m_pModel->m_pCurrentMaterial->textureBump;
clampIndex = ObjFile::Material::TextureBumpType;
} else if (!ASSIMP_strincmp( pPtr,NormalTexture.c_str(), static_cast<unsigned int>(NormalTexture.size()) ) ) {
out = & m_pModel->m_pCurrentMaterial->textureNormal;
clampIndex = ObjFile::Material::TextureNormalType;
} else if(!ASSIMP_strincmp( pPtr, ReflectionTexture.c_str(), static_cast<unsigned int>(ReflectionTexture.size()) ) ) {
return;
} else if (!ASSIMP_strincmp( pPtr, DisplacementTexture.c_str(), static_cast<unsigned int>(DisplacementTexture.size()) ) ) {
out = &m_pModel->m_pCurrentMaterial->textureDisp;
clampIndex = ObjFile::Material::TextureDispType;
} else if (!ASSIMP_strincmp( pPtr, SpecularityTexture.c_str(), static_cast<unsigned int>(SpecularityTexture.size()) ) ) {
out = & m_pModel->m_pCurrentMaterial->textureSpecularity;
clampIndex = ObjFile::Material::TextureSpecularityType;
} else {
DefaultLogger::get()->error("OBJ/MTL: Encountered unknown texture type");
return;
}
bool clamp = false;
getTextureOption(clamp, clampIndex, out);
m_pModel->m_pCurrentMaterial->clamp[clampIndex] = clamp;
std::string texture;
m_DataIt = getName<DataArrayIt>( m_DataIt, m_DataItEnd, texture );
if ( NULL!=out ) {
out->Set( texture );
}
}
void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString *&out) {
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
while (!isEndOfBuffer(m_DataIt, m_DataItEnd) && *m_DataIt == '-')
{
const char *pPtr( &(*m_DataIt) );
int skipToken = 1;
if (!ASSIMP_strincmp(pPtr, ClampOption.c_str(), static_cast<unsigned int>(ClampOption.size())))
{
DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
char value[3];
CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
if (!ASSIMP_strincmp(value, "on", 2))
{
clamp = true;
}
skipToken = 2;
}
else if( !ASSIMP_strincmp( pPtr, TypeOption.c_str(), static_cast<unsigned int>(TypeOption.size()) ) )
{
DataArrayIt it = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
char value[ 12 ];
CopyNextWord( it, m_DataItEnd, value, sizeof( value ) / sizeof( *value ) );
if( !ASSIMP_strincmp( value, "cube_top", 8 ) )
{
clampIndex = ObjFile::Material::TextureReflectionCubeTopType;
out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
}
else if( !ASSIMP_strincmp( value, "cube_bottom", 11 ) )
{
clampIndex = ObjFile::Material::TextureReflectionCubeBottomType;
out = &m_pModel->m_pCurrentMaterial->textureReflection[1];
}
else if( !ASSIMP_strincmp( value, "cube_front", 10 ) )
{
clampIndex = ObjFile::Material::TextureReflectionCubeFrontType;
out = &m_pModel->m_pCurrentMaterial->textureReflection[2];
}
else if( !ASSIMP_strincmp( value, "cube_back", 9 ) )
{
clampIndex = ObjFile::Material::TextureReflectionCubeBackType;
out = &m_pModel->m_pCurrentMaterial->textureReflection[3];
}
else if( !ASSIMP_strincmp( value, "cube_left", 9 ) )
{
clampIndex = ObjFile::Material::TextureReflectionCubeLeftType;
out = &m_pModel->m_pCurrentMaterial->textureReflection[4];
}
else if( !ASSIMP_strincmp( value, "cube_right", 10 ) )
{
clampIndex = ObjFile::Material::TextureReflectionCubeRightType;
out = &m_pModel->m_pCurrentMaterial->textureReflection[5];
}
else if( !ASSIMP_strincmp( value, "sphere", 6 ) )
{
clampIndex = ObjFile::Material::TextureReflectionSphereType;
out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
}
skipToken = 2;
}
else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size()))
|| !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size()))
|| !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size()))
|| !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size()))
|| !ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size()))
|| !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size())))
{
skipToken = 2;
}
else if (!ASSIMP_strincmp(pPtr, ModifyMapOption.c_str(), static_cast<unsigned int>(ModifyMapOption.size())))
{
skipToken = 3;
}
else if ( !ASSIMP_strincmp(pPtr, OffsetOption.c_str(), static_cast<unsigned int>(OffsetOption.size()))
|| !ASSIMP_strincmp(pPtr, ScaleOption.c_str(), static_cast<unsigned int>(ScaleOption.size()))
|| !ASSIMP_strincmp(pPtr, TurbulenceOption.c_str(), static_cast<unsigned int>(TurbulenceOption.size()))
)
{
skipToken = 4;
}
for (int i = 0; i < skipToken; ++i)
{
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
}
}
}
}
#endif