Merge pull request #694 from OtgerRP/master

Support for FBX embedded textures
pull/697/head
Kim Kulling 2015-11-24 21:26:34 +01:00
commit 65d366dad0
9 changed files with 229 additions and 0 deletions

View File

@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXUtil.h"
#include "FBXProperties.h"
#include "FBXImporter.h"
#include "StringComparison.h"
#include "../include/assimp/scene.h"
#include <boost/foreach.hpp>
#include <boost/scoped_array.hpp>
@ -148,6 +149,7 @@ public:
std::for_each(animations.begin(),animations.end(),Util::delete_fun<aiAnimation>());
std::for_each(lights.begin(),lights.end(),Util::delete_fun<aiLight>());
std::for_each(cameras.begin(),cameras.end(),Util::delete_fun<aiCamera>());
std::for_each(textures.begin(),textures.end(),Util::delete_fun<aiTexture>());
}
@ -1449,6 +1451,36 @@ private:
return static_cast<unsigned int>(materials.size() - 1);
}
// ------------------------------------------------------------------------------------------------
// Video -> aiTexture
unsigned int ConvertVideo(const Video& video)
{
// generate empty output texture
aiTexture* out_tex = new aiTexture();
textures.push_back(out_tex);
// assuming the texture is compressed
out_tex->mWidth = static_cast<unsigned int>(video.ContentLength()); // total data size
out_tex->mHeight = 0; // fixed to 0
// steal the data from the Video to avoid an additional copy
out_tex->pcData = reinterpret_cast<aiTexel*>( const_cast<Video&>(video).RelinquishContent() );
// try to extract a hint from the file extension
const std::string& filename = video.FileName().empty() ? video.RelativeFilename() : video.FileName();
std::string ext = BaseImporter::GetExtension(filename);
if(ext == "jpeg") {
ext = "jpg";
}
if(ext.size() <= 3) {
memcpy(out_tex->achFormatHint, ext.c_str(), ext.size());
}
return static_cast<unsigned int>(textures.size() - 1);
}
// ------------------------------------------------------------------------------------------------
void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
@ -1466,6 +1498,24 @@ private:
aiString path;
path.Set(tex->RelativeFilename());
const Video* media = tex->Media();
if(media != 0 && media->ContentLength() > 0) {
unsigned int index;
VideoMap::const_iterator it = textures_converted.find(media);
if(it != textures_converted.end()) {
index = (*it).second;
}
else {
index = ConvertVideo(*media);
textures_converted[media] = index;
}
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
path.data[0] = '*';
path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
}
out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0);
aiUVTransform uvTrafo;
@ -3024,6 +3074,13 @@ private:
std::swap_ranges(cameras.begin(),cameras.end(),out->mCameras);
}
if(textures.size()) {
out->mTextures = new aiTexture*[textures.size()]();
out->mNumTextures = static_cast<unsigned int>(textures.size());
std::swap_ranges(textures.begin(),textures.end(),out->mTextures);
}
}
@ -3037,10 +3094,14 @@ private:
std::vector<aiAnimation*> animations;
std::vector<aiLight*> lights;
std::vector<aiCamera*> cameras;
std::vector<aiTexture*> textures;
typedef std::map<const Material*, unsigned int> MaterialMap;
MaterialMap materials_converted;
typedef std::map<const Video*, unsigned int> VideoMap;
VideoMap textures_converted;
typedef std::map<const Geometry*, std::vector<unsigned int> > MeshMap;
MeshMap meshes_converted;

View File

@ -180,6 +180,9 @@ const Object* LazyObject::Get(bool dieOnError)
else if (!strncmp(obtype,"LayeredTexture",length)) {
object.reset(new LayeredTexture(id,element,doc,name));
}
else if (!strncmp(obtype,"Video",length)) {
object.reset(new Video(id,element,doc,name));
}
else if (!strncmp(obtype,"AnimationStack",length)) {
object.reset(new AnimationStack(id,element,name,doc));
}
@ -483,6 +486,11 @@ void Document::ReadConnections()
for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
const Element& el = *(*it).second;
const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
// PP = property-property connection, ignored for now
// (tokens: "PP", ID1, "Property1", ID2, "Property2")
if(type == "PP") continue;
const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));

View File

