1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42/** @file FBXMaterial.cpp
43 * @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation
44 */
45
46#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
47
48#include "FBXParser.h"
49#include "FBXDocument.h"
50#include "FBXImporter.h"
51#include "FBXImportSettings.h"
52#include "FBXDocumentUtil.h"
53#include "FBXProperties.h"
54#include "ByteSwapper.h"
55
56namespace Assimp {
57namespace FBX {
58
59 using namespace Util;
60
61// ------------------------------------------------------------------------------------------------
62Material::Material(uint64_t id, const Element& element, const Document& doc, const std::string& name)
63: Object(id,element,name)
64{
65 const Scope& sc = GetRequiredScope(element);
66
67 const Element* const ShadingModel = sc["ShadingModel"];
68 const Element* const MultiLayer = sc["MultiLayer"];
69
70 if(MultiLayer) {
71 multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0));
72 }
73
74 if(ShadingModel) {
75 shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0));
76 }
77 else {
78 DOMWarning("shading mode not specified, assuming phong",&element);
79 shading = "phong";
80 }
81
82 std::string templateName;
83
84 const char* const sh = shading.c_str();
85 if(!strcmp(sh,"phong")) {
86 templateName = "Material.FbxSurfacePhong";
87 }
88 else if(!strcmp(sh,"lambert")) {
89 templateName = "Material.FbxSurfaceLambert";
90 }
91 else {
92 DOMWarning("shading mode not recognized: " + shading,&element);
93 }
94
95 props = GetPropertyTable(doc,templateName,element,sc);
96
97 // resolve texture links
98 const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
99 for(const Connection* con : conns) {
100
101 // texture link to properties, not objects
102 if (!con->PropertyName().length()) {
103 continue;
104 }
105
106 const Object* const ob = con->SourceObject();
107 if(!ob) {
108 DOMWarning("failed to read source object for texture link, ignoring",&element);
109 continue;
110 }
111
112 const Texture* const tex = dynamic_cast<const Texture*>(ob);
113 if(!tex) {
114 const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
115 if(!layeredTexture) {
116 DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
117 continue;
118 }
119 const std::string& prop = con->PropertyName();
120 if (layeredTextures.find(prop) != layeredTextures.end()) {
121 DOMWarning("duplicate layered texture link: " + prop,&element);
122 }
123
124 layeredTextures[prop] = layeredTexture;
125 ((LayeredTexture*)layeredTexture)->fillTexture(doc);
126 }
127 else
128 {
129 const std::string& prop = con->PropertyName();
130 if (textures.find(prop) != textures.end()) {
131 DOMWarning("duplicate texture link: " + prop,&element);
132 }
133
134 textures[prop] = tex;
135 }
136
137 }
138}
139
140
141// ------------------------------------------------------------------------------------------------
142Material::~Material()
143{
144}
145
146
147// ------------------------------------------------------------------------------------------------
148Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name)
149: Object(id,element,name)
150, uvScaling(1.0f,1.0f)
151, media(0)
152{
153 const Scope& sc = GetRequiredScope(element);
154
155 const Element* const Type = sc["Type"];
156 const Element* const FileName = sc["FileName"];
157 const Element* const RelativeFilename = sc["RelativeFilename"];
158 const Element* const ModelUVTranslation = sc["ModelUVTranslation"];
159 const Element* const ModelUVScaling = sc["ModelUVScaling"];
160 const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"];
161 const Element* const Cropping = sc["Cropping"];
162
163 if(Type) {
164 type = ParseTokenAsString(GetRequiredToken(*Type,0));
165 }
166
167 if(FileName) {
168 fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
169 }
170
171 if(RelativeFilename) {
172 relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
173 }
174
175 if(ModelUVTranslation) {
176 uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)),
177 ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1))
178 );
179 }
180
181 if(ModelUVScaling) {
182 uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)),
183 ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1))
184 );
185 }
186
187 if(Cropping) {
188 crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0));
189 crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1));
190 crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2));
191 crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3));
192 }
193 else {
194 // vc8 doesn't support the crop() syntax in initialization lists
195 // (and vc9 WARNS about the new (i.e. compliant) behaviour).
196 crop[0] = crop[1] = crop[2] = crop[3] = 0;
197 }
198
199 if(Texture_Alpha_Source) {
200 alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0));
201 }
202
203 props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
204
205 // resolve video links
206 if(doc.Settings().readTextures) {
207 const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
208 for(const Connection* con : conns) {
209 const Object* const ob = con->SourceObject();
210 if(!ob) {
211 DOMWarning("failed to read source object for texture link, ignoring",&element);
212 continue;
213 }
214
215 const Video* const video = dynamic_cast<const Video*>(ob);
216 if(video) {
217 media = video;
218 }
219 }
220 }
221}
222
223
224Texture::~Texture()
225{
226
227}
228
229LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& /*doc*/, const std::string& name)
230: Object(id,element,name)
231,blendMode(BlendMode_Modulate)
232,alpha(1)
233{
234 const Scope& sc = GetRequiredScope(element);
235
236 const Element* const BlendModes = sc["BlendModes"];
237 const Element* const Alphas = sc["Alphas"];
238
239
240 if(BlendModes!=0)
241 {
242 blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0));
243 }
244 if(Alphas!=0)
245 {
246 alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0));
247 }
248}
249
250LayeredTexture::~LayeredTexture()
251{
252
253}
254
255void LayeredTexture::fillTexture(const Document& doc)
256{
257 const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
258 for(size_t i = 0; i < conns.size();++i)
259 {
260 const Connection* con = conns.at(i);
261
262 const Object* const ob = con->SourceObject();
263 if(!ob) {
264 DOMWarning("failed to read source object for texture link, ignoring",&element);
265 continue;
266 }
267
268 const Texture* const tex = dynamic_cast<const Texture*>(ob);
269
270 textures.push_back(tex);
271 }
272}
273
274
275// ------------------------------------------------------------------------------------------------
276Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name)
277: Object(id,element,name)
278, contentLength(0)
279, content(0)
280{
281 const Scope& sc = GetRequiredScope(element);
282
283 const Element* const Type = sc["Type"];
284 const Element* const FileName = sc.FindElementCaseInsensitive("FileName"); //some files retain the information as "Filename", others "FileName", who knows
285 const Element* const RelativeFilename = sc["RelativeFilename"];
286 const Element* const Content = sc["Content"];
287
288 if(Type) {
289 type = ParseTokenAsString(GetRequiredToken(*Type,0));
290 }
291
292 if(FileName) {
293 fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
294 }
295
296 if(RelativeFilename) {
297 relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
298 }
299
300 if(Content) {
301 //this field is ommited when the embedded texture is already loaded, let's ignore if itīs not found
302 try {
303 const Token& token = GetRequiredToken(*Content, 0);
304 const char* data = token.begin();
305 if (!token.IsBinary()) {
306 DOMWarning("video content is not binary data, ignoring", &element);
307 }
308 else if (static_cast<size_t>(token.end() - data) < 5) {
309 DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element);
310 }
311 else if (*data != 'R') {
312 DOMWarning("video content is not raw binary data, ignoring", &element);
313 }
314 else {
315 // read number of elements
316 uint32_t len = 0;
317 ::memcpy(&len, data + 1, sizeof(len));
318 AI_SWAP4(len);
319
320 contentLength = len;
321
322 content = new uint8_t[len];
323 ::memcpy(content, data + 5, len);
324 }
325 } catch (runtime_error runtimeError) {
326 //we donīt need the content data for contents that has already been loaded
327 }
328 }
329
330 props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
331}
332
333
334Video::~Video()
335{
336 if(content) {
337 delete[] content;
338 }
339}
340
341} //!FBX
342} //!Assimp
343
344#endif
345