トップページ > 過去ログ > 記事閲覧
文字にグラデーション
名前:チルチル 日時: 2010/08/19 18:14

いつもありがとうございます 今回は文字についてなんですが DrawString関数やDrawFormatString関数などで 描画する文字列にグラデーションを付けることは可能でしょうか? エッジの有無は関係なく、中の文字本体の色を 上は白で下に行くほど赤とか青にしたりすると キレイに見えそうなのでやってみたいのですが 私が思い付く方法は SetDrawArea関数で描画可能領域を横一列ずつにして 縦のピクセル数だけ色を変えながら描画する ぐらいです・・ これでもできない事はないと思いますが 描画に時間がかかって処理落ちしそうだし 文字を描画する所で毎回そんな事をすると コードが異常に長くなってしまいそうです なんとか簡単に実現する方法はないでしょうか?

Page: 1 | 2 |

Re: 文字にグラデーション ( No.15 )
名前:いっち 日時:2010/08/27 22:48

> sprintf関数は使わない方がスッキリすると思って > 可変長引数の橋渡しを試みたところ > GetDrawFormatStringWidth関数では成功しましたが > DrawFormatStringToZBuffer関数で失敗しているようなのです 受け取った可変引数を利用するには、va_start マクロ等を使う必要があります。 また、そのまま他の関数に渡す場合は、可変引数を va_list に変換してから vsprintf 等の va_list を引数に取る関数に渡す必要があります。 しかし、DXライブラリの DrawString 系関数にはそういった関数が無いので現状では直接の橋渡しはできません。 事前に sprintf や vsprintf 等で変換することをお勧めします。 (GetDrawFormatStringWidth に続けて DrawFormatString を使うのはいかにも2度手間な感じがしますし)
Re: 文字にグラデーション ( No.16 )
名前:チルチル 日時:2010/08/28 18:12

おお、なるほど DxLib.hを見ていて元の関数名に"V"が付いただけの関数がいくつもあって 注釈も同じだったので「これはいったい何に使うんだろう?」と思っていましたが 可変長引数の橋渡しに使う関数だったんですね これは良い事を聞きました va_listを引数に取る関数について調べてみるので ちょっと待って下さいね
Re: 文字にグラデーション ( No.17 )
名前:いっち 日時:2010/08/28 20:54

> DxLib.hを見ていて元の関数名に"V"が付いただけの関数がいくつもあって DrawVString 等のことでしょうか? これらはおそらく縦書き用の文字列出力関数です。va_list を引数に取る関数ではありません。
Re: 文字にグラデーション ( No.18 )
名前:チルチル 日時:2010/08/29 17:41

確かに良く見たら思い違いでした・・ ではvsprintfなどを調べてみます
Re: 文字にグラデーション ( No.19 )
名前:チルチル 日時:2010/09/04 21:17

