ホーム < ゲームつくろー! < DirectX技術編 < Xファイルにカスタムテンプレートデータを保存してみよう:サンプルプログラム


その33 Xファイルにカスタムテンプレートデータを保存してみよう:サンプルプログラム


 DirectX技術編その33「Xファイルにカスタムテンプレートデータを保存してみよう」で説明した内容を踏まえたサンプルプログラムです。実行すると、PersonID.xというテンプレートを定義したファイルからテンプレート定義を読み込み、それを登録した後に、SaveID.xというファイルに対して名前とID番号をXファイル形式で登録します。このプログラムには描画情報はありません。


 以下のプログラムは指定のカスタムテンプレート(PersonID.x)をパスの通った場所に置き、空のプロジェクトにコピペすることで完全に動きます。PersonIDテンプレートは世界に一つしかない番号が振られておりますので、こちらからファイルをダウンロードしてください。上からデバッグしていくと、何をしているか良くわかるように1つのソースで完結させています。今回のポイントになりそうなところは太文字で示されています。

(もしうまく動かないようでしたら掲示板にてご連絡下さい)

(2011. 12. 4改正)
・ MemoryStockerクラスにunsigned long型の対処が無かったので追加。
・ main.cpp内でMemoryStocker.hがインクルードされていなかったのを改正。

MemoryStockerクラス(MemoryStocker.h)
// MemoryStocker.h (2007. 8. 10)

// メモリストッククラス

#pragma once

#include <stdlib.h>
#include <malloc.h>
#include <string.h>

namespace IKD{


/////////////////////////////////////////////////////
// MemoryStocker : オブジェクトメモリ操作クラス
// 色々な情報を格納できる連続的なメモリバッファを作成し
// 登録関数や演算子によりデータを登録する。
//////
class MemoryStocker
{
protected:
   unsigned char *m_pBuf; // メモリバッファへのポインタ
   size_t m_Pos; // 現在のポインタ位置
   size_t m_Size; // 現在のサイズ
   size_t m_FullSize; // 現在の確保メモリ
   size_t m_Remain; // 残りのメモリ量
   size_t m_Unit; // メモリの拡張単位
   size_t *m_pHash; // データアクセスハッシュ
   size_t *m_pSzAry; // 登録データサイズ配列
   size_t m_RegNum; // 登録数
   int m_iPrec; // 浮動小数点精度

public:
   MemoryStocker(){
      m_pBuf = (unsigned char*)malloc(0); m_Pos = 0; m_Unit=10; m_Size=0; m_Remain = 0; m_FullSize=0;
      m_pHash = (size_t*)malloc(0); m_pSzAry = (size_t*)malloc(0); m_RegNum=0;
      m_iPrec = 8;
   }
   ~MemoryStocker(){
      free(m_pBuf);
      free(m_pHash);
      free(m_pSzAry);
   }

   /////////////////////////////////
   // 引数付きマニピュレータ

   // オブジェクトハードコピー
   template<class T> MemoryStocker& Obj( T* Obj ){AddData( (void*)T, sizeof(T) ); return *this;}


