Try   HackMD

2020q3 Homework5 (render)

contributed by < Rsysz >

tags: sysprog

編譯時期生成 lookup table

首先因為對 C++ 一竅不通,花了不少時間在研讀各種命名與定義,考慮到對 C++ 程式碼的理解,就先行撰寫 編譯時期生成 lookup table 的部分。

再來根據我查到的資料,撰寫 compile time table 通常會使用 constexpr ,而它是對於我們常見的 const 修飾子的加強,const 代表英文中 constant 常數的意思,代表被修飾的變數數值在編譯期(compile-time)已定,也無法再通過語法修改,任何對於標示為常數的變數的嘗試修改都會造成編譯器報錯。詳情請看 Reference

那我這邊也不多廢話,constexpr 的標準隨著 C++11, 14, 17 發展逐漸放寬,只要 constexpr 標記的函數內所有變數都能在編譯時期確認,那就能使用,因此可以透過對不同 table 撰寫不同的 Generator 大幅減少程式碼,同時保證程式的靈活度

template <typename T, std::size_t N, typename Generator>
constexpr std::array<T, N> make_array(Generator f)
{
    std::array<T, N> table = {};
    for (std::size_t i = 0; i != N; ++i) {
        table[i] = f(i);
    }
    return table;
}

使用 array 建構物件暫存 for 迴圈內運行時呼叫 f 輸出的數值

constexpr auto f_tan(std::size_t i)
{
    return static_cast<uint16_t>((256.0f * tan(i * M_PI_2 / 256.0f)));
}
...
constexpr static auto LOOKUP_TBL g_tan = make_array<uint16_t, TBL_LEN>(f_tan);

運用上方的 make_array 呼叫對應的 f_tan,將生成的 Table 賦予 const static g_tan

另外我還有一個疑問,如果在不同檔案引入這份 header 且移除 static 宣告,是否會發生問題呢?

當然,為了使用這便利的功能是有代價地,必須使用 c++17 的標準來編譯才給過

-CXXFLAGS = -std=c++11 -O2 -Wall -g
+CXXFLAGS = -std=c++17 -O2 -Wall -g

還有因為 raycaster_fixedMulTanAbsTan 使用了 const uint16_t *lookupTable 的指標來傳遞陣列,但我使用了 std::array 來保存 table,因此會有轉型的問題,為此我只好

-    const uint16_t *lookupTable)
+    auto &lookupTable) // same as const std::array<uint16_t, TBL_LEN>

動了點手腳 (不知道是否允許這種改動?

Frame rate

Reference

constexpr
Frame rate