テクスチャのパレット管理

22 views
Skip to first unread message

zebla

unread,
Jun 22, 2008, 9:21:17 AM6/22/08
to Star Ruby
どうも、zeblaです。

ちょっと思い立ったのですが、StarRubyのテクスチャに「パレット」の概念を導入することができないでしょうか?

>>http://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%AB%E3%83%A9%E3%83%BC

現行のメソッド群では、格闘ゲームの2Pカラーなどを実現することは難しく、またパレットアニメーションは多くのスーファミゲームで活用されていて、表
現の幅が広がると思います。


○テクスチャからパレットデータを取得するメソッド
○指定パレットデータでテクスチャ描画を行うTexture#render_textureメソッドのオプション、またはテクスチャにパレットデータを
適用するメソッド


を提案します。パレットデータの編集も自由にできるとよいですが、この辺はパレットデータがStringになるかArrayやHashになるかはたまた
独自のクラスのインスタンスになるかで方法が変わってくるので、またその時の話ということで。

Hajime Hoshi

unread,
Jun 22, 2008, 11:53:21 AM6/22/08
to star...@googlegroups.com
星です。

ご提案ありがとうございます。

たとえば、 256 色画像から Texture オブエジェクトをつくった場合、
初期状態はたしかに 256 色なのですが、
別の Texture オブジェクトをそれにアルファブレンディングした場合、
新しい色が誕生してしまい、パレットを保持できなくなってしまいます。
そのため、 Texture は最初からパレットを持たずに 32bit カラーのピクセル列という
ことにしてしまっています。

ここらへん何か折り合いつける案はございませんでしょうか。

--
Hajime Hoshi <hajim...@gmail.com>

zebla

unread,
Jun 23, 2008, 3:41:22 AM6/23/08
to Star Ruby


On 6月23日, 午前12:53, "Hajime Hoshi" <hajimeho...@gmail.com> wrote:
> 星です。
>
> > どうも、zeblaです。
>
> > ちょっと思い立ったのですが、StarRubyのテクスチャに「パレット」の概念を導入することができないでしょうか?
>
> >>>http://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%...
>
> > 現行のメソッド群では、格闘ゲームの2Pカラーなどを実現することは難しく、またパレットアニメーションは多くのスーファミゲームで活用されていて、表
> > 現の幅が広がると思います。
>
> > ○テクスチャからパレットデータを取得するメソッド
> > ○指定パレットデータでテクスチャ描画を行うTexture#render_textureメソッドのオプション、またはテクスチャにパレットデータを
> > 適用するメソッド
>
> > を提案します。パレットデータの編集も自由にできるとよいですが、この辺はパレットデータがStringになるかArrayやHashになるかはたまた
> > 独自のクラスのインスタンスになるかで方法が変わってくるので、またその時の話ということで。
>
> ご提案ありがとうございます。
>
> たとえば、 256 色画像から Texture オブエジェクトをつくった場合、
> 初期状態はたしかに 256 色なのですが、
> 別の Texture オブジェクトをそれにアルファブレンディングした場合、
> 新しい色が誕生してしまい、パレットを保持できなくなってしまいます。
> そのため、 Texture は最初からパレットを持たずに 32bit カラーのピクセル列という
> ことにしてしまっています。


つまり Texture の実装にインデックスカラーの概念はない、ということですか。


> ここらへん何か折り合いつける案はございませんでしょうか。


例えば、PNGからテクスチャを作るときにパレットを指定して色違いのテクスチャが作れるだけでも有用かなと思いました。ただPNG自体、インデックス
カラーが有効なのは8bitまでなんでしたっけ。

32bitモードと8bitモードの Texture サブクラスなんて考えも浮かびましたが、やりすぎでしょうか。Numeric 下の
Float と Integer みたいな感覚で。

> --
> Hajime Hoshi <hajimeho...@gmail.com>

Daigo

unread,
Jun 23, 2008, 5:33:18 AM6/23/08
to Star Ruby
これは何度も出てきた議論ですね。

恐らくZeblaさんの言うとおり、Textureクラス自体を2種類持つのがもっともきれいなやり方でしょう。
オプションでビットを分けてもいいかもですが。αチャンネル使わない画像なら、24bit画像とすることでちょっと高速化できるとか・・。