vsprintf_s関数を使って実装してみました 見た目には問題無く動いてくれるのですが どこか間違っている所や無駄な所があるでしょうか? ↓縁なし #include "DxLib.h" // グラデーション文字描画関数 void DrawGradationString( int x, int y, int Color, const char *String, ... ) { int w, h, r, g, b; VERTEX vert[ 6 ] ; char Buffer[128]; va_list List;//可変引数リスト va_start(List,String);//可変引数リストの使用準備 vsprintf_s(Buffer,String,List);//書式付文字列を統合 va_end(List);//可変引数リストの使用終了 // 描画のサイズを取得する w = GetDrawStringWidth( Buffer, -1 ); h = GetFontSize() ; // Zバッファを有効にする SetUseZBufferFlag( TRUE ); // Zバッファに描画する文字列より少し大きいマスクを書き込む DrawBoxToZBuffer( x - 2, y - 2, x + w + 2, y + h + 2, TRUE, DX_ZWRITE_MASK ); // Zバッファに文字列の形でマスクを刳り貫く DrawStringToZBuffer( x, y, Buffer, DX_ZWRITE_CLEAR ); // カラーコードからRGB各成分の取得 GetColor2( Color, &r, &g, &b ) ; // 画像の大きさのグラデーションボックスを描画する( マスクが刳り貫かれているところしか塗りつぶされない ) vert[ 0 ].u = 0.0f ; vert[ 0 ].v = 0.0f ; vert[ 1 ].u = 0.0f ; vert[ 1 ].v = 0.0f ; vert[ 2 ].u = 0.0f ; vert[ 2 ].v = 0.0f ; vert[ 3 ].u = 0.0f ; vert[ 3 ].v = 0.0f ; vert[ 1 ].r = vert[ 0 ].r = 255 ; vert[ 1 ].g = vert[ 0 ].g = 255 ; vert[ 1 ].b = vert[ 0 ].b = 255 ; vert[ 2 ].r = vert[ 3 ].r = r ; vert[ 2 ].g = vert[ 3 ].g = g ; vert[ 2 ].b = vert[ 3 ].b = b ; vert[ 2 ].x = vert[ 0 ].x = x - 1 ; vert[ 3 ].x = vert[ 1 ].x = x + w + 1 ; vert[ 1 ].y = vert[ 0 ].y = y - 1 ; vert[ 3 ].y = vert[ 2 ].y = y + h + 1 ; vert[ 4 ] = vert[ 2 ] ; vert[ 5 ] = vert[ 1 ] ; DrawPolygon( vert, 2, DX_NONE_GRAPH, FALSE ) ; // Zバッファを無効にする SetUseZBufferFlag( FALSE ); } // WinMain関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() == -1 ) return -1; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ); // グラデーションが掛かった文字列を描画する DrawGradationString( 100, 200, GetColor( 255, 0, 0 ), "%s", "グラデーション文字列" ) ; // 裏画面の内容を表画面に反映 ScreenFlip(); // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } ↓縁あり #include "DxLib.h" // グラデーション文字描画関数 void DrawGradationString( int x, int y, int Color, int FontHandle, const char *String, ... ) { int ImageHandle, EdgeImageHandle, DrawWidth ; VERTEX Vertex[ 6 ] ; int r, g, b ; char Buffer[128]; va_list List;//可変引数リスト va_start(List,String);//可変引数リストの使用準備 vsprintf_s(Buffer,String,List);//書式付文字列を統合 va_end(List);//可変引数リストの使用終了 // カラーコードからRGB各成分の取得 GetColor2( Color, &r, &g, &b ) ; int FontSize ; GetFontStateToHandle( NULL , &FontSize , NULL , FontHandle ) ; FontSize+=2; // 文字列イメージを転送する ARGB8形式の画面サイズのメモリイメージを作成( 縁用と二つ ) static int SoftImage = MakeARGB8ColorSoftImage( 640, 480 ) ; static int EdgeSoftImage = MakeARGB8ColorSoftImage( 640, 480 ) ; // 作成したメモリイメージを0で塗りつぶす FillSoftImage( SoftImage, 0, 0, 0, 0 ) ; FillSoftImage( EdgeSoftImage, 0, 0, 0, 0 ) ; // 文字列イメージをメモリイメージに書き込む BltStringSoftImageToHandle( x, y, Buffer, SoftImage, EdgeSoftImage, FontHandle, FALSE ) ; // 描画幅を取得する DrawWidth = GetDrawStringWidthToHandle( Buffer, lstrlen( Buffer ), FontHandle ) ; // 描画幅と描画高さのグラフィックハンドルを作成する ImageHandle = CreateGraphFromRectSoftImage( SoftImage, x, y, DrawWidth, FontSize ) ; EdgeImageHandle = CreateGraphFromRectSoftImage( EdgeSoftImage, x, y, DrawWidth, FontSize ) ; // 縁の部分は黒色で描画 SetDrawBright( 0, 0, 0 ) ; DrawGraph( x, y, EdgeImageHandle, TRUE ) ; SetDrawBright( 255, 255, 255 ) ; // 本体部分は DrawPolygon を使用して上下に赤から青にグラデーションさせながら描画 Vertex[ 0 ].x = x - 0.5f ; Vertex[ 0 ].y = y - 0.5f ; Vertex[ 1 ].x = x + DrawWidth - 0.5f ; Vertex[ 1 ].y = y - 0.5f ; Vertex[ 2 ].x = x - 0.5f ; Vertex[ 2 ].y = y + FontSize - 0.5f ; Vertex[ 3 ].x = x + DrawWidth - 0.5f ; Vertex[ 3 ].y = y + FontSize - 0.5f ; Vertex[ 0 ].u = 0.0f ; Vertex[ 0 ].v = 0.0f ; Vertex[ 1 ].u = 1.0f ; Vertex[ 1 ].v = 0.0f ; Vertex[ 2 ].u = 0.0f ; Vertex[ 2 ].v = 1.0f ; Vertex[ 3 ].u = 1.0f ; Vertex[ 3 ].v = 1.0f ; Vertex[ 0 ].b = 255 ; Vertex[ 0 ].g = 255 ; Vertex[ 0 ].r = 255 ; Vertex[ 0 ].a = 255 ; Vertex[ 1 ].b = 255 ; Vertex[ 1 ].g = 255 ; Vertex[ 1 ].r = 255 ; Vertex[ 1 ].a = 255 ; Vertex[ 2 ].b = b ; Vertex[ 2 ].g = g ; Vertex[ 2 ].r = r ; Vertex[ 2 ].a = 255 ; Vertex[ 3 ].b = b ; Vertex[ 3 ].g = g ; Vertex[ 3 ].r = r ; Vertex[ 3 ].a = 255 ; Vertex[ 4 ] = Vertex[ 2 ] ; Vertex[ 5 ] = Vertex[ 1 ] ; DrawPolygon( Vertex, 2, ImageHandle, TRUE, TRUE ) ; DeleteSoftImage( ImageHandle ) ; DeleteSoftImage( EdgeImageHandle ) ; } // WinMain関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() == -1 ) return -1; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ); // 縁つきアンチエイリアスフォントの作成 int FontHandle = CreateFontToHandle( NULL, -1, -1, DX_FONTTYPE_ANTIALIASING_EDGE ) ; // グラデーションが掛かった文字列を描画する DrawGradationString( 100, 200, GetColor( 255, 0, 0 ), FontHandle, "%s", "グラデーション文字列" ) ; // 裏画面の内容を表画面に反映 ScreenFlip(); // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; }
Re: 文字にグラデーション ( No.20 )
名前:チルチル 日時:2010/09/04 21:41

