kowさんは天ざる大好き

創作に絶望すると、世界が反転した日記

SDL+OpneGLでWindowとFullscreenを切り替える

yaneSDK4Dで組んでいて、リアルタイムにWindowとフルスクリーンを切り替えられないのがつらないなあと思っていた。

やねうBBSのD言語スレのほうでも、解像度切り替えの問題は放置されたようでわたしも途方にくれていたのだ。
OpenGLは赤本を斜め読みしただけなので、あんまり詳しくわからないのだが、いろいろ試してはみてはいた。
問題点は、解像度を変更後、変更前のテクスチャが表示できなくなるのだ。


わたし、今年の3月26日の日記になんか、いろいろとやってある日記があった。
その時のアプローチは単純だ。


  1. 解像度を変更したら変更前のテクスチャはおかしい
  2. 解像度変更後、読み込んだ画像は正常に動作する
  3. OpenGLは詳しいところまでしらない
  4. 具現化されているすべてのリソースをすべて再読込しよう

これもまあ、大胆というか、ダーティというか...
まあ、なにはともあれ勢いである。
しかし、ダサイなぁ...(´ω`)

すべての画像の再読込は、DirectXでいえば、ロストしたサーフェイスの再構築作業と同じことで、こんなのちょちょっと組んでしまえばよい。
ここで、現存するすべてのテクスチャクラスの列挙でかなり填っている。


class Texture {
// コンストラクタで登録
this() {
vElement.puch_back(this);
}

// デストラクタで登録抹消
~this() {
vElement.erase(this);
}

static this() {
vElement = new vector!(Texture);
}

private:
static vector!(Texture) vElement; //!< すべてのテクスチャのコレクション
}

これデストラクタが呼ばれない!
vElementが自分自身の参照をずっともっているのでデストラクタが呼ばれない。
じゃあ、ポインタならといってがんばってやっているようですが、ダメです。
生のポインタは取れません。しかもCGの仕様では、ガベージコレクタが行われるとアドレスは変更されるかもしれない。

でちょっと思い立ってそのとき、やらなかった粗雑な方法で実装することにした。


// もともとの Texture -> TexutreRaw にクラス名変更
class TextureRaw : ICacheObject ,ITextureBase {
// 追加
void restore() {
// Textureのタイプにあったリストアコードを書く
}
(中略)
}


// Textureクラスをのっとってこそーり wrap してしまう!(`ω´)
class Texture : ICacheObject ,ITextureBase {
/// コンストラクタ
this() {
m_id = counter++;
textures[m_id] = new TextureRaw();
}

/// デストラクタ
~this() {
getMyTexture().release();
textures.remove(m_id);
}

/// 全テクスチャの復元
static void restoreAll() {
// あとあとのためにスレッドにしておいてみる
auto dg = delegate int()
{
foreach (inout TextureRaw t ; textures ) {
t.restore();
}
// どっかでやっといたほうがええんだけど...
// textures = textures.rehash;
return 0;
};

Thread thread = new Thread( dg );
thread.start();
thread.wait();
TextureRaw.createTextureAll();

}

/// 指定されたファイル名の画像を読み込む
/**
読み込みに失敗すれば非0が返る。
*/
y4d_result load(char[] filename)
{
return getMyTexture().load(filename);
}

(中略)

TextureRaw getMyTexture() {
return textures[m_id];
}


private:
static TextureRaw[ulong] textures;
static ulong counter;

final ulong m_id;
}

Textureクラスを丸ごとのっとって、内部に実Texutreクラスを隠蔽した。
このWrapのコンストラクタ/デストラクタで登録/抹消処理を行う。
で、リストアの要請があれば、全テクスチャの再読込を行う。
ulongのカウンタはテストコードなので。
実TexutreRawのリストアコードは画像ならファイルから読み込んだり、その他はSurfaceから復元してもいいかな?
このリストアを実行する前に、
Screen#disableBlend
をcallしておかないとアルファが無効の状態になる気がします。


WindowモードとFullscreenモードの切り替え時にこうした復元処理をする。
再読込は重たいので、無駄な復元が発生しないように、事前にstd.gc.fullCollectをcallしておく。


というような、画面切り替えでとりあえず、動いたので、このまま実装していっていいもんだろうか...
OpenGLの動きを知ってないところがすごく怖いので、もうちょっと調査してかんとあかんかも。


それよりも、重大な問題だ。
yaneSDK.netがかなり進んでいるようだ!
そろそろ、わたしもC#の準備体操せな! でも、来年まではD言語がんばりますYO!