αブレンディング転送だと結果が24bitだか32bitになるのは仕方ないことですね。
ただ、8bitテクスチャから8bitテクスチャへの単純転送などはできるといいかもしれません。。

導入を考える場合は、API自体大きな見直しを迫られることになりそうですね・。

Daigo

unread,
Jun 23, 2008, 5:37:31 AM6/23/08
to Star Ruby
追記:ちなみに自分はパレット対応には割りと賛成という感じですね。
高速化の余地も多分あるだろうし、なによりスーファミっぽいことができるわけですからね。
パレットアニメーションならではの表現手法というのは結構あって、それが現状できない(change_hueは実用に耐えないでしょうし)わけなので、
複数のビットに対応するテクスチャってのはあるとさらに自由度・アピール度がアップ・・なんて気がします。もちろん難しくなってはいかんですが。

Hajime Hoshi

unread,
Jun 23, 2008, 9:34:18 AM6/23/08
to star...@googlegroups.com
星です。

>> たとえば、 256 色画像から Texture オブエジェクトをつくった場合、
>> 初期状態はたしかに 256 色なのですが、
>> 別の Texture オブジェクトをそれにアルファブレンディングした場合、
>> 新しい色が誕生してしまい、パレットを保持できなくなってしまいます。
>> そのため、 Texture は最初からパレットを持たずに 32bit カラーのピクセル列という
>> ことにしてしまっています。
>
> つまり Texture の実装にインデックスカラーの概念はない、ということですか。

そーです。
全部 32bit ピクセル列に変換しています。

>> ここらへん何か折り合いつける案はございませんでしょうか。
>
> 例えば、PNGからテクスチャを作るときにパレットを指定して色違いのテクスチャが作れるだけでも有用かなと思いました。ただPNG自体、インデックス
> カラーが有効なのは8bitまでなんでしたっけ。
>
> 32bitモードと8bitモードの Texture サブクラスなんて考えも浮かびましたが、やりすぎでしょうか。Numeric 下の
> Float と Integer みたいな感覚で。

うーむ、「32bit にできて 8bit にできること」やまたはその逆は必ずあって、
それでクラスを分けるのは分かるのですが、
どっちのテクスチャか区別しなければならなくなってしまうのは
使いづらくなってしまうと思います。

また、 Integer と Float の場合は、それぞれ immutable なオブジェクトで
オブジェクトそのもののクラスが変わることはないですが、
Texture は mutable なのでそうはいかないです。
たとえば 8bit Texture オブジェクトを描画して 32bit に変化してしまった場合、
新しいオブジェクトを生み出すことになります。
すると、クラスを分ける場合、 render_texture メソッドの仕様が
「self の状態を変える」のではなく「新しく 32bit Texture オブジェクトを生み出す」
という仕様にならざるを得なくなり、それは使いやすいのかどうか疑問です。

--
Hajime Hoshi <hajim...@gmail.com>

Hajime Hoshi

unread,
Jun 23, 2008, 9:35:57 AM6/23/08
to star...@googlegroups.com
星です。追記。

> また、 Integer と Float の場合は、それぞれ immutable なオブジェクトで
> オブジェクトそのもののクラスが変わることはないですが、

Ruby は immutable かどうかに関係なく、そもそもオブジェクトのクラスを
変えることはできないので、このつながりは変でした。

--
Hajime Hoshi <hajim...@gmail.com>

zebla

unread,
Jun 24, 2008, 8:24:25 AM6/24/08
to Star Ruby
ではこんなのはどうでしょう?

8bit画像を表現するクラス EightbitTexture クラスを新設し、このクラスのインスタンスはテクスチャ描画の転送元としてのみ参照す
ることが可能とする。つまり、 Texture#render_texture(EightbitTexture,x,y,options) とするこ
とは可能だが EightbitTexture#render_texture メソッドは実装しない、ということです。

このようにすると、

EightbitTexture のビット数は変化しないのでパレットを保持できる
Texture クラスは今までどおりの使い方ができる
転送先・転送元ともにビット数が変化しないので新しいオブジェクトを生成する必要はない(本当か?)

こんなメリットが得られるんじゃないかと思いました。
もともと最終出力である Game.screen はテクスチャなので、他のテクスチャをブレンドできなくとも特には問題ないはずです。

> --
> Hajime Hoshi <hajimeho...@gmail.com>

Hajime Hoshi

