DirectXのクラス化について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
結城
記事: 52
登録日時: 14年前
連絡を取る:

DirectXのクラス化について

#1

投稿記事 by 結城 » 14年前

ご無沙汰してますhinariです
今回とある事情に迫られてDirectXによるノベルエンジンを作ることになったのですが
便宜のために文字の表示を行うプロセスをクラス化したところ
画面に描画されなくなってしまいました
どなたか助けていただけないでしょうか?

開発環境
OS[tab=30][tab=30]Windows XP Professional SP3
コンパイラ[tab=30][tab=30]Visual Studio 2010 C++ Express
開発ライブラリバージョン[tab=30]Microsoft DirectX SDK June 2010 (ENG)
文字エンコード[tab=30][tab=30]Unicode

以下はそのコードです

Class D3DTextをGrobal.hにて定義
Metius.cppよりD3DTextをddtとして使用
DirectXの描画処理は_tWinMain内のメインループで行っています

Struct.h(一部抜粋)

コード:

//多重インクルードガード
#ifndef	STRUCT_H
#define	STRUCT_H

struct CUSTOMVERTEX{  
   float x, y, z; // 頂点座標 
   float rhw;     // 除算数 
   float u, v;    // テクスチャ座標 
};

struct CUSTOMVERTEX_T{
   float x,y,z; // 頂点座標 
   float rhw; // 除算数
   DWORD dwColor; // 頂点の色
   float u, v; // テクスチャ座標 
};

struct STRALPHA{
	DWORD color;//予約変数
	LPDIRECT3DTEXTURE9 tex;
	IDirect3DVertexBuffer9 * pVertex_t;
};
#endif
Global.h

コード:

#include "Struct.h"

/*グローバルな定義*/
/*定義固定値*/

#define	DEFWIDTH	1028
#define	DEFHEIGHT	576

/*構造体最大数*/
#define	IMGS	256

/*DirctXのための定義*/
#define MAX_LOADSTRING 100
#define RELEASE(p) { if(p){(p)->Release();p=NULL;} }
/// 頂点関係 ///
#define FVF_CUSTOM ( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 ) // 座標変換済み頂点

/*型定義*/
#define	STRALPHA_NEW(N)	(STRALPHA *)malloc(sizeof(STRALPHA)*N);
#define	STRALPHA_RELEASE(_X)	{free(_X);}
#define	STRALPHA_SIZE_T	size_t

#ifndef	GLOBAL_DECLARE
#define	GLOBAL
#else
#define	GLOBAL	extern
#endif

//PC操作関数

//レジストリの文字列を取得します
	GLOBAL	void GetRegStr(HKEY OpenKey , LPCWSTR KeyRoot , LPCWSTR ValueName, TCHAR& Dest);
	GLOBAL	int DrawImageForAll(IDirect3DDevice9 * &SrcDev,int Width = DEFWIDTH,int Height = DEFHEIGHT);
	GLOBAL	BOOL SetPos(IDirect3DVertexBuffer9* vtx, float Cx, float Cy, float width, float height);

/*グローバル変数*/

/*グローバル構造体変数*/
	GLOBAL	ImageLoad_t imgset[IMGS];
	//GLOBAL	

	GLOBAL	class	D3DText{
	public:
		//IDirect3DVertexBuffer9* pVertex_t;
		DWORD dwColor;    //A,R,G,Bとデータが入っているため
		/*テキスト関数群*/
		float TextSet(IDirect3DDevice9 * &SrcDev,TCHAR *c,LPDIRECT3DTEXTURE9 *Dest,IDirect3DVertexBuffer9 * &pVertex_dest,float x = 0.0f,float y = 0.0f,DWORD FontColor = 0xffffffff);//文字単体を描画する
		void _Draw(IDirect3DDevice9 * &SrcDev,IDirect3DVertexBuffer9 * &pVertex_t);
		int	_DrawString(IDirect3DDevice9 * &SrcDev,TCHAR *c,STRALPHA * &stralpha,STRALPHA_SIZE_T size,float x = 0.0f,float y = 0.0f,DWORD Color = 0xffffffff);//Colorにはアルファ情報を含みます
		void _AlphaChange(IDirect3DDevice9 * &SrcDev,LPDIRECT3DTEXTURE9 &Src,DWORD Color);
	};
Draw2D01.cpp(一部抜粋)

コード:

