vrshoot
view libs/assimp/MaterialSystem.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line source
1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
5 Copyright (c) 2006-2012, assimp team
6 All rights reserved.
8 Redistribution and use of this software in source and binary forms,
9 with or without modification, are permitted provided that the
10 following conditions are met:
12 * Redistributions of source code must retain the above
13 copyright notice, this list of conditions and the
14 following disclaimer.
16 * Redistributions in binary form must reproduce the above
17 copyright notice, this list of conditions and the
18 following disclaimer in the documentation and/or other
19 materials provided with the distribution.
21 * Neither the name of the assimp team, nor the names of its
22 contributors may be used to endorse or promote products
23 derived from this software without specific prior
24 written permission of the assimp team.
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ----------------------------------------------------------------------
39 */
41 /** @file MaterialSystem.cpp
42 * @brief Implementation of the material system of the library
43 */
45 #include "AssimpPCH.h"
47 #include "Hash.h"
48 #include "fast_atof.h"
49 #include "ParsingUtils.h"
50 #include "MaterialSystem.h"
52 using namespace Assimp;
54 // ------------------------------------------------------------------------------------------------
55 // Get a specific property from a material
56 aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
57 const char* pKey,
58 unsigned int type,
59 unsigned int index,
60 const aiMaterialProperty** pPropOut)
61 {
62 ai_assert (pMat != NULL);
63 ai_assert (pKey != NULL);
64 ai_assert (pPropOut != NULL);
66 /* Just search for a property with exactly this name ..
67 * could be improved by hashing, but it's possibly
68 * no worth the effort (we're bound to C structures,
69 * thus std::map or derivates are not applicable. */
70 for (unsigned int i = 0; i < pMat->mNumProperties;++i) {
71 aiMaterialProperty* prop = pMat->mProperties[i];
73 if (prop /* just for safety ... */
74 && 0 == strcmp( prop->mKey.data, pKey )
75 && (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wildcard, but this is undocumented :-) */
76 && (UINT_MAX == index || prop->mIndex == index))
77 {
78 *pPropOut = pMat->mProperties[i];
79 return AI_SUCCESS;
80 }
81 }
82 *pPropOut = NULL;
83 return AI_FAILURE;
84 }
86 // ------------------------------------------------------------------------------------------------
87 // Get an array of floating-point values from the material.
88 aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
89 const char* pKey,
90 unsigned int type,
91 unsigned int index,
92 float* pOut,
93 unsigned int* pMax)
94 {
95 ai_assert (pOut != NULL);
96 ai_assert (pMat != NULL);
98 const aiMaterialProperty* prop;
99 aiGetMaterialProperty(pMat,pKey,type,index, (const aiMaterialProperty**) &prop);
100 if (!prop) {
101 return AI_FAILURE;
102 }
104 // data is given in floats, simply copy it
105 unsigned int iWrite;
106 if( aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) {
107 iWrite = prop->mDataLength / sizeof(float);
108 if (pMax) {
109 iWrite = std::min(*pMax,iWrite); ;
110 }
111 for (unsigned int a = 0; a < iWrite;++a) {
112 pOut[a] = static_cast<float> ( reinterpret_cast<float*>(prop->mData)[a] );
113 }
114 if (pMax) {
115 *pMax = iWrite;
116 }
117 }
118 // data is given in ints, convert to float
119 else if( aiPTI_Integer == prop->mType) {
120 iWrite = prop->mDataLength / sizeof(int32_t);
121 if (pMax) {
122 iWrite = std::min(*pMax,iWrite); ;
123 }
124 for (unsigned int a = 0; a < iWrite;++a) {
125 pOut[a] = static_cast<float> ( reinterpret_cast<int32_t*>(prop->mData)[a] );
126 }
127 if (pMax) {
128 *pMax = iWrite;
129 }
130 }
131 // a string ... read floats separated by spaces
132 else {
133 if (pMax) {
134 iWrite = *pMax;
135 }
136 // strings are zero-terminated with a 32 bit length prefix, so this is safe
137 const char* cur = prop->mData+4;
138 ai_assert(prop->mDataLength>=5 && !prop->mData[prop->mDataLength-1]);
139 for (unsigned int a = 0; ;++a) {
140 cur = fast_atoreal_move<float>(cur,pOut[a]);
141 if(a==iWrite-1) {
142 break;
143 }
144 if(!IsSpace(*cur)) {
145 DefaultLogger::get()->error("Material property" + std::string(pKey) +
146 " is a string; failed to parse a float array out of it.");
147 return AI_FAILURE;
148 }
149 }
151 if (pMax) {
152 *pMax = iWrite;
153 }
154 }
155 return AI_SUCCESS;
157 }
159 // ------------------------------------------------------------------------------------------------
160 // Get an array if integers from the material
161 aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat,
162 const char* pKey,
163 unsigned int type,
164 unsigned int index,
165 int* pOut,
166 unsigned int* pMax)
167 {
168 ai_assert (pOut != NULL);
169 ai_assert (pMat != NULL);
171 const aiMaterialProperty* prop;
172 aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**) &prop);
173 if (!prop) {
174 return AI_FAILURE;
175 }
177 // data is given in ints, simply copy it
178 unsigned int iWrite;
179 if( aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) {
180 iWrite = prop->mDataLength / sizeof(int32_t);
181 if (pMax) {
182 iWrite = std::min(*pMax,iWrite); ;
183 }
184 for (unsigned int a = 0; a < iWrite;++a) {
185 pOut[a] = static_cast<int>(reinterpret_cast<int32_t*>(prop->mData)[a]);
186 }
187 if (pMax) {
188 *pMax = iWrite;
189 }
190 }
191 // data is given in floats convert to int
192 else if( aiPTI_Float == prop->mType) {
193 iWrite = prop->mDataLength / sizeof(float);
194 if (pMax) {
195 iWrite = std::min(*pMax,iWrite); ;
196 }
197 for (unsigned int a = 0; a < iWrite;++a) {
198 pOut[a] = static_cast<int>(reinterpret_cast<float*>(prop->mData)[a]);
199 }
200 if (pMax) {
201 *pMax = iWrite;
202 }
203 }
204 // it is a string ... no way to read something out of this
205 else {
206 if (pMax) {
207 iWrite = *pMax;
208 }
209 // strings are zero-terminated with a 32 bit length prefix, so this is safe
210 const char* cur = prop->mData+4;
211 ai_assert(prop->mDataLength>=5 && !prop->mData[prop->mDataLength-1]);
212 for (unsigned int a = 0; ;++a) {
213 pOut[a] = strtol10(cur,&cur);
214 if(a==iWrite-1) {
215 break;
216 }
217 if(!IsSpace(*cur)) {
218 DefaultLogger::get()->error("Material property" + std::string(pKey) +
219 " is a string; failed to parse an integer array out of it.");
220 return AI_FAILURE;
221 }
222 }
224 if (pMax) {
225 *pMax = iWrite;
226 }
227 }
228 return AI_SUCCESS;
229 }
231 // ------------------------------------------------------------------------------------------------
232 // Get a color (3 or 4 floats) from the material
233 aiReturn aiGetMaterialColor(const aiMaterial* pMat,
234 const char* pKey,
235 unsigned int type,
236 unsigned int index,
237 aiColor4D* pOut)
238 {
239 unsigned int iMax = 4;
240 const aiReturn eRet = aiGetMaterialFloatArray(pMat,pKey,type,index,(float*)pOut,&iMax);
242 // if no alpha channel is defined: set it to 1.0
243 if (3 == iMax) {
244 pOut->a = 1.0f;
245 }
247 return eRet;
248 }
250 // ------------------------------------------------------------------------------------------------
251 // Get a string from the material
252 aiReturn aiGetMaterialString(const aiMaterial* pMat,
253 const char* pKey,
254 unsigned int type,
255 unsigned int index,
256 aiString* pOut)
257 {
258 ai_assert (pOut != NULL);
260 const aiMaterialProperty* prop;
261 aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**)&prop);
262 if (!prop) {
263 return AI_FAILURE;
264 }
266 if( aiPTI_String == prop->mType) {
267 ai_assert(prop->mDataLength>=5);
269 // The string is stored as 32 but length prefix followed by zero-terminated UTF8 data
270 pOut->length = static_cast<unsigned int>(*reinterpret_cast<uint32_t*>(prop->mData));
272 ai_assert(pOut->length+1+4==prop->mDataLength && !prop->mData[prop->mDataLength-1]);
273 memcpy(pOut->data,prop->mData+4,pOut->length+1);
274 }
275 else {
276 // TODO - implement lexical cast as well
277 DefaultLogger::get()->error("Material property" + std::string(pKey) +
278 " was found, but is no string" );
279 return AI_FAILURE;
280 }
281 return AI_SUCCESS;
282 }
284 // ------------------------------------------------------------------------------------------------
285 // Get the number of textures on a particular texture stack
286 ASSIMP_API unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMat,
287 C_ENUM aiTextureType type)
288 {
289 ai_assert (pMat != NULL);
291 /* Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again) */
292 unsigned int max = 0;
293 for (unsigned int i = 0; i < pMat->mNumProperties;++i) {
294 aiMaterialProperty* prop = pMat->mProperties[i];
296 if (prop /* just a sanity check ... */
297 && 0 == strcmp( prop->mKey.data, _AI_MATKEY_TEXTURE_BASE )
298 && prop->mSemantic == type) {
300 max = std::max(max,prop->mIndex+1);
301 }
302 }
303 return max;
304 }
306 // ------------------------------------------------------------------------------------------------
307 aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat,
308 aiTextureType type,
309 unsigned int index,
310 C_STRUCT aiString* path,
311 aiTextureMapping* _mapping /*= NULL*/,
312 unsigned int* uvindex /*= NULL*/,
313 float* blend /*= NULL*/,
314 aiTextureOp* op /*= NULL*/,
315 aiTextureMapMode* mapmode /*= NULL*/,
316 unsigned int* flags /*= NULL*/
317 )
318 {
319 ai_assert(NULL != mat && NULL != path);
321 // Get the path to the texture
322 if (AI_SUCCESS != aiGetMaterialString(mat,AI_MATKEY_TEXTURE(type,index),path)) {
323 return AI_FAILURE;
324 }
325 // Determine mapping type
326 aiTextureMapping mapping = aiTextureMapping_UV;
327 aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index),(int*)&mapping);
328 if (_mapping)
329 *_mapping = mapping;
331 // Get UV index
332 if (aiTextureMapping_UV == mapping && uvindex) {
333 aiGetMaterialInteger(mat,AI_MATKEY_UVWSRC(type,index),(int*)uvindex);
334 }
335 // Get blend factor
336 if (blend) {
337 aiGetMaterialFloat(mat,AI_MATKEY_TEXBLEND(type,index),blend);
338 }
339 // Get texture operation
340 if (op){
341 aiGetMaterialInteger(mat,AI_MATKEY_TEXOP(type,index),(int*)op);
342 }
343 // Get texture mapping modes
344 if (mapmode) {
345 aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_U(type,index),(int*)&mapmode[0]);
346 aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_V(type,index),(int*)&mapmode[1]);
347 }
348 // Get texture flags
349 if (flags){
350 aiGetMaterialInteger(mat,AI_MATKEY_TEXFLAGS(type,index),(int*)flags);
351 }
352 return AI_SUCCESS;
353 }
355 // ------------------------------------------------------------------------------------------------
356 // Construction. Actually the one and only way to get an aiMaterial instance
357 aiMaterial::aiMaterial()
358 {
359 // Allocate 5 entries by default
360 mNumProperties = 0;
361 mNumAllocated = 5;
362 mProperties = new aiMaterialProperty*[5];
363 }
365 // ------------------------------------------------------------------------------------------------
366 aiMaterial::~aiMaterial()
367 {
368 Clear();
370 delete[] mProperties;
371 }
373 // ------------------------------------------------------------------------------------------------
374 void aiMaterial::Clear()
375 {
376 for (unsigned int i = 0; i < mNumProperties;++i) {
377 // delete this entry
378 delete mProperties[i];
379 AI_DEBUG_INVALIDATE_PTR(mProperties[i]);
380 }
381 mNumProperties = 0;
383 // The array remains allocated, we just invalidated its contents
384 }
386 // ------------------------------------------------------------------------------------------------
387 aiReturn aiMaterial::RemoveProperty (const char* pKey,unsigned int type,
388 unsigned int index
389 )
390 {
391 ai_assert(NULL != pKey);
393 for (unsigned int i = 0; i < mNumProperties;++i) {
394 aiMaterialProperty* prop = mProperties[i];
396 if (prop && !strcmp( prop->mKey.data, pKey ) &&
397 prop->mSemantic == type && prop->mIndex == index)
398 {
399 // Delete this entry
400 delete mProperties[i];
402 // collapse the array behind --.
403 --mNumProperties;
404 for (unsigned int a = i; a < mNumProperties;++a) {
405 mProperties[a] = mProperties[a+1];
406 }
407 return AI_SUCCESS;
408 }
409 }
411 return AI_FAILURE;
412 }
414 // ------------------------------------------------------------------------------------------------
415 aiReturn aiMaterial::AddBinaryProperty (const void* pInput,
416 unsigned int pSizeInBytes,
417 const char* pKey,
418 unsigned int type,
419 unsigned int index,
420 aiPropertyTypeInfo pType
421 )
422 {
423 ai_assert (pInput != NULL);
424 ai_assert (pKey != NULL);
425 ai_assert (0 != pSizeInBytes);
427 // first search the list whether there is already an entry with this key
428 unsigned int iOutIndex = UINT_MAX;
429 for (unsigned int i = 0; i < mNumProperties;++i) {
430 aiMaterialProperty* prop = mProperties[i];
432 if (prop /* just for safety */ && !strcmp( prop->mKey.data, pKey ) &&
433 prop->mSemantic == type && prop->mIndex == index){
435 delete mProperties[i];
436 iOutIndex = i;
437 }
438 }
440 // Allocate a new material property
441 aiMaterialProperty* pcNew = new aiMaterialProperty();
443 // .. and fill it
444 pcNew->mType = pType;
445 pcNew->mSemantic = type;
446 pcNew->mIndex = index;
448 pcNew->mDataLength = pSizeInBytes;
449 pcNew->mData = new char[pSizeInBytes];
450 memcpy (pcNew->mData,pInput,pSizeInBytes);
452 pcNew->mKey.length = ::strlen(pKey);
453 ai_assert ( MAXLEN > pcNew->mKey.length);
454 strcpy( pcNew->mKey.data, pKey );
456 if (UINT_MAX != iOutIndex) {
457 mProperties[iOutIndex] = pcNew;
458 return AI_SUCCESS;
459 }
461 // resize the array ... double the storage allocated
462 if (mNumProperties == mNumAllocated) {
463 const unsigned int iOld = mNumAllocated;
464 mNumAllocated *= 2;
466 aiMaterialProperty** ppTemp;
467 try {
468 ppTemp = new aiMaterialProperty*[mNumAllocated];
469 } catch (std::bad_alloc&) {
470 return AI_OUTOFMEMORY;
471 }
473 // just copy all items over; then replace the old array
474 memcpy (ppTemp,mProperties,iOld * sizeof(void*));
476 delete[] mProperties;
477 mProperties = ppTemp;
478 }
479 // push back ...
480 mProperties[mNumProperties++] = pcNew;
481 return AI_SUCCESS;
482 }
484 // ------------------------------------------------------------------------------------------------
485 aiReturn aiMaterial::AddProperty (const aiString* pInput,
486 const char* pKey,
487 unsigned int type,
488 unsigned int index)
489 {
490 // We don't want to add the whole buffer .. write a 32 bit length
491 // prefix followed by the zero-terminated UTF8 string.
492 // (HACK) I don't want to break the ABI now, but we definitely
493 // ought to change aiString::mLength to uint32_t one day.
494 if (sizeof(size_t) == 8) {
495 aiString copy = *pInput;
496 uint32_t* s = reinterpret_cast<uint32_t*>(©.length);
497 s[1] = static_cast<uint32_t>(pInput->length);
499 return AddBinaryProperty(s+1,
500 pInput->length+1+4,
501 pKey,
502 type,
503 index,
504 aiPTI_String);
505 }
506 ai_assert(sizeof(size_t)==4);
507 return AddBinaryProperty(pInput,
508 pInput->length+1+4,
509 pKey,
510 type,
511 index,
512 aiPTI_String);
513 }
515 // ------------------------------------------------------------------------------------------------
516 uint32_t Assimp :: ComputeMaterialHash(const aiMaterial* mat, bool includeMatName /*= false*/)
517 {
518 uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
519 for (unsigned int i = 0; i < mat->mNumProperties;++i) {
520 aiMaterialProperty* prop;
522 // Exclude all properties whose first character is '?' from the hash
523 // See doc for aiMaterialProperty.
524 if ((prop = mat->mProperties[i]) && (includeMatName || prop->mKey.data[0] != '?')) {
526 hash = SuperFastHash(prop->mKey.data,(unsigned int)prop->mKey.length,hash);
527 hash = SuperFastHash(prop->mData,prop->mDataLength,hash);
529 // Combine the semantic and the index with the hash
530 hash = SuperFastHash((const char*)&prop->mSemantic,sizeof(unsigned int),hash);
531 hash = SuperFastHash((const char*)&prop->mIndex,sizeof(unsigned int),hash);
532 }
533 }
534 return hash;
535 }
537 // ------------------------------------------------------------------------------------------------
538 void aiMaterial::CopyPropertyList(aiMaterial* pcDest,
539 const aiMaterial* pcSrc
540 )
541 {
542 ai_assert(NULL != pcDest);
543 ai_assert(NULL != pcSrc);
545 unsigned int iOldNum = pcDest->mNumProperties;
546 pcDest->mNumAllocated += pcSrc->mNumAllocated;
547 pcDest->mNumProperties += pcSrc->mNumProperties;
549 aiMaterialProperty** pcOld = pcDest->mProperties;
550 pcDest->mProperties = new aiMaterialProperty*[pcDest->mNumAllocated];
552 if (iOldNum && pcOld) {
553 for (unsigned int i = 0; i < iOldNum;++i) {
554 pcDest->mProperties[i] = pcOld[i];
555 }
557 delete[] pcOld;
558 }
559 for (unsigned int i = iOldNum; i< pcDest->mNumProperties;++i) {
560 aiMaterialProperty* propSrc = pcSrc->mProperties[i];
562 // search whether we have already a property with this name -> if yes, overwrite it
563 aiMaterialProperty* prop;
564 for (unsigned int q = 0; q < iOldNum;++q) {
565 prop = pcDest->mProperties[q];
566 if (prop /* just for safety */ && prop->mKey == propSrc->mKey && prop->mSemantic == propSrc->mSemantic
567 && prop->mIndex == propSrc->mIndex) {
568 delete prop;
570 // collapse the whole array ...
571 memmove(&pcDest->mProperties[q],&pcDest->mProperties[q+1],i-q);
572 i--;
573 pcDest->mNumProperties--;
574 }
575 }
577 // Allocate the output property and copy the source property
578 prop = pcDest->mProperties[i] = new aiMaterialProperty();
579 prop->mKey = propSrc->mKey;
580 prop->mDataLength = propSrc->mDataLength;
581 prop->mType = propSrc->mType;
582 prop->mSemantic = propSrc->mSemantic;
583 prop->mIndex = propSrc->mIndex;
585 prop->mData = new char[propSrc->mDataLength];
586 memcpy(prop->mData,propSrc->mData,prop->mDataLength);
587 }
588 return;
589 }