unread,
Jun 24, 2008, 10:18:38 AM6/24/08
to star...@googlegroups.com
星です。

> ではこんなのはどうでしょう?
>
> 8bit画像を表現するクラス EightbitTexture クラスを新設し、このクラスのインスタンスはテクスチャ描画の転送元としてのみ参照す
> ることが可能とする。つまり、 Texture#render_texture(EightbitTexture,x,y,options) とするこ
> とは可能だが EightbitTexture#render_texture メソッドは実装しない、ということです。
>
> このようにすると、
>
> EightbitTexture のビット数は変化しないのでパレットを保持できる
> Texture クラスは今までどおりの使い方ができる
> 転送先・転送元ともにビット数が変化しないので新しいオブジェクトを生成する必要はない(本当か?)
>
> こんなメリットが得られるんじゃないかと思いました。
> もともと最終出力である Game.screen はテクスチャなので、他のテクスチャをブレンドできなくとも特には問題ないはずです。

さっきだいご君と話していたのですが、結論から言うとそれでいけそうだと思います。
描画先にならない 8bit 画像クラスを作るということですね。
実装もそんなに難しくなさそうです。

だいごくんの提案で、 EightbitTexture 同士は (お互い違うパレットを持っていようとも)
相互書き込み可能にしてしまおうという案もありましたが、
便利なのかどうか怪しいし、実装が面倒になるので保留にします。

> 転送先・転送元ともにビット数が変化しないので新しいオブジェクトを生成する必要はない(本当か?)

ってのは、 EightbitTexture 内部に普通の Texture 持たせて、
それを使いまわせるだろうということであってますか?
そうだとしたらその通りだと思います。

あと、 EightbitTexture って名前よりよい名前がありそうなので、それが思いついたらかなあ。

P.S.
そもそも Texture って名前がよくないという指摘を受けました。確かに。
Bitmap とかそういう名前にしておけばよかったんですが、今更変えようがない。

--
Hajime Hoshi <hajim...@gmail.com>

zebla

unread,
Jun 24, 2008, 10:39:03 AM6/24/08
to Star Ruby


> さっきだいご君と話していたのですが、結論から言うとそれでいけそうだと思います。
> 描画先にならない 8bit 画像クラスを作るということですね。
> 実装もそんなに難しくなさそうです。
>
> だいごくんの提案で、 EightbitTexture 同士は (お互い違うパレットを持っていようとも)
> 相互書き込み可能にしてしまおうという案もありましたが、
> 便利なのかどうか怪しいし、実装が面倒になるので保留にします。
>
> > 転送先・転送元ともにビット数が変化しないので新しいオブジェクトを生成する必要はない(本当か?)
>
> ってのは、 EightbitTexture 内部に普通の Texture 持たせて、
> それを使いまわせるだろうということであってますか?
> そうだとしたらその通りだと思います。
>

なんていうか、8bit を 32bit に増やさねばならない、またはその逆の状況が起こりえない、くらいのつもりで書きました。あさっての方向に向
かって発言していたとしたらスルーしてください。

> あと、 EightbitTexture って名前よりよい名前がありそうなので、それが思いついたらかなあ。
>

Octa~ とか? むーん。

> P.S.
> そもそも Texture って名前がよくないという指摘を受けました。確かに。
> Bitmap とかそういう名前にしておけばよかったんですが、今更変えようがない。
>

ポリゴンの表面に張り付いてるモノ、てなイメージがありますね。まあ慣れてしまえばどーってことはないので。

ISA

unread,
Jun 25, 2008, 3:47:44 AM6/25/08
to Star Ruby
はじめまして。
RubyでですがStarRubyのサポートライブラリを作りたいなどと思っているISAと言います。
よろしくお願いします。


>EightbitTexture
クラスの本質はビット数ではなくインデックスカラーであるという点と、
インデックスカラーは8bit以外のものも存在するため、
「8bit画像」というクラス名は適切でないと思われます。

・PalettedTexture
・IndexedColorTexture
あたりが無難ではないでしょうか。
後者なら既存の「Texture」は「TrueColorTexture」のことだと考えられますし。

既存のクラスの意味が変化するのが問題ならば、ネームスペースを使って
・Texture::IndexedColor
などとするのもアリかも知れません。

Hajime Hoshi