#include "stdafx.h"
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9tex.h>
#include "Global.h"

float D3DText::TextSet(IDirect3DDevice9 * &SrcDev,TCHAR *c,LPDIRECT3DTEXTURE9 *Dest,IDirect3DVertexBuffer9 * &pVertex_dest,float x,float y,DWORD FontColor)
{
	// フォントの生成
	int fontsize = 60;
	LOGFONT lf = {fontsize, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS,
		CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FIXED_PITCH | FF_MODERN, _T("MS UI Gothic")};
	HFONT hFont;
	if(!(hFont = CreateFontIndirect(&lf))){
		SrcDev->Release();
		return -1.0f;
	}

   // デバイスコンテキスト取得
   // デバイスにフォントを持たせないとGetGlyphOutline関数はエラーとなる
   HDC hdc = GetDC(NULL);
   HFONT oldFont = (HFONT)SelectObject(hdc, hFont);

	// 文字コード取得
	//TCHAR *c = _T("あ");
	UINT code = 0;
#if _UNICODE
	// unicodeの場合、文字コードは単純にワイド文字のUINT変換です
	code = (UINT)*c;
#else
	// マルチバイト文字の場合、
	// 1バイト文字のコードは1バイト目のUINT変換、
	// 2バイト文字のコードは[先導コード]*256 + [文字コード]です
	if(IsDBCSLeadByte(*c))
		code = (BYTE)c[0]<<8 | (BYTE)c[1];
	else
		code = c[0];
#endif

	// フォントビットマップ取得
	TEXTMETRIC TM;
	GetTextMetrics( hdc, &TM );
	GLYPHMETRICS GM;
	CONST MAT2 Mat = {{0,1},{0,0},{0,0},{0,1}};
	DWORD size = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, 0, NULL, &Mat);
	BYTE *ptr = new BYTE[size];
	GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, size, ptr, &Mat);

	// デバイスコンテキストとフォントハンドルの開放
	SelectObject(hdc, oldFont);
	DeleteObject(hFont);
	ReleaseDC(NULL, hdc);


	// 頂点情報
	float a = 1.0f; // テクスチャの縮尺
	float fTexW = GM.gmCellIncX * a; // テクスチャの横幅
	float fTexH = TM.tmHeight * a; // テクスチャの高さ
	//DWORD FontColor = 0xffffffff; // テクスチャカラー(透明度50%)

	CUSTOMVERTEX_T v[]=
	{
		{ fTexW + x,	y,			0.0f,	1.0f,	FontColor,	1.0f,	0.0f},
		{ fTexW + x,	fTexH + y,	0.0f,	1.0f,	FontColor,	1.0f,	1.0f}, 
		{ x,			y,			0.0f,	1.0f,	FontColor,	0.0f,	0.0f}, 
		{ x,			fTexH + y,	0.0f,	1.0f,	FontColor,	0.0f,	1.0f} 
	};

	// 頂点バッファ作成
	if(FAILED(SrcDev->CreateVertexBuffer(sizeof(CUSTOMVERTEX_T)*4, D3DUSAGE_WRITEONLY, FVF_CUSTOM,
		D3DPOOL_MANAGED, &pVertex_dest, NULL))){
			SrcDev->Release();delete[] ptr;
			return -1.0f;
	}
	// 頂点情報の書き込み
	void *pData;
	if(FAILED(pVertex_dest->Lock(0, sizeof(CUSTOMVERTEX_T)*4, (void**)&pData, 0))){
		SrcDev->Release();delete[] ptr;
		return -1.0f;
	}
	memcpy(pData, v, sizeof(CUSTOMVERTEX_T)*4);
	pVertex_dest->Unlock();


	// テクスチャ作成
	LPDIRECT3DTEXTURE9 pTex;
	if(FAILED(SrcDev->CreateTexture( GM.gmCellIncX, TM.tmHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pTex, NULL))){
		if(FAILED(SrcDev->CreateTexture( GM.gmCellIncX, TM.tmHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pTex, NULL)))
		{
			SrcDev->Release();delete[] ptr;
			return -1.0f;
		}
	}

	// テクスチャにフォントビットマップ書き込み
	D3DLOCKED_RECT LockedRect;
	if(FAILED(pTex->LockRect(0, &LockedRect, NULL, D3DLOCK_DISCARD))){
		if(FAILED(pTex->LockRect(0, &LockedRect, NULL, 0)))
		{
			SrcDev->Release();delete[] ptr;
			return -1.0f;
		}
	}
	// フォント情報の書き込み
	// iOfs_x, iOfs_y : 書き出し位置(左上)
	// iBmp_w, iBmp_h : フォントビットマップの幅高
	// Level : α値の段階 (GGO_GRAY4_BITMAPなので17段階)
	int iOfs_x = GM.gmptGlyphOrigin.x;
	int iOfs_y = TM.tmAscent - GM.gmptGlyphOrigin.y;
	int iBmp_w = GM.gmBlackBoxX + (4-(GM.gmBlackBoxX%4))%4;
	int iBmp_h = GM.gmBlackBoxY;
	int Level = 17;
	int _x, _y;
	DWORD Alpha, Color;
	FillMemory(LockedRect.pBits , LockedRect.Pitch * TM.tmHeight, 0);
	for(_y=iOfs_y; _y<iOfs_y+iBmp_h; _y++){
		for(_x=iOfs_x; _x<iOfs_x+iBmp_w; _x++){
			Alpha = (255 * ptr[_x-iOfs_x + iBmp_w*(_y-iOfs_y)]) / (Level-1);
			Color = 0x00ffffff | (Alpha<<24);
			memcpy((BYTE*)LockedRect.pBits + LockedRect.Pitch*_y + 4*_x, &Color, sizeof(DWORD));
		}
	}
	pTex->UnlockRect(0);
	delete[] ptr;

	// テクスチャセット
	SrcDev->SetTexture(0, pTex);
	// テクスチャアルファセット
	SrcDev->SetRenderState(D3DRS_TEXTUREFACTOR,Color);
	SrcDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); 
	SrcDev->SetTextureStageState(0, D3DTSS_COLOROP , D3DTOP_MODULATE );
	SrcDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); 
	SrcDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
	SrcDev->SetTextureStageState(0, D3DTSS_ALPHAOP , D3DTOP_MODULATE ); 
	SrcDev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR ); // 板ポリのα値を利用

	// レンダリングステート
	SrcDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	SrcDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	SrcDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 

	/*
	pD3Device->SetStreamSource(0, pVertex_t, 0, sizeof(CUSTOMVERTEX_T));
	pD3Device->SetFVF(FVF_CUSTOM);
	pD3Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
	*/

	if(Dest != NULL)*Dest = pTex;

	return	fTexW;
}

