HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2006
0731
ますVRAMデータについて13未解決


ます

リンク

2006/7/31(Mon) 14:56:48|NO.1662

度々すみません。
いまバッファーの色を1ドットづつ取得して処理をしているのですが、
pgetでは遅すぎてやってられません。
VRAMデータに直接アクセスすれば早いと聞いたのですが、
検索したりしてみてもどうすれば取得できるのかわかりません。
取得方法を教えてもらえないでしょうか。お願いします!



この記事に返信する


hiroki

リンク

2006/7/31(Mon) 16:13:37|NO.1664

僕がある画像変換のために作った物の抜粋です。
これ以上の説明は省きます。
これが解らないときはpget,psetをお使いください。


;gsel 2 ;pget x1,cnt ;r=ginfo_r:g=ginfo_g:b=ginfo_b vpos=((winy-1-cnt)*winx*3)+(x1*3) b=peek(vram1,vpos) g=peek(vram1,vpos+1) r=peek(vram1,vpos+2) ;gsel 3 ;color r,g,b ;pset x2,cnt vpos=((winy-1-cnt)*winx*3)+(x2*3) poke vram2,vpos,b poke vram2,vpos+1,g poke vram2,vpos+2,r



hiroki

リンク

2006/7/31(Mon) 16:20:28|NO.1665


mref vram1,66 mref vram2,66 winx=ginfo_winx winy=ginfo_winy

の宣言も必要です。



Drip

リンク

2006/7/31(Mon) 20:53:34|NO.1672

Dripです。

 ますさん、こんにちは。VRAMの直接操作は初心者にとっては少し難しいテーマですね。
VRAMについて簡単に説明してみます。
VRAMの情報は、mref vram,66によって取得することができます。これによって得られた情報は、
画面の左下から右上に向かって、青、緑、赤、青、緑、赤...の順で色の情報が格納されています。
また、数値は1バイト単位なので、扱うためには配列参照を行うかpeekによって取り出すしかありません。

 hirokiさんのサンプルは少し意味がわかりませんが、peekを使用する方法はpget,psetの方法より
約2倍程度しか高速化できません。究極なのは、VRAMに直接配列参照を行いビット演算を行うことです。
広域のメモリ操作命令を使用するのも有効です。これならば恐ろしい程の処理の高速化が期待できます。
しかしこの方法は、アルゴリズムによって限られた状況下でしか行えない事が多いです。

 ビット演算による処理はケースバイケースによる少し難しいプログラムを書く必要があるので
今回は置いておくとして、VRAMを使用した最も基本的なサンプルを以下に用意しました。
尚、このサンプルはVRAMの意味を理解するためのサンプルであり、
強力な高速化アルゴリズムを表すものではありません。VRAMの研究材料にしてみてください。

x=32 //赤い点を打つ座標 y=24 screen 0,256,256 //コピー元ウィンドウ color 255:pset x,y mref vramA,66 screen 3,ginfo_winx,ginfo_winy //コピー先ウィンドウ mref vramB,66 p=((ginfo_winy-1-y)*ginfo_winx+x)*3 //検出すべき座標を取得 //座標は、画面左下から右上に向かって //青、緑、赤の順に1バイトずつ格納されている。 b=peek(vramA,p) //screen0に打った点の色を取り出す g=peek(vramA,p+1) r=peek(vramA,p+2) poke vramB,p,b //screen3にscreen0に打った点と同じ位置に同じ色の点を打つ poke vramB,p+1,g poke vramB,p+2,r redraw 1

少し難しいかもしれませんががんばってください。



Shinya

リンク

2006/7/31(Mon) 20:57:06|NO.1673

 ますさんはじめまして。

 VRAM は3つのポイントをおさえれば、扱えるようになります。
	buffer 1,0,0 :picload dir_exe + "/docs/cg.gif"
