ページへ戻る

− Links

 印刷 

introx​/mt_xor1.c のバックアップソース(No.2) :: OSASK計画

osaskwiki:introx/mt_xor1.c のバックアップソース(No.2)

« Prev[4]  Next »[5]
[[introx]]


           "mt_xor1.c"の解説
                                                                 2004/01/22
                                       ベイサイド(bayside_yokohama@yahoo.co.jp)

   このドキュメントは、"mt_xor1.c"の説明だけをするものです。最初に読むべきドキュ
 メントではありません。最初に読むべきドキュメントは"document.txt"です。"mt_xor0
 .c"との違いは32ビットグラフィックボックスを使うことです。


 1.アルゴリズム

   今まで説明してきた描画方法は点を打つとか線を引くというものでした。しかし実際
 のプログラムでは、もっと込み入ったことがやりたいというのはよくあることです。そ
 の場合、あたかもビデオメモリにアクセスするように自由に読み書きできれば、なにか
 と便利でしょう。・・・ここでは、そういうアクセス方法を説明します。

   このアクセス方法は2つの手順で構成されます。まず、指定されたバッファ内に自由に
 読み書きします。このバッファはグラフィックボックスに対応しており、4バイトが1ド
 ットになっています(パックドピクセル)。そして一通りのアクセスが済んだらいじった
 部分をflushします。flushというのは、メモリ内のバッファの内容を画面に確実に反映
 させる方法だと理解してください。この操作をしなくてもOS側の都合でバッファの内容
 が画面に反映されることはありますが、それは保証されていないことですのであてには
 できません。いじったら必ずflushしてください(リードアクセスしかしていないときは
 flushしなくてもよい)。

   グラフィックボックスのバッファ構造は、(int *) gbox + 16から後ろのxsize * ysi
 ze * 4がそっくりそのままバッファになっています。単純明快です。詳しいことはソー
 スをご覧ください。

   このプログラムはその方法でたくさんの点を描画して、ちょっとした「山」を描きま
 す。


 2.ライブラリ関数の説明

   引数の型については、guigui00.hを参照してください。

   lib_flushgraphbox(opt, win, x, y, sx, sy, skip, p) :

   グラフィックボックスをflushします。optは0x8024にしてください。winはグラフィッ
 クボックスが所属するウィンドウです。残りのパラメーターが少々ややこしいです。ま
 ずグラフィックボックス全体をflushするなら、

     x, y   : グラフィックボックスオープン時に指定したx_pos, y_posの値
     sx, sy : グラフィックボックスオープン時に指定したx_size, y_sizeの値
     skip   : 必ず0
     p      : (int *) gbox + 16

 という風に指定します。しかしいじった範囲がグラフィックボックスのごく一部である
 という場合もよくあるでしょう。そんなときこのような全範囲flushをすると処理時間に
 おいてかなりの無駄になります。そんな時は部分flushを使います。

     x, y   : 部分flushしたい範囲の左上の座標(window内の座標系で指定・・・gboxの
              座標ではない)
     sx, sy : 部分flushしたい範囲のサイズ
     skip   : (グラフィックボックスオープン時に指定したx_size - この時のsx) * 4
     p      : x, yで指定した座標に相当するドットを指し示すintポインタ

 これをよくご覧になれば分かるように、結局は全範囲flushも部分flushも同じルールで
 す。

   もしたとえば画面内でキャラクターが走っているとすれば、まずはバッファにアクセ
 スして、元いた場所を背景に戻して移動先にキャラクターを書き込むでしょう。そして
 flushすることになります。この場合、移動距離がある程度あれば、flushは2回やるべき
 です。つまり移動元の部分と移動先の部分です。移動元と移動先を含むような広範囲のf
 lushを1回やることでももちろん代用できますが、flushはOSにとって高負荷な処理です
 。できるだけ狭い範囲に分解してやりましょう。・・・この時以下の2つの方法のどちら
 がいいかと迷われるかもしれません。

     1.移動元書き換え → 移動元flush → 移動先書き換え → 移動先flush
     2.移動元書き換え → 移動先書き換え → 移動元flush → 移動先flush

 もちろんどちらの手順でも問題なく実行できますが、どちらかといえば2.の方がおす
 すめです。というのは、結局画面に反映されるのはflushの時なので、2.の方法の方が
 キャラクターが画面上から消えている時間が短くて済むせいです。もし複数のキャラク
 ターが介在しているのなら、まずはバッファ内の書き換えを集中させ、その後にflushを
 集中的にやる方が良いでしょう。

 3.改造への指針

   このバッファへのアクセスとflushを使えば、かなり自由にグラフィック処理ができる
 はずです。しかしflushの際にはVRAMへアクセスすることになり、これは結構重たい処理
 です。広い範囲を細かい時間間隔でflushするのは今のところやらない方がいいでしょう
 。そういう見栄えのするゲームは、OSASKがグラフィックアクセラレーターを使いこなせ
 るようになるまではちょっと無理かもしれません。・・・それでもマシンパワーのある
 マシンなら、なんとかゲームにはなるかもしれません。

 // "mt_xor1.c"
 //  stack:4k malloc:6k
 //  copyright(C) 2004 ベイサイド

 #include <guigui00.h>

 #define  AUTO_MALLOC  0

 /* ちょっとしたマクロ */
 #define  pixel(x, y)  *(p + (y) * 100 + (x))

 /* 基本的なアルゴリズム */
 /* 1.グラフィックボックスをオープンする */
 /* 2.(int *) graphicbox + 16以降のバイトは、x_size * y_size * 4のcharのバッファになっているので
   そこを好きなようにいじる(リードしてもライトしてもいい) */
 /* 3.いじり終ったら、バッファをflushしなければいけない。この時点で画面に反映される */

 void OsaskMain()
 {
   struct LIB_WINDOW *window;
   struct LIB_TEXTBOX *wintitle;
   struct LIB_GRAPHBOX *graphicbox;
   int i, j;
   int *p;

   lib_init(AUTO_MALLOC);
   window = lib_openwindow(AUTO_MALLOC, 0x0200, 136, 48);
   wintitle = lib_opentextbox(0x1000, AUTO_MALLOC, 0,  7, 1,  0,  0, window, 0x00c0, 0);
   lib_putstring_ASCII(0x0000, 0, 0, wintitle, 0, 0, "Mt.Xor0");

   /* グラフィックボックスをウィンドウに用意する */
   graphicbox = lib_opengraphbox(1, AUTO_MALLOC, 4, 8, 100, 48, 18, 0, window);
   /* パラメーターの意味は以下の通り:
     opt      : 1(固定)
     mode     : 4(固定)
     mode_opt : 初期の背景色(バッファはこのバイトで初期化される)
     x_size   : グラフィックボックスの大きさ(ドット単位)
     y_size   : グラフィックボックスの大きさ(ドット単位)
     x_pos    : グラフィックボックスの位置(ドット単位)
     y_pos    : グラフィックボックスの位置(ドット単位)
   */

   p = (int *) graphicbox + 16;

   /* 頂点に一つ点を打つ */
   pixel(49, 0) = 0; /* 黒い点 */

   /* ちょっとした演算 */
   for (j = 0; j < 47; j++) {
     for (i = 1; i < 99; i++)
       pixel(i, j + 1) = ((pixel(i - 1, j) == 0) ^ (pixel(i + 1, j) == 0)) ? 0 : 0xC6C6C6;
   }

   j = 0;
   for (;;) {

     /* バッファの内容を確実に画面に反映させる */
     lib_flushgraphbox(0x8024, window, 18, 0, 100, 48, 0, p);
     /* パラメーターの意味は以下の通り:
       opt  : 0x8001(固定)
       win  : グラフィックボックスが所属するウィンドウ
       x    : グラフィックボックスのx_pos
       y    : グラフィックボックスのy_pos
       sx   : グラフィックボックスのx_size
       sy   : グラフィックボックスのy_size
       skip : 0(固定)
       p    : (int *) graphbox + 16

       なお、上記の例はグラフィックボックス全体をflushしている
     */

     lib_waitsignaltime(0x0007, 0, 0, 0x80000000, 0, 0); /* 500msec.-wait */

     /* 色変更 */
     j = (j + 1) & 0x868686;
     for (i = 0; i < 48 * 100; i++) {
       if (p[i] != 0xC6C6C6)
         p[i] = j;
     }

   }
 }

*** [[K]]の落書き
-こんなのをそのうち<guigui00.h>に追加しようと思います。
 #if (!defined(LIB_GBOX_BUF))
     #define LIB_GBOX_BUF(gbox)   ((void *) ((char *) (gbox) + 64))
     #define LIB_GBOX_BUF8(gbox)  ((unsigned char *) LIB_GBOX_BUF(gbox))
     #define LIB_GBOX_BUF16(gbox) ((unsigned short *) LIB_GBOX_BUF(gbox))
     #define LIB_GBOX_BUF32(gbox)  ((unsigned int *) LIB_GBOX_BUF(gbox))
 #endif
-たぶん僕の言う「そのうち」はなかなかこないので、上記をコピーして自分のソースに貼り付けてもいいです。

« Prev[4]  Next »[5]