unread,
Jun 25, 2008, 6:21:30 AM6/25/08
to star...@googlegroups.com
星です。

> はじめまして。
> RubyでですがStarRubyのサポートライブラリを作りたいなどと思っているISAと言います。
> よろしくお願いします。

おお、それはありがたいです!
ありがとうございます!

> >EightbitTexture
> クラスの本質はビット数ではなくインデックスカラーであるという点と、
> インデックスカラーは8bit以外のものも存在するため、
> 「8bit画像」というクラス名は適切でないと思われます。
>
> ・PalettedTexture
> ・IndexedColorTexture
> あたりが無難ではないでしょうか。
> 後者なら既存の「Texture」は「TrueColorTexture」のことだと考えられますし。
>
> 既存のクラスの意味が変化するのが問題ならば、ネームスペースを使って
> ・Texture::IndexedColor
> などとするのもアリかも知れません。

8bit であることは本質でないのは同意です。
リードオンリーであることを断らずにに○○Texture とすると、
Texture と同じような操作ができると期待されてしまうので
よろしくないんじゃないかと思います。
特徴として
* パレットを持つこと (インデックスカラーであること)
* リードオンリーであること
があるので、

ImmutablePatelleTexture
ReadOnlyPaletteTexture
IndexedColors

うーん長い。まだこれだという案はないですね・・。

--
Hajime Hoshi <hajim...@gmail.com>

ISA

unread,
Jun 25, 2008, 8:02:54 AM6/25/08
to Star Ruby
> おお、それはありがたいです!
> ありがとうございます!

まだ実用には至っていませんが、
スプライトやシーン管理フレームワークなどを作ろうと思っています。

「すべてがテクスチャである」という特徴が、
こういったライブラリを作成するのには非常に便利でとても楽しんてやれます。


> リードオンリーであることを断らずにに○○Texture とすると、
> Texture と同じような操作ができると期待されてしまうので
> よろしくないんじゃないかと思います。
> 特徴として
> * パレットを持つこと (インデックスカラーであること)
> * リードオンリーであること
> があるので、

既存のゲーム機のネーミングにならってCharactorなんてのはどうでしょう。
単体では画像として使用できず、CharactorとPaletteを組み合わせて
Textureを作成し、初めて画像として使用できるイメージです。

慣習としてリードオンリーであることも暗示していますし。
(そもそもTexture扱いではなくなるのでそんな心配もない?)
リードオンリーだと明示しておかなければ、
将来的にキャラクタをドット単位で操作させるということもできるかと思います。

Hajime Hoshi

unread,
Jun 25, 2008, 4:42:00 PM6/25/08
to star...@googlegroups.com
星です。

>> おお、それはありがたいです!
>> ありがとうございます!
>
> まだ実用には至っていませんが、
> スプライトやシーン管理フレームワークなどを作ろうと思っています。
>
> 「すべてがテクスチャである」という特徴が、
> こういったライブラリを作成するのには非常に便利でとても楽しんてやれます。

なるほど。
結構アニメーションさせるためのクラスは需要があるのですが、
一般解を出すのが難しいので様子見状態です。

>> リードオンリーであることを断らずにに○○Texture とすると、
>> Texture と同じような操作ができると期待されてしまうので
>> よろしくないんじゃないかと思います。
>> 特徴として
>> * パレットを持つこと (インデックスカラーであること)
>> * リードオンリーであること
>> があるので、
>
> 既存のゲーム機のネーミングにならってCharactorなんてのはどうでしょう。
> 単体では画像として使用できず、CharactorとPaletteを組み合わせて
> Textureを作成し、初めて画像として使用できるイメージです。
>
> 慣習としてリードオンリーであることも暗示していますし。
> (そもそもTexture扱いではなくなるのでそんな心配もない?)
> リードオンリーだと明示しておかなければ、
> 将来的にキャラクタをドット単位で操作させるということもできるかと思います。

Character かな。
キャラクターというとゲーム中に登場する人物のようなイメージがあるのですが
違いますでしょうか?
既存のゲーム機の慣習というのがよくわからないもので、
広く使われているならばそれはいいかもしれませんね。

--
Hajime Hoshi <hajim...@gmail.com>

ISA

unread,
Jun 25, 2008, 11:49:16 PM6/25/08
to Star Ruby
> Character かな。
Characterでした(笑)


