処理 - みる会図書館


検索対象: 月刊 C MAGAZINE 1992年8月号
81件見つかりました。

1. 月刊 C MAGAZINE 1992年8月号

C MAGA 制御行 . # endif 改行 end if 行 # else 改行グループ opt else グループ : # elif 定数式改行グルー 宣言並び : 宣言 宣言並び宣言 文並び . 文 式文 . 式 opt 選択文 . 文並び文 if ( 式 ) 文 if ( 式 ) 文 switch ( 式 ) 繰返し文 while ( 式 ) do 文 while for ( 式 opt 分岐文 . goto 識別子 continue break return 式 opt プ 0 pt else 文 文 ( 式 ) 文 式 0 pt 2.4 外部定義 翻訳単位 . 外部宣言 翻訳単位 外部宣言 : 関数定義 宣言 関数定義 外部宣言 宣言子 式 opt) 宣言並び opt 文 複合文 宣言指定子列。 pt 3 前処理指令 前処理ファイル : グループ opt グループ : グループ構成要素 1 2 3 4 グループグループ構成要素 グループ構成要素 前処理字句列。 pt 改行 # if 定数式改行 if グループ : endif 行 制御行 if 節 グループ opt if グループ elif グループ列 opt else グループ opt # ifdef 識別子改行グループ opt elif グループ・ elif グループ列 elif グループ elif グループ elif グループ列 : # ifndef 識別子改行 グループ opt include 前処理字句列改行 define 識別子置換要素並び改行 define 識別子左括弧識別子並び opt ) 置換要素並び改行 undef 識別子改行 line 前処理字句列改行 error 前処理字句列。 pt 改行 pragma 前処理字句列。 pt 改行 改行 改行 前処理字句列前処理字句 前処理字句 前処理字句列 : 前処理字句列。 pt 置換要素並び . 直前に空白類のない左括弧文字 左括弧 ライプラリ 文字操作く ctype. h> VOid assert(int expression); NDEBUG 診断く assert. h> wchar_t Size t ptrdiff—t offsetof(type,member-dosignator) NULL 共通の定義く stddef. h> rrn ERANGE EDOM 工ラーく rno. h > 改行文字 int isupper(int c); int isspace(int c); int ispunct(int c); int isprint(int c); int islower(int c); int isgraph(int c); int isdigit(int c); int iscntrl( int c) : int isalpha(int c); int isalnum(int c); int tolower(int c); int isxdigit(int c); 5 6 7 8 int toupper(int c); 地域化ぐ oc 引 e. h> LC_ALL LC_COLLATE LC_CTYPE LC_MONETARY LC_NUMERIC LC_TIME NULL struct lconv char tsetlocale(int category, const char locale ) ; struct lconv *localeconv(void); 数学く math. h> HUGE_VAL double acos(double x); double asin(double x); double atan(double x); double atan2(doubIe y,double x); double cos(double x); double sin(double x); double tan(double x); double cosh(double x); double sinh(double x); double tanh(double x); double exp(double x); double frexp(double value,int texp); double ldexp(double x,int exp); double log(double x); double 10g10 ( double x); double modf(double value,double *iptr); double pow(double x,double y); double sqrt(double x); double ceil(double x); double fabs(double x); double floor(double x); double fmod(double x,double y); 非局所分岐 <setjmp. h> jmp—buf int setjmp(jmp—buf env); void longjmp(jmp-buf env,int val); シグナル操作く sign 引 . h > S1g_ato m ic_t N ews Square 145 SIGSEGV SIGINT SIGILL SIGFPE SIGABRT SIG 」 GN SIG_ERR SIG_DFL

2. 月刊 C MAGAZINE 1992年8月号