   /////////////////////
   // オペレータ
   ////
   MemoryStocker& operator <<(const int &val){AddData( (void*)&val, sizeof(const int) ); return *this;}
   MemoryStocker& operator <<(int &val){AddData( (void*)&val, sizeof(int) ); return *this;}
   MemoryStocker& operator <<(const unsigned int &val){AddData( (void*)&val, sizeof(const unsigned int) ); return *this;}
   MemoryStocker& operator <<(unsigned int &val){AddData( (void*)&val, sizeof(int) ); return *this;}
   MemoryStocker& operator <<(const unsigned long &val){AddData( (void*)&val, sizeof(const unsigned long) ); return *this;}
   MemoryStocker& operator <<(unsigned long &val){AddData( (void*)&val, sizeof(unsigned long) ); return *this;}
   MemoryStocker& operator <<(const float &val){AddData( (void*)&val, sizeof(const float) ); return *this;}
   MemoryStocker& operator <<(float &val){AddData( (void*)&val, sizeof(float) ); return *this;}
   MemoryStocker& operator <<(const double &val){AddData( (void*)&val, sizeof(const double) ); return *this;}
   MemoryStocker& operator <<(double &val){AddData( (void*)&val, sizeof(double) ); return *this;}
   MemoryStocker& operator <<(const unsigned char &val){AddData( (void*)&val, sizeof(const unsigned char) ); return *this;}
   MemoryStocker& operator <<(unsigned char &val){AddData( (void*)&val, sizeof(unsigned char) ); return *this;}
   MemoryStocker& operator <<(const unsigned short &val){AddData( (void*)&val, sizeof(const unsigned short) ); return *this;}
   MemoryStocker& operator <<(unsigned short &val){AddData( (void*)&val, sizeof(unsigned short) ); return *this;}
   MemoryStocker& operator <<(const char &val){AddData( (void*)&val, sizeof(const char) ); return *this;}
   MemoryStocker& operator <<(char &val){AddData( (void*)&val, sizeof(char) ); return *this;}
   MemoryStocker& operator <<(const void* &val){AddData( (void*)&val, sizeof(const void*) ); return *this;} // 汎用ポインタ
   MemoryStocker& operator <<(void* &val){AddData( (void*)&val, sizeof(void*) ); return *this;}
   MemoryStocker& operator <<(const void* val){AddData( (void*)val, sizeof(const void*) ); return *this;} // 汎用ポインタ
   MemoryStocker& operator <<(void* val){AddData( (void*)val, sizeof(void*) ); return *this;}
   MemoryStocker& operator <<(MemoryStocker &val){AddData( (void*)(val.GetRootPtr()), val.Size() ); return *this;}

   // 文字列は特別
   MemoryStocker& operator <<(const char* val){AddData( (void*)val, strlen(val)+1 ); return *this;}
   MemoryStocker& operator <<(char* &val){AddData( (void*)val, strlen(val)+1 ); return *this;}


public:
   //////////////////////////////////////////
   // 指定のサイズ分データをメモリに格納
   ///////
   MemoryStocker& AddData( void* dataptr, size_t size ){
      // 残量メモリをチェックし、足りなければ拡張
      size_t tmpRemain = m_Remain;
      int cnt = 0;
      while( tmpRemain < size ){
         tmpRemain += m_Unit;
         cnt++;
      }
      // カウント数分だけメモリを拡張
      unsigned char *p = (unsigned char*)realloc( m_pBuf, m_FullSize+cnt*m_Unit );
      if(!p) // 確保失敗
      return *this;

      // ハッシュを拡張
      size_t *pH = (size_t*)realloc( m_pHash, (m_RegNum+1)*sizeof(size_t));
      if(!pH) // 確保失敗
      return *this;

      // 登録サイズ配列を拡張
      size_t *pSz = (size_t*)realloc( m_pSzAry, (m_RegNum+1)*sizeof(size_t));
      if(!pSz) // 確保失敗
         return *this;

      // 増加部分を初期化
      memset( p+m_FullSize, 0, cnt*m_Unit);

      // 情報を格納
      memcpy( p+m_Pos, dataptr, size );
      pH[m_RegNum] = m_Pos; // ハッシュ位置登録
      pSz[m_RegNum] = size; // サイズ登録

      // メモリ情報を更新
      m_Pos+=size; // 現在位置を更新
      m_FullSize += cnt*m_Unit;
      m_Size += size;
      m_Remain = m_FullSize - m_Size;
      m_RegNum++;

      m_pBuf = p; // ポインタを更新
      m_pHash = pH;
      m_pSzAry = pSz;

      return *this;
   }

   ///////////////////////////
   // ルートポインタを取得
   /////
   void *GetRootPtr(){ return (void*)m_pBuf; }

   ///////////////////////
   // 保存サイズを取得
   /////
   size_t Size(){ return m_Size; }

   /////////////////////
   // 情報を取得
   /////
   size_t GetData( size_t elem, void** pout ){
      if( elem >= m_RegNum ){ // 指定の要素が無い
         if(pout)
            *pout=NULL;
         return 0;
      }
      if(pout)
         memcpy(*pout, m_pBuf+m_pHash[elem], m_pSzAry[elem]);
      // サイズを返す
      return m_pSzAry[elem];
   }

