0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

x86ベアメタル三角形描画

0
Posted at

目的

将来x86上でOSを介さずに動く簡単な3Dエンジンを開発したいと思っています。
今回はポリゴンを理解する為にVGAに直接三角形を描画する検証を行います。

参考にした筆者の過去記事

ブートローダや、32ビットへ移行する方法及びC言語でのベアメタル開発の手順は以下に纏めています。
DVDから直接起動してC言語を動かす手順
x86ベアメタル直線描画

boot.asm,swtc.asm,linker.ldは前記事中のものを流用しています。

動作検証

QEMU

截图 2026-07-12 21-30-47

dynabook SS M10 11L/2

5e8930ce4575f8

コード

kernel.c
#define VGA_MEM 0xA0000
#define SCREEN_W 320
#define SCREEN_H 200

typedef unsigned char  u8;

/* 点 */
typedef struct {
    int x, y;
} Point;

/* 三角形 */
typedef struct {
    Point p0, p1, p2;
    u8 color;
} Triangle;

/* (x,y)座標にcで指定した色の点を打つ
  メモリは線形。(X,Y)の位置に対応するアドレスを求める公式 = 
  VRAM開始アドレス + Y*画面の解像度横 + X
*/
void put_pixel(int x, int y, u8 c)
{
    // 描画範囲外(負値は unsigned 変換で弾く)
    if ((unsigned)x >= SCREEN_W || (unsigned)y >= SCREEN_H)
        return;
    ((volatile u8 *)VGA_MEM)[y * SCREEN_W + x] = c;
}

/* (x0, y)から (x1, y)まで横1本の線を引く */
void draw_hline(int x0, int x1, int y, u8 c)
{
    if ((unsigned)y >= SCREEN_H)return; //画面外なら即終了
    
    if (x0 > x1) { int t = x0; x0 = x1; x1 = t; }//左 → 右になるよう入れ替え
    
    for (int x = x0; x <= x1; x++)
        put_pixel(x, y, c);
}

/* 三角形塗りつぶし(底辺を揃えない・汎用版) */
void fill_triangle(const Triangle *t)
{
    // 元の頂点
    int x0 = t->p0.x, y0 = t->p0.y;
    int x1 = t->p1.x, y1 = t->p1.y;
    int x2 = t->p2.x, y2 = t->p2.y;

    // 上下ソート用
    //     top
    //        *
    //       / \
    //      /   \
    //     /     \
    //    *-------* 実際は斜め
    //  mid       bot 
    int top_x, top_y;
    int mid_x, mid_y;
    int bot_x, bot_y;

    // 上(Yが最小)
    if (y0 <= y1 && y0 <= y2) { top_x = x0; top_y = y0; }
    else if (y1 <= y0 && y1 <= y2) { top_x = x1; top_y = y1; }
    else { top_x = x2; top_y = y2; }

    // 下(Yが最大)
    if (y0 >= y1 && y0 >= y2) { bot_x = x0; bot_y = y0; }
    else if (y1 >= y0 && y1 >= y2) { bot_x = x1; bot_y = y1; }
    else { bot_x = x2; bot_y = y2; }

    // 残りが真ん中
    if ((top_x == x0 && bot_x == x1) || (top_x == x1 && bot_x == x0))
        { mid_x = x2; mid_y = y2; }
    else if ((top_x == x0 && bot_x == x2) || (top_x == x2 && bot_x == x0))
        { mid_x = x1; mid_y = y1; }
    else
        { mid_x = x0; mid_y = y0; }

    // 分割描画に必要な差分(Yの差 ΔY)
    // 上半分と下半分に分けて描画する
    int dy_top_mid = mid_y - top_y;
    int dy_top_bot = bot_y - top_y;
    int dy_mid_bot = bot_y - mid_y;

    // 上部(top ~ mid)
    // 上現在のY座標 yにおいて、三角形の左端 xaと右端 xbを計算して、その間を横線で塗る
    for (int y = top_y; y <= mid_y; y++) { // 行ループ(Y方向)
    
        if ((unsigned)y >= SCREEN_H) continue; // 画面端を越えたら何もしない

        int xa = top_x;
        int xb = top_x;

        // 今のY位置における、top→midの辺のX座標を求める
        if (dy_top_mid != 0) // 0除算防止
        // 現在の行が全体の何割進んだか(相似比)を求め、
        // その割合だけXを加算(或いは減算)して位置を補間する
            xa += (mid_x - top_x) * (y - top_y) / dy_top_mid; // 短辺
        if (dy_top_bot != 0)
            xb += (bot_x - top_x) * (y - top_y) / dy_top_bot; // 長編

        if (xa > xb) { int tmp = xa; xa = xb; xb = tmp; } // 常に xa ≤ xbにする (xa→xbへ描写する)
        draw_hline(xa, xb, y, t->color);
    }

    // 下部(mid ~ bot)
    for (int y = mid_y + 1; y <= bot_y; y++) {
        if ((unsigned)y >= SCREEN_H) continue;

        int xa = mid_x;
        int xb = top_x;

        if (dy_mid_bot != 0)
            xa += (bot_x - mid_x) * (y - mid_y) / dy_mid_bot;
        if (dy_top_bot != 0)
            xb += (bot_x - top_x) * (y - top_y) / dy_top_bot;

        if (xa > xb) { int tmp = xa; xa = xb; xb = tmp; }
        draw_hline(xa, xb, y, t->color);
    }
}

/* 無限待機(省電力) */
static void idle_loop(void)
{
    while (1)
        __asm__ volatile ("hlt");
}

void kernel_main(void)
{
    Triangle tri = {
        .p0 = {70, 170},
        .p1 = {180, 40},
        .p2 = {260, 140},
        .color = 12
    };

    fill_triangle(&tri);

    idle_loop();
}
eed62930ccec08
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?