ダの フィンロ あつばれ ご意見番 「ロ要素へ」 んない。なお , これは実話て、すから , なぜ ちらが自然 ? 「女子」中学生なのかは深く考えてもしよう がない ところて、 , この問題を見て気になったの アガサ・クリスティの推理小説に「 0 時間 は解答て、はない。「 1 , 2 , 3 ・・・・・・ 9 , 0 」という へ」というのがある。タイトルだけて、は意味 数字の順序て、ある。普通のセンスをもって 不明だが , 要するに逆算タイマーの感覚て、 いれば , 「 0 , 1 , 2 ・・・・・・ 9 」となるような気が ある。通常 , 日時というのは , 文字どおり する。しかし , やはり考えてみると 0 から始 刻々と増加するものだし , 時間を計測する めるのは無理があるのだ。「一から始める」 ときには 0 からスタートして「はいそこまて、」 といういい回しがあるのて、わかるように『最 というまて、の長さを調べるのて、ある。この 初の数字は 1 』というイメージが強烈なのて、 小説を総論として考えてみれば , クリステ ある。 0 から始まっている , という感触はど ィの作品の中て、もとくに印象に残るわけて、 うも特殊らしい。というか , 0 という数字の もないのだが , ある時点を目標に減少して ノ 位置は , あまり直感的て、ないのかもしれな いくという違和感だけは印象に残っている。 こて、 0 という数は , 本来の い。想像だが , 6 月号の List 2 て、 , 頃には決着がついているかもしれない 0 という意味て、はなく , 10 という数の下の桁 fopen ("test. dat" を表現しているイメージとして理解されて if ()p ! = NULL) { の位置 いるのかもしれない / * 何か処理する * / ブッシュホンのキー配列を見ても , やは fclose(fp) ・ り 1 から始まって , 9 の次が * , そして 0 , # 某塾の電車広告に私立中学の入試問題が となっている ( Fig. 1 ) 。今や数少なくなった 掲示されていた。中学の入試問題といって と書いたら早速反論がきました。趣旨とし ダイアル式電話機も , 1 から 9 , 0 という順番 けっこう難しい問題もあ ては , 次のように書いたほうが自然て、はな もあなどれない て、番号がふられている。どうも通常の感覚 る。先日見たのは , どこの中学の問題か忘 いかというのて、ある。 れたが , 本にふってあるべージの数字に含 て、はこちらが自然なのだろう。これに比べ fopen ("test. dat" ると , キーボ、一ドのテンキーの配列は , 下 まれている 1 , 2 , 3 ・・・・・・ 9 , 0 の数を数えたら NULL) { if (fp から「 0 , 1 , 2 , 3 ・・・・・・ 7 , 8 , 9 」という順序に n 個て、した ( 本当は n 個て、はない , ちゃんと数 / * 工ラーの処理をする * / なっていて , 0 は 1 の近くにある。この配置 return ; / * 必要なら値を戻す * / 字が書いてあったのだが , これも忘れてし まったのだ ) 。さて , この本は何ページまて、 が電話と統一て、きなかった , というか , い / * または exit ( ) ; とする * / まだにて、きないことが実に驚異て、ある。仕 ありますか , という間題て、ある。 様が不統一になったまま広まってしまうこ つまり , もしこの本が 1 ページまて、の本な / * 何か処理する * / との恐ろしさを実感て、きる。 ら 1 , 2 ページなら 1 と 2 の 2 個て、 2 , 10 ページ fclose(fp) ・ 電話といえば , ISDN には掛けた人の電話 普通なら「どっちて、もいいじゃん」となる の本なら 1 ~ 9 まて、の 9 個と 10 ページには 1 , 0 番号を知るための機能が用意されているが , 「より自然なプログラミング」を主 の 2 個の数字があるのて、 11 , という意味て、あ のだが , この機能はオプション選択て、強制て、きない 張している立場としては , そうもいってら れない。『どちらが自然だ』とか , 『これは この間題自体は何て、もないのだが , 偶然 そうだ。通信の秘密云々のため , という理 由を聞いた記憶もあるが , 実際どうなのだ 違和感がある』 , というのは重要なポイント これを見ていた女子中学生の会話を横て、聞 ろう。しかし受信者には電話を受けるかど こて、はとりあえず問 いていると「最初と最後の数字を足して 2 て、 なのだ。難問だが , うか判断する自由があるし , そのための情 題提起にとどめておく。本誌が書店に並ぶ 割るのよねえ」とかいっていて , わけがわか 第 4 回 イラスト / 椙村嘉ー 0 ロロロロ目 9 碆 住 3 ”ー 4 152 C MAGAZINE 1992 8

3. 月刊 C MAGAZINE 1992年8月号

切り直さないといけません。 mask 自体は左 と右の mask のビットごとの and を取ったも のになります。 byte mask = maskL & maskR 書き込みが 1 バイトになる場合には , 保存 されたバイト数が 1 バイトて、済んて、いるとき と , 2 バイトにまたがっているときの 2 通り あります。さらにシフトの方向も考慮しな ければなりません。ところて、 , 書き込みバ イト数が 1 バイトて、保存バイト数が 2 バイト て、あるならば , 左シフトの場合しか原理的 にありえません。 1 プレーンのみの処理に注 目して , List 42 のようになります。 次は保存されたバイト数と書き込みバイ ト数が一致していないときて、す (Fig. 11 ) 。 つまり , 保存してあるイメージにシフト操 作を加えて書き込んて、いますが , 過不足な くイメージが保存されていた場合 , 右にシ フトすると保存してあるイメージの右端を 越えてはみだすビットがて、てきます。また , 左右に端数ビットがある場合 , 左シフトす Fig. 11 るとひとつ前のバイトに収まってしまうこ とがあります。当然 , 保存してあるイメー ジのバイト数て、処理が可能な場合もあるわ けて、す。 シフト数が 0 のときは当然何も必要がない のはあきらかだと思います。右シフトの場 合を考えてみます。左端は普通に書いてか まわないてしよう。それから間を描きます。 この長さは書き込みバイト数分書き込みま す。 問題は右端て、す。右シフトの場合は書き 込みバイト数が保存されたバイト数と同じ か 1 バイト多くなる場合が考えられます。バ イト数が同じ場合はすて、に書いたのて、 , 1 バ イト多い場合の動作を考えます。この場合 , 前のバイトから送られてきたものだけを , ただ画面と合成すればいいことはすぐわか ります。このとき , すて、に保存側のポイン タは更新済みなのて、 , 更新しないように気 をつけて List 43 のように書きます。左シフ トのときは右下から描くことにしたのて , 右端の処理を手直しします。左シフトの場 合は保存された右端の端数が左のバイトに 52 C MAGAZINE 1 2 8 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 17 : 18 : 20 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 左右のこほれは切り捨てる 1 : VOid far *farshift(int count, word length, void far *dst) int countr; byte cmp, tmp ; byte far *src = (byte far *)dst; if (count 〉の { 〃右シフト count & = 0X07 ; countr = 8 ー count; cmp ニ *src くく countr; *Src = *src 〉 > count; for ( int i = 1 ; i く length; i + + ) { SI'C 十十 ; t 叩 = *src くく countr; *src = cmp ー (*src 〉 > count) : cmp ま t 叩 ; } else ( / / 左シフト count ー —count ; count & = 0X07 ; countr = 8 ー count; for ( int i = 1 : i く length; i + + ) { *src = (*src くく count) ー (*(src + 1) > > countr) : src 十十・ *src = (*src くく count) : return dst; ティスティネー イメージの保存と描画時のずれ xdiff ション一書き込み時に必要なずれ ソース dx d iff diff diff おきます (List 44 ) 。 もうひとつのアプローチとして , ストア 時に全部左にシフトしてしまい リストア 時に全部右シフトするという方法も考えら れます (Fig. 12 ) 。これだとモデルとしては 単純になりますが , リストアの右シフト時 に元の保存情報をシフトて、きないのて、 , テ ンボラリが必要となります。 まず指定されたメモリ領域を左右にシフ トする関数を書きます。簡略化して , シフ ト数は 0 ー 7 に限定します。左右からこばれた 分は切り捨てられます。右シフトを正 , 左 シフトを負のシフト数として与えることに します (List 45 ) 。これを使って List 46 のよ うに定義しておきましよう。 保存するときには , 左シフトしかありえ

4. 月刊 C MAGAZINE 1992年8月号

gpp myuse. cc ー 0 -fundump-myhead. bin て、プレロードコンパイルて、きますが , ヘッ ダファイル myhead. h は毎回 include されま す。実はコンパイラドライバは -fundump-< dump File name> オプションカ財旨定される とコンパイルの対象となるソースから inclu de されるファイルはすべてマクロ定義だけ 処理されて実体は何も出力しないようにプ リプロセッサに指令します。 List 5 て、用いら れるマクロ MESOUT はちゃんと fprintf に展 開されるのて、 , ダンプコンパイルて、も正し くコンパイルて、きます。 この処理のために逆に制限がて、きます。 ダンプコンパイルを行う場合はすべてのヘ ッダはマクロ定義のみ処理されるのて、 , # in clude を複数記述してその間に #pragma du mp を挿入してのダンプコンパイルはて、きま せん。この制限を忘れると意味のないエラ ーを多数引き起こすことになるのて、十分に 注意してください アンダンプコンノヾイルについての注意点 をまとめておきます。 ・非常に巨大なファイルを生成します。デ イスクのフリーエリアに十分な注意をし ー G 十十 X68000 ダンプ原理 ダンプコンバイルの原理について簡単に 説明しておきます。 Fig. A は XC および GCC で作成した実行ファイルが実行されるとき のメモリのようすです。通常 m 訓 oc で確保 されるメモリ領域は , そのプログラムのス タックの先頭からメモリ番地の大きくなる 方向へ伸びていくように配置されます。 うしておくことで , m 訓 oc が最初に与えら れた 64K バイトのヒープを使い尽くすと , sb 「 k を呼び出してさらに上方にメモリを確 保してヒープを拡大することができます。 GCC, G 十十では , コンバイラの構文木 やコードはほとんどがこの m 訓 oc で確保 されたヒープ上にあります。 Fig. A からわ かるように , コンバイラの静的な (static と いう意味ではありません ) 変数 data 領域 , bss 領域の間にスタック空間が挟まっているの で , プログラムコードとヒープ領域の相対 番地は , スタックサイズによって変化しま す。 スタックサイズは , 最適化を行う場合に 多量にワークとして確保したい場合がある ので , いつも同じサイズだけ確保とはかぎ りません。ダンプコンバイルをしたい場合 は , コンバイラのワークすべてをファイル にするので , スタック領域が変数とヒープ の間に挟まるのは望ましくありません。 そこで gpp_ccl. x では Fig. B のようなメ モリ割り当てを行います。 gpp_ccl. x は別 のプログラムは起動しないので , Human68 k から起動された時点の全メモリを自分のワ ークとして使います。スタックはメモリの 最高番地から下方に伸びてゆき , ヒープは 128 C MAGAZINE 1992 8 下位からスタック下限まで上方に伸びてゆ きます。スタック消費は , ほとんど最適化 のためのワーク確保に消費されます。この とき , 毎回スタック下限を越えないことを コンバイラはチェックしますので , ヒープ とスタックが重なって暴走することは避け られます。 また , この書き出されたワークのかなり の部分はポインタ変数 , つまりアドレスを 表しています。 Human68k では , プログラ ムが起動されるアドレスは一定ではありま せんから常駐プログラムの解除や , そのほ かの原因でダンプしたときのアドレスと , 再 度このダンプをワークイメージとして展開 するときのアドレスが 1 バイトでもずれると 正しく動かなくなります。 これでは実用性がないので , この純粋な バイナリワークをプログラムがロードされ るアドレスをずらして 2 個生成してリローケ ート可能なバイナリデータを作成するユー ティリティが付録ディスクに収録してあり ます。 ダンプコンバイルは , ユーザがある程度 Human68k のメモリ管理や実行ファイル形 式についての理解を前提にしています。も ともと G 十十は「無保証」ですが , このダンプ コンバイルについては , さらに「無保証」 ( ! !) なのでディスクに収録されているソースプ ログラムやバッチファイルだけでは理解で きない人は使うことは避けてください。ま た , ダンプコンバイルは多量のディスク容 量を必要とします。 Fig. A S S S S S Fig. B S S S S S I/O,Vram,Tram iocs ROM S: スーノヾバイサ領域 割り込みべクタ Human68k 常駐 ( co g. sys 指定 ) command. X 常駐 (command. x 指定 ) 親プロセス text 空間 ( プログラム ) data ( 初期化変数 ) bss ( 非初期化変数 ) スタック ( 標準 64k バイト ) m 訓 oc 空間 次のプロセス用メモリ S: スーババイザ領域 割り込みべクタ Human68k 常駐 (config. sys 指定 ) command. X 常駐 (command. x 指定 ) 親プロセス text 空間 ( プログラム ) data ( 初期化変数 ) bss ( 非初期化変数 ) ma oc 空間 スタック I/O, Vram,Tram iocs ROM $OOFFFFFF $ 00C00000 ぐー ←ー ←ー メモリ上限 スタートアップ が SETBLOCK する上限 ( sb 「 k ) で上に伸ひる スタック top プログラム先頭 $ 00000000 $OOFFFFFF $ 00C00000 ( ーメモリ上限 ダンプする領域 《ープログラム先頭 $ 00000000

5. 月刊 C MAGAZINE 1992年8月号

C MAGA 文字集合中の任意の要素 二重引用苻” , 逆斜線 \ 又は改行文字を除く s 文字 : s 文字列 s 文字 s 文字 s 文字列 : L"s 文字列 opt" " s 文字列。 pt " 文字列リテラル : 1 .5 文字列リテラル 16 進拡張表記 16 進数字 \x 16 進数字 16 進拡張表記 : \ 8 進数字 8 進数字 8 進数字 \ 8 進数字 8 進数字 く = ソース く = 整数定数 10 進定数 8 進定数 16 進定数 10 進定数 非 0 数字 10 進定数 8 進定数 0 8 進定数 16 進定数 整数接尾語。 pt 整数接尾語。 pt 整数接尾語。 pt 数字 8 進数字 16 進定数 16 進数字 0X 16 進数字 0x 16 進数字 2 句構造文法 2.1 式 一次式 . 識別子 定数 文字列リテラル ( 式 ) 後置式 . 一次式 後置式 後置式 後置式 後置式 後置式 後置式 [ 式 ] ( 実引数式並び。 pt ) . 識別子 - > 識別子 十十 非 0 数字 : 1 2 3 8 進数字 : 0 1 2 16 進数字 : a b 次のいずれか 4 5 6 7 8 次のいずれか 3 4 5 6 7 次のいずれか 9 6 拡張表記 1 .6 演算子 演算子 . 次のいずれか , 代入式 2 3 C D 4 5 f e E F 7 8 9 実引数式並び : 代入式 実引数式並び 単項式 . 後置式 + + 単項式 単項式 整数接尾語 : 符号無し接尾語 長語接尾語 0 pt 長語接尾語符号無し接尾語。 pt 符号無し接尾語 : 次のいずれか 長語接尾語 : 次のいすれか 列挙定数 識別子 文字定数 ' c 文字列 ' L ' c 文字列 ' c 文字列 . c 文字 c 文字列 c 文字 c 文字 . \ 8 進数字 8 進拡張表記 . \a \b \f \n \r \t \v 単純拡張表記 : 次のいすれか 16 進拡張表記 8 進拡張表記 単純拡張表記 拡張表記 . 拡張表記 文字集合中の任意の要素 単一引用符 ' , 逆斜線 \ 又は改行文字を除くソス くく 区切り子 : 次のいずオ功、 1.7 区切り子 1.9 前処理数 q 文字 . q 文字列 q 文字 q 文字 q 文字列 : h 文字 : h 文字列 h 文字 h 文字 h 文字列 " q 文字 く h 文字列 > ヘッタ名 sizeof くく = 単項演算子キャスト式 sizeof 単項式 sizeof ( 型名 ) 単項演算子 : 次のいずれか キャスト式 単項式 ( 型名 ) キャスト式 十 乗除式 : キャスト式 乗除式本 乗除式 / 改行文字と > を除くソース文字集合中の任意の要素 改行文字と”を除くソース文字集合中の任意の要素 乗除式 加減式 . 乗除式 加減式 加減式 シフト式 加減式 シフト式 シフト式 関係式 : シフト式 関係式 等価式 . 関係式 関係式 関係式 関係式 キャスト式 キャスト式 キャスト式 乗除式 乗除式 くく加減式 > > 加減式 前処理数 数字 数字 前処理数 前処理数 前処理数 前処理数 前処理数 く 数字 非数字 符号 E 符号 シフト式 シフト式 シフト式 シフト式 News Square 143

6. 月刊 C MAGAZINE 1992年8月号

画のルーチンて、す。本文て、解説した 2 種類の 方法が実装されています。ただし , 横方向 のクリッビングは実装されていません。 patfill.h, patfill. cpp には , GRCG を使っ た tone パターンの描画ルーチンが含まれま プログラムを作ることがあります。霧でか・教わった方法で , 理論的には上位バイトと 20 : end : seedfill. h, seedfill. cpp シードフィルアル ゴリズムのルーチンが含まれます。 amouse. h, amouse. cpp は , Microsoft m ouse 互換のマウスの処理関数群て、す。ポー リングを前提に最低限のもののみが実装さ す。 れています。 フィルタの話 をかけて拡張します。 - これはフリーソフト ので , バレットデータのおのおのの値に 0X11 それぞれ 256 階調もあれば十分だと思われる ので , カラーを内部的に拡張します。 GRB 普通に考えてそのままではまず不可能な ことを考えましよう。 として , 全般的にどのようにするかという のフィルタのアルゴリズムは専門書に譲る くなっていれば雰囲気はでるものです。個々 で , 色が少しぐらい違っていてもそれらし すが , 人間の目なんていい加減なものなの んでくるものは完全に行うことは不可能で いかなという感じがします。とくに色が絡 ログカラーでやろうとするとちょっと難し じないと思います。しかし , PC ー 9801 のアナ モノクロ 16 階調のときでもとくに問題は生 できるのでとくに間題ありません。また , フルカラーの場合は , そのまま理論的に す。 が , PC ー 9801 上でもある程度のことはできま 画像処理の範疇なので詳しくは扱いません ッジ抽出やレリーフ処理などです。これは・ すんだような効果を得る fog や , ほかし , 工 画面に特殊効果をかけるためにフィルタ : とつの手でしよう ( ListD ) 。 : ofbyte の配列を作って保存しておくのもひ : うのであれば , array 〔 0 、 . 15 , 0..15 , 0..15 ] ・てもたいした手間ではありません。毎回使 たかが 16 色しかないので総当たりで調べ ・匠に教わった方法ですが。 : いので簡略化しています。これも W RINN 師 うが , たかだか 4 , 096 色中 16 色であるし , 遅 ものを選択するということになるのでしょ ・カラー空間を考えて , もっとも距離の短い ・近い色を探してきます。理論的には GRB の てはいないので , バレットの中でなるべく 得られた RGB 値は 16 色の制限内に収まっ : になります ( 付録ディスク収録凵 ST C 参照 ) 。 . 計算していき値を見て点を打っていくこと : ておいて , 輝度の最大値が 15 になるように けです 9 デイザは 4X4 のディサ配列を作っ あとにディサリングして書き戻せばいいわ あとはフルカラーのふりをして演算した . でいき 256 階調になるように調整します。 あるいはデイザの倍率にあわせて足し込ん ド拡張されるためとても都合よくいきます。 : 下位バイトに同じ値を代入することでワー ウェア mps の作者で著名な W R 爪 N 師匠に 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 : function getNearColor(), g, b : integer) var dist, c, d : integer; min_color : byte; integer; beg i n dist for C = $7FFF ; ( * とりあえず最大にしておく * ) ニ 0 to MAXCOLOR do begin 2 * abs (r ー paletteDataCc, + 4 * abs (g ー paletteDataCc, abs(b ー paletteDataCc, 十 if dist 〉 d then begin dist ・ min_color = c; ( * パレット end; if dist > d then begin dist ・ min C010r end; end; getDiffuseCOIor ・ RED] ) GREEN]) BLUE) ) : 1 が今のところー番近い * ) 1 が今のところー番近い * ) ニ c; ( * パレット lllill C010r : 00 3 田 グラフィックライプラリ 作成入門 gdc. h, gdc. cpp は , 参考用の GDC 処理ル ーチンて、す。昨今の速いマシンて、は GDC を 使うより直接 CPU て、扱ったほうがよい場合 が多いのて、すが , 参考まて、に 各関数の使い方は本文と , ソースファイ ルを見てください おわりに ックス』 JICC 出版 [ 2 ] 安斎利洋 , 伊吹龍著『ターポグラフィ ードに強くなる本 II 』技術評論社 [ 1 ] 東エ大電算機愛好会 & 小高輝真著『 98 参考文献 ます。 の記事から読み取っていただけたらと思い きる場面も多々あります。その一端を今回 いる GRCG を使用すればさらに簡潔に記述て、 きます。それに加えて標準的に装備されて とをうまく生かせば高速化を図ることがて、 もある 8 ビットまとめて取り扱えるというこ て、すが , 水平型の長所て、もあり , またて、 ば点を打つだけて、すべて処理が可能なわけ 送につきるような気がします。なんとなれ 結局のところ点を打っことと , 横方向の転 水平型のグラフィックを扱っていると , こともありません。 動くと嬉しいものて、すし , 権利問題に悩む ば簡単に実現て、きることも自前て、処理して と思います。て、きあいのライプラリを呼べ ときに , 何かしらの役に立つのて、はないか 動作を理解したり , ゲームを作ったりする ルの部分から見ていくことはライプラリの れません。しかし , 基本的な扱いを低レベ だけの結果にとどまるにすぎないのかもし ひとつの互換性の低いライプラリを増やす 表されている昨今 , このような記事もまた たくさんのグラフィックライプラリが発 ら , ビットマップの扱いまて、を見てきまし 駆け足て、 PC ー 9801 のグラフィックの構造か 62 C MAGAZINE 1992 8

7. 月刊 C MAGAZINE 1992年8月号

」丿う 別ラ入 プ成 e--o イ乍 一フィ イ フ ラ グ 特集 アニメーション乍成 前章まで ; - グラフィックを扱うための多くの関数を作成 した。またアプリケトション作成には , マウス処理やア ニメーション処理を知るのも有益だろう。本章ではそれ、 らを用い第アニメーションのプログラムを作成する。 グラフィックの関数の動作を確認するに て、す。ここて、注意することは , NEC の MS- はマウスを使用した簡単なテストルーチン DOS に付属してくる mouse. sys はファンクシ を作成しておくと便利て、す。といってもマ ョンが一部異なるために使用て、きません。 ウスドライバを書くのはたいへんなのて、 , マウスドライバの制御は int 33h を通して それて、はいままて、作った関数を実際に使 既存のマウスドライバを使用するインタフ 行います。 って動作を確認しましよう。 ェイスの関数群を作成しておきましよう。 マウスドライバは Microsoft Mouse と互 lSt マウス制御の定義 換のドライバを使用します。常駐型のマウ スドライバには大別して Micorsoft Mouse マウス割り込みは , 非同期な割り込みを 発生するのて、 , 取りこばしをなくすために 互換のものと NEC マウスドライバがありま は本来ューザ割り込みルーチンを定義して す。 イベント駆動て、処理するのが常套手段て、す Microsoft Mouse は Code View や MS-D OS Ver. 5.0 に付属してくる mouse.com と , が , けっこうたいへんて、す。ポーリングて、 それと互換の機能を持ったマウスドライバ 処理することにして , ューザが自前て、状態 lSt List 58 マウスカーソルを表示・消去 , マウスの状態を構造体に代入 28 : union REGS reg; 29 : MRec. lastx = MRec. x; 30 : 31 : MRec. lasty = MRec. y; reg. x. = 0X0003 : 32 : i nt86 (MouseVect, &reg, &reg) : 33 : 34 : MRec. x = reg. x. cx; MRec. y = reg. x. : 35 : MRec. Lbt = ((reg. x. bx & 0X0001 ) ! = の : 36 : MRec. Rbt = ((reg. x. bx & 0X0002 ) ! = の : 39 : 40 : b001 LButton(void) union REGS reg; 42 : 43 : reg. x. ax = 0X0003 ; i nt86 (MouseVec t, &reg, &reg) : 45 : return ((reg. x. bx & 0X0001 ) トの ; 46 : 47 : } 48 : 49 : 01 RButton(void) 50 : ( union REGS reg; 52 : reg. x. = 0X0003 : 53 : ⅲ t86 (MouseVect, &reg, &reg) : 54 : return ((reg. x. bx & 0X0002 ) ! = の : 55 : テスト マウス制御 1 : #define MouseVect 0X33 2 : s truct MouseRec ( 3 : int x, y; boo 1 Lbt, Rbt : 4 : int lastx, lasty; 5 : 7 : 8 : MouseRec Mstat; 1 : 01 MouseAlive(void) union REGS reg; 3 : 4 : reg. x. = 0X0000 : 5 : int86 (MouseVect, &reg, &reg) : 6 : 7 : return reg. X. ax = 9 : 10 : void MouseShow(void) 11 : { union REGS 「 ; reg. x. = 0X0001 : 14 : int86 (MouseVect, &reg. &reg) : 16 : } 18 : void MouseHide(void) 19 : { 20 : union REGS reg; 22 : reg. x. ax = 0X0002 ; &reg) : int86 (MouseVect, &reg, 23 : 24 : ) 25 : 26 : void MouseStat(MouseRec& MRec) 27 : { 特集 PC -98 田グラフィックライプラリ作成入門 57

8. 月刊 C MAGAZINE 1992年8月号

」丿う 別ラ入 フ成 c-o イ乍 一フィ イ フ グ 特集 的なクオリティは , フィルムや , いまのと ころビデオにすらおよぶはずもないのに CRT 上て、アニメーションをしようと数々の 試みが行われています。 現在日本の誇る新しい 3 大文化 , コミック ( アニメーション ) , ファミコン , カラオケ のうちふたつの要素を含む CRT 上て、のアニ メ表現はこれからも尽きることのなく探求 されていくことが当然期待されます。さら にフルカラー環境が一般に浸透して , もっ ともっとクオリティの高い作品が登場して , 楽しむことがて、きるようになるといいて、す ね。 Fig. 2 PC ー 9801 のメモリ PC ー 9801 の VRAM セグメント ープレーン E000 G プレーン B800 B000 B プレーン A800 R プレーン 400 行 80 バイト PC -9801 のグラフィック PC ー 9801 シリーズて、グラフィックを扱った プログラムを組もう , とします。実現する にはいくつか方法がありますが , まず初め に , グラフィックライプラリをどう選択す るかが間題となります。 ①できあいのものを使う ②自前でなんとかする ということになるて、しよう。 て、きあいのものを使う場合て、も , 市販の ライプラリを使う , BGI など処理系に付属し ているライプラリを使う , GLIO を使う , G BIOS を使うなど , いろいろな選択肢があり のをいじくりまわせばどうもなんかてきそ さて , 今回はて、きあいのライプラリの解 ます。 て、きあいのライプラリは , ひと通りの機 説をするのは意味もないことなのて、 , そっ ということがなんとなくわかってき 能が実現されていて関数をコールすればこ ちは置いておきましよう。 ます。 と足りるし , 最適化もされているのて、使う 一から自前て、作れば , 自分て、把握したプ VRAM は一般に VIDEO RAM と呼ばれて ログラムがて、きるのて、処理にあった最適化 価値は十分にあります。しかし , もっと細 いるものて , その名のとおり画面出力用に が可能になるし , 何より作ったほうがおも かい処理をしたい場面も多々あるて、しよう。 割り当てられた RAM て、す。この VRAM の構 ライプラリというものは便利て、すが , 一般 しろそうなのて、なんとかしたいと思います。 成は当然 , 機種によってまったく異なって 化されているのて、どうしてもなんだかんだ て , それからどうするの ? という話て、 います。 PC ー 9801 の場合はグラフィック画面 す。さて , どうしましよう。 とムダな処理が入ってきたり , 軽く線を引 そのままのイメージがメモリ上にマッピン きたいだけなのに巨大なライプラリがリン グされているのて、取り扱いが簡単てす。 PC -9801 の V 日 AM 構造 クされてしまったりして , ちょっと敬遠し こから本格的な話に入っていきましよう。 たい場合があります。もしソースが付属し さてまず初めに知っておいてほしいのは , 自前て、グラフィックを扱うときにハード VRAM にはグラフィックプレーンと呼ばれ ていればそれをいじってなんとかすること るものが 4 枚あるということてす。なぜ 4 枚 もて、きるて、しようが , 普通はあまり付属し ウェアの構成を知ることは避けて通れぬ道 て、す。本を見たりすると VRAM とかいうも なのかをあえて説明するなら , PC ー 9801 には ていません。 特集 PC ー 98 田グラフィックライプラリ作成入門 37 メモリマップ セグメント F000 E800 E000 mv/RAM ープレーン ROM ープレー ン C000 B800 B000 A800 G プレー ン R プレ ーン B プレー ン G プレーン R プレーン B プレーン メイン RAM 0000

9. 月刊 C MAGAZINE 1992年8月号

向繙。 9 LiSt IA 13 : } 13 : } 関数の「名字」 ( よい例 ) List 関数の「名字」 ( 悪い例 ) 1 : good— 12 : 11 : 10 : 9 : 8 : 7 : 6 : 5 : 4 : 3 : sample() VMHAND char far vm—close() ; Ⅷ free(h) ; vm—unlock(h) ; P = vm—lock(h) ; h ニ vm ー a110C ( 10 の : Ⅷー open ( 10 の ; 1 : 3 : 4 : 5 : 6 : 8 : 9 : 10 : 11 : 12 : bad-sample() VMHAND char far vm—open()0 の ; h = v ー a110C ( 10 の ; P ニ vmlock(h) ; m—unlock(h) : free—memory(h) ; close—mem(); スは接尾辞と呼びます。 既ゆ名前に似せる ているからなのて、す。プログラムを書くと という名前が男性て、あることをみんな知っ 前を見て男性て、あるとわかるのは , 「ひろし」 することがて、きるからて、す。「」という名 の人があなたの関数名を見て , 処理を想像 おくのはよいことて、す。そうすれば , ほか 似の処理をするものならば , 名前を似せて もしそれがすて、に存在する関数と類 これからあなたが関数の名前をつけると 理なら clOse という名前が入っています。 という名前が入っていますし , クローズ処 ン処理をするならレベルにかかわらず叩 en 前がついていることがわかります。オープ 似ている処理をする関数には似ている名 表を横に見てみましよう。 て、あることがわかりますね。ところて、この ル 2 の関数が名前の最初の、、 f 〃によって仲間 書いたように , Table 1 を縦に見ると , レベ るとレベル 2 の関数名になりますね。前節て、 ベル 1 の関数名の頭に、、 f 〃という文字をつけ 較してみましよう。シークを除いては , レ ベル 2 の 2 種類があります。その関数名を比 操作する関数には大きく分けてレベル 1 とレ ひとっ話題を思い出しました。ファイルを いているうちに , 関数の名前についてもう プレフィックスとサフィックスの話を書 きも , プログラムを読む人が何を知ってい るかに注意を向け , 理解を助けるような書 き方をこころがけましよう。 プログラムによく使われる動詞を TabIe 2 に並べてみました。意味のうえて、関連が深 そうなものをそばに置いています。名前を つけるときの参考にしてください。また , あえてカタカナて、各単語の読みを付け加え ておきました。英語の発音がきちんとて、き る人はこのカタカナは無視してください 名月長さ 次に名前の長さにづいて考えてみましよ う。初期の C のコンパイラて、は名前は 8 文字 以内というものがありましたが , 現代の C コ ンパイラて、はそういう制限があるものは少 なくなりました。常識的にいって , 名前は 1 文字 ~ 40 文字程度の長さの範囲に収まるて、 しよう。問題はどのくらいの長さがよいか , て、す。 たとえば「現在のディレクトリの名前」を 保存しておく変数の名前を考えるとしまし よう。長いほうから思いつくまま列記して みます。あなたならどれを選びますか。 current directory name cur directory name current dir name cur dir name current dir cur dirname cur dir curdir curd Cdir cd すいぶんバリエーションがありますね。 私なら , current directory name cur dir あたりを使うように思います。意味と長さ のバランスがよいように感じるからて、す。 けれどもどれを使うかはそう画一的に決ま るものて、はありません。たとえば List 2 を見 てください。関数 get current directory_n ame ( ) という関数があったとしたら , その 引数名はわざわざ①のように current direc TabIe 1 ファイル操作関数の名前の比較 関数の動き オープン クローズ 書き込み 読み込み レベル 1 open close lseek write read レベル 2 fopen fcl ose fseek fwrite frea d プログラミングの工ッセンス 105

10. 月刊 C MAGAZINE 1992年8月号

」丿う 別ラ入 プ成 7--0 イ乍 一フィ イ フ グ 特集 マスクを使って処理をするのが適切だと思 シフトが必要ない場合はそのまま左から byte maskR = 0xFF くく ()x & 0X07 ) ; いますが , 今回はいちおう C だけて、記述して と宣言します。 右へ描けます。右シフトもシフトしながら 保存されたビットマップへのポインタを 左から描けます。左シフトは反対から描い います。 これて、 , だいたいの場合は期待した動作 たほうが何かと都合がよいのて、右から描く src, リストアする VRAM へのポインタを d をするのて、すが , 先ほど保留した条件 , st, 横幅を xsize とします。矩形の処理は 1 ラ ことにします。 イト数が 1 バイトのときと , 保存したバイト 基本的には端を描いて , あふれた分と次 インの処理のループに還元て、きるのて、 , 1 ラ のバイトをシフトしたものを合成して描く 数と書き込みバイト数が一致しないときの インの処理に注目します。とりあえず , 保 存されたバイト数 (xsize) は 2 以上て、 ( つまり ことになります。それから , 反対側の端を 処理を加えてやらなければなりません。 1 バイト内に収まっていない ) , 書き込みバイ 描きます (List 41 ) 。反対側の端の描画時に バイト数不一致の場合 は , あふれたビットとの合成を考慮しなけ ト数が 1 バイトて、なく , 保存されたバイト数 と書き込みバイト数が同じとて、あるとしま ればなりません。 まず , 書き込みバイト数がレヾイトのとき あふれたビットを次のループに送るのに す。 を考えましよう (Fig. 10 ) 。左端と右端のバ ちょっと制限が多いて、すが , 例外的な事 テンボラリ変数を使っています (Fig. 9 ) 。ア センプラを使う場合は , ローテイト命令と イトが一致しているのて、 , 当然 mask を別に 項はあとまわしにしましよう。 書き込みバイトが 1 バイトのとき 制限っき描画 1 : / / 書込が lbyte 2 : byte msk = maskL & maskR; 3 : if (xsize = 1 ) ( / / lbyte で収まっている 4 : for (int py = sy; py ← ey; py + + ) ( 5 : if (diff > = の ( 6 : *dst = ((*src 〉 > diff) & mask) ー (*dst & mask); } else ( 8 : *dst : ((*src くく -diff) & mask) ー (*dGt & mask); 9 : 10 : 11 : Src 十十 ; dst + = 冊 RB 買 : 12 : 13 : 14 : } else { 〃 2byte にまたがっているが 15 : 〃書込サイズが lbyte なので左シフトにきまっている 16 : for (int = sy; PY ← : PY + + ) { 17 : cmp : ((*src くく -diff) & maskL) ー ((*(src•l) 〉 ) rdiff) & maskR): 18 : *dst : (cmp & mask) ー (*dst & -mask); 19 : src 十ニ 2 : 20 : dst + ニ HORBYTES; 21 : 1 : if (diff ニ / / シフトなし 2 : / / 左端を描く 3 : *dst = (*src & mskL) ー (*dst & zskL) : 4 : / / 間を描く 5 : fmemcpy()s い 1, src + 1, 6 : xsize-2); 7 : src 十 = 8 : dst 十ニ xsize—l; 〃右端を描く 9 : ー (*dst & maskR); *dst ニ (*src & maskR) 10 : 11 : } else if (diff > の { / / 右シフト 12 : / / 左端を描く 13 : *dst ニ ((*src 〉 > diff) & maskL) ー (*dst & maskL) ; 14 : *src くく rdiff; 15 : / / 間を描く for (int dx 17 : 2 ; dx ← xsize-l; dX+-) { 18 : 十十・ dst++ : *dst ニ cmp ー (*src > 〉 di (f) : 20 : / / あふれたビットを次に送る 21 : 22 : cmp = *src くく rdiff; 23 : / / 右端を描く 24 : ニ ((cmp ー (*src diff)) & maskR) (*dst & maskR) : 25 : *ds t 26 : } e I se if (d i ff くの { / / 左シフト 27 : / / 後ろからかきもどす 28 : diff ー -diff; 29 : 30 : src = XSize ー 1 ; dst + = xsize ー 1 ; 31 : / / 左端を描く 32 : ニ ((*src くく diff) & maskR) 33 : *ds t maskR) : 34 : cmp ニ *src > 〉 rdiff; / / 間を描く 35 : for (int dx ニ 2 ; dx ← xsize-l; 38 : dst- ー (*src くく diff) ー cmp; 39 : *ds t / / あふれたビットを次に送る 40 : 41 : cmp = *src > 〉 rdiff; 42 : 45 : 46 : 22 : 23 : } 修正した右シフトの場合 1 : if (dsize 〉 xsize) { 2 : 〃あふれた 3 : *dst = cmp ー (*dst & maskR) : 4 : } else { 5 : *dst = (cmp ー (*src 》 diff)) ー (*dst & maskR) : 6 : S rc 十十 : dst-- / / 右端を描く *dst ニ (*dst & -maskL) ー (((*src くく diff) ー c 叩 ) & rnaskL); 修正した左シフトの場合 1 : if (dsize く xsize) { cmp ニ (*src > > rdiff); 2 : 3 : src— *dst ニ ((*src くく diff) ー cmp) ー (*dst & maskR) : 4 : 5 : } else { *dst : (*src くく diff) ー (*dst & maskR); 6 : 8 : cmp ニ (*src 〉 > rdiff) : 特集 PC ー 98 田グラフィックライプラリ作成入門 51