void D3DText::_Draw(IDirect3DDevice9 * &SrcDev,IDirect3DVertexBuffer9 * &pVertex_t)
{
	SrcDev->SetStreamSource(0, pVertex_t, 0, sizeof(CUSTOMVERTEX_T));
	SrcDev->SetFVF(FVF_CUSTOM);
	SrcDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}

void _AlphaChange(IDirect3DDevice9 * &SrcDev,LPDIRECT3DTEXTURE9 &Src,DWORD Color)
{
	// テクスチャセット
	SrcDev->SetTexture(0, Src);
	// テクスチャアルファセット
	SrcDev->SetRenderState(D3DRS_TEXTUREFACTOR,Color);
	SrcDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); 
	SrcDev->SetTextureStageState(0, D3DTSS_COLOROP , D3DTOP_MODULATE );
	SrcDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); 
	SrcDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
	SrcDev->SetTextureStageState(0, D3DTSS_ALPHAOP , D3DTOP_MODULATE ); 
	SrcDev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR ); // 板ポリのα値を利用

	// レンダリングステート
	SrcDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	SrcDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	SrcDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 
}

int	D3DText::_DrawString(IDirect3DDevice9 * &SrcDev,TCHAR *c,STRALPHA * &stralpha,STRALPHA_SIZE_T size,float x,float y,DWORD Color)
{
	LPDIRECT3DTEXTURE9	Dest;
	float currentwidth = 0.0f;
	int j = 0;
	TCHAR k[256];
	ZeroMemory(k,_tcslen(k)-1);

	for(TCHAR * i = c; *i; ++i)
	{
		k[0] = *i;
		if((currentwidth = D3DText::TextSet(SrcDev,&k[0],&stralpha[j].tex,stralpha[j].pVertex_t,x + currentwidth,y,Color)) == -1)return -1;
		j++;
	}
	return 1;
}
Metius.cpp(デバイス作成以降抜粋)