> キャラクターというとゲーム中に登場する人物のようなイメージがあるのですが
> 違いますでしょうか?
FC、SFC等の2Dゲーム機では良く使われているネーミングだと思います。
確かにゲーム内のキャラクター(人物登場)と混同してしまいそうな気はしますが、
StarRubyネームスペースの中で命名する分にはあまり問題にはならないんじゃないでしょうか?


http://hp.vector.co.jp/authors/VA042397/nes/ppu.html
http://akkera102.sakura.ne.jp/gbadev/index.php?Step.4%20%A5%BF%A5%A4%A5%EB%A5%E2%A1%BC%A5%C9%281%29

キャラクタが1枚のタイルだとして、それを複数枚組み合わせることでスプライトや背景を表示します。
その際に、キャラクタごとにパレットを適用させることで色のついた画像になります。

StarRuby標準では組み合わせのことは考えず、単純に1枚のキャラクタから1枚の画像が作成できるだけで良いんじゃないかと思います。
そういえば、この方法ならTextureに手を加えなくて良いのでライブラリで対応することもできますね。ちょっと処理が重そうですが。


以下に擬似コードを示します。
hoge = Character.load("hoge_char")
hoge_color_1p = Palette.load("hoge_color_1p") # てきとー
hoge_color_2p = Palette.load("hoge_color_2p")

hoge_1p = hoge.draw(hoge_color_1p) # ここでTextureが作成される
hoge_2p = hoge.draw(hoge_color_1p)

Game.screen.render_texture(hoge_1p, 0, 0)
Game.screen.render_texture(hoge_2p, 64, 0)

Hajime Hoshi

unread,
Jun 26, 2008, 1:06:34 AM6/26/08
to star...@googlegroups.com
星です。

>> キャラクターというとゲーム中に登場する人物のようなイメージがあるのですが
>> 違いますでしょうか?
> FC、SFC等の2Dゲーム機では良く使われているネーミングだと思います。
> 確かにゲーム内のキャラクター(人物登場)と混同してしまいそうな気はしますが、
> StarRubyネームスペースの中で命名する分にはあまり問題にはならないんじゃないでしょうか?
>
>
> http://hp.vector.co.jp/authors/VA042397/nes/ppu.html
> http://akkera102.sakura.ne.jp/gbadev/index.php?Step.4%20%A5%BF%A5%A4%A5%EB%A5%E2%A1%BC%A5%C9%281%29
>
> キャラクタが1枚のタイルだとして、それを複数枚組み合わせることでスプライトや背景を表示します。
> その際に、キャラクタごとにパレットを適用させることで色のついた画像になります。
>
> StarRuby標準では組み合わせのことは考えず、単純に1枚のキャラクタから1枚の画像が作成できるだけで良いんじゃないかと思います。
> そういえば、この方法ならTextureに手を加えなくて良いのでライブラリで対応することもできますね。ちょっと処理が重そうですが。

なるほどう。
たしかに StarRuby モジュール内で Character クラスを作れば問題はなさそうですね。
ただ、なるべくトップレベルの名前空間内でもユニークな名前にするのに越したことはないです。
たとえば、 StarRuby::Array というクラスを定義すると、いくら名前空間が分かれていると
いっても、使いづらいものがあります。

> 以下に擬似コードを示します。
> hoge = Character.load("hoge_char")
> hoge_color_1p = Palette.load("hoge_color_1p") # てきとー
> hoge_color_2p = Palette.load("hoge_color_2p")
>
> hoge_1p = hoge.draw(hoge_color_1p) # ここでTextureが作成される
> hoge_2p = hoge.draw(hoge_color_1p)
>
> Game.screen.render_texture(hoge_1p, 0, 0)
> Game.screen.render_texture(hoge_2p, 64, 0)

毎回 Texture オブジェクトを生成するのは現実的ではないと思います。
パレットアニメーションをさせたい場合、パレットが変わる度に Texture オブジェクトを
生成することになってしまうからです。
そもそもインデックスカラーのテクスチャが欲しいという要望には、
パレットアニメーションをやりたいということがあったはずで、
パレットが頻繁に変わることを想定せねばなりません。

Texture オブジェクト生成はせず、描画元の Texture オブジェクトが描画の対象として
Character (仮) オブジェクトを認識するようにするのがよいと思います。
使う側にとっても変換を意識せずに済みますし。