   ////////////////////////
   // コピー関連
   /////////
   // コピーコンストラクタ
   MemoryStocker( const MemoryStocker& src ) {
      // 自分の情報を削除
      free( m_pBuf );
      m_pBuf = (unsigned char*)malloc(0); m_Pos = 0; m_Unit=10; m_Size=0; m_Remain = 0; m_FullSize=0;
      m_pHash = (size_t*)malloc(0); m_pSzAry = (size_t*)malloc(0); m_RegNum=0;
      m_iPrec = 8;
      AddData( src.m_pBuf, src.m_Size );
   }

   // 代入演算子
   MemoryStocker& operator = ( MemoryStocker& src ) {
      free( m_pBuf );
      m_pBuf = (unsigned char*)malloc(0); m_Pos = 0; m_Unit=10; m_Size=0; m_Remain = 0; m_FullSize=0;
      m_pHash = (size_t*)malloc(0); m_pSzAry = (size_t*)malloc(0); m_RegNum=0;
      m_iPrec = 8;
      AddData( src.m_pBuf, src.m_Size );
      return *this;
   }
};


} // end namespace IKD
XFileカスタムテンプレートセーブテスト(main.cpp)
/// XFileカスタムテンプレートセーブテスト

#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "d3dxof.lib")

#include <windows.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <dxfile.h>   // Xファイル関連を使用するのに必要
#include <fstream>
#include "memorystocker.h"

using namespace std;
using namespace IKD;

// PersonIDテンプレートGUID
const GUID PersonID_GUID ={ 0xB2B63407,0x6AA9,0x4618, 0x95, 0x63, 0x63, 0x1E, 0xDC, 0x20, 0x4C, 0xDE};

// テキストファイルをメモリにコピーする関数
char* GetFileText( char* filename ){
   ifstream ifs;
   ifs.open( filename );
   if( !ifs.is_open() )
      return NULL;
   DWORD FileSize=0;
   while(!ifs.eof()){ ifs.ignore(); FileSize++;}  // サイズ取得
   ifs.clear(); ifs.seekg(0, ios_base::beg);      // ファイルポインタを初期位置へ
   char* tmp = new char[FileSize];
   ZeroMemory( tmp, FileSize );
   ifs.read( tmp, FileSize-1);
   return tmp;
}


int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
   // カスタムテンプレートファイルからテンプレート定義を抽出
   char* g_pTEMPLATE_PERSONID = GetFileText( "PersonID.x" );
   if( !g_pTEMPLATE_PERSONID ){
      return 0;
   }

   // セーブするテンプレート文字列を取得
   IDirectXFile *pDXFile;
   DirectXFileCreate( &pDXFile );
   if(FAILED(pDXFile->RegisterTemplates( g_pTEMPLATE_PERSONID, strlen( g_pTEMPLATE_PERSONID ) ))){
      return 0;
   }

   // セーブオブジェクトを作成する
   IDirectXFileSaveObject *pDXSave;
   if(FAILED(pDXFile->CreateSaveObject("SaveID.x", DXFILEFORMAT_TEXT, &pDXSave ))){
      pDXFile->Release(); return 0;
   }

   // 保存するデータを生成   
   MemoryStocker MS;
   char *Name = "IKD";   // 名前
   DWORD val = 1234;     // ID番号

   MS << &Name << val;  // 文字列はダブルポインタを与えます

   void* ptr = MS.GetRootPtr();

   // データオブジェクトを作成する
   IDirectXFileData *pDXData;
   if(FAILED(pDXSave->CreateDataObject( PersonID_GUID, "Me", NULL, MS.Size(), ptr, &pDXData))){
       pDXSave->Release(); pDXFile->Release(); return 0;
   }

   // データをセーブする
   if(FAILED(pDXSave->SaveData( pDXData ))){
       pDXData->Release(); pDXSave->Release(); pDXFile->Release(); return 0;
   }

   // Xファイル関連のインターフェイスを解放
   pDXData->Release();
   pDXSave->Release();
   pDXFile->Release();

   return 0;
}