Re: BltStringSoftImageの拡大縮小について ( No.1 ) |
- 名前:管理人 日時:2023/01/02 21:26
あけましておめでとうございます!
仮に BltStringSoftImage の拡大縮小に対応したものを追加したとしても、
大きな画像をCPUでバイリニアフィルタリングなどを伴った縮小処理を行うと
非常に処理負荷が高くなるので、DrawString で縁だけ、若しくは本体だけ描画できるようにするための
機能を追加して、BltStringSoftImage を使用しなくても『文字のグラデーション』のスレッドの No.2 の処理が
行えるようにしてみました
というわけで、よろしければこちらの機能を追加した暫定最新バージョンを
ダウンロードしてください m(_ _)m
https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用
https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用
https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 10.3 用
https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用
https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用
https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース
(中身を既存のライブラリのファイルに上書きして『リビルド』をして下さい)
以下の関数を追加しました
// フォントの描画で縁のみ、又は本体のみ描画を行うかどうかを設定する
// OnlyType 0:通常描画 1:本体のみ描画 2:縁のみ描画
int SetFontOnlyDrawType( int OnlyType ) ;
DrawString 等の文字列描画関数を使用する前に SetFontOnlyDrawType( 1 ); を実行していれば
縁付きフォントでも本体だけが描画され、 SetFontOnlyDrawType( 2 ); を実行していれば
本体は描画されず縁だけが描画されますので、これで BltStringSoftImage と CreateGraphFromRectSoftImage で
行っていた『本体と縁を別々のグラフィックハンドルとして作成する』を BltStringSoftImage などを使用しなくても
実現することが出来ます
そしてこちらが 『文字のグラデーション』の No.2 に書かれている処理を BltStringSoftImage を
使用せずに実装したものとなります
#include "DxLib.h"
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
int FontHandle, ImageHandle, EdgeImageHandle, DrawWidth ;
int TempScreen, EdgeTempScreen ;
VERTEX Vertex[ 6 ] ;
ChangeWindowMode( TRUE ) ;
// 32bitカラーを設定
SetGraphMode( 640, 480, 32 ) ;
// DXライブラリの初期化
if( DxLib_Init() < 0 )
{
// エラーが発生したら直ちに終了
return -1 ;
}
// 乗算済みアルファタイプの縁つきアンチエイリアスフォントの作成
SetFontCacheUsePremulAlphaFlag( TRUE ) ;
FontHandle = CreateFontToHandle( NULL, 24, -1, DX_FONTTYPE_ANTIALIASING_EDGE ) ;
// 文字列イメージを描き込む仮画面を作成( 縁用と二つ )
TempScreen = MakeScreen( 640, 480, TRUE ) ;
EdgeTempScreen = MakeScreen( 640, 480, TRUE ) ;
// 文字列の本体を仮画面に描き込む
SetDrawScreen( TempScreen ) ;
ClearDrawScreen() ;
SetDrawBlendMode( DX_BLENDMODE_PMA_ALPHA, 255 ) ; // 乗算済みアルファ版のアルファブレンドに設定
SetFontOnlyDrawType( 1 ) ;
DrawStringToHandle( 0, 0, "グラデーションテスト", GetColor( 255,255,255 ), FontHandle, GetColor( 255,255,255 ) ) ;
// 文字列の縁を仮画面に描き込む
SetDrawScreen( EdgeTempScreen ) ;
ClearDrawScreen() ;
SetDrawBlendMode( DX_BLENDMODE_PMA_ALPHA, 255 ) ; // 乗算済みアルファ版のアルファブレンドに設定
SetFontOnlyDrawType( 2 ) ;
DrawStringToHandle( 0, 0, "グラデーションテスト", GetColor( 255,255,255 ), FontHandle, GetColor( 255,255,255 ) ) ;
// 描画幅を取得する
DrawWidth = GetDrawStringWidthToHandle( "グラデーションテスト", strlenDx( "グラデーションテスト" ), FontHandle ) ;
// 描画幅と描画高さの派生グラフィックハンドルを作成する
ImageHandle = DerivationGraph( 0, 0, DrawWidth, 26, TempScreen ) ;
EdgeImageHandle = DerivationGraph( 0, 0, DrawWidth, 26, EdgeTempScreen ) ;
// 描画先を表画面に戻す
SetDrawScreen( DX_SCREEN_FRONT ) ;
// 縁の部分は緑色で描画
SetDrawBright( 0, 255, 0 ) ;
SetDrawBlendMode( DX_BLENDMODE_PMA_ALPHA, 255 ) ; // 乗算済みアルファ版のアルファブレンドに設定
DrawGraph( 0, 0, EdgeImageHandle, TRUE ) ;
SetDrawBright( 255, 255, 255 ) ;
// 本体部分は DrawPolygon を使用して上下に赤から青にグラデーションさせながら描画
Vertex[ 0 ].x = 0.0f ; Vertex[ 0 ].y = 0.0f ;
Vertex[ 1 ].x = DrawWidth ; Vertex[ 1 ].y = 0.0f ;
Vertex[ 2 ].x = 0.0f ; Vertex[ 2 ].y = 26.0f ;
Vertex[ 3 ].x = DrawWidth ; Vertex[ 3 ].y = 26.0f ;
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 = 0 ; Vertex[ 0 ].g = 0 ; Vertex[ 0 ].r = 255 ; Vertex[ 0 ].a = 255 ;
Vertex[ 1 ].b = 0 ; Vertex[ 1 ].g = 0 ; Vertex[ 1 ].r = 255 ; Vertex[ 1 ].a = 255 ;
Vertex[ 2 ].b = 255 ; Vertex[ 2 ].g = 0 ; Vertex[ 2 ].r = 0 ; Vertex[ 2 ].a = 255 ;
Vertex[ 3 ].b = 255 ; Vertex[ 3 ].g = 0 ; Vertex[ 3 ].r = 0 ; Vertex[ 3 ].a = 255 ;
Vertex[ 4 ] = Vertex[ 2 ] ;
Vertex[ 5 ] = Vertex[ 1 ] ;
DrawPolygon( Vertex, 2, ImageHandle, TRUE, TRUE ) ;
// キー入力待ち
WaitKey() ;
// DXライブラリの後始末
DxLib_End() ;
// ソフトの終了
return 0 ;
}
MakeARGB8ColorSoftImage をはじめとしたソフトウェアイメージは使用せずに MakeScreen や DrawString を使用して実装しています
ソフトウェアイメージに対する文字列描画である BltStringSoftImage では拡大縮小描画を行うことは出来ませんが、
通常の文字列描画の場合は DrawExtendStringToHandle という拡大縮小描画の関数がありますので
これで lego hasiriさんの望まれる処理が行えるのではないかと思います
// フォントハンドルを使用して文字列を拡大描画する
int DrawExtendStringToHandle( int x, int y, double ExRateX, double ExRateY, const char *String, unsigned int Color, int FontHandle, unsigned int EdgeColor = 0, int VerticalFlag = FALSE ) ;
因みにきれいに拡大縮小表示ができるようにフォントサイズを100にされているとのことですが、
SetDrawMode( DX_DRAWMODE_BILINEAR ); を設定してバイリニアフィルタリングを伴う縮小描画を行った場合でも
バイリニアフィルタリングのアルゴリズムの性質上 1/2 以下のサイズへの縮小は SetDrawMode( DX_DRAWMODE_NEAREST ); の
最近点フィルタリングと同様に潰れたドットの情報が欠落した縮小描画となりますので、きれいに縮小して描画を行う場合は
フォントサイズ 100 のフォントハンドル → サイズ 51 〜 100 の範囲の描画用
フォントサイズ 50 のフォントハンドル → サイズ 26 〜 50 の範囲の描画用
フォントサイズ 25 のフォントハンドル → サイズ 12 〜 25 の範囲の描画用
↑
こちらのように、幾つかのサイズのフォントハンドルを用意して使い回す必要がありますのでご注意ください m(_ _)m
 |