--
Hajime Hoshi <hajim...@gmail.com>

ISA

unread,
Jun 28, 2008, 12:29:05 AM6/28/08
to Star Ruby
> ただ、なるべくトップレベルの名前空間内でもユニークな名前にするのに越したことはないです。
> たとえば、 StarRuby::Array というクラスを定義すると、いくら名前空間が分かれていると
> いっても、使いづらいものがあります。

そうですね。
Characterというメソッドは明らかにゲーム製作者が使いそうなので、もう少し考える必要はありますね。
「キャラクタパターン」「BGパターン」と言うのでPatternとか?


> 毎回 Texture オブジェクトを生成するのは現実的ではないと思います。
> パレットアニメーションをさせたい場合、パレットが変わる度に Texture オブジェクトを
> 生成することになってしまうからです。

確かに毎回Textureを生成するのは現実的ではないですね。



> Texture オブジェクト生成はせず、描画元の Texture オブジェクトが描画の対象として
> Character (仮) オブジェクトを認識するようにするのがよいと思います。

最初に戻ってしまいましたが、キャラクタのインスタンス変数にパレットを格納しておいて、
Textureとの違いを意識せずにrender_textureで描画できるというのが良さそうですね。

hajimehoshi

unread,
Jul 5, 2008, 9:23:23 AM7/5/08
to Star Ruby
星です。

さっき思いついた新しい案です。
いままでの案は、 Texture クラス / メソッドに大規模な変更が必要でした。
新しい案は、既存のメソッドへの影響がほぼゼロです。

各クラス、メソッド名は暫定です。

class IndexedColors
インデックスカラーの画像を表すクラス。
内部的にはインデックス列、幅、高さ、カラーキー (インデックス) を保持する。
パレットは保持しない (あえて分けた方がわかりやすいかなあと思いました)。

IndexedColors.load_with_palette(file)
8bit PNG 画像の file を読み込み、
[IndexedColors オブジェクト, palette] という配列を返す。
palette は、パレットを表す Color の単なる配列である。

Texture#render_indexed_colors(indices, palette)
self にインデックスカラーの画像を描画する。
左上からピクセル列をそのまま流し込む形で描画することを想定しているので、
縦横の大きさが合わないと変になる。

この案のいいところは以下の通りです:

* 大規模なクラス追加がない
* Texture クラスの既存のメソッドに影響を及ぼすことはない
* 描画の際に新しい Texture オブジェクトを毎回生成する必要はなく、
中間バッファとしての Texture を使いまわせば効率的

zebla

unread,
Jul 6, 2008, 12:31:23 AM7/6/08
to Star Ruby
> class IndexedColors
> インデックスカラーの画像を表すクラス。
> 内部的にはインデックス列、幅、高さ、カラーキー (インデックス) を保持する。
> パレットは保持しない (あえて分けた方がわかりやすいかなあと思いました)。

パレットをインスタンス内に保持するか否かはどっちもどっちかなあ、といった感想です。
パレットとインデクス列がくっついているほうが都合がいいとプログラマが思えば、そのように管理する仕組みをプログラマ自身が作れるでしょうし、そうい
う意味では離れていたほうがいいのかもしれないと、個人的には思います。

> IndexedColors.load_with_palette(file)
> 8bit PNG 画像の file を読み込み、
> [IndexedColors オブジェクト, palette] という配列を返す。
> palette は、パレットを表す Color の単なる配列である。
>
> Texture#render_indexed_colors(indices, palette)
> self にインデックスカラーの画像を描画する。
> 左上からピクセル列をそのまま流し込む形で描画することを想定しているので、
> 縦横の大きさが合わないと変になる。
>
> この案のいいところは以下の通りです:
>
> * 大規模なクラス追加がない
> * Texture クラスの既存のメソッドに影響を及ぼすことはない
> * 描画の際に新しい Texture オブジェクトを毎回生成する必要はなく、
> 中間バッファとしての Texture を使いまわせば効率的

IndexedColors オブジェクトとTextureの大きさが一致していないといけない、というのがちょっと引っかかります。様々な大きさの
IndexedColors オブジェクトを扱いたい場合、同じように様々な大きさの中間バッファを使わねばなりません。その場合、実行効率・プログラ
ミング効率に影響を与えないとも限らないと思います。

