Initial support for FBX embedded textures
parent
916cfb9d53
commit
f94bc8d66e
|
@ -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) {
|
||||
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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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,60 @@ 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;
|
||||
contentLength = 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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue