nuclear@0: /* nuclear@0: --------------------------------------------------------------------------- nuclear@0: Open Asset Import Library (assimp) nuclear@0: --------------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the following nuclear@0: conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: --------------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file Implementation of the material part of the MDL importer class */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #ifndef ASSIMP_BUILD_NO_MDL_IMPORTER nuclear@0: nuclear@0: // internal headers nuclear@0: #include "MDLLoader.h" nuclear@0: #include "MDLDefaultColorMap.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: static aiTexel* const bad_texel = reinterpret_cast(SIZE_MAX); nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Find a suitable pallette file or take teh default one nuclear@0: void MDLImporter::SearchPalette(const unsigned char** pszColorMap) nuclear@0: { nuclear@0: // now try to find the color map in the current directory nuclear@0: IOStream* pcStream = pIOHandler->Open(configPalette,"rb"); nuclear@0: nuclear@0: const unsigned char* szColorMap = (const unsigned char*)::g_aclrDefaultColorMap; nuclear@0: if(pcStream) nuclear@0: { nuclear@0: if (pcStream->FileSize() >= 768) nuclear@0: { nuclear@0: unsigned char* colorMap = new unsigned char[256*3]; nuclear@0: szColorMap = colorMap; nuclear@0: pcStream->Read(colorMap,256*3,1); nuclear@0: DefaultLogger::get()->info("Found valid colormap.lmp in directory. " nuclear@0: "It will be used to decode embedded textures in palletized formats."); nuclear@0: } nuclear@0: delete pcStream; nuclear@0: pcStream = NULL; nuclear@0: } nuclear@0: *pszColorMap = szColorMap; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Free the palette again nuclear@0: void MDLImporter::FreePalette(const unsigned char* szColorMap) nuclear@0: { nuclear@0: if (szColorMap != (const unsigned char*)::g_aclrDefaultColorMap) nuclear@0: delete[] szColorMap; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Check whether we can replace a texture with a single color nuclear@0: aiColor4D MDLImporter::ReplaceTextureWithColor(const aiTexture* pcTexture) nuclear@0: { nuclear@0: ai_assert(NULL != pcTexture); nuclear@0: nuclear@0: aiColor4D clrOut; nuclear@0: clrOut.r = get_qnan(); nuclear@0: if (!pcTexture->mHeight || !pcTexture->mWidth) nuclear@0: return clrOut; nuclear@0: nuclear@0: const unsigned int iNumPixels = pcTexture->mHeight*pcTexture->mWidth; nuclear@0: const aiTexel* pcTexel = pcTexture->pcData+1; nuclear@0: const aiTexel* const pcTexelEnd = &pcTexture->pcData[iNumPixels]; nuclear@0: nuclear@0: while (pcTexel != pcTexelEnd) nuclear@0: { nuclear@0: if (*pcTexel != *(pcTexel-1)) nuclear@0: { nuclear@0: pcTexel = NULL; nuclear@0: break; nuclear@0: } nuclear@0: ++pcTexel; nuclear@0: } nuclear@0: if (pcTexel) nuclear@0: { nuclear@0: clrOut.r = pcTexture->pcData->r / 255.0f; nuclear@0: clrOut.g = pcTexture->pcData->g / 255.0f; nuclear@0: clrOut.b = pcTexture->pcData->b / 255.0f; nuclear@0: clrOut.a = pcTexture->pcData->a / 255.0f; nuclear@0: } nuclear@0: return clrOut; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Read a texture from a MDL3 file nuclear@0: void MDLImporter::CreateTextureARGB8_3DGS_MDL3(const unsigned char* szData) nuclear@0: { nuclear@0: const MDL::Header *pcHeader = (const MDL::Header*)mBuffer; //the endianess is allready corrected in the InternReadFile_3DGS_MDL345 function nuclear@0: nuclear@0: VALIDATE_FILE_SIZE(szData + pcHeader->skinwidth * nuclear@0: pcHeader->skinheight); nuclear@0: nuclear@0: // allocate a new texture object nuclear@0: aiTexture* pcNew = new aiTexture(); nuclear@0: pcNew->mWidth = pcHeader->skinwidth; nuclear@0: pcNew->mHeight = pcHeader->skinheight; nuclear@0: nuclear@0: pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight]; nuclear@0: nuclear@0: const unsigned char* szColorMap; nuclear@0: this->SearchPalette(&szColorMap); nuclear@0: nuclear@0: // copy texture data nuclear@0: for (unsigned int i = 0; i < pcNew->mWidth*pcNew->mHeight;++i) nuclear@0: { nuclear@0: const unsigned char val = szData[i]; nuclear@0: const unsigned char* sz = &szColorMap[val*3]; nuclear@0: nuclear@0: pcNew->pcData[i].a = 0xFF; nuclear@0: pcNew->pcData[i].r = *sz++; nuclear@0: pcNew->pcData[i].g = *sz++; nuclear@0: pcNew->pcData[i].b = *sz; nuclear@0: } nuclear@0: nuclear@0: FreePalette(szColorMap); nuclear@0: nuclear@0: // store the texture nuclear@0: aiTexture** pc = this->pScene->mTextures; nuclear@0: this->pScene->mTextures = new aiTexture*[pScene->mNumTextures+1]; nuclear@0: for (unsigned int i = 0; i mNumTextures;++i) nuclear@0: pScene->mTextures[i] = pc[i]; nuclear@0: nuclear@0: pScene->mTextures[this->pScene->mNumTextures] = pcNew; nuclear@0: pScene->mNumTextures++; nuclear@0: delete[] pc; nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Read a texture from a MDL4 file nuclear@0: void MDLImporter::CreateTexture_3DGS_MDL4(const unsigned char* szData, nuclear@0: unsigned int iType, nuclear@0: unsigned int* piSkip) nuclear@0: { nuclear@0: ai_assert(NULL != piSkip); nuclear@0: nuclear@0: const MDL::Header *pcHeader = (const MDL::Header*)mBuffer; //the endianess is allready corrected in the InternReadFile_3DGS_MDL345 function nuclear@0: nuclear@0: if (iType == 1 || iType > 3) nuclear@0: { nuclear@0: DefaultLogger::get()->error("Unsupported texture file format"); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: const bool bNoRead = *piSkip == UINT_MAX; nuclear@0: nuclear@0: // allocate a new texture object nuclear@0: aiTexture* pcNew = new aiTexture(); nuclear@0: pcNew->mWidth = pcHeader->skinwidth; nuclear@0: pcNew->mHeight = pcHeader->skinheight; nuclear@0: nuclear@0: if (bNoRead)pcNew->pcData = bad_texel; nuclear@0: ParseTextureColorData(szData,iType,piSkip,pcNew); nuclear@0: nuclear@0: // store the texture nuclear@0: if (!bNoRead) nuclear@0: { nuclear@0: if (!this->pScene->mNumTextures) nuclear@0: { nuclear@0: pScene->mNumTextures = 1; nuclear@0: pScene->mTextures = new aiTexture*[1]; nuclear@0: pScene->mTextures[0] = pcNew; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: aiTexture** pc = pScene->mTextures; nuclear@0: pScene->mTextures = new aiTexture*[pScene->mNumTextures+1]; nuclear@0: for (unsigned int i = 0; i < this->pScene->mNumTextures;++i) nuclear@0: pScene->mTextures[i] = pc[i]; nuclear@0: pScene->mTextures[pScene->mNumTextures] = pcNew; nuclear@0: pScene->mNumTextures++; nuclear@0: delete[] pc; nuclear@0: } nuclear@0: } nuclear@0: else { nuclear@0: pcNew->pcData = NULL; nuclear@0: delete pcNew; nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Load color data of a texture and convert it to our output format nuclear@0: void MDLImporter::ParseTextureColorData(const unsigned char* szData, nuclear@0: unsigned int iType, nuclear@0: unsigned int* piSkip, nuclear@0: aiTexture* pcNew) nuclear@0: { nuclear@0: const bool do_read = bad_texel != pcNew->pcData; nuclear@0: nuclear@0: // allocate storage for the texture image nuclear@0: if (do_read) { nuclear@0: pcNew->pcData = new aiTexel[pcNew->mWidth * pcNew->mHeight]; nuclear@0: } nuclear@0: nuclear@0: // R5G6B5 format (with or without MIPs) nuclear@0: // **************************************************************** nuclear@0: if (2 == iType || 10 == iType) nuclear@0: { nuclear@0: VALIDATE_FILE_SIZE(szData + pcNew->mWidth*pcNew->mHeight*2); nuclear@0: nuclear@0: // copy texture data nuclear@0: unsigned int i; nuclear@0: if (do_read) nuclear@0: { nuclear@0: for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i) nuclear@0: { nuclear@0: MDL::RGB565 val = ((MDL::RGB565*)szData)[i]; nuclear@0: AI_SWAP2(val); nuclear@0: nuclear@0: pcNew->pcData[i].a = 0xFF; nuclear@0: pcNew->pcData[i].r = (unsigned char)val.b << 3; nuclear@0: pcNew->pcData[i].g = (unsigned char)val.g << 2; nuclear@0: pcNew->pcData[i].b = (unsigned char)val.r << 3; nuclear@0: } nuclear@0: } nuclear@0: else i = pcNew->mWidth*pcNew->mHeight; nuclear@0: *piSkip = i * 2; nuclear@0: nuclear@0: // apply MIP maps nuclear@0: if (10 == iType) nuclear@0: { nuclear@0: *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1; nuclear@0: VALIDATE_FILE_SIZE(szData + *piSkip); nuclear@0: } nuclear@0: } nuclear@0: // ARGB4 format (with or without MIPs) nuclear@0: // **************************************************************** nuclear@0: else if (3 == iType || 11 == iType) nuclear@0: { nuclear@0: VALIDATE_FILE_SIZE(szData + pcNew->mWidth*pcNew->mHeight*4); nuclear@0: nuclear@0: // copy texture data nuclear@0: unsigned int i; nuclear@0: if (do_read) nuclear@0: { nuclear@0: for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i) nuclear@0: { nuclear@0: MDL::ARGB4 val = ((MDL::ARGB4*)szData)[i]; nuclear@0: AI_SWAP2(val); nuclear@0: nuclear@0: pcNew->pcData[i].a = (unsigned char)val.a << 4; nuclear@0: pcNew->pcData[i].r = (unsigned char)val.r << 4; nuclear@0: pcNew->pcData[i].g = (unsigned char)val.g << 4; nuclear@0: pcNew->pcData[i].b = (unsigned char)val.b << 4; nuclear@0: } nuclear@0: } nuclear@0: else i = pcNew->mWidth*pcNew->mHeight; nuclear@0: *piSkip = i * 2; nuclear@0: nuclear@0: // apply MIP maps nuclear@0: if (11 == iType) nuclear@0: { nuclear@0: *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 1; nuclear@0: VALIDATE_FILE_SIZE(szData + *piSkip); nuclear@0: } nuclear@0: } nuclear@0: // RGB8 format (with or without MIPs) nuclear@0: // **************************************************************** nuclear@0: else if (4 == iType || 12 == iType) nuclear@0: { nuclear@0: VALIDATE_FILE_SIZE(szData + pcNew->mWidth*pcNew->mHeight*3); nuclear@0: nuclear@0: // copy texture data nuclear@0: unsigned int i; nuclear@0: if (do_read) nuclear@0: { nuclear@0: for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i) nuclear@0: { nuclear@0: const unsigned char* _szData = &szData[i*3]; nuclear@0: nuclear@0: pcNew->pcData[i].a = 0xFF; nuclear@0: pcNew->pcData[i].b = *_szData++; nuclear@0: pcNew->pcData[i].g = *_szData++; nuclear@0: pcNew->pcData[i].r = *_szData; nuclear@0: } nuclear@0: } nuclear@0: else i = pcNew->mWidth*pcNew->mHeight; nuclear@0: nuclear@0: nuclear@0: // apply MIP maps nuclear@0: *piSkip = i * 3; nuclear@0: if (12 == iType) nuclear@0: { nuclear@0: *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) *3; nuclear@0: VALIDATE_FILE_SIZE(szData + *piSkip); nuclear@0: } nuclear@0: } nuclear@0: // ARGB8 format (with ir without MIPs) nuclear@0: // **************************************************************** nuclear@0: else if (5 == iType || 13 == iType) nuclear@0: { nuclear@0: VALIDATE_FILE_SIZE(szData + pcNew->mWidth*pcNew->mHeight*4); nuclear@0: nuclear@0: // copy texture data nuclear@0: unsigned int i; nuclear@0: if (do_read) nuclear@0: { nuclear@0: for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i) nuclear@0: { nuclear@0: const unsigned char* _szData = &szData[i*4]; nuclear@0: nuclear@0: pcNew->pcData[i].b = *_szData++; nuclear@0: pcNew->pcData[i].g = *_szData++; nuclear@0: pcNew->pcData[i].r = *_szData++; nuclear@0: pcNew->pcData[i].a = *_szData; nuclear@0: } nuclear@0: } nuclear@0: else i = pcNew->mWidth*pcNew->mHeight; nuclear@0: nuclear@0: // apply MIP maps nuclear@0: *piSkip = i << 2; nuclear@0: if (13 == iType) nuclear@0: { nuclear@0: *piSkip += ((i >> 2) + (i >> 4) + (i >> 6)) << 2; nuclear@0: } nuclear@0: } nuclear@0: // palletized 8 bit texture. As for Quake 1 nuclear@0: // **************************************************************** nuclear@0: else if (0 == iType) nuclear@0: { nuclear@0: VALIDATE_FILE_SIZE(szData + pcNew->mWidth*pcNew->mHeight); nuclear@0: nuclear@0: // copy texture data nuclear@0: unsigned int i; nuclear@0: if (do_read) nuclear@0: { nuclear@0: nuclear@0: const unsigned char* szColorMap; nuclear@0: SearchPalette(&szColorMap); nuclear@0: nuclear@0: for (i = 0; i < pcNew->mWidth*pcNew->mHeight;++i) nuclear@0: { nuclear@0: const unsigned char val = szData[i]; nuclear@0: const unsigned char* sz = &szColorMap[val*3]; nuclear@0: nuclear@0: pcNew->pcData[i].a = 0xFF; nuclear@0: pcNew->pcData[i].r = *sz++; nuclear@0: pcNew->pcData[i].g = *sz++; nuclear@0: pcNew->pcData[i].b = *sz; nuclear@0: } nuclear@0: this->FreePalette(szColorMap); nuclear@0: nuclear@0: } nuclear@0: else i = pcNew->mWidth*pcNew->mHeight; nuclear@0: *piSkip = i; nuclear@0: nuclear@0: // FIXME: Also support for MIP maps? nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get a texture from a MDL5 file nuclear@0: void MDLImporter::CreateTexture_3DGS_MDL5(const unsigned char* szData, nuclear@0: unsigned int iType, nuclear@0: unsigned int* piSkip) nuclear@0: { nuclear@0: ai_assert(NULL != piSkip); nuclear@0: bool bNoRead = *piSkip == UINT_MAX; nuclear@0: nuclear@0: // allocate a new texture object nuclear@0: aiTexture* pcNew = new aiTexture(); nuclear@0: nuclear@0: VALIDATE_FILE_SIZE(szData+8); nuclear@0: nuclear@0: // first read the size of the texture nuclear@0: pcNew->mWidth = *((uint32_t*)szData); nuclear@0: AI_SWAP4(pcNew->mWidth); nuclear@0: szData += sizeof(uint32_t); nuclear@0: nuclear@0: pcNew->mHeight = *((uint32_t*)szData); nuclear@0: AI_SWAP4(pcNew->mHeight); nuclear@0: szData += sizeof(uint32_t); nuclear@0: nuclear@0: if (bNoRead) { nuclear@0: pcNew->pcData = bad_texel; nuclear@0: } nuclear@0: nuclear@0: // this should not occur - at least the docs say it shouldn't. nuclear@0: // however, one can easily try out what MED does if you have nuclear@0: // a model with a DDS texture and export it to MDL5 ... nuclear@0: // yeah, it embedds the DDS file. nuclear@0: if (6 == iType) nuclear@0: { nuclear@0: // this is a compressed texture in DDS format nuclear@0: *piSkip = pcNew->mWidth; nuclear@0: VALIDATE_FILE_SIZE(szData + *piSkip); nuclear@0: nuclear@0: if (!bNoRead) nuclear@0: { nuclear@0: // place a hint and let the application know that this is a DDS file nuclear@0: pcNew->mHeight = 0; nuclear@0: pcNew->achFormatHint[0] = 'd'; nuclear@0: pcNew->achFormatHint[1] = 'd'; nuclear@0: pcNew->achFormatHint[2] = 's'; nuclear@0: pcNew->achFormatHint[3] = '\0'; nuclear@0: nuclear@0: pcNew->pcData = (aiTexel*) new unsigned char[pcNew->mWidth]; nuclear@0: ::memcpy(pcNew->pcData,szData,pcNew->mWidth); nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // parse the color data of the texture nuclear@0: ParseTextureColorData(szData,iType,piSkip,pcNew); nuclear@0: } nuclear@0: *piSkip += sizeof(uint32_t) * 2; nuclear@0: nuclear@0: if (!bNoRead) nuclear@0: { nuclear@0: // store the texture nuclear@0: if (!this->pScene->mNumTextures) nuclear@0: { nuclear@0: pScene->mNumTextures = 1; nuclear@0: pScene->mTextures = new aiTexture*[1]; nuclear@0: pScene->mTextures[0] = pcNew; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: aiTexture** pc = pScene->mTextures; nuclear@0: pScene->mTextures = new aiTexture*[pScene->mNumTextures+1]; nuclear@0: for (unsigned int i = 0; i < pScene->mNumTextures;++i) nuclear@0: this->pScene->mTextures[i] = pc[i]; nuclear@0: nuclear@0: pScene->mTextures[pScene->mNumTextures] = pcNew; nuclear@0: pScene->mNumTextures++; nuclear@0: delete[] pc; nuclear@0: } nuclear@0: } nuclear@0: else { nuclear@0: pcNew->pcData = NULL; nuclear@0: delete pcNew; nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get a skin from a MDL7 file - more complex than all other subformats nuclear@0: void MDLImporter::ParseSkinLump_3DGS_MDL7( nuclear@0: const unsigned char* szCurrent, nuclear@0: const unsigned char** szCurrentOut, nuclear@0: aiMaterial* pcMatOut, nuclear@0: unsigned int iType, nuclear@0: unsigned int iWidth, nuclear@0: unsigned int iHeight) nuclear@0: { nuclear@0: aiTexture* pcNew = NULL; nuclear@0: nuclear@0: // get the type of the skin nuclear@0: unsigned int iMasked = (unsigned int)(iType & 0xF); nuclear@0: nuclear@0: if (0x1 == iMasked) nuclear@0: { nuclear@0: // ***** REFERENCE TO ANOTHER SKIN INDEX ***** nuclear@0: int referrer = (int)iWidth; nuclear@0: pcMatOut->AddProperty(&referrer,1,AI_MDL7_REFERRER_MATERIAL); nuclear@0: } nuclear@0: else if (0x6 == iMasked) nuclear@0: { nuclear@0: // ***** EMBEDDED DDS FILE ***** nuclear@0: if (1 != iHeight) nuclear@0: { nuclear@0: DefaultLogger::get()->warn("Found a reference to an embedded DDS texture, " nuclear@0: "but texture height is not equal to 1, which is not supported by MED"); nuclear@0: } nuclear@0: nuclear@0: pcNew = new aiTexture(); nuclear@0: pcNew->mHeight = 0; nuclear@0: pcNew->mWidth = iWidth; nuclear@0: nuclear@0: // place a proper format hint nuclear@0: pcNew->achFormatHint[0] = 'd'; nuclear@0: pcNew->achFormatHint[1] = 'd'; nuclear@0: pcNew->achFormatHint[2] = 's'; nuclear@0: pcNew->achFormatHint[3] = '\0'; nuclear@0: nuclear@0: pcNew->pcData = (aiTexel*) new unsigned char[pcNew->mWidth]; nuclear@0: memcpy(pcNew->pcData,szCurrent,pcNew->mWidth); nuclear@0: szCurrent += iWidth; nuclear@0: } nuclear@0: if (0x7 == iMasked) nuclear@0: { nuclear@0: // ***** REFERENCE TO EXTERNAL FILE ***** nuclear@0: if (1 != iHeight) nuclear@0: { nuclear@0: DefaultLogger::get()->warn("Found a reference to an external texture, " nuclear@0: "but texture height is not equal to 1, which is not supported by MED"); nuclear@0: } nuclear@0: nuclear@0: aiString szFile; nuclear@0: const size_t iLen = strlen((const char*)szCurrent); nuclear@0: size_t iLen2 = iLen+1; nuclear@0: iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2; nuclear@0: memcpy(szFile.data,(const char*)szCurrent,iLen2); nuclear@0: szFile.length = iLen; nuclear@0: nuclear@0: szCurrent += iLen2; nuclear@0: nuclear@0: // place this as diffuse texture nuclear@0: pcMatOut->AddProperty(&szFile,AI_MATKEY_TEXTURE_DIFFUSE(0)); nuclear@0: } nuclear@0: else if (iMasked || !iType || (iType && iWidth && iHeight)) nuclear@0: { nuclear@0: // ***** STANDARD COLOR TEXTURE ***** nuclear@0: pcNew = new aiTexture(); nuclear@0: if (!iHeight || !iWidth) nuclear@0: { nuclear@0: DefaultLogger::get()->warn("Found embedded texture, but its width " nuclear@0: "an height are both 0. Is this a joke?"); nuclear@0: nuclear@0: // generate an empty chess pattern nuclear@0: pcNew->mWidth = pcNew->mHeight = 8; nuclear@0: pcNew->pcData = new aiTexel[64]; nuclear@0: for (unsigned int x = 0; x < 8;++x) nuclear@0: { nuclear@0: for (unsigned int y = 0; y < 8;++y) nuclear@0: { nuclear@0: const bool bSet = ((0 == x % 2 && 0 != y % 2) || nuclear@0: (0 != x % 2 && 0 == y % 2)); nuclear@0: nuclear@0: aiTexel* pc = &pcNew->pcData[y * 8 + x]; nuclear@0: pc->r = pc->b = pc->g = (bSet?0xFF:0); nuclear@0: pc->a = 0xFF; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // it is a standard color texture. Fill in width and height nuclear@0: // and call the same function we used for loading MDL5 files nuclear@0: nuclear@0: pcNew->mWidth = iWidth; nuclear@0: pcNew->mHeight = iHeight; nuclear@0: nuclear@0: unsigned int iSkip = 0; nuclear@0: ParseTextureColorData(szCurrent,iMasked,&iSkip,pcNew); nuclear@0: nuclear@0: // skip length of texture data nuclear@0: szCurrent += iSkip; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // sometimes there are MDL7 files which have a monochrome nuclear@0: // texture instead of material colors ... posssible they have nuclear@0: // been converted to MDL7 from other formats, such as MDL5 nuclear@0: aiColor4D clrTexture; nuclear@0: if (pcNew)clrTexture = ReplaceTextureWithColor(pcNew); nuclear@0: else clrTexture.r = get_qnan(); nuclear@0: nuclear@0: // check whether a material definition is contained in the skin nuclear@0: if (iType & AI_MDL7_SKINTYPE_MATERIAL) nuclear@0: { nuclear@0: BE_NCONST MDL::Material_MDL7* pcMatIn = (BE_NCONST MDL::Material_MDL7*)szCurrent; nuclear@0: szCurrent = (unsigned char*)(pcMatIn+1); nuclear@0: VALIDATE_FILE_SIZE(szCurrent); nuclear@0: nuclear@0: aiColor3D clrTemp; nuclear@0: nuclear@0: #define COLOR_MULTIPLY_RGB() \ nuclear@0: if (is_not_qnan(clrTexture.r)) \ nuclear@0: { \ nuclear@0: clrTemp.r *= clrTexture.r; \ nuclear@0: clrTemp.g *= clrTexture.g; \ nuclear@0: clrTemp.b *= clrTexture.b; \ nuclear@0: } nuclear@0: nuclear@0: // read diffuse color nuclear@0: clrTemp.r = pcMatIn->Diffuse.r; nuclear@0: AI_SWAP4(clrTemp.r); nuclear@0: clrTemp.g = pcMatIn->Diffuse.g; nuclear@0: AI_SWAP4(clrTemp.g); nuclear@0: clrTemp.b = pcMatIn->Diffuse.b; nuclear@0: AI_SWAP4(clrTemp.b); nuclear@0: COLOR_MULTIPLY_RGB(); nuclear@0: pcMatOut->AddProperty(&clrTemp,1,AI_MATKEY_COLOR_DIFFUSE); nuclear@0: nuclear@0: // read specular color nuclear@0: clrTemp.r = pcMatIn->Specular.r; nuclear@0: AI_SWAP4(clrTemp.r); nuclear@0: clrTemp.g = pcMatIn->Specular.g; nuclear@0: AI_SWAP4(clrTemp.g); nuclear@0: clrTemp.b = pcMatIn->Specular.b; nuclear@0: AI_SWAP4(clrTemp.b); nuclear@0: COLOR_MULTIPLY_RGB(); nuclear@0: pcMatOut->AddProperty(&clrTemp,1,AI_MATKEY_COLOR_SPECULAR); nuclear@0: nuclear@0: // read ambient color nuclear@0: clrTemp.r = pcMatIn->Ambient.r; nuclear@0: AI_SWAP4(clrTemp.r); nuclear@0: clrTemp.g = pcMatIn->Ambient.g; nuclear@0: AI_SWAP4(clrTemp.g); nuclear@0: clrTemp.b = pcMatIn->Ambient.b; nuclear@0: AI_SWAP4(clrTemp.b); nuclear@0: COLOR_MULTIPLY_RGB(); nuclear@0: pcMatOut->AddProperty(&clrTemp,1,AI_MATKEY_COLOR_AMBIENT); nuclear@0: nuclear@0: // read emissive color nuclear@0: clrTemp.r = pcMatIn->Emissive.r; nuclear@0: AI_SWAP4(clrTemp.r); nuclear@0: clrTemp.g = pcMatIn->Emissive.g; nuclear@0: AI_SWAP4(clrTemp.g); nuclear@0: clrTemp.b = pcMatIn->Emissive.b; nuclear@0: AI_SWAP4(clrTemp.b); nuclear@0: pcMatOut->AddProperty(&clrTemp,1,AI_MATKEY_COLOR_EMISSIVE); nuclear@0: nuclear@0: #undef COLOR_MULITPLY_RGB nuclear@0: nuclear@0: // FIX: Take the opacity from the ambient color. nuclear@0: // The doc say something else, but it is fact that MED exports the nuclear@0: // opacity like this .... oh well. nuclear@0: clrTemp.r = pcMatIn->Ambient.a; nuclear@0: AI_SWAP4(clrTemp.r); nuclear@0: if (is_not_qnan(clrTexture.r)) { nuclear@0: clrTemp.r *= clrTexture.a; nuclear@0: } nuclear@0: pcMatOut->AddProperty(&clrTemp.r,1,AI_MATKEY_OPACITY); nuclear@0: nuclear@0: // read phong power nuclear@0: int iShadingMode = (int)aiShadingMode_Gouraud; nuclear@0: AI_SWAP4(pcMatIn->Power); nuclear@0: if (0.0f != pcMatIn->Power) nuclear@0: { nuclear@0: iShadingMode = (int)aiShadingMode_Phong; nuclear@0: pcMatOut->AddProperty(&pcMatIn->Power,1,AI_MATKEY_SHININESS); nuclear@0: } nuclear@0: pcMatOut->AddProperty(&iShadingMode,1,AI_MATKEY_SHADING_MODEL); nuclear@0: } nuclear@0: else if (is_not_qnan(clrTexture.r)) nuclear@0: { nuclear@0: pcMatOut->AddProperty(&clrTexture,1,AI_MATKEY_COLOR_DIFFUSE); nuclear@0: pcMatOut->AddProperty(&clrTexture,1,AI_MATKEY_COLOR_SPECULAR); nuclear@0: } nuclear@0: // if the texture could be replaced by a single material color nuclear@0: // we don't need the texture anymore nuclear@0: if (is_not_qnan(clrTexture.r)) nuclear@0: { nuclear@0: delete pcNew; nuclear@0: pcNew = NULL; nuclear@0: } nuclear@0: nuclear@0: // If an ASCII effect description (HLSL?) is contained in the file, nuclear@0: // we can simply ignore it ... nuclear@0: if (iType & AI_MDL7_SKINTYPE_MATERIAL_ASCDEF) nuclear@0: { nuclear@0: VALIDATE_FILE_SIZE(szCurrent); nuclear@0: int32_t iMe = *((int32_t*)szCurrent); nuclear@0: AI_SWAP4(iMe); nuclear@0: szCurrent += sizeof(char) * iMe + sizeof(int32_t); nuclear@0: VALIDATE_FILE_SIZE(szCurrent); nuclear@0: } nuclear@0: nuclear@0: // If an embedded texture has been loaded setup the corresponding nuclear@0: // data structures in the aiScene instance nuclear@0: if (pcNew && pScene->mNumTextures <= 999) nuclear@0: { nuclear@0: nuclear@0: // place this as diffuse texture nuclear@0: char szCurrent[5]; nuclear@0: ::sprintf(szCurrent,"*%i",this->pScene->mNumTextures); nuclear@0: nuclear@0: aiString szFile; nuclear@0: const size_t iLen = strlen((const char*)szCurrent); nuclear@0: ::memcpy(szFile.data,(const char*)szCurrent,iLen+1); nuclear@0: szFile.length = iLen; nuclear@0: nuclear@0: pcMatOut->AddProperty(&szFile,AI_MATKEY_TEXTURE_DIFFUSE(0)); nuclear@0: nuclear@0: // store the texture nuclear@0: if (!pScene->mNumTextures) nuclear@0: { nuclear@0: pScene->mNumTextures = 1; nuclear@0: pScene->mTextures = new aiTexture*[1]; nuclear@0: pScene->mTextures[0] = pcNew; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: aiTexture** pc = pScene->mTextures; nuclear@0: pScene->mTextures = new aiTexture*[pScene->mNumTextures+1]; nuclear@0: for (unsigned int i = 0; i < pScene->mNumTextures;++i) { nuclear@0: pScene->mTextures[i] = pc[i]; nuclear@0: } nuclear@0: nuclear@0: pScene->mTextures[pScene->mNumTextures] = pcNew; nuclear@0: pScene->mNumTextures++; nuclear@0: delete[] pc; nuclear@0: } nuclear@0: } nuclear@0: VALIDATE_FILE_SIZE(szCurrent); nuclear@0: *szCurrentOut = szCurrent; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Skip a skin lump nuclear@0: void MDLImporter::SkipSkinLump_3DGS_MDL7( nuclear@0: const unsigned char* szCurrent, nuclear@0: const unsigned char** szCurrentOut, nuclear@0: unsigned int iType, nuclear@0: unsigned int iWidth, nuclear@0: unsigned int iHeight) nuclear@0: { nuclear@0: // get the type of the skin nuclear@0: const unsigned int iMasked = (unsigned int)(iType & 0xF); nuclear@0: nuclear@0: if (0x6 == iMasked) nuclear@0: { nuclear@0: szCurrent += iWidth; nuclear@0: } nuclear@0: if (0x7 == iMasked) nuclear@0: { nuclear@0: const size_t iLen = ::strlen((const char*)szCurrent); nuclear@0: szCurrent += iLen+1; nuclear@0: } nuclear@0: else if (iMasked || !iType) nuclear@0: { nuclear@0: if (iMasked || !iType || (iType && iWidth && iHeight)) nuclear@0: { nuclear@0: // ParseTextureColorData(..., aiTexture::pcData == bad_texel) will simply nuclear@0: // return the size of the color data in bytes in iSkip nuclear@0: unsigned int iSkip = 0; nuclear@0: nuclear@0: aiTexture tex; nuclear@0: tex.pcData = bad_texel; nuclear@0: tex.mHeight = iHeight; nuclear@0: tex.mWidth = iWidth; nuclear@0: ParseTextureColorData(szCurrent,iMasked,&iSkip,&tex); nuclear@0: nuclear@0: // FIX: Important, otherwise the destructor will crash nuclear@0: tex.pcData = NULL; nuclear@0: nuclear@0: // skip length of texture data nuclear@0: szCurrent += iSkip; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // check whether a material definition is contained in the skin nuclear@0: if (iType & AI_MDL7_SKINTYPE_MATERIAL) nuclear@0: { nuclear@0: BE_NCONST MDL::Material_MDL7* pcMatIn = (BE_NCONST MDL::Material_MDL7*)szCurrent; nuclear@0: szCurrent = (unsigned char*)(pcMatIn+1); nuclear@0: } nuclear@0: nuclear@0: // if an ASCII effect description (HLSL?) is contained in the file, nuclear@0: // we can simply ignore it ... nuclear@0: if (iType & AI_MDL7_SKINTYPE_MATERIAL_ASCDEF) nuclear@0: { nuclear@0: int32_t iMe = *((int32_t*)szCurrent); nuclear@0: AI_SWAP4(iMe); nuclear@0: szCurrent += sizeof(char) * iMe + sizeof(int32_t); nuclear@0: } nuclear@0: *szCurrentOut = szCurrent; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void MDLImporter::ParseSkinLump_3DGS_MDL7( nuclear@0: const unsigned char* szCurrent, nuclear@0: const unsigned char** szCurrentOut, nuclear@0: std::vector& pcMats) nuclear@0: { nuclear@0: ai_assert(NULL != szCurrent); nuclear@0: ai_assert(NULL != szCurrentOut); nuclear@0: nuclear@0: *szCurrentOut = szCurrent; nuclear@0: BE_NCONST MDL::Skin_MDL7* pcSkin = (BE_NCONST MDL::Skin_MDL7*)szCurrent; nuclear@0: AI_SWAP4(pcSkin->width); nuclear@0: AI_SWAP4(pcSkin->height); nuclear@0: szCurrent += 12; nuclear@0: nuclear@0: // allocate an output material nuclear@0: aiMaterial* pcMatOut = new aiMaterial(); nuclear@0: pcMats.push_back(pcMatOut); nuclear@0: nuclear@0: // skip length of file name nuclear@0: szCurrent += AI_MDL7_MAX_TEXNAMESIZE; nuclear@0: nuclear@0: ParseSkinLump_3DGS_MDL7(szCurrent,szCurrentOut,pcMatOut, nuclear@0: pcSkin->typ,pcSkin->width,pcSkin->height); nuclear@0: nuclear@0: // place the name of the skin in the material nuclear@0: if (pcSkin->texture_name[0]) nuclear@0: { nuclear@0: // the 0 termination could be there or not - we can't know nuclear@0: aiString szFile; nuclear@0: ::memcpy(szFile.data,pcSkin->texture_name,sizeof(pcSkin->texture_name)); nuclear@0: szFile.data[sizeof(pcSkin->texture_name)] = '\0'; nuclear@0: szFile.length = ::strlen(szFile.data); nuclear@0: nuclear@0: pcMatOut->AddProperty(&szFile,AI_MATKEY_NAME); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: #endif // !! ASSIMP_BUILD_NO_MDL_IMPORTER