気になったのはそこだけです。

Hajime Hoshi

unread,
Jul 6, 2008, 1:24:26 PM7/6/08
to star...@googlegroups.com
星です。

ご意見ありがとうございます。

>> class IndexedColors
>> インデックスカラーの画像を表すクラス。
>> 内部的にはインデックス列、幅、高さ、カラーキー (インデックス) を保持する。
>> パレットは保持しない (あえて分けた方がわかりやすいかなあと思いました)。
>
> パレットをインスタンス内に保持するか否かはどっちもどっちかなあ、といった感想です。
> パレットとインデクス列がくっついているほうが都合がいいとプログラマが思えば、そのように管理する仕組みをプログラマ自身が作れるでしょうし、そうい
> う意味では離れていたほうがいいのかもしれないと、個人的には思います。

ほとんど変化のない「ピクセル列」の情報と、
頻繁に変わりえる「パレット」の情報は分けたほうが良いかと思いました。

(前の議論で IndexedColors (EightbitTexture) は Immutable であるべきという
僕の主張がありましたが、内部 Texture を持たなければ別にその必要はないかなと思いました。)

>> IndexedColors.load_with_palette(file)
>> 8bit PNG 画像の file を読み込み、
>> [IndexedColors オブジェクト, palette] という配列を返す。
>> palette は、パレットを表す Color の単なる配列である。
>>
>> Texture#render_indexed_colors(indices, palette)
>> self にインデックスカラーの画像を描画する。
>> 左上からピクセル列をそのまま流し込む形で描画することを想定しているので、
>> 縦横の大きさが合わないと変になる。
>>
>> この案のいいところは以下の通りです:
>>
>> * 大規模なクラス追加がない
>> * Texture クラスの既存のメソッドに影響を及ぼすことはない
>> * 描画の際に新しい Texture オブジェクトを毎回生成する必要はなく、
>> 中間バッファとしての Texture を使いまわせば効率的
>
> IndexedColors オブジェクトとTextureの大きさが一致していないといけない、というのがちょっと引っかかります。様々な大きさの
> IndexedColors オブジェクトを扱いたい場合、同じように様々な大きさの中間バッファを使わねばなりません。その場合、実行効率・プログラ
> ミング効率に影響を与えないとも限らないと思います。
>
> 気になったのはそこだけです。

まず既存の Texture に IndexedColors (名前は仮ですが) を描画させる方法として

1. Texture の既存の描画メソッドが IndexedColors を受け付ける
1.1. IndexedColors のピクセル列をそのまま認識できるよう改造する
1.2. IndexedColors が内部 Texture を持ち、それを使う ([starruby:130])
2. Texture が IndexColors を描画できる専用メソッドを作る ([starruby:161])

という案があります。

1.1. は提案すらされていませんが、改造コストが高すぎるのでだめです。
ということで今のところ 1.2. か 2. かのどちらかになります。
1.2. の場合、パレットがちょっとでも変わるたびに内部テクスチャの変化が行われるため、
(内部テクスチャが一個の場合は) 速度面で不利になると思われます。
2. の場合、パレットが変わる分 Texture オブジェクトを用意してもよいし、
メモリの効率のために 1 つの Texture を使いまわすこともできます。
つまり、速度面が最悪のケースでも 1.2. と同様です。

プログラミング効率は落ちるというか、
内部テクスチャに比べて余計な手間が確実に増えますね。

と書きながら思いついたのですが、
1.2. の案で内部テクスチャを複数個持つこともできます。
* パレットはせいぜい n 種類であろうと想定して、内部テクスチャを n 個もつ
(一色でも変わると違うパレットとみなさなければならないので、実用的でないかも?)
* パレットに関係なく n 個の内部 Texture を持ち、なんらかの方法 (FIFO など) で管理する

もう少し検討してみます。

--
Hajime Hoshi <hajim...@gmail.com>

Hajime Hoshi

unread,
Jul 7, 2008, 5:37:35 PM7/7/08
to star...@googlegroups.com
星です。

> 1. Texture の既存の描画メソッドが IndexedColors を受け付ける
> 1.1. IndexedColors のピクセル列をそのまま認識できるよう改造する
> 1.2. IndexedColors が内部 Texture を持ち、それを使う ([starruby:130])
> 2. Texture が IndexColors を描画できる専用メソッドを作る ([starruby:161])
>