それから縁ありの方の関数をフォントを変えない場合に対応させてみたのですが こちらも使い方はあっているでしょうか? #include "DxLib.h" // グラデーション文字描画関数 void DrawGradationString( int x, int y, int Color, const char *String, ... ) { int ImageHandle, EdgeImageHandle, DrawWidth ; VERTEX Vertex[ 6 ] ; int r, g, b ; char Buffer[128]; va_list List;//可変引数リスト va_start(List,String);//可変引数リストの使用準備 vsprintf_s(Buffer,String,List);//書式付文字列を統合 va_end(List);//可変引数リストの使用終了 // カラーコードからRGB各成分の取得 GetColor2( Color, &r, &g, &b ) ; int FontSize=GetFontSize()+2; // 文字列イメージを転送する ARGB8形式の画面サイズのメモリイメージを作成( 縁用と二つ ) static int SoftImage = MakeARGB8ColorSoftImage( 640, 480 ) ; static int EdgeSoftImage = MakeARGB8ColorSoftImage( 640, 480 ) ; // 作成したメモリイメージを0で塗りつぶす FillSoftImage( SoftImage, 0, 0, 0, 0 ) ; FillSoftImage( EdgeSoftImage, 0, 0, 0, 0 ) ; // 文字列イメージをメモリイメージに書き込む BltStringSoftImage( x, y, Buffer, SoftImage, EdgeSoftImage, FALSE ) ; // 描画幅を取得する DrawWidth = GetDrawStringWidth( Buffer, -1 ) ; // 描画幅と描画高さのグラフィックハンドルを作成する ImageHandle = CreateGraphFromRectSoftImage( SoftImage, x, y, DrawWidth, FontSize ) ; EdgeImageHandle = CreateGraphFromRectSoftImage( EdgeSoftImage, x, y, DrawWidth, FontSize ) ; // 縁の部分は黒色で描画 SetDrawBright( 0, 0, 0 ) ; DrawGraph( x, y, EdgeImageHandle, TRUE ) ; SetDrawBright( 255, 255, 255 ) ; // 本体部分は DrawPolygon を使用して上下に赤から青にグラデーションさせながら描画 Vertex[ 0 ].x = x - 0.5f ; Vertex[ 0 ].y = y - 0.5f ; Vertex[ 1 ].x = x + DrawWidth - 0.5f ; Vertex[ 1 ].y = y - 0.5f ; Vertex[ 2 ].x = x - 0.5f ; Vertex[ 2 ].y = y + FontSize - 0.5f ; Vertex[ 3 ].x = x + DrawWidth - 0.5f ; Vertex[ 3 ].y = y + FontSize - 0.5f ; Vertex[ 0 ].u = 0.0f ; Vertex[ 0 ].v = 0.0f ; Vertex[ 1 ].u = 1.0f ; Vertex[ 1 ].v = 0.0f ; Vertex[ 2 ].u = 0.0f ; Vertex[ 2 ].v = 1.0f ; Vertex[ 3 ].u = 1.0f ; Vertex[ 3 ].v = 1.0f ; Vertex[ 0 ].b = 255 ; Vertex[ 0 ].g = 255 ; Vertex[ 0 ].r = 255 ; Vertex[ 0 ].a = 255 ; Vertex[ 1 ].b = 255 ; Vertex[ 1 ].g = 255 ; Vertex[ 1 ].r = 255 ; Vertex[ 1 ].a = 255 ; Vertex[ 2 ].b = b ; Vertex[ 2 ].g = g ; Vertex[ 2 ].r = r ; Vertex[ 2 ].a = 255 ; Vertex[ 3 ].b = b ; Vertex[ 3 ].g = g ; Vertex[ 3 ].r = r ; Vertex[ 3 ].a = 255 ; Vertex[ 4 ] = Vertex[ 2 ] ; Vertex[ 5 ] = Vertex[ 1 ] ; DrawPolygon( Vertex, 2, ImageHandle, TRUE, TRUE ) ; DeleteSoftImage( ImageHandle ) ; DeleteSoftImage( EdgeImageHandle ) ; } // WinMain関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() == -1 ) return -1; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ); // 縁つきアンチエイリアスフォントに変更 ChangeFontType( DX_FONTTYPE_ANTIALIASING_EDGE ) ; // グラデーションが掛かった文字列を描画する DrawGradationString( 100, 200, GetColor( 255, 0, 0 ), "%s", "グラデーション文字列" ) ; // 裏画面の内容を表画面に反映 ScreenFlip(); // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } あとGetDrawStringWidth関数の第二引数を-1にするのはリファレンスにも無かったと思うのですが これは文字列の全長を渡した場合と同じ意味になるのでしょうか?
Re: 文字にグラデーション ( No.21 )
名前:いっち 日時:2010/09/05 01:01

