目的
将来x86上でOSを介さずに動く簡単な3Dエンジンを開発したいと思っています。
今回は第一段階としてVGAに直接直線を描画する検証を行います。
参考にした筆者の過去記事
ブートローダや、32ビットへ移行する方法及びC言語でのベアメタル開発の手順は以下に纏めています。
DVDから直接起動してC言語を動かす手順
boot.asm,swtc.asm,linker.ldは前記事中のものを流用していますが、グラフィックモードへ切り替える為にswtc.asmのみ一部変更しています。
変更前:
swtc.asm
mov ax, 0x0003
int 0x10
変更後:
swtc.asm
mov ax, 0x0013
int 0x10
動作検証
QEMU
dynabook SS M10 11L/2
コード
kernel.c
#define VGA_MEM 0xA0000
#define SCREEN_W 320
#define SCREEN_H 200
typedef unsigned char u8;
typedef unsigned int u32;
/* (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 = (volatile u8 *)VGA_MEM;
vga[y * SCREEN_W + x] = c;
}
/* (x0,y0)→(x1,y1)へ線を描画
ブレゼンハムのアルゴリズムを使用(※筆者もまだ完全に理解できていない)
*/
void draw_line(int x0, int y0, int x1, int y1, u8 color)
{
int dx = x1 - x0;
int dy = y1 - y0;
int sx = (dx > 0) ? 1 : -1;
int sy = (dy > 0) ? 1 : -1;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
int err = (dx > dy ? dx : -dy) >> 1;
while (1)
{
put_pixel(x0, y0, color);
if (x0 == x1 && y0 == y1)
break;
int e2 = err;
if (e2 > -dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
void idle_loop(void)
{
while (1) {
__asm__ volatile ("hlt");
}
}
void kernel_main() {
draw_line(0, 0, 319, 199, 15); // 白斜線
draw_line(0, 199, 319, 0, 12); // 赤斜線
draw_line(160, 0, 160, 199, 10); // 緑縦線
draw_line(0, 100, 319, 100, 14); // 黄横線
idle_loop();//while(1);は排熱の為にファンが回ってうるさい
}