30日OS自作入門11日目(Win10)

初めに

年内のテスト等が終わったので気軽にやれる!

目次

ついにウィンドウ

もっとマウス(harib08a)

WindowsLinux等のGUIは、マウスカーソルを端っこに持ってゆくと画面外にカーソルが隠れるまでめり込んで止まります。これを悔しいからハリボテOSでも実現しよう!って話です。

でも、それならHarimainの画面外に行ってしまうのを防止していた。引数の数値を対応させればいいだけじゃない?ということで…

                    if (mx > binfo->scrnx - 1) {
                        mx = binfo->scrnx - 1;
                    }
                    if (my > binfo->scrny - 1) {
                        my = binfo->scrny - 1;
                    }

こうすればいいじゃないかと…で実行すると。
f:id:No000:20191220181543p:plain

うわ…本と同じエラーではないけど、大変なことに…
下敷きが対応していないのがまずいみたいですね…

画面外サポート(harib08b)

この修正をするのは簡単なようです。現状VRAMに該当するアドレスに、直接データを書き込んでいるのは、関数sheet_refleshsubだけなので、この関数内で画面外を対象外にする処理を追加してあげればいいみたいなのです!

rereshsubの上の方をこんな感じに...

  /* refresh範囲が画面外にはみ出していたら補正 */
  if (vx0 < 0) { vx0 = 0; } /* 画面外に出ている間は、下敷きの対応範囲xを修正 */
  if (vy0 < 0) { vy0 = 0; } /* 画面外に出ている間は、下敷きの対応範囲xを修正 */
  if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } /* 右の端っこの補正 */
  if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } /* 下の端っこの補正 */
  for (h = 0; h <= ctl->top; h++) { /* 下から一番上の下敷きまでを */

修正し、実行すると

キレイに動いてる!

shtctlの指定省略(harib08c)

ここは著者の趣味の問題みたいですね。とは言っても、こうも構造体が入り乱れていると混乱してしまうことは、私も思います。

ここで、構造体SHEETの方にも構造体SHTCTLを管理できるように、struct SHTCTL *ctlを追加します。なんかグルングルンしているような感じ…これもデータ構造として名称があるのかな…?

/* 下敷き1枚の情報 */
struct SHEET {
    unsigned char *buf;
    int bxsize, bysize, vx0, vy0, col_inv, height, flags;
    /* boxsize:下敷きの大きさx, bysize:下敷きの大きさy, vx0:下敷きの位置x, vy0:下敷きの位置y */
    /*col_inv:透明色の番号, height:下敷きの高さ, flags:下敷きの設定情報 */
    struct SHTCTL *ctl; /* ctlをこちらでも管理 */
};

追加!

そのあとは、*ctlが含まれ、汚くなっていた関数の箇所を修正します。
引数だけでなく、コード中での修正も数か所あるので、注意

そして、Harimainを修正し実行すると…

f:id:No000:20191220191610p:plain

すっきりしつつ、キチンと動いている。こういった、構造体が2つも3つも引数に入ってしまう場合は、どれかの構造体にまとめてしまうのがいい感じみたいですね!

ウィンドウを出してみよう(harib08d)

下敷きの設定をしたことによりウィンドウも表示できるようになっているみたいなのです。
なので、ウィンドウを表示する関数make_window8を作成します。

void make_window8(unsigned char *buf, int xsize, int ysize, char *title)
{
    static char closebtn[14][16] = {
        "OOOOOOOOOOOOOOO@",
        "OQQQQQQQQQQQQQ$@",
        "OQQQQQQQQQQQQQ$@",
        "OQQQ@@QQQQ@@QQ$@",
        "OQQQQ@@QQ@@QQQ$@",
        "OQQQQQ@@@@QQQQ$@",
        "OQQQQQQ@@QQQQQ$@",
        "OQQQQQ@@@@QQQQ$@",
        "OQQQQ@@QQ@@QQQ$@",
        "OQQQ@@QQQQ@@QQ$@",
        "OQQQQQQQQQQQQQ$@",
        "OQQQQQQQQQQQQQ$@",
        "O$$$$$$$$$$$$$$@",
        "@@@@@@@@@@@@@@@@"
    };  /* ×ボタン */
    int x, y;
    char c;
    boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         xsize - 1, 0        );
    boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         xsize - 2, 1        );
    boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         0,         ysize - 1);
    boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         1,         ysize - 2);
    boxfill8(buf, xsize, COL8_848484, xsize - 2, 1,         xsize - 2, ysize - 2);
    boxfill8(buf, xsize, COL8_000000, xsize - 1, 0,         xsize - 1, ysize - 1);
    boxfill8(buf, xsize, COL8_C6C6C6, 2,         2,         xsize - 3, ysize - 3);
    boxfill8(buf, xsize, COL8_000084, 3,         3,         xsize - 4, 20       );
    boxfill8(buf, xsize, COL8_848484, 1,         ysize - 2, xsize - 2, ysize - 2);
    boxfill8(buf, xsize, COL8_000000, 0,         ysize - 1, xsize - 1, ysize - 1);
    putfonts8_asc(buf, xsize, 24, 4, COL8_FFFFFF, title);
    /* ×ボタンの解読 */
    for (y = 0; y < 14; y++) {
        for (x = 0; x < 16; x++) {
            c = closebtn[y][x];
            if (c == '@') {
                c = COL8_000000;
            } else if (c == '$') {
                c = COL8_848484;
            } else if (c == 'Q') {
                c = COL8_C6C6C6;
            } else {
                c = COL8_FFFFFF;
            }
            buf[(5 + y) * xsize + (xsize - 21 + x)] = c;
        }
    }
    return;
}