vsprintf_s の引数が足りないような気がします。 それと、Buffer のサイズが少し小さいような気がします。(もしくは文字数をチェックをする必要がありそうです)
Re: 文字にグラデーション ( No.22 )
名前:チルチル 日時:2010/09/05 13:37

ありがとうございます vsprintf_s関数に関しては 私の使っているVC++で引数が3個のものがオーバーロードされていたのでそちらを使ってみました Bufferのサイズは128なので2バイト文字の場合に約64文字描画できますが 一文字の横幅が15ピクセルと仮定すると 15×64=960ピクセルとなり 640ピクセルの画面をオーバーするので そんなに長い文字列になる事は無いと決め打ちして とりあえず128にしておきました なのでこの2つは大丈夫だと思いますが 他には特に問題無さそうでしょうか?
Re: 文字にグラデーション ( No.23 )
名前:tare 日時:2010/09/05 17:59

試してないので確証は持てませんが、実行するごとにグラフィックを新しく作っていると動作速度に問題があるような……。 実際に運用するとなると一秒間に60回程度呼び出されるわけですし。
Re: 文字にグラデーション ( No.24 )
名前:チルチル 日時:2010/09/05 20:23

確かに処理落ちしそうなので計測してみたのですが 1フレームに40回描画してみたところ 縁なしでも縁ありでも40回描画するのに約300msもかかりました これは尋常じゃない重さなのでこのままでは使えないですが しかし管理人様が「この方法が1番速い」と仰っていたので これでも速い方なのかもしれません だとしたらグラデーション文字は実現不可能という結論になってしまいます・・ 縁なしの方も重いのでグラフィックだけの問題では無いと思いますが どうにか速くする方法は無いでしょうか?
Re: 文字にグラデーション ( No.25 )
名前:いっち 日時:2010/09/05 22:59

以下のコードで私の環境でも試してみました。 > ttp://www1.axfc.net/uploader/Sc/so/150526.zip&key=dxlib 結果、Zバッファを利用する場合は10000回描画して750ミリ秒を少し超える感じでした。 ソフトイメージを利用する場合は10000回描画して25秒程度でした。 それと、試してみて気づいたのですが、ソフトイメージを利用する場合の以下のコードは > DeleteSoftImage( ImageHandle ) ; > DeleteSoftImage( EdgeImageHandle ) ; 以下のようにするのが正しいと思います。 > DeleteGraph( ImageHandle ) ; > DeleteGraph( EdgeImageHandle ) ; (※上記に掲載したテストコードでは訂正していないです)
Re: 文字にグラデーション ( No.26 )
名前:tare 日時:2010/09/06 13:24

単純に、自分が大分前のレスで言ったように作成と描画を別にすれば解決します。 LoadGraphとDrawGraphの関係と同様です。 管理人さんの仰ったのもそういう運用を想定してのことだと思われます。
Re: 文字にグラデーション ( No.27 )
名前:NNN 日時:2010/09/06 20:58

速度を気にされてるようですが、パフォーマンスの問題の切り分けが出来てないように思います。 tareさんの仰るように予め情報を作成した場合、気になるようなコストにはならないはずです。 どうしても1関数で高速に実行したいなら関数に渡すパラメータを保持する構造体を用意して、 イメージハンドルと共に残して「以前同じパラメータで作成したイメージハンドルがないか」のチェックを行い、 保持したハンドルを使いまわす事で初回描画以外は高速に実行出来るはずです。 言ってる意味が分からないならパフォーマンス等は気にせずもっと基本的な事から勉強される事をお勧めします。
Re: 文字にグラデーション ( No.28 )
名前:チルチル 日時:2010/09/07 23:18

