HSP | 透過 PNG で gmode 7 する
※大幅に修正したものを別記事にしました
HSP | 透過 PNG で gmode 7 する
1. HSP gmode 7用 アルファブレンド画像作成モジュール - AkicanBlog
COM オブジェクトと GDI の API を用いて実装されている。
おそらく HSP が PNG 未対応時代の代物。
PNG ファイルフォーマットを解析して描画 (デコードは COM オブジェクトまかせ)。2. HSP用 画像関連モジュール - 略して仮。
DLL 色々呼んでます。めっちゃ高機能!3. なんだか雲行きの怪しい雑記帖 HSPのPNG読み込みからgmode7で使える形式に
標準機能だけを用いてアルファ値と色を算出。
※今回のプログラムの参考とさせていただきました。4. PNG2Gmode7 - SoupSeed
何か良く分からないけど、作成者曰く、色が微妙に変わってしまうバグがあるそうなのでボツ。
1 や 2 でも手ごろで良かったのですが、他のプラットフォームに移植することなどを考えると、なるべく標準命令だけで実装したほうがいいかな~とか考えてしまって、3 を使うことにしました (^^
ソースコード
/**
* モジュール
*/
#module Pixela//
// フィールド
//
#define global picload_pixela(%1) picload_pixela@Pixela %1/**
* 画像ファイルをピクセルアルファブレンドコピーに対応させて読み込み
*
* gmode 7
*/
#deffunc local picload_pixela str fnameload@Pixela fname
draw@Pixelareturn
/**
* 画像読み込み
*/
#deffunc local load str fname// 出力ウィンドウ
BUFFER_ID_PIXELA = ginfo_sel// 背景黒バッファ
BUFFER_ID_BG_BLACK = ginfo_newidbuffer BUFFER_ID_BG_BLACK
picload fname, 2
/* 画像サイズ取得 */
img_height = ginfo_winy
img_width = ginfo_winx// 背景白バッファ
BUFFER_ID_BG_WHITE = ginfo_newidbuffer BUFFER_ID_BG_WHITE, img_width, img_height
pos 0, 0 : picload fname, 1
// 出力ウィンドウ 初期化
type = ginfo_type(BUFFER_ID_PIXELA)
if ( type == 1 ) {
buffer BUFFER_ID_PIXELA, img_width * 2, img_height
} else : if ( type == 2 ) {
screen BUFFER_ID_PIXELA, img_width * 2, img_height
} else : if ( type == 3 ) {
bgscr BUFFER_ID_PIXELA, img_width * 2, img_height
}return
/**
* ウィンドウの種類取得
*
* 1 = buffer, 2 = screen, 3 = bgscr
*/
#defcfunc local ginfo_type int id
mref bmscr, 96 + id // mref bmscr, 67
return bmscr.17/**
* RGBA を計算し出力
*/
#deffunc local drawgsel BUFFER_ID_BG_BLACK
mref img_bgblack, 66
gsel BUFFER_ID_BG_WHITE
mref img_bgwhite, 66
gsel BUFFER_ID_PIXELA
mref img_rgba, 66repeat img_height : y = cnt
index_height = img_width * (img_height - 1 - y)
repeat img_width : x = cnt
// VRAM インデックス
index = (index_height + x ) * 3 // 背景黒・白
index2 = (index_height * 2 + x ) * 3 // RGB
index3 = (index_height * 2 + x + img_width) * 3 // alpha
// 色取得 (配列にすると 15% ほど遅くなる HSP ver.3.4)
black_r = peek(img_bgblack, index + 2)
black_g = peek(img_bgblack, index + 1)
black_b = peek(img_bgblack, index + 0)
white_r = peek(img_bgwhite, index + 2)
white_g = peek(img_bgwhite, index + 1)
white_b = peek(img_bgwhite, index + 0)
// RGB 出力
poke img_rgba, index2 + 2, 255 * black_r / (255 - white_r + black_r)
poke img_rgba, index2 + 1, 255 * black_g / (255 - white_g + black_g)
poke img_rgba, index2 + 0, 255 * black_b / (255 - white_b + black_b)
// alpha 出力
alpha = 255 - white_r + black_r
poke img_rgba, index3 + 2, alpha
poke img_rgba, index3 + 1, alpha
poke img_rgba, index3 + 0, alpha
loop
loopreturn
#global
サンプル
// ファイル選択
dialog "png", 16, "png file!"
if ( stat == 0 ) : end
fname = refstr// ファイル読み込み
buffer 1
picload_pixela fnameimg_width = ginfo_winx / 2
img_height = ginfo_winy// 描画
gsel 0
gmode 7redraw 0
/* 左上: 背景黒 */
color 0, 0, 0 : boxf 0, 0, img_width - 1, img_height - 1
pos 0, 0 : gcopy 1, 0, 0, img_width, img_height/* 右上: 背景白 */
color 255, 255, 255 : boxf img_width, 0, img_width * 2 - 1, img_height - 1
pos img_width, 0 : gcopy 1, 0, 0, img_width, img_height/* 左下: 背景赤 */
color 255, 0, 0 : boxf 0, img_height, img_width - 1, img_height * 2 - 1
pos 0, img_height : gcopy 1, 0, 0, img_width, img_height/* 右下: 背景青 */
color 0, 0, 255 : boxf img_width, img_height, img_width * 2 - 1, img_height * 2 - 1
pos img_width, img_height : gcopy 1, 0, 0, img_width, img_heightredraw
主な変更点
「配列変数に代入せず、直接 VRAM に読み書きするよう変更」
- 配列変数を用いて一括 pset, pget
- 地道に pset, pget
- VRAM 直接アクセス
自分のプログラムでは、元のプログラムより 5 倍ぐらい速くなりました! (数式の変更なども含めて)
誤差
poke img_rgba, index2 + 2, 255 * black_r / (255 - white_r + black_r)