> (中略)


>
> 1.2. の場合、パレットがちょっとでも変わるたびに内部テクスチャの変化が行われるため、
> (内部テクスチャが一個の場合は) 速度面で不利になると思われます。
> 2. の場合、パレットが変わる分 Texture オブジェクトを用意してもよいし、
> メモリの効率のために 1 つの Texture を使いまわすこともできます。
> つまり、速度面が最悪のケースでも 1.2. と同様です。

と述べましたが、 1.2. で速度が気になるならばその分 IndexedColors を複製すればよい
だけの話であることに気づきました。
1.2. と 2. は「内部テクスチャ」が内部か表に出ているかの違いだけになります。
すると、 Star Ruby 利用者にとって使いやすい API であることを最重要視して
比較するのがよさそうに思いました。

ところで、 1.2. を発展させて、新しいクラス追加が一切ない簡単な案を思いつきました。

* Texture.load(path)

基本的に変化なし。
8bit 画像をロードしたときは、内部にインデックス列とパレットも保持する。

パレットとピクセル列 (Texture オブジェクトが元々持っているもの) とは
自動的に同期を取る。
パレットを変化させると、ピクセル列もそれに伴い変化する。
逆に、ピクセル列を直接変更すると、その瞬間にパレットおよびインデックス列は消滅する
(今までの普通の 32bit テクスチャになる)。

* Texture#palette

パレット (Color の frozen な配列) を取得する。
frozen なので、要素を変化させることはできない。

例)
texture.palette[i] = Color.new(0, 0, 0) # TypeError になる

なぜ frozen なのかというと、パレットと実際のテクスチャのピクセルとの同期をとる必要があり、
パレットが変化したらピクセル列の取得時にはピクセル列が変化してなくてはならず、
その同期を取るのが大変だからである。

(パレットを配列ではなく専用のクラスにし、ギリギリまでピクセル列の変化を遅延するなどすれば
Texture#palette を frozen にせずともピクセル列と同期をとることは可能です。
ちなみに、ピクセル列変化を遅延しないで、パレット一色変わるたびに
ピクセル列を変えてしまうと、速度的に使い物にならなくなると思います。
ただ、実装にかかるコストの割にはそんなにうれしい事はないかなあと思い、今回は見送りました。
パレットを変化させる場合は、僕の感覚では大抵がらっと変わるものだと思うからです。
実際そうじゃないかもしれませんが、そのときはそのときで考えます。)

パレットおよびインデックス列がない場合は nil を返す。

* Texture#palette=(palette)

パレット (Color の配列) を設定する。
設定した瞬間に、ピクセル列もそれにあわせて変化する。
引数 (palette) は複製され (dup) 凍結される (freeze)。
そのため、代入後に plaette 引数の値を変化させても、テクスチャには影響はない。

例)
texture.palette = palette # texture に設定されるパレットと palette は別物になる
palette[0] = Color.new(0, 0, 0) # texture に何の影響もない

Texture#palette が nil の場合に Texture#palette= を呼ぶとエラーになる。


議論にかなり時間を食ってしまいました。
とりあえずこれで実装しようと思います。

--
Hajime Hoshi <hajim...@gmail.com>

hajimehoshi

unread,
Jul 10, 2008, 3:31:29 PM7/10/08
to Star Ruby
星です。

また前回のメールから微妙に変更を行いました。

* Texture.load(path, options = {})
options のキーと値は以下の通り:
:palette
真値で、かつパレットが取得できる場合にパレットの情報を持つ。デフォルトは false。
オプションで指定しない限りは、パレットを持つ画像でも単なるフルカラー画像として扱われます。

* Texture#palette
パレットを表す Color の frozen な配列を取得する。
前回のメールからは変わらず。

* Texture#palette= はなくなりました。

* Texture#change_palette(palette) / Texture#change_palette!(palette)
パレットを変更し、ピクセルに反映させます。
! がつく方はパレットおよびテクスチャを破壊的に変更します。
palette は Color の配列を指定します。

その他、パレットを持つ画像に対して直接ピクセルを変更するようなメソッドを実行しようとした場合に、
例外が投げられるように変更しました。

現在 trunk にサンプルとともにあがっています。確かめてみたい方はどうぞ。
Reply all
Reply to author
Forward
0 new messages