Re: BltStringSoftImageの拡大縮小について ( No.2 ) |
- 名前:lego hasiri 日時:2023/01/04 04:50
ご対応ありがとうございます。 なんとかやりたいことはできそうです。
フォントサイズの件も了解しました。
ただ提示いただいたコードで問題点(?)があって、PMA_ALPHAを使って20程度の大きさの縁付きグラデーションの文字を描画すると、にじんだような感じになってしまいました。(フォントはMSゴシック、ブレンドはPMA_ALPHA、α値は255、本体のほうが広がった感じになっていた)
まだしっかりと検証したわけではないのでこちら側の問題なのかもしれませんが、管理人さんのほうで確認していただければと思います。
また少し別件なのですが、DrawModiString系で文字列を描画すると最初の描画時の文字数分しか描画されませんでした。
以下のコードをすると
int i = 0;
while(ProcessMessage() == 0 && ScreenFlip() == 0 && ClearDrawScreen() == 0) {
auto s = std::format("{}", i + 50);
auto w = GetDrawStringWidth(s.c_str(), s.length());
DrawModiString(0, 0, w, 0, w, 20, 0, 20, 0xffffff, 0, 0, s.c_str());
DrawModiFormatString(0, 64, w, 64, w, 84, 0, 84, 0xffffff, 0, 0, "%d", i + 1000);
i++;
}
2つとも上位の2桁が、横幅がwで描画されています。グラデーションと同様にスクリーンを使ってやれば回避はできると思いますが、これはバグかなと思うのでこちらも確認いただければと思います。
|
Re: BltStringSoftImageの拡大縮小について ( No.3 ) |
- 名前:lego hasiri 日時:2023/01/04 04:55
追記で、PMAを使わず普通にアルファブレンドをした場合は期待通りに描画できました。
|
Re: BltStringSoftImageの拡大縮小について ( No.4 ) |
- 名前:管理人 日時:2023/01/05 00:47
 |
