1: 2004-01-22 (木) 23:28:42 |
現: 2024-01-08 (月) 12:59:00 ゲスト |
| [[introx]] | | [[introx]] |
| | | |
| + | |
| "mt_xor1.c"の解説 | | "mt_xor1.c"の解説 |
| 2004/01/22 | | 2004/01/22 |
- | ベイサイド(bayside_yokohama@yahoo.co.jp) | + | ベイサイド |
| + | |
| このドキュメントは、"mt_xor1.c"の説明だけをするものです。最初に読むべきドキュ | | このドキュメントは、"mt_xor1.c"の説明だけをするものです。最初に読むべきドキュ |
| メントではありません。最初に読むべきドキュメントは"document.txt"です。"mt_xor0 | | メントではありません。最初に読むべきドキュメントは"document.txt"です。"mt_xor0 |
| .c"との違いは32ビットグラフィックボックスを使うことです。 | | .c"との違いは32ビットグラフィックボックスを使うことです。 |
- | | + | |
| + | |
| 1.アルゴリズム | | 1.アルゴリズム |
| + | |
| 今まで説明してきた描画方法は点を打つとか線を引くというものでした。しかし実際 | | 今まで説明してきた描画方法は点を打つとか線を引くというものでした。しかし実際 |
| のプログラムでは、もっと込み入ったことがやりたいというのはよくあることです。そ | | のプログラムでは、もっと込み入ったことがやりたいというのはよくあることです。そ |
| の場合、あたかもビデオメモリにアクセスするように自由に読み書きできれば、なにか | | の場合、あたかもビデオメモリにアクセスするように自由に読み書きできれば、なにか |
| と便利でしょう。・・・ここでは、そういうアクセス方法を説明します。 | | と便利でしょう。・・・ここでは、そういうアクセス方法を説明します。 |
| + | |
| このアクセス方法は2つの手順で構成されます。まず、指定されたバッファ内に自由に | | このアクセス方法は2つの手順で構成されます。まず、指定されたバッファ内に自由に |
- | 読み書きします。このバッファはグラフィックボックスに対応しており、1バイトが1ド | + | 読み書きします。このバッファはグラフィックボックスに対応しており、4バイトが1ド |
| ットになっています(パックドピクセル)。そして一通りのアクセスが済んだらいじった | | ットになっています(パックドピクセル)。そして一通りのアクセスが済んだらいじった |
| 部分をflushします。flushというのは、メモリ内のバッファの内容を画面に確実に反映 | | 部分をflushします。flushというのは、メモリ内のバッファの内容を画面に確実に反映 |
| できません。いじったら必ずflushしてください(リードアクセスしかしていないときは | | できません。いじったら必ずflushしてください(リードアクセスしかしていないときは |
| flushしなくてもよい)。 | | flushしなくてもよい)。 |
| + | |
| グラフィックボックスのバッファ構造は、(int *) gbox + 16から後ろのxsize * ysi | | グラフィックボックスのバッファ構造は、(int *) gbox + 16から後ろのxsize * ysi |
| ze * 4がそっくりそのままバッファになっています。単純明快です。詳しいことはソー | | ze * 4がそっくりそのままバッファになっています。単純明快です。詳しいことはソー |
| スをご覧ください。 | | スをご覧ください。 |
| + | |
| このプログラムはその方法でたくさんの点を描画して、ちょっとした「山」を描きま | | このプログラムはその方法でたくさんの点を描画して、ちょっとした「山」を描きま |
| す。 | | す。 |
- | | + | |
| + | |
| 2.ライブラリ関数の説明 | | 2.ライブラリ関数の説明 |
| + | |
| 引数の型については、guigui00.hを参照してください。 | | 引数の型については、guigui00.hを参照してください。 |
| + | |
| lib_flushgraphbox(opt, win, x, y, sx, sy, skip, p) : | | lib_flushgraphbox(opt, win, x, y, sx, sy, skip, p) : |
| + | |
| グラフィックボックスをflushします。optは0x8024にしてください。winはグラフィッ | | グラフィックボックスをflushします。optは0x8024にしてください。winはグラフィッ |
| クボックスが所属するウィンドウです。残りのパラメーターが少々ややこしいです。ま | | クボックスが所属するウィンドウです。残りのパラメーターが少々ややこしいです。ま |
| ずグラフィックボックス全体をflushするなら、 | | ずグラフィックボックス全体をflushするなら、 |
| + | |
| x, y : グラフィックボックスオープン時に指定したx_pos, y_posの値 | | x, y : グラフィックボックスオープン時に指定したx_pos, y_posの値 |
| sx, sy : グラフィックボックスオープン時に指定したx_size, y_sizeの値 | | sx, sy : グラフィックボックスオープン時に指定したx_size, y_sizeの値 |
| skip : 必ず0 | | skip : 必ず0 |
| p : (int *) gbox + 16 | | p : (int *) gbox + 16 |
| + | |
| という風に指定します。しかしいじった範囲がグラフィックボックスのごく一部である | | という風に指定します。しかしいじった範囲がグラフィックボックスのごく一部である |
| という場合もよくあるでしょう。そんなときこのような全範囲flushをすると処理時間に | | という場合もよくあるでしょう。そんなときこのような全範囲flushをすると処理時間に |
| おいてかなりの無駄になります。そんな時は部分flushを使います。 | | おいてかなりの無駄になります。そんな時は部分flushを使います。 |
| + | |
| x, y : 部分flushしたい範囲の左上の座標(window内の座標系で指定・・・gboxの | | x, y : 部分flushしたい範囲の左上の座標(window内の座標系で指定・・・gboxの |
| 座標ではない) | | 座標ではない) |
| skip : (グラフィックボックスオープン時に指定したx_size - この時のsx) * 4 | | skip : (グラフィックボックスオープン時に指定したx_size - この時のsx) * 4 |
| p : x, yで指定した座標に相当するドットを指し示すintポインタ | | p : x, yで指定した座標に相当するドットを指し示すintポインタ |
| + | |
| これをよくご覧になれば分かるように、結局は全範囲flushも部分flushも同じルールで | | これをよくご覧になれば分かるように、結局は全範囲flushも部分flushも同じルールで |
| す。 | | す。 |
| + | |
| もしたとえば画面内でキャラクターが走っているとすれば、まずはバッファにアクセ | | もしたとえば画面内でキャラクターが走っているとすれば、まずはバッファにアクセ |
| スして、元いた場所を背景に戻して移動先にキャラクターを書き込むでしょう。そして | | スして、元いた場所を背景に戻して移動先にキャラクターを書き込むでしょう。そして |
| 。できるだけ狭い範囲に分解してやりましょう。・・・この時以下の2つの方法のどちら | | 。できるだけ狭い範囲に分解してやりましょう。・・・この時以下の2つの方法のどちら |
| がいいかと迷われるかもしれません。 | | がいいかと迷われるかもしれません。 |
| + | |
| 1.移動元書き換え → 移動元flush → 移動先書き換え → 移動先flush | | 1.移動元書き換え → 移動元flush → 移動先書き換え → 移動先flush |
| 2.移動元書き換え → 移動先書き換え → 移動元flush → 移動先flush | | 2.移動元書き換え → 移動先書き換え → 移動元flush → 移動先flush |
| + | |
| もちろんどちらの手順でも問題なく実行できますが、どちらかといえば2.の方がおす | | もちろんどちらの手順でも問題なく実行できますが、どちらかといえば2.の方がおす |
| すめです。というのは、結局画面に反映されるのはflushの時なので、2.の方法の方が | | すめです。というのは、結局画面に反映されるのはflushの時なので、2.の方法の方が |
| ターが介在しているのなら、まずはバッファ内の書き換えを集中させ、その後にflushを | | ターが介在しているのなら、まずはバッファ内の書き換えを集中させ、その後にflushを |
| 集中的にやる方が良いでしょう。 | | 集中的にやる方が良いでしょう。 |
| + | |
| 3.改造への指針 | | 3.改造への指針 |
| + | |
| このバッファへのアクセスとflushを使えば、かなり自由にグラフィック処理ができる | | このバッファへのアクセスとflushを使えば、かなり自由にグラフィック処理ができる |
| はずです。しかしflushの際にはVRAMへアクセスすることになり、これは結構重たい処理 | | はずです。しかしflushの際にはVRAMへアクセスすることになり、これは結構重たい処理 |
| るようになるまではちょっと無理かもしれません。・・・それでもマシンパワーのある | | るようになるまではちょっと無理かもしれません。・・・それでもマシンパワーのある |
| マシンなら、なんとかゲームにはなるかもしれません。 | | マシンなら、なんとかゲームにはなるかもしれません。 |
| + | |
| + | // "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 |
| + | -たぶん僕の言う「そのうち」はなかなかこないので、上記をコピーして自分のソースに貼り付けてもいいです。 |
| + | |
| + | *** 修正した説明(案) |
| + | -説明がt_xor0と重複しすぎていて、読み手が飛ばし読みをする恐れがあったので、違いのみをピックアップして書き直しました。 |
| + | |
| + | |
| + | "mt_xor1.c"の解説 |
| + | 2004/01/24 |
| + | 川合秀実(kawai@osask.jp) |
| + | |
| + | このドキュメントは、"mt_xor1.c"の説明だけをするものです。最初に読むべきドキュ |
| + | メントではありません。最初に読むべきドキュメントは"document.txt"です。 |
| + | |
| + | |
| + | 1.アルゴリズム |
| + | |
| + | このmt_xor1は、mt_xor0の改造版に相当します。違いは8ビットグラフィックボックス |
| + | ではなく32ビットグラフィックボックスを使うことです。mt_xor0を理解してから読んで |
| + | ください。 |
| + | |
| + | グラフィックボックスのバッファ構造は、LIB_GBOX_BUF32(gbox)から後ろのxsize * |
| + | ysize * 4がそっくりそのままバッファになっています。詳しいことはソースをご覧く |
| + | ださい。1ドットが4バイトで構成され、 |
| + | bit 0- 7:青成分(0-255) |
| + | bit 8-15:緑成分(0-255) |
| + | bit16-23:赤成分(0-255) |
| + | bit24-31:リザーブで必ず0 |
| + | となっています。8bitグラフィックボックスと同様に、自由に読み書きして、必要に応 |
| + | じてflushしてください。 |
| + | |
| + | |
| + | 2.ライブラリ関数の説明 |
| + | |
| + | 引数の型については、guigui00.hを参照してください。 |
| + | |
| + | lib_flushgraphbox(opt, win, x, y, sx, sy, skip, p) : |
| + | |
| + | グラフィックボックスをflushします。optは0x8004か0x8024にしてください。winは |
| + | グラフィックボックスが所属するウィンドウです。残りのパラメーターが少々ややこし |
| + | いです。まずグラフィックボックス全体をflushするなら、 |
| + | |
| + | x, y : グラフィックボックスオープン時に指定したx_pos, y_posの値 |
| + | sx, sy : グラフィックボックスオープン時に指定したx_size, y_sizeの値 |
| + | skip : 必ず0 |
| + | p : LIB_GBOX_BUF32(gox) |
| + | |
| + | という風に指定します。 |
| + | |
| + | 32ビットグラフィックボックスで部分フラッシュをすることもできます。その場合は |
| + | 次のように引数を指定します。 |
| + | |
| + | x, y : 部分flushしたい範囲の左上の座標(window内の座標系で指定・・・gboxの |
| + | 座標ではない) |
| + | sx, sy : 部分flushしたい範囲のサイズ |
| + | skip : (グラフィックボックスオープン時に指定したx_size - この時のsx) * 4 |
| + | p : x, yで指定した座標に相当するドットを指し示すポインタ |
| + | |
| + | optの違いについてですが、通常は0x8004を使います。色表現力が犠牲になってもいい |
| + | から、速度を速くしてほしいという場合に限って(もしくはすべての画面モードで細い |
| + | 線がタイリングで点線に化けたりするのが不都合な場合)、0x8024を指定します。 |
| + | |
| + | |
| + | 3.改造への指針 |
| + | |
| + | これをつかえば8ビットグラフィックボックスでは得られなかった高い表現力が得られ |
| + | るでしょう。今のところ(完成度が低いせいで)32ビットグラフィックボックス内でラ |
| + | インを引くなどができませんが、それでもバッファに書いてflushすれば、一応どんな絵 |
| + | でもかけます。ラインなどの基本描画機能のサポートはもうしばらくお待ちください。 |
| + | |
| + | -[[K]]の視点で改良したソース。 |
| + | |
| + | // "mt_xor1.c" |
| + | // stack:4k malloc:20k |
| + | // copyright(C) 2004 Hidemi KAWAI |
| + | |
| + | #include <guigui00.h> |
| + | |
| + | #define AUTO_MALLOC 0 |
| + | |
| + | /* ちょっとしたマクロ */ |
| + | #define pixel(x, y) *(p + (y) * 100 + (x)) |
| + | #if (!defined(LIB_GBOX_BUF)) |
| + | #define LIB_GBOX_BUF(gbox) ((void *) ((char *) (gbox) + 64)) |
| + | #define LIB_GBOX_BUF32(gbox) ((unsigned int *) LIB_GBOX_BUF(gbox)) |
| + | #endif |
| + | |
| + | void OsaskMain() |
| + | { |
| + | struct LIB_WINDOW *window; |
| + | struct LIB_TEXTBOX *wintitle; |
| + | struct LIB_GRAPHBOX *graphicbox; |
| + | int i, j; |
| + | int *p; |
| + | static colortable[8] = { |
| + | 0x000000, 0x840000, 0x008400, 0x848400, 0x000084, 0x840084, 0x008484, 0x848484 |
| + | }; |
| + | |
| + | 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.Xor1"); |
| + | |
| + | /* グラフィックボックスをウィンドウに用意する */ |
| + | graphicbox = lib_opengraphbox(1, AUTO_MALLOC, 4, 0xc6c6c6, 100, 48, 18, 0, window); |
| + | /* パラメーターの意味は以下の通り: |
| + | opt : 1(固定) |
| + | mode : 4(固定) |
| + | mode_opt : 初期の背景色(バッファはこの値で初期化される) |
| + | x_size : グラフィックボックスの大きさ(ドット単位) |
| + | y_size : グラフィックボックスの大きさ(ドット単位) |
| + | x_pos : グラフィックボックスの位置(ドット単位) |
| + | y_pos : グラフィックボックスの位置(ドット単位) |
| + | */ |
| + | |
| + | p = LIB_GBOX_BUF32(graphicbox); |
| + | |
| + | /* 頂点に一つ点を打つ */ |
| + | pixel(49, 0) = 0x000000; /* 黒い点 */ |
| + | |
| + | /* ちょっとした演算 */ |
| + | for (j = 0; j < 47; j++) { |
| + | for (i = 1; i < 99; i++) |
| + | pixel(i, j + 1) = pixel(i - 1, j) ^ pixel(i + 1, j) ^ 0xc6c6c6; |
| + | } |
| + | |
| + | j = 0; |
| + | for (;;) { |
| + | /* バッファの内容を確実に画面に反映させる */ |
| + | lib_flushgraphbox(0x8004, window, 18, 0, 100, 48, 0, p); |
| + | /* パラメーターの意味は以下の通り: |
| + | opt : 0x8004 or 0x8024(固定) |
| + | win : グラフィックボックスが所属するウィンドウ |
| + | x : グラフィックボックスのx_pos |
| + | y : グラフィックボックスのy_pos |
| + | sx : グラフィックボックスのx_size |
| + | sy : グラフィックボックスのy_size |
| + | skip : 0(固定) |
| + | p : LIB_GBOX_BUF32(graphbox) |
| + | なお、上記の例はグラフィックボックス全体をflushしている |
| + | */ |
| + | |
| + | lib_waitsignaltime(0x0007, 0, 0, 0x80000000, 0, 0); /* 500msec.-wait */ |
| + | |
| + | /* 色変更 */ |
| + | j = (j + 1) & 7; |
| + | for (i = 0; i < 48 * 100; i++) { |
| + | if (p[i] != 0xc6c6c6) |
| + | p[i] = colortable[j]; |
| + | } |
| + | } |
| + | } |