といっても、いままで作ってきた関数を組み合わせて作っているので簡単です。

後は、本通りにメモリの確保と、下敷きの各種設定を行えば…
f:id:No000:20191221173701p:plain
かっけぇ…
これって、キーが来ているかを確認する無限ループに仕込んでいるから、これがカウントされていくたびにチェックを行っていると思うと感慨深いですね…

少し遊んでみる(harib08e)

下敷きの高さを変更するとどうなるんだろう…みたいな。
Harimain上の関数sheet_updownの数値と位置を入れ替えて
やってみると...

高速カウンタだぁ(harib08f)

起動したら電源が消えるまで全力で数字を数えるカウンタを、ウィンドウの中に仕込むみたいです。
ウィンドウの設定を変え、無限ループの内容を書き換えると…

チラチラの解消(harib08g)

じゃあなんでちらちらするのかと言うと、描きなおしを行う際に背景まで合わせて描画しているから、いくら高速でもチラチラしてしまうってことみたいですね。ってことで、重ね合わせが必要なレイヤーより上だけを描きなおすようにするみたいです。

要は、reflesh_subの引数にレイヤーの高さの情報を加えて、その高さより、低い場合は、再描画しないように、if文で条件分岐させるだけです。

実行してみると...

本で言われている通り、マウスがチラチラしてしまう…

チラチラ解消(2)(harib08h)

これ以上マウスを描画しないわけにはいけないし、VRAMは一つしかないし、どうしようって言った感じです。これを解決するために、VRAMと同じ大きさのデータをいくつかメモリ上に用意して、別々で管理するみたいです(VRAMが増えたわけではなく、あくまでバックアップ。倉庫のイメージ)。そんなことできるのか…

  ctl->map = (unsigned char *) memman_alloc_4k(memman, xsize * ysize); /* VRAMと同じ多きさのメモリ確保 */
  if (ctl->map == 0) { /* 確保をできなかったら */
    memman_free_4k(meman, (int) ctl, sizeof(struct SHTCTL)); /* メモリを解放する */
    goto err; /* 例外処理 */
  }

この処理でメモリを確保します。

あとは、refreshsubで描き換える上限も作ることで、描き換えが早くしている

/* 一部対応させる描きなおし関数(ローカル) */
void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) /* h0 < HIGHT < h1 */

あとは、マップする必要がある関数のrefreshsubの前に、refreshmapを配置して
実行すると…

終わりに

いろんな新しい考え方ができてきて好奇心が満たされていくばかりですね。次は、タイマーで直接ハードウェア上の時間に関するデータを読み取ろうってことみたいです。