// ------------------------------------------------------------------------------------------------ // read an array of uints void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) { out.resize( 0 ); const TokenList& tok = el.Tokens(); if(tok.empty()) { ParseError("unexpected empty element",&el); } if(tok[0]->IsBinary()) { const char* data = tok[0]->begin(), *end = tok[0]->end(); char type; uint32_t count; ReadBinaryDataArrayHead(data, end, type, count, el); if(!count) { return; } if (type != 'i') { ParseError("expected (u)int array (binary)",&el); } std::vector<char> buff; ReadBinaryDataArray(type, count, data, end, buff, el); ai_assert(data == end); ai_assert(buff.size() == count * 4); out.reserve(count); const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]); for (unsigned int i = 0; i < count; ++i, ++ip) { BE_NCONST int32_t val = *ip; if(val < 0) { ParseError("encountered negative integer index (binary)"); } AI_SWAP4(val); out.push_back(val); } return; } const size_t dim = ParseTokenAsDim(*tok[0]); // see notes in ParseVectorDataArray() out.reserve(dim); const Scope& scope = GetRequiredScope(el); const Element& a = GetRequiredElement(scope,"a",&el); for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { const int ival = ParseTokenAsInt(**it++); if(ival < 0) { ParseError("encountered negative integer index"); } out.push_back(static_cast<unsigned int>(ival)); } }
// ------------------------------------------------------------------------------------------------ // read an array of float3 tuples void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el) { out.resize( 0 ); const TokenList& tok = el.Tokens(); if(tok.empty()) { ParseError("unexpected empty element",&el); } if(tok[0]->IsBinary()) { const char* data = tok[0]->begin(), *end = tok[0]->end(); char type; uint32_t count; ReadBinaryDataArrayHead(data, end, type, count, el); if(count % 3 != 0) { ParseError("number of floats is not a multiple of three (3) (binary)",&el); } if(!count) { return; } if (type != 'd' && type != 'f') { ParseError("expected float or double array (binary)",&el); } std::vector<char> buff; ReadBinaryDataArray(type, count, data, end, buff, el); ai_assert(data == end); ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); const uint32_t count3 = count / 3; out.reserve(count3); if (type == 'd') { const double* d = reinterpret_cast<const double*>(&buff[0]); for (unsigned int i = 0; i < count3; ++i, d += 3) { out.push_back(aiVector3D(static_cast<float>(d[0]), static_cast<float>(d[1]), static_cast<float>(d[2]))); } // for debugging /*for ( size_t i = 0; i < out.size(); i++ ) { aiVector3D vec3( out[ i ] ); std::stringstream stream; stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl; DefaultLogger::get()->info( stream.str() ); }*/ } else if (type == 'f') { const float* f = reinterpret_cast<const float*>(&buff[0]); for (unsigned int i = 0; i < count3; ++i, f += 3) { out.push_back(aiVector3D(f[0],f[1],f[2])); } } return; } const size_t dim = ParseTokenAsDim(*tok[0]); // may throw bad_alloc if the input is rubbish, but this need // not to be prevented - importing would fail but we wouldn't // crash since assimp handles this case properly. out.reserve(dim); const Scope& scope = GetRequiredScope(el); const Element& a = GetRequiredElement(scope,"a",&el); if (a.Tokens().size() % 3 != 0) { ParseError("number of floats is not a multiple of three (3)",&el); } for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { aiVector3D v; v.x = ParseTokenAsFloat(**it++); v.y = ParseTokenAsFloat(**it++); v.z = ParseTokenAsFloat(**it++); out.push_back(v); } }
// ------------------------------------------------------------------------------------------------ // read an array of float2 tuples void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) { out.resize( 0 ); const TokenList& tok = el.Tokens(); if(tok.empty()) { ParseError("unexpected empty element",&el); } if(tok[0]->IsBinary()) { const char* data = tok[0]->begin(), *end = tok[0]->end(); char type; uint32_t count; ReadBinaryDataArrayHead(data, end, type, count, el); if(count % 2 != 0) { ParseError("number of floats is not a multiple of two (2) (binary)",&el); } if(!count) { return; } if (type != 'd' && type != 'f') { ParseError("expected float or double array (binary)",&el); } std::vector<char> buff; ReadBinaryDataArray(type, count, data, end, buff, el); ai_assert(data == end); ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); const uint32_t count2 = count / 2; out.reserve(count2); if (type == 'd') { const double* d = reinterpret_cast<const double*>(&buff[0]); for (unsigned int i = 0; i < count2; ++i, d += 2) { out.push_back(aiVector2D(static_cast<float>(d[0]), static_cast<float>(d[1]))); } } else if (type == 'f') { const float* f = reinterpret_cast<const float*>(&buff[0]); for (unsigned int i = 0; i < count2; ++i, f += 2) { out.push_back(aiVector2D(f[0],f[1])); } } return; } const size_t dim = ParseTokenAsDim(*tok[0]); // see notes in ParseVectorDataArray() above out.reserve(dim); const Scope& scope = GetRequiredScope(el); const Element& a = GetRequiredElement(scope,"a",&el); if (a.Tokens().size() % 2 != 0) { ParseError("number of floats is not a multiple of two (2)",&el); } for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { aiVector2D v; v.x = ParseTokenAsFloat(**it++); v.y = ParseTokenAsFloat(**it++); out.push_back(v); } }
// ------------------------------------------------------------------------------------------------ void Tokenize(TokenList& output_tokens, const char* input) { ai_assert(input); // line and column numbers numbers are one-based unsigned int line = 1; unsigned int column = 1; bool comment = false; bool in_double_quotes = false; bool pending_data_token = false; const char* token_begin = NULL, *token_end = NULL; for (const char* cur = input;*cur;column += (*cur == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1), ++cur) { const char c = *cur; if (IsLineEnd(c)) { comment = false; column = 0; ++line; } if(comment) { continue; } if(in_double_quotes) { if (c == '\"') { in_double_quotes = false; token_end = cur; ProcessDataToken(output_tokens,token_begin,token_end,line,column); pending_data_token = false; } continue; } switch(c) { case '\"': if (token_begin) { TokenizeError("unexpected double-quote", line, column); } token_begin = cur; in_double_quotes = true; continue; case ';': ProcessDataToken(output_tokens,token_begin,token_end,line,column); comment = true; continue; case '{': ProcessDataToken(output_tokens,token_begin,token_end, line, column); output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column)); continue; case '}': ProcessDataToken(output_tokens,token_begin,token_end,line,column); output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column)); continue; case ',': if (pending_data_token) { ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true); } output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column)); continue; case ':': if (pending_data_token) { ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true); } else { TokenizeError("unexpected colon", line, column); } continue; } if (IsSpaceOrNewLine(c)) { if (token_begin) { // peek ahead and check if the next token is a colon in which // case this counts as KEY token. TokenType type = TokenType_DATA; for (const char* peek = cur; *peek && IsSpaceOrNewLine(*peek); ++peek) { if (*peek == ':') { type = TokenType_KEY; cur = peek; break; } } ProcessDataToken(output_tokens,token_begin,token_end,line,column,type); } pending_data_token = false; } else { token_end = cur; if (!token_begin) { token_begin = cur; } pending_data_token = true; } } }
// ------------------------------------------------------------------------------- aiMesh* MakeSubmesh(const aiMesh *pMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags) { aiMesh *oMesh = new aiMesh(); std::vector<unsigned int> vMap(pMesh->mNumVertices,UINT_MAX); size_t numSubVerts = 0; size_t numSubFaces = subMeshFaces.size(); for(unsigned int i=0;i<numSubFaces;i++) { const aiFace &f = pMesh->mFaces[subMeshFaces[i]]; for(unsigned int j=0;j<f.mNumIndices;j++) { if(vMap[f.mIndices[j]]==UINT_MAX) { vMap[f.mIndices[j]] = numSubVerts++; } } } oMesh->mName = pMesh->mName; oMesh->mMaterialIndex = pMesh->mMaterialIndex; oMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes; // create all the arrays for this mesh if the old mesh contained them oMesh->mNumFaces = subMeshFaces.size(); oMesh->mNumVertices = numSubVerts; oMesh->mVertices = new aiVector3D[numSubVerts]; if( pMesh->HasNormals() ) { oMesh->mNormals = new aiVector3D[numSubVerts]; } if( pMesh->HasTangentsAndBitangents() ) { oMesh->mTangents = new aiVector3D[numSubVerts]; oMesh->mBitangents = new aiVector3D[numSubVerts]; } for( size_t a = 0; pMesh->HasTextureCoords( a) ; ++a ) { oMesh->mTextureCoords[a] = new aiVector3D[numSubVerts]; oMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a]; } for( size_t a = 0; pMesh->HasVertexColors( a); ++a ) { oMesh->mColors[a] = new aiColor4D[numSubVerts]; } // and copy over the data, generating faces with linear indices along the way oMesh->mFaces = new aiFace[numSubFaces]; for(unsigned int a = 0; a < numSubFaces; ++a ) { const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; aiFace& dstFace = oMesh->mFaces[a]; dstFace.mNumIndices = srcFace.mNumIndices; dstFace.mIndices = new unsigned int[dstFace.mNumIndices]; // accumulate linearly all the vertices of the source face for( size_t b = 0; b < dstFace.mNumIndices; ++b ) { dstFace.mIndices[b] = vMap[srcFace.mIndices[b]]; } } for(unsigned int srcIndex = 0; srcIndex < pMesh->mNumVertices; ++srcIndex ) { unsigned int nvi = vMap[srcIndex]; if(nvi==UINT_MAX) { continue; } oMesh->mVertices[nvi] = pMesh->mVertices[srcIndex]; if( pMesh->HasNormals() ) { oMesh->mNormals[nvi] = pMesh->mNormals[srcIndex]; } if( pMesh->HasTangentsAndBitangents() ) { oMesh->mTangents[nvi] = pMesh->mTangents[srcIndex]; oMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex]; } for( size_t c = 0, cc = pMesh->GetNumUVChannels(); c < cc; ++c ) { oMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex]; } for( size_t c = 0, cc = pMesh->GetNumColorChannels(); c < cc; ++c ) { oMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex]; } } if(~subFlags&AI_SUBMESH_FLAGS_SANS_BONES) { std::vector<unsigned int> subBones(pMesh->mNumBones,0); for(unsigned int a=0;a<pMesh->mNumBones;++a) { const aiBone* bone = pMesh->mBones[a]; for(unsigned int b=0;b<bone->mNumWeights;b++) { unsigned int v = vMap[bone->mWeights[b].mVertexId]; if(v!=UINT_MAX) { subBones[a]++; } } } for(unsigned int a=0;a<pMesh->mNumBones;++a) { if(subBones[a]>0) { oMesh->mNumBones++; } } if(oMesh->mNumBones) { oMesh->mBones = new aiBone*[oMesh->mNumBones](); unsigned int nbParanoia = oMesh->mNumBones; oMesh->mNumBones = 0; //rewind for(unsigned int a=0;a<pMesh->mNumBones;++a) { if(subBones[a]==0) { continue; } aiBone *newBone = new aiBone; oMesh->mBones[oMesh->mNumBones++] = newBone; const aiBone* bone = pMesh->mBones[a]; newBone->mName = bone->mName; newBone->mOffsetMatrix = bone->mOffsetMatrix; newBone->mWeights = new aiVertexWeight[subBones[a]]; for(unsigned int b=0;b<bone->mNumWeights;b++) { const unsigned int v = vMap[bone->mWeights[b].mVertexId]; if(v!=UINT_MAX) { aiVertexWeight w(v,bone->mWeights[b].mWeight); newBone->mWeights[newBone->mNumWeights++] = w; } } } ai_assert(nbParanoia==oMesh->mNumBones); (void)nbParanoia; // remove compiler warning on release build } } return oMesh; }
// ------------------------------------------------------------------------------------------------ void M3Importer::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) { ai_assert( !pFile.empty() ); const std::string mode = "rb"; boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode ) ); if ( NULL == file.get() ) { throw DeadlyImportError( "Failed to open file " + pFile + "."); } // Get the file-size and validate it, throwing an exception when it fails const size_t filesize = file->FileSize(); if( filesize < 1 ) { throw DeadlyImportError( "M3-file is too small."); } m_Buffer.resize( filesize ); file->Read( &m_Buffer[ 0 ], sizeof( unsigned char ), filesize ); m_pHead = reinterpret_cast<MD33*>( &m_Buffer[ 0 ] ); m_pRefs = reinterpret_cast<ReferenceEntry*>( &m_Buffer[ 0 ] + m_pHead->ofsRefs ); MODL20* pMODL20( NULL ); MODL23* pMODL23( NULL ); VertexExt* pVerts1( NULL ); Vertex* pVerts2( NULL ); DIV *pViews( NULL ); Region* regions( NULL ); uint16* faces( NULL ); uint32 nVertices = 0; bool ok = true; switch( m_pRefs[ m_pHead->MODL.ref ].type ) { case 20: pMODL20 = GetEntries<MODL20>( m_pHead->MODL ); if ( ( pMODL20->flags & 0x20000) != 0 ) { // Has vertices if( (pMODL20->flags & 0x40000) != 0 ) { // Has extra 4 byte pVerts1 = GetEntries<VertexExt>( pMODL20->vertexData ); nVertices = pMODL20->vertexData.nEntries/sizeof(VertexExt); } else { pVerts2 = GetEntries<Vertex>( pMODL20->vertexData ); nVertices = pMODL20->vertexData.nEntries / sizeof( Vertex ); } } pViews = GetEntries<DIV>( pMODL20->views ); break; case 23: pMODL23 = GetEntries<MODL23>(m_pHead->MODL ); if( (pMODL23->flags & 0x20000) != 0 ) { // Has vertices if( (pMODL23->flags & 0x40000) != 0 ) { // Has extra 4 byte pVerts1 = GetEntries<VertexExt>( pMODL23->vertexData ); nVertices = pMODL23->vertexData.nEntries/sizeof( VertexExt ); } else { pVerts2 = GetEntries<Vertex>( pMODL23->vertexData ); nVertices = pMODL23->vertexData.nEntries/sizeof( Vertex ); } } pViews = GetEntries<DIV>( pMODL23->views ); break; default: ok = false; break; } // Everything ok, if not throw an exception if ( !ok ) { throw DeadlyImportError( "Failed to open file " + pFile + "."); } // Get all region data regions = GetEntries<Region>( pViews->regions ); // Get the face data faces = GetEntries<uint16>( pViews->faces ); // Convert the vertices std::vector<aiVector3D> vertices; vertices.resize( nVertices ); unsigned int offset = 0; for ( unsigned int i = 0; i < nVertices; i++ ) { if ( pVerts1 ) { vertices[ offset ].Set( pVerts1[ i ].pos.x, pVerts1[ i ].pos.y, pVerts1[ i ].pos.z ); ++offset; } if ( pVerts2 ) { vertices[ offset ].Set( pVerts2[ i ].pos.x, pVerts2[ i ].pos.y, pVerts2[ i ].pos.z ); ++offset; } } // Write the UV coordinates offset = 0; std::vector<aiVector3D> uvCoords; uvCoords.resize( nVertices ); for( unsigned int i = 0; i < nVertices; ++i ) { if( pVerts1 ) { float u = (float) pVerts1[ i ].uv[ 0 ] / 2048; float v = (float) pVerts1[ i ].uv[ 1 ] / 2048; uvCoords[ offset ].Set( u, v, 0.0f ); ++offset; } if( pVerts2 ) { float u = (float) pVerts2[ i ].uv[ 0 ] / 2048; float v = (float) pVerts2[ i ].uv[ 1 ] / 2048; uvCoords[ offset ].Set( u, v, 0.0f ); ++offset; } } // Compute the normals std::vector<aiVector3D> normals; normals.resize( nVertices ); float w = 0.0f; Vec3D norm; offset = 0; for( unsigned int i = 0; i < nVertices; i++ ) { w = 0.0f; if( pVerts1 ) { norm.x = (float) 2*pVerts1[ i ].normal[ 0 ]/255.0f - 1; norm.y = (float) 2*pVerts1[ i ].normal[ 1 ]/255.0f - 1; norm.z = (float) 2*pVerts1[ i ].normal[ 2 ]/255.0f - 1; w = (float) pVerts1[ i ].normal[ 3 ]/255.0f; } if( pVerts2 ) { norm.x = (float) 2*pVerts2[ i ].normal[ 0 ]/255.0f - 1; norm.y = (float) 2*pVerts2[ i ].normal[ 1 ]/255.0f - 1; norm.z = (float) 2*pVerts2[ i ].normal[ 2 ]/255.0f - 1; w = (float) pVerts2[ i ].normal[ 3 ] / 255.0f; } if ( w ) { const float invW = 1.0f / w; norm.x = norm.x * invW; norm.y = norm.y * invW; norm.z = norm.z * invW; normals[ offset ].Set( norm.x, norm.y, norm.z ); ++offset; } } // Convert the data into the assimp specific data structures convertToAssimp( pFile, pScene, pViews, regions, faces, vertices, uvCoords, normals ); }
// ------------------------------------------------------------------------------------------------ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) { if(Offset(cursor, end) < 1) { TokenizeError("cannot ReadData, out of bounds reading length",input, cursor); } const char type = *cursor; sbegin_out = cursor++; switch(type) { // 16 bit int case 'Y': cursor += 2; break; // 1 bit bool flag (yes/no) case 'C': cursor += 1; break; // 32 bit int case 'I': // <- fall through // float case 'F': cursor += 4; break; // double case 'D': cursor += 8; break; // 64 bit int case 'L': cursor += 8; break; // note: do not write cursor += ReadWord(...cursor) as this would be UB // raw binary data case 'R': { const uint32_t length = ReadWord(input, cursor, end); cursor += length; break; } case 'b': // TODO: what is the 'b' type code? Right now we just skip over it / // take the full range we could get cursor = end; break; // array of * case 'f': case 'd': case 'l': case 'i': { const uint32_t length = ReadWord(input, cursor, end); const uint32_t encoding = ReadWord(input, cursor, end); const uint32_t comp_len = ReadWord(input, cursor, end); // compute length based on type and check against the stored value if(encoding == 0) { uint32_t stride = 0; switch(type) { case 'f': case 'i': stride = 4; break; case 'd': case 'l': stride = 8; break; default: ai_assert(false); }; ai_assert(stride > 0); if(length * stride != comp_len) { TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor); } } // zip/deflate algorithm (encoding==1)? take given length. anything else? die else if (encoding != 1) { TokenizeError("cannot ReadData, unknown encoding",input, cursor); } cursor += comp_len; break; } // string case 'S': { const char* sb, *se; // 0 characters can legally happen in such strings ReadString(sb, se, input, cursor, end, true, true); break; } default: TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor); } if(cursor > end) { TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1),input, cursor); } // the type code is contained in the returned range send_out = cursor; }
// ------------------------------------------------------------------------------------------------ // Close a filestream. void Q3BSPZipArchive::Close(IOStream *pFile) { ai_assert(pFile != NULL); // We don't do anything in case the file would be opened again in the future }
// ------------------------------------------------------------------------------------------------ void TempMesh::RemoveAdjacentDuplicates() { bool drop = false; std::vector<IfcVector3>::iterator base = verts.begin(); BOOST_FOREACH(unsigned int& cnt, vertcnt) { if (cnt < 2){ base += cnt; continue; } IfcVector3 vmin,vmax; ArrayBounds(&*base, cnt ,vmin,vmax); const IfcFloat epsilon = (vmax-vmin).SquareLength() / static_cast<IfcFloat>(1e9); //const IfcFloat dotepsilon = 1e-9; //// look for vertices that lie directly on the line between their predecessor and their //// successor and replace them with either of them. //for(size_t i = 0; i < cnt; ++i) { // IfcVector3& v1 = *(base+i), &v0 = *(base+(i?i-1:cnt-1)), &v2 = *(base+(i+1)%cnt); // const IfcVector3& d0 = (v1-v0), &d1 = (v2-v1); // const IfcFloat l0 = d0.SquareLength(), l1 = d1.SquareLength(); // if (!l0 || !l1) { // continue; // } // const IfcFloat d = (d0/sqrt(l0))*(d1/sqrt(l1)); // if ( d >= 1.f-dotepsilon ) { // v1 = v0; // } // else if ( d < -1.f+dotepsilon ) { // v2 = v1; // continue; // } //} // drop any identical, adjacent vertices. this pass will collect the dropouts // of the previous pass as a side-effect. FuzzyVectorCompare fz(epsilon); std::vector<IfcVector3>::iterator end = base+cnt, e = std::unique( base, end, fz ); if (e != end) { cnt -= static_cast<unsigned int>(std::distance(e, end)); verts.erase(e,end); drop = true; } // check front and back vertices for this polygon if (cnt > 1 && fz(*base,*(base+cnt-1))) { verts.erase(base+ --cnt); drop = true; } // removing adjacent duplicates shouldn't erase everything :-) ai_assert(cnt>0); base += cnt; } if(drop) { IFCImporter::LogDebug("removing duplicate vertices"); } }
//! Hax function... not mine. int ModelImporter::FindValidPath(aiString* p_szString) { ai_assert(NULL != p_szString); aiString pcpy = *p_szString; if ('*' == p_szString->data[0]) { // '*' as first character indicates an embedded file return 5; } // first check whether we can directly load the file FILE* pFile = fopen(p_szString->data,"rb"); if (pFile)fclose(pFile); else { // check whether we can use the directory of the asset as relative base char szTemp[MAX_PATH*2], tmp2[MAX_PATH*2]; strcpy(szTemp, mFilename.c_str()); strcpy(tmp2,szTemp); char* szData = p_szString->data; if (*szData == '\\' || *szData == '/')++szData; char* szEnd = strrchr(szTemp,'\\'); if (!szEnd) { szEnd = strrchr(szTemp,'/'); if (!szEnd)szEnd = szTemp; } szEnd++; *szEnd = 0; strcat(szEnd,szData); pFile = fopen(szTemp,"rb"); if (!pFile) { // convert the string to lower case for (unsigned int i = 0;;++i) { if ('\0' == szTemp[i])break; szTemp[i] = (char)tolower(szTemp[i]); } if(TryLongerPath(szTemp,p_szString))return 1; *szEnd = 0; // search common sub directories strcat(szEnd,"tex\\"); strcat(szEnd,szData); pFile = fopen(szTemp,"rb"); if (!pFile) { if(TryLongerPath(szTemp,p_szString))return 1; *szEnd = 0; strcat(szEnd,"textures\\"); strcat(szEnd,szData); pFile = fopen(szTemp,"rb"); if (!pFile) { if(TryLongerPath(szTemp, p_szString))return 1; } // patch by mark sibly to look for textures files in the asset's base directory. const char *path=pcpy.data; const char *p=strrchr( path,'/' ); if( !p ) p=strrchr( path,'\\' ); if( p ){ char *q=strrchr( tmp2,'/' ); if( !q ) q=strrchr( tmp2,'\\' ); if( q ){ strcpy( q+1,p+1 ); if(pFile=fopen( tmp2,"r" ) ){ fclose( pFile ); strcpy(p_szString->data,tmp2); p_szString->length = strlen(tmp2); return 1; } } } return 0; } } fclose(pFile); // copy the result string back to the aiString const size_t iLen = strlen(szTemp); size_t iLen2 = iLen+1; iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2; memcpy(p_szString->data,szTemp,iLen2); p_szString->length = iLen; } return 1; }
// ------------------------------------------------------------------------------------------------ ZipFile::ZipFile(size_t size) : m_Size(size) { ai_assert(m_Size != 0); m_Buffer = malloc(m_Size); }
//------------------------------------------------------------------------------- int CMaterialManager::CreateMaterial( AssetHelper::MeshHelper* pcMesh,const aiMesh* pcSource) { ai_assert(NULL != pcMesh); ai_assert(NULL != pcSource); ID3DXBuffer* piBuffer; D3DXMACRO sMacro[64]; // extract all properties from the ASSIMP material structure const aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[pcSource->mMaterialIndex]; // // DIFFUSE COLOR -------------------------------------------------- // if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_DIFFUSE, (aiColor4D*)&pcMesh->vDiffuseColor)) { pcMesh->vDiffuseColor.x = 1.0f; pcMesh->vDiffuseColor.y = 1.0f; pcMesh->vDiffuseColor.z = 1.0f; pcMesh->vDiffuseColor.w = 1.0f; } // // SPECULAR COLOR -------------------------------------------------- // if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_SPECULAR, (aiColor4D*)&pcMesh->vSpecularColor)) { pcMesh->vSpecularColor.x = 1.0f; pcMesh->vSpecularColor.y = 1.0f; pcMesh->vSpecularColor.z = 1.0f; pcMesh->vSpecularColor.w = 1.0f; } // // AMBIENT COLOR -------------------------------------------------- // if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_AMBIENT, (aiColor4D*)&pcMesh->vAmbientColor)) { pcMesh->vAmbientColor.x = 0.0f; pcMesh->vAmbientColor.y = 0.0f; pcMesh->vAmbientColor.z = 0.0f; pcMesh->vAmbientColor.w = 1.0f; } // // EMISSIVE COLOR ------------------------------------------------- // if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_EMISSIVE, (aiColor4D*)&pcMesh->vEmissiveColor)) { pcMesh->vEmissiveColor.x = 0.0f; pcMesh->vEmissiveColor.y = 0.0f; pcMesh->vEmissiveColor.z = 0.0f; pcMesh->vEmissiveColor.w = 1.0f; } // // Opacity -------------------------------------------------------- // if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_OPACITY,&pcMesh->fOpacity)) { pcMesh->fOpacity = 1.0f; } // // Shading Model -------------------------------------------------- // bool bDefault = false; if(AI_SUCCESS != aiGetMaterialInteger(pcMat,AI_MATKEY_SHADING_MODEL,(int*)&pcMesh->eShadingMode )) { bDefault = true; pcMesh->eShadingMode = aiShadingMode_Gouraud; } // // Shininess ------------------------------------------------------ // if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_SHININESS,&pcMesh->fShininess)) { // assume 15 as default shininess pcMesh->fShininess = 15.0f; } else if (bDefault)pcMesh->eShadingMode = aiShadingMode_Phong; // // Shininess strength ------------------------------------------------------ // if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_SHININESS_STRENGTH,&pcMesh->fSpecularStrength)) { // assume 1.0 as default shininess strength pcMesh->fSpecularStrength = 1.0f; } aiString szPath; aiTextureMapMode mapU(aiTextureMapMode_Wrap),mapV(aiTextureMapMode_Wrap); bool bib =false; if (pcSource->mTextureCoords[0]) { // // DIFFUSE TEXTURE ------------------------------------------------ // if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0),&szPath)) { LoadTexture(&pcMesh->piDiffuseTexture,&szPath); aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0),(int*)&mapU); aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0),(int*)&mapV); } // // SPECULAR TEXTURE ------------------------------------------------ // if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SPECULAR(0),&szPath)) { LoadTexture(&pcMesh->piSpecularTexture,&szPath); } // // OPACITY TEXTURE ------------------------------------------------ // if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_OPACITY(0),&szPath)) { LoadTexture(&pcMesh->piOpacityTexture,&szPath); } else { int flags = 0; aiGetMaterialInteger(pcMat,AI_MATKEY_TEXFLAGS_DIFFUSE(0),&flags); // try to find out whether the diffuse texture has any // non-opaque pixels. If we find a few, use it as opacity texture if (pcMesh->piDiffuseTexture && !(flags & aiTextureFlags_IgnoreAlpha) && HasAlphaPixels(pcMesh->piDiffuseTexture)) { int iVal; // NOTE: This special value is set by the tree view if the user // manually removes the alpha texture from the view ... if (AI_SUCCESS != aiGetMaterialInteger(pcMat,"no_a_from_d",0,0,&iVal)) { pcMesh->piOpacityTexture = pcMesh->piDiffuseTexture; pcMesh->piOpacityTexture->AddRef(); } } } // // AMBIENT TEXTURE ------------------------------------------------ // if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_AMBIENT(0),&szPath)) { LoadTexture(&pcMesh->piAmbientTexture,&szPath); } // // EMISSIVE TEXTURE ------------------------------------------------ // if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_EMISSIVE(0),&szPath)) { LoadTexture(&pcMesh->piEmissiveTexture,&szPath); } // // Shininess TEXTURE ------------------------------------------------ // if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SHININESS(0),&szPath)) { LoadTexture(&pcMesh->piShininessTexture,&szPath); } // // Lightmap TEXTURE ------------------------------------------------ // if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_LIGHTMAP(0),&szPath)) { LoadTexture(&pcMesh->piLightmapTexture,&szPath); } // // NORMAL/HEIGHT MAP ------------------------------------------------ // bool bHM = false; if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_NORMALS(0),&szPath)) { LoadTexture(&pcMesh->piNormalTexture,&szPath); } else { if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_HEIGHT(0),&szPath)) { LoadTexture(&pcMesh->piNormalTexture,&szPath); } else bib = true; bHM = true; } // normal/height maps are sometimes mixed up. Try to detect the type // of the texture automatically if (pcMesh->piNormalTexture) { HMtoNMIfNecessary(pcMesh->piNormalTexture, &pcMesh->piNormalTexture,bHM); } } // check whether a global background texture is contained // in this material. Some loaders set this value ... if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_GLOBAL_BACKGROUND_IMAGE,&szPath)) { CBackgroundPainter::Instance().SetTextureBG(szPath.data); } // BUGFIX: If the shininess is 0.0f disable phong lighting // This is a workaround for some meshes in the DX SDK (e.g. tiny.x) // FIX: Added this check to the x-loader, but the line remains to // catch other loader doing the same ... if (0.0f == pcMesh->fShininess){ pcMesh->eShadingMode = aiShadingMode_Gouraud; } int two_sided = 0; aiGetMaterialInteger(pcMat,AI_MATKEY_TWOSIDED,&two_sided); pcMesh->twosided = (two_sided != 0); // check whether we have already a material using the same // shader. This will decrease loading time rapidly ... for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) { if (g_pcAsset->pcScene->mMeshes[i] == pcSource) { break; } AssetHelper::MeshHelper* pc = g_pcAsset->apcMeshes[i]; if ((pcMesh->piDiffuseTexture != NULL ? true : false) != (pc->piDiffuseTexture != NULL ? true : false)) continue; if ((pcMesh->piSpecularTexture != NULL ? true : false) != (pc->piSpecularTexture != NULL ? true : false)) continue; if ((pcMesh->piAmbientTexture != NULL ? true : false) != (pc->piAmbientTexture != NULL ? true : false)) continue; if ((pcMesh->piEmissiveTexture != NULL ? true : false) != (pc->piEmissiveTexture != NULL ? true : false)) continue; if ((pcMesh->piNormalTexture != NULL ? true : false) != (pc->piNormalTexture != NULL ? true : false)) continue; if ((pcMesh->piOpacityTexture != NULL ? true : false) != (pc->piOpacityTexture != NULL ? true : false)) continue; if ((pcMesh->piShininessTexture != NULL ? true : false) != (pc->piShininessTexture != NULL ? true : false)) continue; if ((pcMesh->piLightmapTexture != NULL ? true : false) != (pc->piLightmapTexture != NULL ? true : false)) continue; if ((pcMesh->eShadingMode != aiShadingMode_Gouraud ? true : false) != (pc->eShadingMode != aiShadingMode_Gouraud ? true : false)) continue; if ((pcMesh->fOpacity != 1.0f ? true : false) != (pc->fOpacity != 1.0f ? true : false)) continue; if (pcSource->HasBones() != g_pcAsset->pcScene->mMeshes[i]->HasBones()) continue; // we can reuse this material if (pc->piEffect) { pcMesh->piEffect = pc->piEffect; pc->bSharedFX = pcMesh->bSharedFX = true; pcMesh->piEffect->AddRef(); return 2; } } m_iShaderCount++; // build macros for the HLSL compiler unsigned int iCurrent = 0; if (pcMesh->piDiffuseTexture) { sMacro[iCurrent].Name = "AV_DIFFUSE_TEXTURE"; sMacro[iCurrent].Definition = "1"; ++iCurrent; if (mapU == aiTextureMapMode_Wrap) sMacro[iCurrent].Name = "AV_WRAPU"; else if (mapU == aiTextureMapMode_Mirror) sMacro[iCurrent].Name = "AV_MIRRORU"; else // if (mapU == aiTextureMapMode_Clamp) sMacro[iCurrent].Name = "AV_CLAMPU"; sMacro[iCurrent].Definition = "1"; ++iCurrent; if (mapV == aiTextureMapMode_Wrap) sMacro[iCurrent].Name = "AV_WRAPV"; else if (mapV == aiTextureMapMode_Mirror) sMacro[iCurrent].Name = "AV_MIRRORV"; else // if (mapV == aiTextureMapMode_Clamp) sMacro[iCurrent].Name = "AV_CLAMPV"; sMacro[iCurrent].Definition = "1"; ++iCurrent; } if (pcMesh->piSpecularTexture) { sMacro[iCurrent].Name = "AV_SPECULAR_TEXTURE"; sMacro[iCurrent].Definition = "1"; ++iCurrent; } if (pcMesh->piAmbientTexture) { sMacro[iCurrent].Name = "AV_AMBIENT_TEXTURE"; sMacro[iCurrent].Definition = "1"; ++iCurrent; } if (pcMesh->piEmissiveTexture) { sMacro[iCurrent].Name = "AV_EMISSIVE_TEXTURE"; sMacro[iCurrent].Definition = "1"; ++iCurrent; } char buff[32]; if (pcMesh->piLightmapTexture) { sMacro[iCurrent].Name = "AV_LIGHTMAP_TEXTURE"; sMacro[iCurrent].Definition = "1"; ++iCurrent; int idx; if(AI_SUCCESS == aiGetMaterialInteger(pcMat,AI_MATKEY_UVWSRC_LIGHTMAP(0),&idx) && idx >= 1 && pcSource->mTextureCoords[idx]) { sMacro[iCurrent].Name = "AV_TWO_UV"; sMacro[iCurrent].Definition = "1"; ++iCurrent; sMacro[iCurrent].Definition = "IN.TexCoord1"; } else sMacro[iCurrent].Definition = "IN.TexCoord0"; sMacro[iCurrent].Name = "AV_LIGHTMAP_TEXTURE_UV_COORD"; ++iCurrent;float f= 1.f; aiGetMaterialFloat(pcMat,AI_MATKEY_TEXBLEND_LIGHTMAP(0),&f); sprintf(buff,"%f",f); sMacro[iCurrent].Name = "LM_STRENGTH"; sMacro[iCurrent].Definition = buff; ++iCurrent; } if (pcMesh->piNormalTexture && !bib) { sMacro[iCurrent].Name = "AV_NORMAL_TEXTURE"; sMacro[iCurrent].Definition = "1"; ++iCurrent; } if (pcMesh->piOpacityTexture) { sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE"; sMacro[iCurrent].Definition = "1"; ++iCurrent; if (pcMesh->piOpacityTexture == pcMesh->piDiffuseTexture) { sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE_REGISTER_MASK"; sMacro[iCurrent].Definition = "a"; ++iCurrent; } else { sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE_REGISTER_MASK"; sMacro[iCurrent].Definition = "r"; ++iCurrent; } } if (pcMesh->eShadingMode != aiShadingMode_Gouraud && !g_sOptions.bNoSpecular) { sMacro[iCurrent].Name = "AV_SPECULAR_COMPONENT"; sMacro[iCurrent].Definition = "1"; ++iCurrent; if (pcMesh->piShininessTexture) { sMacro[iCurrent].Name = "AV_SHININESS_TEXTURE"; sMacro[iCurrent].Definition = "1"; ++iCurrent; } } if (1.0f != pcMesh->fOpacity) { sMacro[iCurrent].Name = "AV_OPACITY"; sMacro[iCurrent].Definition = "1"; ++iCurrent; } if( pcSource->HasBones()) { sMacro[iCurrent].Name = "AV_SKINNING"; sMacro[iCurrent].Definition = "1"; ++iCurrent; } // If a cubemap is active, we'll need to lookup it for calculating // a physically correct reflection if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode()) { sMacro[iCurrent].Name = "AV_SKYBOX_LOOKUP"; sMacro[iCurrent].Definition = "1"; ++iCurrent; } sMacro[iCurrent].Name = NULL; sMacro[iCurrent].Definition = NULL; // compile the shader if(FAILED( D3DXCreateEffect(g_piDevice, g_szMaterialShader.c_str(),(UINT)g_szMaterialShader.length(), (const D3DXMACRO*)sMacro,NULL,0,NULL,&pcMesh->piEffect,&piBuffer))) { // failed to compile the shader if( piBuffer) { MessageBox(g_hDlg,(LPCSTR)piBuffer->GetBufferPointer(),"HLSL",MB_OK); piBuffer->Release(); } // use the default material instead if (g_piDefaultEffect) { pcMesh->piEffect = g_piDefaultEffect; g_piDefaultEffect->AddRef(); } // get the name of the material and use it in the log message if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szPath) && '\0' != szPath.data[0]) { std::string sz = "[ERROR] Unable to load material: "; sz.append(szPath.data); CLogDisplay::Instance().AddEntry(sz); } else { CLogDisplay::Instance().AddEntry("Unable to load material: UNNAMED"); } return 0; } else { // use Fixed Function effect when working with shaderless cards if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) pcMesh->piEffect->SetTechnique( "MaterialFX_FF"); } if( piBuffer) piBuffer->Release(); // now commit all constants to the shader // // This is not necessary for shared shader. Shader constants for // shared shaders are automatically recommited before the shader // is being used for a particular mesh if (1.0f != pcMesh->fOpacity) pcMesh->piEffect->SetFloat("TRANSPARENCY",pcMesh->fOpacity); if (pcMesh->eShadingMode != aiShadingMode_Gouraud && !g_sOptions.bNoSpecular) { pcMesh->piEffect->SetFloat("SPECULARITY",pcMesh->fShininess); pcMesh->piEffect->SetFloat("SPECULAR_STRENGTH",pcMesh->fSpecularStrength); } pcMesh->piEffect->SetVector("DIFFUSE_COLOR",&pcMesh->vDiffuseColor); pcMesh->piEffect->SetVector("SPECULAR_COLOR",&pcMesh->vSpecularColor); pcMesh->piEffect->SetVector("AMBIENT_COLOR",&pcMesh->vAmbientColor); pcMesh->piEffect->SetVector("EMISSIVE_COLOR",&pcMesh->vEmissiveColor); if (pcMesh->piDiffuseTexture) pcMesh->piEffect->SetTexture("DIFFUSE_TEXTURE",pcMesh->piDiffuseTexture); if (pcMesh->piOpacityTexture) pcMesh->piEffect->SetTexture("OPACITY_TEXTURE",pcMesh->piOpacityTexture); if (pcMesh->piSpecularTexture) pcMesh->piEffect->SetTexture("SPECULAR_TEXTURE",pcMesh->piSpecularTexture); if (pcMesh->piAmbientTexture) pcMesh->piEffect->SetTexture("AMBIENT_TEXTURE",pcMesh->piAmbientTexture); if (pcMesh->piEmissiveTexture) pcMesh->piEffect->SetTexture("EMISSIVE_TEXTURE",pcMesh->piEmissiveTexture); if (pcMesh->piNormalTexture) pcMesh->piEffect->SetTexture("NORMAL_TEXTURE",pcMesh->piNormalTexture); if (pcMesh->piShininessTexture) pcMesh->piEffect->SetTexture("SHININESS_TEXTURE",pcMesh->piShininessTexture); if (pcMesh->piLightmapTexture) pcMesh->piEffect->SetTexture("LIGHTMAP_TEXTURE",pcMesh->piLightmapTexture); if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode()){ pcMesh->piEffect->SetTexture("lw_tex_envmap",CBackgroundPainter::Instance().GetTexture()); } return 1; }
//------------------------------------------------------------------------------- void CMaterialManager::HMtoNMIfNecessary( IDirect3DTexture9* piTexture, IDirect3DTexture9** piTextureOut, bool bWasOriginallyHM) { ai_assert(NULL != piTexture); ai_assert(NULL != piTextureOut); bool bMustConvert = false; uintptr_t iElement = 3; *piTextureOut = piTexture; // Lock the input texture and try to determine its type. // Criterias: // - If r,g,b channel are identical it MUST be a height map // - If one of the rgb channels is used and the others are empty it // must be a height map, too. // - If the average color of the whole image is something inside the // purple range we can be sure it is a normal map // // - Otherwise we assume it is a normal map // To increase performance we take not every pixel D3DLOCKED_RECT sRect; D3DSURFACE_DESC sDesc; piTexture->GetLevelDesc(0,&sDesc); if (FAILED(piTexture->LockRect(0,&sRect,NULL,D3DLOCK_READONLY))) { return; } const int iPitchDiff = (int)sRect.Pitch - (int)(sDesc.Width * 4); struct SColor { union { struct {unsigned char b,g,r,a;}; char _array[4]; }; }; const SColor* pcData = (const SColor*)sRect.pBits; union { const SColor* pcPointer; const unsigned char* pcCharPointer; }; pcPointer = pcData; // 1. If r,g,b channel are identical it MUST be a height map bool bIsEqual = true; for (unsigned int y = 0; y < sDesc.Height;++y) { for (unsigned int x = 0; x < sDesc.Width;++x) { if (pcPointer->b != pcPointer->r || pcPointer->b != pcPointer->g) { bIsEqual = false; break; } pcPointer++; } pcCharPointer += iPitchDiff; } if (bIsEqual)bMustConvert = true; else { // 2. If one of the rgb channels is used and the others are empty it // must be a height map, too. pcPointer = pcData; while (*pcCharPointer == 0)pcCharPointer++; iElement = (uintptr_t)(pcCharPointer - (unsigned char*)pcData) % 4; unsigned int aiIndex[3] = {0,1,2}; if (3 != iElement)aiIndex[iElement] = 3; pcPointer = pcData; bIsEqual = true; if (3 != iElement) { for (unsigned int y = 0; y < sDesc.Height;++y) { for (unsigned int x = 0; x < sDesc.Width;++x) { for (unsigned int ii = 0; ii < 3;++ii) { // don't take the alpha channel into account. // if the texture was stored n RGB888 format D3DX has // converted it to ARGB8888 format with a fixed alpha channel if (aiIndex[ii] != 3 && pcPointer->_array[aiIndex[ii]] != 0) { bIsEqual = false; break; } } pcPointer++; } pcCharPointer += iPitchDiff; } if (bIsEqual)bMustConvert = true; else { // If the average color of the whole image is something inside the // purple range we can be sure it is a normal map // (calculate the average color line per line to prevent overflows!) pcPointer = pcData; aiColor3D clrColor; for (unsigned int y = 0; y < sDesc.Height;++y) { aiColor3D clrColorLine; for (unsigned int x = 0; x < sDesc.Width;++x) { clrColorLine.r += pcPointer->r; clrColorLine.g += pcPointer->g; clrColorLine.b += pcPointer->b; pcPointer++; } clrColor.r += clrColorLine.r /= (float)sDesc.Width; clrColor.g += clrColorLine.g /= (float)sDesc.Width; clrColor.b += clrColorLine.b /= (float)sDesc.Width; pcCharPointer += iPitchDiff; } clrColor.r /= (float)sDesc.Height; clrColor.g /= (float)sDesc.Height; clrColor.b /= (float)sDesc.Height; if (!(clrColor.b > 215 && clrColor.r > 100 && clrColor.r < 140 && clrColor.g > 100 && clrColor.g < 140)) { // Unable to detect. Believe the original value obtained from the loader if (bWasOriginallyHM) { bMustConvert = true; } } } } } piTexture->UnlockRect(0); // if the input data is assumed to be a height map we'll // need to convert it NOW if (bMustConvert) { D3DSURFACE_DESC sDesc; piTexture->GetLevelDesc(0, &sDesc); IDirect3DTexture9* piTempTexture; if(FAILED(g_piDevice->CreateTexture( sDesc.Width, sDesc.Height, piTexture->GetLevelCount(), sDesc.Usage, sDesc.Format, sDesc.Pool, &piTempTexture, NULL))) { CLogDisplay::Instance().AddEntry( "[ERROR] Unable to create normal map texture", D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0)); return; } DWORD dwFlags; if (3 == iElement)dwFlags = D3DX_CHANNEL_LUMINANCE; else if (2 == iElement)dwFlags = D3DX_CHANNEL_RED; else if (1 == iElement)dwFlags = D3DX_CHANNEL_GREEN; else /*if (0 == iElement)*/dwFlags = D3DX_CHANNEL_BLUE; if(FAILED(D3DXComputeNormalMap(piTempTexture, piTexture,NULL,0,dwFlags,1.0f))) { CLogDisplay::Instance().AddEntry( "[ERROR] Unable to compute normal map from height map", D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0)); piTempTexture->Release(); return; } *piTextureOut = piTempTexture; piTexture->Release(); } }
//------------------------------------------------------------------------------- int CMaterialManager::LoadTexture(IDirect3DTexture9** p_ppiOut,aiString* szPath) { ai_assert(NULL != p_ppiOut); ai_assert(NULL != szPath); *p_ppiOut = NULL; const std::string s = szPath->data; TextureCache::iterator ff; if ((ff = sCachedTextures.find(s)) != sCachedTextures.end()) { *p_ppiOut = (*ff).second; (*p_ppiOut)->AddRef(); return 1; } // first get a valid path to the texture if( 5 == FindValidPath(szPath)) { // embedded file. Find its index unsigned int iIndex = atoi(szPath->data+1); if (iIndex < g_pcAsset->pcScene->mNumTextures) { if (0 == g_pcAsset->pcScene->mTextures[iIndex]->mHeight) { // it is an embedded file ... don't need the file format hint, // simply let D3DX load the file D3DXIMAGE_INFO info; if (FAILED(D3DXCreateTextureFromFileInMemoryEx(g_piDevice, g_pcAsset->pcScene->mTextures[iIndex]->pcData, g_pcAsset->pcScene->mTextures[iIndex]->mWidth, D3DX_DEFAULT, D3DX_DEFAULT, 1, D3DUSAGE_AUTOGENMIPMAP, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, &info, NULL, p_ppiOut))) { std::string sz = "[ERROR] Unable to load embedded texture (#1): "; sz.append(szPath->data); CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0)); this->SetDefaultTexture(p_ppiOut); return 1; } } else { // fill a new texture ... if(FAILED(g_piDevice->CreateTexture( g_pcAsset->pcScene->mTextures[iIndex]->mWidth, g_pcAsset->pcScene->mTextures[iIndex]->mHeight, 0,D3DUSAGE_AUTOGENMIPMAP,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,p_ppiOut,NULL))) { std::string sz = "[ERROR] Unable to load embedded texture (#2): "; sz.append(szPath->data); CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0)); this->SetDefaultTexture(p_ppiOut); return 1; } // now copy the data to it ... (assume non pow2 to be supported) D3DLOCKED_RECT sLock; (*p_ppiOut)->LockRect(0,&sLock,NULL,0); const aiTexel* pcData = g_pcAsset->pcScene->mTextures[iIndex]->pcData; for (unsigned int y = 0; y < g_pcAsset->pcScene->mTextures[iIndex]->mHeight;++y) { memcpy(sLock.pBits,pcData,g_pcAsset->pcScene->mTextures[iIndex]-> mWidth *sizeof(aiTexel)); sLock.pBits = (char*)sLock.pBits + sLock.Pitch; pcData += g_pcAsset->pcScene->mTextures[iIndex]->mWidth; } (*p_ppiOut)->UnlockRect(0); (*p_ppiOut)->GenerateMipSubLevels(); } sCachedTextures[s] = *p_ppiOut; (*p_ppiOut)->AddRef(); return 1; } else { std::string sz = "[ERROR] Invalid index for embedded texture: "; sz.append(szPath->data); CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0)); SetDefaultTexture(p_ppiOut); return 1; } } // then call D3DX to load the texture if (FAILED(D3DXCreateTextureFromFileEx( g_piDevice, szPath->data, D3DX_DEFAULT, D3DX_DEFAULT, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, p_ppiOut))) { // error ... use the default texture instead std::string sz = "[ERROR] Unable to load texture: "; sz.append(szPath->data); CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0)); this->SetDefaultTexture(p_ppiOut); } sCachedTextures[s] = *p_ppiOut; (*p_ppiOut)->AddRef(); return 1; }
//------------------------------------------------------------------------------- int CMeshRenderer::DrawSorted(unsigned int iIndex,const aiMatrix4x4& mWorld) { ai_assert(iIndex < g_pcAsset->pcScene->mNumMeshes); AssetHelper::MeshHelper* pcHelper = g_pcAsset->apcMeshes[iIndex]; const aiMesh* pcMesh = g_pcAsset->pcScene->mMeshes[iIndex]; if (!pcHelper || !pcMesh || !pcHelper->piIB) return -5; if (pcMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE || pcMesh->HasBones() || g_sOptions.bNoAlphaBlending) return DrawUnsorted(iIndex); // compute the position of the camera in worldspace aiMatrix4x4 mWorldInverse = mWorld; mWorldInverse.Inverse(); mWorldInverse.Transpose(); const aiVector3D vLocalCamera = mWorldInverse * g_sCamera.vPos; // well ... this is really funny now. We must compute their distance // from the camera. We take the average distance of a face and add it // to a map which sorts it std::map<float,unsigned int, std::greater<float> > smap; for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace) { const aiFace* pcFace = &pcMesh->mFaces[iFace]; float fDist = 0.0f; for (unsigned int c = 0; c < 3;++c) { aiVector3D vPos = pcMesh->mVertices[pcFace->mIndices[c]]; vPos -= vLocalCamera; fDist += vPos.SquareLength(); } smap.insert(std::pair<float, unsigned int>(fDist,iFace)); } // now we can lock the index buffer and rebuild it D3DINDEXBUFFER_DESC sDesc; pcHelper->piIB->GetDesc(&sDesc); if (D3DFMT_INDEX16 == sDesc.Format) { uint16_t* aiIndices; pcHelper->piIB->Lock(0,0,(void**)&aiIndices,D3DLOCK_DISCARD); for (std::map<float,unsigned int, std::greater<float> >::const_iterator i = smap.begin(); i != smap.end();++i) { const aiFace* pcFace = &pcMesh->mFaces[(*i).second]; *aiIndices++ = (uint16_t)pcFace->mIndices[0]; *aiIndices++ = (uint16_t)pcFace->mIndices[1]; *aiIndices++ = (uint16_t)pcFace->mIndices[2]; } } else if (D3DFMT_INDEX32 == sDesc.Format) { uint32_t* aiIndices; pcHelper->piIB->Lock(0,0,(void**)&aiIndices,D3DLOCK_DISCARD); for (std::map<float,unsigned int, std::greater<float> >::const_iterator i = smap.begin(); i != smap.end();++i) { const aiFace* pcFace = &pcMesh->mFaces[(*i).second]; *aiIndices++ = (uint32_t)pcFace->mIndices[0]; *aiIndices++ = (uint32_t)pcFace->mIndices[1]; *aiIndices++ = (uint32_t)pcFace->mIndices[2]; } } pcHelper->piIB->Unlock(); // set vertex and index buffer g_piDevice->SetStreamSource(0,pcHelper->piVB,0,sizeof(AssetHelper::Vertex)); // and draw the mesh g_piDevice->SetIndices(pcHelper->piIB); g_piDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,0, pcMesh->mNumVertices,0, pcMesh->mNumFaces); return 1; }
// ------------------------------------------------------------------------------------------------ // void M3Importer::convertToAssimp( const std::string& pFile, aiScene* pScene, DIV *pViews, Region *pRegions, uint16 *pFaces, const std::vector<aiVector3D> &vertices, const std::vector<aiVector3D> &normals ) { std::vector<aiMesh*> MeshArray; // Create the root node pScene->mRootNode = createNode( NULL ); // Set the name of the scene ai_assert( !pFile.empty() ); pScene->mRootNode->mName.Set( pFile ); aiNode *pRootNode = pScene->mRootNode; aiNode *pCurrentNode = NULL; // Lets create the nodes pRootNode->mNumChildren = pViews->regions.nEntries; if ( pRootNode->mNumChildren > 0 ) pRootNode->mChildren = new aiNode*[ pRootNode->mNumChildren ]; for ( unsigned int i=0; i<pViews->regions.nEntries; ++i ) { // Create a new node pCurrentNode = createNode( pRootNode ); std::stringstream stream; stream << "Node_" << i; pCurrentNode->mName.Set( stream.str().c_str() ); pRootNode->mChildren[ i ] = pCurrentNode; // Loop over the faces of the nodes unsigned int numFaces = ( pRegions[ i ].ofsIndices + pRegions[ i ].nIndices ) - pRegions[ i ].ofsIndices; aiMesh *pMesh = new aiMesh; MeshArray.push_back( pMesh ); pMesh->mNumFaces = numFaces; pMesh->mFaces = new aiFace[ pMesh->mNumFaces ]; aiFace *pCurrentFace = NULL; unsigned int faceIdx = 0; for ( unsigned int j = pRegions[ i ].ofsIndices; j < ( pRegions[ i ].ofsIndices + pRegions[ i ].nIndices ); j += 3 ) { pCurrentFace = &( pMesh->mFaces[ faceIdx ] ); faceIdx++; pCurrentFace->mNumIndices = 3; pCurrentFace->mIndices = new unsigned int[ 3 ]; pCurrentFace->mIndices[ 0 ] = pFaces[ j ]+1; pCurrentFace->mIndices[ 1 ] = pFaces[ j+1 ] + 1; pCurrentFace->mIndices[ 2 ] = pFaces[ j+2 ] + 1; } // Now we can create the vertex data itself pCurrentNode->mNumMeshes = 1; pCurrentNode->mMeshes = new unsigned int[ 1 ]; pCurrentNode->mMeshes[ 0 ] = MeshArray.size() - 1; createVertexData( pMesh, vertices, normals ); } // Copy the meshes into the scene pScene->mNumMeshes = MeshArray.size(); pScene->mMeshes = new aiMesh*[ MeshArray.size() ]; unsigned int pos = 0; for ( std::vector<aiMesh*>::iterator it = MeshArray.begin(); it != MeshArray.end(); ++it ) { pScene->mMeshes[ pos ] = *it; pos++; } }