≫いっち様 よく見たらImageHandleとEdgeImageHandleは イメージハンドルではなくグラフィックハンドルなので DeleteSoftImage関数では解放できないですね・・ これを修正すれば少しは速くなるかもしれないので 次はDeleteGraph関数でやってみます ≫tare様 確かに現状では遅すぎるので ある程度は使い回しが効くように分割してみます ≫NNN様 なるほど文字列の描画は毎回同じものを描画する事も多いですから 使い回せば速くなるかもしれませんね 縁なしの方は直接描画なので保持できませんが 縁ありの方は作成したグラフィックハンドルを保持しておけそうです ストップウォッチのように値が高速で変化するものは無理かもしれませんが ImageHandleとEdgeImageHandleを保持すれば グラデーションの変更は容易にできる気もします グラフィックハンドルが溜まってくるとそっちで遅くなりそうなので 古いものとか使ってないものから消していく方法も考えます あと関数内のどこで時間がかかっているかも計ってみます
Re: 文字にグラデーション ( No.29 )
名前:チルチル 日時:2010/09/18 21:46

グラフィックハンドルを使いまわすように改良してみました 値が毎フレーム変化するものについては無力ですが しばらく変わらないものや複数描画するものについては かなり速く処理できるようになりました #include "DxLib.h" #include <list> using namespace std; struct Graph_t { bool flag; char String[128]; int ImageHandle; int EdgeImageHandle; }; list<Graph_t> GraphList; // グラデーション文字描画関数 void DrawGradationString( int x, int y, int Color, const char *String, ... ) { int r, g, b ; // カラーコードからRGB各成分の取得 GetColor2( Color, &r, &g, &b ) ; char Buffer[128]; va_list List;//可変引数リスト va_start(List,String);//可変引数リストの使用準備 vsprintf_s(Buffer,String,List);//書式付文字列を統合 va_end(List);//可変引数リストの使用終了 // 描画幅を取得する int DrawWidth = GetDrawStringWidth( Buffer, -1 ) ; int FontSize=GetFontSize()+2; //////////////////////////////////////////////////////////////////// list<Graph_t>::iterator Graph = GraphList.begin(); while( true ){ if( Graph == GraphList.end() ){ Graph_t Temp; // 文字列イメージを転送する ARGB8形式の画面サイズのメモリイメージを作成( 縁用と二つ ) static int SoftImage = MakeARGB8ColorSoftImage( 640, 480 ) ; static int EdgeSoftImage = MakeARGB8ColorSoftImage( 640, 480 ) ; // 作成したメモリイメージを0で塗りつぶす FillSoftImage( SoftImage, 0, 0, 0, 0 ) ; FillSoftImage( EdgeSoftImage, 0, 0, 0, 0 ) ; // 文字列イメージをメモリイメージに書き込む BltStringSoftImage( 0, 0, Buffer, SoftImage, EdgeSoftImage, FALSE ) ; Temp.flag=false; strcpy_s(Temp.String,Buffer); // 描画幅と描画高さのグラフィックハンドルを作成する Temp.ImageHandle = CreateGraphFromRectSoftImage( SoftImage, 0, 0, DrawWidth, FontSize ) ; Temp.EdgeImageHandle = CreateGraphFromRectSoftImage( EdgeSoftImage, 0, 0, DrawWidth, FontSize ) ; GraphList.push_back( Temp ); --Graph; break; } if( strcmp(Graph->String,Buffer)==0 ){ Graph->flag=false; break; } ++Graph; } /////////////////////////////////////////////////////////////////// // 縁の部分は黒色で描画 SetDrawBright( 0, 0, 0 ) ; DrawGraph( x, y, Graph->EdgeImageHandle, TRUE ) ; SetDrawBright( 255, 255, 255 ) ; VERTEX Vertex[ 6 ] ; // 本体部分は DrawPolygon を使用して上下に赤から青にグラデーションさせながら描画 Vertex[ 0 ].x = x - 0.5f ; Vertex[ 0 ].y = y - 0.5f ; Vertex[ 1 ].x = x + DrawWidth - 0.5f ; Vertex[ 1 ].y = y - 0.5f ; Vertex[ 2 ].x = x - 0.5f ; Vertex[ 2 ].y = y + FontSize - 0.5f ; Vertex[ 3 ].x = x + DrawWidth - 0.5f ; Vertex[ 3 ].y = y + FontSize - 0.5f ; Vertex[ 0 ].u = 0.0f ; Vertex[ 0 ].v = 0.0f ; Vertex[ 1 ].u = 1.0f ; Vertex[ 1 ].v = 0.0f ; Vertex[ 2 ].u = 0.0f ; Vertex[ 2 ].v = 1.0f ; Vertex[ 3 ].u = 1.0f ; Vertex[ 3 ].v = 1.0f ; Vertex[ 0 ].b = 255 ; Vertex[ 0 ].g = 255 ; Vertex[ 0 ].r = 255 ; Vertex[ 0 ].a = 255 ; Vertex[ 1 ].b = 255 ; Vertex[ 1 ].g = 255 ; Vertex[ 1 ].r = 255 ; Vertex[ 1 ].a = 255 ; Vertex[ 2 ].b = b ; Vertex[ 2 ].g = g ; Vertex[ 2 ].r = r ; Vertex[ 2 ].a = 255 ; Vertex[ 3 ].b = b ; Vertex[ 3 ].g = g ; Vertex[ 3 ].r = r ; Vertex[ 3 ].a = 255 ; Vertex[ 4 ] = Vertex[ 2 ] ; Vertex[ 5 ] = Vertex[ 1 ] ; DrawPolygon( Vertex, 2, Graph->ImageHandle, TRUE, TRUE ) ; } // グラデーション文字消去関数 void DeleteGradationString(void) { list<Graph_t>::iterator Graph = GraphList.begin(); while( Graph != GraphList.end() ){ if( Graph->flag ){ DeleteGraph( Graph->ImageHandle ) ; DeleteGraph( Graph->EdgeImageHandle ) ; GraphList.erase(Graph); Graph = GraphList.begin(); } else Graph->flag=true; ++Graph; } } // WinMain関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() == -1 ) return -1; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ); // 縁つきアンチエイリアスフォントに変更 ChangeFontType( DX_FONTTYPE_ANTIALIASING_EDGE ) ; int i=0,Time=0; while( !ProcessMessage() && !ClearDrawScreen() ){ Time=GetNowCount(); // グラデーションが掛かった文字列を描画する for( int j=0;j<20;j++ )DrawGradationString( 300, j*20, GetColor( 255, 255/60*(i%60), 255/60*(i%60) ), "グラデーション文字列 %3d" , i/60 ) ; // グラデーション文字消去 DeleteGradationString(); DrawFormatString(0,0,GetColor(255,255,255),"Count = %4d Time = %2d",i,GetNowCount()-Time); // 裏画面の内容を表画面に反映 ScreenFlip(); ++i; } // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } どのくらい速くなるかのテスト用なのでちょっと汚いですが おそらく間違ってはいないと思います あと書き換える時にGetDrawStringWidth以外にも気になる所があったんですが GetFontSize()の戻り値に2を足しているのと DrawPolygonを使う時に描画位置を-0.5fしているのはなぜでしょうか?
Re: 文字にグラデーション ( No.30 )
名前:管理人 日時:2010/09/19 01:49