@ -73,6 +73,8 @@ namespace FBX {
class Material;
class Geometry;
class Video;
class AnimationCurve;
class AnimationCurveNode;
class AnimationLayer;
@ -571,6 +573,10 @@ public:
return crop;
}
const Video* Media() const {
return media;
}
private:
aiVector2D uvTrans;
@ -583,6 +589,8 @@ private:
boost::shared_ptr<const PropertyTable> props;
unsigned int crop[4];
const Video* media;
};
/** DOM class for layered FBX textures */
@ -654,6 +662,59 @@ typedef std::fbx_unordered_map<std::string, const Texture*> TextureMap;
typedef std::fbx_unordered_map<std::string, const LayeredTexture*> LayeredTextureMap;
/** DOM class for generic FBX videos */
class Video : public Object
{
public:
Video(uint64_t id, const Element& element, const Document& doc, const std::string& name);
~Video();
public:
const std::string& Type() const {
return type;
}
const std::string& FileName() const {
return fileName;
}
const std::string& RelativeFilename() const {
return relativeFileName;
}
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
}
const uint8_t* Content() const {
ai_assert(content);
return content;
}
const uint32_t ContentLength() const {
return contentLength;
}
uint8_t* RelinquishContent() {
uint8_t* ptr = content;
content = 0;
return ptr;
}
private:
std::string type;
std::string relativeFileName;
std::string fileName;
boost::shared_ptr<const PropertyTable> props;
uint32_t contentLength;
uint8_t* content;
};
/** DOM class for generic FBX materials */
class Material : public Object
{

View File

@ -55,6 +55,7 @@ struct ImportSettings
, readAllLayers(true)
, readAllMaterials(false)
, readMaterials(true)
, readTextures(true)
, readCameras(true)
, readLights(true)
, readAnimations(true)
@ -92,6 +93,9 @@ struct ImportSettings
* material. The default value is true.*/
bool readMaterials;
/** import embedded textures? Default value is true.*/
bool readTextures;
/** import cameras? Default value is true.*/
bool readCameras;

View File

@ -126,6 +126,7 @@ void FBXImporter::SetupProperties(const Importer* pImp)
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);

View File

@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXImportSettings.h"
#include "FBXDocumentUtil.h"
#include "FBXProperties.h"
#include "ByteSwapper.h"
#include <boost/foreach.hpp>
namespace Assimp {
@ -147,6 +148,7 @@ Material::~Material()
Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: Object(id,element,name)
, uvScaling(1.0f,1.0f)
, media(0)
{
const Scope& sc = GetRequiredScope(element);
@ -199,6 +201,23 @@ Texture::Texture(uint64_t id, const Element& element, const Document& doc, const
}
props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
// resolve video links
if(doc.Settings().readTextures) {
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
BOOST_FOREACH(const Connection* con, conns) {
const Object* const ob = con->SourceObject();
if(!ob) {
DOMWarning("failed to read source object for texture link, ignoring",&element);
continue;
}
const Video* const video = dynamic_cast<const Video*>(ob);
if(video) {
media = video;
}
}
}
}
@ -253,6 +272,68 @@ void LayeredTexture::fillTexture(const Document& doc)
}
}
// ------------------------------------------------------------------------------------------------
Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: Object(id,element,name)
, contentLength(0)
, content(0)
{
const Scope& sc = GetRequiredScope(element);
const Element* const Type = sc["Type"];
const Element* const FileName = sc["FileName"];
const Element* const RelativeFilename = sc["RelativeFilename"];
const Element* const Content = sc["Content"];
if(Type) {
type = ParseTokenAsString(GetRequiredToken(*Type,0));
}
if(FileName) {
fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
}
if(RelativeFilename) {
relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
}
if(Content) {
const Token& token = GetRequiredToken(*Content, 0);
const char* data = token.begin();
if(!token.IsBinary()) {
DOMWarning("video content is not binary data, ignoring", &element);
}
else if(static_cast<size_t>(token.end() - data) < 5) {
DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element);
}
else if(*data != 'R') {
DOMWarning("video content is not raw binary data, ignoring", &element);
}
else {
// read number of elements
uint32_t len = 0;
::memcpy(&len, data + 1, sizeof(len));
AI_SWAP4(len);
contentLength = len;
content = new uint8_t[len];
::memcpy(content, data + 5, len);
}
}
props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
}
Video::~Video()
{
if(content) {
delete[] content;
}
}
} //!FBX
} //!Assimp

View File

@ -561,6 +561,15 @@ enum aiComponent
#define AI_CONFIG_IMPORT_FBX_READ_MATERIALS \
"IMPORT_FBX_READ_MATERIALS"
// ---------------------------------------------------------------------------
/** @brief Set whether the fbx importer will read embedded textures.
*
* The default value is true (1)
* Property type: bool
*/
#define AI_CONFIG_IMPORT_FBX_READ_TEXTURES \
"IMPORT_FBX_READ_TEXTURES"
// ---------------------------------------------------------------------------
/** @brief Set whether the fbx importer will read cameras.
*

View File

@ -116,6 +116,10 @@ struct aiTexel
* 2. Compressed textures stored in a file format like png or jpg. The raw file
* bytes are given so the application must utilize an image decoder (e.g. DevIL) to
* get access to the actual color data.
*
* Embedded textures are referenced from materials using strings like "*0", "*1", etc.
* as the texture paths (a single asterisk character followed by the
* zero-based index of the texture in the aiScene::mTextures array).
*/
struct aiTexture
{

Binary file not shown.