Re: BltStringSoftImageの拡大縮小について ( No.5 ) |
- 名前:lego hasiri 日時:2023/01/06 23:55
DrawModiStringの修正ありがとうございます。無事描画されてました。
滲みの件ですが、実行結果を張ります。見れますでしょうか?
(共にMSゴシックのサイズは16、縁は黒で上が白、下が青のグラデーション、その他は変えてません)
gyazo.com/258d681c2b62b05f1f8b1967ca32301d
上がPMAを使わないほうで下がPMAを使ったほうです。
滲みという言い方があれだったかもしれませんが、上のほうが縁が濃いように感じます。それで縁がみにくくなっていて滲んでるように感じたのだと思います。
この場合下のほうが正しい描画結果ということなのでしょうか?
|
Re: BltStringSoftImageの拡大縮小について ( No.6 ) |
- 名前:管理人 日時:2023/01/07 01:23
> DrawModiStringの修正ありがとうございます。無事描画されてました。
ご迷惑おかけしました、正常に動作したようで何よりです m(_ _)m
> この場合下のほうが正しい描画結果ということなのでしょうか?
すみません、lego hasiriさんがどのようにプログラムを変更されたのか詳細が不明なため
正しい描画結果なのかを判断することが出来ません
申し訳ありませんが、No.1 のプログラムをそのまま実行した際に正常に表示されるかをご確認いただけますでしょうか? m(_ _)m
因みに、私の環境で No.1 のプログラムをそのまま実行した際はこちらのような結果になっています
https://dxlib.xsrv.jp/temp/GradationStringTest.png
|
Re: BltStringSoftImageの拡大縮小について ( No.7 ) |
- 名前:lego hasiri 日時:2023/01/07 18:06
いただいたサンプルをそのまま実行すると、画像と同じものです。
あと一応No5のプログラムも載せておきます。
#include "DxLib.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
int size = 18;
ChangeWindowMode(TRUE);
SetBackgroundColor(255, 255, 255);
// 32bitカラーを設定
SetGraphMode(640, 480, 32);
// DXライブラリの初期化
if (DxLib_Init() < 0) {
// エラーが発生したら直ちに終了
return -1;
}
{
int FontHandle, ImageHandle, EdgeImageHandle, DrawWidth;
int TempScreen, EdgeTempScreen;
VERTEX Vertex[6];
FontHandle = CreateFontToHandle("MSゴシック", size - 2, -1, DX_FONTTYPE_ANTIALIASING_EDGE);
// 文字列イメージを描き込む仮画面を作成( 縁用と二つ )
TempScreen = MakeScreen(640, 480, TRUE);
EdgeTempScreen = MakeScreen(640, 480, TRUE);
// 文字列の本体を仮画面に描き込む
SetDrawScreen(TempScreen);
ClearDrawScreen();
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 255); // のアルファブレンドに設定
SetFontOnlyDrawType(1);
DrawStringToHandle(0, 0, "通常のグラデーションテスト", GetColor(255, 255, 255), FontHandle, GetColor(255, 255, 255));
// 文字列の縁を仮画面に描き込む
SetDrawScreen(EdgeTempScreen);
ClearDrawScreen();
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 255); // アルファブレンドに設定
SetFontOnlyDrawType(2);
DrawStringToHandle(0, 0, "通常のグラデーションテスト", GetColor(255, 255, 255), FontHandle, GetColor(255, 255, 255));
// 描画幅を取得する
DrawWidth = GetDrawStringWidthToHandle("通常のグラデーションテスト", strlenDx("通常のグラデーションテスト"), FontHandle);
// 描画幅と描画高さの派生グラフィックハンドルを作成する
ImageHandle = DerivationGraph(0, 0, DrawWidth, size, TempScreen);
EdgeImageHandle = DerivationGraph(0, 0, DrawWidth, size, EdgeTempScreen);
// 描画先を表画面に戻す
SetDrawScreen(DX_SCREEN_FRONT);
// 縁の部分は緑色で描画
SetDrawBright(0, 0, 0);
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 255); // アルファブレンドに設定
DrawGraph(0, 0, EdgeImageHandle, TRUE);
SetDrawBright(255, 255, 255);
// 本体部分は DrawPolygon を使用して上下に赤から青にグラデーションさせながら描画
Vertex[0].x = 0.0f; Vertex[0].y = 0.0f;
Vertex[1].x = DrawWidth; Vertex[1].y = 0.0f;
Vertex[2].x = 0.0f; Vertex[2].y = size;
Vertex[3].x = DrawWidth; Vertex[3].y = size;
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 = 255; Vertex[2].g = 0; Vertex[2].r = 0; Vertex[2].a = 255;
Vertex[3].b = 255; Vertex[3].g = 0; Vertex[3].r = 0; Vertex[3].a = 255;
Vertex[4] = Vertex[2];
Vertex[5] = Vertex[1];
DrawPolygon(Vertex, 2, ImageHandle, TRUE, TRUE);
}
{
int FontHandle, ImageHandle, EdgeImageHandle, DrawWidth;
int TempScreen, EdgeTempScreen;
VERTEX Vertex[6];
// 乗算済みアルファタイプの縁つきアンチエイリアスフォントの作成
SetFontCacheUsePremulAlphaFlag(TRUE);
FontHandle = CreateFontToHandle("MSゴシック", size - 2, -1, DX_FONTTYPE_ANTIALIASING_EDGE);
//SetFontCacheUsePremulAlphaFlag(FALSE);
// 文字列イメージを描き込む仮画面を作成( 縁用と二つ )
TempScreen = MakeScreen(640, 480, TRUE);
EdgeTempScreen = MakeScreen(640, 480, TRUE);
// 文字列の本体を仮画面に描き込む
SetDrawScreen(TempScreen);
ClearDrawScreen();
SetDrawBlendMode(DX_BLENDMODE_PMA_ALPHA, 255); // 乗算済みアルファ版のアルファブレンドに設定
SetFontOnlyDrawType(1);
DrawStringToHandle(0, 0, "乗算済みグラデーションテスト", GetColor(255, 255, 255), FontHandle, GetColor(255, 255, 255));
// 文字列の縁を仮画面に描き込む
SetDrawScreen(EdgeTempScreen);
ClearDrawScreen();
SetDrawBlendMode(DX_BLENDMODE_PMA_ALPHA, 255); // 乗算済みアルファ版のアルファブレンドに設定
SetFontOnlyDrawType(2);
DrawStringToHandle(0, 0, "乗算済みグラデーションテスト", GetColor(255, 255, 255), FontHandle, GetColor(255, 255, 255));
// 描画幅を取得する
DrawWidth = GetDrawStringWidthToHandle("乗算済みグラデーションテスト", strlenDx("乗算済みグラデーションテスト"), FontHandle);
// 描画幅と描画高さの派生グラフィックハンドルを作成する
ImageHandle = DerivationGraph(0, 0, DrawWidth, size, TempScreen);
EdgeImageHandle = DerivationGraph(0, 0, DrawWidth, size, EdgeTempScreen);
// 描画先を表画面に戻す
SetDrawScreen(DX_SCREEN_FRONT);
// 縁の部分は緑色で描画
SetDrawBright(0, 0, 0);
SetDrawBlendMode(DX_BLENDMODE_PMA_ALPHA, 255); // 乗算済みアルファ版のアルファブレンドに設定
DrawGraph(0, 30, EdgeImageHandle, TRUE);
SetDrawBright(255, 255, 255);
// 本体部分は DrawPolygon を使用して上下に赤から青にグラデーションさせながら描画
Vertex[0].x = 0.0f; Vertex[0].y = 30.0f;
Vertex[1].x = DrawWidth; Vertex[1].y = 30.0f;
Vertex[2].x = 0.0f; Vertex[2].y = 30+ size;
Vertex[3].x = DrawWidth; Vertex[3].y = 30+ size;
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 = 255; Vertex[2].g = 0; Vertex[2].r = 0; Vertex[2].a = 255;
Vertex[3].b = 255; Vertex[3].g = 0; Vertex[3].r = 0; Vertex[3].a = 255;
Vertex[4] = Vertex[2];
Vertex[5] = Vertex[1];
DrawPolygon(Vertex, 2, ImageHandle, TRUE, TRUE);
}
// キー入力待ち
WaitKey();
// DXライブラリの後始末
DxLib_End();
// ソフトの終了
return 0;
}
 |
Re: BltStringSoftImageの拡大縮小について ( No.8 ) |
- 名前:管理人 日時:2023/01/08 20:38
No.5 のプログラムの掲載ありがとうございます
PMA の方が正常な描画結果にならない原因がわかりました
すみません、乗算済みアルファを使用する場合は仮画面を必ず真っ黒( R=0 G=0 B=0 )で初期化しなければ
いけないので、SetBackgroundColor の引数が 0, 0, 0 以外になっていると正常に動作しません
なので、載せていただいたプログラムの DxLib_Init の呼び出し後の箇所に
SetBackgroundColor(0, 0, 0);
を追加した所、PMA を使用した文字列の描画も正常な描画結果になりましたので
よろしければお試しください m(_ _)m
|
Re: BltStringSoftImageの拡大縮小について ( No.9 ) |
- 名前:lego hasiri(解決済) 日時:2023/01/09 15:09
検証ありがとうございます。
背景を黒にする処理を追加したところ、無事描画できました。
ご対応ありがとうございました。
|
|