Re: Spine描画時の補間に関して ( No.1 ) |
- 名前:管理人 日時:2024/09/19 16:51
|
Re: Spine描画時の補間に関して ( No.2 ) |
- 名前:Ingaan 日時:2024/09/19 22:19
すみません、リファレンスを見直したらSetDrawMode()はDxLib_Init()の呼び出し後に実行していたので、
元々前に呼び出していたのを後にずらしたら線形補間が反映されました。
(GetDrawMode()で確認しましたが、呼び出し前に設定してもInitで最近傍補間に戻されてしまうんですね…)
SaveDrawScreenToPNG()の方はライブラリを差し替えましたが、現象は変わらず、128×128がエラーにならない限度でした。
[いくつかの寸法に対するSaveDrawScreenToPNGの戻り値](ttps://ibb.co/rvW7gzt)
|
Re: Spine描画時の補間に関して ( No.3 ) |
- 名前:管理人 日時:2024/09/20 02:47
線形補間の問題は解決したようで何よりです
> (GetDrawMode()で確認しましたが、呼び出し前に設定してもInitで最近傍補間に戻されてしまうんですね…)
はい、殆どの関数は DxLib_Init 実行後にのみ有効となっています
> SaveDrawScreenToPNG()の方はライブラリを差し替えましたが、現象は変わらず、128×128がエラーにならない限度でした。
最新のライブラリでも駄目でしたか… うーん…謎です…
↓こちらのような画面中央に描画した四角形をただpngで保存するだけのようなシンプルなプログラムでも
Ingaanさんの環境では SaveDrawScreenToPNG が失敗してしまうのでしょうか?
#include "DxLib.h"
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
// ウインドウモードで起動
ChangeWindowMode( TRUE ) ;
// 画面モードを 1280x720 に設定
SetGraphMode( 1280, 720, 32 ) ;
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1 ;
// 画面の中央に四角形を描画
DrawBox( 640 - 100, 360 - 100, 640 + 100, 360 + 100, GetColor( 255,255,255 ), TRUE ) ;
// 画面全体をPNGで保存
SaveDrawScreenToPNG( 0, 0, 1280, 720, "TestPngSave.png" ) ;
// DXライブラリの後始末
DxLib_End() ;
// ソフトの終了
return 0;
}
|
Re: Spine描画時の補間に関して ( No.4 ) |
- 名前:Ingaan 日時:2024/09/20 22:23
SaveDrawScreenToPNGはシンプルなプログラムの場合、正常に出力されました。
Spine描画プログラムではInit呼び出しの前に次の設定をしていることが影響しているのかもしれません。
====================
#ifdef _WIN32
HWND hWnd = static_cast<HWND>(pWindowHandle);
if (hWnd != nullptr)
{
iRet = DxLib::SetUserWindow(hWnd);
if (iRet == -1)return;
}
iRet = DxLib::SetUserWindowMessageProcessDXLibFlag(hWnd != nullptr ? FALSE : TRUE);
if (iRet == -1)return;
iRet = DxLib::SetChangeScreenModeGraphicsSystemResetFlag(hWnd != nullptr ? FALSE : TRUE);
if (iRet == -1)return;
iRet = DxLib::ChangeWindowMode(TRUE);
if (iRet == -1)return;
#endif
====================
こちらでSaveDrawScreenToPNGのソースコードを追ってみたところ、以下のような動きでした。
1. SaveDrawScreen_WCHAR_T()で指定座標とGSYS.DrawSetting.DrawSizeX, Yを比較
2. DrawSizeX, YはNS_GetGraphSizeで書き込み
3. GetGraphSizeはDX_SCREEN_BACKの場合GSYS.Screen.MainScreenSizeX, Yの値を格納
4. MainScreenSizeX, YはGraphics_Screen_SetMainScreenSizeで変更
5. NS_SetGraphModeでDxLib_InitializeFlag == FALSEならばSetMainScreenSize呼び出し
元々リサイズするたびに::GetClientRect()の値を元にSetGraphModeを呼ぶようにしていましたが、初期化前には呼び出していませんでした。
そこで、DxLib_Init()の呼び出し前に以下のコードを追加したらうまくいきましたが、正しいやり方なのかわかりません。
====================
#ifdef _WIN32
// 中略
int iDesktopWidth = ::GetSystemMetrics(SM_CXSCREEN);
int iDesktopHeight = ::GetSystemMetrics(SM_CYSCREEN);
iRet = DxLib::SetGraphMode(iDesktopWidth, iDesktopHeight, 32);
#endif
====================
それとライブラリの話というよりデバッグ一般の話になってしまって恐縮なのですが、
例えばVisual Studioの場合、静的ライブラリの内部にステップインするにはどのようにするのでしょうか?
実行時のデータを追ってみようとDxLibMake3_24d.zipに含まれている.slnを元に、ソースコードを最新のものに書き換えて生成した
DxLib_d.lib, DxLib_d.pdbを使おうと思ったのですが、設定が悪いのかうまくいきませんでした。
|
Re: Spine描画時の補間に関して ( No.5 ) |
- 名前:管理人 日時:2024/09/20 23:34
> SaveDrawScreenToPNGはシンプルなプログラムの場合、正常に出力されました。
お試し頂きありがとうございます
> Spine描画プログラムではInit呼び出しの前に次の設定をしていることが影響しているのかもしれません。
SetUserWindow, SetUserWindowMessageProcessDXLibFlag, SetChangeScreenModeGraphicsSystemResetFlag,
ChangeWindowMode を使用する以下のようなテストプログラムで試してみましたが、
SaveDrawScreenToPNG は正常に動作しました
#include "DxLib.h"
// メッセージ処理用関数
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
return DefWindowProc( hWnd, msg, wParam, lParam );
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR lpszCmdLine, int nCmdShow )
{
char szClassNme[] = "ウィンドウクラスネーム";
HWND hWnd ;
// ウインドウの作成
if( hPreInst == NULL )
{
WNDCLASS myProg;
myProg.style = CS_HREDRAW | CS_VREDRAW;
myProg.lpfnWndProc = WndProc;
myProg.cbClsExtra = 0;
myProg.cbWndExtra = 0;
myProg.hInstance = hInstance;
myProg.hIcon = NULL;
myProg.hCursor = LoadCursor( NULL, IDC_ARROW );
myProg.hbrBackground = ( HBRUSH )GetStockObject( WHITE_BRUSH );
myProg.lpszMenuName = NULL;
myProg.lpszClassName = szClassNme;
if( !RegisterClass( &myProg ) )
{
return FALSE;
}
}
hWnd = CreateWindow(
szClassNme,
"テストプログラム",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL );
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
SetUserWindow( hWnd ) ;
SetUserWindowMessageProcessDXLibFlag( TRUE ) ;
SetChangeScreenModeGraphicsSystemResetFlag( FALSE ) ;
ChangeWindowMode( TRUE ) ;
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1;
SetDrawScreen( DX_SCREEN_BACK ) ;
// メッセージループ
while( ProcessMessage() == 0 )
{
// メッセージがあったら処理する
MSG msg ;
if( PeekMessage( &msg, hWnd, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg ) ;
DispatchMessage( &msg ) ;
}
// ウインドウに四角形を描画する
ClearDrawScreen() ;
// 描画先のサイズを取得
int w, h;
GetDrawScreenSize( &w, &h );
// 画面の中心に四角形を描画
DrawBox( 100, 100, w - 100, h - 100, GetColor( 255,255,255 ), TRUE ) ;
// 初回のループのみ png を保存
static bool flag = false;
if( flag == false )
{
flag = true;
SaveDrawScreenToPNG( 0, 0, w, h, "TestSavePng.png" );
}
ScreenFlip() ;
}
// DXライブラリの後始末
DxLib_End();
return 0;
}
> そこで、DxLib_Init()の呼び出し前に以下のコードを追加したらうまくいきましたが、正しいやり方なのかわかりません。
> ====================
> #ifdef _WIN32
> // 中略
> int iDesktopWidth = ::GetSystemMetrics(SM_CXSCREEN);
> int iDesktopHeight = ::GetSystemMetrics(SM_CYSCREEN);
>
> iRet = DxLib::SetGraphMode(iDesktopWidth, iDesktopHeight, 32);
> #endif
> ====================
なぜこちらでエラーが発生しなくなったのかは不明ですが、特に変な挙動をしていないのでしたら
こちらの対処方で問題ないと思います
> それとライブラリの話というよりデバッグ一般の話になってしまって恐縮なのですが、
> 例えばVisual Studioの場合、静的ライブラリの内部にステップインするにはどのようにするのでしょうか?
すみません、私も静的ライブラリの内部にステップインすることが可能なのかや、仮に可能だった場合
どのようにすれば良いのかなどは分かりません…
なので静的ライブラリの内部でブレークしたい場合などは、静的ライブラリのソースファイルを
プロジェクトに入れてしまうという方法でステップインできるようにしています
DXライブラリもこちら↓の『DXライブラリのソースファイルを直接コンパイルして使用するプロジェクト』のように
プロジェクトにDXライブラリのソースファイルを含めてしまうことでDXライブラリの関数にステップインできるようになります
https://dxlib.xsrv.jp/temp/DxLibSourceTest_WithUseCLib.zip
|
Re: Spine描画時の補間に関して ( No.6 ) |
- 名前:Ingaan 日時:2024/09/21 02:00
ステップインの方法ご教示ありがとうございます。参考にさせていただきます。
PNGの方はその後色々試した結果、やはり駄目でした。
SFMLの同様の機能のsf::Image::saveToFileは1920×1080(125%)のディスプレイに対して1802×1022のウィンドウを作成、
作成後にウィンドウを2928×1660までリサイズしてもPNGを出力できます。
SDLの同様の機能のIMG_SavePNGも200×200のウィンドウを作成し、その後3190×1809までリサイズしてもPNGを出力できます。
DxLibの場合、200×200でウィンドウを作成し、その後1802×1022にリサイズしてもSetGraphModeを呼ぶことで
描画自体は問題なくできるのですが、SaveDrawScreenToPNGは128×128が限度になります。
仮に先の修正コードを加えても、その後::GetClientRect()で得られる大きさが1942×1102のように
ディスプレイの大きさを超えた時点でSaveDrawScreenToPNGはエラー返答になりました。
|
Re: Spine描画時の補間に関して ( No.7 ) |
- 名前:管理人 日時:2024/09/21 22:02
> DxLibの場合、200×200でウィンドウを作成し、その後1802×1022にリサイズしてもSetGraphModeを呼ぶことで
> 描画自体は問題なくできるのですが、SaveDrawScreenToPNGは128×128が限度になります。
私の環境ではリサイズ後のサイズで SetGraphMode を呼ぶことで SaveDrawScreenToPNG も正常に動作しました
手元で実際に SaveDrawScreenToPNG がエラーになるところを確認できれば原因も直ぐに
特定できると思いますので、もし不都合が無ければ SaveDrawScreenToPNG でエラーが
発生してしまうプロジェクトを zip などで圧縮して頂いて、こちらのメールアドレス
BQE00322(あっとまーく)nifty.com
( (あっとまーく) を @ に置き換えてください )
に送っていただけないでしょうか? m(_ _)m
|
Re: Spine描画時の補間に関して ( No.8 ) |
- 名前:Ingaan 日時:2024/09/22 02:36
ソースコードの方、指定のメールアドレス先に添付して送信しました。
ご確認よろしくお願いいたします。
|
Re: Spine描画時の補間に関して ( No.9 ) |
- 名前:管理人 日時:2024/09/23 01:34
|
Re: Spine描画時の補間に関して ( No.10 ) |
- 名前:Ingaan 日時:2024/09/24 22:23
対応ありがとうございます。
リサイズへの追従を確認できました。
(SetGraphModeにモニタ解像度より大きい値をエラーになることを失念しており、
SaveDrawScreenToPNG呼び出し前にもSM_CXSCREEN、SM_CYSCREENによる制限を掛けるようにしました。)
しかし透過情報にどう対応すればよいのか分かりません。
画面消去色ではない箇所まで透過色として扱われてしまうようで、
画面消去色は透過としつつ、この部分を画面表示通りに保存するにはどのようにすればよいのでしょうか?
[SaveDrawScreenToJPEGによる出力結果](ttps://ibb.co/R61sf67)
[SaveDrawScreenToPNGによる出力結果](ttps://ibb.co/1TmJdww)
|
Re: Spine描画時の補間に関して ( No.11 ) |
- 名前:管理人 日時:2024/09/25 04:53
> 画面消去色ではない箇所まで透過色として扱われてしまうようで、
> 画面消去色は透過としつつ、この部分を画面表示通りに保存するにはどのようにすればよいのでしょうか?
すみません、『画面消去色ではない箇所まで透過色として扱われてしまう』というのは
具体的にはどのような状況なのか、もう少し詳しく教えていただけないでしょうか?
また、お送りいただいたプログラムの内、DxlibSpineTestC について、Setting を選択して表示される
ダイアログがシステムのディスプレイ設定の『テキスト、アプリ、その他の項目のサイズを変更する』で
200% に設定していると正常に表示されず、Binary のチェックを外す事ができませんでした
あと、表示倍率を 100% に変更して Binary のチェックを外し手順通りに2つの atlas.txt を
選択したところ Failed to load spine(s) と表示され、ロードが行えませんでした
ご確認をお願いします m(_ _)m
|
Re: Spine描画時の補間に関して ( No.12 ) |
- 名前:Ingaan 日時:2024/09/25 21:57
状況としましては出力結果として上げた画像のように、画面上には形状が描き出されていて、
SaveDrawScreenToJPEGやBMPで保存した際には画面通りの画像が出力されるのに対して、
SaveDrawScreenToPNGで保存した際には抜け落ちてしまう領域が存在するというものです。
ダイアログに関してはすみません。ウィンドウ作成時にDPIを考慮するよう修正したのでメールにて送りました。
ファイルやプログラム機能の絡む部分はメール本文にて説明させていただきましたので、そちらを参照して頂ければと思います。
|
Re: Spine描画時の補間に関して ( No.13 ) |
- 名前:管理人 日時:2024/09/26 01:07
すみません、本日時間が確保できずまだ更新版のプログラムを拝見できていないのですが、
SaveDrawScreenToJPG や SaveDrawScreenToBMP と同じように透明情報が無い画像として
pngファイルを保存されたいとのことでしたら、以下のように関数 MakeScreen でアルファチャンネルの
無い仮画面を作成して使用することで解決することができます
〜〜〜〜〜グローバル変数定義に追加する記述〜〜〜〜〜
// 仮画面のグラフィックハンドル
int TempScreen;
〜〜〜〜〜初期化処理に追加する記述〜〜〜〜〜
// 仮画面の作成
TempScreen = MakeScreen( 画面の幅, 画面の高さ, FALSE );
〜〜〜〜〜描画処理に追加する記述〜〜〜〜〜
// 裏画面の代わりに仮画面を描画対象にする
SetDrawScreen( TempScreen );
====描画処理====
===Sキーが押されたら SaveDrawScreenToPNG する処理===
// 描画先を裏画面にする
SetDrawScreen( DX_SCREEN_BACK );
// 仮画面を裏画面に描画する
DrawGraph( 0, 0, TempScreen, FALSE );
〜〜〜〜〜画面サイズを変える処理に追加する記述〜〜〜〜〜
// 画面サイズを変更
SetGraphMode( 画面の幅, 画面の高さ, 32);
// 仮画面も作り直す
DeleteGraph( TempScreen );
TempScreen = MakeScreen( 画面の幅, 画面の高さ, FALSE );
よろしければお試しください m(_ _)m
|
Re: Spine描画時の補間に関して ( No.14 ) |
- 名前:Ingaan 日時:2024/09/26 23:35
いいえ、透明情報は欲しいのですが、意図していない箇所が透明になることが問題でした。
それと、原因は分かりました。Spine側でspBlendMode::SP_BLEND_MODE_MULTIPLYとして指定されているスロットが問題で、
画素は最終的に(186, 171, 160, 0)のように、色情報はあるのですが、αは0のため出力時に透明になるようでした。
========== SP_BLEND_MODE_MULTIPLYの混成計算式 ==========
dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))
dstA = dstA
そこでspBlendMode::SP_BLEND_MODE_MULTIPLY指定のスロットに対しては、
(1)RGBはDX_BLENDMODE_SPINE_MULTIPLYを基調とし、
(2)αはDX_BLENDMODE_SPINE_NORMALを基調とする、
次のような混成法で描画するようにしたら、画面通りのPNGとなりました。
DxLib::SetDrawCustomBlendMode
(
TRUE,
DX_BLEND_DEST_COLOR,
DX_BLEND_INV_SRC_ALPHA,
DX_BLENDOP_ADD,
DX_BLEND_ONE,
DX_BLEND_INV_SRC_ALPHA,
DX_BLENDOP_ADD,
255
);
(本当は重ね塗りの領域に対して常にNormalよりMultiplyが先に描画されるような順番だといいんでしょうけど、
スロットの配列順がそうなっていないんですよね…)
|
Re: Spine描画時の補間に関して ( No.15 ) |
- 名前:管理人 日時:2024/09/27 00:37
なるほど、MULTIPLY が原因だったのですね、問題が解決したようで何よりです
頂いたプログラムを拝見したところ、高DPIでも Setting のダイアログが正常に表示されました
これで全ての問題が解決したという認識で問題ないでしょうか?
|