DirectX9 までサポートされていた、モデル・アニメーションを保存するフォーマット
Xファイルですが、D3DX のサポート終了とともに、読み込む方法がなくなってしまいました。
(代替フォーマットがいくらでもあり、ふつうは困らないのですが・・・・)
今回、現行バージョン(2016年末現在)のDirectX11 で読み込んでみようというねらいで、
Xファイル読み込みのプログラムをフルスクラッチで組もうと考えました。まず第一弾として、
テキスト形式、第二弾でバイナリ形式・・・でいいかなと思ったのですが、やはり不完全は
悔しく、圧縮形式に対応しようと考え、ネットを見て圧縮されたxファイルのフォーマットを
探しました。DirectX9付属のドキュメント、MSDN、あれこれ調べましたが、詳しい情報は
結局見つかりませんでした。DirectX9のドキュメントでさえ「圧縮ストリームはサポートされない」
とのつれない言葉。
仕方ないので、判る範囲の情報から、自分であれこれ試しながら調べてみました。結果として
動くようになりました。完全に仕様を把握できているか疑問ですが、こんなフォーマットになっているようです。
ここにある数値は多分こういう意味だろうという推測とやってみるでなんとか動かしています。
正確かどうかは保証できませんが、このフォーマットを重要な業務に使うとも思えないので、
多少違っていてもいいのかなと。
Required Header(s) | Compressapi.h |
Required Library(s) | Cabinet.lib |
/// // @brief Decompress the specified compressed x file. // // @param // pBufferCompressed [in] compressed x file data // dwSize [in] size of compressed data // ppBufferUncompressed [out] buffer to store uncompressed data // pdwUncompressedSize [out] size of uncompressed data // // @return // S_OK : succeeded // E_FAIL : failed // HRESULT DecompressMSZipXFile(BYTE *pBufferCompressed, DWORD dwSize, BYTE **ppBufferUncompressed, DWORD *pdwUncompressedSize){ HRESULT hr = E_FAIL; DECOMPRESSOR_HANDLE hCompress = NULL; BYTE *pNewBuffer = NULL; BYTE *pSrc, *pDest; DWORD finalSize; DWORD compressedSize, bytesRead; DWORD uncompressedSize, uncompressedSum; //! prepare decompressor for RFC 1951 compression if (0 == CreateDecompressor(COMPRESS_ALGORITHM_MSZIP|COMPRESS_RAW,NULL,&hCompress)){ goto EXIT; } //! preparation pSrc = pBufferCompressed + 16; bytesRead = 16; uncompressedSize = 0; uncompressedSum = 0; finalSize = *(DWORD*)pSrc; //!< Read the uncompressed size pNewBuffer = new BYTE[finalSize]; pDest = pNewBuffer; pSrc += sizeof(DWORD); bytesRead += sizeof(DWORD); uncompressedSum += 16; pDest += 16; //! Decompress blocks loop. while(bytesRead < dwSize && uncompressedSum < finalSize){ uncompressedSize = *(WORD*)pSrc; pSrc += sizeof(WORD); compressedSize = *(WORD*)pSrc; pSrc += sizeof(WORD); if (0 == Decompress(hCompress,(VOID*)pSrc,compressedSize,pDest,uncompressedSize,0)){ //DWORD err = GetLastError(); SAFE_DELETE(pNewBuffer); goto EXIT; } bytesRead += compressedSize+4; pSrc += compressedSize; pDest += uncompressedSize; uncompressedSum += uncompressedSize; } { //! Clone the x file header DWORD *pdwSrc = (DWORD*)pBufferCompressed; DWORD *pdwDest = (DWORD*)pNewBuffer; *pdwDest++ = *pdwSrc++; //!< xof *pdwDest++ = *pdwSrc++; //!< vers //! bin/txt if (0==_strnicmp((CHAR*)pdwSrc,"bzip",4)){ *pdwDest = *(DWORD*)"bin "; }else if (0==_strnicmp((CHAR*)pdwSrc,"tzip",4)){ *pdwDest = *(DWORD*)"txt "; }else{ SAFE_DELETE(pNewBuffer); goto EXIT; } pdwDest++; pdwSrc++; *pdwDest++ = *pdwSrc++; //!< float length (means precision) } hr = S_OK; EXIT: if (hCompress != NULL) CloseDecompressor(hCompress); *ppBufferUncompressed = pNewBuffer; *pdwUncompressedSize = uncompressedSum; return hr; }