トップページ > 記事閲覧
文字描画の要望です。
名前:taro 日時: 2018/01/06 21:51

お忙しいところ申し訳ありません。文字描画の要望です。 フォトショップなどにある境界線(サイズ調節可)、光彩、グラデーションオーバーレイなど テキストにエフェクトを簡単にかけれる関数があると非常に助かります。
メンテ

Page: 1 |

Re: 文字描画の要望です。 ( No.1 )
名前:管理人 日時:2018/01/07 01:25

すみません、今少し優先したい作業が立て込んでいるので、すぐには対応できません 現在ある機能でも GraphFilter や GraphBlend や MakeScreen や MakeGraph などを駆使すると 光彩やグラデーションオーバーレイなどの効果に近いものを実現できます 縁の太さ 3ドット、グラデーション付き、光彩っぽい効果を実現してみたサンプルプログラムを作成してみましたので よろしければご覧になってみてください m(_ _;m <補足> こちらのプログラムで使用している Grad.bmp はこちらにアップしてあります https://dxlib.xsrv.jp/temp/Grad.bmp あと、WinMain は一番下にあります #include "DxLib.h" #define EFFSTR_FONT_SIZE (32) #define EFFSTR_SCREEN_W (512) #define EFFSTR_SCREEN_H (64) #define EFFSTR_STR_X (16) #define EFFSTR_STR_Y (16) int FontHandle ; int GradGrHandle ; int GradExtendGrHandle ; int StringSoftHandle ; int StringEdgeSoftHandle ; int StringGrHandle ; int StringEdgeGrHandle ; int WorkScreen1 ; int WorkScreen2 ; int AddBlendStringScreen ; int GradStringScreen ; // エフェクト付き文字列描画処理の初期化 int EffectString_Initialize( void ) { // フォントハンドルを作成( 縁の太さを 3 ドット設定 ) FontHandle = CreateFontToHandle( "MS ゴシック", EFFSTR_FONT_SIZE, 8, DX_FONTTYPE_ANTIALIASING_EDGE_4X4, DX_CHARSET_SHFTJIS, 3 ) ; // グラデーション画像を読み込み GradGrHandle = LoadGraph( "Grad.bmp" ) ; // グラデーション画像を作業用画像サイズいっぱいに引き伸ばしたものを格納するためのグラフィックハンドルを作成 GradExtendGrHandle = MakeScreen( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H, FALSE ) ; // グラデーション画像を引き伸ばしたグラデーション画像を格納しておくグラフィックハンドルに拡大描画 SetDrawScreen( GradExtendGrHandle ) ; SetDrawMode( DX_DRAWMODE_BILINEAR ) ; DrawExtendGraph( 0, 0, EFFSTR_SCREEN_W, EFFSTR_SCREEN_H, GradGrHandle, FALSE ) ; SetDrawScreen( DX_SCREEN_BACK ) ; // 文字列の本体部分を格納するソフトウェアイメージの作成 StringSoftHandle = MakeARGB8ColorSoftImage( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H ) ; // 文字列の縁部分を格納するソフトウェアイメージの作成 StringEdgeSoftHandle = MakeARGB8ColorSoftImage( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H ) ; // 文字列の本体部分用のグラフィックハンドルの作成 StringGrHandle = MakeGraph( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H ) ; // 文字列の縁部分用のグラフィックハンドルの作成 StringEdgeGrHandle = MakeGraph( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H ) ; // 作業用の描画先として指定できるグラフィックハンドルの作成 WorkScreen1 = MakeScreen( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H, TRUE ) ; WorkScreen2 = MakeScreen( EFFSTR_SCREEN_W / 2, EFFSTR_SCREEN_H / 2, TRUE ) ; // 加算ブレンドで描画する部分を格納するグラフィックハンドルの作成 AddBlendStringScreen = MakeScreen( EFFSTR_SCREEN_W / 2, EFFSTR_SCREEN_H / 2, TRUE ) ; // アルファブレンドで描画する部分を格納するグラフィックハンドルの作成 GradStringScreen = MakeScreen( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H, TRUE ) ; return 0 ; } // エフェクト付き文字列病が処理の後始末 int EffectString_Terminate( void ) { // グラフィックハンドルとソフトウエアハンドルとフォントハンドルを削除 DeleteFontToHandle( FontHandle ) ; DeleteGraph( GradGrHandle ) ; DeleteGraph( GradExtendGrHandle ) ; DeleteSoftImage( StringSoftHandle ) ; DeleteSoftImage( StringEdgeSoftHandle ) ; DeleteGraph( StringGrHandle ) ; DeleteGraph( StringEdgeGrHandle ) ; DeleteGraph( WorkScreen1 ) ; DeleteGraph( WorkScreen2 ) ; DeleteGraph( AddBlendStringScreen ) ; DeleteGraph( GradStringScreen ) ; return 0 ; } // エフェクト付き文字列描画処理の描画文字列の準備 int EffectString_Setup( const char *String ) { // ソフトウェアイメージのクリア FillSoftImage( StringSoftHandle, 0, 0, 0, 0 ) ; FillSoftImage( StringEdgeSoftHandle, 0, 0, 0, 0 ) ; // ソフトウェアイメージに文字列を描画 BltStringSoftImageToHandle( EFFSTR_STR_X, EFFSTR_STR_Y, String, StringSoftHandle, StringEdgeSoftHandle, FontHandle ) ; // ソフトウェアイメージからグラフィックハンドルに転送 ReCreateGraphFromSoftImage( StringSoftHandle, StringGrHandle ) ; ReCreateGraphFromSoftImage( StringEdgeSoftHandle, StringEdgeGrHandle ) ; // 文字本体の画像と、グラデーション画像を合成 GraphBlendBlt( StringGrHandle, GradExtendGrHandle, GradStringScreen, 255, DX_GRAPH_BLEND_NORMAL ) ; // 作業用グラフィックハンドル1に本体部分と縁部分を加算描画 SetDrawScreen( WorkScreen1 ) ; DrawBox( 0, 0, EFFSTR_SCREEN_W, EFFSTR_SCREEN_H, GetColor( 0,0,0 ), TRUE ) ; SetDrawBlendMode( DX_BLENDMODE_ADD, 255 ) ; DrawGraph( 0, 0, StringEdgeGrHandle, TRUE ) ; DrawGraph( 0, 0, StringGrHandle, TRUE ) ; // 作業用グラフィックハンドル2に作業用グラフィックハンドル1を縦横半分のサイズに縮小描画 SetDrawScreen( WorkScreen2 ) ; SetDrawBlendMode( DX_BLENDMODE_ALPHA, 255 ) ; SetDrawMode( DX_DRAWMODE_BILINEAR ) ; DrawExtendGraph( 0, 0, EFFSTR_SCREEN_W / 2, EFFSTR_SCREEN_H / 2, WorkScreen1, FALSE ) ; // 作業用グラフィックハンドル2の内容をガウスフィルタでぼかす GraphFilterBlt( WorkScreen2, AddBlendStringScreen, DX_GRAPH_FILTER_GAUSS, 8, 360 ) ; // 描画先を元に戻す SetDrawScreen( DX_SCREEN_BACK ) ; return 0 ; } // エフェクト付き文字列の描画 int EffectString_Draw( int x, int y, int Alpha ) { // バイリニア補間設定にする SetDrawMode( DX_DRAWMODE_BILINEAR ) ; // 加算部分の描画 SetDrawBlendMode( DX_BLENDMODE_ADD_X4, Alpha ) ; SetDrawBright( 255, 64, 64 ) ; DrawExtendGraph( x - EFFSTR_STR_X, y - EFFSTR_STR_Y, x - EFFSTR_STR_X + EFFSTR_SCREEN_W, y - EFFSTR_STR_Y + EFFSTR_SCREEN_H, AddBlendStringScreen, TRUE ) ; // 縁を描画 SetDrawBright( 0, 200, 200 ) ; SetDrawBlendMode( DX_BLENDMODE_ALPHA, Alpha ) ; DrawGraph( x - EFFSTR_STR_X, y - EFFSTR_STR_Y, StringEdgeGrHandle, TRUE ) ; // 本体部分を描画 SetDrawBright( 255, 255, 255 ) ; DrawGraph( x - EFFSTR_STR_X, y - EFFSTR_STR_Y, GradStringScreen, TRUE ) ; return 0 ; } // WinMain int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウィンドウモードで起動 ChangeWindowMode( TRUE ) ; // DXライブラリ初期化処理 if( DxLib_Init() == -1 ) { return -1 ; } // エフェクト付き文字列描画処理の初期化 EffectString_Initialize() ; // 描画する文字列のセットアップ EffectString_Setup( "あいうえお" ) ; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ) ; // メインループ while( ProcessMessage() == 0 ) { // 裏画面をクリア ClearDrawScreen() ; // エフェクト付き文字列の描画 EffectString_Draw( 64, 64, 255 ) ; // 裏画面の内容を表画面に反映 ScreenFlip() ; } // エフェクト付き文字列描画処理の後始末 EffectString_Terminate() ; // DXライブラリ使用の終了処理 DxLib_End() ; // ソフトの終了 return 0 ; }
メンテ
Re: 文字描画の要望です。 ( No.2 )
名前:にこよん 日時:2018/01/07 08:18

横から失礼します 私も光彩エフェクト付き文字描画関数を使いたいのですが、上のサンプルコードで何が起こっているのかわからないため 改造できそうにありません... フォントも使用したうえで光彩だけつけて描画できるような関数(下の様な関数)のサンプルもいただけないでしょうか? 重くなってしまうのは困るため、あらかじめ文字をセットする必要があるのならクラスなどにして複数セットできるようにしたいです 忙しい中すみません(-_-;) 急ぎではないので時間に余裕ができてからとかで大丈夫です DrawFormatStringToHandle_kousai(10, 670, colorH, fontH, 光彩の強度, "aaaaaa %0.2f", 10.5f);
メンテ
Re: 文字描画の要望です。 ( No.3 )
名前:taro(解決) 日時:2018/01/07 13:03

なるほど結構な力技でそれっぽい表現が出来るんですね。 私は少し前はas3を使ってflashゲームを作っていてその時は textField.filters=[glowFilter1,glowFilter2]; みたいな感じで簡単にテキストにフィルターをかけていたので 内部でどのようなことが起こっているかは知りもしませんでした。 非常に勉強になりました。 テキストにエフェクトを追加する簡易関数の件は 気長に待ちますので是非実装お願いします。 ご丁寧に対応していただきありがとうございました。
メンテ
Re: 文字描画の要望です。 ( No.4 )
名前:管理人 日時:2018/01/07 14:46

> にこよんさん > 私も光彩エフェクト付き文字描画関数を使いたいのですが、上のサンプルコードで何が起こっているのかわからないため > 改造できそうにありません... ご所望の機能を作成するのはすぐには難しそうなので、よろしければ何処が分からないのか教えていただけないでしょうか? > DrawFormatStringToHandle_kousai(10, 670, colorH, fontH, 光彩の強度, "aaaaaa %0.2f", 10.5f); レスNo.1 のサンプルは時間のかかる『描画の準備』( EffectString_Setup )と高速に行える『実際の描画』( EffectString_Draw )を分けていますので、 こちらのように『描画の準備』と『実際の描画』を一度に行うような関数にしてしまうと1回の関数呼び出しが かなり重いものとなってしまいます・・・ もし実際にDXライブラリの機能として実装する場合はこちらの関数のように『お手軽さ』と『速度』が両立したものとなると思いますが、 既存の機能だけで実装する場合は『速度』が犠牲になります・・・ ( 厳密には既存の機能だけでも『お手軽さ』と『速度』を両立することはできますが、それを実現するにはコード量が  多くなり時間も掛かるので「その作業時間があったらDXライブラリの機能を実装した方が良い」という状態になってしまいます・・・ )
メンテ
Re: 文字描画の要望です。 ( No.5 )
名前:BayLeaf 日時:2018/01/07 19:49

横から便乗させていただきます。 私も文字描画で光彩を扱いたいと思っていたので管理人さんのサンプルプログラムを改造して使用しようと思っています。 Androidで実行してみたら二つほど質問したいことがあったので書きます。 // ソフトウェアイメージに文字列を描画 BltStringSoftImageToHandle( EFFSTR_STR_X, EFFSTR_STR_Y, String, StringSoftHandle, StringEdgeSoftHandle, FontHandle ) ; 1. 恐らく上記の関数で改行文字が認識されていないようなのですが、こちらは仕様ということでよろしいですか? (実行すると改行文字以降の文字列が表示されない) 2. テキスト内のエフェクト(グラデーション)が再アクティブ化で初期化されてしまうことがあるのですが原因が分かればお願いします お忙しいところ申し訳ないですがお願いします。
メンテ
Re: 文字描画の要望です。 ( No.6 )
名前:にこよん 日時:2018/01/08 10:14

> ご所望の機能を作成するのはすぐには難しそうなので、よろしければ何処が分からないのか教えていただけないでしょうか? このあたりの分野は苦手でどの関数が光彩に関係してるかが分からないため何を抜けば グラデーションなどの不要な部分を抜き取り、光彩だけの関数にできるかが分からないです > レスNo.1 のサンプルは時間のかかる『描画の準備』( EffectString_Setup )と高速に行える『実際の描画』( EffectString_Draw )を分けていますので、 > こちらのように『描画の準備』と『実際の描画』を一度に行うような関数にしてしまうと1回の関数呼び出しが > かなり重いものとなってしまいます・・・ なるほどです ならば上の関数の形のままで(2つにわかれた形式の)光彩エフェクトだけバージョンの様な関数のサンプルをいただけないでしょうか? サンプルコードから光彩描画以外のものを抜き取っただけのかんたんなもので大丈夫です
メンテ
Re: 文字描画の要望です。 ( No.7 )
名前:管理人 日時:2018/01/08 22:06

> BayLeafさん > 1. 恐らく上記の関数で改行文字が認識されていないようなのですが、こちらは仕様ということでよろしいですか? >  (実行すると改行文字以降の文字列が表示されない) 仕様では改行されるはずです 手元で試してみましたが、改行されました サンプルでは1行づつ描画することを前提とした処理となっていて作業用のスクリーンのサイズが縦 64 ピクセルしかないので 2行目以降が見切れてしまっているのだと思います > 2. テキスト内のエフェクト(グラデーション)が再アクティブ化で初期化されてしまうことがあるのですが原因が分かればお願いします アプリが非アクティブになると大抵の場合アプリ内のグラフィックがロストするので、再アクティブ化した際に内容を復帰する必要があります ( 画像ファイルを読み込んで作成したグラフィックハンドルの内容はDXライブラリが自動的に復帰します ) SetGraphicsDeviceRestoreCallbackFunction で復帰時呼ばれるコールバック関数を登録できますので、登録したコールバック関数の中で グラデーション画像を引き伸ばしたものを保持しておくグラフィックハンドル( GradExtendGrHandle )の内容を復帰するようにしてください m(_ _;m // グラフィックスデバイスがロストから復帰した際に呼ばれるコールバック関数を設定する int SetGraphicsDeviceRestoreCallbackFunction( void (* Callback )( void *Data ), void *CallbackData ) ; > にこよんさん > ならば上の関数の形のままで(2つにわかれた形式の)光彩エフェクトだけバージョンの様な関数のサンプルをいただけないでしょうか? > サンプルコードから光彩描画以外のものを抜き取っただけのかんたんなもので大丈夫です わかりました、レスNo.1 のプログラムからグラデーション効果を無くして光彩効果だけにしてみましたのでよろしければご覧ください #include "DxLib.h" #define EFFSTR_FONT_SIZE (32) #define EFFSTR_SCREEN_W (512) #define EFFSTR_SCREEN_H (64) #define EFFSTR_STR_X (16) #define EFFSTR_STR_Y (16) int FontHandle ; int StringSoftHandle ; int StringEdgeSoftHandle ; int StringGrHandle ; int StringEdgeGrHandle ; int WorkScreen1 ; int WorkScreen2 ; int AddBlendStringScreen ; // エフェクト付き文字列描画処理の初期化 int EffectString_Initialize( void ) { // フォントハンドルを作成( 縁の太さを 3 ドット設定 ) FontHandle = CreateFontToHandle( "MS ゴシック", EFFSTR_FONT_SIZE, 8, DX_FONTTYPE_ANTIALIASING_EDGE_4X4, DX_CHARSET_SHFTJIS, 3 ) ; // 文字列の本体部分を格納するソフトウェアイメージの作成 StringSoftHandle = MakeARGB8ColorSoftImage( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H ) ; // 文字列の縁部分を格納するソフトウェアイメージの作成 StringEdgeSoftHandle = MakeARGB8ColorSoftImage( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H ) ; // 文字列の本体部分用のグラフィックハンドルの作成 StringGrHandle = MakeGraph( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H ) ; // 文字列の縁部分用のグラフィックハンドルの作成 StringEdgeGrHandle = MakeGraph( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H ) ; // 作業用の描画先として指定できるグラフィックハンドルの作成 WorkScreen1 = MakeScreen( EFFSTR_SCREEN_W, EFFSTR_SCREEN_H, TRUE ) ; WorkScreen2 = MakeScreen( EFFSTR_SCREEN_W / 2, EFFSTR_SCREEN_H / 2, TRUE ) ; // 加算ブレンドで描画する部分を格納するグラフィックハンドルの作成 AddBlendStringScreen = MakeScreen( EFFSTR_SCREEN_W / 2, EFFSTR_SCREEN_H / 2, TRUE ) ; return 0 ; } // エフェクト付き文字列病が処理の後始末 int EffectString_Terminate( void ) { // グラフィックハンドルとソフトウエアハンドルとフォントハンドルを削除 DeleteFontToHandle( FontHandle ) ; DeleteSoftImage( StringSoftHandle ) ; DeleteSoftImage( StringEdgeSoftHandle ) ; DeleteGraph( StringGrHandle ) ; DeleteGraph( StringEdgeGrHandle ) ; DeleteGraph( WorkScreen1 ) ; DeleteGraph( WorkScreen2 ) ; DeleteGraph( AddBlendStringScreen ) ; return 0 ; } // エフェクト付き文字列描画処理の描画文字列の準備 int EffectString_Setup( const char *String ) { // ソフトウェアイメージのクリア FillSoftImage( StringSoftHandle, 0, 0, 0, 0 ) ; FillSoftImage( StringEdgeSoftHandle, 0, 0, 0, 0 ) ; // ソフトウェアイメージに文字列を描画 BltStringSoftImageToHandle( EFFSTR_STR_X, EFFSTR_STR_Y, String, StringSoftHandle, StringEdgeSoftHandle, FontHandle ) ; // ソフトウェアイメージからグラフィックハンドルに転送 ReCreateGraphFromSoftImage( StringSoftHandle, StringGrHandle ) ; ReCreateGraphFromSoftImage( StringEdgeSoftHandle, StringEdgeGrHandle ) ; // 作業用グラフィックハンドル1に本体部分と縁部分を加算描画 SetDrawScreen( WorkScreen1 ) ; DrawBox( 0, 0, EFFSTR_SCREEN_W, EFFSTR_SCREEN_H, GetColor( 0,0,0 ), TRUE ) ; SetDrawBlendMode( DX_BLENDMODE_ADD, 255 ) ; DrawGraph( 0, 0, StringEdgeGrHandle, TRUE ) ; DrawGraph( 0, 0, StringGrHandle, TRUE ) ; // 作業用グラフィックハンドル2に作業用グラフィックハンドル1を縦横半分のサイズに縮小描画 SetDrawScreen( WorkScreen2 ) ; SetDrawBlendMode( DX_BLENDMODE_ALPHA, 255 ) ; SetDrawMode( DX_DRAWMODE_BILINEAR ) ; DrawExtendGraph( 0, 0, EFFSTR_SCREEN_W / 2, EFFSTR_SCREEN_H / 2, WorkScreen1, FALSE ) ; // 作業用グラフィックハンドル2の内容をガウスフィルタでぼかす GraphFilterBlt( WorkScreen2, AddBlendStringScreen, DX_GRAPH_FILTER_GAUSS, 8, 360 ) ; // 描画先を元に戻す SetDrawScreen( DX_SCREEN_BACK ) ; return 0 ; } // エフェクト付き文字列の描画 int EffectString_Draw( int x, int y, int Alpha ) { // バイリニア補間設定にする SetDrawMode( DX_DRAWMODE_BILINEAR ) ; // 加算部分の描画 SetDrawBlendMode( DX_BLENDMODE_ADD_X4, Alpha ) ; SetDrawBright( 255, 64, 64 ) ; DrawExtendGraph( x - EFFSTR_STR_X, y - EFFSTR_STR_Y, x - EFFSTR_STR_X + EFFSTR_SCREEN_W, y - EFFSTR_STR_Y + EFFSTR_SCREEN_H, AddBlendStringScreen, TRUE ) ; // 縁を描画 SetDrawBright( 0, 200, 200 ) ; SetDrawBlendMode( DX_BLENDMODE_ALPHA, Alpha ) ; DrawGraph( x - EFFSTR_STR_X, y - EFFSTR_STR_Y, StringEdgeGrHandle, TRUE ) ; // 本体部分を描画 SetDrawBright( 255, 255, 255 ) ; DrawGraph( x - EFFSTR_STR_X, y - EFFSTR_STR_Y, StringGrHandle, TRUE ) ; return 0 ; } // WinMain int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウィンドウモードで起動 ChangeWindowMode( TRUE ) ; // DXライブラリ初期化処理 if( DxLib_Init() == -1 ) { return -1 ; } // エフェクト付き文字列描画処理の初期化 EffectString_Initialize() ; // 描画する文字列のセットアップ EffectString_Setup( "あいうえお" ) ; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ) ; // メインループ while( ProcessMessage() == 0 ) { // 裏画面をクリア ClearDrawScreen() ; // エフェクト付き文字列の描画 EffectString_Draw( 64, 64, 255 ) ; // 裏画面の内容を表画面に反映 ScreenFlip() ; } // エフェクト付き文字列描画処理の後始末 EffectString_Terminate() ; // DXライブラリ使用の終了処理 DxLib_End() ; // ソフトの終了 return 0 ; }
メンテ
Re: 文字描画の要望です。 ( No.8 )
名前:BayLeaf(解決) 日時:2018/01/08 23:14

> サンプルでは1行づつ描画することを前提とした処理となっていて作業用のスクリーンのサイズが縦 64 ピクセルしかないので > 2行目以降が見切れてしまっているのだと思います なるほど、縦ピクセルをいじれば2行目以降も表示できるのですね。 せっかくなので見切れることを逆に利用してみようと思います。 > アプリが非アクティブになると大抵の場合アプリ内のグラフィックがロストするので、再アクティブ化した際に内容を復帰する必要があります > ( 画像ファイルを読み込んで作成したグラフィックハンドルの内容はDXライブラリが自動的に復帰します ) > SetGraphicsDeviceRestoreCallbackFunction で復帰時呼ばれるコールバック関数を登録できますので、登録したコールバック関数の中で > グラデーション画像を引き伸ばしたものを保持しておくグラフィックハンドル( GradExtendGrHandle )の内容を復帰するようにしてください m(_ _;m 自動的に復帰されるものとされないものがあるのですね。 「アプリアイコンをタップして復帰したとき」と「スリープ状態から復帰したとき」とで挙動が違っていたことがあったので気になっていました。 コールバック関数については時間がある時に確認しようと思います。 忙しいのにも関わらずありがとうございました。 ここを見て新しいプログラミング技法も思いついたので色々と試してみます。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存