wx = ginfo_winx wy = ginfo_winy // Point ① ; wx が4の倍数でなければダミーを加える( 4の倍数にする ) if wx & 0x00000003 : wx = wx & 0x0ffffffc | 4 ; ; ↓は↑と同じ意味( 実行速度が遅い ) ; ; if wx \ 4 : wx = wx + ( 4 - wx \ 4 ) ; ; 変数 VRAM を現在のビデオメモリデータとおく mref VRAM,66 gsel i = 0 ; (VRAMサイズ)/3 分繰り返す (3Byteづつ取り出すから) repeat wx * wy // Point ② ; VRAM は 青,緑,赤 と並んでいる (R,G,B ではなく B,G,R と並んでいる) ; 1byteめ = B (青) ; 2byteめ = G (緑) ; 3byteめ = R (赤) ; これらが連なっている color peek( VRAM,i+2 ),peek( VRAM,i+1 ),peek( VRAM,i ) // Point ③ ; VRAM はスクリーンの左下が 0Byte になっている ; つまり,左下から描くことになる pos cnt\wx,wy-cnt/wx pset i+3; ←RGB合計 3BYTE を加える loop
Point ①
 VRAMのサイズは、
  式1:VRAMサイズ = スクリーンの幅 * スクリーンの高さ * 3(RGB)
 で求められる。

  しかし、スクリーンの幅が 4の倍数でないとき、VRAMのサイズが
 4の倍数にならないことがある。そこで、スクリーンの幅に
 ダミーを加え、4の倍数にしてから 上の式 を使う。

 スクリーンの幅が 4の倍数で、上式を使うとVRAMサイズは、必ず 4 で割り切れる。
 (4 で割り切れると peek の代わりに lpeek が使える)

Point ②
 VRAM は1byteめから 青,緑,赤,青,緑,赤... が続く

Point ③
 VRAM は画像の左下が 0byte になっている



Shinya

リンク

2006/7/31(Mon) 21:30:31|NO.1677

 あわわっ。NO.1673の「Point ①」のダミーを加えるやつ。
何でそんな面倒なことするのかってやつ。・・・書き忘れてた。
(実は、僕もよくわかんない。予想なら立てられる)

 peek で n回 繰り返すより、lpeek で n/4回 繰り返すほうが
約4倍速い。VRAMサイズが 4 の倍数だと、lpeek で一括処理ができる。

 しかし、問題なのは、VRAMサイズを 4で割ったときの余りを、
peek で処理すればよいので、ほかに理由があるのかもしれません。



ます

リンク

2006/7/31(Mon) 21:59:28|NO.1679

hirokiさん、Dripさん、Shinyaさん、ありがとうございます。

hirokiさんのサンプルは、理解できませんでした…。すみません。
Dripさんのサンプルは、

p=((ginfo_winy-1-y)*ginfo_winx+x)*3 //検出すべき座標を取得
の部分が分かりません。他は分かるのですが…。
(ginfo_winy-1-y)
は分かるのですが、その後の
*ginfo_winx+x
の意味が良く分からないんです…

Shinyaさんのサンプルは、
疑問点がありました。
lpeek で一括処理ができるとありますが、
ということは
BGRB,GRBG,RBGR,…
とデータを取り出していくということでしょうか。
分かりづらくありませんか?


あと、いま作っているスクリプトは、
bufferで作ったウィンドウに読み込んだ画像を読み込み、
色を1ドットづつ取得して、それを加工していってまとめてファイルに保存
するものなのですが、
「画像は左上から右下へ」っていう概念があったので、
良く考えたらそれにとらわれずにVRAMにしたがって全ての処理をすれば楽だということに、
今気が付きました(笑)

皆様のサンプルを見て、なんとなく処理方法が頭の中にうかんできたので、
がんばってみようと思います。



hiroki

リンク

2006/8/1(Tue) 08:38:11|NO.1685

ごめんなさい。

ただの既存のソースから抜粋しただけです。
でも、上に注釈あるから解るかなと思って・・・。(^^;)



Shinya

リンク

2006/8/1(Tue) 22:16:49|NO.1708

>lpeek で一括処理ができるとありますが、
>ということは
>BGRB,GRBG,RBGR,…
>とデータを取り出していくということでしょうか。

 すみません。ますさんの、質問から離れたことをいっていました。
は、VRAMの特性について書き込んだつもりでした・・・。

 とりあえず画像処理において lpeek を使うのは、ビット数列(画像)のスクロールや、コピーをするとき
に限定されます。
/*
screen 0 に screen 1 の内容をコピーするサンプル */ #define RGB 3 buffer 1,0,0 :picload dir_exe + "/docs/cg.gif" mref VRAM1,66 sx1 = ginfo_winx sy1 = ginfo_winy // 一行のバイト数を4の倍数に設定( 必ず必要 ) if sx1 & 3 : sx1 = sx1 & 0x0ffffffc | 4 // VRAMのサイズ VramSize = sx1 * sy1 * RGB gsel mref VRAM0,66 sx0 = ginfo_winx sy0 = ginfo_winy if sx0 & 3 : sx0 = sx0 & 0x0ffffffc | 4 x = 0 y = 0 gosub *Draw x = 320 y = 240 gosub *Draw redraw 1 stop *Draw // コピーを始める座標(x,y+sy1)のアドレス r = ( (sy0 - y - sy1) * sx0 + x ) * RGB // コピー先の 一行のバイトサイズ xb0 = sx0 * RGB // コピー元の 一行のバイトサイズ xb1 = sx1 * RGB repeat VramSize / 4; ← VRAMのサイズは必ず 4 で割り切れる a = cnt * 4 c = a\xb1 + (a/xb1*xb0) lpoke VRAM0, r + c, lpeek( VRAM1,cnt*4 ) loop return
 ↑は、単に lpeek を使用してみるサンプルで、HSPの他のスクリプトへの