GetFontSize() の戻り値に2を足しているのは、GetFontSize の戻り値がフォントの高さと イコールではない場合があるので、フォントの高さが GetFontSize の戻り値より大きくなる 可能性を考えて2を足しています DrawPolygon を使うときに頂点座標を -0.5f しているのは、Direct3D のポリゴンを画面に 描画する際のラスタライズのアルゴリズムとテクスチャフィルタリングのアルゴリズムの関係で、 テクスチャを等倍でキッチリ描画する場合は頂点座標を -0.5f するのが正しいからです ( -0.5f をしないと SetDrawMode( DX_DRAWMODE_BILINEAR )のモードで描画した場合に 文字がぼやけて描画されてしまいます ) こちらに Direct3D のその辺りの事情に関する説明が載っていますので、よろしければ 少し覗いてみてください < Direct3D のラスタライズのアルゴリズムに関する説明 > http://msdn.microsoft.com/ja-jp/library/cc373007.aspx < Direct3D の最近点サンプリング ( SetDrawMode( DX_DRAWMODE_NEAREST ) ) のテクスチャフィルタリングアルゴリズムに関する説明 > http://msdn.microsoft.com/ja-jp/library/cc373044.aspx あと、新しく文字画像を作成する際に FillSoftImage で 640x480 サイズのソフトウエアイメージ全体を 0クリアしていますが、文字が書き込まれる部分だけをクリアすれば良いので、そのための関数を追加しました http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい) 追加した関数はこちらです // ソフトウエアで扱うイメージの指定の領域を0クリアする int ClearRectSoftImage( int SIHandle, int x, int y, int w, int h ) ; こちらの関数を FillSoftImage( SoftImage, 0, 0, 0, 0 ) ; の代わりに ClearRectSoftImage( SIHandle, 0, 0, DrawWidth, FontSize ) ; という風に、文字を書き込む部分だけクリアするともう少し処理負荷が小さくなります よろしければお使い下さい m(_ _)m
Re: 文字にグラデーション ( No.31 )
名前:チルチル 日時:2010/09/20 09:49