コード:

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_METIUS));

	imgset[0].flag=TRUE;
	_tcscpy(imgset[0].Src,L"Water lilies.jpg");
	imgset[0].x=32;

	ShowWindow(hWnd,nCmdShow);

	D3DText	ddt;
	static IDirect3DVertexBuffer9 * dest_v;
	ddt.TextSet(pD3Device,_T("あ"),NULL,dest_v);
	/*
	int w = _tcslen(_T("てすとてすと"));
	STRALPHA * stralpha = STRALPHA_NEW(w);
	ddt._DrawString(pD3Device,_T("てすとてすと"),stralpha,w);
	*/

	// メッセージ ループ
	do{
		Sleep(1);
		if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ){ DispatchMessage(&msg);}
		else{
			// Direct3Dの処理
			pD3Device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
			pD3Device->BeginScene();

			// 描画
			DrawImageForAll(pD3Device);
			ddt._Draw(pD3Device,dest_v);
			/*
			for(int i = 0; i < w; i++)ddt._Draw(pD3Device,stralpha[i].pVertex_t);
			*/

			pD3Device->EndScene();
			pD3Device->Present( NULL, NULL, NULL, NULL );
		}
	}while(msg.message != WM_QUIT);

	// 解放
	RELEASE( pD3Device );
	RELEASE( pDirect3D );


	return 0;
}
ANGE;ART

アバター
うしお
記事: 56
登録日時: 14年前

Re: DirectXのクラス化について

#2

投稿記事 by うしお » 14年前

あせる気持ちは分かりますが、
このように大量のコードを前に、ここが~だ、と全部的確に判断できる人は熟練でもなかなかいないでしょう。

デバッガで、ステップ実行などを駆使し、
・呼ばれるべきメソッドが呼ばれないのか?、それは何行目か?
・処理の順番は正しいか?
・記述漏れがないか?
・変数に異常な数が入っていないか?初期化漏れがないか?

等をチェックし、自信をもって正しいと言える箇所を増やしていき、
曖昧な部分を無くして「バグの範囲を狭めて行く」のがデバッグの基本です。
難問は分割せよ、とデカルトも言っています。

例えばクラスを作るときもいきなりDirectxの乱雑な処理をいくのではなく、
空実装で処理の順番や結果を確かめ、それから少しずつ移行していく、といった方法も取れるかと思います。
大きな変更の前にはバックアップを取り、それと見比べてみるのもよいかもしれません。

また、Directxでのデバッグでは、
"(DIRECTX_SDK_DIR) \Utilities\bin\x86\PIXWin.exe"
PIX for Windows というデバッガもありますので、使ってみるのも一つの道かもしれません。
 使い方http://www.t-pot.com/program/131_PIX/index.html

「謎の部分」を絞った質問は、解決も早いですし、質問者、回答者ともに負担が少なく、
皆幸せになれるとおもいます^-^
ご検討ください。

アバター
結城
記事: 52
登録日時: 14年前
連絡を取る:

Re: DirectXのクラス化について

#3

投稿記事 by 結城 » 14年前

うしお様
確かにその通りですね^^;
少し焦りすぎたかもしれません、もう少し情報を選別してみたいと思います
うしお さんが書きました: また、Directxでのデバッグでは、
"(DIRECTX_SDK_DIR) \Utilities\bin\x86\PIXWin.exe"
PIX for Windows というデバッガもありますので、使ってみるのも一つの道かもしれません。
 使い方http://www.t-pot.com/program/131_PIX/index.html
このようなものがあったのですか!
知りませんでした……
さっそく使ってみたいと思います
ANGE;ART

アバター
うしお
記事: 56
登録日時: 14年前

Re: DirectXのクラス化について

#4

投稿記事 by うしお » 14年前

蛇足かもしれませんが、
PIX は日本語を含むパス名が苦手なようなので注意してください^^;昔それでハマったことがあります。

fr

Re: DirectXのクラス化について

#5

投稿記事 by fr » 14年前

クラスを使うだけなら既に用意されている
http://marupeke296.com/TOOL_No5_BillboardString.html
を使うのはどうでしょうか?

アバター
結城
記事: 52
登録日時: 14年前
連絡を取る:

Re: DirectXのクラス化について

#6

投稿記事 by 結城 » 14年前

これは……!
サイトの巡回不足でしたか……
fr様教えてくださってありがとうございます
一度これでやってみようかと思います
ANGE;ART

閉鎖

“C言語何でも質問掲示板” へ戻る