汎用性はまったくありません。


>(ginfo_winy-1-y)
>は分かるのですが、その後の
>*ginfo_winx+x
>の意味が良く分からないんです…
 ↑は、よくRPGのマップ処理で目にすると思います。

 とりあえず (ginfo_winy-1-y) = Y' とおいてみてください。
すると (Y'*ginfo_winx+x) となります。
ginfo_winx はスクリーンの一行分のバイトサイズと考えられるので。

{ Y' * (一行分のバイトサイズ) } + x つまり、

Y'=0 なら、0行目 + x
Y'=1 なら、1行目 + x
Y'=n なら、n行目 + x

 つまり
 Y'*(一行分のバイトサイズ) は 第n行目のバイトサイズをあらわしているのです。

(ginfo_winy-1-y) = Y' の(ginfo_winy-1-y)は、VRAMが、スクリーンの
左下が、0byteになっているからこのような形になっています。
ただし、HSPに慣れ親しんでいる人は、
 Y' = (ginfo_winy-1-y) ではなく
 Y' = (ginfo_winy-y) を使ったほうがよいと思いますよ。



Drip

リンク

2006/8/1(Tue) 22:17:03|NO.1709

Dripです。

 こんにちは。
p=((ginfo_winy-1-y)*ginfo_winx+x)*3
の意味がわかりにくいとのことですが、例えば+xを消すと常に処理されるX座標は0になります。
「+x」がないとX座標は常に0です。

「*ginfo_winx」については、これがないとy座標の計算が完結しません。
下方向に1ずれると、データはginfo_winx*3バイトずれるからです。(*3は式の最後でまとめてかけます。)
わかりにくい数式はすぐに挫折せず粘り強く慎重に調べてみる必要があります。



ます

リンク

2006/8/1(Tue) 22:27:53|NO.1710

>Shinyaさん、Dripさん
ご説明ありがとうございます。
やっと式の意味が分かりました。

lpeekを使う意味も、分かりました。
ありがとうございます。
もう少しがんばってみます。



Shinya

リンク

2006/8/1(Tue) 22:34:43|NO.1711

間違えました。
NO.1708の
>ginfo_winx はスクリーンの一行分のバイトサイズと考えられるので。
のginfo_winxは一行分のバイトサイズとは考えられません。単なる、スクリーンサイズでした。
 意味不明な、回答をしてすみません。注意します。



Shinya

リンク

2006/8/2(Wed) 05:31:41|NO.1721

間違えました。
NO.1708の
>Y' = (ginfo_winy-1-y) ではなく
>Y' = (ginfo_winy-y) を使ったほうがよいと思いますよ。
は、NO.1708のサンプルスクリプト内だけの話です。

 ぼけぼけな、回答をしてどうもすみませんでした。



Shinya

リンク

2006/8/12(Sat) 10:35:27|NO.1977

NO.1708のサンプルが間違っていたので、修正したものを載せておきます。
#define	RGB 3
; ↓あえて 4 の倍数にしない buffer 1,319,240 : picload dir_exe + "/docs/cg.gif",1 mref VRAM1,66 sx1 = ginfo_winx * RGB sy1 = ginfo_winy dsize = sx1 /* if sx1 & 3 : sx1 = (sx1 & 0x0ffffffc) + 4 */ dsize = sx1 - dsize ; ←ダミーのサイズ VramSize = sx1 * sy1; ←VRAM のサイズ gsel mref VRAM0,66 sx0 = ginfo_winx : tmp = sx0 * RGB sy0 = ginfo_winy if tmp & 3 : tmp = (tmp & 0x0ffffffc) + 4 x = 0 : y = 0 gosub *Draw x = 320 : y = 240 gosub *Draw redraw 1 stop *Draw r = (sy0 - y - sy1) * tmp + x * RGB repeat VramSize / 4 a = cnt * 4 b = a\sx1 + (a/sx1*tmp) /* c = (a\sx1>dsize)*dsize ; ← ダミーを描画しないための値 */ lpoke VRAM0, r + b, lpeek( VRAM1,cnt*4 - c ) loop return
 ダミーの追加処理を行っていないので、画像が斜めに表示されます。
トグルコメントを削除するとうまく表示されます。



ONION software Copyright 1997-2025(c) All rights reserved.