なるほどGetFontSize()が正しい値を返すとは限らないんですね DrawPolygonに関しては-0.5しないと どのピクセルを指しているのか曖昧になる ・・と言った感じでしょうか? 確かにClearRectSoftImageを使用して必要な所だけ イメージをクリアした方が効率が良さそうですね 必要な所だけのついでに サイズは変えないと思うので 640×480も領域は使わないように 640×FontSizeにしてみます とりあえず実用的な速度に達したので コードを綺麗に書き直してみます
Re: 文字にグラデーション ( No.32 )
名前:チルチル 日時:2010/09/20 12:38

あと気になったんですが グラデーション文字を描画した時に 「ー」とか「0」の下1ピクセルぐらいが切れるんですが アンチエイリアスエッジの段階で切れているようなので これは仕様なのでしょうか? それからMakeScreen関数で作った画面を ClearDrawScreen関数でクリアすると黒くなると思うのですが これを透明にクリアすることはできないでしょうか? できるとすればDrawGraphとDrawPolygonの結果を保持する事で さらなる高速化が期待できるかもしれません
Re: 文字にグラデーション ( No.33 )
名前:管理人 日時:2010/09/25 20:10

> グラデーション文字を描画した時に > 「ー」とか「0」の下1ピクセルぐらいが切れるんですが > アンチエイリアスエッジの段階で切れているようなので > これは仕様なのでしょうか? いえ、バグです orz 切れないように修正したバージョンをアップしましたので、よろしければお試し下さい m(_ _)m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい) > それからMakeScreen関数で作った画面を > ClearDrawScreen関数でクリアすると黒くなると思うのですが > これを透明にクリアすることはできないでしょうか? MakeScreen で作成した描画可能画像には透明度情報はありませんので、 ClearDrawScreen した結果を透明な状態にしたい場合は 透明度情報( アルファチャンネル )付きの描画可能画像を使用する必要があります SetDrawValidAlphaChannelGraphCreateFlag( TRUE ) ; int Handle = MakeScreen( 640, 480 ) ; SetDrawValidAlphaChannelGraphCreateFlag( FALSE ) ; ただ、アルファチャンネル付きの描画可能画像は少し古いノートパソコンに搭載されているような グラフィックスデバイスだと作成できない場合がありますので、高速化のために使うのには 向かないかもしれません
Re: 文字にグラデーション ( No.34 )
名前:チルチル 日時:2010/10/20 23:02

