Upgrade to Pro — share decks privately, control downloads, hide ads and more …

UEFIでうごくゲームを作ってみた〜2017年夏休みの自由研究〜

Narazaka
September 13, 2017

 UEFIでうごくゲームを作ってみた〜2017年夏休みの自由研究〜

UEFIで動くノベルゲーを作ってみたので、その時の苦労とか知見とかまとめた自由研究発表です。
発表時のコードとかはこちら https://github.com/Narazaka/efigame

Narazaka

September 13, 2017
Tweet

More Decks by Narazaka

Other Decks in Technology

Transcript

  1. View Slide

  2. 奈良阪
    奈良阪
    ドリコム2015新卒(3年目) T
    yp
    e
    S
    cr
    ipt

    R
    u
    by
    書いてます
    T
    yp
    e
    S
    cr
    ipt / C
    # / P
    er
    l / R
    u
    by
    あたりが好き
    その他: 伺か / 漫画読み描き / OP
    アニメ愛好家 / 鉄
    T
    w
    itt
    er: @nar
    az
    aka
    G
    it
    hu
    b: @N
    ar
    az
    aka
    np
    m: @nar
    az
    aka
    CPAN
    : NARA
    Z
    AKA
    R
    u
    byG
    ems: N
    ar
    az
    aka
    P
    ix
    iv: 奈良阪
    M
    edia
    M
    ar
    ker: nar
    az
    aka

    View Slide


  3. 注意:
    いわゆる「○○
    やってみた」
    系の発表です。
    UEFI
    ガチ勢、C
    ++ガチ勢の方々
    は生暖かく聞いて下さ
    い。

    View Slide

  4. 夏休みの自由研究の目標

    そういうテー
    マでなんかやってくれって言われたので)
    UEFI
    で動くなんらかのゲー
    ムエンジンを作りたい

    View Slide

  5. UEFI
    とは
    コンピュー
    ター

    OS
    を立ち上げる前に動く
    BIOS
    関係の仕様
    W
    indows
    立ち上げる前に
    HP
    とか
    T
    hink
    P
    ad とか Z
    OT
    AC
    とかロゴ
    が出てるあそこ
    2010年以降の
    PC
    (M
    ac込み)で旧来の
    BIOS
    から徐々
    に置き換わって
    いる
    OS
    なし状態にもかかわらず結構高水準な
    API
    が存在する←
    ここ重要
    例:
    キー
    ボー
    ド, マウス, ファイルシステム, 画面表示, ネットワー
    ク, et
    c.

    View Slide

  6. モチベー
    ション
    ‑ 個人的に「
    どこでも動く」
    プログラムが至高という想い
    ‑ 近年の
    PC
    にはあまねく
    UEFI
    が載っている
    ‑ UEFI
    で実装すれば
    OS
    という枷を超えてどこでも動く
    ‑ JVM
    なんかメじゃないぜ(
    無理
    ‑ 最近
    C
    ++触ってなかったのでリハビリしておきたい

    View Slide

  7. 参考資料
    C
    92(コミケ)新刊:
    フルスクラッチで作る!UEFI
    ベアメタルプログラミング (大神 祐真)
    http://yu
    ma.ohgami.jp/

    ベアメタルプログラミング:
    OS
    を使わない、
    ハー
    ドウェア上の低レイヤー
    のプログラミング

    この資料上では仕様からヘッダファイルを起こすところまで自作していますが、
    さす
    がにきついので
    EDK II
    由来のヘッダファイル群 kiz
    nit/u
    efi‑headers
    を利用しました。
    リファレンスとしては
    P
    hoenixW
    iki が割と見やすいと思います。

    View Slide

  8. UEFI
    ベアメタルプログラミング
    OS
    なし
    libc/libc++ではない(POSI
    X標準ではない)独自の
    API
    ベー

    C
    ++ (参考資料では
    C
    )
    ファイルシステムは
    FA
    T
    (USB
    フラッシュメモリに入れる)
    動作確認は
    QEMU
    最近の
    PC
    (M
    ac系含む)には載ってるので一応ある程度動作するはず

    View Slide

  9. 実装したもの
    とりあえず
    UEFI

    API
    をラップ
    C
    ons
    ole(wr
    it
    e
    L
    ineとか), F
    ile
    S
    yst
    em(r
    ead, r
    eaddir
    等)
    ゲー
    ムに要りそうなやつ
    描画系(1dot、
    矩形、
    円形、
    画像描画)
    入力系(
    get
    c相当他、
    on
    K
    eyP
    r
    ess、
    on
    M
    ous
    e*)
    簡易イベントルー

    ゲー
    ムに要りそうなやつで付随して必要になったもの
    p
    ng等一般画像形式読み込みライブラリの統合
    st
    dlib.hとstr
    ing.hの一部(mallocとか)
    フォント
    ゲー
    ム本体
    簡易シー
    ンマネー
    ジャー(
    諸事情によりマクロ)
    ノベルゲー
    ムシナリオインター
    プリター
    マウスカー
    ソル描画

    View Slide

  10. 大体こんなん
    こういうシナリオファイルと画像を入れておけばマウスキー
    ボー
    ドポチ
    ポチで読み進められるノベルゲー
    #
    b
    g
    _
    s
    c
    h
    o
    o
    l
    .
    p
    n
    g (
    背景ファイル)
    :
    R
    0
    =
    s
    u
    r
    f
    a
    c
    e
    0
    .
    p
    n
    g (
    人物0
    のファイルを右に描画)
    :
    L
    1
    =
    s
    u
    r
    f
    a
    c
    e
    1
    0
    .
    p
    n
    g (
    人物1
    のファイル左に描画)
    @
    ねぷ (
    名前欄)
    >
    はろー (
    セリフ)
    ‐ (
    ここまでが1
    セリフ)
    :
    R
    0
    =
    s
    u
    r
    f
    a
    c
    e
    1
    .
    p
    n
    g
    >
    にゅー
    わー
    るど

    View Slide

  11. アレのパクリスプラッシュ

    View Slide

  12. マウスクリックでも動きます

    View Slide

  13. ポチポチすすめる
    ADV

    View Slide

  14. ポチポチすすめる
    ADV

    View Slide

  15. ポチポチすすめる
    ADV

    View Slide

  16. C
    onsole(write
    L
    ineとか),
    F
    ile
    S
    ystem(read, readdir等)
    st
    dout
    とst
    derr
    の別はないが文字は出せるので普通にラッパを実装
    op
    en, r
    ead, r
    eaddir, clos
    eの流れは大体一緒
    op
    endir
    とop
    enの区別がなくて一緒くたに処理する
    なお文字列は w
    c
    h
    a
    r
    _
    t
    *
    相当の C
    H
    A
    R
    1
    6
    *
    =
    E
    F
    I
    _
    S
    T
    R
    I
    N
    G
    (UTF
    16LE
    )
    パス区切りは
    FA
    T
    っぽく \
    \
    (
    E
    F
    I
    _
    S
    T
    R
    I
    N
    G
    )
    L
    "
    f
    o
    n
    t
    s
    \
    \
    3
    3
    .
    p
    n
    g
    "

    View Slide

  17. 描画系
    1ドットごと色変更と、
    ビットマップをバルク転送する
    B
    lt() API
    矩形、
    円形描画、
    画像描画(
    透過色対応)
    など実装
    参考に読んだ記事では
    EDK II
    では透過対応が完全ではないとのこ
    と。

    まあ見るからに重い処理だし……)
    入力系
    待ちなしでキー
    入力とマウスが受けられる
    イベントルー
    プ中差分把握を実装してon
    M
    ous
    e
    L
    eftC
    lick等も実装
    QEMU
    だとマウスが効かなかったので実機確認のみになった

    View Slide

  18. イベントルー

    複数のイベントを待ち受けできる
    API
    が存在するので、w
    hile(tru
    e)
    ルー
    プ内でイベント番号でsw
    it
    chして処理できる
    今回は30fps
    で発生するイベントとキー
    ボー
    ド入力イベントをとっ
    てます
    マウスカー
    ソル
    1フレー
    ムごとに、
    描画する領域色を保存して描画して前にいた場
    所の色を戻すみたいなことをしている
    オフスクリー
    ンレンダリングやレイヤー
    利用していないので、
    タイ
    ミングによっては色が乱れる
    画像、
    フォント、
    libc、
    シー
    ンマネー
    ジャー
    このあと述べます

    View Slide

  19. 直面した問題・
    ハマりどころ
    (UEFI
    だから、
    というより制約下のフルスクラッチ風味
    C
    /C
    ++開発故と
    いうものが多いです)

    View Slide

  20. libc/libc++相当が使えない
    クロスコンパイラ氏、
    そういうものを用意してくれてはいない。
    最終的に
    m
    a
    l
    l
    o
    c
    , f
    r
    e
    e
    , r
    e
    a
    l
    l
    o
    c
    , a
    b
    s
    , i
    t
    o
    a
    (
    s
    t
    d
    l
    i
    b
    .
    h
    )
    m
    e
    m
    s
    e
    t
    , m
    e
    m
    c
    p
    y
    , s
    t
    r
    n
    c
    p
    y
    , s
    t
    r
    c
    p
    y
    , s
    t
    r
    c
    a
    t
    , s
    t
    r
    l
    e
    n
    (
    s
    t
    r
    i
    n
    g
    .
    h
    )
    を自前で書くことに……。
    /
    /
    例: m
    a
    l
    l
    o
    c
    v
    o
    i
    d
    * m
    a
    l
    l
    o
    c
    (
    U
    I
    N
    T
    N s
    i
    z
    e
    ) {
    v
    o
    i
    d *
    p
    t
    r
    ;
    E
    F
    I
    _
    S
    T
    A
    T
    U
    S S
    t
    a
    t
    u
    s = l
    i
    b
    c
    :
    :
    B
    o
    o
    t
    S
    e
    r
    v
    i
    c
    e
    s

    >
    A
    l
    l
    o
    c
    a
    t
    e
    P
    o
    o
    l
    (
    E
    f
    i
    L
    o
    a
    d
    e
    r
    D
    a
    t
    a
    , s
    i
    z
    e
    , &
    p
    t
    r
    )
    ;
    r
    e
    t
    u
    r
    n S
    t
    a
    t
    u
    s =
    = E
    F
    I
    _
    S
    U
    C
    C
    E
    S
    S ? p
    t
    r : n
    u
    l
    l
    p
    t
    r
    ;
    }
    フルスクラッチ風味とかこだわらず単に
    UEFI
    アプリケー
    ションを作りたいだけなら、
    EDK II
    という
    SDK
    を使うとこの辺には困らないはず。

    View Slide

  21. 画像処理系等のライブラリ stb の導入
    やっぱ画像なら
    PNG
    を読みたい。
    フォントも使いたい。
    しかし前提としてlibcがないのでlibp
    ngとかは無謀そう。
    stb ‑ single‑file public domain libraries for C
    /C
    ++
    (nothings/stb)
    画像、
    音声、
    タイルマップ、
    フォント周りとかが揃ったシングルファイ
    ルヘッダー
    構成かつ他への依存がないライブラリがあった。
    神か。

    View Slide

  22. 画像処理系等のライブラリ stb の導入(続き)
    #inclu
    de dlib.h> // 自前libc
    #define
    STB
    _IMAGE
    _IMPLEMENT
    A
    TION
    #define
    STBI
    _ASSERT
    (x) // assert.h がないので無視
    #define
    STBI
    _NO
    _STDIO
    // stdio.h がないのではずす
    #define
    STBI
    _NO
    _LINEAR
    // math.h がないのではずす
    #define
    STBI
    _NO
    _HDR
    // math.h がないのではずす
    #define
    STBI
    _ONL
    Y_PNG
    #define
    STBI
    _MALLOC
    (sz) malloc(sz) // 自前malloc, free, realloc
    #define
    STBI
    _FREE
    (p) fr
    ee(p)
    #define
    STBI
    _REALLOC
    _SI
    Z
    ED
    (p,oldsz,newsz)
    r
    ealloc_s
    iz
    ed(p,oldsz,newsz)
    #inclu
    de b_image.h> // stbの画像処理系本体
    制約の強い環境も考えてくれてる良いライブラリだ……

    View Slide

  23. 画像処理系等のライブラリ stb の導入(続き)
    画像読み込み系のst
    b_image.hは導入できた
    画像リサイズ系のst
    b_image_r
    es
    iz
    e.hはmath.hが必要
    フォント処理系のst
    b_tru
    etyp
    e.hもmath.hががっつり必要

    mat
    h.h実装がないと画像リサイズ不可&フォントは別で用意する必要

    View Slide

  24. reallocをまともに実装すると実は大変
    st
    b導入に際し r
    e
    a
    l
    l
    o
    c
    が必要になったが……
    ネイティブ
    API
    は m
    a
    l
    l
    o
    c
    相当の A
    l
    l
    o
    c
    a
    t
    e
    P
    o
    o
    l
    と f
    r
    e
    e
    相当
    の F
    r
    e
    e
    P
    o
    o
    l
    しかない
    この制約下での r
    e
    a
    l
    l
    o
    c
    は f
    r
    e
    e → m
    a
    l
    l
    o
    c
    か、
    最初にメモリ位置
    指定までできる A
    l
    l
    o
    c
    a
    t
    e
    P
    a
    g
    e
    s
    を使うしかなさそう。
    どちらにしても、
    現在どのポインタがどのサイズを持っているかとい
    う情報を保持せねばならない。

    大変
    (EDK II
    では頑張って実装していた。)
    (st
    bにはサイズ情報を追加で渡すr
    ealloc_s
    iz
    edという拡張呼び出しが用
    意されていたのでなんとか事なきを得た。)

    View Slide

  25. 失われた math.h を求めて
    1. フォントやリサイズを使うためにはmat
    h.hが必要
    2. ヘッダー
    ファイルとしてのmat
    h.hは使えるのだが、UEFI
    クロスコ
    ンパイル環境だと実装がなさそう?
    3. 「
    mat
    h.h 実装」[検索]
    4. どうやらfdlibmというライブラリがもとになっているらしい?
    5. fdlibmは古く、W
    ebでファイルを配ってるだけなので導入しにくさ
    6. ただし
    M
    akefileがめっちゃシンプルで良い
    7. G
    it
    hu
    bにあるのだと
    J
    ulia
    L
    ang/openlibm が使いやすそう
    8. 結局時間切れにより導入には至らず

    View Slide

  26. フォントの用意
    前提: BIOS
    に日本語フォントはなく、ttf、
    otfは使えない

    フォントを
    PNG
    にして都度読み込み
    1. フォントを用意
    JF
    ドット
    K
    app
    a20‑0213
    2. t
    ar
    lety/tt
    f2p
    ngがフォントが対応している文字ごとに1つずつテキス
    トファイルに出してくれるのでその部分だけ使う(
    他部分は古くて
    動かなかった)
    3. テキストファイル全部をさらって
    I
    mage
    M
    agickでp
    ngにする
    c
    o
    n
    v
    e
    r
    t ‐
    b
    a
    c
    k
    g
    r
    o
    u
    n
    d n
    o
    n
    e ‐
    f
    i
    l
    l b
    l
    a
    c
    k +
    a
    n
    t
    i
    a
    l
    i
    a
    s ‐
    f
    o
    n
    t J
    F

    D
    o
    t

    K
    a
    p
    p
    a
    2
    0

    0
    2
    1
    3
    .
    t
    t
    f ‐
    p
    o
    i
    n
    t
    s
    i
    z
    e 2
    0 l
    a
    b
    e
    l
    :
    @
    #
    {
    t
    e
    x
    t
    _
    f
    i
    l
    e
    }
    f
    s
    /
    f
    o
    n
    t
    s
    /
    文字コー
    ド数値.
    p
    n
    g
    "
    4. UEFI
    では
    FA
    T
    ファイルシステム上においたファイルが普通に読める
    ので頑張って1文字ごと表示時に画像読みまくって描画

    View Slide

  27. フォントの用意(
    ボツ案)
    UEFI
    では
    FA
    T
    ファイルシステム上においたファイルが普通に読める
    ので頑張って1文字ごと表示時に読みまくって描画
    1. 控えめに言って酷い
    2. 昔のコンピュー
    タの日本語フォント
    ROM
    よろしくデー
    タを全部
    st
    at
    icに持ってしまうのはどうか?
    3. p
    ngからむりやりデー
    タのcpp
    ファイルを生成↓
    c
    o
    n
    s
    t p
    n
    g = P
    N
    G
    .
    s
    y
    n
    c
    .
    r
    e
    a
    d
    (
    i
    m
    a
    g
    e
    .
    r
    e
    a
    d
    F
    i
    l
    e
    S
    y
    n
    c
    (
    )
    )
    ;
    .
    .
    .
    f
    o
    n
    t
    s
    S
    t
    r +
    = `
    s
    t
    a
    t
    i
    c U
    I
    N
    T
    8 c
    f
    o
    n
    t
    _
    $
    {
    c
    h
    a
    r
    C
    o
    d
    e
    }
    _
    a
    l
    p
    h
    a
    [
    ] {
    `
    ;
    f
    o
    r (
    l
    e
    t i = 0
    ; i < l
    e
    n
    g
    t
    h
    ; +
    +
    i
    ) {
    f
    o
    n
    t
    s
    S
    t
    r +
    = `
    $
    {
    p
    n
    g
    .
    d
    a
    t
    a
    [
    i * 4 + 3
    ]
    }
    ,
    `
    ;
    }
    f
    o
    n
    t
    s
    S
    t
    r +
    = `
    }
    ;
    \
    n
    `
    ;
    バイナリが8MB
    くらいになって、
    起動失敗したので断念

    View Slide

  28. C
    ++はlib(std)c++がないとクラス関連機能が
    色々
    使えない
    シー
    ンをしようとクラスを作ったところで判明。
    まずnew
    演算子の参照がないと怒られるのでnew
    できない
    → v
    o
    i
    d
    * o
    p
    e
    r
    a
    t
    o
    r n
    e
    w
    (
    U
    I
    N
    T
    N s
    i
    z
    e
    ) {
    r
    e
    t
    u
    r
    n m
    a
    l
    l
    o
    c
    (
    s
    i
    z
    e
    )
    ;
    }
    など定義することで一応解決はできる
    v
    irtu
    al関係はlibc++が型解決を受け持っているらしく使えない

    cxx
    abi.hで定義されててる__class_typ
    e_infoまたは
    __v
    mi_class_typ
    e_infoと言うクラスがないと実現できないっぽい。
    C
    ++は言語組み込みでクラスの全挙動をサポー
    トしているわけではなく、
    インター
    フェー
    スだけ用意して実装は本質的に自前でやる必要がある……
    だと……ッ!?

    View Slide

  29. なおvirtualが使えないと……
    シー
    ンマネー
    ジャー
    を作ろうとしたんですが……
    /
    /
    親クラス = n
    e
    w
    子クラス(
    )
    S
    c
    e
    n
    e
    * s
    c
    e
    n
    e = n
    e
    w S
    t
    a
    r
    t
    S
    c
    e
    n
    e
    (
    )
    ;
    s
    c
    e
    n
    e

    >
    u
    p
    d
    a
    t
    e
    (
    )
    ;
    この u
    p
    d
    a
    t
    e
    (
    )
    が子クラス
    S
    t
    artS
    ceneのものを指せないので、
    無理矢理
    ダウンキャストするなどしかない……?
    今回はマクロで定数定義してsw
    it
    chで分岐するなど無理矢理対応し
    た……。
    #
    d
    e
    f
    i
    n
    e s
    c
    e
    n
    e
    I
    d
    (
    C
    l
    a
    s
    s
    ) C
    l
    a
    s
    s #
    # I
    d
    #
    d
    e
    f
    i
    n
    e d
    e
    l
    r
    a
    r
    e
    S
    c
    e
    n
    e
    (
    C
    l
    a
    s
    s
    ) s
    t
    a
    t
    i
    c C
    l
    a
    s
    s * C
    l
    a
    s
    s #
    # _
    o
    b
    j
    #
    d
    e
    f
    i
    n
    e i
    n
    i
    t
    S
    c
    e
    n
    e
    (
    C
    l
    a
    s
    s
    ) C
    l
    a
    s
    s #
    # _
    o
    b
    j = n
    e
    w C
    l
    a
    s
    s (
    )
    #
    d
    e
    f
    i
    n
    e s
    c
    e
    n
    e
    C
    a
    s
    e
    (
    C
    l
    a
    s
    s
    ) c
    a
    s
    e C
    l
    a
    s
    s #
    # I
    d : \
    C
    l
    a
    s
    s #
    # _
    o
    b
    j ‐
    > u
    p
    d
    a
    t
    e
    (
    )
    ; +
    + C
    l
    a
    s
    s #
    # _
    o
    b
    j ‐
    > t
    i
    c
    k
    ; b
    r
    e
    a
    k
    ;
    #
    d
    e
    f
    i
    n
    e c
    h
    a
    n
    g
    e
    S
    c
    e
    n
    e
    (
    C
    l
    a
    s
    s
    ) c
    u
    r
    r
    e
    n
    t
    S
    c
    e
    n
    e
    I
    d = C
    l
    a
    s
    s #
    # I
    d

    View Slide

  30. 60fpsが出ない
    多くのゲー
    ムにおいて最大の障害
    単純な w
    h
    i
    l
    e
    (
    t
    r
    u
    e
    )
    ;
    ではなくタイマー
    で描画スピー
    ドを調整でき
    はするが……?
    C
    or
    e i7が載ってる
    PC

    QEMU
    では元気に60fps
    出してくれる
    Z
    BO
    X
    CI
    320だと30fpsもでない

    早期に認識していたので、
    その辺関係ないノベルゲー
    に絞った
    やり方が間違っていたりするだろうか……?

    View Slide

  31. M
    acで立ち上げると
    FA
    T
    が読めなさそう?
    会社の
    M
    acでも立ち上げてみたけれど、
    画像とかが
    USB
    メモリから
    読めてなさそうだった
    UEFI
    、FA
    T
    読めるはずだけど、
    仕様上実装必須ではないのか?

    どこでも動く」
    の障害になりそう

    View Slide

  32. 解像度変更すると画面上の各ピクセルを表す
    ポインタ位置がバグる
    解像度変更の
    API
    があるのだけれど、
    画面上の色を表すポインタが
    画面上シー
    ケンシャルにならない
    UEFI
    起動すると解像度変更しなくてもディスプレイ最大に合わせて
    くれるのであまり意識しなくて良い事項ではある

    View Slide

  33. 描画の微妙な問題?
    描画系(GRAPHICS
    _OUTPUT
    _PROTOCOL


    API
    コー
    ル、
    関数を
    またいで呼ばれると描画処理が行われない場合がある?
    とりあえず同じトコにまとめちゃったりしてうやむや解決したので
    定かではないです。

    View Slide

  34. 課題(
    積み残し)
    UEFI
    で動くなんらかのゲー
    ムエンジンを作りたい
    mat
    h.hを入れてフォントとリサイズしたい
    レイヤー
    管理等がなくベタ描画なのでチラつくし面倒
    イベントルー
    プまではなんとかしたが、
    シー
    ン管理とかは大分微妙
    最後突貫工事でなんとかノベルゲー
    にしたのでライブラリの形には
    整っていない
    ……思ったより意外と積み残しが少ない?
    ライブラリ化だけなんとかしてこのまんまギッハブに投げてもいい……?

    View Slide

  35. まとめ
    UEFI
    で動くなんらかのゲー
    ムエンジンを作りたい
    ゲー
    ムエンジンではなく単体のゲー
    ムができました
    主に強い制限状況下での
    C
    ++コー
    ディングで、C
    ++の基盤を垣間見
    ることができました
    ゲー
    ムエンジンっぽい部分は一応分けてあるのでなんとかして公開
    したいですね

    View Slide