ライブラリを置き換えたら切れなくなりました どうもありがとうございます 描画可能画像には透明度情報が無かったんですね 古いPCで使えないのは少々危険なので とりあえず保留にしておきます おかげさまで望んでいた結果を得る事ができました 計測用のコードは雑に作ってしまったので もう少し綺麗に書き直して最終的にこんな感じです struct Handle_t {//ハンドルの構造体 bool flag; //フラグ char String[128]; //文字列 int Char; //文字の画像 int Edge; //縁の画像 Handle_t *Next; //次のノードへのポインタ Handle_t *Prev; //前のノードへのポインタ }; class Gradation_c {//グラデーションのクラス private://非公開 Handle_t Sentinel;//番兵ノード Gradation_c(void);//コンストラクタ ~Gradation_c(void);//デストラクタ public://公開 static Gradation_c* New(void);//作成の関数 void DrawGradationString(int x,int y,int Color,char *String);//グラデーション文字列を描画する関数 void Delete(void);//グラデーション文字列を削除する関数 }; Gradation_c::Gradation_c(void){//コンストラクタ Sentinel.Next=Sentinel.Prev=&Sentinel;//番兵ノード循環連結 } Gradation_c::~Gradation_c(void){//デストラクタ for( Handle_t *Handle=Sentinel.Next , *Next=Handle->Next ; Handle!=&Sentinel ; Handle=Next , Next=Handle->Next ){ delete Handle;//ハンドルを削除 } } Gradation_c* Gradation_c::New(void){//作成の関数 static Gradation_c Gradation; return &Gradation; } void Gradation_c::DrawGradationString(int x,int y,int Color,char *String){//グラデーション文字列を描画する関数 int Red,Green,Blue; //RGB成分 GetColor2( Color , &Red , &Green , &Blue ); //カラーコードからRGB成分を取得 int DrawWidth = GetDrawStringWidth( String , -1 ); //文字列の描画幅を取得 int FontSize = GetFontSize() + 2; //フォントのサイズを取得 Handle_t *Handle=Sentinel.Next;//ハンドルのポインタ for( ; Handle!=&Sentinel ; Handle=Handle->Next ){ if( strcmp(Handle->String,String)==0 ){//リストに存在すれば Handle->flag=true; //フラグを立てる break; //検索終了 } } if( Handle==&Sentinel ){//リストに存在しなければ Handle = new Handle_t; //新しいノードを作成 Handle->flag = true; //フラグを立てる strcpy_s(Handle->String,String); //文字列をコピー Handle->Next = &Sentinel; //次のノードへのポインタ Handle->Prev = Sentinel.Prev; //前のノードへのポインタ Handle->Prev->Next = Handle; //前のノードに新しいノードを連結 Handle->Next->Prev = Handle; //次のノードに新しいノードを連結 //文字列イメージを転送するARGB8形式の画面サイズのメモリイメージを作成(縁用と二つ) static int CharImage = MakeARGB8ColorSoftImage( 640 , FontSize ); static int EdgeImage = MakeARGB8ColorSoftImage( 640 , FontSize ); //作成したメモリイメージを0で塗りつぶす ClearRectSoftImage( CharImage , 0 , 0 , DrawWidth , FontSize ); ClearRectSoftImage( EdgeImage , 0 , 0 , DrawWidth , FontSize ); //文字列イメージをメモリイメージに書き込む BltStringSoftImage( 0 , 0 , String , CharImage , EdgeImage , false ); //描画幅と描画高さのグラフィックハンドルを作成する Handle->Char = CreateGraphFromRectSoftImage( CharImage , 0 , 0 , DrawWidth , FontSize ); Handle->Edge = CreateGraphFromRectSoftImage( EdgeImage , 0 , 0 , DrawWidth , FontSize ); } //縁の部分は黒色で描画 SetDrawBright( 0 , 0 , 0 ); DrawGraph( x , y , Handle->Edge , true ); SetDrawBright( 255 , 255 , 255 ); //2Dポリゴン VERTEX Vertex[6]; //本体部分はDrawPolygonを使用して上下にグラデーションさせながら描画 Vertex[ 0 ].x = x - 0.5f ; Vertex[ 0 ].y = y - 0.5f ; Vertex[ 1 ].x = x + DrawWidth - 0.5f ; Vertex[ 1 ].y = y - 0.5f ; Vertex[ 2 ].x = x - 0.5f ; Vertex[ 2 ].y = y + FontSize - 0.5f ; Vertex[ 3 ].x = x + DrawWidth - 0.5f ; Vertex[ 3 ].y = y + FontSize - 0.5f ; Vertex[ 0 ].u = 0.0f ; Vertex[ 0 ].v = 0.0f ; Vertex[ 1 ].u = 1.0f ; Vertex[ 1 ].v = 0.0f ; Vertex[ 2 ].u = 0.0f ; Vertex[ 2 ].v = 1.0f ; Vertex[ 3 ].u = 1.0f ; Vertex[ 3 ].v = 1.0f ; Vertex[ 0 ].b = 255 ; Vertex[ 0 ].g = 255 ; Vertex[ 0 ].r = 255 ; Vertex[ 0 ].a = 255 ; Vertex[ 1 ].b = 255 ; Vertex[ 1 ].g = 255 ; Vertex[ 1 ].r = 255 ; Vertex[ 1 ].a = 255 ; Vertex[ 2 ].b = Blue ; Vertex[ 2 ].g = Green ; Vertex[ 2 ].r = Red ; Vertex[ 2 ].a = 255 ; Vertex[ 3 ].b = Blue ; Vertex[ 3 ].g = Green ; Vertex[ 3 ].r = Red ; Vertex[ 3 ].a = 255 ; Vertex[ 4 ] = Vertex[ 2 ] ; Vertex[ 5 ] = Vertex[ 1 ] ; DrawPolygon( Vertex , 2 , Handle->Char , true , true ); } void Gradation_c::Delete(void){//グラデーション文字列を削除する関数 for( Handle_t *Handle=Sentinel.Next , *Next=Handle->Next ; Handle!=&Sentinel ; Handle=Next , Next=Handle->Next ){ if( !Handle->flag ){//フラグが降りていれば DeleteGraph( Handle->Char );//文字の画像を削除 DeleteGraph( Handle->Edge );//縁の画像を削除 Handle->Prev->Next=Handle->Next;//前のノードに次のノードを連結 Handle->Next->Prev=Handle->Prev;//次のノードに前のノードを連結 delete Handle;//ハンドルを削除 } else Handle->flag=false;//フラグを降ろす } } 実際に使う時は別の関数を経由して呼び出されて そちらで可変長引数を処理しています 皆様のおかげで完成する事ができましたので これで解決とさせていただきます ありがとうございました

Page: 1 | 2 |